/* ==========================================================================
   NÍTIDOS — sistema de diseño
   Base blanca, naranja con presencia real, Archivo como única familia.
   La jerarquía se construye con peso + ancho + caja, no con más fuentes.
   ========================================================================== */

:root {
  /* --- Color --- */
  --o:        #ff6633;   /* naranja de marca: fondos, fills, íconos */
  --o-deep:   #e85a2b;   /* 3.5:1 sobre blanco: solo texto grande y hover */
  --o-text:   #c2410c;   /* 5.2:1 sobre blanco: texto chico y errores */
  --o-wash:   #fff4f0;   /* naranja lavado para superficies */

  --ink:      #0a0a0a;
  --ink-2:    #1c1c1c;
  --paper:    #ffffff;
  --mute:     #6b6862;   /* 5.6:1 sobre blanco */
  --faint:    #a8a49d;   /* decorativo, nunca texto */
  --line:     #e6e3de;
  --line-2:   #d6d2cb;

  /* Sobre naranja el blanco da 2.9:1 y no cumple AA. Todo el texto sobre
     naranja es ink (6.8:1) o este tono quemado del mismo hue (5.5:1). */
  --on-o:      var(--ink);
  --on-o-soft: #3d1605;

  /* Sobre ink */
  --on-ink:      #ffffff;   /* 19.8:1 */
  --on-ink-soft: #a8a49d;   /* 7.6:1 */
  --line-ink:    #2a2a2a;
  --on-media:    #d4d0c9;   /* metadatos sobre foto con velo */

  /* --- Tipografía: una sola familia, eje de ancho --- */
  --font: "Archivo", "Archivo Fallback", system-ui, -apple-system, sans-serif;

  --fs-hero:  clamp(2.25rem, 1.2rem + 3.9vw, 4rem);
  --fs-h2:    clamp(2rem,   1.2rem + 3.2vw, 3.75rem);
  --fs-h3:    clamp(1.35rem, 1.1rem + 1.1vw, 1.9rem);
  --fs-h4:    clamp(1.1rem, 1rem + 0.5vw, 1.3rem);
  --fs-lede:  clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
  --fs-body:  1rem;
  --fs-sm:    0.875rem;
  --fs-xs:    0.75rem;

  /* --- Espaciado 8pt --- */
  --s1: 4px;  --s2: 8px;  --s3: 16px; --s4: 24px;
  --s5: 32px; --s6: 48px; --s7: 64px; --s8: 96px; --s9: 128px;

  /* --- Ejes tipográficos del mundo --- */
  --wdth-display: 120;
  --wdth-rotulo:  82;
  --wdth-cuerpo:  100;

  /* --- Radios --- */
  --r-0: 0px;
  --r: 10px;
  --r-xl: clamp(20px, 2.2vw, 32px);   /* piezas grandes: panel de servicios */
  --r-pill: 999px;

  /* --- Motion --- */
  /* Tres curvas, una por tipo de movimiento. Las tres son de salida: la
     sensación de suavidad viene del frenado largo, no de la duración.
     La anterior --ease (.2,.7,.2,1) recorría 70% de la distancia en 20% del
     tiempo: eso es lo que se leía como tirón. La anterior --ease-soft
     (.4,0,.2,1) arrancaba lenta, y por eso los zooms se sentían con retardo. */
  --ease:      cubic-bezier(.215, .61, .355, 1);  /* interacción, hover, UI  */
  --ease-soft: cubic-bezier(.165, .84, .44, 1);   /* recorridos largos, zooms */
  --ease-mov:  cubic-bezier(.32, .72, 0, 1);      /* paneles que entran y salen */
  /* easeInOutQuad, del mismo repertorio del que salen --ease y --ease-soft.
     Se usa donde una superficie grande cambia de tamaño en pantalla. Su
     virtud no es el arranque —parte lento— sino la velocidad pico: 1,82x la
     media, contra 4,22x de --ease-mov y 5,05x de --ease-soft. Ese pico es lo
     que se percibe como tirón, y acá es lo que había que bajar. */
  --ease-morfeo: cubic-bezier(.455, .03, .515, .955);
  --t-fast: 180ms;
  --t:      260ms;
  --t-slow: 440ms;
  --t-rev:  660ms;                                /* apariciones al scrollear */
  --t-panel: 700ms;                               /* el acordeón de servicios */

  /* --- Layout --- */
  --maxw: 1340px;
  --gut: clamp(20px, 4.5vw, 60px);
  --nav-h: 76px;
}

/* ==========================================================================
   RESET
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + var(--s4));
  color-scheme: light;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.6;
  font-variation-settings: "wdth" 100;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg, video { display: block; max-width: 100%; }
img, video { height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }
ul, ol { margin: 0; padding: 0; list-style: none; }
p { margin: 0; }

/* El display usa Archivo expandido: es lo que le da el aire de estudio.
   El texto vuelve a ancho normal para no perder legibilidad. */
h1, h2, h3, h4 {
  margin: 0;
  font-weight: 700;
  font-variation-settings: "wdth" 112;
  letter-spacing: -0.028em;
  line-height: 1.02;
  text-wrap: balance;
}
h3, h4 { font-variation-settings: "wdth" 105; letter-spacing: -0.018em; line-height: 1.15; }

/* --- Superficies del navegador --- */
::selection { background: var(--o); color: var(--ink); }
.on-ink ::selection, #equipo ::selection { background: var(--o); color: var(--ink); }
:root { accent-color: var(--o); caret-color: var(--o-deep); }
* { scrollbar-color: var(--line-2) var(--paper); scrollbar-width: thin; }
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--paper); }
::-webkit-scrollbar-thumb { background: var(--line-2); border: 3px solid var(--paper); border-radius: var(--r-pill); }
::-webkit-scrollbar-thumb:hover { background: var(--faint); }

:focus-visible { outline: 2px solid var(--o-deep); outline-offset: 3px; border-radius: 3px; }
.on-ink :focus-visible, .on-orange :focus-visible { outline-color: var(--paper); }

.num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

.skip-link {
  position: absolute; top: -200px; left: var(--s3); z-index: 300;
  background: var(--ink); color: var(--paper);
  padding: var(--s3) var(--s4); border-radius: var(--r); font-weight: 500;
}
.skip-link:focus-visible { top: var(--s3); }

/* ==========================================================================
   PRIMITIVAS
   ========================================================================== */
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gut); }
.section { padding-block: clamp(var(--s7), 8vw, var(--s9)); }
.section-sm { padding-block: clamp(var(--s6), 5vw, var(--s8)); }

.on-ink { background: var(--ink); color: var(--on-ink); }
.on-orange { background: var(--o); color: var(--on-o); }

/* Etiqueta de sección: versalita ancha en naranja. Es el hilo que repite
   el color a lo largo de la página sin recurrir a fondos naranjas. */
.kicker {
  display: flex; align-items: center; gap: var(--s3);
  font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--o-text);
  font-variation-settings: "wdth" 108;
  margin-bottom: var(--s4);
}
.kicker::before { content: ""; width: 28px; height: 3px; background: var(--o); flex: none; }
.on-ink .kicker { color: var(--o); }
.on-orange .kicker { color: var(--on-o-soft); }
.on-orange .kicker::before { background: var(--ink); }

/* La voz display del hero, no la simulada con el eje de ancho de Archivo.
   Hasta acá ".h2" y ".h2-placa" eran la misma idea con dos tratamientos
   distintos porque nacieron en momentos distintos del sitio: quedan
   unificadas en una sola regla. */
.h2 {
  font-family: "Big Shoulders Display", "Archivo", system-ui, sans-serif;
  font-weight: 800;
  font-size: clamp(2.3rem, 1.2rem + 3.6vw, 4.4rem); max-width: 17ch;
  font-variation-settings: normal;
  letter-spacing: -0.012em; line-height: .9;
  text-transform: uppercase; text-wrap: balance;
}
#equipo .h2 { max-width: 13ch; }
/* Rótulo de señalética: condensado y espaciado, como se escribe en una placa
   cuando el ancho manda. No se usa sobre titulares —eso sería un kicker— sino
   para nombrar piezas: una placa de dato, una estación del proceso. */
.rotulo {
  display: block;
  font-size: var(--fs-xs); font-weight: 700;
  font-variation-settings: "wdth" var(--wdth-rotulo), "wght" 700;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.lede { font-size: var(--fs-lede); color: var(--mute); max-width: 56ch; line-height: 1.55; }
.on-ink .lede { color: var(--on-ink-soft); }
.on-orange .lede { color: var(--on-o-soft); }

.sec-head { margin-bottom: clamp(var(--s6), 5vw, var(--s7)); }
.sec-head .lede { margin-top: var(--s4); }

/* El naranja puro sobre blanco no llega a AA. En display grande usamos el
   naranja profundo, que sí cumple el 3:1 de texto grande. */
.accent { color: var(--o-deep); }
.on-ink .accent { color: var(--o); }
.on-orange .accent { color: var(--paper); }

/* ==========================================================================
   BOTONES
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: 52px; padding: 0 var(--s5);
  border-radius: var(--r-pill);
  font-size: var(--fs-sm); font-weight: 600; letter-spacing: 0.01em;
  font-variation-settings: "wdth" 104;
  white-space: nowrap; border: 1.5px solid transparent;
  transition: background-color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.btn:active { transform: scale(.975); }
.btn .arrow { transition: transform var(--t) var(--ease); }
@media (hover: hover) and (pointer: fine) { .btn:hover .arrow { transform: translateX(3px); } }

/* Sobre blanco */
.btn-primary { background: var(--o); color: var(--ink); }
.btn-primary:hover { background: var(--o-deep); }
.btn-ghost { border-color: var(--line-2); color: var(--ink); }
.btn-ghost:hover { border-color: var(--ink); background: var(--ink); color: var(--paper); }

/* Sobre naranja */
.on-orange .btn-primary { background: var(--ink); color: var(--paper); }
.on-orange .btn-primary:hover { background: var(--ink-2); }
.on-orange .btn-ghost { border-color: var(--ink); color: var(--ink); }
.on-orange .btn-ghost:hover { background: var(--ink); color: var(--paper); }

/* Sobre ink */
.on-ink .btn-primary { background: var(--o); color: var(--ink); }
.on-ink .btn-primary:hover { background: var(--o-deep); }
.on-ink .btn-ghost { border-color: var(--line-ink); color: var(--paper); }
.on-ink .btn-ghost:hover { background: var(--paper); color: var(--ink); border-color: var(--paper); }

.btn-lg { min-height: 58px; padding: 0 var(--s6); font-size: var(--fs-body); }

.tag {
  display: inline-flex; align-items: center; padding: 6px var(--s3);
  border: 1px solid var(--line); border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: 500; letter-spacing: 0.03em;
  color: var(--mute); background: var(--paper);
}
.on-ink .tag { border-color: var(--line-ink); color: var(--on-ink-soft); background: transparent; }

/* ==========================================================================
   NAV — recuperado de la versión anterior: fija, transparente arriba,
   esmerilada al bajar, logo teñido de naranja, CTA en píldora.
   ========================================================================== */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  border-bottom: 1px solid transparent;
  transition: background-color var(--t) var(--ease),
              backdrop-filter var(--t) var(--ease),
              border-color var(--t) var(--ease),
              box-shadow var(--t) var(--ease);
}
.site-header.is-scrolled {
  background: rgba(255,255,255,.88);
  backdrop-filter: saturate(140%) blur(14px);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  border-bottom-color: var(--line);
  box-shadow: 0 1px 8px rgba(0,0,0,.04);
}

.nav-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s6);
  height: var(--nav-h);
}

.brand { display: inline-flex; align-items: center; flex-shrink: 0; }
.brand-logo {
  height: 44px; width: auto; display: block;
  /* El logo original es blanco; este filtro lo lleva al naranja de marca. */
  filter: brightness(0) saturate(100%) invert(56%) sepia(81%) saturate(1478%) hue-rotate(338deg) brightness(101%) contrast(101%);
  transform-origin: left center;
  /* Solo transform anima. El filtro cambia de "none"/brightness(0) a la
     cadena naranja de 8 funciones al cruzar is-scrolled: son formas de
     filtro distintas y CSS no las interpola, solo puede saltar entre ellas
     — intentar animarlas igual produce un glitch cromático a mitad de
     camino. El salto ocurre igual, pero de golpe y sin pasar por colores
     intermedios raros. */
  transition: transform var(--t) var(--ease);
}
.site-header.is-scrolled .brand-logo { transform: scale(.86); }

.nav-links { display: none; gap: var(--s7); align-items: center; }
.nav-links a {
  position: relative; padding: 6px 0;
  font-size: var(--fs-sm); font-weight: 500; color: var(--mute);
  transition: color var(--t-fast) var(--ease);
}
.nav-links a:hover { color: var(--ink); }
.nav-links a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px; background: var(--o);
  /* scaleX en vez de animar `right`: `right` es una propiedad de layout y
     obliga a recalcular la caja en cada fotograma. El transform va en GPU. */
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--t) var(--ease);
}
@media (hover: hover) and (pointer: fine) { .nav-links a:hover::after { transform: scaleX(1); } }

.nav-cta {
  display: none; align-items: center; gap: var(--s2);
  min-height: 44px; padding: 0 var(--s4);
  background: var(--o); color: var(--ink);
  border-radius: var(--r-pill);
  font-size: var(--fs-sm); font-weight: 600;
  font-variation-settings: "wdth" 104;
  transition: background-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.nav-cta:hover { background: var(--o-deep); }
.nav-cta:active { transform: scale(.975); }
.nav-cta .arrow { transition: transform var(--t) var(--ease); }
@media (hover: hover) and (pointer: fine) { .nav-cta:hover .arrow { transform: translateX(3px); } }

.menu-btn {
  display: inline-flex; width: 44px; height: 44px;
  align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: var(--o-wash); border: 1px solid var(--line); color: var(--ink);
  transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.menu-btn:hover { border-color: var(--ink); }

@media (min-width: 940px) {
  .nav-links { display: flex; }
  .nav-cta { display: inline-flex; }
  .menu-btn { display: none; }
}

/* Drawer: baja desde arriba, como en la versión anterior */
.drawer {
  position: fixed; inset: 0; z-index: 200;
  background: var(--paper);
  display: flex; flex-direction: column;
  padding: 16px var(--gut) var(--s6);
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform var(--t-slow) var(--ease-mov), visibility var(--t-slow);
}
.drawer.is-open { transform: translateY(0); visibility: visible; }
.drawer-top { display: flex; justify-content: space-between; align-items: center; height: 60px; }
.drawer-top .brand-logo { height: 40px; }
.drawer-links { margin: auto 0; display: flex; flex-direction: column; gap: var(--s3); }
.drawer-links a {
  font-size: clamp(2rem, 9vw, 3rem); font-weight: 700;
  font-variation-settings: "wdth" 110; letter-spacing: -0.03em;
  line-height: 1.05; color: var(--ink);
}
.drawer-links a:hover { color: var(--o-deep); }
.drawer-cta {
  display: flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: 54px; margin-top: var(--s5);
  background: var(--o); color: var(--ink);
  border-radius: var(--r-pill); font-weight: 600;
}
.drawer-foot {
  margin-top: var(--s5); padding-top: var(--s4);
  border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; gap: var(--s3);
  font-size: var(--fs-xs); letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--mute);
}
body.is-locked { overflow: hidden; }

/* --------------------------------------------------------------------------
   HERO — foto de rodaje a la derecha, texto sobre tinta a la izquierda
   Estructura tomada de una referencia del cliente (13-sep): sujeto a un lado,
   fondo que continúa liso bajo la columna de texto, desvanecido inferior hacia
   la sección siguiente. Acá el suelo es ink porque «Qué hacemos» también lo
   es: la foto se funde en el mismo negro por la izquierda y por abajo, así que
   no hay borde de imagen visible en ningún lado.

   Los degradados son la excepción al patrón de foto a sangre (que pide velo
   plano) y tienen una razón: la foto ocupa solo parte del bloque, y un velo
   plano no la funde con el suelo, la oscurece entera.
   -------------------------------------------------------------------------- */
.hero {
  /* El marco de la foto arranca a una distancia fija del borde de la
     columna de texto, no a un porcentaje del viewport. Con porcentaje, el
     contenedor centrado y el marco se desplazaban a ritmos distintos y el
     hombro iluminado del camarógrafo caía detrás de «EQUIPO» a 1024 y a
     1920 px: 1,6:1 contra el naranja, medido. */
  --col-borde: max(var(--gut), (100% - var(--maxw)) / 2 + var(--gut));
  --foto-desde: 480px;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex; align-items: center;
  min-height: clamp(640px, 100svh, 980px);
  padding-top: var(--nav-h);
  background: var(--ink);
}
.hero-media {
  position: absolute; top: 0; right: 0; bottom: 0; z-index: -1;
  left: calc(var(--col-borde) + var(--foto-desde));
  /* Dos fundidos que se intersectan: hacia la izquierda, donde vive el texto,
     y hacia abajo, donde el hero se funde en la tinta de "Qué hacemos" —desde
     el 19-sep son un solo bloque oscuro continuo, sin la cinta que antes
     marcaba la costura. */
  /* El tramo superior protege la nav: sobre fotos claras arriba —el techo del
     drone, las líneas de código— el logo y los enlaces blancos se perdían. */
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 46%),
                      linear-gradient(to bottom, transparent 0, #000 calc(var(--nav-h) * 1.8), #000 58%, transparent 100%);
  -webkit-mask-composite: source-in;
          mask-image: linear-gradient(to right, transparent 0, #000 46%),
                      linear-gradient(to bottom, transparent 0, #000 calc(var(--nav-h) * 1.8), #000 58%, transparent 100%);
          mask-composite: intersect;
}
.hero-media picture { display: contents; }
/* Póster y video comparten encuadre: si no coinciden, se ve un salto en el
   instante en que el video entra. El encuadre se ajusta por página con
   --foto-pos, porque cada foto tiene al sujeto en otro lugar. */
.hero-media img, .hero-media video {
  width: 100%; height: 100%;
  object-fit: cover; object-position: var(--foto-pos, 40% 30%);
}
/* El video va sobre el póster y entra recién cuando puede reproducir: el
   póster pinta el LCP. */
.hero-video {
  position: absolute; inset: 0;
  opacity: 0; transition: opacity var(--t-rev) var(--ease-soft);
}
.hero-video.is-ready { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .hero-video { display: none; } }
.hero-in { width: 100%; padding-block: clamp(var(--s6), 6vw, var(--s8)); }
.hero-col { max-width: min(640px, 57%); }

/* Rótulo de sitio en píldora: dice qué es y dónde, que es la primera
   pregunta de quien llega desde una búsqueda. El punto es la luz de
   grabación de una cámara, no un adorno genérico. */
.hero-sitio {
  display: inline-flex; align-items: center; gap: 10px;
  margin-bottom: var(--s5);
  padding: 8px 16px 8px 13px;
  border: 1px solid rgba(255,255,255,.14);
  border-radius: var(--r-pill);
  /* Tinte claro sobre una base oscura translúcida: sobre tinta se ve igual
     que el tinte solo, pero sobre un fotograma claro —el techo del drone en
     audiovisual, a 390 px— la base sostiene las migas. Sin ella, 4,28:1. */
  background: linear-gradient(rgba(255,255,255,.07), rgba(255,255,255,.07)), rgba(10,10,10,.55);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  font-size: var(--fs-xs); font-weight: 600;
  font-variation-settings: "wdth" var(--wdth-rotulo), "wght" 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--on-ink);
}
.hero-sitio::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--o); box-shadow: 0 0 0 3px rgba(255,102,51,.22);
}
.hero h1 {
  font-family: "Big Shoulders Display", "Archivo", system-ui, sans-serif;
  font-weight: 900;
  font-size: clamp(3rem, 1.1rem + 5.4vw, 6.4rem);
  line-height: .97; letter-spacing: -0.005em;
  text-transform: uppercase; text-wrap: balance;
  color: var(--on-ink); margin: 0;
}
.hero h1 .accent { color: var(--o); }
.hero-bajada {
  margin: var(--s4) 0 0; max-width: 46ch;
  font-size: var(--fs-lede); line-height: 1.5;
  color: var(--on-media);
}
.hero-ctas { display: flex; flex-wrap: wrap; gap: var(--s3); margin-top: var(--s5); }

/* Botón claro con ícono en círculo: la píldora blanca es lo que más pesa en
   el bloque, y el círculo naranja mantiene el acento de marca en el único
   punto donde se hace click. */
.btn-claro {
  gap: var(--s3);
  padding: 0 7px 0 var(--s5);
  background: var(--paper); color: var(--ink);
}
.btn-claro:hover { background: #f1efec; }
.btn-ico {
  display: grid; place-items: center;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--o); color: var(--ink);
  transition: transform var(--t) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .btn-claro:hover .btn-ico { transform: rotate(45deg); }
}
.hero .btn-ghost { border-color: rgba(255,255,255,.55); }

/* Los cuatro oficios en fila solapada, y los compromisos debajo. */
.hero-oficios { margin-top: clamp(var(--s6), 6vw, var(--s8)); }
.hero-iconos { display: flex; }
.hero-iconos li {
  display: grid; place-items: center;
  width: 48px; height: 48px; border-radius: 50%;
  background: var(--ink-2); color: var(--on-ink);
  border: 2px solid var(--ink);
  box-shadow: 0 0 0 1px rgba(255,255,255,.2);
}
.hero-iconos li + li { margin-left: -10px; }
/* En naranja, el oficio de la página actual. */
.hero-iconos .es-actual { background: var(--o); color: var(--ink); }
.hero-sellos {
  margin-top: var(--s3);
  font-size: var(--fs-sm); color: var(--on-media);
}

/* Sobre la foto, la nav entera pasa a negativo: enlaces y logo en blanco
   —el logo en su silueta original, sin el filtro que lo tiñe de naranja— y
   el CTA en la misma píldora blanca del hero. La usan la home y las cuatro
   landings. Al hacer scroll la nav se vuelve blanca y todo recupera el
   esquema normal: una silueta blanca sobre blanco desaparece. */
.nav-negativa .site-header:not(.is-scrolled) .nav-links a { color: var(--paper); }
.nav-negativa .site-header:not(.is-scrolled) .nav-links a::after { background: var(--paper); }
.nav-negativa .site-header:not(.is-scrolled) .brand-logo { filter: none; }
.nav-negativa .site-header:not(.is-scrolled) .nav-cta { background: var(--paper); color: var(--ink); }
.nav-negativa .site-header:not(.is-scrolled) .nav-cta:hover { background: #f1efec; }

/* Entrada: la foto se asienta desde un leve acercamiento y la columna sube
   escalonada. Corta a propósito: es lo primero que pinta la página. */
@media (prefers-reduced-motion: no-preference) {
  /* Con la escena 3D de automatizaciones el texto lo revela su propia
     coreografía (ver «HERO CON ESCENA 3D»): una animación acá le ganaría a
     esas reglas y el texto aparecería antes de que la escena despeje. */
  .js .hero-media img { animation: hero-asienta 1600ms var(--ease-soft) both; }
  .js:not(.spline-ready) .hero-col > * { animation: hero-sube 700ms var(--ease-soft) both; }
  .js:not(.spline-ready) .hero-col > :nth-child(2) { animation-delay: 80ms; }
  .js:not(.spline-ready) .hero-col > :nth-child(3) { animation-delay: 160ms; }
  .js:not(.spline-ready) .hero-col > :nth-child(4) { animation-delay: 240ms; }
  .js:not(.spline-ready) .hero-col > :nth-child(5) { animation-delay: 320ms; }
}
/* Landings de servicio. Sus titulares son más largos que el de la home
   (hasta 27 caracteres por línea contra 15). El tope sale de medir la línea
   más larga —«CON DIRECCIÓN DE ARTE REAL.», 723 px a 66,5 px de cuerpo— contra
   la columna de 640: a 3,6rem entra justa y todas quedan en sus líneas. */
.hero-servicio h1 { font-size: clamp(2rem, .9rem + 2.9vw, 3.6rem); line-height: 1; }
/* Las migas hacen de rótulo en píldora: conservan la navegación y su
   BreadcrumbList, y ocupan el lugar que en la home tiene «Agencia digital». */
.hero .crumbs.hero-sitio {
  /* inline-flex otra vez: .crumbs lo pone en flex y la píldora se estiraba
     a todo el ancho de la columna. */
  display: inline-flex; max-width: 100%;
  gap: 8px; margin-bottom: var(--s5);
  font-size: var(--fs-xs); letter-spacing: .1em; color: var(--on-media);
}
/* En teléfono el primer tramo se retira —el logo ya lleva al inicio— para que
   la ruta quepa en una línea; si una página larga igual se parte, la píldora
   se vuelve caja redondeada en vez de un óvalo deforme. */
@media (max-width: 480px) {
  .hero .crumbs.hero-sitio { font-size: 11px; letter-spacing: .06em; border-radius: 18px; }
  .hero .crumbs > a:first-child, .hero .crumbs > a:first-child + .sep { display: none; }
}
.hero .crumbs a { color: var(--on-media); text-decoration-color: rgba(255,255,255,.3); }
.hero .crumbs a:hover { color: var(--paper); text-decoration-color: currentColor; }
.hero .crumbs [aria-current] { color: var(--paper); font-weight: 600; }
.hero .crumbs .sep { color: rgba(255,255,255,.35); }
/* Por página: dónde está el sujeto de cada foto. */
.hero-ia { --foto-pos: 78% 62%; --foto-pos-m: 50% 60%; }
/* El árbol de archivos de la izquierda de la foto se asomaba detrás del
   titular: el encuadre se corre al código. */
.hero-software { --foto-pos: 96% 30%; --foto-pos-m: 30% 30%; }

@keyframes hero-asienta { from { opacity: 0; transform: scale(1.06); } to { opacity: 1; transform: none; } }
@keyframes hero-sube { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* Apilado: la foto arriba a todo el ancho y el texto entra sobre su fundido
   inferior. Bajo 701 px sirve el recorte vertical del <picture>. */
@media (max-width: 1000px) {
  .hero { --foto-alto: min(136vw, 80svh); display: block; min-height: 0; }
  .hero-media {
    left: 0; bottom: auto; height: var(--foto-alto);
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 calc(var(--nav-h) * 1.6), #000 42%, transparent 80%);
            mask-image: linear-gradient(to bottom, transparent 0, #000 calc(var(--nav-h) * 1.6), #000 42%, transparent 80%);
  }
  .hero-media img, .hero-media video { object-position: var(--foto-pos-m, 50% 18%); }
  .hero-in { padding-top: calc(var(--foto-alto) * .7 - var(--nav-h)); padding-bottom: var(--s7); }
  .hero-col { max-width: none; }
  .hero-oficios { margin-top: var(--s6); }
}
@media (max-width: 480px) {
  .hero-ctas .btn { width: 100%; justify-content: space-between; }
  .hero-ctas .btn-ghost { justify-content: center; }
}

/* --------------------------------------------------------------------------
   QUÉ HACEMOS — campo naranja y cuadrícula de cuatro
   Cuatro cuadrados a todo el ancho, uno por servicio, con la foto del
   servicio de fondo. En gris por defecto para que el titular mande; el color
   entra al pasar el cursor. El velo NO se toca entre estados: es lo único
   que sostiene el contraste del texto, y aclararlo en hover rompería el
   mínimo justo cuando la foto suma saturación.
   -------------------------------------------------------------------------- */
/* El color lo pone la utilidad .on-ink en el HTML, no esta clase: así la
   sección hereda de una sola vez el par de texto, la selección y el anillo de
   foco correctos para fondo oscuro, en lugar de invertirlos uno por uno.
   Acá solo vive el ritmo vertical. */
.seccion-servicios {
  /* Arriba a ras y no porque algo marque la costura: el hero y esta sección
     son el mismo tinta, así que no hace falta separador entre ellos —desde
     el 19-sep, sin la marquesina que antes marcaba dónde terminaba uno y
     empezaba el otro. Abajo sí hay aire, y es el encargo: sin él los paneles
     quedaban apoyados sobre el blanco de la sección siguiente en vez de
     flotando dentro de la negra. */
  padding: 0 0 clamp(var(--s6), 5vw, var(--s8));
}

/* El titular manda y el argumento cuelga de su última línea, desplazado a la
   derecha: la sangría hace que se lea como una nota al pie del titular y no
   como una segunda columna que compite con él. */
.qh-head {
  /* Abajo lleva algo más de aire desde que se retiró la regla (13-sep): esa
     línea era la que separaba el titular de los paneles. */
  padding-block: clamp(var(--s6), 5vw, var(--s8)) clamp(var(--s6), 5vw, var(--s7));
}
.qh-head h2 {
  margin: 0;
  font-family: "Big Shoulders Display", "Archivo", sans-serif;
  font-weight: 900; font-size: clamp(2.4rem, 1rem + 5.4vw, 5.6rem);
  line-height: .9; letter-spacing: -0.015em; text-transform: uppercase;
}
.qh-arg {
  margin: clamp(var(--s4), 3vw, var(--s5)) 0 0 auto;
  max-width: 44ch; font-size: var(--fs-lede); line-height: 1.5;
  color: var(--on-ink-soft);
}

/* ==========================================================================
   PANELES DE SERVICIO — dos tarjetas fijas (13-sep)
   Reemplaza el acordeón horizontal de 4 pestañas del 12-sep: el negocio dejó
   de ofrecer software a medida y automatización con IA, y con solo dos
   servicios el mecanismo de antes deja de tener sentido —un panel cuadrado
   abierto repartiéndole el resto del ancho a un solo lomo colapsado, que
   quedaría casi tan ancho como el abierto—. Con dos opciones no hay nada que
   revelar progresivamente: las dos tarjetas muestran su foto, placa
   numerada, título, bajada y enlace siempre, y la tarjeta entera es el
   enlace. Ver «Los paneles de servicio» en DESIGN.md para el porqué.
   ========================================================================== */
.paneles {
  --alto: clamp(320px, 30vw, 520px);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--s2);
}
.panel {
  position: relative; isolation: isolate; overflow: hidden;
  display: block; height: var(--alto);
  color: var(--on-ink);
  border: 1px solid var(--line-ink);
  border-radius: var(--r);
}
.panel-foto {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
  /* Un acercamiento leve de reposo que se suelta al pasar el cursor: el
     mismo lenguaje que ya usa .work en el resto del sitio, así
     que las tres tarjetas fotográficas del sitio se sienten como el mismo
     componente y no como tres soluciones distintas al mismo problema. */
  transform: scale(1.02);
  transition: transform 700ms var(--ease-soft);
}
@media (hover: hover) and (pointer: fine) {
  .panel:hover .panel-foto { transform: scale(1.06); }
}
/* Velo en degradado: oscurece donde vive el texto —abajo— y casi nada
   arriba, para que la foto se siga viendo entera y no solo en su mitad
   inferior. Al no haber ya un estado "cerrado" que proteger, un solo
   degradado alcanza —el velo de dos capas del acordeón existía para poder
   quitar una capa entera al abrir, y acá no hay nada que abrir.
   Los topes se corrieron más arriba que en el acordeón: ahí el panel abierto
   era ancho y bajo, y el texto ocupaba una franja chica cerca del borde
   inferior. Estas tarjetas son más altas —hasta apiladas en móvil, donde el
   panel puede medir menos que la columna de texto completa (título + bajada
   + enlace)—, así que el título queda a media altura y no cerca del piso.
   Con los topes del acordeón el título caía en la franja de ~0,4 de opacidad
   y el enlace en ~0,7: medido sobre `shero_web.jpg`, el título bajaba a
   2,4:1. Movidos, el 88% de opacidad cubre hasta el 55% de la altura —más
   que todo el bloque de texto en el caso más alto medido— y solo el 20%
   superior, donde vive la placa numerada con su propio fondo sólido, se
   deja ver casi entera. */
.panel::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(to top,
    rgba(10, 10, 10, .92) 0%, rgba(10, 10, 10, .88) 55%,
    rgba(10, 10, 10, .45) 82%, rgba(10, 10, 10, 0) 100%);
}
.panel-n {
  position: absolute; top: var(--s4); left: var(--s4); z-index: 2;
  padding: 3px 8px 2px;
  background: var(--o); color: var(--ink);
  font-family: "Big Shoulders Display", sans-serif; font-weight: 800;
  font-size: 1.05rem; line-height: 1.1; letter-spacing: .08em;
}
.panel-detalle {
  position: absolute; inset: 0; z-index: 1;
  display: flex; flex-direction: column; justify-content: flex-end;
  gap: var(--s2); padding: var(--s5);
}
.panel-tit {
  margin: 0;
  font-family: "Big Shoulders Display", "Archivo", sans-serif;
  font-weight: 800; font-size: clamp(1.6rem, 1rem + 1.8vw, 2.6rem);
  line-height: .95; letter-spacing: -0.012em; text-transform: uppercase;
}
.panel-desc { margin: 0; max-width: 42ch; font-size: var(--fs-sm); line-height: 1.55; color: var(--on-media); }
.panel-ir {
  margin-top: 2px;
  display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--fs-sm); font-weight: 700; color: var(--on-ink);
}
.panel-ir .arrow { transition: transform var(--t) var(--ease); }
@media (hover: hover) and (pointer: fine) { .panel:hover .panel-ir .arrow { transform: translateX(4px); } }
.panel:focus-visible { outline: 2px solid var(--o); outline-offset: -3px; }

@media (max-width: 620px) {
  .paneles { grid-template-columns: 1fr; }
  .panel { height: clamp(280px, 88vw, 420px); }
}

@media (prefers-reduced-motion: reduce) {
  .panel-foto, .panel-ir .arrow { transition: none; }
}

/* ==========================================================================
   TRABAJO — rejilla asimétrica de 4 piezas
   Los spans están hechos a mano para que sumen exacto 6 columnas por fila
   (4+2, luego 6, luego el CTA en 6): si el número de .work cambia, hay que
   volver a cuadrar esta cuenta o queda un hueco antes del CTA.
   ========================================================================== */
.work-grid { display: grid; grid-template-columns: repeat(6, 1fr); grid-auto-rows: 210px; gap: var(--s3); }
.work {
  position: relative; overflow: hidden; border-radius: var(--r);
  background: var(--ink); padding: 0; text-align: left; width: 100%; height: 100%;
}
.work:nth-child(1) { grid-column: span 4; grid-row: span 2; }
.work:nth-child(2) { grid-column: span 2; grid-row: span 1; }
.work:nth-child(3) { grid-column: span 2; grid-row: span 1; }
.work:nth-child(4) { grid-column: span 6; grid-row: span 2; }
.work.is-hidden { display: none; }

.work > img, .work > video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform 700ms var(--ease-soft);
}
.work::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, rgba(10,10,10,.34) 0%, rgba(10,10,10,.06) 40%, rgba(10,10,10,0) 70%);
}
@media (hover: hover) and (pointer: fine) { .work:hover > img, .work:hover > video { transform: scale(1.04); } }

.work-info {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: var(--s8) var(--s4) var(--s4);
  background: linear-gradient(to top, rgba(10,10,10,.95) 0%, rgba(10,10,10,.86) 34%, rgba(10,10,10,.5) 66%, rgba(10,10,10,0) 100%);
}
.work-cat { display: block; font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--o); margin-bottom: var(--s2); }
.work-title { display: block; font-size: var(--fs-h4); font-weight: 700; font-variation-settings: "wdth" 106; letter-spacing: -0.015em; color: var(--paper); }
.work-meta { display: block; margin-top: 4px; font-size: var(--fs-sm); color: var(--on-media); }
.work-open {
  position: absolute; top: var(--s3); right: var(--s3); z-index: 2;
  width: 38px; height: 38px; display: grid; place-items: center;
  border-radius: var(--r-pill); background: var(--o); color: var(--ink);
  opacity: 0; transform: scale(.9);
  transition: opacity var(--t) var(--ease), transform var(--t) var(--ease);
}
@media (hover: hover) and (pointer: fine) { .work:hover .work-open { opacity: 1; transform: scale(1); } }
.work:focus-visible .work-open { opacity: 1; transform: scale(1); }

/* Invitación de cierre: ocupa la fila completa bajo las cinco piezas. No es
   una obra, así que no lleva foto ni abre el modal — es la salida de la
   sección hacia el formulario. */
.work-cta {
  grid-column: span 6;
  display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr) auto;
  align-items: center; gap: var(--s5) var(--s7);
  padding: var(--s5) var(--s5);
  border-radius: var(--r); background: var(--ink); color: var(--on-ink);
  transition: background-color var(--t) var(--ease), color var(--t) var(--ease);
}
.work-cta-tit {
  font-family: "Big Shoulders Display", "Archivo", sans-serif;
  font-weight: 800; font-size: clamp(1.6rem, 1rem + 1.9vw, 2.4rem);
  line-height: .98; text-transform: uppercase;
}
.work-cta-p { font-size: var(--fs-sm); line-height: 1.55; color: var(--on-ink-soft); max-width: 52ch; transition: color var(--t) var(--ease); }
.work-cta-ir {
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
  font-size: var(--fs-sm); font-weight: 700;
}
.work-cta-ir .arrow { transition: transform var(--t) var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .work-cta:hover { background: var(--o); color: var(--ink); }
  .work-cta:hover .work-cta-p { color: var(--ink); }
  .work-cta:hover .work-cta-ir .arrow { transform: translateX(4px); }
}

@media (max-width: 900px) {
  .work-grid { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 172px; }
  .work:nth-child(n) { grid-column: span 2; grid-row: span 1; }
  .work:nth-child(1), .work:nth-child(4) { grid-row: span 2; }
  /* Apilada necesita dos pistas: las de 172px son fijas y el texto no cabe
     en una sola. */
  .work-cta {
    grid-column: span 2; grid-row: span 2;
    grid-template-columns: 1fr; align-content: center;
    gap: var(--s3); align-items: start;
  }
}
@media (max-width: 560px) {
  .work-grid { grid-template-columns: 1fr; grid-auto-rows: 200px; }
  .work:nth-child(n) { grid-column: span 1; grid-row: span 1; }
  .work-cta { grid-column: span 1; grid-row: span 2; }
}
@media (prefers-reduced-motion: reduce) {
  .work-cta, .work-cta-p, .work-cta-ir .arrow { transition: none; }
}


/* ==========================================================================
   PROCESO
   El ".steps"/".step" real —el de estaciones sobre la regla— vive más abajo,
   junto a "Quiénes somos". Acá solo queda lo que esa versión no redeclara:
   el párrafo y el quiebre a una columna bajo 500px, que sigue siendo el que
   manda a ese ancho porque el bloque de más abajo no lo repite.
   ========================================================================== */
/* Es la prosa que desarma la objeción: no puede ser el texto más chico. */
.step p { margin-top: var(--s3); font-size: var(--fs-body); color: var(--mute); }
@media (max-width: 500px) { .steps { grid-template-columns: 1fr; } }

/* ==========================================================================
   CITA / CTA — banda naranja con el equipo mostrado en pantalla
   ========================================================================== */

/* ==========================================================================
   FAQ — acordeón con ícono, chevron y panel animado
   Sigue siendo <details>/<summary>: la accesibilidad y el funcionamiento sin
   JS vienen del navegador. Lo que se añade encima es el formato.
   ========================================================================== */
#faq.section { padding-block: clamp(var(--s6), 4.5vw, var(--s8)); }
/* El acordeón mide 72ch por fila (icono + pregunta + chevron); sin este
   límite se queda pegado al borde izquierdo de los 1340px de --maxw y deja
   una franja vacía enorme a la derecha en pantallas anchas. Centrado como
   columna de lectura, no como texto — el chevron a la derecha de cada
   pregunta se pierde si se centra la fila entera. */
#faq .sec-head { max-width: 800px; margin-inline: auto; margin-bottom: var(--s5); text-align: center; }
#faq .sec-head h2 { margin-inline: auto; }
#faq .faq { max-width: 800px; margin-inline: auto; }
#faq .sec-head { max-width: none; }
/* El FAQ va delante del cierre: si merece ese lugar, merece el mismo
   tamaño de titular que las demás secciones. */
#faq .sec-head .h2 { font-size: var(--fs-h2); max-width: 28ch; }
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); transition: border-color var(--t) var(--ease); }
.faq details:hover { border-bottom-color: var(--ink); }

.faq summary {
  display: flex; align-items: center; gap: var(--s3);
  padding: 18px 0; cursor: pointer; list-style: none;
  font-size: clamp(1rem, .95rem + .28vw, 1.125rem); font-weight: 600;
  font-variation-settings: "wdth" 104; letter-spacing: -0.012em;
  line-height: 1.35;
}
.faq summary::-webkit-details-marker { display: none; }

/* Ícono de la pregunta */
.faq-ico-q {
  flex: none; display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 8px;
  background: var(--o-wash); color: var(--o-text);
  transition: background-color 420ms var(--ease), color 420ms var(--ease);
}
.faq details[open] .faq-ico-q { background: var(--o); color: var(--ink); }

.faq-q { flex: 1; min-width: 0; max-width: 72ch; }

/* Indicador: chevron que gira al abrir */
.faq-ico {
  flex: none; color: var(--mute);
  transition: transform 420ms var(--ease-soft), color 420ms var(--ease);
}
.faq details[open] .faq-ico { transform: rotate(180deg); color: var(--o-text); }

.faq-body { padding: 0 0 20px calc(32px + var(--s3)); color: var(--mute); font-size: var(--fs-body); max-width: 72ch; }

/* Suavizado del despliegue.
   Base para cualquier navegador: solo desplazamiento, sin tocar la opacidad
   ni recortar altura. Si la animación no llegara a correr, el peor caso es un
   texto 8px más arriba, nunca un texto invisible. */
@media (prefers-reduced-motion: no-preference) {
  .faq details[open] .faq-body {
    animation: faq-entra 460ms var(--ease-soft);
  }
  .faq details[open] .faq-ico-q { animation: faq-marca 460ms var(--ease-soft); }
}
@keyframes faq-entra {
  from { transform: translateY(-8px); }
}
@keyframes faq-marca {
  from { transform: scale(.82); }
}

/* Lo que hacía que la apertura se sintiera de golpe es que <details> no anima
   altura: el panel pasa de no existir a existir en un fotograma. Para animarla
   hay que interpolar `block-size` de 0 a `auto`, y eso exige `interpolate-size`.
   Todo el bloque va tras @supports a propósito: el recorte de altura solo se
   aplica en el navegador que además sabe interpolar hasta `auto`, así que no
   existe el caso "recortado pero sin animar", que dejaría la respuesta oculta.
   El que no lo soporta abre como siempre. */
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }

  @media (prefers-reduced-motion: no-preference) {
    .faq details::details-content {
      block-size: 0;
      overflow: hidden;
      transition: block-size 460ms var(--ease-soft),
                  content-visibility 460ms allow-discrete;
    }
    .faq details[open]::details-content { block-size: auto; }

    /* Con la altura ya animada, el texto puede además fundirse: aquí el
       soporte de @supports garantiza un motor que sí corre animaciones. */
    .faq details[open] .faq-body { animation-name: faq-abre; }
  }
}
@keyframes faq-abre {
  from { opacity: 0; transform: translateY(-6px); }
}

@media (max-width: 620px) {
  .faq summary { gap: var(--s2); padding: 15px 0; }
  .faq-ico-q { width: 28px; height: 28px; }
  .faq-body { padding-left: calc(28px + var(--s2)); }
}

/* ==========================================================================
   CONTACTO
   ========================================================================== */
.contact-grid { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: clamp(var(--s6), 6vw, var(--s8)); align-items: start; }
@media (max-width: 940px) { .contact-grid { grid-template-columns: 1fr; } }

.field { display: grid; gap: var(--s2); margin-bottom: var(--s3); }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
@media (max-width: 560px) { .field-row { grid-template-columns: 1fr; } }
.field label { font-size: var(--fs-sm); font-weight: 600; }
.field .opt { color: var(--mute); font-weight: 400; }
.field input, .field select, .field textarea {
  width: 100%; min-height: 46px; padding: 10px var(--s3);
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--line-2); border-radius: var(--r);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
/* 46px de alto todavía cumple el mínimo táctil de 44px; es el padding
   vertical el que se recorta, no el área de toque. */
.field textarea { min-height: 100px; resize: vertical; line-height: 1.5; }
.field input::placeholder, .field textarea::placeholder { color: var(--mute); opacity: 1; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--faint); }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible {
  border-color: var(--o-deep); outline: 2px solid var(--o-deep);
  outline-offset: 2px; box-shadow: none;
}
.field select {
  appearance: none; padding-right: 44px; background-repeat: no-repeat;
  background-position: right var(--s3) center;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b6862' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}
.field-err { display: none; font-size: var(--fs-sm); color: var(--o-text); }
.field.is-bad input, .field.is-bad select, .field.is-bad textarea { border-color: var(--o-text); }
.field.is-bad .field-err { display: block; }

.check { display: flex; gap: var(--s3); align-items: flex-start; margin-bottom: var(--s4); cursor: pointer; font-size: var(--fs-sm); color: var(--mute); }
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check-box {
  flex: none; width: 22px; height: 22px; margin-top: 2px;
  border: 1px solid var(--line-2); border-radius: 6px;
  display: grid; place-items: center; color: transparent;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.check input:checked + .check-box { background: var(--o); border-color: var(--o); color: var(--ink); }
.check input:focus-visible + .check-box { outline: 2px solid var(--o-deep); outline-offset: 2px; }
.check.is-bad .check-box { border-color: var(--o-text); }
.check a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }

.submit-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s4); }
.btn[data-busy="true"] { pointer-events: none; }
.btn[data-busy="true"] .btn-label { opacity: .55; }
.btn[data-busy="true"] .arrow { display: none; }
.spinner { display: none; width: 16px; height: 16px; border: 2px solid currentColor; border-top-color: transparent; border-radius: var(--r-pill); }
.btn[data-busy="true"] .spinner { display: block; animation: spin 640ms linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.form-note { display: none; margin-top: var(--s5); padding: var(--s4); border: 1px solid var(--line); border-radius: var(--r); }
.form-note.is-on { display: block; }
.form-note h3 { font-size: var(--fs-h4); }
.form-note p { margin-top: var(--s2); font-size: var(--fs-sm); color: var(--mute); }
.form-note a { text-decoration: underline; text-underline-offset: 3px; }
.form-note.ok { border-color: var(--ink); }
.form-note.bad { border-color: var(--o); background: var(--o-wash); }

/* Antes era un relleno gris (--paper-2); la tarjeta ahora se define por el
   borde, no por el color, así que se queda en blanco puro. */
.contact-side { background: var(--paper); border: 1px solid var(--line); border-radius: var(--r); padding: var(--s5); }
.contact-side h3 { font-size: var(--fs-h3); }
.contact-side .lede { margin-top: var(--s3); font-size: var(--fs-body); }
.contact-links { margin-top: var(--s5); border-top: 1px solid var(--line-2); }
.contact-links a {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s4) 0; border-bottom: 1px solid var(--line-2);
  font-weight: 600; font-size: var(--fs-sm);
  transition: color var(--t-fast) var(--ease);
}
.contact-links a:hover { color: var(--o-text); }
.contact-links .ico { color: var(--o-deep); flex: none; }
.contact-links .arrow { margin-left: auto; color: var(--faint); transition: transform var(--t) var(--ease); }
@media (hover: hover) and (pointer: fine) { .contact-links a:hover .arrow { transform: translateX(3px); } }

/* ==========================================================================
   FOOTER
   ========================================================================== */
/* Pie en tinta con texto blanco (20-sep, por encargo del cliente: antes era
   naranja con logo negativo y texto ink, y el cliente lo quería más quieto y
   más compacto). ".on-ink" en el HTML pone el fondo, el color base, la
   selección y el anillo de foco —son los mismos tokens que usa el resto del
   sitio sobre tinta, así que el pie no inventa su propia paleta—. Todo lo de
   acá abajo es ritmo (más apretado que antes) y los tonos que "on-ink" no
   cubre por sí solo. */
.footer { padding-block: var(--s7) var(--s4); }
/* Tres columnas, no cuatro (20-sep): "Servicios" se fusionó dentro de
   "Sitio" —ver el porqué en DESIGN.md— porque con solo dos servicios esa
   columna quedaba muy corta al lado de "Sitio" (6-7 ítems) y dejaba un
   hueco vacío antes de la línea de copyright. */
.footer-grid { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1.15fr) minmax(0, 1fr); gap: var(--s5); }
.footer-logo {
  height: 38px; width: auto;
  /* El logo ya nace blanco (assets/img/logo_blanco.png): sobre tinta no
     hace falta el filtro que lo tiñe de naranja en la nav. */
}
.footer-tag { margin-top: var(--s3); font-size: var(--fs-sm); color: var(--on-ink-soft); max-width: 38ch; line-height: 1.5; }
.footer h3, .footer h4 { font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--on-ink-soft); font-variation-settings: "wdth" 106; }
.footer-col ul { margin-top: var(--s3); display: grid; gap: var(--s2); }
.footer-col a {
  font-size: var(--fs-sm); color: var(--on-ink-soft);
  text-decoration: underline; text-decoration-color: transparent; text-underline-offset: 3px;
  transition: color var(--t-fast) var(--ease), text-decoration-color var(--t-fast) var(--ease);
}
.footer-col a:hover { color: var(--on-ink); text-decoration-color: currentColor; }
.footer-bottom {
  margin-top: var(--s6); padding-top: var(--s3); border-top: 1px solid var(--line-ink);
  display: flex; flex-wrap: wrap; gap: var(--s4); align-items: center; justify-content: space-between;
  font-size: var(--fs-sm); color: var(--on-ink-soft);
}
.footer-socials { display: flex; gap: var(--s2); }
.footer-socials a {
  width: 42px; height: 42px; display: grid; place-items: center;
  border: 1px solid var(--line-ink); border-radius: var(--r-pill); color: var(--on-ink-soft);
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.footer-socials a:hover { border-color: var(--on-ink); background: var(--on-ink); color: var(--ink); }
/* Con tres bloques y no cuatro, el paso intermedio de 2 columnas dejaba
   "Contacto" solo en su propia fila, chico y descolgado; se salta directo
   de 3 a 1. */
@media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr; } }

/* ==========================================================================
   MODAL
   ========================================================================== */
.modal { position: fixed; inset: 0; z-index: 250; display: grid; place-items: center; padding: var(--gut); opacity: 0; visibility: hidden; transition: opacity var(--t-slow) var(--ease), visibility var(--t-slow); }
.modal.is-open { opacity: 1; visibility: visible; }
.modal-scrim { position: absolute; inset: 0; background: rgba(10,10,10,.76); }
.modal-card { position: relative; width: min(980px, 100%); max-height: min(88dvh, 900px); overflow: auto; background: var(--paper); border-radius: var(--r); display: grid; grid-template-columns: 1fr 1fr; }
.modal-media { position: relative; background: var(--ink); min-height: 280px; }
.modal-media img, .modal-media video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.modal-body { padding: var(--s6) var(--s5); }
.modal-body h3 { font-size: var(--fs-h3); }
.modal-cat { display: block; font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--o-text); margin-bottom: var(--s2); }
.modal-meta { margin-top: var(--s2); font-size: var(--fs-sm); color: var(--mute); }
.modal-block { margin-top: var(--s5); }
.modal-block h4 { font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--mute); }
.modal-block p { margin-top: var(--s2); font-size: var(--fs-sm); }
.modal-tags { margin-top: var(--s5); display: flex; flex-wrap: wrap; gap: var(--s2); }
.modal-link {
  margin-top: var(--s5);
  display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--fs-sm); font-weight: 700; color: var(--o-text);
}
.modal-link .arrow { transition: transform var(--t) var(--ease); }
.modal-link:hover .arrow { transform: translateX(4px); }
.modal-link[hidden] { display: none; }
.modal-close {
  position: absolute; top: var(--s3); right: var(--s3); z-index: 3;
  width: 44px; height: 44px; display: grid; place-items: center;
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-pill);
  transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.modal-close:hover { border-color: var(--ink); background: var(--o); }
@media (prefers-reduced-motion: no-preference) {
  .modal-card { transform: scale(.97); transition: transform var(--t-slow) var(--ease-soft); }
  .modal.is-open .modal-card { transform: scale(1); }
}
@media (max-width: 780px) {
  .modal-card { grid-template-columns: 1fr; }
  .modal-media { aspect-ratio: 16 / 10; min-height: 0; }
}

/* ==========================================================================
   MOTION
   El único momento autoral es la entrada del hero: el bloque naranja se
   descubre y las piezas de trabajo entran escalonadas detrás de él.
   El resto es una sola aparición discreta al hacer scroll.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  .js .rise { opacity: 0; transform: translateY(10px); transition: opacity var(--t-rev) var(--ease-soft), transform var(--t-rev) var(--ease-soft); transition-delay: calc(var(--i, 0) * 60ms); }
  .js .rise.is-in { opacity: 1; transform: none; }

  .js .hero-line { display: block; overflow: hidden; padding-bottom: .06em; }
  .js .hero-line > span { display: block; transform: translateY(105%); animation: line-up 780ms var(--ease-soft) forwards; animation-delay: calc(var(--i, 0) * 90ms); }
  .js .hero-fade { opacity: 0; animation: fade-in 640ms var(--ease) forwards; animation-delay: calc(300ms + var(--i, 0) * 90ms); }
  .js .m-cell.is-work { clip-path: inset(0 0 100% 0); animation: wipe-up 940ms var(--ease-soft) forwards; animation-delay: calc(180ms + var(--i, 0) * 120ms); }
}
@keyframes line-up { to { transform: translateY(0); } }
@keyframes fade-in { to { opacity: 1; } }
@keyframes wipe-up { to { clip-path: inset(0 0 0 0); } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; transition-duration: 1ms !important; }
}

/* ==========================================================================
   PÁGINAS DE SERVICIO
   Mismo sistema que la home, con hero propio para no clonar el mosaico.
   ========================================================================== */
.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); font-size: var(--fs-xs); color: var(--mute); margin-bottom: var(--s4); }
.crumbs a { color: var(--mute); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--line-2); }
.crumbs a:hover { color: var(--o-text); text-decoration-color: currentColor; }
.crumbs [aria-current] { color: var(--ink); font-weight: 600; }
.crumbs .sep { color: var(--faint); }

/* Sobre el campo naranja del hero la nav va en ink: el logo teñido de naranja
   y el texto --mute desaparecerían contra su propio color. Al esmerilarse
   vuelve al esquema normal. */
.hero-naranja .site-header:not(.is-scrolled) .nav-links a { color: var(--ink); }
.hero-naranja .site-header:not(.is-scrolled) .nav-links a::after { background: var(--ink); }
.hero-naranja .site-header:not(.is-scrolled) .brand-logo { filter: brightness(0); }
.hero-naranja .site-header:not(.is-scrolled) .nav-cta { background: var(--ink); color: var(--paper); }
.hero-naranja .site-header:not(.is-scrolled) .nav-cta:hover { background: var(--ink-2); }
.hero-naranja .site-header:not(.is-scrolled) .menu-btn {
  background: transparent; border-color: var(--ink); color: var(--ink);
}


/* El problema: banda naranja con las cifras del dolor */
.pain { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s6); }
.pain-item { border-top: 3px solid var(--ink); padding-top: var(--s4); }
.pain-n {
  display: block; font-size: clamp(1.9rem, 1.2rem + 2vw, 2.9rem); font-weight: 700;
  font-variation-settings: "wdth" 112; letter-spacing: -0.035em; line-height: 1; color: var(--ink);
}
.pain-h { display: block; margin-top: var(--s3); font-weight: 600; font-size: var(--fs-body); }
.pain-p { margin-top: var(--s2); font-size: var(--fs-sm); color: var(--on-o-soft); }
@media (max-width: 860px) { .pain { grid-template-columns: 1fr; gap: var(--s5); } }

/* Qué hacemos: dos columnas separadas por filetes, sin tarjetas */
.offer { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--s7); }
.offer-item { padding-block: var(--s5); border-top: 1px solid var(--line); }
.offer-item:nth-child(-n+2) { border-top: 0; padding-top: 0; }
.offer-n { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.14em; color: var(--o-text); }
.offer-item h3 { font-size: var(--fs-h4); }
.offer-item p { margin-top: var(--s2); font-size: var(--fs-sm); color: var(--mute); }
.offer-tags { margin-top: var(--s4); display: flex; flex-wrap: wrap; gap: var(--s2); }
@media (max-width: 800px) {
  .offer { grid-template-columns: 1fr; }
  .offer-item:nth-child(2) { border-top: 1px solid var(--line); padding-top: var(--s5); }
}

/* Precios (solo diseño web, 01-sep): tres placas, no tarjetas de SaaS con
   sombra. El plan de en medio se marca con borde y una pestaña —nunca con
   una cifra de "el más elegido", que no está confirmada. Los ticks de la
   lista son el mismo trazo de la regla del hero, no un ícono de check. */
.plans { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s5); }
.plan {
  position: relative; min-width: 0;
  display: flex; flex-direction: column;
  border: 1px solid var(--line-ink); border-radius: var(--r);
}
.plan-badge {
  position: absolute; top: 0; left: var(--s5); transform: translateY(-50%);
  padding: 5px 11px; border-radius: var(--r-pill);
  background: var(--o); color: var(--ink);
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
}
.plan.is-recomendado { border-color: var(--o); border-width: 2px; }
.plan-in { flex: 1; display: flex; flex-direction: column; gap: var(--s4); padding: var(--s6) var(--s5) var(--s5); }
.plan-tit { font-size: var(--fs-h4); }
.plan-para { margin: 0; font-size: var(--fs-sm); color: var(--on-ink-soft); }
.plan-precio {
  margin: 0; padding-top: var(--s3); border-top: 1px solid var(--line-ink);
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px;
}
.plan-desde { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--on-ink-soft); }
.plan-precio .num {
  font-family: "Big Shoulders Display", "Archivo", sans-serif; font-weight: 800;
  font-size: clamp(1.8rem, 1rem + 2vw, 2.4rem); line-height: 1; letter-spacing: -0.01em;
}
.plan-iva { font-size: var(--fs-xs); color: var(--on-ink-soft); }
.plan-incluye { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--s2); font-size: var(--fs-sm); color: var(--on-ink-soft); }
.plan-incluye li { position: relative; padding-left: var(--s4); }
.plan-incluye li::before { content: ""; position: absolute; left: 0; top: .6em; width: 8px; height: 1px; background: var(--o); }
/* ".btn" es nowrap por defecto porque en todo el resto del sitio vive en
   filas con espacio de sobra. Acá no: "Cotizar sitio corporativo" no cabe en
   una columna angosta sin partirse, así que esta instancia sí envuelve y va
   a lo ancho de la tarjeta en vez de forzar el desborde. */
.plan-in .btn { margin-top: auto; align-self: stretch; white-space: normal; text-align: center; }
/* 1100px y no 900px: medido en vivo, entre ~961 y 1024px la columna a tres
   queda tan angosta que "Cotizar sitio corporativo" se parte en dos o tres
   líneas —el --gut crece con vw ahí, no antes—, así que el quiebre a una
   columna se corre hasta pasar esa franja entera. */
@media (max-width: 1100px) {
  .plans { grid-template-columns: 1fr; gap: var(--s6); }
  .plan-badge { left: var(--s4); }
}

/* Equipo: tres piezas con la foto arriba y la ficha colgando. Sin tarjeta,
   igual que .offer: el bloque es la foto y el texto vive debajo. */
.gear { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s6); }
.gear-item { display: flex; flex-direction: column; }
/* Hijo directo: si no, la regla también alcanza al recorte dentro de
   .gear-figura y le mete fondo ink y aspect-ratio propios. */
.gear-item > img {
  width: 100%; aspect-ratio: 3 / 2; object-fit: cover;
  border-radius: var(--r); background: var(--ink);
}
.gear-k {
  display: block; margin-top: var(--s4);
  font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--o-text);
}
.gear-t {
  display: block; margin-top: var(--s2);
  font-size: var(--fs-h4); font-weight: 700;
  font-variation-settings: "wdth" 104; letter-spacing: -0.015em;
}
.gear-item p { margin-top: var(--s2); font-size: var(--fs-sm); color: var(--mute); }

/* El drone es el diferenciador (DGAC), así que su pieza no es una foto más:
   el recorte flota sobre lavado naranja y rompe la fila a propósito. */
.gear-figura {
  width: 100%; aspect-ratio: 3 / 2;
  display: grid; place-items: center;
  padding: var(--s4);
  border-radius: var(--r);
  background: var(--o-wash);
  border: 1px solid var(--line);
}
.gear-figura img { width: 100%; height: auto; object-fit: contain; background: none; }

/* Cierre de la sección: el paso siguiente, a la vista, sin tener que seguir
   bajando hasta el CTA final. */
.gear-cierre {
  margin-top: var(--s7);
  border-top: 3px solid var(--ink);
  padding-top: var(--s5);
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--s5) var(--s7); align-items: center;
}
.gear-cierre-k {
  display: block; font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--o-text);
}
.gear-cierre-t { margin-top: var(--s3); font-size: var(--fs-lede); max-width: 52ch; line-height: 1.5; }
.gear-chips { margin-top: var(--s4); display: flex; flex-wrap: wrap; gap: var(--s2); }
.gear-cierre-pie { margin-top: var(--s3); font-size: var(--fs-sm); color: var(--mute); }
.gear-cierre-cta { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s2); }
/* Acento: el mismo drone visto de perfil, chico y decorativo. Es puro remate
   visual, así que desaparece apenas el espacio se pone justo. */
.gear-cierre-drone { display: none; }
@media (min-width: 1100px) {
  .gear-cierre { grid-template-columns: minmax(0, 1fr) auto auto; }
  .gear-cierre-drone { display: block; width: 190px; height: auto; opacity: .9; }
}

@media (max-width: 860px) { .gear { grid-template-columns: 1fr; gap: var(--s6); } }
@media (max-width: 760px) { .gear-cierre { grid-template-columns: 1fr; } }

/* Casos con métricas */
.cases { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: var(--s4); }
.case {
  display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: var(--r); overflow: hidden;
  background: var(--paper);
  transition: border-color var(--t) var(--ease);
}
.case:hover { border-color: var(--ink); }
.case-media { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--paper); }
.case-media img, .case-media video { width: 100%; height: 100%; object-fit: cover; }
.case-in { padding: var(--s4); display: flex; flex-direction: column; flex: 1; }
.case-k { font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--o-text); }
.case h3 { margin-top: var(--s2); font-size: var(--fs-h4); }
.case p { margin-top: var(--s2); font-size: var(--fs-sm); color: var(--mute); }
.case-metrics { margin-top: auto; padding-top: var(--s4); display: flex; gap: var(--s5); }
.case-metrics div { min-width: 0; }
.case-m-n { display: block; font-size: clamp(1.35rem, 1.1rem + 0.7vw, 1.7rem); font-weight: 700; font-variation-settings: "wdth" 110; letter-spacing: -0.025em; line-height: 1.1; color: var(--o-text); }
.case-m-l { display: block; margin-top: 2px; font-size: var(--fs-xs); color: var(--mute); }


/* CTA final
   La foto dejó de ser una columna al costado: ahora ocupa el fondo completo
   de la sección. El velo es una capa plana, sin degradados: el mismo valor
   en todo el bloque. Como la opacidad que hace falta depende de qué tan
   clara sea la foto, va en una variable y no en un número fijo. */
.cta-full {
  --cta-velo: .55;         /* fotos planas y oscuras; se sube por página */
  position: relative;
  isolation: isolate;      /* encierra los z-index negativos del fondo */
  overflow: hidden;
  display: grid;
  align-items: center;
  min-height: clamp(420px, 46vw, 600px);
}
.cta-bg {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover; object-position: 68% center;
}
.cta-full::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: rgba(10, 10, 10, var(--cta-velo));
}

/* El trazo ink del botón fantasma se pierde sobre la foto — sobre el velo
   hace falta un borde translúcido claro. El hover de .on-ink lo pisa. */
.cta-full .btn-ghost { border-color: rgba(255,255,255,.42); }

.final-cta { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: var(--s7); align-items: center; }
.final-cta .kicker { margin-bottom: var(--s3); }
.final-cta h2 {
  font-family: "Big Shoulders Display", "Archivo", system-ui, sans-serif;
  font-weight: 800; font-variation-settings: normal;
  font-size: var(--fs-h2); line-height: .95; letter-spacing: -0.012em;
  text-transform: uppercase; max-width: 17ch;
}
/* El párrafo es texto sobre foto velada: le corresponde --on-media. */
.final-cta p { margin-top: var(--s3); color: var(--on-media); max-width: 46ch; }
.final-cta .btn-row { display: flex; flex-wrap: wrap; gap: var(--s3); margin-top: var(--s6); }

@media (max-width: 900px) {
  .final-cta { grid-template-columns: 1fr; gap: var(--s5); }
  .cta-full { min-height: 0; }
  .cta-bg { object-position: 60% center; }
}

/* La cita de la home reusa el patrón, pero su kicker es naranja de marca y
   --o necesita un fondo muy oscuro para llegar a 4.5:1. Con el encuadre por
   defecto caía sobre el borde iluminado de la pantalla y se quedaba en 2.9.
   Corrido al 88% el texto queda sobre el lado oscuro del cuadro. */
.cta-cita { --cta-velo: .78; }
.cta-cita .cta-bg { object-position: 88% center; }

/* ==========================================================================
   HERO CON ESCENA 3D (Spline)
   Equivalente en vanilla del componente React de referencia: el motor es el
   mismo (@splinetool/runtime); lo que sobra es el envoltorio de React.

   Coreografía: la escena entra cubriendo el hero completo, se aleja hacia la
   derecha y deja el hueco donde nace el texto.
   ========================================================================== */
/* Desde el 13-sep el suelo es ink, como el resto de los heros: la escena del
   componente original estaba pensada sobre negro, y su fondo ya se vuelve
   transparente al cargar. La coreografía no cambió. */

/* Sin JS, sin WebGL, con reduced-motion o bajo 1001 px el hero es el normal:
   foto del robot a la derecha y texto visible. La escena solo se suma si de
   verdad puede correr. */

/* En cuanto sabemos que la escena se va a cargar, la foto del hero se va.
   Si no, se alcanza a ver el hero anterior y luego salta al 3D. */
.spline-ready .shero-spline .hero-media,
.shero-spline.is-3d .hero-media { visibility: hidden; }

/* El canvas nunca se transforma: Spline reencuadra la cámara si cambia la
   caja del canvas, así que el movimiento se hace sobre .spline-frame, cuya
   caja (100% del stage) no cambia nunca. Solo cambia su transform, que es
   puramente visual y no dispara el ResizeObserver de Spline. */
.spline-stage {
  position: absolute; inset: 0; z-index: 1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 800ms var(--ease);
}
.spline-frame {
  position: absolute; inset: 0;
  /* Origen abajo: al alejarse, los pies no se despegan del borde inferior del
     hero, que es donde empieza la banda naranja. */
  transform-origin: 50% 100%;
  transform: scale(1);
  transition: transform 2300ms cubic-bezier(.5, 0, .2, 1);
}
.spline-frame canvas { width: 100%; height: 100%; display: block; }
.shero-spline.is-3d .spline-stage { opacity: 1; }
.shero-spline.is-settling .spline-frame { transform: translateX(19%) scale(.88); }
/* En portátiles angostos la columna de texto ocupa más del ancho y el robot,
   asentado al 19%, dejaba la mano izquierda detrás del final de la bajada
   (medido a 1024 px). Mismo recorrido y misma duración; solo se detiene un
   poco más a la derecha y un punto más lejos. */
@media (max-width: 1299px) {
  .shero-spline.is-settling .spline-frame { transform: translateX(27%) scale(.82); }
}

/* Foco de luz que sigue al cursor. Sobre blanco va en naranja: el blanco del
   componente original sería invisible. */
.spline-glow {
  position: absolute; top: 0; left: 0; width: 520px; height: 520px;
  margin: -260px 0 0 -260px;
  border-radius: var(--r-pill);
  background: radial-gradient(circle at center, rgba(255,102,51,.20), rgba(255,102,51,.07) 46%, transparent 72%);
  filter: blur(34px);
  opacity: 0; pointer-events: none; z-index: 0;
  transition: opacity 400ms var(--ease);
  will-change: transform;
}
.shero-spline.is-lit .spline-glow { opacity: 1; }

/* El texto nace cuando la escena ya despejó el lado izquierdo */
/* Oculto SIN transición: con transición el texto se ve desvanecerse en vez de
   no estar. La transición solo existe al revelarlo. */
.spline-ready .shero-spline .hero-col > * { opacity: 0; transform: translateY(16px); }
.spline-ready .shero-spline.is-open .hero-col > * {
  opacity: 1; transform: none;
  transition: opacity 760ms var(--ease-soft), transform 760ms var(--ease-soft);
}
.spline-ready .shero-spline.is-open .hero-col > *:nth-child(1) { transition-delay: 0ms; }
.spline-ready .shero-spline.is-open .hero-col > *:nth-child(2) { transition-delay: 90ms; }
.spline-ready .shero-spline.is-open .hero-col > *:nth-child(3) { transition-delay: 180ms; }
.spline-ready .shero-spline.is-open .hero-col > *:nth-child(4) { transition-delay: 270ms; }
.spline-ready .shero-spline.is-open .hero-col > *:nth-child(5) { transition-delay: 360ms; }

.shero-spline .hero-in { position: relative; z-index: 2; }

/* Reglas para la escena en vertical. Hoy no se activan: nitidos.js descarta el
   3D bajo 1001px (ver ANCHO_MINIMO_3D), que es donde el hero se apila. Se conservan porque si algún día se
   quiere forzar en teléfonos, esto es lo que hace falta. Medido en 390px: con
   proporción 16/9 el robot queda en una franja de 213px, y con una caja más
   alta Spline lo encuadra fuera y sale cortado. */
@media (max-width: 1000px) {   /* debe coincidir con ANCHO_MINIMO_3D en nitidos.js */
  .spline-ready .shero-spline { display: flex; flex-direction: column; }
  .spline-ready .shero-spline .spline-stage {
    order: 2;
    position: relative; inset: auto;
    width: 100%; height: auto; aspect-ratio: 16 / 9;
  }
  .spline-ready .shero-spline .hero-in { order: 1; }
  .spline-ready .shero-spline .hero-in { padding-top: var(--s6); }

  /* Fase 1: solo el robot. El texto no ocupa ni sitio, así la escena queda
     arriba y llena la primera pantalla en vez de dejar un hueco. */
  .spline-ready .shero-spline:not(.is-open) .hero-in { display: none; }

  /* El acercamiento es suave: un salto de escala grande solo magnifica el
     recorte, no muestra más robot. */
  .spline-ready .shero-spline .spline-frame { transform: scale(1.14); }
  .spline-ready .shero-spline.is-settling .spline-frame { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .spline-stage, .spline-frame, .shero-spline.is-3d .hero-col > * { transition: none !important; transform: none !important; opacity: 1 !important; }
}

/* ==========================================================================
   NUBE DE HERRAMIENTAS EN 3D
   Perspectiva real (perspective + translateZ + preserve-3d), no una librería.
   Pesa ~3 KB de CSS contra el 1,7 MB que costaría un motor 3D.

   El movimiento va en tres capas con frecuencias distintas. Esa es la razón
   de que se lea como nube y no como una fila que ondea: si todo se mueve al
   mismo ritmo, el ojo detecta el patrón enseguida.
     1. el campo entero cabecea muy lento (y se inclina hacia el cursor)
     2. cada ícono deriva por su propia órbita en X, Y y Z
     3. cada cara cabecea más rápido y con poco recorrido
   ========================================================================== */
.tools {
  position: relative;
  perspective: 900px;
  perspective-origin: 50% 45%;
  padding-block: var(--s6);
  min-height: 300px;
}
.tools-field {
  position: relative; height: 300px;
  transform-style: preserve-3d;
  transition: transform 500ms var(--ease);
  animation: tools-vaiven 26s ease-in-out infinite alternate;
}
/* Con el cursor encima manda el puntero: se corta el vaivén para que no
   peleen dos transforms sobre el mismo elemento. */
.tools:hover .tools-field { animation-play-state: paused; }

@keyframes tools-vaiven {
  from { transform: rotateY(-2.5deg) rotateX(1.2deg); }
  to   { transform: rotateY(2.5deg)  rotateX(-1.2deg); }
}

.tool {
  position: absolute;
  left: var(--x); top: var(--y);
  transform-style: preserve-3d;
  transform: translate(-50%, -50%) translateZ(var(--z));
}

/* Deriva: cada ícono recorre una elipse propia en los tres ejes. El
   desplazamiento en Z es el que vende la nube, porque la perspectiva lo
   escala de verdad al acercarse. */
.tool-orbita {
  transform-style: preserve-3d;
  animation: tool-deriva var(--orbita) ease-in-out infinite;
  animation-delay: var(--delay);
}
@keyframes tool-deriva {
  0%   { transform: translate3d(0, 0, 0); }
  25%  { transform: translate3d(var(--dx), calc(var(--dy) * -1), var(--dz)); }
  50%  { transform: translate3d(calc(var(--dx) * .35), calc(var(--dy) * -1.35), calc(var(--dz) * -.5)); }
  75%  { transform: translate3d(calc(var(--dx) * -1), var(--dy), calc(var(--dz) * -1)); }
  100% { transform: translate3d(0, 0, 0); }
}

.tool-cara {
  display: grid; place-items: center;
  width: calc(var(--tam) * var(--esc, 1));
  height: calc(var(--tam) * var(--esc, 1));
  padding: calc(var(--tam) * var(--esc, 1) * .22);
  /* Algunas marcas se leen sobre su propio color, no sobre blanco. */
  background: var(--plato, var(--paper));
  border: 1px solid var(--borde-plato, var(--line));
  border-radius: 22%;
  box-shadow: 0 18px 40px rgba(10, 10, 10, .10), 0 2px 6px rgba(10, 10, 10, .05);
  animation: tool-cabeceo var(--dur) ease-in-out infinite alternate;
  animation-delay: var(--delay2);
}
.tool-cara img { width: 100%; height: 100%; object-fit: contain; display: block; }

@keyframes tool-cabeceo {
  from { transform: translateY(-5px) rotateX(3.5deg) rotateY(-4.5deg); }
  to   { transform: translateY(5px)  rotateX(-3.5deg) rotateY(4.5deg); }
}

/* Los que están más atrás pierden nitidez y contraste: es lo que vende la
   profundidad. Sin esto se ven como pegatinas planas a distinto tamaño. */
.tool[data-plano="fondo"] .tool-cara { opacity: .68; filter: blur(.8px); }
.tool[data-plano="medio"] .tool-cara { opacity: .9; }

/* Etiqueta bajo el conjunto */
.tools-pie {
  position: relative; z-index: 2;
  margin-top: var(--s4); text-align: center;
  font-size: var(--fs-sm); color: var(--mute);
}
.tools-pie strong { color: var(--ink); font-weight: 600; }

@media (max-width: 860px) {
  /* Mismo reparto, tarjetas proporcionalmente más chicas: el campo es 3,7
     veces más angosto pero las tarjetas medían lo mismo. */
  .tools { perspective: 700px; min-height: 250px; --esc: .58; }
  .tools-field { height: 250px; width: 84%; margin-inline: auto; }
  /* En pantalla chica sobra el plano de fondo: satura y no aporta. */
  .tool[data-plano="fondo"] { display: none; }
  /* Menos hueco entre íconos: la deriva se recorta para que no se toquen. */
  .tool-orbita { animation-duration: calc(var(--orbita) * 1.25); }
  .tool { --dx: 7px; --dy: 6px; --dz: 14px; }
}

@media (max-width: 520px) {
  /* Siete tarjetas en 390px quedaban a 9px unas de otras. */
  .tools { --esc: .47; }
  .tools-field { width: 92%; }
  .tool { --dx: 5px; --dy: 4px; --dz: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  .tool-cara, .tool-orbita, .tools-field { animation: none; }
  .tools-field { transition: none; }
}

/* --------------------------------------------------------------------------
   PÁGINA LEGAL Y NOTA DE CONSENTIMIENTO
   -------------------------------------------------------------------------- */
/* El enlace va fuera del <label>: dentro, pulsarlo empujaba "#" al historial
   y sacaba a la persona de un formulario a medio llenar. */
.check-nota { margin: var(--s2) 0 0 34px; font-size: var(--fs-xs); }
.check-nota a { color: var(--o-text); text-decoration: underline; text-underline-offset: 3px; }

.legal { max-width: 68ch; }
.legal-fecha { font-size: var(--fs-sm); color: var(--mute); margin-bottom: var(--s6); }
.legal h2 { font-size: var(--fs-h4); margin-top: var(--s6); }
.legal p { margin-top: var(--s3); color: var(--mute); }
.legal ul { margin-top: var(--s3); padding-left: var(--s4); color: var(--mute); }
.legal li { margin-bottom: var(--s2); }
.legal strong { color: var(--ink); font-weight: 600; }
.legal a { color: var(--o-text); text-decoration: underline; text-underline-offset: 3px; }

/* --------------------------------------------------------------------------
   SEÑALÉTICA — el resto de las superficies
   -------------------------------------------------------------------------- */

/* --- Cierre: mismo patrón de foto a sangre que el CTA de las landings
       (.cta-full), con más aire vertical porque es el remate del sitio. --- */
/* Grano de serigrafía sobre el velo: sin él la foto se lee como un fondo de
   stock cualquiera. Vive acá porque el cierre es el único bloque que lo usa
   desde que el hero pasó a tinta plana. */
.grano {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  opacity: .5; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
}

.cierre { padding-block: clamp(var(--s7), 8vw, var(--s9)); }
/* El grano queda en z-index:1 (ver .hero): sin esto el texto sin posicionar
   pinta detrás de él en el orden de apilado y se ve el grano por encima. */
.cierre > .wrap { position: relative; z-index: 2; }
.cierre .final-cta { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); align-items: end; }
.cierre h2 {
  font-size: clamp(2.2rem, 1.1rem + 4vw, 4.2rem); max-width: 14ch;
  font-variation-settings: normal;
  letter-spacing: -0.012em; line-height: .95;
  text-transform: uppercase;
}
.cierre .btn-row { margin-top: var(--s6); }

/* --- Proceso: estaciones en columna, sin la regla (retirada 22-sep) --- */
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; }
.step {
  position: relative; padding: 0 var(--s4);
  border-left: 1px solid var(--line);
}
.step:first-child { border-left: 0; padding-left: 0; }
/* El ícono va en línea con "Paso 0X", del tamaño de ese rótulo: es una nota
   de la ficha técnica, no una tarjeta de icono+título+texto —eso lo prohíbe
   este mundo en cualquier otro lado de la página. */
.step-head { display: flex; align-items: center; gap: var(--s2); }
.step-ico {
  display: grid; place-items: center; flex: none;
  width: 22px; height: 22px; color: var(--o-text);
}
.step-n {
  font-size: var(--fs-xs);
  font-variation-settings: "wdth" var(--wdth-rotulo), "wght" 700;
  letter-spacing: 0.14em; color: var(--o-text);
}
.step h3 {
  margin-top: var(--s3); font-size: var(--fs-h4);
  font-variation-settings: "wdth" 106, "wght" 700; letter-spacing: -0.02em;
}

/* Entrada: el ícono se asienta un instante después de que la estación
   aparece (misma "--i" del rise, sin inventar un segundo contador), como si
   se sellara al llegar. Hover: un cuarto de giro discreto, la misma curva de
   interacción que ya usan los botones fantasma. */
@media (prefers-reduced-motion: no-preference) {
  .js .step-ico { opacity: 0; transform: scale(.6) rotate(-8deg); }
  .js .rise.is-in .step-ico {
    opacity: 1; transform: none;
    transition: opacity var(--t-slow) var(--ease-soft), transform var(--t-slow) var(--ease-soft);
    transition-delay: calc(var(--i, 0) * 60ms + 160ms);
  }
}
@media (hover: hover) and (pointer: fine) {
  .step-ico { transition: color var(--t) var(--ease); }
  .step:hover .step-ico { color: var(--o); }
}
/* El giro es el único tramo que se cae con "reducir movimiento": el color
   sí se conserva arriba, fuera de esta condición.
   Especificidad a propósito: ".step:hover .step-head .step-ico" empata en
   peso con ".js .rise.is-in .step-ico" de la entrada (cuatro clases cada
   una) y gana por ir después en el archivo. Con menos peso, el reposo de la
   entrada ganaba siempre y el hover nunca se veía —pasó en la primera
   versión de esta regla. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .step-ico { transition: color var(--t) var(--ease), transform var(--t) var(--ease); }
  .step:hover .step-head .step-ico { transform: rotate(-14deg); }
}

/* --- #equipo sobre ink ---
   La home tenía su "Quiénes somos" en este mismo id, retirado el 13-sep.
   Lo que queda vivo es "Con qué trabajamos" (el equipamiento de audiovisual,
   ver .gear en produccion-audiovisual.html), que comparte id="equipo" porque
   ambas eran, en su momento, la sección de cierre sobre tinta antes del
   portafolio. No fusionar de nuevo un id de "equipo humano" con este: si se
   necesita, que sea un id propio. */
#equipo { background: var(--ink); color: var(--on-ink); }
#equipo .h2 { color: var(--on-ink); }
#equipo .lede { color: var(--on-ink-soft); }

@media (max-width: 860px) {
  .steps { grid-template-columns: repeat(2, 1fr); }
  .step { padding-left: var(--s4); border-left: 1px solid var(--line); }
  .step:nth-child(odd) { border-left: 0; padding-left: 0; }
  .step:nth-child(odd)::before { left: 0; }
  .step:nth-child(n+3) { margin-top: var(--s6); }
}
@media (max-width: 500px) {
  .steps { grid-template-columns: 1fr; }
  .step { border-left: 0; padding-left: 0; }
  .step::before { left: 0; }
  .step:nth-child(n+2) { margin-top: var(--s5); }
}


/* El consentimiento vive en un .field para que su mensaje de error quede en
   el mismo contenedor que el control; dentro del <label> pasaría a formar
   parte del nombre accesible. */
.field-check { display: block; }
.field-check .check { margin-bottom: 0; }

/* Objetivos táctiles al mínimo de 44 px: los iconos sociales estaban en 42 y
   los enlaces del menú abierto en 36,8 de alto. */
.footer-socials a { min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
.drawer-links a { min-height: 44px; display: flex; align-items: center; }
.drawer-sep { display: block; height: 1px; background: var(--line); margin: var(--s3) 0; }
.drawer-foot a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
