/* ==========================================================================
   CONGENIA — Landing one-page
   Dirección de arte: editorial suizo / monocromo cálido (ver ../../../.rules/style.md)
   Paleta, escala tipográfica y grid clonados de la referencia aprobada.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Paleta del manual de marca CONGENIA (tonos de obra: grises, azulados y
     verdosos). Los nombres de las variables se mantienen para no tocar las
     1200 lineas que las consumen; el mapeo contra el manual es este:
       --off-white    #f3f3f3  fondo base
       --beige        #d6d3d0  lamina de Cultura / superficies alternas
       --charcoal     #1c1c1c  texto principal, secciones oscuras
       --dark-beige   #7a8681  texto secundario, hairlines, numeracion
       --darker-beige #444443  cuerpo sobre la lamina
       --accent       #4d5e6a  unico acento (eyebrows entre corchetes)
       #ffffff                 blanco puro, ver .cursor-cube */
  --off-white: #f3f3f3;
  --beige: #d6d3d0;
  --charcoal: #1c1c1c;
  /* Un tono mas profundo que el charcoal, solo para el footer: es lo que lo
     separa del bloque de contacto sin sacarlo del cierre oscuro. Es un
     derivado del #1c1c1c del manual, no un color nuevo. */
  --charcoal-deep: #121212;
  --dark-beige: #7a8681;
  --darker-beige: #444443;
  /* Acento azulado del manual. Se usa SOLO en los eyebrows entre corchetes;
     no pinta botones ni fondos. */
  --accent: #4d5e6a;
  /* Sobre charcoal el acento del manual da 2.5:1 y el eyebrow desaparece. Esta
     es la misma familia azulada aclarada hasta 6.8:1 contra #1c1c1c, para los
     eyebrows del cierre de contacto y del panel de Cultura. */
  --accent-invert: #8fa5b2;
  /* Fuera de la paleta de marca: solo estados de error de formulario. */
  --error: #ad1a1a;

  --radius: 0.5rem;
  --radius-sm: 0.375rem;

  /* Hairlines */
  --line: rgba(28, 28, 28, 0.14);
  --line-invert: rgba(214, 211, 208, 0.2);

  /* Escala tipográfica fluida */
  --heading-footer: clamp(3.5rem, 1.95rem + 9.5vi, 17rem);
  --heading-expertise: clamp(3rem, 1.8rem + 5.2vi, 8.65rem);
  --heading-display: clamp(2.54rem, 1.8rem + 3.3vi, 6.8rem);
  --heading-1: clamp(2.34rem, 1.71rem + 3.13vi, 4.52rem);
  --heading-2: clamp(1.875rem, 1.43rem + 2.18vi, 3.4rem);
  --heading-3: clamp(1.5rem, 1.2rem + 1.5vi, 2.55rem);
  --heading-4: clamp(1.2rem, 0.99rem + 1.02vi, 1.9rem);
  --heading-5: clamp(1.05rem, 0.84rem + 0.43vw, 1.5rem);
  --heading-6: clamp(1rem, 0.928rem + 0.36vw, 1.25rem);
  --text-base: clamp(0.9rem, 0.9rem + 0.07vw, 1.05rem);
  --text-large: clamp(1rem, 0.7071rem + 0.5143vi, 1.4rem);
  --text-small: clamp(0.821rem, 0.3071rem + 0.4647vi, 0.8943rem);
  --text-xsmall: clamp(0.721rem, 0.3071rem + 0.4647vi, 0.8943rem);

  /* Espaciado fluido */
  --space-3xs: clamp(0.3125rem, 0.3125rem + 0vi, 0.3125rem);
  --space-2xs: clamp(0.5625rem, 0.5446rem + 0.0893vi, 0.625rem);
  --space-xs: clamp(0.875rem, 0.8571rem + 0.0893vi, 0.9375rem);
  --space-sm: clamp(1.125rem, 1.0893rem + 0.1786vi, 1.25rem);
  --space-md: clamp(1.6875rem, 1.6339rem + 0.2679vi, 1.875rem);
  --space-lg: clamp(2.25rem, 2.1786rem + 0.3571vi, 2.5rem);
  --space-xl: clamp(3.375rem, 3.2679rem + 0.5357vi, 3.75rem);
  --space-2xl: clamp(4.5rem, 4.3571rem + 0.7143vi, 5rem);
  --space-3xl: clamp(5.75rem, 6.2571rem + 1.2023vi, 7.25rem);

  /* Grid */
  --column-count: 12;
  --gap-fluid: clamp(1rem, 0.8571rem + 1.0143vi, 3.5rem);
  --grid-main: repeat(var(--column-count), minmax(0, 1fr));
  /* 27px a 390 (lo que mide la referencia en mobile) y los mismos 39.68px de
     antes a 1440: la recta que une esos dos puntos es 1.393rem + 1.2076vw.
     El piso de 1.6875rem sostiene los 27px por debajo de 390. Antes arrancaba
     en 1rem y en mobile el texto quedaba a 16px del borde, la mitad del aire de
     la referencia; el tramo de desktop queda igual que estaba. */
  --pad-x: clamp(1.6875rem, 1.393rem + 1.2076vw, 3.5rem);
  --header-h: 4rem;

  /* Motion */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  /* La portada es una foto clara: el velo se profundiza y va en charcoal, no en
     negro puro, para que el blanco del lockup y de la bajada no se lave contra
     ella y la foto siga dentro de la paleta. */
  --scrim: linear-gradient(180deg, rgba(28, 28, 28, 0.34) 0%, rgba(28, 28, 28, 0.66) 100%);
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }

body {
  font-family: "Figtree", system-ui, sans-serif;
  font-weight: 400;
  font-size: var(--text-base);
  line-height: 1.5;
  color: var(--charcoal);
  background: var(--off-white);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
body.is-locked { overflow: hidden; }

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }
button, input, textarea { font: inherit; color: inherit; background: none; border: none; }
button { cursor: pointer; }

h1, h2, h3, h4, h5, h6 { font-weight: 500; letter-spacing: -0.035em; line-height: 1.05; }

::selection { background: var(--charcoal); color: var(--off-white); }

:focus-visible { outline: 2px solid var(--charcoal); outline-offset: 3px; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --------------------------------------------------------------------------
   3. Layout
   -------------------------------------------------------------------------- */
.wrap { padding-inline: var(--pad-x); }

.grid {
  display: grid;
  grid-template-columns: var(--grid-main);
  gap: var(--gap-fluid);
}

/* En mobile la referencia baja el aire de seccion a space-lg (36px medidos a
   390): con space-3xl cada seccion sumaba 105px arriba y abajo, el doble de
   pagina en blanco entre bloque y bloque, y la lectura se cortaba. El valor
   grande vuelve desde 48rem, que es donde la grilla se abre a dos columnas. */
.section { padding-block: var(--space-lg); }
.section--tight { padding-block: var(--space-md); }

@media (min-width: 48rem) {
  .section { padding-block: var(--space-3xl); }
  .section--tight { padding-block: var(--space-2xl); }
}

/* Lamina beige: se despega del off-white y hace de quiebre visual a mitad de
   pagina. Cierra a ras del bloque oscuro de contacto, sin franja de off-white
   ni sombra en el medio: con la banda de logos dada de baja, cualquier aire ahi
   deja una costura clara entre la lamina y el cierre. Por eso las esquinas de
   abajo van a escuadra y no lleva sombra: el quiebre lo hacen el cambio de
   fondo y las esquinas de arriba. */
.section--sheet {
  position: relative;
  background: var(--beige);
  border-radius: var(--radius) var(--radius) 0 0;
}

/* Los eyebrows van entre corchetes y en el acento del manual, como en la
   referencia. Los corchetes se escriben en el HTML, no con ::before.
   Van en --text-base y no en --text-small: a 13px la etiqueta en mayusculas
   quedaba por debajo del cuerpo de texto y se leia como una nota al pie. */
.eyebrow {
  font-size: var(--text-base);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  color: var(--accent);
  font-weight: 500;
  line-height: 1.2;
}
/* Sobre fondo oscuro (cierre de contacto, panel de Cultura) el acento pasa a
   su variante clara: es el mismo azulado, pero legible. */
.contact .eyebrow, .drawer .eyebrow { color: var(--accent-invert); }

.lead { font-size: var(--text-large); line-height: 1.35; letter-spacing: -0.01em; }
.muted { color: var(--dark-beige); }
.hairline { border-top: 1px solid var(--line); }

/* Titular monumental de seccion ("Servicios", "Expertise").
   En la referencia es el primer elemento de la seccion y ocupa el ancho util
   completo; el eyebrow, la bajada y el CTA van DEBAJO, no al lado. El
   font-size lo calcula initFitText() midiendo el texto. */
.section__word {
  grid-column: 1 / -1;
  font-size: 19vw;
  line-height: 0.7;
  font-weight: 500;
  /* -0.012em y no -0.035em: a 350px el tracking cerrado son 12px negativos y
     pares como la "rt" de Expertise se superponen. Al aflojarlo el texto mide
     mas, y como initFitText() lo ajusta al ancho de la caja, el font-size baja
     ~5% solo. Las letras se despegan y el titular sigue a ancho completo. */
  letter-spacing: -0.012em;
  white-space: nowrap;
  /* space-lg y no space-xl: con line-height 0.7 el titular ya deja aire
     propio debajo, y en la referencia la distancia real al eyebrow es 40px. */
  padding-bottom: var(--space-lg);
}

/* Fila de apoyo bajo el titular: eyebrow a la izquierda, bajada y CTA en la
   mitad. La ultima columna queda libre a proposito: es donde flotan las
   pastillas de navegacion. */
.section__intro { grid-column: 1 / -1; display: grid; gap: var(--space-md); }
.section__intro p { max-width: 46ch; }
/* Sin este span el eyebrow se auto-ubica en UNA sola columna de las 12 y el
   texto se parte en tres lineas de dos palabras. */
.section__eyebrow { grid-column: 1 / -1; }

@media (min-width: 48rem) {
  /* Sin padding-bottom: el aire hasta el primer bloque lo pone el propio
     bloque (space-2xl), como en la referencia. Sumar los dos daba 140px. */
  .section__intro { grid-column: 5 / span 5; padding-bottom: 0; }
  .section__eyebrow { grid-column: 1 / span 4; align-self: start; }
}

/* --------------------------------------------------------------------------
   4. Botones y links
   -------------------------------------------------------------------------- */
/* Pildora de la referencia: rectangulo de esquinas blandas en charcoal, con
   la etiqueta a la izquierda y un cuadrado beige con la flecha pegado al borde
   derecho. Al hover la etiqueta corre y el cuadrado se pliega sobre si mismo.
   El padding izquierdo es 0: lo pone la propia etiqueta, asi el cuadrado queda
   a la misma distancia del borde por los cuatro lados. */
.btn {
  display: inline-flex;
  align-items: center;
  padding: 0.5625rem 0.5625rem 0.5625rem 0;
  border: 0;
  border-radius: 0.5rem;
  background: var(--charcoal);
  color: var(--off-white);
  line-height: 1;
  overflow: hidden;
}
.btn__label {
  display: block;
  padding-inline: var(--space-sm);
  font-size: var(--text-base);
  font-weight: 500;
  transition: transform 0.6s var(--ease);
}
.btn__icon {
  flex: none;
  display: grid; place-items: center;
  width: 1.75rem; height: 1.75rem;
  padding: 0.3125rem;
  border-radius: 0.25rem;
  background: var(--beige);
  color: var(--charcoal);
  transition: transform 0.6s var(--ease);
}
.btn__icon svg { width: 100%; height: 100%; }
@media (hover: hover) {
  .btn:hover .btn__label { transform: translateX(1rem); }
  .btn:hover .btn__icon { transform: scale(0.2) rotate(90deg); }
}

/* Link con subrayado que se dibuja */
.link-underline { position: relative; display: inline-block; }
.link-underline::after {
  content: "";
  position: absolute; left: 0; bottom: -0.15em;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.5s var(--ease);
}
.link-underline:hover::after { transform: scaleX(1); transform-origin: left; }

.num { color: var(--dark-beige); font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   4a. Barra de progreso y cursor propio
   -------------------------------------------------------------------------- */
/* La barra vive en el borde superior y crece con el scroll. No lleva riel
   visible: en la referencia solo se ve el tramo recorrido. El color lo decide
   initProgress() segun lo que haya debajo del pixel 0, que es lo unico que la
   barra tapa. */
.scroll-progress {
  position: fixed; top: 0; left: 0; z-index: 200;
  width: 100%; height: 2px;
  background: var(--charcoal);
  transform: scaleX(0);
  transform-origin: 0 50%;
  pointer-events: none;
  transition: background-color 0.4s var(--ease);
}
.scroll-progress.is-on-dark { background: var(--off-white); }

/* Cursor propio: un cuadrado que persigue al puntero con inercia y se agranda
   sobre lo clickeable. En difference no hace falta saber el fondo: se invierte
   contra lo que tenga debajo, igual que en la referencia. */
.cursor-cube {
  position: fixed; top: 0; left: 0; z-index: 300;
  width: 10px; height: 10px;
  background: #fff;
  mix-blend-mode: difference;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.3s var(--ease);
  will-change: transform;
}
.cursor-cube.is-on { opacity: 1; }

/* Solo se esconde el cursor del sistema si el cubo esta activo: sin puntero
   fino, con motion reducido o sin JS, initCursor() no agrega la clase y el
   cursor nativo sigue siendo el unico. El `*` es necesario porque links y
   botones declaran su propio cursor. */
body.has-cube-cursor, body.has-cube-cursor * { cursor: none; }
/* Escribir sin caret es peor que no tener cubo: los campos conservan el suyo. */
body.has-cube-cursor input, body.has-cube-cursor textarea { cursor: text; }

/* --------------------------------------------------------------------------
   4b. Wordmark
   El sprite solo declara los trazos: no pinta nada. Los consumidores heredan
   el color por currentColor, que atraviesa <use>.
   -------------------------------------------------------------------------- */
.cg-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.cg-logo { display: block; overflow: hidden; }

/* --------------------------------------------------------------------------
   5. Header flotante
   No hay barra: la marca y el reloj flotan sobre el hero; la nav son pastillas
   oscuras translucidas que quedan legibles sobre cualquier fondo y por eso
   nunca se ocultan.
   -------------------------------------------------------------------------- */
.site-header {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  pointer-events: none;
  padding: var(--space-sm) var(--pad-x);
}
.site-header a, .site-header button { pointer-events: auto; }

.header-top {
  display: flex; align-items: flex-start; gap: var(--space-md);
  color: var(--off-white);
}

.brand {
  display: flex; align-items: baseline; gap: 0.7em;
  /* --text-large y no --text-small: la marca es lo primero que se lee sobre la
     portada y a 13px competia con el reloj en vez de encabezar. Todo el bloque
     esta en em (el logo, el gap, el recorte de la mascara), asi que sube en
     conjunto sin tocar nada mas. */
  font-size: var(--text-large); letter-spacing: 0.06em; font-weight: 500;
  text-transform: uppercase;
  transition: color 0.4s var(--ease);
}
/* El logo va a la altura de la caja de mayusculas del descriptor y alineado a
   su linea de base: con align-items:baseline, la base de un SVG en linea es su
   borde inferior, asi que ambos apoyan en la misma linea sin ajustes a mano. */
.brand__logo { width: auto; height: 0.72em; flex: none; }
.brand > span {
  /* Visible tambien en mobile: en la referencia "ENGINEERING" acompana al
     wordmark en todo el rango, y a 16px el par entero mide 217px de los 336
     utiles. Lo que si queda solo para desktop es el reloj. */
  font-weight: 400; letter-spacing: 0.02em; opacity: 0.75;
  transition: opacity 0.4s var(--ease);
}

/* Al scrollear, "Ingenieria" no se desvanece en bloque: cada letra cae y la
   linea de base se la come, en orden aleatorio. Es el efecto de la referencia.
   El recorte va con clip-path y no con overflow: un inline-block con overflow
   distinto de visible pasa a tener su borde inferior como linea de base, y el
   logo de al lado dejaria de alinear. clip-path no toca la linea de base.
   0.15em es lo que va del borde inferior de la caja (line-height: 1) a la linea
   de base en Figtree (ascender 950 + descender 250 sobre 1000 upm: 0.25 - 0.1);
   con Montserrat eran 0.14em. El -0.7em de arriba deja pasar la tilde de la I. */
.brand__mask {
  display: inline-block;
  line-height: 1;
  clip-path: inset(-0.7em 0 0.15em 0);
}
.brand__mask > span { display: inline-block; will-change: transform; }

.clock {
  display: none;
  margin-inline: auto;
  white-space: nowrap;
  font-size: var(--text-small);
  text-transform: uppercase; letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  transition: opacity 0.4s var(--ease);
}

/* Pasado el hero la marca NO se va: se queda anclada arriba a la izquierda y se
   invierte contra lo que tenga debajo, igual que en la referencia (su <header>
   lleva mix-blend-difference con el texto en off-white). Sobre el off-white de
   la pagina el resultado es negro; sobre el charcoal del cierre, casi blanco.
   No hay que saber que hay abajo ni mantener una lista de secciones oscuras.

   El blend arranca recien aca y no en el hero: ahi la foto es un cielo gris
   claro y difference dejaria la marca en gris oscuro, cuando el hero esta
   compuesto con el lockup en blanco sobre el velo. Sobre la foto, entonces,
   blanco plano.

   Lo que si se desvanece es el descriptor y el reloj, compuestos para leerse
   sobre la foto. */
.site-header.is-past-hero { mix-blend-mode: difference; }
.site-header.is-past-hero .clock { opacity: 0; pointer-events: none; }
/* Respaldo sin GSAP o con motion reducido: el descriptor se va de una pieza.
   Con el efecto letra por letra activo, .has-letter-fx desactiva esta regla. */
.site-header.is-past-hero .brand:not(.has-letter-fx) > span { opacity: 0; pointer-events: none; }

/* Sobre el cierre oscuro la marca ya no se retira: con el blend se invierte a
   blanco sola. Las pastillas translucidas si se van, porque un fondo charcoal
   al 50% sobre charcoal no se distingue del bloque (ver .is-hidden). */

/* Pastillas de navegacion, apiladas arriba a la derecha */
.pill-nav {
  position: fixed; top: var(--space-sm); right: var(--pad-x); z-index: 101;
  transition: opacity 0.4s var(--ease);
}
.pill-nav.is-hidden { opacity: 0; pointer-events: none; }
.pill-nav ul { display: none; flex-direction: column; gap: 0.3rem; }

/* Entrada de las pastillas, con los valores de la referencia: cada una sube
   10px y aparece en 1.1s con la curva --ease (que es su cubic-bezier), 0.6s de
   espera inicial y 0.05s de diferencia entre una y la siguiente
   (navItemVariants + navContainerVariants del sitio original).
   Va en CSS y no en GSAP porque la opacidad del contenedor ya la maneja
   .is-hidden sobre el bloque oscuro del cierre: una animacion con forwards
   sobre .pill-nav le ganaria en el cascade y la nav no podria ocultarse. */
@keyframes pill-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}
.pill-nav li {
  opacity: 0;
  animation: pill-in 1.1s var(--ease) 0.6s forwards;
}
.pill-nav li:nth-child(2) { animation-delay: 0.65s; }
.pill-nav li:nth-child(3) { animation-delay: 0.7s; }
.pill-nav li:nth-child(4) { animation-delay: 0.75s; }
.pill-nav li:nth-child(5) { animation-delay: 0.8s; }
.pill-nav a {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-xs);
  min-width: 7.25rem;
  padding: 0.34rem 0.6rem;
  border-radius: var(--radius-sm);
  background: rgba(28, 28, 28, 0.5);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  color: var(--off-white);
  font-size: var(--text-small);
  font-weight: 500;
  transition: background 0.4s var(--ease);
}
.pill-nav a:hover { background: rgba(28, 28, 28, 0.85); }
.pill-nav .num { font-size: 10px; color: var(--off-white); opacity: 0.7; }

.nav-toggle {
  position: relative;
  width: 3rem; height: 3rem;
  border-radius: var(--radius-sm);
  background: rgba(28, 28, 28, 0.5);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
}
.nav-toggle span {
  position: absolute; left: 50%; top: 50%;
  width: 18px; height: 2px; border-radius: 2px; background: var(--off-white);
  transition: transform 0.4s var(--ease);
}
.nav-toggle span:first-child { transform: translate(-50%, -3px); }
.nav-toggle span:last-child { transform: translate(-50%, 3px); }
.nav-toggle[aria-expanded="true"] span:first-child { transform: translate(-50%, 0) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:last-child { transform: translate(-50%, 0) rotate(-45deg); }

.mobile-nav {
  position: fixed; inset: 0; z-index: 99;
  background: var(--charcoal); color: var(--off-white);
  padding: calc(var(--space-2xl) + 3rem) var(--pad-x) var(--space-xl);
  display: flex; flex-direction: column; gap: var(--space-sm);
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform 0.6s var(--ease), visibility 0s linear 0.6s;
}
.mobile-nav.is-open {
  transform: translateY(0); visibility: visible;
  transition: transform 0.6s var(--ease), visibility 0s linear 0s;
}
.mobile-nav a { display: flex; gap: 0.5em; align-items: baseline; font-size: var(--heading-4); font-weight: 500; }
.mobile-nav .num { font-size: var(--text-small); color: var(--dark-beige); }

@media (min-width: 40rem) {
  .pill-nav ul { display: flex; }
  .nav-toggle { display: none; }
}

@media (min-width: 48rem) {
  .clock { display: block; }
}

/* --------------------------------------------------------------------------
   6. Hero
   La seccion mide dos viewports: el contenido queda pinneado con position
   sticky y el margen negativo hace que el resto de la pagina suba por encima
   como una lamina. Es el efecto de la referencia.
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  margin-bottom: -100svh;
  overflow: clip;
}
.hero__sticky {
  position: sticky; top: 0;
  height: 100svh;
  overflow: clip;
  padding: var(--space-sm) var(--pad-x);
}
.hero__spacer { height: 100svh; }

.hero__bg {
  position: absolute; inset: 0; z-index: -1;
  width: 100%; height: 100%;
  object-fit: cover;
  pointer-events: none;
  /* La foto tiene un cielo azul saturado que se pelea con la paleta cerrada.
     Bajarle el croma la devuelve al monocromo de la referencia y de paso apaga
     el ruido de color detras de la tipografia. */
  filter: saturate(0.3) contrast(1.02);
  /* La portada es una panoramica 2.33:1 y el hero mide 100svh: `cover` siempre
     recorta a los costados. Corrido a la derecha, el transformador de potencia
     queda en cuadro; centrado se iba de foco y solo quedaba cielo. */
  object-position: 72% center;
}
@media (max-width: 47.99rem) {
  /* En portrait el recorte es mucho mas agresivo (se ve ~30% del ancho): el
     encuadre se cierra todavia mas sobre el equipamiento. */
  .hero__bg { object-position: 78% center; }
}
.hero__scrim { position: absolute; inset: 0; background: var(--scrim); pointer-events: none; }

.hero__inner {
  position: relative; z-index: 1;
  height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end;
  color: var(--off-white);
}

.hero__lead { display: grid; grid-template-columns: var(--grid-main); gap: var(--gap-fluid); }
/* En la referencia el [descargar] queda a la izquierda de la bajada tambien en
   mobile, no solo en desktop: son dos items de la misma fila. Dos columnas de
   las doce alcanzan para la flecha y la bajada arranca en la tercera. */
.hero__cue { grid-column: 1 / span 2; font-weight: 500; }
.hero__cue svg { display: inline-block; width: 1em; height: 1em; vertical-align: -0.12em; }
.hero__tagline {
  grid-column: 3 / -1;
  max-width: 28ch;
  font-size: calc(var(--text-large) - 2px);
  line-height: 1.35;
}

/* El wordmark es el logo solo, al ancho util completo. Sin nada al lado gana
   todo el ancho disponible, que es lo mas grande que puede quedar sin romper el
   padding de pagina. */
.hero__wordmark {
  padding-top: var(--space-lg);
  line-height: 1;
}
.hero__logo { width: 100%; height: auto; }

@media (min-width: 48rem) {
  .hero__inner { justify-content: center; }
  .hero__lead { padding-bottom: var(--space-2xl); }
  .hero__cue { grid-column: 6 / span 1; justify-self: end; }
  .hero__tagline { grid-column: 7 / -1; max-width: 45ch; font-size: var(--text-large); }
  /* El bloque contenedor es .hero__inner, que ya esta dentro del padding de
     pagina: por eso left/right van en 0 y no en var(--pad-x). */
  .hero__wordmark { position: absolute; left: 0; right: 0; bottom: var(--space-sm); padding-top: 0; }
}

/* La pagina sube por encima del hero: necesita fondo propio y esquinas
   redondeadas arriba, como la lamina de la referencia. */
.page-over {
  position: relative; z-index: 2;
  background: var(--off-white);
  border-radius: var(--radius) var(--radius) 0 0;
}

/* Reveal por palabras.
   El colchon de abajo es por las metricas de Figtree: la linea de base queda a
   0.15em del borde de la caja, pero el descendente baja 0.25em, asi que el
   overflow: hidden le comia el pie a la "j" y la "y". El padding agranda la
   caja de recorte y el margen negativo lo devuelve, para no mover el layout.
   Con la caja mas alta, el desplazamiento inicial del reveal tiene que ser
   mayor que el colchon (ver yPercent en initReveals) o la palabra asoma. */
.word-mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}
.word-mask > span { display: inline-block; will-change: transform; }

/* Reveal de imagen con mascara */
.img-mask { overflow: hidden; }
.img-mask img { will-change: transform; }

/* Fade generico */
.reveal { will-change: transform, opacity; }

/* --------------------------------------------------------------------------
   7. Nosotros
   Igual que en la referencia: cuerpo a la izquierda con el acceso al equipo
   entre hairlines y la ficha de la obra al pie, alineada a derecha; a la
   derecha, la foto grande con el riel de miniaturas al costado.
   -------------------------------------------------------------------------- */
.about__head { grid-column: 1 / -1; }
.about__claim {
  grid-column: 1 / -1;
  font-size: var(--heading-1);
  text-wrap: balance;
  /* 5px al eyebrow y 30px al cuerpo. El interlineado del titular ya aporta
     aire propio arriba y abajo, asi que con 20/60 el bloque se leia como tres
     piezas suetas en vez de un solo parrafo de apertura. */
  padding-block: var(--space-3xs) var(--space-md);
}

/* La cabecera y la fila de cuerpo + galeria son dos grillas separadas (en
   desktop la segunda se pinnea), asi que el aire entre ambas ya no lo pone el
   gap de una grilla compartida: lo pone esta regla. */
.about__stage { padding-top: var(--space-lg); }

/* En una sola columna la ficha tiene que ir DESPUES de la foto que describe, y
   la foto entre el cuerpo y la ficha. display:contents promueve los tres
   bloques de la columna a items de la grilla, y ahi `order` puede intercalar la
   galeria en el medio. Desde 48rem la columna vuelve a ser un item solo. */
.about__col { display: contents; }
.about__body { grid-column: 1 / -1; order: 1; display: grid; gap: var(--space-md); }
.about__body p { max-width: 62ch; }

/* Fila destacada de la columna: una sola linea encerrada entre hairlines, con
   la miniatura a la izquierda y la flecha empujada al extremo derecho. Llevaba
   al equipo; ahora destaca la posventa (el cliente decidio no mostrar gente). */
/* "Presencia en todo el pais" es del cliente y sobrevive a la banda de cifras
   que la llevaba: queda como rotulo al pie de la columna. */
.about__reach { grid-column: 1 / -1; order: 3; padding-top: var(--space-lg); }

.about__feature {
  grid-column: 1 / -1; order: 4;
  display: flex; align-items: center; gap: var(--space-xs);
  padding-block: var(--space-2xs);
  border-block: 1px solid var(--line);
  font-size: var(--heading-6);
  transition: color 0.4s var(--ease);
}
.about__feature img {
  flex: none; width: 2.25rem; height: 2.25rem;
  object-fit: cover; border-radius: var(--radius-sm);
}
/* Elemento grafico del manual (trazado tecnico) en lugar de la foto: hereda
   currentColor, asi que entra en la misma transicion de hover que la fila. */
.about__mark { flex: none; width: 2.25rem; height: 2.25rem; }
.about__feature .arrow-ne {
  margin-left: auto; font-size: 0.8em; color: var(--dark-beige);
  transition: transform 0.4s var(--ease);
}
.about__feature:hover { color: var(--dark-beige); }
.about__feature:hover .arrow-ne { transform: translate(3px, -3px); }

/* --- Galeria de obras --------------------------------------------------- */
.about__gallery { grid-column: 1 / -1; order: 2; }
/* position:relative es lo que ancla el dato a la esquina de la foto. */
.gallery__stage { aspect-ratio: 4 / 3; position: relative; }

/* Dato de la obra en pantalla, sobre la esquina inferior izquierda. Antes era
   una banda de seis cifras debajo de la seccion; asi cada numero queda pegado
   a la obra que lo respalda, que es de donde saca su sentido.
   El velo sube desde abajo y muere antes de la mitad: la foto no se tapa, y el
   numero se lee igual sobre un parque solar claro que sobre un aereo de noche. */
.gallery__dato {
  position: absolute; inset: auto 0 0 0; z-index: 1;
  /* El aire de arriba es el largo del degrade. En mobile la foto mide poco mas
     de 250 px y con --space-2xl el velo se comia media imagen, asi que arranca
     corto y crece recien cuando hay foto donde apoyarlo. */
  padding: var(--space-lg) var(--space-xs) var(--space-xs);
  color: var(--off-white);
  background: linear-gradient(to top,
    rgba(28, 28, 28, 0.82) 0%,
    rgba(28, 28, 28, 0.55) 38%,
    rgba(28, 28, 28, 0) 100%);
  pointer-events: none;
}
.gallery__dato-fig {
  display: block;
  font-size: var(--heading-3); font-weight: 500;
  letter-spacing: -0.04em; line-height: 1;
  /* tabular-nums: sin esto el contador cambia de ancho en cada frame y el
     numero se mueve solo mientras cuenta. */
  font-variant-numeric: tabular-nums;
}
.gallery__dato-label {
  display: block;
  padding-top: 0.25em;
  font-size: var(--text-small); line-height: 1.3;
  color: var(--beige);
}

/* --- Flechas de la galeria (solo mobile) -------------------------------- */
/* En mobile el riel corre en horizontal y nada avisa que hay mas obras al
   costado. Las flechas son esa senal, y de paso pasan de obra: mejor que un
   cartelito de "desliza", que ocupa lugar y no hace nada. */
.gallery__nav {
  position: absolute; top: 50%; z-index: 2;
  transform: translateY(-50%);
  width: 2.5rem; height: 2.5rem;
  display: grid; place-items: center;
  color: var(--off-white);
  background: rgba(28, 28, 28, 0.42);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-radius: 50%;
  transition: background-color 0.3s var(--ease), opacity 0.3s var(--ease);
}
/* Mismo icono que los botones del sitio (linea + punta), no un chevron
   distinto: es la unica flecha horizontal de la interfaz y conviene que sea
   siempre la misma. La de "anterior" es la misma volteada. */
.gallery__nav svg { width: 1.15rem; height: 1.15rem; }
.gallery__nav--prev svg { transform: scaleX(-1); }
.gallery__nav--prev { left: var(--space-2xs); }
.gallery__nav--next { right: var(--space-2xs); }
.gallery__nav:active { background: rgba(28, 28, 28, 0.68); }
/* Al llegar a la punta la flecha no desaparece: se apaga. Si se va, el riel
   parece haberse quedado sin obras. */
.gallery__nav[disabled] { opacity: 0.42; }

@media (min-width: 48rem) {
  /* En desktop el riel vertical ya esta a la vista al costado de la foto. */
  .gallery__nav { display: none; }
}
@media (min-width: 48rem) {
  .gallery__dato { padding: var(--space-2xl) var(--space-sm) var(--space-sm); }
}
.gallery__stage img,
.gallery__video { width: 100%; height: 100%; object-fit: cover; }
/* El stage alterna entre la foto y el video con el atributo hidden, y algunas
   reglas de display podrian ganarle: explicito para que no dependa del UA. */
.gallery__stage [hidden] { display: none; }

/* Mobile: el riel corre en horizontal debajo de la foto. */
.gallery__rail {
  display: flex; gap: 0.4rem;
  margin-top: 0.4rem;
  overflow-x: auto;
  scrollbar-width: none;
}
.gallery__rail::-webkit-scrollbar { display: none; }

.gallery__thumb {
  flex: none;
  width: 4.25rem; aspect-ratio: 4 / 3;
  overflow: hidden;
  opacity: 0.4;
  transition: opacity 0.4s var(--ease);
}
.gallery__thumb img { width: 100%; height: 100%; object-fit: cover; }
.gallery__thumb:hover, .gallery__thumb:focus-visible { opacity: 0.75; }
.gallery__thumb.is-active { opacity: 1; }

@media (min-width: 48rem) {
  .about__claim { grid-column: 1 / span 11; }
  /* Cuerpo a la izquierda, galeria a la derecha: es el orden de la
     referencia. Invertido, el bloque de texto queda apretado contra el borde. */
  .about__col { display: block; grid-column: 1 / span 6; }
  .about__body, .about__feature { grid-column: auto; order: 0; }
  .about__feature { margin-top: var(--space-2xl); }

  /* --- Fila fija --------------------------------------------------------
     La fila de cuerpo + galeria queda pinneada mientras el visitante recorre
     las seis obras, y se suelta cuando pasa la ultima. El recorrido lo da
     .about__run, que es alto vacio debajo: sin el, el sticky no tiene por
     donde viajar.
     Se pinnea esta fila y no la seccion entera porque con el titular adentro
     el bloque mide 868 px y no entra en una pantalla de 900: el titular se
     lee, se va, y recien ahi arranca el pin. */
  .about__stage {
    position: sticky;
    /* Sin cajon de 100svh: centrar el contenido en una pantalla completa
       dejaba ~220 px muertos entre el titular y el cuerpo. La fila mide lo que
       mide su contenido y se pega al titular; el aire hasta el pin lo da top,
       que despeja la marca y las pastillas del encabezado. */
    top: var(--space-3xl);
    padding-top: var(--space-sm);
  }
  /* 6 obras a ~40svh de scroll cada una. Mas corto se pasan de golpe; mas
     largo el visitante siente que la pagina se trabo. */
  .about__run { height: 240svh; }

  /* La galeria toma las seis columnas de la derecha y las reparte entre foto y
     riel con el mismo gap de la grilla: el riel queda en la ultima columna,
     por fuera de la foto, como en la referencia. */
  .about__gallery {
    grid-column: 7 / -1; order: 0;
    display: flex; align-items: flex-start; gap: var(--gap-fluid);
  }
  .gallery__stage { flex: 1 1 auto; min-width: 0; }
  .gallery__rail {
    flex: 0 0 4.25rem;
    flex-direction: column;
    margin-top: 0;
    /* El riel arranca mas abajo que la foto, no a la par: asi la columna no
       compite con el borde superior de la imagen. */
    padding-top: var(--space-3xl);
    overflow: visible;
  }
  .gallery__thumb { width: 100%; }
}

/* --------------------------------------------------------------------------
   8. Servicios
   -------------------------------------------------------------------------- */
/* Cada familia de servicio es un bloque de dos partes, como en la referencia:
   una cabecera con la numeracion, el nombre a gran escala y una miniatura; y
   debajo, separada por una hairline, la lista de capacidades a dos columnas.
   No hay tarjetas ni iconos por item. */
/* La familia es la propia grilla de 12 columnas: asi la numeracion, el nombre,
   la miniatura y el listado se anclan a columnas reales en vez de calcular
   offsets a mano. */
.svc__group {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: var(--grid-main);
  gap: var(--space-sm) var(--gap-fluid);
  /* La foto arranca en el borde superior de la familia, como en la referencia,
     y la numeracion y el nombre bajan a apoyar sobre la hairline: con todo
     top-aligned un nombre de una sola linea quedaba flotando a 130px de la
     linea, muy despegado de la foto. */
  align-items: start;
  padding-top: var(--space-2xl);
}
.svc__num, .svc__name { align-self: end; }
/* La numeracion y el nombre no usan la escala tipografica general sino un
   clamp solo en vi: la escala crece mas rapido que la columna de la grilla, y
   con --heading-1 una palabra como "electromecanicas" se desbordaba sobre la
   foto entre 48rem y 90rem. Atado a vi, la proporcion entre el ancho del
   titular y el de su columna se mantiene en todo el rango. */
.svc__num {
  grid-column: 1 / -1;
  font-size: clamp(1.75rem, 3.55vi, 4.5rem);
  font-weight: 500; letter-spacing: -0.035em; line-height: 1.2;
  font-variant-numeric: tabular-nums;
}
.svc__name {
  grid-column: 1 / -1;
  font-size: clamp(1.75rem, 3.55vi, 4.5rem);
  line-height: 1;
}
/* Hasta 48rem el nombre ocupa el ancho completo y no compite con la foto, asi
   que puede ir a la escala de la referencia (40px a 390) en vez de los 28px que
   deja el clamp en vi. Arriba de 48rem manda el clamp: es lo que evita que
   "electromecanicas" se desborde sobre la foto entre 48rem y 90rem. */
@media (max-width: 47.999rem) {
  .svc__name { font-size: clamp(2rem, 10.2vi, 2.5rem); }
}
.svc__thumb { grid-column: 1 / -1; }
.svc__thumb img {
  width: 100%; aspect-ratio: 16 / 7; object-fit: cover;
  border-radius: var(--radius-sm);
}

/* El listado cuelga de la hairline con 40px de aire, y sus items van en la
   escala de cuerpo, no de titulo: es lo que hace que la familia entera entre
   en un bloque compacto como en la referencia. */
.svc__list {
  grid-column: 1 / -1;
  padding-top: var(--space-lg);
  border-top: 1px solid var(--line);
  display: grid;
  gap: var(--space-sm) var(--space-md);
}
/* Sin hairlines entre items: en la referencia la unica linea es la que separa
   la cabecera de la familia de su listado. El aire entre items lo pone el gap
   de la grilla, no el padding: asi el ritmo no depende del alto de linea. */
.svc__list a, .svc__list span {
  display: inline-flex; align-items: baseline; gap: 0.5em;
  font-size: var(--heading-6); font-weight: 400; letter-spacing: -0.035em;
  line-height: 1.4;
  transition: color 0.4s var(--ease);
}
.svc__list .arrow-ne { font-size: 0.85em; color: var(--dark-beige); transition: transform 0.4s var(--ease); }
.svc__list li:hover .arrow-ne { transform: translate(2px, -2px); }
.svc__list li:hover a { color: var(--dark-beige); }

@media (min-width: 48rem) {
  .svc__num { grid-column: 1 / span 3; }
  .svc__name { grid-column: 4 / span 5; }
  .svc__thumb { grid-column: 9 / -1; }
  /* El listado y su hairline arrancan en la columna 4, alineados con el nombre
     de la familia; la hairline no cruza la pagina entera.
     Cinco filas y flujo por columnas, como en la referencia: la primera
     columna se llena hasta cinco items y recien ahi pasa a la segunda. Una
     familia mas corta ocupa una sola columna, y no media pagina vacia. */
  .svc__list {
    grid-column: 4 / -1;
    grid-template-rows: repeat(5, auto);
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    column-gap: var(--gap-fluid);
  }
}

/* --------------------------------------------------------------------------
   9. Expertise
   -------------------------------------------------------------------------- */
/* El listado de sectores manda y la imagen lo acompania: la columna de foto
   queda pinneada mientras la lista sube, y el sector que cruza la linea de
   lectura se enciende y saca el guion. Es exactamente el mecanismo de la
   referencia. Sin hairlines: lo que ordena la lista es la escala y el peso.
   Las clases is-active las pone initExpertiseScroll(). */
.exp__media {
  grid-column: 1 / -1;
  /* En Servicios el aire bajo el CTA lo pone el padding-top de la familia; aca
     no habia nada y el boton quedaba pegado a la foto y al primer sector. */
  margin-top: var(--space-xl);
  padding-bottom: var(--space-lg);
}
.exp__stack {
  position: relative;
  aspect-ratio: 15 / 8;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--beige);
}
.exp__shot {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}
.exp__shot.is-active { opacity: 1; }

.exp__list { grid-column: 1 / -1; }
.exp__row a {
  display: flex; align-items: center;
  font-size: var(--heading-expertise);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.035em;
  color: var(--charcoal);
  opacity: 0.4;
  transition: opacity 0.5s var(--ease);
}
.exp__row.is-active a { opacity: 1; }
@media (hover: hover) { .exp__row a:hover { opacity: 1; } }

/* El guion vive siempre en el DOM y lo que se anima es el ancho de su caja:
   inline-grid con una columna de 1em y overflow recortado, igual que en la
   referencia. Animar el ancho y no el contenido evita que la linea salte. */
.exp__dash {
  display: inline-grid;
  grid-template-columns: 1em;
  overflow: clip;
  width: 0;
  transition: width 0.6s var(--ease);
}
.exp__dash > span { display: block; }
.exp__row.is-active .exp__dash { width: 0.78em; }

/* 64rem y no 48rem como el resto de la pagina: partido en dos columnas a
   768px el listado se queda con 402px utiles mientras --heading-expertise sigue
   creciendo con el viewport (68.7px ahi), y "Agroindustria" se iba 40px afuera
   de su columna, por debajo de las pastillas de navegacion y arrastrando la
   pagina 8px en horizontal. Entre 48rem y 66rem conviene el apilado de mobile:
   la lista toma el ancho completo y entra con aire. El corte va en 66rem y no
   en 64rem porque justo en 1024px "Agroindustria" entra exacto, sin un pixel de
   margen contra el borde de su columna. */
@media (min-width: 66rem) {
  /* La foto se clava a 14rem del borde superior y se queda ahi mientras el
     listado recorre su alto. align-self:start es obligatorio: un item de
     grilla estirado no puede quedar sticky. */
  .exp__media {
    grid-column: 1 / span 5;
    position: sticky; top: 14rem;
    align-self: start;
    padding-bottom: 0;
    padding-right: var(--space-2xl);
  }
  /* El colchon inferior le da recorrido al ultimo sector: sin el, la lista se
     termina antes de que su ultima fila llegue a la linea de lectura. */
  /* Mismo colchon que la foto: en desktop el listado comparte fila con ella y
     arranca justo debajo del CTA. */
  .exp__list { grid-column: 6 / -1; margin-top: var(--space-xl); padding-bottom: 22vh; }
}

/* --------------------------------------------------------------------------
   10. Cultura
   -------------------------------------------------------------------------- */
/* Titulo monumental. Antes el tamano salia de una constante medida a mano
   sobre 100vw; con barra de scroll presente 100vw es mas ancho que la caja y
   la "o" final de "Cuidado" quedaba cortada contra el borde. Ahora lo calcula
   initFitText() sobre el ancho real del contenedor, midiendo la linea mas
   larga, asi que no hay constante que mantener ni desborde posible. */
.culture__title {
  grid-column: 1 / -1;
  /* align-items:flex-start es lo que permite medirlo: con el stretch por
     defecto cada linea ocupa el ancho de la caja y initFitText() mediria el
     contenedor en vez del texto. */
  display: flex; flex-direction: column; align-items: flex-start;
  line-height: 0.85;
  /* Mismo criterio que .section__word: ver el comentario de ahi. */
  letter-spacing: -0.012em;
  padding-bottom: var(--space-lg);
}
.culture__title > span { white-space: nowrap; }
.culture__title .row { display: flex; align-items: baseline; gap: 0.06em; }

/* El guion se cierra a medida que la seccion sube: initCultureDash() escribe
   el ancho. Mismo mecanismo que en el listado de Expertise. */
.culture__dash {
  display: inline-grid;
  grid-template-columns: 1em;
  overflow: clip;
  width: 0.85em;
}
.culture__dash > span { display: block; }

.culture__eyebrow { grid-column: 1 / -1; }
.culture__intro { grid-column: 1 / -1; padding-top: var(--space-sm); }
.culture__intro p { max-width: 45ch; font-size: var(--text-large); color: var(--darker-beige); }

.culture__media { grid-column: 1 / -1; padding-top: var(--space-lg); }
.culture__media img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }

/* Pilares: solo nombre y flecha entre hairlines, sin bajada. Las filas se
   reparten el alto disponible para que la columna termine a la par del video,
   como en la referencia. */
.culture__pillars {
  grid-column: 1 / -1;
  display: flex; flex-direction: column;
  padding-top: var(--space-lg);
}
.culture__pillars li { flex: 1 1 0; border-top: 1px solid rgba(28, 28, 28, 0.28); }
.culture__pillars li:last-child { border-bottom: 1px solid rgba(28, 28, 28, 0.28); }
.culture__pillar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-sm);
  width: 100%; height: 100%;
  padding-block: var(--space-sm);
  font-size: var(--heading-5);
  font-weight: 400;
  letter-spacing: -0.035em;
  line-height: 1.1;
  text-align: left;
  transition: color 0.4s var(--ease);
}
.culture__pillars .arrow-ne {
  flex: none; width: 1em; height: 1em;
  transition: transform 0.4s var(--ease);
}
.culture__pillars .arrow-ne svg { width: 100%; height: 100%; }
.culture__pillar:hover { color: var(--darker-beige); }
.culture__pillar:hover .arrow-ne { transform: translate(3px, -3px); }

/* --------------------------------------------------------------------------
   7c. Proposito — mision, vision y valores
   Estaba al pie de Cultura, donde quedaba huerfano detras de los cuatro
   pilares. Ahora es su propia seccion pegada a Nosotros, y el reparto va al
   reves que ahi (foto a la izquierda, texto a la derecha) para que dos
   secciones seguidas no repitan el mismo esquema.
   -------------------------------------------------------------------------- */
.creed__head { grid-column: 1 / -1; }
.creed {
  grid-column: 1 / -1;
  padding-top: var(--space-lg);
  display: grid; gap: var(--space-lg);
}
/* Mision y vision salen de la escala de cuerpo: son dos frases, no dos
   parrafos, y a este tamano se leen como declaracion. */
.creed__claim {
  font-size: var(--heading-4); font-weight: 400;
  letter-spacing: -0.03em; line-height: 1.25;
  color: var(--charcoal);
  padding-top: var(--space-2xs);
  max-width: 30ch;
}

/* --- Marquesina de valores --------------------------------------------- */
/* Sangra a todo el ancho de la ventana: es el unico bloque del sitio que se
   sale de .wrap, y de ahi que corte el ritmo de la pagina. */
.marquee {
  /* La seccion lleva .wrap, asi que el bloque nace con el padding lateral de
     la pagina. El margen negativo se lo saca y lo lleva borde a borde: es el
     unico elemento del sitio que sangra a todo el ancho de la ventana. */
  margin-top: var(--space-xl);
  margin-inline: calc(var(--pad-x) * -1);
  padding-block: var(--space-sm);
  border-block: 1px solid var(--line);
  overflow: hidden;
}
.marquee__track {
  display: flex; width: max-content;
  animation: marquee-run 48s linear infinite;
}
/* Al pasar el mouse se frena: si un valor interesa, se puede leer. */
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__set {
  display: flex; align-items: center;
  flex: none;
}
.marquee__set li {
  display: flex; align-items: center; gap: var(--space-md);
  padding-inline: 0 var(--space-md);
  white-space: nowrap;
  font-size: var(--heading-5); font-weight: 400; letter-spacing: -0.03em;
  color: var(--charcoal);
}
.marquee__set li::after { content: "↗"; color: var(--accent); }
@keyframes marquee-run {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
/* Con motion reducido la marquesina se detiene y pasa a ser una tira que se
   arrastra a mano: el contenido no depende de la animacion. */
@media (prefers-reduced-motion: reduce) {
  .marquee { overflow-x: auto; }
  .marquee__track { animation: none; }
  .marquee__set[aria-hidden="true"] { display: none; }
}
@media (min-width: 48rem) {
  .culture__eyebrow { grid-column: 1 / span 7; }
  .culture__intro { grid-column: 8 / -1; padding-top: 0; }
  .culture__media { grid-column: 1 / span 7; }
  .culture__pillars { grid-column: 8 / -1; }
  /* Mision y vision enfrentadas, cada una en media pagina. */
  .creed { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-fluid); align-items: start; }
}

/* --------------------------------------------------------------------------
   10b. Reseñas
   Cuatro citas en dos columnas que arrancan a distinta altura. Alineadas en
   filas se leian como una tabla de cuatro celdas iguales; desfasadas obligan a
   recorrerlas de a una, y de paso el bloque deja de tener una silueta
   rectangular. Sin tarjetas ni recuadros: cada cita cuelga de una hairline,
   que es como el resto del sitio separa cosas.
   -------------------------------------------------------------------------- */
.quotes {
  grid-column: 1 / -1;
  padding-top: var(--space-2xl);
  display: grid; gap: var(--space-2xl);
}

.quote {
  position: relative;
  padding-top: var(--space-lg);
  border-top: 1px solid var(--line);
}
/* Comilla de apertura sobredimensionada, montada sobre la hairline y saliendo
   de la caja por arriba. Es el mismo recurso que el wordmark del hero y los
   titulares de seccion: un glifo mas grande de lo que la caja pide.
   aria-hidden via ::before, asi que el lector no la anuncia. */
.quote::before {
  content: "“";
  position: absolute; top: 0; left: -0.06em;
  transform: translateY(-0.42em);
  font-size: clamp(4rem, 2rem + 6vi, 7rem);
  line-height: 1;
  color: var(--accent);
  opacity: 0.22;
  pointer-events: none;
}
.quote blockquote {
  position: relative;
  font-size: var(--heading-5); font-weight: 400;
  letter-spacing: -0.025em; line-height: 1.35;
  color: var(--charcoal);
  max-width: 42ch;
}
.quote figcaption {
  display: grid; gap: 0.1em;
  padding-top: var(--space-sm);
  font-size: var(--text-small); line-height: 1.35;
}
.quote__who { color: var(--charcoal); font-weight: 500; }
.quote__org { color: var(--dark-beige); }

@media (min-width: 48rem) {
  .quotes {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-2xl) var(--gap-fluid);
    align-items: start;
  }
  /* El desfasaje: la columna derecha arranca mas abajo que la izquierda, asi
     las cuatro citas no forman dos filas prolijas. */
  .quote:nth-child(even) { margin-top: var(--space-3xl); }
}

/* --------------------------------------------------------------------------
   11. Contacto
   -------------------------------------------------------------------------- */
/* En la referencia el cierre de la pagina es un unico bloque oscuro: contacto y
   footer comparten el fondo charcoal, sin costura entre ambos. Por eso aca se
   redefinen --line y los colores en vez de heredar los del cuerpo claro. */
.contact {
  /* Textura de hormigon como fondo del cierre. El velo va en el mismo
     background-image, como primera capa: sin el, la foto es casi blanca y ni el
     formulario ni el titular se leen. Al 0.93 la textura queda como una veladura
     y el contraste del texto es el mismo que sobre el charcoal plano.
     El color de fondo queda debajo por si la imagen no carga. */
  background-color: var(--charcoal);
  background-image:
    linear-gradient(rgba(28, 28, 28, 0.93), rgba(28, 28, 28, 0.93)),
    url("../images/texturas/contacto-sm.webp");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  color: var(--beige);
  /* La veladura aclara el fondo de #1c1c1c a ~#262626 y el texto secundario en
     --dark-beige caia a 4.0:1. Aca esa variable pasa a su version clara: mismo
     gris verdoso del manual, 6.0:1 sobre la textura. Solo aplica a esta seccion.
     El footer no lleva textura y no lo necesita. */
  --dark-beige: #9aa5a1;
  --line: var(--line-invert);
  /* El borde inferior de esta seccion y el superior del footer caen en el mismo
     pixel fraccionario, y por el antialias se colaba una linea del off-white de
     .page-over que esta detras. Esta sombra de 1px tapa la costura sin tocar el
     layout; la hairline del footer se pinta despues, encima. */
  box-shadow: 0 1px 0 0 var(--charcoal);
}
/* La cabecera ocupa el ancho completo y recien debajo la seccion se abre en
   dos columnas: datos de contacto a la izquierda, formulario a la derecha. */
/* La cabecera del cierre va una escala por debajo del resto de los titulares:
   es el pie de la pagina, no una seccion mas, y con --heading-1 mas el mail a
   gran escala el formulario arrancaba a media pantalla. */
.contact__head { grid-column: 1 / -1; }
/* El aire hasta el mail lo pone el row-gap del grid, no un padding: el mail es
   otro item de la grilla y los dos aires tienen que salir de la misma fuente. */
.contact__title { font-size: var(--heading-2); padding-block: var(--space-xs) 0; }
.contact__mail { grid-column: 1 / -1; }

.contact__info {
  grid-column: 1 / -1;
  display: grid; gap: var(--space-lg);
  align-content: start;
  padding-top: var(--space-lg);
  padding-bottom: var(--space-xl);
}
.contact__block h3 {
  font-size: var(--text-xsmall);
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--dark-beige);
  font-weight: 400;
  padding-bottom: var(--space-2xs);
}
.contact__block p { font-size: var(--text-small); }
.contact__block address { font-style: normal; }

/* El email es el CTA real del cierre: va a gran escala, subrayado y con el
   glifo de retorno delante, como en la referencia. */
.contact__mail {
  /* El email real tiene 34 caracteres: con --heading-2 (30px de piso) se iba
     200px afuera del viewport en mobile. Atado a vi con tope en la misma escala
     entra en todo el rango, y el overflow-wrap es la red de seguridad si
     mañana el email fuera todavia mas largo.
     2.4vi y no 4.6vi: a 66px el mail competia con el titular de la seccion y
     empujaba el formulario media pantalla para abajo. */
  font-size: clamp(0.95rem, 2.4vi, 1.9rem);
  font-weight: 400; letter-spacing: -0.035em;
  display: flex; align-items: baseline; gap: 0.35em;
}
.contact__mail a {
  border-bottom: 1px solid var(--line-invert);
  min-width: 0; overflow-wrap: anywhere;
}
.contact__mail .glyph { color: var(--dark-beige); }
.contact__form { grid-column: 1 / -1; }

.field { position: relative; padding-top: var(--space-md); }
.field input, .field textarea {
  width: 100%;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--text-base);
  transition: border-color 0.4s var(--ease);
}
.field textarea { resize: vertical; min-height: 3.5rem; }
.field label {
  position: absolute; left: 0; top: calc(var(--space-md) + 0.5rem);
  font-size: var(--text-base);
  color: var(--dark-beige);
  pointer-events: none;
  transform-origin: left top;
  transition: transform 0.4s var(--ease), color 0.4s var(--ease);
}
.field input:focus, .field textarea:focus { outline: none; border-color: var(--charcoal); }
.field input:focus + label,
.field textarea:focus + label,
.field input:not(:placeholder-shown) + label,
.field textarea:not(:placeholder-shown) + label {
  transform: translateY(-1.6rem) scale(0.72);
  color: var(--dark-beige);
}
.field .error {
  display: block; min-height: 1.2em;
  padding-top: 0.35rem;
  font-size: var(--text-xsmall);
  color: var(--error);
}
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"] { border-color: var(--error); }

.hp { position: absolute; left: -9999px; opacity: 0; pointer-events: none; }

.form__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-sm);
  padding-top: var(--space-lg);
}
.form__status { font-size: var(--text-small); color: var(--dark-beige); }
.form__status[data-state="error"] { color: var(--error); }
.form__status[data-state="ok"] { color: var(--charcoal); }
.btn[disabled] { opacity: 0.5; pointer-events: none; }

/* El formulario ahora vive sobre charcoal: hay que invertir lo que estaba
   resuelto para fondo claro, o el boton y el foco quedan invisibles. */
/* Sobre charcoal la pildora se invierte entera: fondo beige y el cuadrado de
   la flecha en charcoal. Si solo se invirtiera el fondo, el cuadrado quedaria
   beige sobre beige y desapareceria. */
.contact .btn { background: var(--beige); color: var(--charcoal); }
.contact .btn__icon { background: var(--charcoal); color: var(--beige); }
.contact .field input:focus, .contact .field textarea:focus { border-color: var(--beige); }
.contact .form__status[data-state="ok"] { color: var(--beige); }
.contact .field .error { color: #ff8c8c; }
.contact .field input[aria-invalid="true"],
.contact .field textarea[aria-invalid="true"] { border-color: #ff8c8c; }
.contact :focus-visible { outline-color: var(--beige); }

@media (min-width: 48rem) {
  .contact {
    background-image:
      linear-gradient(rgba(28, 28, 28, 0.93), rgba(28, 28, 28, 0.93)),
      url("../images/texturas/contacto-md.webp");
  }
  /* Tres filas: cabecera, mail y datos. El row-gap baja a space-sm porque ahora
     separa el titular del mail; el aire hasta los datos lo pone el padding-top
     de .contact__info, que es el unico que tiene que ser grande. */
  .contact .grid { row-gap: var(--space-sm); }
  .contact__head { grid-column: 1 / span 6; }
  .contact__mail { grid-column: 1 / span 5; }
  .contact__info {
    grid-column: 1 / span 5;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-lg) var(--gap-fluid);
    padding-top: var(--space-2xl);
    padding-bottom: 0;
  }
  /* El formulario arranca en la fila del mail y baja hasta la de los datos. Asi
     su primera linea queda a la altura del mail sin medir nada a mano; el
     margen negativo solo compensa el padding-top del primer .field. */
  .contact__form {
    grid-column: 7 / -1;
    grid-row: 2 / span 2;
    margin-top: calc(-1 * var(--space-md));
  }
  .form__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--gap-fluid); }
  .field--full { grid-column: 1 / -1; }
}

/* --------------------------------------------------------------------------
   12. Footer
   -------------------------------------------------------------------------- */
/* El footer comparte el cierre oscuro con #contacto pero no es la misma pieza:
   un tono mas profundo y una hairline lo separan. Antes eran un unico bloque
   continuo (asi esta en la referencia) y no se leia donde terminaba el
   formulario y empezaba la informacion de la empresa. */
.site-footer {
  background: var(--charcoal-deep);
  color: var(--beige);
  --line: var(--line-invert);
  border-top: 1px solid var(--line-invert);
}
.footer__top { padding-block: var(--space-2xl) var(--space-lg); }
/* El wordmark abre el footer y las columnas quedan debajo, separadas por la
   hairline. Es el unico lugar del cierre donde aparece la marca. */
.footer__brand { display: block; padding-bottom: var(--space-lg); }
.footer__logo { width: clamp(9rem, 22vw, 15rem); height: auto; }
.footer__cols { display: grid; gap: var(--space-lg); }
.footer__col h3 { font-size: var(--text-xsmall); text-transform: uppercase; letter-spacing: 0.08em; color: var(--dark-beige); font-weight: 400; padding-bottom: var(--space-2xs); }
.footer__col p, .footer__col a { font-size: var(--text-small); }
.footer__col li + li { margin-top: 0.35em; }
.footer__nav a { display: inline-flex; gap: 0.4em; align-items: baseline; text-transform: uppercase; letter-spacing: 0.08em; font-size: var(--text-xsmall); }

.socials { display: flex; gap: var(--space-sm); padding-top: var(--space-md); }
.socials a { display: grid; place-items: center; width: 2.75rem; height: 2.75rem; border: 1px solid var(--line-invert); border-radius: 999px; transition: background 0.4s var(--ease), color 0.4s var(--ease); }
.socials a:hover { background: var(--beige); color: var(--charcoal); }
.socials svg { width: 21px; height: 21px; }

.footer__legal {
  display: flex; flex-wrap: wrap; gap: var(--space-xs) var(--space-md);
  /* Quedo un solo bloque (el copyright), asi que va centrado y no repartido. */
  justify-content: center;
  text-align: center;
  padding-block: var(--space-md);
  border-top: 1px solid var(--line-invert);
  font-size: var(--text-xsmall);
  color: var(--dark-beige);
}
.footer__legal a { color: var(--beige); }

@media (min-width: 48rem) {
  .footer__cols { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------------------
   13. Panel lateral de Cultura
   Medidas tomadas de la referencia: panel a la derecha de 48rem de ancho maximo
   y alto de viewport, charcoal al 80% con blur de 24px por detras, esquinas
   izquierdas redondeadas y velo charcoal al 50% sobre el resto de la pagina.
   Entra corriendo 300px hacia la izquierda (no el ancho completo: el
   desplazamiento corto con curva larga es lo que da la sensacion de peso).
   -------------------------------------------------------------------------- */
.drawer {
  position: fixed; inset: 0; z-index: 210;
  visibility: hidden;
  /* El panel cerrado vive 300px a la derecha del viewport y, aunque el contenedor
     sea fixed, alrededor de 48rem eso hacia crecer el scrollWidth y la pagina se
     podia arrastrar 8px en horizontal (body tiene overflow-x: hidden, pero el
     que scrollea es el elemento raiz). Recortando aca el panel no puede empujar
     el layout, y abierto no se recorta nada porque el contenedor es el viewport. */
  overflow: hidden;
  /* Igual que en el modal: visibility con delay y no interpolada, si no el
     panel sigue computando hidden al abrir y no acepta el foco. */
  transition: visibility 0s linear 0.6s;
}
.drawer.is-open { visibility: visible; transition: visibility 0s linear 0s; }

.drawer__backdrop {
  position: absolute; inset: 0;
  background: rgba(28, 28, 28, 0.5);
  opacity: 0;
  cursor: pointer;
  transition: opacity 0.35s var(--ease);
}
.drawer.is-open .drawer__backdrop { opacity: 1; }

.drawer__panel {
  position: absolute; top: 0; right: 0;
  width: 100%; max-width: 48rem;
  height: 100%;
  display: flex; flex-direction: column;
  padding: var(--space-md);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: rgba(28, 28, 28, 0.8);
  -webkit-backdrop-filter: blur(24px);
  backdrop-filter: blur(24px);
  border-radius: var(--radius) 0 0 var(--radius);
  color: var(--beige);
  /* El panel es una isla oscura: las hairlines de adentro tienen que ser las
     invertidas, como en el cierre de la pagina. */
  --line: var(--line-invert);
  transform: translateX(300px);
  opacity: 0;
  transition: transform 0.75s var(--ease), opacity 0.5s var(--ease);
}
.drawer.is-open .drawer__panel { transform: none; opacity: 1; }

/* Cabecera: eyebrow a la izquierda, cerrar a la derecha, y la hairline debajo
   separando la cabecera del titular. */
.drawer__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-sm);
  padding-bottom: var(--space-xs);
  border-bottom: 1px solid var(--line);
}
.drawer__close {
  font-size: var(--text-base); font-weight: 500;
  letter-spacing: -0.035em;
  color: var(--off-white);
  transition: color 0.4s var(--ease);
}
.drawer__close:hover { color: var(--dark-beige); }

.drawer__title {
  padding-top: var(--space-lg);
  font-size: var(--heading-2);
  line-height: 1;
  color: var(--off-white);
}
.drawer__lead { padding-top: var(--space-md); max-width: 46ch; }

/* Listado de la ficha: filas entre hairlines, en gris y a escala de cuerpo. La
   ultima cierra con su propia linea, como en la referencia. */
.drawer__list { padding-top: var(--space-lg); }
.drawer__list li {
  padding-block: 0.625rem;
  border-top: 1px solid var(--line);
  color: var(--dark-beige);
}
.drawer__list li:last-child { border-bottom: 1px solid var(--line); }

.drawer__text { padding-top: var(--space-lg); max-width: 52ch; }

@media (min-width: 48rem) {
  .drawer__panel { padding: var(--space-lg); }
}

/* --------------------------------------------------------------------------
   14. Modal de privacidad
   -------------------------------------------------------------------------- */
.modal {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  padding: var(--pad-x);
  visibility: hidden; opacity: 0;
  /* visibility con delay en vez de transicion: si se interpola, el panel sigue
     computando hidden al abrir y no acepta el foco. */
  transition: opacity 0.4s var(--ease), visibility 0s linear 0.4s;
}
.modal.is-open {
  visibility: visible; opacity: 1;
  transition: opacity 0.4s var(--ease), visibility 0s linear 0s;
}
.modal__backdrop { position: absolute; inset: 0; background: rgba(28, 28, 28, 0.6); }
.modal__panel {
  position: relative;
  width: min(46rem, 100%);
  max-height: min(80vh, 44rem);
  overflow-y: auto;
  background: var(--off-white);
  color: var(--charcoal);
  padding: var(--space-lg);
  transform: translateY(16px);
  transition: transform 0.5s var(--ease);
}
.modal.is-open .modal__panel { transform: translateY(0); }
.modal__panel h2 { font-size: var(--heading-4); padding-bottom: var(--space-sm); }
.modal__panel h3 { font-size: var(--text-base); font-weight: 500; padding-top: var(--space-sm); }
.modal__panel p { font-size: var(--text-small); padding-top: var(--space-3xs); max-width: 68ch; }
.modal__close {
  position: absolute; top: var(--space-sm); right: var(--space-sm);
  width: 2rem; height: 2rem; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 999px;
  transition: background 0.4s var(--ease), color 0.4s var(--ease);
}
.modal__close:hover { background: var(--charcoal); color: var(--off-white); }

/* --------------------------------------------------------------------------
   15. Preferencias de movimiento reducido
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal, .word-mask > span, .img-mask img { opacity: 1 !important; transform: none !important; }
  /* Sin animacion las pastillas tienen que arrancar visibles: el delay no se
     resetea con animation-duration y quedarian en blanco casi un segundo. */
  .pill-nav li { opacity: 1 !important; animation: none !important; }
}

/* --------------------------------------------------------------------------
   16. Video (Plyr) — tematizado con la paleta de la marca
   -------------------------------------------------------------------------- */
/* El atributo height="720" del <video> gana contra el aspect-ratio del wrapper
   de Plyr y estiraba el reproductor a 720px de alto. Fijar la relacion en el
   propio video lo devuelve a 16:9 con o sin Plyr montado. */
.culture__media video,
.culture__media .plyr { width: 100%; }
.culture__media video { height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.culture__media .plyr__video-wrapper--fixed-ratio video { height: 100%; }
.culture__media .plyr--video { background: var(--charcoal); }
.plyr {
  --plyr-color-main: var(--beige);
  --plyr-video-background: var(--charcoal);
  --plyr-video-control-color: var(--beige);
  --plyr-range-thumb-background: var(--beige);
  --plyr-font-family: "Figtree", system-ui, sans-serif;
  --plyr-border-radius: 0;
}
.plyr__control--overlaid { background: rgba(214, 211, 208, 0.9); color: var(--charcoal); }
.plyr__control--overlaid:hover { background: var(--beige); }
