@charset "utf-8";
/* ==========================================================================
   DEL — hoja de estilos
   --------------------------------------------------------------------------
   ESCALA: el diseño está dibujado a 1080 pt de ancho.  1rem = 10 pt de diseño,
   así que un valor de 68 pt del PDF se escribe 6.8rem y se puede cotejar
   directamente contra docs/03-mapa-de-secciones.md.

   El rem crece con el viewport y se detiene en 1440 px (1440/108 = 13.333px),
   que es la decisión registrada en docs/07-pendientes-y-decisiones.md.

   Los comentarios «y NNN» son coordenadas del PDF, para poder auditar.
   ========================================================================== */

/* ---------- fuentes ---------- */
@font-face{
  font-family:'Gravesend Sans';
  src:url('../fuentes/gravesend-sans-medium.woff2') format('woff2');
  font-weight:500; font-style:normal; font-display:swap;
}
@font-face{
  font-family:'Gravesend Sans';
  src:url('../fuentes/gravesend-sans-bold.woff2') format('woff2');
  font-weight:700; font-style:normal; font-display:swap;
}
@font-face{
  font-family:'Montserrat';
  src:url('../fuentes/montserrat-regular.woff2') format('woff2');
  font-weight:400; font-style:normal; font-display:swap;
}
@font-face{
  font-family:'Montserrat';
  src:url('../fuentes/montserrat-semibolditalic.woff2') format('woff2');
  font-weight:600; font-style:italic; font-display:swap;
}
/* Recta, para el menú. Antes sólo estaba la itálica, así que pedir 600 recto
   daba una negrita sintética. La genera _extraido/fuente_menu.py recortando la
   del sistema —Montserrat es OFL— al latino que usa el sitio: 15 KB. */
@font-face{
  font-family:'Montserrat';
  src:url('../fuentes/montserrat-semibold.woff2') format('woff2');
  font-weight:600; font-style:normal; font-display:swap;
}

/* ---------- variables ---------- */
:root{
  --titular:'Gravesend Sans', system-ui, sans-serif;
  --cuerpo:'Montserrat', system-ui, sans-serif;

  --azul:#173d75;          /* color de todo el texto oscuro */
  --azul-ui:#204983;       /* cabecera y píldoras */
  --azul-punto:#1f57a9;    /* punto activo del selector */
  --blanco:#fff;

  --tr-titular:-0.070em;   /* leído del operador Tc del PDF */
  --tr-cuerpo:-0.025em;

  --ancho:108rem;          /* 1080 pt */

  /* Los dos únicos tamaños del sitio. Van en variable y no repartidos por
     quince reglas porque el bloque móvil los redefine de golpe: allí la raíz
     mide de 9 a 12 px en vez de 13.333, y heredar estos valores dejaría el
     cuerpo en 11 px. Redefinir la variable evita además pelearse con la
     especificidad, que es lo que pasaría repitiendo los quince selectores. */
  /* 1.35rem = 18 px. El diseño traía 1.125rem (15 px) y se llegó aquí por
     tanteo del cliente: 1.5 (20 px) le pareció grande, y 1.2 (16 px) no se
     distinguía del original —un 6.7 % no lo ve nadie—. 18 px es un 20 % sobre
     el diseño, que sí se nota.

     Los héroes se quedan en 1.5: eso se aprobó aparte, y que la entradilla
     sea mayor que el cuerpo es jerarquía, no incoherencia.

     Se cambia AQUÍ y no en veinte reglas, que es justo para lo que está la
     variable. Y afecta sólo a escritorio sin tener que decirlo: el bloque
     móvil redefine `--texto` a 1.4rem más abajo, donde la raíz mide de 9 a
     12 px y el cuerpo ya era proporcionalmente mayor. */
  --texto:1.35rem;         /* 18 px a 1440 */
  --titulo:2.7rem;         /* 36 px a 1440 */
}

/* ---------- base ---------- */
*,*::before,*::after{box-sizing:border-box}

html{
  font-size:min(calc(100vw / 108), 13.333px);
  scroll-behavior:smooth;
}
@media (prefers-reduced-motion:reduce){ html{scroll-behavior:auto} }

body{
  margin:0;
  font-family:var(--cuerpo);
  /* El diseño compone el cuerpo a 15 pt. La clienta lo ve grande y pide que
     vaya al tamaño de los pies de icono y del submenú, que son 14. Se cambia
     aquí, en la base, para que herede todo el sitio; los titulares se quedan
     como estaban. Esto SEPARA el cuerpo del PDF a propósito: lo que se mueve
     por debajo está anotado en docs/14-tamano-de-texto.md. */
  font-size:var(--texto);
  line-height:1;                     /* el diseño compone a interlínea 1 */
  letter-spacing:var(--tr-cuerpo);
  color:var(--azul);
  background:var(--blanco);
  -webkit-font-smoothing:antialiased;
}

img,svg{display:block;max-width:100%}
ul{margin:0;padding:0;list-style:none}
p{margin:0}
a{color:inherit;text-decoration:none}

h1,h2{
  font-family:var(--titular);
  font-weight:700;
  letter-spacing:var(--tr-titular);
  line-height:1;
  margin:0;
  /* Gravesend Sans es unicase: dibuja mayúsculas por sí sola.
     NO añadir text-transform — ver docs/01-tipografia.md */
}

.vo{                                  /* sólo para lectores de pantalla */
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}
/* fuera de pantalla sin usar left:-9999px, que ensucia las comprobaciones
   de desborde horizontal */
.saltar{
  position:absolute;left:1rem;top:1rem;z-index:100;
  background:var(--blanco);color:var(--azul);padding:1rem 2rem;
  clip-path:inset(50%);
}
.saltar:focus{clip-path:none}

:where(a,button,input,select,textarea):focus-visible{
  outline:0.25rem solid var(--azul-punto);
  outline-offset:0.3rem;
}

/* ==========================================================================
   CABECERA · y 0–74 · #204983 al 60 % en modo Multiplicar sobre la foto
   ========================================================================== */
.cabecera{
  /* `fixed` y no `absolute`: el cliente la quiere visible todo el rato, en PC
     y en móvil. Sobre el héroe sigue siendo la banda translúcida del diseño;
     en cuanto se baja, el JS pone `.cabecera--posada` y se vuelve opaca, o el
     menú quedaría ilegible sobre las zonas claras. */
  position:fixed;
  inset-inline:0; top:0; z-index:40;
  height:7.4rem;                     /* 74 pt */
  transition:background-color .25s ease, box-shadow .25s ease;
}
.cabecera--posada{
  background:var(--azul);
  box-shadow:0 .4rem 1.6rem rgba(10,13,53,.28);
}
/* Posada, la banda translúcida sobra: duplicaría el azul */
.cabecera--posada::before{opacity:0}
.cabecera::before{                   /* la banda, aislada para poder fusionarla */
  content:'';position:absolute;inset:0;
  background:var(--azul-ui);
  opacity:.6;
  mix-blend-mode:multiply;
}
.cabecera__interior{
  position:relative;
  max-width:var(--ancho);
  margin-inline:auto;
  height:100%;
  display:flex;
  align-items:center;
}

.logo{margin-left:4.58rem}           /* x 45.8 */
.logo img{width:7.63rem;height:3.17rem}   /* 76.3 × 31.7 */

.menu{margin-left:auto;margin-right:7.03rem}   /* el menú acaba en x 1009.7 */
/* `>` obligatorio: sin él la regla alcanza también a .submenu y le pone
   los siete servicios en fila, no en columna */
.menu > ul{display:flex;gap:2rem}    /* separación uniforme de 20 pt */
/* El menú va en la tipografía del cuerpo y no en la de titulares: Gravesend
   Sans es unicase —sólo tiene mayúsculas— y el cliente lo quiere en minúscula.
   Con Montserrat se lee tal como está escrito. Peso 600 recto, que ahora sí
   existe; a 400 quedaba flojo sobre la foto del héroe. */
.menu a{
  font-family:var(--cuerpo);
  font-weight:600;
  font-size:1.361rem;                /* 13.61 pt, el del diseño */
  letter-spacing:var(--tr-cuerpo);
  color:var(--blanco);
  padding-block:1rem;
}
.menu a:hover{opacity:.75}

/* --- desplegable de «Servicios» ---------------------------------------- */
/* Nada de `display:flex` en el <li>: convertiría su enlace en un elemento de
   caja y dejaría de compartir línea base con los otros cuatro. «Servicios»
   bajaba 8.8 pt respecto al resto del menú. */
.menu__desplegable{position:relative}
.menu__flecha{
  display:inline-grid; place-items:center;
  vertical-align:-0.18em;            /* a la altura de la línea base del menú */
  width:1.4rem; height:1.4rem; margin-left:.55rem; padding:0;
  background:none; border:0; cursor:pointer;
  color:var(--blanco);
}
.menu__flecha svg{width:1.4rem; height:1.4rem; transition:transform .18s ease}
.menu__desplegable:hover .menu__flecha svg,
.menu__flecha[aria-expanded="true"] svg{transform:rotate(180deg)}

.submenu{
  position:absolute; top:100%; left:50%;
  transform:translateX(-50%) translateY(.6rem);
  min-width:26rem;
  background:var(--azul);
  border-radius:1.4rem;
  padding-block:.95rem;
  box-shadow:0 1.4rem 3.4rem rgba(10,13,53,.45);
  opacity:0; visibility:hidden;
  transition:opacity .18s ease, transform .18s ease, visibility .18s;
  z-index:30;
}
.menu__desplegable:hover > .submenu,
.menu__desplegable:focus-within > .submenu,
.submenu[data-abierto="true"]{
  opacity:1; visibility:visible;
  transform:translateX(-50%) translateY(0);
}
.submenu a{
  display:block;
  font-family:var(--cuerpo);
  font-weight:400;
  /* El panel se veía desproporcionado con las siete entradas a 14 pt. Baja a
     11.25 pt, que a 1440 son los 15 px pedidos, y el relleno con él en la
     misma proporción (0.80) para que la caja no quede holgada. */
  font-size:1.125rem;                /* 11.25 pt · 15 px a 1440 */
  letter-spacing:var(--tr-cuerpo);
  color:var(--blanco);
  padding:.76rem 1.9rem;
  white-space:nowrap;
}
.submenu a:hover{background:rgba(255,255,255,.14); opacity:1}
@media (prefers-reduced-motion:reduce){
  .submenu, .menu__flecha svg{transition:none}
}

.hamburguesa{display:none}

/* ==========================================================================
   LIENZO · y 0–2765.3
   Un solo degradado continuo: el diseño no lo trocea por secciones.
   Las paradas salen de muestrear el render cada pocos puntos.
   ========================================================================== */
.lienzo{
  position:relative;
  background:linear-gradient(
    to bottom,
    #163c74  0%,
    #163c74 19.53%,   /* y  540 */
    #1e4278 23.14%,   /* y  640 */
    #2e5082 26.76%,   /* y  740 */
    #496692 30.38%,   /* y  840 */
    #5c779e 32.55%,   /* y  900 */
    #7389ab 34.72%,   /* y  960 */
    #8a9db9 36.89%,   /* y 1020 */
    #a4b3c8 39.06%,   /* y 1080 */
    #bdc8d7 41.23%,   /* y 1140 */
    #d5dce6 43.40%,   /* y 1200 */
    #e9edf2 45.56%,   /* y 1260 */
    #ffffff 49.90%,   /* y 1380 — meseta blanca */
    #ffffff 54.24%,   /* y 1500 */
    #f6f8fa 55.69%,   /* y 1540 */
    #e9edf2 57.14%,   /* y 1580 */
    #d4dbe5 58.58%,   /* y 1620 */
    #bdc8d7 60.03%,   /* y 1660 */
    #a7b5ca 61.48%,   /* y 1700 */
    #8498b6 63.65%,   /* y 1760 */
    #6e86a8 65.09%,   /* y 1800 */
    #3d5c8b 68.71%,   /* y 1900 */
    #163c74 75.94%,   /* y 2100 */
    #173d75 83.17%,   /* y 2300 */
    #1d4279 90.40%,   /* y 2500 */
    #446390 97.64%,   /* y 2700 */
    #5b769e 100%      /* y 2765 */
  );
}

/* foto del héroe: cubre y 0–538.9 y se disuelve en el degradado */
.lienzo__heroe-fondo{
  position:absolute; inset-inline:0; top:0;
  height:53.89rem;                   /* 538.9 pt */
  overflow:hidden;
  z-index:0;
}
/* El vídeo de portada ocupa el marco con `cover`: el encuadre exacto del PDF
   era para la foto que sustituye, y con otro material no significa nada. El
   póster va en el mismo sitio para que no haya salto al arrancar. */
.lienzo__heroe-fondo .heroe-video{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover; object-position:50% 50%;
}

.lienzo__heroe-fondo img,
.lienzo__heroe-fondo .heroe-video{
  /* La foto no se corta: se disuelve en el azul. Las paradas salen de comparar,
     píxel a píxel, el render del PDF con la foto original a esa misma altura. */
  --velo:linear-gradient(to bottom,
    rgba(0,0,0,.95)   0%,
    rgba(0,0,0,.93) 27.8%,   /* y 150 */
    rgba(0,0,0,.79) 37.1%,   /* y 200 */
    rgba(0,0,0,.55) 48.2%,   /* y 260 */
    rgba(0,0,0,.28) 61.2%,   /* y 330 */
    rgba(0,0,0,.10) 77.9%,   /* y 420 */
    rgba(0,0,0,0)   89.1%);  /* y 480 · a partir de aquí sólo el degradado */
  -webkit-mask-image:var(--velo);
          mask-image:var(--velo);
}

.lienzo > section{
  position:relative; z-index:1;
  max-width:var(--ancho);
  margin-inline:auto;
}


/* --------------------------------------------------------------------------
   ENCUADRE DE FOTO
   El diseño no centra las fotos: cada una está colocada y recortada en un
   sitio concreto. `object-fit:cover` da otro encuadre. Los porcentajes salen
   de comparar el rectángulo de colocación con el de recorte del PDF.
   -------------------------------------------------------------------------- */
.encuadre,
.quienes__foto,
.proyectos__foto,
.banda-foto{position:relative; overflow:hidden}
.encuadre > img,
.quienes__foto img,
.proyectos__foto img,
.banda-foto img{position:absolute; height:auto; max-width:none}

/* ==========================================================================
   PÍLDORA · 96.5 × 25.8 pt · #204983 · idéntica en las cuatro apariciones
   ========================================================================== */
.pildora{
  display:inline-grid;place-items:center;
  width:9.65rem;height:2.58rem;      /* 96.5 × 25.8 */
  border-radius:1.29rem;
  background:var(--azul-ui);
  color:var(--blanco);
  font-size:var(--texto);
  letter-spacing:var(--tr-cuerpo);
  border:0;
  box-shadow:-0.3rem 0.5rem 1.2rem rgba(10,13,53,.35);
  transition:transform .15s ease, box-shadow .15s ease;
}
.pildora:hover{transform:translateY(-0.15rem);box-shadow:-0.3rem 0.8rem 1.6rem rgba(10,13,53,.45)}
.pildora:active{transform:translateY(0)}

/* ==========================================================================
   HÉROE · y 0–491
   ========================================================================== */
.heroe{
  height:49.11rem;                   /* 0 → 491.1 */
  padding-top:21.6rem;               /* H1 en y 216 */
  text-align:center;
}
/* El `text-align:center` del héroe lo pone todo centrado, titular incluido.
   La clienta pide el texto justificado y los titulares como estaban, así que
   el justificado se aplica sólo a los párrafos. Vale para los tres héroes
   —portada, tecnología y fichas—, porque los tres llevan la clase `heroe`. */
.heroe p{text-align:justify}

.heroe h1{
  font-size:var(--titulo);                    /* 30 pt */
  color:var(--blanco);
  /* El diseño NO centra el H1: sus dos líneas van centradas en x 512.9 cuando
     el centro de la página es 540, y el botón de debajo sí va centrado
     (541.75). Se reprodujo con `padding-right:5.43rem` porque el encargo era
     replicar el PDF, y dejaba los 11 titulares del sitio 36.2 px a la
     izquierda. El cliente lo señaló: se quita. Nadie centra un botón y deja el
     título de encima descuadrado a propósito; era un descuido del diseñador.
     Para volver al PDF, reponer `padding-right:5.43rem`.
     Lo vigila `_extraido/auditar_centrado.py`. */
}
.heroe .pildora{margin-top:1.91rem}  /* botón en y 295.1 */

/* ==========================================================================
   ¿QUIÉNES SOMOS? · y 491–897
   ========================================================================== */
.quienes{
  height:40.59rem;                   /* 491.1 → 897.0 */
  position:relative;
  color:var(--blanco);
  /* La foto va absoluta y el texto en flujo, así que no hay un flex que los
     empareje. Se centran los dos por separado dentro de la sección, que tiene
     alto fijo: centrados en la misma caja, quedan centrados entre sí. Además
     reparte el hueco que dejó el texto al encoger, que antes caía todo abajo.
     El móvil lo devuelve a `block`: allí la foto deja de ser absoluta y con
     flex se pondría en fila al lado del texto. */
  display:flex; align-items:center;
}
.quienes__texto{
  width:38.65rem;                    /* 386.5 pt */
  margin-left:11.54rem;              /* x 115.4 */
}
/* ==========================================================================
   INTERLÍNEA DEL TEXTO CORRIDO
   El diseño compone a interlínea 1 y así estaba: a 15 pt ya iba justo, y al
   bajar el cuerpo a 14 las líneas se tocaban y el bloque se leía denso —más
   grande, de hecho, aunque midiera lo mismo—. Cinco bloques de prosa iban a 1
   y el resto a 1.2; se igualan todos a 1.2, que es el del detalle de
   servicios. El `body{line-height:1}` no se toca: la interfaz —menú, rótulos,
   botones y etiquetas de sector— sí compone así.
   ========================================================================== */
.quienes p,
.intro p,
.antetitulo,
.innovacion__texto p,
.lienzo--nosotros .bloque__texto p,
.ficha--texto p,
.proyectos__texto{line-height:1.2}

.quienes h2{font-size:var(--titulo)}        /* 25 pt */
.quienes p{
  margin-top:1.5rem;                 /* 15 pt de aire entre párrafos */
  text-align:justify;
}
.quienes__texto > p:first-of-type{margin-top:.68rem}   /* y 522.9 */
/* El botón va detrás del párrafo, así que se mueve con él. Bajar el cuerpo a
   14 pt lo subía 15 pt; abrir la interlínea a 1.2 lo baja 27. Se deja que
   siga al texto, con el aire del diseño: fijarlo a su y original exigiría un
   margen negativo, que se rompería en cuanto cambie una palabra del párrafo.
   El desfase queda anotado en docs/14-tamano-de-texto.md. */
.quienes .pildora{margin-top:1.19rem}                  /* el diseño lo pone en y 789.8 */

.quienes__foto{
  position:absolute;
  left:55.18rem;
  /* centrada con margen negativo y no con `transform`: el transform lo usa
     la animación de aparición, y `.hecho` lo deja en `none`, que borraría el
     centrado. Como el alto es fijo, medio alto exacto vale igual. */
  top:50%;                           /* el diseño la ponía en y 533.9 */
  width:43.15rem; height:24.09rem;   /* 431.5 × 240.9 */
  /* el margen va DESPUÉS del atajo `margin`, o éste lo pisa y el centrado se
     pierde sin dar ningún error */
  margin:-12.045rem 0 0;             /* medio alto: sube la foto a su centro */
  border-radius:2rem;
  box-shadow:0 1.2rem 3rem rgba(10,13,53,.3);
}
.quienes__foto img{width:134.81%; left:-1.67%; top:-49.07%}

/* ==========================================================================
   CARRUSEL DE FOTOS · y 897–1263 · diapositiva de 574 × 366.2, hueco 28.35
   Las vecinas asoman por los bordes (225.9 a la izquierda, 223.4 a la derecha).
   ========================================================================== */
.galeria{
  max-width:none !important;         /* la banda es a sangre */
  padding-top:0;
  /* El hueco que dejaban los puntos de paginación se conserva, para que lo de
     abajo no suba y siga coincidiendo con el PDF: 1.86 de margen + 0.57 de los
     propios puntos. */
  padding-bottom:2.43rem;
}
/* La ventana recorta y se desvanece por los lados; las flechas van fuera de
   ella, o la máscara también las difuminaría. */
.galeria__ventana{
  overflow:hidden;
  --difuminado:linear-gradient(to right,
      transparent 0, #000 6%, #000 94%, transparent 100%);
  -webkit-mask-image:var(--difuminado);
          mask-image:var(--difuminado);
}
.galeria__pista{
  display:flex; gap:2.835rem;        /* 28.35 pt */
  width:max-content;
  will-change:transform;
}
.galeria__pieza{
  margin:0; flex:0 0 57.4rem;        /* 574 pt */
  height:36.62rem;                   /* 366.2 pt */
  overflow:hidden;
  background:var(--azul);
}
.galeria__pieza img{width:100%;height:100%;object-fit:cover}

/* --- flechas ------------------------------------------------------------
   No están en el PDF. Se colocan sobre las diapositivas de los lados, que ya
   asoman recortadas por el borde, para no comer nada de la del centro. */
.galeria__flecha{
  position:absolute; top:18.31rem;   /* centro vertical de la banda de 366.2 */
  z-index:4;
  transform:translateY(-50%);
  z-index:3;
  display:grid; place-items:center;
  width:4.4rem; height:4.4rem; padding:0;
  border:0; border-radius:50%;
  background:var(--azul-ui);
  color:var(--blanco);
  cursor:pointer;
  box-shadow:0 .6rem 1.8rem rgba(10,13,53,.4);
  opacity:.82;
  transition:opacity .15s ease, transform .15s ease;
}
.galeria__flecha svg{width:2.2rem; height:2.2rem}
.galeria__flecha:hover{opacity:1; transform:translateY(-50%) scale(1.06)}
.galeria__flecha--prev{left:8rem}
.galeria__flecha--sig{right:8rem}
@media (prefers-reduced-motion:reduce){ .galeria__flecha{transition:none} }

/* puntos de paginación · 5.7 pt de diámetro, paso 15.2 */
.puntos{
  display:flex; justify-content:center; gap:0.95rem;
  margin-top:1.86rem;                /* y 1281.8 */
}
.puntos button{
  width:.57rem;height:.57rem;padding:0;border:0;border-radius:50%;
  background:#163c75;opacity:.35;cursor:pointer;
}
.puntos button[aria-current="true"]{opacity:1}
.puntos--claros button{background:var(--blanco)}

/* ==========================================================================
   SERVICIOS TECNOLÓGICOS · y 1300–1707
   ========================================================================== */
.servicios{padding-top:3.31rem}      /* título en y 1320.6 */
.servicios h2{
  font-size:var(--titulo);                  /* 25 pt */
  text-align:center;
  color:var(--azul);
}
.servicios__cuerpo{
  position:relative;
  margin-top:2.99rem;
  height:33.14rem;                   /* hasta y 1706.9 */
}

/* --- selector: ventana de 3 sobre los 7 servicios --- */
/* `flex` para centrar la lista en la columna: la guía va absoluta y no le
   afecta. Centrada aquí, su centro cae en el de la foto. */
.selector{
  position:absolute; left:0; top:-.58rem; width:25.27rem; height:33.72rem;
  display:flex; align-items:center;
}
.selector__lista{
  width:22.76rem;                    /* el texto acaba en x 227.6 */
  text-align:right;
  display:flex; flex-direction:column;
  /* sin `padding-top`: con `box-sizing:border-box` iba por dentro del alto
     fijo y empujaba el contenido 1.25rem por debajo del centro de la caja,
     que es justo lo que desviaba el punto. Servía cuando la lista colgaba de
     arriba; ahora va centrada en la columna y sobra. */
  height:26rem;
}
/* Un tercio del alto para cada uno, con el texto centrado dentro. Antes iban
   con `space-between`, y como los tres nombres tienen distinto número de
   líneas, el del medio caía en un sitio distinto según cuáles se enseñaran:
   el punto de la guía, que lo marca, se desviaba hasta 31 px. Con tercios
   iguales el activo está SIEMPRE en el centro de la lista, y el punto puede
   ir al 50% sin depender de qué servicio esté elegido. */
.selector__lista li{
  flex:1 1 0;
  display:grid; align-content:center;
  /* Al tamaño del cuerpo: el cliente avisó de que «los títulos de lado
     izquierdo están más grandes» que el resto del bloque. Con los siete a la
     vista, además, a 26 px no cabrían. */
  font-size:var(--texto);
  line-height:1.15;
  padding-block:.3rem;
  color:var(--azul);
  cursor:pointer;
}
.selector__lista li[aria-selected="true"]{
  font-weight:600; font-style:italic;
}
.selector__guia{
  position:absolute; left:25.27rem; top:0; bottom:0;
  width:0.1895rem;                   /* trazo de 1.895 pt */
  background:linear-gradient(to bottom,#8b9eba,#6c84a7);
}
.selector__punto{
  position:absolute; left:50%; top:50%;
  width:.92rem;height:.92rem;        /* 9.2 pt */
  margin-left:-.46rem; margin-top:-.46rem;
  border-radius:50%;
  background:var(--azul-punto);
  /* El diseño lo ponía en el 55.3% (y 1560.7), pero eso valía con los textos
     a su tamaño original: al encogerlos, el servicio activo subió y el punto
     se quedó 73 px por debajo de lo que marca. Con la lista ya centrada en la
     columna, el activo cae en el centro, así que el punto va al 50% y sigue
     al texto en vez de a una coordenada. */
  top:50%;
  transition:top .3s ease;
}

.servicios__figura{
  position:absolute; left:28.96rem; top:.99rem;    /* x 289.6 · y 1385.4 */
  width:35.87rem; height:30.71rem;                 /* 358.7 × 307.1 */
  margin:0; overflow:hidden; border-radius:.8rem;
}
.servicios__figura{position:relative; overflow:hidden}
.servicios__figura img{width:100%;height:100%;object-fit:cover}

.servicios__detalle{
  position:absolute; left:67.21rem;
  width:32.92rem;                                  /* 329.2 pt */
  /* La caja copia la vertical de la foto y el contenido se centra dentro. Se
     hace con flex y no con `transform` porque este bloque lleva animación de
     aparición, y su `.hecho` deja el transform en `none`: borraría el
     centrado. Además el texto cambia de largo con cada servicio, así que un
     `top` fijo sólo cuadraría con uno. */
  top:.99rem; height:30.71rem;                     /* la vertical de la foto */
  display:flex; flex-direction:column; justify-content:center;
}
.servicios__detalle p{
  text-align:justify;
  line-height:1.2;                                 /* salto de 18 pt sobre 15 */
}
.servicios__detalle p + p{margin-top:1.8rem}
.servicios__detalle .pildora{margin-top:2.4rem}

/* ==========================================================================
   SECTORES E INDUSTRIAS · y 1707 en adelante
   El diseño dibuja 9 en 4+5; van 11 en 4+4+3 (decisión registrada en
   docs/05-contenido-y-contradicciones.md). La sección crece 171.7 pt.
   ========================================================================== */
.sectores{padding-top:2.4rem; color:var(--blanco)}
.sectores h2{
  font-size:var(--titulo);                  /* 25 pt · y 1730.9 */
  text-align:center;
}
/* 24 columnas y no 4: con 4 columnas no hay forma de centrar la última fila
   de 3 sin que el tercero se desborde a una fila nueva. Con 24, cada celda
   ocupa 6 y las tres últimas empiezan en la 4, la 10 y la 16 — centradas. */
.sectores__rejilla{
  display:grid;
  grid-template-columns:repeat(24,1fr);
  row-gap:6.05rem;                   /* paso de fila 171.7 − 111.2 de celda */
  margin-top:4.96rem;                /* iconos en y 1805.5 */
  padding-inline:6.5rem;
}
.sectores__rejilla li{grid-column:span 6}
.sectores__rejilla li{
  display:flex; flex-direction:column; align-items:center;
  text-align:center;
}
.sectores__rejilla img{
  width:7rem; height:7rem;           /* caja de 70 × 70 pt */
  object-fit:contain;
}
.sectores__rejilla span{
  margin-top:1.32rem;                /* pie en y 1888.7 */
  font-size:var(--texto);
  line-height:1;
}
/* la última fila lleva 3: se centra bajo la rejilla de 4 */
.sectores__rejilla li:nth-child(9){grid-column:4 / span 6}
.sectores__rejilla li:nth-child(10){grid-column:10 / span 6}
.sectores__rejilla li:nth-child(11){grid-column:16 / span 6}

/* ==========================================================================
   PROYECTOS · y 2120–2470
   ========================================================================== */
/* El `padding-bottom` no sale del PDF tal cual. Allí proyectos y clientes son
   las dos azules, así que la frontera no se ve y lo único medible es la
   distancia de la foto al titular de clientes: 2435.7 -> 2572.6 = 136.9 pt.
   Como la clienta pidió la franja de clientes en blanco, esa frontera ahora sí
   se ve, y el reparto importa: todo el aire va del lado azul para que la foto
   no quede pegada al blanco, y `.clientes` conserva sus 5.6rem simétricos.
   136.9 - 56 = 80.9 pt. */
.proyectos{padding-top:7.47rem; padding-bottom:8.09rem; color:var(--blanco)}
.proyectos h2{font-size:var(--titulo); text-align:center}   /* y 2163.1 */
.proyectos__cuerpo{
  /* `center` y no `flex-start`: el texto bajó de 20 pt a 15 px y ya no llena
     el alto de la foto, así que arrancando arriba dejaba un hueco de 75 pt
     debajo. Medido con la foto a 288 px y el texto a 138. */
  display:flex; align-items:center;
  margin-top:3.19rem;                                /* foto en y 2220 */
  padding-left:17.96rem;                             /* x 179.6 */
  gap:3.68rem;
}
.proyectos__foto{
  margin:0; flex:0 0 35.27rem; height:21.57rem;      /* 352.7 × 215.7 */
  border-radius:.6rem;
  box-shadow:0 1rem 2.4rem rgba(10,13,53,.35);
}
/* `cover`, no los porcentajes medidos de antes. La foto de Biciruta era una
   captura de un visor 3D con dos barras de interfaz y una cuña de fondo negro
   arriba; se recortó el archivo (1614x908 -> 1614x568, quitando hasta y=340) y
   aquellos offsets, atados a la retícula vieja, dejaban 168 px vacíos. Con
   `cover` las tres piezas que usan esta foto —portada, cabecera y ficha de
   Proyectos— encuadran solas y aguantan un cambio de imagen. */
.proyectos__foto img{position:static; width:100%; height:100%; object-fit:cover}

.proyectos__texto{width:41rem; font-size:var(--texto); text-align:justify}  /* el diseño trae 20 pt */
.proyectos__nombre{font-weight:600; font-style:italic; margin-bottom:1.02rem}
.proyectos .pildora{margin-top:1.37rem}              /* y 2410 */

/* ==========================================================================
   CLIENTES DESTACADOS · y 2470–2765 · discos de 118.7 pt, paso 218.7
   ========================================================================== */
/* Fondo blanco: sobre el azul del lienzo se veía el disco de cada logo como
   una pelota, y el cliente quiere poder añadir logos sin pelearse con el
   fondo. Al cambiar el fondo hay que cambiar también el color del titular, que
   era blanco. */
/* La franja va A SANGRE. Con el fondo blanco y el ancho de 108rem que heredaba
   de `.lienzo > section`, quedaba una caja blanca flotando sobre el azul, con
   la foto asomando por los lados: parecía pegada. A sangre se lee como una
   banda del sitio, y además la cinta se desvanece contra el borde de la
   pantalla en vez de contra un canto. */
/* `.lienzo > .clientes` y no `.clientes`: `.lienzo > section` le pone el tope
   de 108rem y es más específico, así que sin el `>` la caja seguía en 1440. */
.lienzo > .clientes{max-width:none}
.clientes{
  width:100%;
  /* equilibrado: antes el titular quedaba arriba y sobraba una franja de
     blanco debajo de los logotipos */
  padding-block:5.6rem;
  background:var(--blanco); color:var(--azul);
}
.clientes h2{color:var(--azul)}
.clientes h2{font-size:var(--titulo); text-align:center}    /* y 2521 */
/* Cinta continua: los 27 logotipos escritos dos veces, desplazándose hacia la
   izquierda sin parar. El paso entre discos es el del diseño (218.7 − 118.7).
   Sin `transition`: lo mueve el JS fotograma a fotograma, y una transición
   pelearía con ese movimiento. */
.clientes__marco{position:relative; margin-top:3.4rem}
/* La ventana es la que recorta, y se desvanece por los lados: sin eso la cinta
   se corta en seco contra el borde. Las flechas van FUERA de ella, o la
   máscara también las difuminaría. */
.clientes__ventana{
  overflow:hidden;
  /* más ancho que antes (7%): ahí es donde viven las flechas, y así ningún
     logotipo queda debajo de una a plena opacidad */
  --difuminado:linear-gradient(to right,
      transparent 0, #000 11%, #000 89%, transparent 100%);
  -webkit-mask-image:var(--difuminado);
          mask-image:var(--difuminado);
}
.clientes__pista{
  /* El paso del diseño (218.7 − 118.7 = 10rem) se calculó para una caja de
     1080. A sangre deja la cinta muy vacía, así que se junta. */
  display:flex; gap:7rem;
  width:max-content;
  will-change:transform;
}
/* Las de esta cinta van sobre blanco, no sobre una foto: a tamaño y opacidad
   plenos tapaban el primer y el último logotipo. Se hacen más pequeñas, se
   apoyan en el blanco con un halo y sólo se encienden al pasar por encima. */
.clientes__marco .galeria__flecha{
  top:50%; z-index:4;
  width:3.6rem; height:3.6rem;
  background:var(--blanco);
  color:var(--azul);
  opacity:.55;
  box-shadow:0 .3rem 1.2rem rgba(10,13,53,.18), 0 0 0 .1rem rgba(23,61,117,.12);
}
.clientes__marco .galeria__flecha:hover{
  opacity:1; background:var(--azul-ui); color:var(--blanco);
}
.clientes__marco .galeria__flecha--prev{left:1.6rem}
.clientes__marco .galeria__flecha--sig{right:1.6rem}
.clientes__disco{
  flex:0 0 13rem; height:13rem;       /* el diseño traía 118.7 pt */
  border-radius:50%;
  background:var(--blanco);
  display:grid; place-items:center;
  overflow:hidden;
  /* Sobre blanco los logotipos ya no tienen disco que los encuadre, así que un
     respiro interior evita que los más anchos se peguen al vecino. */
  padding:.9rem;
}
.clientes__disco img{
  width:100%; height:100%; object-fit:contain;
  /* Tope de alto: sin él los logotipos verticales (UVG) se ven mucho mayores
     que los apaisados aunque ocupen la misma caja. */
  max-height:9.4rem;
}
/* Los puntos de paginación desaparecen con la cinta continua —no marcarían
   nada—, pero su hueco se conserva: 2.4 + 0.57 de los puntos + 4.44 que ya
   tenía la sección. Si no, todo lo que va debajo sube 30 pt y deja de
   coincidir con el PDF. */

/* ==========================================================================
   ##########  PÁGINA «TECNOLOGÍA Y EQUIPAMIENTO» (pág. 1 del PDF)  ##########
   1080 × 2130 pt. Reutiliza cabecera, píldora, contacto y pie.
   ========================================================================== */
.lienzo--claro{background:var(--blanco)}

/* --- héroe · foto y 0–625.6, se funde en blanco por abajo --- */
.lienzo__heroe-fondo--tec{height:62.56rem}
.lienzo__heroe-fondo--tec img{
  width:178.50%; left:-42.44%; top:-164.29%;   /* colocación del PDF (xref 316) */
  -webkit-mask-image:none; mask-image:none;
}
/* Velo medido comparando el render con la foto original fila a fila: arriba un
   oscurecido constante de ~0.35, y a partir de la mitad una disolución a blanco
   que se completa hacia y 540. */
.velo-tec{
  position:absolute; inset:0;
  background:linear-gradient(to bottom,
    rgba(6,10,20,.42)      0%,
    rgba(6,10,20,.34)     25%,   /* y 156 */
    rgba(6,10,20,.33)     38%,   /* y 238 */
    rgba(90,95,105,.50)   47%,   /* y 294 */
    rgba(175,178,190,.60) 62%,   /* y 388 */
    rgba(226,228,232,.85) 70%,   /* y 438 */
    rgba(252,252,253,.98) 79%,   /* y 494 */
    #fff                  86%,   /* y 538 */
    #fff                 100%);
}

.heroe--tec{
  height:51.88rem;                   /* 0 → 518.8 */
  padding-top:24.31rem;              /* H1 en y 243.1 */
  padding-right:0;                   /* aquí el H1 SÍ va centrado en la página */
  text-align:center;
}
.heroe--tec h1{font-size:var(--titulo); color:var(--blanco)}

/* --- introducción · y 518.8–764.6 · texto justificado, NO centrado --- */
.intro{
  /* Sin alto fijo. El diseño traía 245.8 pt y el texto no los llena: debajo
     quedaban 216 px de vacío, el mismo problema que ya se corrigió en las dos
     tarjetas de la portada. Ahora lo decide el contenido y la separación la
     pone el relleno. */
  height:auto;
  padding-block:3.5rem 0;
  padding-left:9.45rem;              /* x 94.5 */
}
/* El diseño dejaba el texto en 767 pt, con 218.5 de aire muerto a la derecha.
   El cliente lo señaló en Nosotros y luego en Tecnología: lo ve como un error,
   no como aire. 891 pt = 1080 - 94.5 de margen a cada lado, el mismo borde al
   que llegan `.bloque` y `.fichas`. */
.intro > *{width:89.1rem}
.intro p{text-align:justify}
.intro p + p{margin-top:1.5rem}
.antetitulo{
  font-weight:600; font-style:italic;
  margin-bottom:1.53rem;             /* primer párrafo en y 549.1 */
}

/* --- tarjeta «Tecnología y equipos» · y 764.6–1240 --- */
/* `.lienzo > section` lleva `margin-inline:auto` y tiene MÁS especificidad
   (0,1,1) que `.tarjeta-tec` (0,1,0): sin el `.lienzo >` de delante, el
   margen automático gana y la tarjeta se centra sola. */
.lienzo > .tarjeta-tec{
  width:77.88rem;                    /* 778.8 pt */
  margin-left:17.18rem;              /* x 171.8 — no está centrada en la página */
  margin-right:auto;
  min-height:47.54rem;               /* 475.4 pt */
  padding:4.24rem 0 4.91rem;
  background:var(--blanco);
  border-radius:3rem;
  box-shadow:0 1.6rem 4rem rgba(10,13,53,.16);
}
.tarjeta-tec h2{font-size:var(--titulo); text-align:center}   /* 25 pt · y 807 */

.equipos{display:grid}
.equipos li{
  display:flex; flex-direction:column; align-items:center; text-align:center;
}
/* Banda de altura fija con el icono centrado: en el diseño los siete tienen
   tamaños distintos pero comparten eje vertical (centros en y 933 y 1095). */
.equipos__icono{display:grid; place-items:center}
.equipos img{object-fit:contain}
.equipos li > span:last-child{
  font-size:var(--texto);
  line-height:1.2;
}
/* Cada icono conserva su tamaño del diseño: no son todos iguales. */
.equipos img[src$="tec-drones.svg"]        {width:9.01rem; height:9.01rem}
.equipos img[src$="tec-lidar.svg"]         {width:9.52rem; height:9rem}
.equipos img[src$="tec-gnss.svg"]          {width:8.08rem; height:9.54rem}
.equipos img[src$="tec-fotogrametria.svg"] {width:9.81rem; height:9rem}
.equipos img[src$="tec-topografico.svg"]   {width:4.72rem; height:9.5rem}
.equipos img[src$="tec-slam.svg"]          {width:7.15rem; height:9.59rem}
.equipos img[src$="tec-procesamiento.svg"] {width:10.29rem; height:9.03rem}

.equipos--cuatro{
  grid-template-columns:repeat(4,1fr);
  padding-inline:3.28rem;            /* centros en 121.9 / 300.2 / 478.6 / 656.9 */
  margin-top:5.33rem;                /* banda centrada en y 933 */
}
.equipos--cuatro .equipos__icono{height:9.54rem}
.equipos--cuatro li > span:last-child{margin-top:.82rem}   /* pies en y 988.9 */

.equipos--tres{
  grid-template-columns:repeat(3,1fr);
  padding-inline:7.14rem;            /* centros en 177.4 / 389.4 / 601.4 */
  margin-top:2.46rem;                /* banda centrada en y 1095 */
}
.equipos--tres .equipos__icono{height:9.59rem}
.equipos--tres li > span:last-child{margin-top:1.44rem}    /* pies en y 1157.3 */

/* --- innovación continua · y 1240–1608 --- */
.innovacion{
  position:relative;
  height:36.84rem;
}
.innovacion__foto{
  position:absolute; margin:0;
  left:8.73rem; top:5.99rem;         /* x 87.3 · y 1299.9 */
  width:43.15rem; height:30.85rem;   /* 431.5 × 308.5 */
  overflow:hidden; border-radius:1.4rem;
  box-shadow:0 1.2rem 3rem rgba(10,13,53,.25);
}
.innovacion__foto img{
  position:absolute; height:auto; max-width:none;
  width:105.91%; left:-2.94%; top:-31.25%;   /* colocación del PDF (xref 418) */
}
.innovacion__texto{
  position:absolute;
  left:56.71rem;
  /* centrado sobre la foto: su centro está en 5.99 + 30.85/2 = 21.42rem.
     Aquí sí se puede usar `transform` porque este bloque no lleva animación
     de aparición; si algún día se le pone, hay que rehacer esto. */
  top:21.42rem; transform:translateY(-50%);   /* el diseño lo ponía en y 1339.3 */
  /* 423.8 en casi todas las líneas, pero la última del tercer párrafo mide
     425.6 en el PDF: con 423.8 justos, «proyectos.» se cae a una cuarta línea
     y el bloque deja de coincidir. El cuadro de texto real es un pelo más ancho. */
  width:42.6rem;
}
.innovacion h2{font-size:var(--titulo)}
.innovacion__texto p{margin-top:1.5rem; text-align:justify}
.innovacion__texto > p:first-of-type{margin-top:1.42rem}   /* y 1378.5 */

/* estas dos páginas tienen otro aire alrededor del bloque de contacto */
.contacto--tec{--contacto-aire:5.17rem}
.pie--tec{--pie-abajo:9.4rem}

/* ==========================================================================
   ##############  FICHA DE SERVICIO (pág. 3 del PDF)  ##############
   1080 × 1520.2 pt. Es la plantilla de las 7 páginas de servicio; se genera
   con `python construir.py` desde web/_datos/servicios.json.
   ========================================================================== */

/* --- héroe · foto y 0–603.8, se disuelve en blanco --- */
.lienzo__heroe-fondo--serv{height:62.56rem}
.lienzo__heroe-fondo--serv img{
  position:static; width:100%; height:100%; max-width:none;
  left:auto; top:auto;
  object-fit:cover; object-position:50% 45%;
  -webkit-mask-image:none; mask-image:none;
}
/* Velo medido fila a fila: oscurecido constante de ~0.21 hasta la mitad y
   disolución a blanco que se completa hacia y 600. */
.velo-serv{
  position:absolute; inset:0;
  background:linear-gradient(to bottom,
    rgba(4,6,14,.28)       0%,
    rgba(4,6,14,.21)      21%,   /* y 131 */
    rgba(4,6,14,.22)      40%,   /* y 250 */
    rgba(30,32,40,.26)    53%,   /* y 332 */
    rgba(80,84,96,.34)    59%,   /* y 369 */
    rgba(150,155,180,.45) 66%,   /* y 413 */
    rgba(195,196,205,.56) 72%,   /* y 450 */
    rgba(215,214,218,.70) 78%,   /* y 488 */
    rgba(235,234,238,.82) 85%,   /* y 532 */
    rgba(248,248,250,.94) 91%,   /* y 569 */
    #fff                  97%,
    #fff                 100%);
}

/* Seis de las siete fotos definitivas son claras justo en la franja del
   titular (luminancia medida: de 111 a 182 sobre 255, contra 77 de la única
   oscura). Con el velo del diseño el blanco se pierde encima, así que esas
   llevan uno más denso. Quién lo lleva no se decide a ojo: lo mide
   _extraido/fotos_servicio.py y lo escribe en _datos/servicios.json. */
.heroe-fondo--claro .velo-serv{
  background:linear-gradient(to bottom,
    rgba(4,6,14,.52)       0%,
    rgba(4,6,14,.46)      21%,
    rgba(4,6,14,.46)      40%,
    rgba(30,32,40,.48)    53%,
    rgba(80,84,96,.52)    59%,
    rgba(150,155,180,.58) 66%,
    rgba(195,196,205,.66) 72%,
    rgba(215,214,218,.76) 78%,
    rgba(235,234,238,.86) 85%,
    rgba(248,248,250,.95) 91%,
    #fff                  97%,
    #fff                 100%);
}

/* Tercer nivel. Los montajes que mando el cliente tienen paneles muy
   brillantes justo donde cae el texto, y con el velo reforzado seguian
   sin llegar al 4.5:1 que pide la norma para el cuerpo. Quien lo lleva no
   se decide a ojo: lo mide _extraido/probar_contraste.py, que esconde el
   texto y fotografia lo que queda detras. */
.heroe-fondo--fuerte .velo-serv{background:linear-gradient(to bottom,
    rgba(4,6,14,0.69)       0%,
    rgba(4,6,14,0.63)      21%,
    rgba(4,6,14,0.63)      40%,
    rgba(30,32,40,0.65)    53%,
    rgba(80,84,96,0.69)    59%,
    rgba(150,155,180,0.75) 66%,
    rgba(195,196,205,0.83) 72%,
    rgba(215,214,218,0.93) 78%,
    rgba(235,234,238,0.93) 85%,
    rgba(248,248,250,0.93) 91%,
    #fff                  97%,
    #fff                 100%)}

.heroe--serv{
  height:60.28rem;                   /* 0 → 602.8 */
  padding-top:27.01rem;              /* H1 en y 270.1 */
  padding-right:0;
  text-align:center;
  color:var(--blanco);
}
.heroe--serv h1{font-size:var(--titulo); color:var(--blanco)}

/* --- el héroe de Nosotros: sólo la imagen y el título ---
   Con los párrafos fuera, el alto del diseño dejaba 327 px de hueco bajo el
   título. Se recorta y el título se centra en lo que queda. */
.heroe--nos{
  height:42rem;
  padding-top:0;
  display:flex; flex-direction:column; justify-content:center;
}
.lienzo__heroe-fondo--nos{height:44.3rem}
.intro--entrada{padding-top:5rem}
.heroe--serv p{
  width:57rem; margin-inline:auto;   /* la línea más larga del diseño mide 569.6 */
  line-height:1.2;                   /* salto de 18 pt sobre 15 */
  /* Corta, cerrada y oscura: separa la letra de la foto sin que se note que
     hay una sombra. Una difusa sobre un collage sólo ensucia. Las nueve
     páginas con este héroe llevan texto blanco sobre foto — comprobado. */
  text-shadow:0 .1rem .3rem rgba(10,13,53,.55);
}
.heroe--serv > p:first-of-type{margin-top:.97rem}   /* y 309.8 */
.heroe--serv p + p{margin-top:1.8rem}               /* y 381.8 */

@media (min-width:1000px){
  /* La entradilla de los nueve héroes va a 1.5rem (20 px). Es lo que el
     cliente aprobó el 16/10, y se queda aunque el cuerpo haya bajado a 1.2:
     mayor que el cuerpo es la jerarquía que se buscaba.

     El móvil no entra aquí: allí `--texto` ya es 1.4rem y la raíz es menor,
     así que la entradilla ya es proporcionalmente grande. */
  .heroe--serv p{font-size:1.5rem}
}

/* Sólo en Proyectos: el cliente lo pidió centrado. El resto del sitio va
   justificado, que es lo que se acordó en septiembre, así que esto se cuelga
   de `.lienzo--proyectos` y no toca a las fichas de servicio, que comparten
   `.heroe--serv`. Justificado dejaba la segunda línea corta y pegada a la
   izquierda debajo de un título centrado. */
.lienzo--proyectos .heroe p{text-align:center}

/* Contacto, igual que Proyectos: el cliente lo quiere centrado. `text-wrap:balance`
   reparte las líneas en vez de dejar la última suelta y corta — es lo que hace que
   un texto centrado se vea cuidado y no descolgado. Donde no esté soportado,
   simplemente se centra sin repartir. */
.lienzo--contacto .heroe p{text-align:center; text-wrap:balance}

/* --- dos fichas · y 602.8–1034.6 · 262.8 × 431.7, separadas 79.5 --- */
.fichas{
  display:flex; justify-content:center;
  gap:7.95rem;                       /* 79.5 pt */
  padding-right:1.47rem;             /* el par está 7.35 a la izquierda del centro */
}
.ficha{
  flex:0 0 26.28rem;                 /* 262.8 pt */
  /* El diseño les daba 431.7 pt fijos, pero con los textos a 15 px sobraban
     221 y 319 px por debajo del contenido. El cliente las quiere cortadas
     donde acaba el texto, así que el alto lo pone el contenido. */
  padding-bottom:3.4rem;
  background:var(--azul);
  border-radius:2rem;
  box-shadow:0 1.4rem 3.4rem rgba(10,13,53,.3);
  color:var(--blanco);
  padding-inline:2.97rem 3.2rem;     /* viñeta en x +29.7 */
}
.ficha h2{font-size:var(--titulo); text-align:center}        /* 30 pt */
.ficha ul{
  font-size:var(--texto);            /* el diseño trae 14.82 */
  line-height:1.35;                  /* salto de 20 pt */
  letter-spacing:0;                  /* estas listas van SIN tracking */
}
.ficha li{
  position:relative;
  padding-left:1.79rem;              /* el texto arranca 17.9 después de la viñeta */
  /* sin margen entre elementos: en el diseño el aire lo pone la interlínea de
     20 pt y nada más. Con margen, la ficha crece y deja de medir 431.7 */
}
.ficha li::before{
  content:'•';
  position:absolute; left:0; top:0;
}
.ficha--a h2{margin-top:2.28rem}     /* y 625.6 */
.ficha--a ul{margin-top:1.08rem}     /* y 666.4 */
.ficha--b h2{margin-top:1.20rem}     /* y 614.8, dos líneas */
.ficha--b ul{margin-top:2.02rem}     /* y 695.0 */

.contacto--serv{--contacto-aire:8.22rem}   /* título en y 1116.8 */
.pie--serv{--pie-abajo:2.7rem}

/* ==========================================================================
   ####################  PÁGINA «NOSOTROS»  ####################
   No está en el PDF. Todo lo que hay aquí son variantes de piezas que sí lo
   están: el héroe de la ficha, la introducción justificada de Tecnología, el
   bloque de foto y texto de «Innovación Continua» y las fichas azules.
   ========================================================================== */

/* TODO lo de esta sección va colgado de `.lienzo--nosotros`. Sin ese ancla,
   `.intro` y `.fichas` alcanzarían también a Tecnología y a las 7 fichas, que
   tienen alturas exactas del PDF, y las romperían sin avisar. */


/* --- bloque de foto y texto, en las dos direcciones --------------------- */
.lienzo--nosotros .bloque{
  display:flex; align-items:center; gap:6.5rem;
  padding:7rem 9.45rem 0;            /* mismo margen izquierdo que la introducción */
}
.lienzo--nosotros .bloque--invertido{flex-direction:row-reverse}

/* Cierre de Nosotros. Historia de este número: con 7rem eran 180 px y el cliente
   dijo que sobraba; se quitó y quedaron los 87 que ponía el bloque de contacto;
   al quitar también ese bloque caía a 33, demasiado apretado. 3.5rem -> 80 px,
   casi los mismos 87 que ya se habían dado por buenos.
   Va AQUÍ y no antes de `.lienzo--nosotros .bloque{...}`: misma especificidad
   (0,2,0), decide el orden, y su atajo `padding:7rem 9.45rem 0` pondría el
   inferior a 0. */
.lienzo--nosotros .bloque--invertido{padding-bottom:3.5rem}
.lienzo--nosotros .bloque__foto{
  position:relative; overflow:hidden;
  margin:0; flex:0 0 43.15rem; height:30.85rem;   /* la medida del PDF (431.5 × 308.5) */
  border-radius:1.4rem;
  box-shadow:0 1.2rem 3rem rgba(10,13,53,.25);
}
.lienzo--nosotros .bloque__foto img{width:100%; height:100%; object-fit:cover}

/* El mapa de presencia no es una foto: con el marco, la sombra y el recorte a
   `cover` parecería la fotografía de un mapa, y además se comería los rótulos
   de los bordes. Va limpio, entero y sobre el blanco de la página. */
.lienzo--nosotros .bloque__foto--mapa{
  height:auto;
  border-radius:0;
  box-shadow:none;
  align-self:center;
  /* Más ancho que el bloque de foto (43.15rem, la medida del PDF): el cliente
     pidió el mapa más cerca. El archivo ya venía con un 19% de aire horneado
     —se recortó— y aun así se quedaba pequeño. 48rem, y la separación baja de
     6.5 a 5rem, dejan el texto en 481 px, que sigue leyéndose justificado. */
  flex:0 0 48rem;
}
.lienzo--nosotros .bloque--invertido{gap:5rem}
.lienzo--nosotros .bloque__foto--mapa img{height:auto; object-fit:contain}
.lienzo--nosotros .bloque__texto{flex:1}
.lienzo--nosotros .bloque__texto h2{font-size:var(--titulo)}                /* 25 pt, como los demás */
.lienzo--nosotros .bloque__texto p{margin-top:1.5rem; text-align:justify}
.lienzo--nosotros .bloque__texto > p:first-of-type{margin-top:1.42rem}

/* --- las fichas azules, aquí con texto corrido en vez de viñetas -------- */
/* Las fichas de servicio miden 262.8 porque llevan viñetas de una o dos
   palabras. Para texto corrido esa anchura deja columnas de cinco palabras y
   el justificado se abre en canales: aquí ocupan la mitad del ancho útil. */
.lienzo--nosotros .fichas{
  padding:7rem 9.45rem 0;
  gap:6.5rem;
  align-items:stretch;
}
.ficha--texto{flex:1 1 0; min-height:0; padding-bottom:3.4rem}
.ficha--texto p{
  margin-top:1.5rem;
  font-size:var(--texto);            /* la interlínea la manda la regla común */
  text-align:justify;
}
.ficha--texto.ficha--b h2{margin-top:2.28rem}      /* «Visión» cabe en una línea */

/* --- valores: ocho cápsulas con la geometría de la píldora -------------- */
.lienzo--nosotros .valores{padding-block:7rem 0; text-align:center}
.lienzo--nosotros .valores h2{font-size:var(--titulo)}

/* «Historia» encabeza todo el relato de la página. Mismo tamaño que los demás
   titulares de sección (Nuestros Valores, Presencia nacional), para que no
   parezca otro nivel. El `.intro` que lo lleva ya aporta su `padding-top`, así
   que el h2 sólo necesita separarse de su propio antetítulo. */
.lienzo--nosotros .intro h2{font-size:var(--titulo); margin-bottom:2.4rem}
.lienzo--nosotros .valores__lista{
  display:flex; flex-wrap:wrap; justify-content:center;
  gap:1.4rem;
  margin-top:3rem;
  padding-inline:9.45rem;
}
.lienzo--nosotros .valores__lista li{
  padding:.9rem 2.6rem;
  border:0.12rem solid var(--azul);
  border-radius:1.8rem;              /* cápsula, como el botón */
  font-size:var(--texto);
  letter-spacing:var(--tr-cuerpo);
}

/* el bloque de contacto de esta página respira como el de la portada */
/* --- la cinta de clientes, también al final de «Nosotros» ----------------
   Allí el lienzo es blanco y los discos también, así que la sección se trae su
   propia banda azul y va a sangre, como en la portada. */
.clientes--banda{
  max-width:none !important;
  background:linear-gradient(to bottom, #163c74 0%, #24487d 55%, #3a5789 100%);
  padding-block:7rem;
  margin-top:6rem;
}

.contacto--nos{--contacto-aire:6.5rem}

/* ==========================================================================
   FOTO A SANGRE · y 2765.3–3275
   ========================================================================== */
.banda-foto{height:50.97rem}                         /* 509.7 pt */
.banda-foto img{width:139.83%; left:-15.18%; top:-89.23%}

/* ==========================================================================
   CONTACTO · y 3275–3650
   ========================================================================== */
.contacto{background:var(--blanco); padding-block:var(--contacto-aire,4.62rem) 0}
.contacto__interior{
  max-width:var(--ancho); margin-inline:auto;
  position:relative;
  min-height:33.71rem;
}
.contacto h2{font-size:var(--titulo)}                       /* y 3321.2 · x 53.5 */
.contacto__datos{margin-left:5.35rem}
.contacto__datos ul{margin-top:2.94rem}              /* primer dato en y 3370.6 */
.contacto__datos li{
  display:flex; align-items:flex-start; gap:1.28rem;
  margin-bottom:1.28rem;
  line-height:1.05;
}
.contacto__datos svg{
  width:1.9rem; height:1.9rem; flex:0 0 1.9rem;
  fill:currentColor; margin-top:.1rem;
}
.contacto__datos a:hover{text-decoration:underline}

/* --- formulario · campos de 438.4 × 33.7, separación 10, área de 92.4 --- */
.formulario{
  position:absolute; right:5.41rem; top:.76rem;      /* acaba en x 1025.9 */
  width:43.84rem;                                    /* 438.4 pt */
  display:flex; flex-direction:column; gap:1rem;     /* 10 pt */
}
.formulario input,
.formulario select,
.formulario textarea{
  width:100%; height:3.37rem;                        /* 33.7 pt */
  padding-inline:1.68rem;
  font-family:var(--cuerpo);
  font-size:var(--texto);                            /* el diseño trae 15.61 */
  letter-spacing:var(--tr-cuerpo);
  color:var(--azul);
  /* blanco explícito y no `transparent`: da igual sobre el blanco de la
     sección, pero deja el campo a salvo de cualquier fondo que se le ponga
     detrás. La flecha del <select> la pone una regla posterior con
     `background-image`, que sigue aplicándose. */
  background:var(--blanco);
  border:0.1rem solid var(--azul);
  border-radius:1.685rem;                            /* cápsula */
}
.formulario textarea{
  height:9.24rem;                                    /* 92.4 pt */
  border-radius:1.6rem;
  padding-block:1rem;
  resize:vertical;
}
.formulario ::placeholder{color:var(--azul); opacity:.75}

/* --------------------------------------------------------------------------
   El campo del KMZ/KML · sólo en Contacto

   Un `input[type=file]` nativo no se deja dar forma: lo único que se puede
   vestir es su botón, con `::file-selector-button`. Así que el campo no imita
   la cápsula de los demás —sería un parecido a medias, que se ve peor que una
   diferencia clara— sino que se presenta como lo que es: una zona aparte,
   con su rótulo y su explicación.

   La regla de altura de `.formulario input` hay que anularla: 3.37rem deja el
   botón del navegador recortado.
   -------------------------------------------------------------------------- */
.campo-archivo{
  display:flex; flex-direction:column; gap:.7rem;
  padding:1.4rem 1.68rem 1.5rem;
  border:0.1rem dashed var(--azul);
  border-radius:1.6rem;
}
.campo-archivo__rotulo{display:flex; align-items:center; gap:.8rem}
.campo-archivo__titulo{
  font-size:var(--texto); color:var(--azul); letter-spacing:var(--tr-cuerpo);
}
.campo-archivo__opcional{
  font-size:calc(var(--texto) * .8);
  text-transform:uppercase; letter-spacing:.08em;
  color:var(--azul); opacity:.6;
  border:0.1rem solid currentColor; border-radius:1rem;
  padding:.1rem .7rem;
}
.campo-archivo__fila{display:flex; align-items:center; gap:1rem; flex-wrap:wrap}

/* El `input` va oculto pero SIGUE recibiendo el foco: la regla de
   `.formulario input` le daría 3.37rem de alto y 100% de ancho, así que aquí
   se le devuelve el tamaño de `.vo`. */
.formulario .campo-archivo input[type="file"]{
  width:1px; height:1px; padding:0; border:0; background:none;
}
.campo-archivo__boton{
  font-size:calc(var(--texto) * .92); letter-spacing:var(--tr-cuerpo);
  color:var(--blanco); background:var(--azul);
  border-radius:1.685rem;
  padding:.6rem 1.6rem;
  cursor:pointer;
}
.campo-archivo__boton:hover{background:var(--azul-punto)}
/* Sin esto, quien navegue con el teclado no vería dónde está: el campo real
   es invisible y el navegador dibujaría el anillo alrededor de nada. */
.campo-archivo input[type="file"]:focus-visible + .campo-archivo__boton{
  outline:0.2rem solid var(--azul); outline-offset:.2rem;
}
.campo-archivo__nombre{
  font-size:calc(var(--texto) * .88); color:var(--azul); opacity:.8;
  overflow-wrap:anywhere;
}
/* El formulario va en `position:absolute`, así que NO empuja a su caja: al
   añadirle el campo del KMZ se salía y se montaba encima del pie. La caja
   crece sólo aquí — las siete páginas de servicio comparten `contacto--serv`
   y con el cuerpo a 1.5rem necesitan 32.24rem de las 33.71 que ya tienen, así
   que no se tocan.

   45 = los 44.76rem que mide el formulario en la anchura más exigente
   (medido, no estimado) más un pelo para no quedarse al filo del subpíxel.

   Este número SIGUE al tamaño del cuerpo, porque el bloque del KMZ tiene alto
   automático: fue 44 con 1.125rem, 44.4 con 1.2, 45 con los 1.35 de ahora y
   45.6 con 1.5. Si se vuelve a tocar `--texto` hay que medirlo otra vez —
   quedarse corto monta el formulario sobre el pie, y pasarse deja un hueco
   muerto encima de él.

   Las siete de servicio no entran aquí y no hace falta tocarlas: su
   formulario no lleva el bloque del archivo, así que su alto lo mandan las
   alturas fijas de los campos y no cambia con el tamaño del texto —necesitan
   32.24rem de las 33.71 que ya tienen, a cualquier anchura. */
.contacto--kmz .contacto__interior{min-height:45rem}

.campo-archivo__pista{
  font-size:calc(var(--texto) * .85);
  line-height:1.35; color:var(--azul); opacity:.85;
}

/* el desplegable nativo rompe la cápsula: se anula y se dibuja la flecha */
.formulario select{
  appearance:none; -webkit-appearance:none;
  padding-right:4.5rem;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23173d75' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round' d='M5 9l7 7 7-7'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 2rem center;
  background-size:1.6rem;
}
.formulario select:invalid{color:var(--azul); opacity:.75}

.pildora--enviar{margin-top:1.19rem; align-self:flex-start; margin-left:.16rem}

/* ==========================================================================
   PIE · y 3650–3727
   ========================================================================== */
.pie{background:var(--blanco); padding-block:2.05rem var(--pie-abajo,3rem)}
.pie__interior{
  max-width:var(--ancho); margin-inline:auto;
  display:flex; align-items:center; justify-content:space-between;
  padding-inline:5.35rem 5.41rem;
}
.pie__credito{
  font-size:calc(var(--texto) * .89);                /* el diseño lo pone bajo el cuerpo */
  letter-spacing:var(--tr-cuerpo);
  text-transform:uppercase;                          /* Montserrat sí lo necesita */
}
.pie__redes{display:flex; gap:1.5rem}
.pie__redes svg{width:1.85rem;height:1.85rem;fill:var(--azul)}
.pie__redes a:hover svg{opacity:.7}

/* ==========================================================================
   MOVIMIENTO
   Dos piezas: la aparición al entrar en pantalla y los estados de hover.

   Regla que no se salta: sólo se animan `opacity` y `transform`. Ninguna de
   las dos toca el layout, así que las coordenadas medidas contra el PDF se
   quedan donde estaban y el navegador puede componer en la GPU.

   Cuidado con `transform`: convierte al elemento en bloque contenedor de sus
   descendientes absolutos. Por eso NO se anima `.lienzo`, ni `.quienes`, ni
   `.servicios__cuerpo`, ni `.proyectos__cuerpo`: son el ancla de las fotos
   colocadas al punto. Se animan sus hijos.

   La clase `anim-ok` la pone un script en el <head>, ANTES de pintar. Si el
   JS no corre, o el visitante pide menos movimiento, o el navegador no trae
   IntersectionObserver, la clase no aparece, la opacidad 0 nunca se aplica y
   la página se ve entera. El fallo es «sin animación», jamás «sin contenido».

   La aparición va con `animation` y no con `transition` por un motivo
   concreto: varios de estos elementos —iconos de sector, tarjetas— llevan
   además un `:hover` con su propia transición de 0.28 s. Si la aparición
   fuese una transición, su regla (más específica) dejaría esos elementos con
   0.7 s para siempre y el hover respondería con retardo. Con `animation`, en
   cuanto termina el JS marca `hecho` y el elemento se queda limpio.
   ========================================================================== */
@keyframes aparecer{
  from{opacity:0; transform:translateY(2.4rem)}
  to  {opacity:1; transform:none}
}

.anim-ok .anim,
.anim-ok .anim-lista > *{opacity:0}

.anim-ok .anim.visible,
.anim-ok .anim-lista.visible > *{
  animation:aparecer .7s cubic-bezier(.22,.61,.36,1) both;
}

/* Escalonado de las rejillas: cada hijo entra 70 ms después del anterior. Se
   corta en el duodécimo —hay 11 sectores— para que la última fila no se haga
   esperar más de tres cuartos de segundo. */
  .anim-ok .anim-lista.visible > *:nth-child(2){animation-delay:0.07s}
  .anim-ok .anim-lista.visible > *:nth-child(3){animation-delay:0.14s}
  .anim-ok .anim-lista.visible > *:nth-child(4){animation-delay:0.21s}
  .anim-ok .anim-lista.visible > *:nth-child(5){animation-delay:0.28s}
  .anim-ok .anim-lista.visible > *:nth-child(6){animation-delay:0.35s}
  .anim-ok .anim-lista.visible > *:nth-child(7){animation-delay:0.42s}
  .anim-ok .anim-lista.visible > *:nth-child(8){animation-delay:0.49s}
  .anim-ok .anim-lista.visible > *:nth-child(9){animation-delay:0.56s}
  .anim-ok .anim-lista.visible > *:nth-child(10){animation-delay:0.63s}
  .anim-ok .anim-lista.visible > *:nth-child(11){animation-delay:0.70s}
  .anim-ok .anim-lista.visible > *:nth-child(12){animation-delay:0.77s}

/* Terminada la aparición. Sin esto, `both` seguiría fijando `transform:none`
   desde la animación, que en la cascada gana a cualquier `:hover`. */
.anim-ok .anim.hecho,
.anim-ok .anim-lista.hecho > *{opacity:1; transform:none; animation:none}

/* --- hover: el mismo gesto en todo el sitio, un empujón hacia arriba ------
   Con `transform` y no con `margin` o `top`: así no se recalcula el layout
   en cada pasada del ratón. */
.sectores__rejilla li,
.equipos li,
.clientes__disco,
.galeria__pieza img,
.tarjeta-tec,
.ficha,
.selector__lista li{
  transition:transform .28s ease, box-shadow .28s ease, opacity .2s ease;
}
.sectores__rejilla li:hover,
.equipos li:hover{transform:translateY(-.7rem)}
.clientes__disco:hover{transform:translateY(-.5rem) scale(1.06)}
.galeria__pieza{overflow:hidden}
.galeria__pieza:hover img{transform:scale(1.06)}
.tarjeta-tec:hover,
.ficha:hover{transform:translateY(-.5rem)}
.selector__lista li:hover{opacity:.72; transform:translateX(-.4rem)}

/* Quien pide menos movimiento no recibe ninguno: ni apariciones ni hover. */
@media (prefers-reduced-motion:reduce){
  .anim-ok .anim,
  .anim-ok .anim-lista > *{opacity:1; animation:none}
  .sectores__rejilla li,
  .equipos li,
  .clientes__disco,
  .galeria__pieza img,
  .tarjeta-tec,
  .ficha,
  .selector__lista li{transition:none}
  .sectores__rejilla li:hover,
  .equipos li:hover,
  .clientes__disco:hover,
  .galeria__pieza:hover img,
  .tarjeta-tec:hover,
  .ficha:hover,
  .selector__lista li:hover{transform:none}
}

/* ==========================================================================
   REDES FLOTANTES
   El cliente las quiere «flotando». Van ancladas al borde derecho, centradas
   verticalmente, y siguen estando en el pie: quitarlas de allí dejaría el pie
   del diseño cojo. En móvil pasan a la esquina inferior, que es donde no
   estorban al pulgar ni al contenido.
   ========================================================================== */
.redes-flotantes{
  position:fixed; right:1.6rem; top:50%; transform:translateY(-50%);
  z-index:35;
  display:flex; flex-direction:column; gap:.8rem;
  margin:0; padding:0; list-style:none;
}
.redes-flotantes a{
  display:grid; place-items:center;
  width:3.8rem; height:3.8rem;
  border-radius:50%;
  background:var(--azul-ui);
  color:var(--blanco);
  box-shadow:0 .4rem 1.2rem rgba(10,13,53,.3);
  transition:transform .2s ease, background-color .2s ease;
}
.redes-flotantes a:hover{transform:translateY(-.3rem); background:var(--azul-punto)}
.redes-flotantes svg{width:1.9rem; height:1.9rem; fill:currentColor}

/* --------------------------------------------------------------------------
   Botón de WhatsApp.

   Va aparte de las redes flotantes a propósito: no es un enlace a un perfil,
   es la llamada a la acción. De ahí el verde de la marca —el único color del
   sitio que no sale de la paleta, porque aquí se reconoce antes el icono que
   el diseño— y la esquina inferior derecha, que es donde ya se busca sin
   mirar.

   En escritorio no choca con las redes: ellas van centradas verticalmente
   (4 iconos = 17.6rem, del 41.2% al 58.8% del alto) y esto vive abajo del
   todo. El número sale del teléfono de contacto; lo pone construir.py y lo
   repone el panel en cada visita.
   -------------------------------------------------------------------------- */
.wasap{
  position:fixed; right:1.6rem; bottom:1.6rem;
  z-index:36;                        /* una más que las redes flotantes */
  display:grid; place-items:center;
  width:4.6rem; height:4.6rem;
  border-radius:50%;
  background:#25d366; color:#fff;
  box-shadow:0 .4rem 1.2rem rgba(10,13,53,.3);
  transition:transform .2s ease, background-color .2s ease, opacity .25s ease;
}
.wasap:hover{transform:translateY(-.3rem); background:#1da851}
.wasap svg{width:2.7rem; height:2.7rem; fill:currentColor}

/* Al llegar al pie, el botón se retira.

   Vive pegado al borde inferior de la ventana, así que al final de la página
   cae justo encima de la fila de redes del pie y le tapa un icono. Pasaba en
   las doce páginas; en Proyectos salta a la vista, porque es corta.

   Se RETIRA, no se sube. Subirlo fue lo primero que probé y el remedio salió
   peor: en Contacto y en los siete servicios el formulario está pegado al
   pie, así que el botón subía y aterrizaba sobre el campo de «Servicio
   solicitado». Tapar un campo de un formulario es peor que tapar un icono
   que, además, está repetido ahí mismo en el pie.

   `portada.js` pone la clase en el instante exacto en que el borde de arriba
   del pie cruza por encima del botón: ni antes —sería un parpadeo sin
   motivo— ni después, que ya lo habría tapado. */
.redes-flotantes{transition:opacity .25s ease}
.pie-a-la-vista .wasap{opacity:0; pointer-events:none}

@media (prefers-reduced-motion:reduce){
  .cabecera, .redes-flotantes a, .redes-flotantes, .wasap{transition:none}
  .redes-flotantes a:hover, .wasap:hover{transform:none}
}

/* ==========================================================================
   AGRÉGANOS TU KMZ · página de contacto
   ========================================================================== */
.kmz{
  display:flex; align-items:center; gap:6.5rem;
  padding:7rem 9.45rem;
}
.kmz__texto{flex:1 1 0}
.kmz__texto h2{font-size:var(--titulo); margin-bottom:1.5rem}
.kmz__texto p{text-align:justify; line-height:1.2}
.kmz__texto p + p{margin-top:1.5rem}

/* `.pildora` mide 9.65rem clavados —es la medida de los «Leer más» del
   diseño— y aquí el rótulo es largo. Sólo se le suelta el ancho; alto, color
   y sombra siguen siendo los de todos los botones del sitio. */
.pildora--kmz{
  width:auto; padding-inline:2.4rem;
  margin-top:2.4rem;
  text-decoration:none;
}
.kmz__video{
  flex:0 0 48rem;
  aspect-ratio:9 / 16;              /* el vídeo del cliente es un «short» */
  max-height:54rem;
  border-radius:1.4rem; overflow:hidden;
  box-shadow:0 1.2rem 3rem rgba(10,13,53,.25);
}
.kmz__video iframe{width:100%; height:100%; border:0; display:block}

/* ==========================================================================
   PROYECTOS · la página
   Las fichas alternan el lado de la foto para que la columna no se lea como
   una lista. Salen de _datos/proyectos.json.
   ========================================================================== */
.proyectos-lista{padding:6rem 9.45rem 8rem; display:flex; flex-direction:column; gap:7rem}
.proyecto{display:flex; align-items:center; gap:6.5rem}
.proyecto--invertido{flex-direction:row-reverse}
.proyecto__foto{
  flex:0 0 46rem; height:30rem; margin:0;
  border-radius:1.4rem; overflow:hidden;
  box-shadow:0 1.2rem 3rem rgba(10,13,53,.25);
}
.proyecto__foto img{width:100%; height:100%; object-fit:cover}
.proyecto__texto{flex:1 1 0}
.proyecto__meta{
  font-weight:600; font-style:italic;
  color:var(--azul-punto); margin-bottom:.6rem;
}
.proyecto__texto h2{font-size:var(--titulo); margin-bottom:1.5rem}
.proyecto__texto p{text-align:justify; line-height:1.2}
.proyecto__entregables{
  margin:1.8rem 0 0; padding:0; list-style:none;
  display:flex; flex-wrap:wrap; gap:.8rem 1rem;
}
.proyecto__entregables li{
  padding:.7rem 1.8rem;
  border:.12rem solid var(--azul);
  border-radius:1.8rem;
  letter-spacing:var(--tr-cuerpo);
}

/* `[hidden]` lo pone el navegador como `display:none`, pero cualquier regla
   con `display` propio le gana. Le pasa a los dos: `.formulario` declara
   `display:flex` y `.formulario__acuse` declara `display:grid`. Sin estas dos
   líneas el acuse se ve desde que carga la página, flotando sobre el
   formulario, y el formulario sigue viéndose detrás del acuse al enviar.
   Lo vigila `_extraido/auditar_hidden.py`. */
.formulario[hidden],
.formulario__acuse[hidden]{display:none}

/* Aviso de que el envío falló. Mismo tratamiento que el acuse: el `[hidden]`
   necesita su propia línea porque la regla de arriba declara `display`. */
.formulario__error{
  color:#b3261e; font-weight:600;
  line-height:1.2; margin-top:-.4rem;
}
.formulario__error[hidden]{display:none}

/* --- acuse de recibo del formulario --- */
.formulario__acuse{
  position:absolute; right:0; top:.76rem;
  width:43.84rem;                    /* el ancho del formulario */
  display:grid; place-items:center; gap:1.2rem;
  padding:4rem 3rem;
  text-align:center;
  border:.1rem solid var(--azul);
  border-radius:1.4rem;
  color:var(--azul);
}
.formulario__acuse svg{
  width:4.4rem; height:4.4rem;
  color:var(--azul-punto);
}
.formulario__acuse-titulo{
  font-weight:600; text-transform:uppercase;
  letter-spacing:var(--tr-cuerpo);
}

/* ==========================================================================
   PANTALLAS MÁS ANCHAS QUE 1440
   El contenido deja de crecer en 1440, pero las dos bandas a sangre siguen
   ocupando todo el ancho. Como su alto va en rem —que ya está topado— la
   proporción de la caja deja de ser la del diseño y el encuadre exacto
   descuadra. A partir de aquí las fotos pasan a `cover`, con el centro puesto
   en la misma zona de la imagen que enseña el PDF.
   ========================================================================== */
@media (min-width:1441px){
  .lienzo__heroe-fondo img,
  .banda-foto img{
    position:static; width:100%; height:100%; max-width:100%;
    left:auto; top:auto;
    object-fit:cover;
  }
  .lienzo__heroe-fondo img{object-position:42% 52%}
  .banda-foto img{object-position:47% 63%}

  }

/* ==========================================================================
   MÓVIL · por debajo de 1000 px
   El diseño mide 1080 pt: el corte tiene que quedar POR DEBAJO de ese ancho,
   o la maqueta de escritorio nunca llega a verse a su tamaño de referencia.
   Entre 1000 y 1080 el diseño se reduce un poco (a 1000 px el cuerpo queda en
   13.9 px, aceptable); por debajo entra el diseño móvil, porque escalar el de
   escritorio hasta 390 px dejaría el cuerpo en 5 px.
   ========================================================================== */
@media (max-width:999px){
  html{font-size:clamp(9px, 2.6vw, 12px)}
  /* Aquí la raíz mide de 9 a 12 px, no 13.333: heredar los valores de
     escritorio dejaría el cuerpo en 11 px. El móvil conserva el suyo y los
     titulares guardan la misma proporción (1.267) que arriba. */
  :root{--texto:1.4rem; --titulo:3.36rem}

  /* El degradado del lienzo está calibrado en porcentajes del montaje de
     escritorio. Al reordenar en una columna las secciones cambian de altura y
     el degradado se descuadra: los iconos blancos de Sectores acababan sobre
     fondo claro, invisibles. En móvil cada sección lleva su propio fondo. */
  .lienzo{background:#173d75}
  .galeria{background:linear-gradient(to bottom,#173d75 0,#173d75 55%,#e9edf2 100%)}
  .servicios{background:linear-gradient(to bottom,#e9edf2 0,#fff 8%,#fff 86%,#c6d0de 100%)}
  .sectores{background:linear-gradient(to bottom,#c6d0de 0,#3d5c8b 22%,#173d75 55%)}
  .proyectos{background:#173d75}
  /* `.clientes` NO lleva fondo propio aquí a propósito. Heredaba un
     degradado azul de cuando la franja era azul; al pasarla a blanco
     por petición de la clienta se cambió arriba y esta línea se quedó
     atrás, así que en móvil el titular quedaba #173d75 sobre #173d75:
     invisible. Es plano, no depende del degradado del lienzo, y con un
     solo sitio donde vive el color no se puede volver a desincronizar. */

  .cabecera__interior{padding-inline:2rem}
  .logo{margin-left:0}

  .hamburguesa{
    display:flex; flex-direction:column; justify-content:center; gap:.5rem;
    margin-left:auto; width:4.4rem; height:4.4rem;
    background:none; border:0; cursor:pointer; padding:0;
  }
  .hamburguesa span:not(.vo){display:block;height:.25rem;background:var(--blanco);border-radius:.2rem}

  .menu{
    position:absolute; inset-inline:0; top:7.4rem;
    margin:0; background:var(--azul-ui);
    display:none;
  }
  .menu[data-abierto="true"]{display:block}
  .menu > ul{flex-direction:column; gap:0; padding:1rem 2rem 2rem}
  .menu > ul > li > a{display:block; padding:1.4rem 0; font-size:1.8rem}

  /* el desplegable pasa a ser una lista dentro del propio menú: en una
     columna estrecha un panel flotante no cabe */
  .menu__desplegable{flex-wrap:wrap}
  .menu__desplegable > a{flex:1}
  .menu__flecha{width:4.4rem; height:4.4rem; margin-left:0}
  .menu__flecha svg{width:1.8rem; height:1.8rem}
  .submenu{
    position:static; transform:none; min-width:0; width:100%;
    background:rgba(0,0,0,.18);
    border-radius:1rem;
    padding-block:.6rem;
    box-shadow:none;
    display:none; opacity:1; visibility:visible;
  }
  /* en móvil sólo abre el botón: `hover` no existe como estado permanente y
     `focus-within` se dispararía al tabular, dejándolo abierto sin querer */
  .menu__desplegable:hover > .submenu,
  .menu__desplegable:focus-within > .submenu{display:none}
  /* El selector tiene que ser tan específico como el de arriba. `:hover`
     cuenta como clase, así que `.menu__desplegable:hover > .submenu` es
     (0,3,0) y le ganaba a `.submenu[data-abierto]` (0,2,0): al tocar la
     flecha el puntero queda encima y el panel volvía a ocultarse. */
  .menu__desplegable > .submenu[data-abierto="true"]{display:block; transform:none}
  .submenu a{font-size:1.5rem; padding:1rem 1.6rem; white-space:normal}

  .lienzo > section{padding-inline:2.4rem}

  .heroe{height:auto; padding-block:16rem 8rem}
  .heroe h1{font-size:var(--titulo)}
  .lienzo__heroe-fondo{height:42rem}

  /* `block`: aquí la foto deja de ser absoluta y con el flex de
     escritorio se colocaría en fila junto al texto. */
  .quienes{height:auto; padding-bottom:6rem; display:block}
  .quienes__texto{width:auto; margin-left:0}
  /* `relative`, no `static`: si deja de ser bloque contenedor, su <img>
     absoluta se cuelga de un ancestro y el overflow:hidden deja de
     recortarla — sin dar ningún error, sólo desborde horizontal */
  .quienes__foto{
    position:relative; left:auto; top:auto;
    width:100%; height:28rem; margin-top:3rem;
  }

  .galeria__pista{gap:1.8rem}
  /* ancho explícito: con `flex-basis:100%` dentro de una pista `max-content`
     la medida sería circular. Así además se ve más de una foto a la vez, que
     es lo que hace que se entienda que la cinta se mueve. */
  .galeria__pieza{flex:0 0 30rem; height:20rem}

  /* En una columna estrecha la flecha siempre taparía la imagen o un logotipo,
     y en táctil tampoco hay `hover` con el que pausar: las cintas se dejan
     correr solas. Vale para las dos, que comparten clase. */
  .galeria__flecha{display:none}

  .servicios__cuerpo{height:auto; display:flex; flex-direction:column; gap:3rem}
  .selector{position:static; width:auto; height:auto; display:block}
  .selector__lista{
    width:auto; height:auto; text-align:left; padding:0;
    flex-direction:row; gap:2rem; overflow-x:auto;
  }
  .selector__lista li{flex:0 0 auto; display:block; font-size:1.7rem; line-height:1.2}
  .selector__guia{display:none}
  /* `height:auto`: el alto de escritorio copia el de la foto, y aquí
     dejaría una caja de 300 px con el texto flotando en medio */
  .servicios__detalle{position:static; width:100%; height:auto}
  /* hay que anular también left/top, o el desplazamiento del escritorio
     (left:28.96rem) sigue empujando la figura fuera de la pantalla */
  .servicios__figura{position:relative; left:auto; top:auto; width:100%; height:26rem}
    .sectores__rejilla{grid-template-columns:repeat(2,1fr); padding-inline:0; row-gap:3.6rem}
  .sectores__rejilla li,
  .sectores__rejilla li:nth-child(9),
  .sectores__rejilla li:nth-child(10),
  .sectores__rejilla li:nth-child(11){grid-column:auto}

  /* en columna, `align-items` pasa a ser el eje horizontal: con `center`
     heredado del escritorio los hijos dejarían de ocupar el ancho */
  .proyectos__cuerpo{flex-direction:column; padding-left:0; gap:2.4rem;
                     align-items:stretch}
  .proyectos__foto{flex:0 0 auto; width:100%; height:24rem}
  .proyectos__texto{width:auto; font-size:1.7rem}

  .clientes__pista{gap:4.5rem}
  .clientes__disco{flex:0 0 11rem; height:11rem}

  .clientes__marco .galeria__flecha{top:50%; width:3.6rem; height:3.6rem}
  .clientes__marco .galeria__flecha svg{width:1.8rem; height:1.8rem}
  .clientes__marco .galeria__flecha--prev{left:0}
  .clientes__marco .galeria__flecha--sig{right:0}

  /* Completa, no recortada: en móvil la imagen lleva el encuadre exacto del
     PDF y sobresalía 81 px del marco. Aquí manda la proporción de la foto. */
  .banda-foto{height:auto}
  .banda-foto img{position:static; width:100%; height:auto; display:block}

  .contacto__interior{min-height:0; padding-inline:0}
  .contacto__datos{margin-left:0}
  .formulario__acuse{position:static; width:100%; margin-top:4rem}
  .formulario{
    position:static; width:100%; margin-top:4rem;
  }
  .formulario input,.formulario select{height:4.4rem}
  .formulario textarea{height:12rem}

  .pie__interior{
    flex-direction:column; gap:2.4rem; padding-inline:0; text-align:center;
  }

  /* ---------- página «Tecnología y Equipamiento» ---------- */
  /* hay que repetirlo: la regla móvil `.lienzo{background:#173d75}` de arriba
     tiene la misma especificidad y va antes, así que ganaba ella y el texto
     azul de la introducción quedaba sobre fondo azul */
  .lienzo--claro{background:var(--blanco)}

  .lienzo__heroe-fondo--tec{height:34rem}
  /* La foto nueva del equipo es más clara que el valle que había antes y el
     titular caía a 2.63:1. Oscurecer la parte de ARRIBA no servía —de hecho
     empeoraba—: en móvil la banda mide 332 px y el titular cae en el 41–61%
     del degradado, justo donde el velo de escritorio ya ha virado a gris
     claro. Lo que hace falta es correr el desvanecido hacia abajo, no
     oscurecer. Se eligió la variante más floja que pasa, como hace
     `ajustar_velos.py`: 7.0–7.2:1 contra un mínimo de 3. */
  .velo-tec{background:linear-gradient(to bottom,
    rgba(6,10,20,.52)      0%,
    rgba(6,10,20,.50)     32%,
    rgba(6,10,20,.48)     66%,
    rgba(140,145,156,.66) 76%,
    rgba(235,236,240,.92) 86%,
    #fff                  94%,
    #fff                 100%)}
  .lienzo__heroe-fondo--tec img{
    position:static; width:100%; height:100%; max-width:100%;
    left:auto; top:auto; object-fit:cover; object-position:50% 40%;
  }
  /* el hueco de abajo tiene que dejar pasar el velo: si la introducción
     empieza antes de que la foto se haya disuelto del todo, el texto azul
     queda sobre la fotografía y no se lee */
  .heroe--tec{height:auto; padding-block:14rem 9rem}
  .heroe--tec h1{font-size:var(--titulo)}

  .intro{height:auto; padding-left:0; padding-bottom:4rem}
  .intro > *{width:auto}

  /* sin el `.lienzo >` no gana a `margin-inline:auto` de `.lienzo > section` */
  .lienzo > .tarjeta-tec{
    width:auto; margin-inline:0; min-height:0;
    padding:3rem 1.6rem 3.5rem;
    border-radius:2rem;
  }
  .equipos--cuatro,
  .equipos--tres{
    grid-template-columns:repeat(2,1fr);
    padding-inline:0; row-gap:3.2rem;
  }
  .equipos--cuatro{margin-top:3.4rem}
  .equipos--tres{margin-top:3.2rem}

  .innovacion{
    height:auto; display:flex; flex-direction:column; gap:2.6rem;
    padding-block:4rem;
  }
  /* `relative`, no `static`: la <img> de dentro es absoluta y dejaría de
     estar recortada por el figure (misma trampa que en la portada) */
  .innovacion__foto{
    position:relative; left:auto; top:auto;
    width:100%; height:26rem;
  }
  .innovacion__texto{position:relative; left:auto; top:auto; width:auto; transform:none}

  .contacto--tec{--contacto-aire:4.62rem}
  .pie--tec{--pie-abajo:3rem}

  /* ---------- páginas nuevas: contacto y proyectos ---------- */
  .kmz{flex-direction:column; gap:3rem; padding:5rem 2.4rem}
  .kmz__video{flex:0 0 auto; width:100%; max-height:none; aspect-ratio:9 / 16}

  .proyectos-lista{padding:4rem 2.4rem 6rem; gap:4.5rem}
  .proyecto,
  .proyecto--invertido{flex-direction:column; gap:2.4rem}
  .proyecto__foto{flex:0 0 auto; width:100%; height:24rem}

  /* las redes flotantes estorban en el centro de una pantalla estrecha */
  .redes-flotantes{
    top:auto; bottom:1.6rem; right:1.6rem; transform:none;
    flex-direction:row;
  }
  .redes-flotantes a{width:3.4rem; height:3.4rem}

  /* El WhatsApp se APILA encima de las redes, no al otro lado. Se probó
     llevándolas a la izquierda y ahí tapaban el «Leer más» de la portada:
     esta esquina lleva meses comprobada contra el contenido y no se mueve.
     1.6 (hueco) + 3.4 (alto de las redes) + 1 de aire = 6rem. */
  .wasap{bottom:6rem; width:4.2rem; height:4.2rem}
  .wasap svg{width:2.5rem; height:2.5rem}

  /* Aquí las redes también están ancladas abajo, así que también estorban al
     pie. En escritorio no: van centradas a media altura y nunca lo rozan —
     por eso esta regla vive dentro del bloque móvil y no fuera, y allí los
     iconos siguen a la vista todo el rato. */
  .pie-a-la-vista .redes-flotantes{opacity:0; pointer-events:none}

  /* ---------- fichas de servicio ---------- */
  /* El alto va MEDIDO: el titular mas los dos parrafos mas largos (los de
     «Desarrollo Tecnológico») acaban en 45rem a 320 px de ancho, que es
     donde más envuelven. Con la caja en 40rem esa última línea caía fuera
     de la foto —blanco sobre blanco—, así que la caja sube a 56rem y el
     velo empieza a disolver en el 80%, ya por debajo del texto. */
  .lienzo__heroe-fondo--serv{height:56rem}
  .velo-serv{background:linear-gradient(to bottom,
    rgba(4,6,14,.28)       0%,
    rgba(4,6,14,.21)      42%,
    rgba(4,6,14,.22)      80%,
    rgba(30,32,40,.26)    84.56%,
    rgba(80,84,96,.34)    86.67%,
    rgba(150,155,180,.45) 89.12%,
    rgba(195,196,205,.56) 91.23%,
    rgba(215,214,218,.70) 93.33%,
    rgba(235,234,238,.82) 95.79%,
    rgba(248,248,250,.94) 97.89%,
    #fff                  100%,
    #fff                 100%)}
  .heroe-fondo--claro .velo-serv{background:linear-gradient(to bottom,
    rgba(4,6,14,.52)       0%,
    rgba(4,6,14,.46)      42%,
    rgba(4,6,14,.46)      80%,
    rgba(30,32,40,.48)    84.56%,
    rgba(80,84,96,.52)    86.67%,
    rgba(150,155,180,.58) 89.12%,
    rgba(195,196,205,.66) 91.23%,
    rgba(215,214,218,.76) 93.33%,
    rgba(235,234,238,.86) 95.79%,
    rgba(248,248,250,.95) 97.89%,
    #fff                  100%,
    #fff                 100%)}
  /* Estas dos líneas estuvieron pegadas en un mismo selector por un desliz de
     edición: `.lienzo__heroe-fondo--serv img, .heroe--serv{...}`. El
     `padding-block:14rem 7rem` era para la sección, pero se lo comía también la
     foto —168 px de relleno dentro de su caja—, y por ese hueco se veía el
     blanco del lienzo teñido de gris por el velo. Afectaba a las diez páginas
     con héroe `--serv`. La cuenta cuadraba: 516 + 168 + 84 = 768 px. */
  .lienzo__heroe-fondo--serv img{
    position:static; width:100%; height:100%; max-width:100%;
    left:auto; top:auto; padding:0;
    object-fit:cover;
  }
  .heroe--serv{height:auto; padding-block:14rem 7rem}
  /* El de Nosotros lleva sólo el título, así que su foto tiene que acabar
     donde acaba él. Van juntos y DESPUÉS de la regla de `--serv`, que si no
     gana por orden y la foto se comía el texto de debajo. */
  .heroe--nos{height:30rem; padding-block:0}
  .lienzo__heroe-fondo--nos{height:32rem}
  .heroe--serv h1{font-size:var(--titulo)}
  .heroe--serv p{width:auto}

  .fichas{
    flex-direction:column; gap:2.4rem;
    padding-right:0;
  }
  .ficha{flex:0 0 auto; min-height:0; padding-bottom:3rem}

  .contacto--serv{--contacto-aire:4.62rem}
  .pie--serv{--pie-abajo:3rem}

  /* ---------- página «Nosotros» ---------- */
  /* hay que repetir el selector completo: `.lienzo--nosotros .fichas` (0,2,0)
     gana a la regla móvil de `.fichas` (0,1,0) aunque vaya después */
  .lienzo--nosotros .fichas{
    flex-direction:column; gap:2.4rem;
    padding:5rem 0 0;
  }
  .lienzo--nosotros .bloque,
  .lienzo--nosotros .bloque--invertido{
    flex-direction:column; gap:2.6rem;
    padding:5rem 0 0;
  }
  .lienzo--nosotros .bloque__foto{flex:0 0 auto; width:100%; height:26rem}
  /* el mapa entero, sin alto fijo: con él se recortaban 11 px por abajo */
  .lienzo--nosotros .bloque__foto--mapa{height:auto}
  /* `padding-inline:0` ganaba por especificidad al 2.4rem de `.lienzo >
     section` y el texto quedaba pegado a los dos bordes. El cliente lo pidió
     con márgenes. */
  .lienzo--nosotros .intro{padding-inline:2.4rem; padding-block:4.5rem 0}
  .lienzo--nosotros .bloque{padding-inline:2.4rem}
  .lienzo--nosotros .intro--cierre{padding-bottom:5rem}
  .lienzo--nosotros .valores{padding-block:5rem 0}
  .lienzo--nosotros .valores__lista{padding-inline:0; gap:1rem}
  .lienzo--nosotros .valores__lista li{padding:.8rem 1.8rem; font-size:var(--texto)}

  .contacto--nos{--contacto-aire:4.62rem}
  .pie--nos{--pie-abajo:3rem}
}
