/* ============================================================================
   SERVIMATHE S.A.S. — hoja de estilos global
   Compartida por las 9 paginas. Antes vivia inline en <style> dentro de
   <helmet> (index.html:154-232, runtime DC). Se conserva LITERAL salvo tres
   bloques que dejaron de existir al quitar support.js e image-slot.js:
     - .sc-placeholder / .sc-interp.sc-missing  (clases del runtime DC)
     - image-slot::part(image) { touch-action }  (ya no hay shadow DOM)
     - @keyframes marquee                        (nunca se uso)
   ============================================================================ */

/* ---------- 1. Base ---------- */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body { background: #ffffff; color: #0c2c52; font-family: 'Barlow', sans-serif; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
a { color: #2f9e38; text-decoration: none; }
a:hover { color: #278a30; }
img { display: block; max-width: 100%; }

/* El header es position:fixed. Sin esto, /nosotros#cumplimiento aterriza
   con el titular tapado por el header. Debe coincidir con .nav-spacer.
   NO anadir aqui 'scroll-behavior: smooth': la galeria de servicios de la home
   coloca la pagina con window.scrollTo() y da por hecho que el salto es seco;
   con scroll suave esos saltos pasarian a ser animados y la galeria se
   desincronizaria del scroll sin que salte ningun error. */
html { scroll-padding-top: 115px; }

/* Contenedor central. Antes estaba repetido inline en los 39 .wrap
   (`max-width:1240px; margin:0 auto;`). El padding sigue inline porque
   varia por seccion, y las media queries lo pisan con !important. */
.wrap { max-width: 1240px; margin: 0 auto; }

/* ---------- 2. Aparicion al hacer scroll ---------- */
@keyframes revealUp { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }

/* IMPORTANTE — el estado OCULTO va prefijado con .js, el visible NO.
   La clase 'js' la pone un script inline del <head>. Si site.js no carga
   (bloqueador, error de red), el contenido se ve igual, sin animacion,
   en vez de quedar invisible para siempre. Es tambien lo que ve Googlebot
   en su primer pase, antes de renderizar. */
.js .reveal, .js .grid-3 > div, .js .grid-4 > div, .js .grid-6 > div, .js .row-2 { opacity: 0; transform: translateY(24px); }
.reveal.in, .grid-3 > div.in, .grid-4 > div.in, .grid-6 > div.in, .row-2.in { opacity: 1; transform: none; animation: revealUp .7s ease forwards; }
@media (prefers-reduced-motion: reduce) {
  .reveal, .grid-3 > div, .grid-4 > div, .grid-6 > div, .row-2 { opacity: 1 !important; transform: none !important; animation: none !important; }
}

/* ---------- 2b. Zoom lento del hero (Ken Burns) ----------
   El hero es un solo video estatico (sin carrusel), asi que el zoom corre
   una sola vez desde el page load: la clase .kb-play ya viene en el HTML,
   no hace falta JS para reiniciarla. */
@keyframes heroKenBurns { from { transform: scale(1); } to { transform: scale(1.08); } }
.media.kb-play { animation: heroKenBurns 9s ease-out forwards; }
@media (prefers-reduced-motion: reduce) {
  .media.kb-play { animation: none !important; transform: scale(1) !important; }
}

/* ---------- 3. Navegacion ---------- */
.hamburger-btn { display: none; }
.mobile-menu { display: flex; max-height: 0; opacity: 0; overflow: hidden; transition: max-height .35s ease, opacity .25s ease; }
.mobile-menu.open { max-height: 420px; opacity: 1; }
@media (min-width: 861px) { .mobile-menu { display: none !important; } }
.nav-spacer { height: 115px; }

/* El icono X sustituye a la hamburguesa segun aria-expanded. Antes eran dos
   interpolaciones del runtime ({{ dHam }} / {{ dX }}); ahora sale del mismo
   atributo que ya necesita el lector de pantalla: una sola fuente de verdad. */
.hamburger-btn .ico-ham { display: flex; flex-direction: column; gap: 5px; }
.hamburger-btn .ico-x { display: none; }
.hamburger-btn[aria-expanded="true"] .ico-ham { display: none; }
.hamburger-btn[aria-expanded="true"] .ico-x { display: block; }

/* --- Color de los enlaces --------------------------------------------------
   TRAMPA: la regla global `a { color:#2f9e38 }` tine de verde TODO enlace.
   Al convertir los 46 <span onClick> del runtime en <a href> reales, el nav,
   el footer y los titulos de tarjeta se volverian verdes de golpe. Hay que
   acotarla ANTES de que existan esos enlaces. */
header a, footer a { color: inherit; }
.nav-links a, .mobile-menu a[data-nav] { color: #51617a; }
.nav-links a[aria-current="page"], .mobile-menu a[aria-current="page"] { color: #0c2c52; }

/* ---------- 4. Hovers (antes atributo style-hover del runtime) -------------
   Los 43 style-hover del original eran solo 6 valores distintos.
   El runtime los aplicaba escribiendo en element.style, asi que ganaban
   siempre. Una regla de hoja de estilos PIERDE frente a una declaracion
   inline de la misma propiedad -> las dos clases cuyos elementos llevan esa
   propiedad inline necesitan !important. Solo esas dos. Verificado uno a uno.
   -------------------------------------------------------------------------- */

/* x15 — tarjetas claras (servicios home, proyectos, valores, objetivos...)
   Sin !important: estos elementos no llevan transform ni box-shadow inline. */
.hov-lift { transition: transform .25s ease, box-shadow .25s ease; }
.hov-lift:hover, .hov-lift:focus-within {
  transform: translateY(-6px);
  box-shadow: 0 26px 48px -26px rgba(12,44,82,.26);
}

/* x11 — boton verde de WhatsApp / CTA.
   !important OBLIGATORIO: los 11 llevan `background:#2f9e38` inline. */
.hov-green { transition: background .2s ease; }
.hov-green:hover, .hov-green:focus-visible { background: #278a30 !important; }

/* x5 — boton fantasma con borde sobre fondo oscuro.
   Sin !important: no llevan background inline, solo border y color. */
.hov-ghost { transition: background .2s ease; }
.hov-ghost:hover, .hov-ghost:focus-visible { background: rgba(255,255,255,.1); }

/* x1 — CTA blanco sobre la banda verde de Proyectos */
.hov-nudge { transition: transform .2s ease; }
.hov-nudge:hover, .hov-nudge:focus-visible { transform: translateY(-2px); }

/* ---------- 5. Imagenes (antes el custom element <image-slot>) -------------
   Los 57 slots usaban shape="rect" (sin border-radius: el redondeo lo pone
   siempre el wrapper padre) y solo se diferenciaban en fit. El atributo
   radius="18" de 7 de ellos era codigo muerto: image-slot.js solo lo leia
   cuando shape era 'rounded'. Por eso todo el mapeo se reduce a esto. */
.media { width: 100%; height: 100%; object-fit: cover; display: block; }
.media--contain { object-fit: contain; }

/* Hueco de certificacion sin imagen todavia (replica el estado .empty del
   componente que se elimino). Ver clientes.html. */
.cert-vacio {
  width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; text-align: center;
  font: 500 13px/1.3 'Barlow', sans-serif; color: rgba(0,0,0,.55);
  border: 1.5px dashed rgba(0,0,0,.25); border-radius: 8px;
}
.cert-vacio svg { opacity: .45; }

/* ---------- 6. Accesibilidad ---------- */
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus {
  left: 16px; top: 16px; z-index: 100;
  background: #fff; color: #0c2c52; padding: 12px 18px; border-radius: 8px;
  font-family: 'Barlow Semi Condensed', sans-serif; font-weight: 700;
}
:focus-visible { outline: 3px solid #57b947; outline-offset: 2px; }

/* Toda la tarjeta clicable, pero con UN solo enlace de texto sensato.
   Envolver el bloque entero en <a> daria un texto de enlace de tres lineas
   al lector de pantalla. */
.stretch::after { content: ""; position: absolute; inset: 0; z-index: 1; }

/* ---------- 7. Filtro de Proyectos ---------- */
.chip {
  cursor: pointer; font-family: 'Barlow Semi Condensed', sans-serif;
  background: #fff; border: 1px solid #e6ecf3; color: #51617a;
  font-weight: 600; transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.chip:hover { border-color: #c9d6e6; }
.chip[aria-pressed="true"] { background: #0c2c52; border-color: #0c2c52; color: #fff; font-weight: 700; }

/* ---------- 8. Noticias — composicion editorial ---------- */
.news-section {
  padding: 84px 0 104px;
  background: linear-gradient(180deg, #f7f9fc 0%, #fff 38%);
}
.news-section__wrap { padding: 0 48px; }
.news-section__intro {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 48px;
  margin-bottom: 34px;
}
.news-kicker {
  margin: 0 0 8px;
  color: #2f9e38;
  font: 700 13px/1 'Barlow Semi Condensed', sans-serif;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.news-section__title {
  margin: 0;
  color: #0c2c52;
  font: 800 42px/1 'Barlow Semi Condensed', sans-serif;
  letter-spacing: -.015em;
  text-transform: uppercase;
}
.news-section__description {
  max-width: 470px;
  margin: 0;
  color: #63748c;
  font-size: 16px;
  line-height: 1.6;
}
.news-featured,
.news-card {
  position: relative;
  min-width: 0;
  overflow: hidden;
  border: 1px solid #e2e8f0;
  background: #fff;
  transition: transform .25s ease, border-color .25s ease, box-shadow .25s ease;
}
.news-featured:hover,
.news-featured:focus-within,
.news-card:hover,
.news-card:focus-within {
  transform: translateY(-5px);
  border-color: #d0dae7;
  box-shadow: 0 24px 55px -32px rgba(7, 27, 52, .46);
}
.news-featured {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(340px, .85fr);
  min-height: 420px;
  border-radius: 24px;
}
.news-featured__media,
.news-card__media {
  min-width: 0;
  overflow: hidden;
  background: #dfe7f0;
}
.news-featured__media .media,
.news-card__media .media {
  transition: transform .5s ease;
}
.news-featured:hover .media,
.news-featured:focus-within .media,
.news-card:hover .media,
.news-card:focus-within .media {
  transform: scale(1.035);
}
.news-featured__content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  min-width: 0;
  padding: 42px 44px;
}
.news-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 16px;
  color: #7b899c;
  font-size: 12px;
}
.news-tag {
  display: inline-flex;
  align-items: center;
  min-height: 27px;
  padding: 5px 10px;
  border-radius: 999px;
  background: #eaf7e9;
  color: #278a30;
  font: 700 11px/1 'Barlow Semi Condensed', sans-serif;
  letter-spacing: .09em;
  text-transform: uppercase;
}
.news-featured__title,
.news-card__title {
  overflow-wrap: anywhere;
  color: #0c2c52;
  font-family: 'Barlow Semi Condensed', sans-serif;
}
.news-featured__title {
  margin: 0;
  font-size: 34px;
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -.015em;
}
.news-featured__excerpt,
.news-card__excerpt {
  color: #63748c;
  line-height: 1.6;
}
.news-featured__excerpt {
  margin: 18px 0 0;
  font-size: 15px;
}
.news-read-more {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 24px;
  color: #2f9e38;
  font: 700 13px/1 'Barlow Semi Condensed', sans-serif;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.news-read-more span {
  transition: transform .2s ease;
}
.news-featured:hover .news-read-more span,
.news-featured:focus-within .news-read-more span,
.news-card:hover .news-read-more span,
.news-card:focus-within .news-read-more span {
  transform: translateX(4px);
}
.news-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 24px;
  margin-top: 24px;
}
.news-card {
  display: flex;
  grid-column: span 2;
  flex-direction: column;
  border-radius: 18px;
}
.news-card:nth-last-child(-n + 2) { grid-column: span 3; }
.news-card__media { aspect-ratio: 16 / 9; }
.news-card__content {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
  padding: 25px 26px 27px;
}
.news-card__content .news-meta { margin-bottom: 13px; }
.news-card__title {
  margin: 0;
  font-size: 22px;
  font-weight: 700;
  line-height: 1.18;
}
.news-card__excerpt {
  margin: 13px 0 0;
  font-size: 14px;
}
.news-card .news-read-more {
  margin-top: auto;
  padding-top: 22px;
}
@media (max-width: 1024px) {
  .news-featured {
    grid-template-columns: minmax(0, 1.15fr) minmax(320px, .85fr);
  }
  .news-featured__content { padding: 34px; }
  .news-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .news-card,
  .news-card:nth-last-child(-n + 2) { grid-column: auto; }
}
@media (max-width: 760px) {
  .news-section__intro {
    display: block;
  }
  .news-section__description {
    max-width: 620px;
    margin-top: 16px;
  }
  .news-featured {
    grid-template-columns: minmax(0, 1fr);
    min-height: 0;
  }
  .news-featured__media { aspect-ratio: 16 / 9; }
  .news-featured__content { padding: 30px; }
}
@media (max-width: 640px) {
  .news-section { padding: 58px 0 72px; }
  .news-section__wrap { padding: 0 18px; }
  .news-section__intro { margin-bottom: 26px; }
  .news-section__title { font-size: 32px; }
  .news-section__description { font-size: 15px; }
  .news-featured { border-radius: 18px; }
  .news-featured__media { aspect-ratio: 16 / 10; }
  .news-featured__content { padding: 25px 22px 27px; }
  .news-featured__title {
    font-size: 26px;
    line-height: 1.12;
  }
  .news-featured__excerpt { margin-top: 14px; }
  .news-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 18px;
    margin-top: 18px;
  }
  .news-card,
  .news-card:nth-last-child(-n + 2) { grid-column: auto; }
  .news-card__content { padding: 22px 21px 24px; }
  .news-card__title {
    font-size: 22px;
    line-height: 1.18;
  }
}

/* ---------- 8b. Proyecto destacado ---------- */
/* =========================================================
   PROYECTO DESTACADO

   Maquetacion editorial: una foto ancha y, flotando encima, un panel
   desplazado a la derecha que sobresale por abajo.

   Por que asi y no una tarjeta partida en dos columnas: la seccion de
   arriba (Servicios) ya cierra con un panel azul de 610px de alto. Una
   tarjeta del mismo azul y la misma altura justo debajo se leia como el
   mismo objeto repetido dos veces. El solape y la sombra son lo que
   separa las dos piezas.
   ========================================================= */

.featured-project {
  position: relative;

  padding: 120px 0 130px;

  background: #ffffff;

  overflow: hidden;
}


.featured-project__container {
  width: min(1240px, calc(100% - 96px));

  margin: 0 auto;
}


/* =========================================================
   CABECERA
   ========================================================= */

.featured-project__header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 40px;

  margin-bottom: 55px;
}


.featured-project__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 12px;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;

  color: #2f9e38;
}


.featured-project__eyebrow::before {
  content: "";

  width: 34px;
  height: 2px;

  background: #2f9e38;
}


.featured-project__title {
  margin: 15px 0 0;

  max-width: 650px;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: clamp(44px, 5vw, 68px);
  font-weight: 800;
  line-height: .95;
  letter-spacing: -.025em;
  text-transform: uppercase;

  color: #0c2c52;
}


.featured-project__title span {
  color: #7b8795;
}


.featured-project__index {
  display: flex;
  align-items: center;
  gap: 12px;

  padding-bottom: 8px;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .16em;

  color: #7b8795;
}


.featured-project__index span:first-child {
  font-size: 28px;

  color: #0c2c52;
}


.featured-project__index i {
  display: block;

  width: 35px;
  height: 1px;

  background: #cdd5dd;
}


/* =========================================================
   SHOWCASE — LA SUPERPOSICION
   ========================================================= */

.featured-project__showcase {
  position: relative;

  /* El panel sobresale por debajo de la foto. Ese hueco lo reserva un
     padding y no un margen negativo en el panel: con margen negativo la
     seccion siguiente se subiria encima. */
  padding-bottom: 90px;
}


/* =========================================================
   IMAGEN
   ========================================================= */

.featured-project__media {
  position: relative;

  /* La foto no llega al borde derecho del contenedor. Ese carril de
     150px es justo lo que deja al panel sobresalir por fuera en vez de
     quedar encajado dentro de la imagen. */
  width: calc(100% - 150px);
  height: 620px;

  border-radius: 18px;
  overflow: hidden;
}


/* El parallax se aplica a este envoltorio, nunca al <img>.
   site.js escribe el desplazamiento como transform inline; el zoom de
   hover es otro transform. En el mismo elemento el inline gana y el zoom
   no se veria. Separados en dos capas, los dos efectos conviven. */

.featured-project__media-inner {
  position: absolute;

  left: 0;
  right: 0;
  top: -80px;

  /* 160 = 2 x 80, mas del doble del recorrido del parallax (60px).
     Es el colchon que impide que asome el fondo por arriba o por abajo
     en cualquier punto del desplazamiento. Si se sube data-parallax,
     hay que subir esto con el. */
  height: calc(100% + 160px);
}


.featured-project__media img {
  display: block;

  width: 100%;
  height: 100%;

  object-fit: cover;

  transition: transform 1.1s cubic-bezier(.22, 1, .36, 1);
}


/* Doble degradado. El vertical asienta el panel sobre la foto para que
   no parezca pegado; el horizontal solo da fondo al sello SERVIMATHE de
   abajo a la izquierda, que sobre una zona clara se perdia. */

.featured-project__media::after {
  content: "";

  position: absolute;
  inset: 0;

  background:
    linear-gradient(
      180deg,
      rgba(4, 18, 35, 0) 45%,
      rgba(4, 18, 35, .55) 100%
    ),
    linear-gradient(
      90deg,
      rgba(4, 18, 35, .32) 0%,
      rgba(4, 18, 35, 0) 45%
    );

  pointer-events: none;
}


.featured-project__media-label {
  position: absolute;

  left: 28px;
  bottom: 28px;

  /* Por encima del ::after de la propia .featured-project__media, que al
     ser el ultimo hijo se pintaria sobre el sello. */
  z-index: 2;

  padding: 8px 12px;

  border: 1px solid rgba(255, 255, 255, .35);
  background: rgba(5, 20, 37, .45);
  backdrop-filter: blur(8px);

  color: white;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .18em;
}


/* =========================================================
   PANEL FLOTANTE
   ========================================================= */

.featured-project__content {
  position: absolute;

  right: 0;
  bottom: 0;
  z-index: 2;

  /* Columna flex y no bloque normal: el enlace es inline-flex, y como
     caja en linea arrastraria el interlineado de su line box como hueco
     muerto debajo. Ademas es lo que hace efectivo su align-self. */
  display: flex;
  flex-direction: column;

  width: 470px;
  padding: 48px 46px 50px;

  border-radius: 18px;

  /* Recorta la barra de acento contra las esquinas redondeadas. Una barra
     de 4px con su propio border-radius de 18px no vale: el navegador
     reduce los radios proporcionalmente cuando no caben en el alto, se
     queda en 4px y asoma un pico del panel por debajo en cada esquina. */
  overflow: hidden;

  background: linear-gradient(150deg, #0c2c52 0%, #071b34 100%);

  /* La sombra es lo que hace que se lea como una pieza flotando sobre la
     foto y no como la segunda columna de una tarjeta partida. */
  box-shadow: 0 30px 60px -30px rgba(7, 27, 52, .55);

  color: white;
}


/* Barra de acento: sella el canto superior del panel y lo engancha con
   el verde de marca que abre la seccion en el eyebrow. */

.featured-project__content::before {
  content: "";

  position: absolute;

  top: 0;
  left: 0;
  right: 0;

  height: 4px;

  background: linear-gradient(90deg, #2f9e38 0%, #45b64d 100%);
}


.featured-project__category {
  margin-bottom: 16px;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;

  color: #45b64d;
}


.featured-project__content h3 {
  max-width: 520px;

  margin: 0;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: clamp(34px, 3.2vw, 46px);
  font-weight: 800;
  line-height: .95;
  letter-spacing: -.02em;
  text-transform: uppercase;

  color: white;
}


.featured-project__content p {
  max-width: 490px;

  margin: 24px 0 0;

  font-size: 15px;
  line-height: 1.75;

  /* Subido desde .66: a ese nivel el parrafo quedaba flojo sobre el azul
     y el bloque entero perdia jerarquia. */
  color: rgba(255, 255, 255, .72);
}


/* =========================================================
   ESPECIFICACIONES
   ========================================================= */

.featured-project__specs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;

  margin-top: 34px;

  border-top: 1px solid rgba(255, 255, 255, .16);
  border-bottom: 1px solid rgba(255, 255, 255, .16);
}


.featured-project__spec {
  padding: 17px 14px 17px 0;

  border-right: 1px solid rgba(255, 255, 255, .16);
}


.featured-project__spec:not(:first-child) {
  padding-left: 14px;
}


.featured-project__spec:last-child {
  border-right: 0;
}


.featured-project__spec span {
  display: block;

  margin-bottom: 7px;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .14em;

  color: rgba(255, 255, 255, .55);
}


.featured-project__spec strong {
  display: block;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: .05em;

  color: white;
}


/* =========================================================
   NUMERO DECORATIVO
   ========================================================= */

/* Antes iba arriba a la derecha en macizo a rgba(255,255,255,.045):
   1.02:1 de contraste, o sea invisible, ocupando sitio para nada.
   Contorneado y abajo a la derecha -donde el enlace, alineado a la
   izquierda, deja el hueco libre- se lee como marca de agua sin
   competir con el titular. */

.featured-project__number {
  position: absolute;

  right: 34px;
  bottom: 26px;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 108px;
  font-weight: 800;
  line-height: 1;

  color: transparent;
  -webkit-text-stroke: 1px rgba(255, 255, 255, .20);

  pointer-events: none;
}


/* =========================================================
   LINK
   ========================================================= */

.featured-project__link {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: 18px;

  /* OJO: nada de position:relative aqui. .stretch cuelga su ::after de
     este enlace pero lo ancla al ancestro posicionado mas cercano, que
     debe ser el panel entero. Con position en el propio enlace, el
     ::after se anclaria a el y solo seria clicable su texto. */

  margin-top: 34px;
  padding-bottom: 11px;

  border-bottom: 1px solid rgba(255, 255, 255, .35);

  color: white;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;

  transition: gap .3s ease, border-color .3s ease;
}


/* El <b> paso de contener el caracter ↗ a contener un SVG, por el mismo
   motivo que .service-row__arrow: en movil ese caracter caia en la fuente de
   emoji y salia a color en vez de verde. Sigue siendo <b> para no tocar el
   resto de la regla; lo que lo tine es el color, que el SVG hereda con
   currentColor. display:flex quita el hueco de linea base del elemento en
   linea, que descuadraba el SVG respecto al texto del enlace. */
.featured-project__link b {
  display: flex;

  color: #45b64d;
}


.featured-project__link b svg {
  width: 17px;
  height: 17px;
}


/* =========================================================
   HOVER

   Aislado en (hover: hover) porque en tactil el :hover se queda pegado
   despues del toque y el zoom se quedaria congelado.
   ========================================================= */

@media (hover: hover) {

  .featured-project__showcase:hover .featured-project__media img,
  .featured-project__showcase:focus-within .featured-project__media img {
    transform: scale(1.04);
  }

  /* El panel entero es clickable via .stretch, asi que el enlace tiene
     que responder al pasar por cualquier punto de el, no solo encima
     de su texto. */
  .featured-project__link:hover,
  .featured-project__content:hover .featured-project__link,
  .featured-project__content:focus-within .featured-project__link {
    gap: 26px;

    border-color: #45b64d;
  }

}


/* =========================================================
   TABLET
   ========================================================= */

@media (max-width: 950px) {

  .featured-project { padding: 90px 0; }

  .featured-project__container { width: calc(100% - 64px); }

  .featured-project__header { margin-bottom: 40px; }

  /* Se acaba el carril lateral: la foto pasa a ancho completo y el panel
     baja al flujo, solapando solo por arriba. */
  .featured-project__showcase { padding-bottom: 0; }

  .featured-project__media {
    width: 100%;
    height: 430px;
  }

  .featured-project__content {
    /* relative y NO static: en static el panel dejaria de ser un elemento
       posicionado y .featured-project__media -que si lo es- se pintaria
       encima, tapando justo la parte que solapa. */
    position: relative;

    right: auto;
    bottom: auto;

    width: auto;
    margin: -70px 32px 0;
    padding: 42px 38px 44px;
  }

  .featured-project__number {
    font-size: 92px;
  }

}


/* =========================================================
   MOVIL

   A 640px y no a 600px a proposito: es el ancho en el que entra el
   bloque global de "9. Puntos de ruptura globales". Con el corte en 600
   quedaba una franja de 40px en la que el global ya pisaba y la seccion
   todavia no reaccionaba.
   ========================================================= */

@media (max-width: 640px) {

  .featured-project { padding: 75px 0; }

  .featured-project__container { width: calc(100% - 32px); }

  .featured-project__header { display: block; }

  .featured-project__index { margin-top: 25px; }

  /* Los !important de aqui abajo NO son por gusto. El bloque global
     declara h2 { font-size: 26px !important } y h3 { 22px !important }
     para domar los titulares antiguos, que llevan el tamano en style
     inline. De paso aplasta cualquier clase BEM nueva: sin contra-
     !important, este titular sale a 26px en todos los telefonos y la
     jerarquia de la seccion se viene abajo. Mismo caso que .commitment. */
  .featured-project__title { font-size: 40px !important; }

  .featured-project__content h3 { font-size: 32px !important; }

  .featured-project__media {
    height: 300px;

    border-radius: 14px;
  }

  .featured-project__media-label {
    left: 18px;
    bottom: 18px;
  }

  .featured-project__content {
    margin: -46px 0 0;
    padding: 34px 24px 38px;

    border-radius: 16px;
  }

  .featured-project__content p { font-size: 14px; }

  /* En tres columnas "HIDROSTATICA" no cabe a este ancho. */
  .featured-project__specs {
    grid-template-columns: 1fr;

    margin-top: 28px;
  }

  .featured-project__spec {
    padding: 14px 0;

    border-right: 0;
    border-bottom: 1px solid rgba(255, 255, 255, .16);
  }

  .featured-project__spec:not(:first-child) { padding-left: 0; }

  .featured-project__spec:last-child { border-bottom: 0; }

  .featured-project__number {
    right: 20px;
    bottom: 16px;

    font-size: 74px;
  }

}

/* ---------- 8c. Servicios — lista editorial ---------- */
/* =========================================================
   SERVICIOS — LISTA EDITORIAL
   ========================================================= */

.services-list {
  position: relative;

  padding: 120px 0 140px;

  background: #f4f6f7;

  /* SIN overflow:hidden a proposito, a diferencia de otras secciones: aqui
     adentro .services-list__visual usa position:sticky (ver
     .services-list__body mas abajo), y overflow != visible en CUALQUIER
     ancestro -incluida esta seccion- le corta el recorrido: la imagen deja
     de seguir el scroll y queda clavada arriba en vez de despegarse al
     llegar al final de la lista. No hay nada aqui dentro que necesite
     recortarse. */
}


.services-list__container {
  width: min(
    1240px,
    calc(100% - 96px)
  );

  margin: 0 auto;
}


/* =========================================================
   HEADER
   ========================================================= */

.services-list__header {
  display: flex;

  align-items: flex-end;

  justify-content: space-between;

  gap: 70px;

  margin-bottom: 70px;
}


.services-list__heading {
  max-width: 700px;
}


.services-list__eyebrow {
  display: inline-flex;

  align-items: center;

  gap: 12px;

  font-family:
    "Barlow Semi Condensed",
    sans-serif;

  font-size: 13px;

  font-weight: 800;

  letter-spacing: .18em;

  text-transform: uppercase;

  color: #2f9e38;
}


.services-list__eyebrow::before {
  content: "";

  width: 34px;

  height: 2px;

  background: #2f9e38;
}


.services-list__heading h2 {
  margin: 14px 0 0;

  font-family:
    "Barlow Semi Condensed",
    sans-serif;

  font-size: clamp(
    48px,
    5.5vw,
    76px
  );

  font-weight: 800;

  line-height: .92;

  letter-spacing: -.025em;

  text-transform: uppercase;

  color: #0c2c52;
}


.services-list__heading h2 span {
  display: block;

  color: #778596;
}


.services-list__header > p {
  max-width: 390px;

  margin: 0 0 5px;

  font-size: 15px;

  line-height: 1.7;

  color: #596b80;
}


/* =========================================================
   BODY
   ========================================================= */

.services-list__body {
  display: grid;

  grid-template-columns:
    minmax(0, 1fr)
    minmax(400px, .72fr);

  gap: 85px;

  /* stretch (el valor por defecto) y NO start: position:sticky necesita que
     la CELDA de .services-list__visual sea tan alta como la fila (o sea,
     tan alta como la lista de servicios, la columna mas alta) para tener
     recorrido donde pegarse. Con align-items:start la celda se encogia a
     los 570px de la propia imagen -> sticky no tenia margen para viajar y
     la imagen se soltaba enseguida, dejando el resto de la lista con la
     columna derecha en blanco. */
  align-items: stretch;
}


/* =========================================================
   LISTA
   ========================================================= */

.services-list__items {
  border-top:
    1px solid #ccd5de;

  /* Colchon CHICO a proposito: el ideal seria cubrir top(110px) + alto de
     la imagen (570px, ver .services-list__visual) = 680px para que nunca se
     corte, pero ese hueco vacio se veia peor que el problema que arregla
     (ver commit anterior, se probo con 580 y 680). Con esto de compromiso
     las filas 09 y 10 llegan a verse completas; la 11 puede quedar
     cortandose un poco al final, con un hueco bastante mas chico despues. */
  padding-bottom: 180px;
}


.service-row {
  position: relative;

  /* Un SOLO numero para el sangrado de la fila activa y para el ancho extra
     del panel de ::before. Si los dos no coinciden, el panel se sale de la
     fila; y como .services-list no puede llevar overflow:hidden (rompe el
     sticky, ver arriba), ese sobrante se convierte en scroll horizontal. */
  --fila-sangrado: 20px;

  display: grid;

  grid-template-columns:
    55px
    1fr
    35px;

  gap: 20px;

  align-items: start;

  padding: 29px 0 30px;

  border-bottom:
    1px solid #ccd5de;

  text-decoration: none;

  color: #0c2c52;

  transition:
    padding .35s ease,
    background .35s ease;
}


.service-row::before {
  content: "";

  position: absolute;

  left: calc(var(--fila-sangrado) * -1);
  right: calc(var(--fila-sangrado) * -1);
  top: 0;
  bottom: 0;

  background: white;

  opacity: 0;

  transform: scaleY(.85);

  z-index: -1;

  transition:
    opacity .35s ease,
    transform .35s ease;
}


/* Solo .is-active en las reglas base; la mitad :hover vive en el bloque
   @media (hover: hover) de mas abajo. Motivo: en tactil, arrastrar empezando
   sobre una fila deja el :hover pegado en varios navegadores, asi que esa
   fila se quedaba verde mientras el scroll activaba otra — dos filas verdes
   a la vez. */
.service-row.is-active::before {
  opacity: 1;

  transform: scaleY(1);
}


.service-row.is-active {
  padding-left: var(--fila-sangrado);

  padding-right: var(--fila-sangrado);
}


/* =========================================================
   NÚMERO
   ========================================================= */

.service-row__number {
  padding-top: 5px;

  font-family:
    "Barlow Semi Condensed",
    sans-serif;

  font-size: 12px;

  font-weight: 800;

  letter-spacing: .08em;

  color: #8c99a7;

  transition:
    color .3s ease;
}


.service-row.is-active .service-row__number {
  color: #2f9e38;
}


/* =========================================================
   CONTENIDO
   ========================================================= */

.service-row__main h3 {
  margin: 0;

  font-family:
    "Barlow Semi Condensed",
    sans-serif;

  font-size: clamp(
    25px,
    2.5vw,
    34px
  );

  font-weight: 800;

  line-height: 1;

  letter-spacing: -.015em;

  text-transform: uppercase;

  color: #0c2c52;

  transition:
    color .3s ease;
}


.service-row.is-active .service-row__main h3 {
  color: #2f9e38;
}


.service-row__main p {
  max-width: 570px;

  margin: 12px 0 0;

  font-size: 13px;

  line-height: 1.65;

  color: #6c7a89;

  opacity: 0;

  max-height: 0;

  overflow: hidden;

  transform: translateY(-5px);

  transition:
    opacity .35s ease,
    max-height .4s ease,
    transform .35s ease;
}


.service-row.is-active .service-row__main p {
  opacity: 1;

  max-height: 100px;

  transform: translateY(0);
}


/* =========================================================
   FLECHA
   ========================================================= */

/* La flecha es un SVG en linea y NO el caracter ↗ (U+2197). No es purismo:
   Barlow no trae ese caracter -el subconjunto latino de Google Fonts incluye
   U+2191 y U+2193, pero no U+2197-, asi que el navegador caia a una fuente del
   sistema. Y como U+2197 esta en la tabla de emoji de Unicode, en iOS y en
   varios Android esa fuente era la de emoji: la flecha salia a color, se
   saltaba el `color` de aqui abajo y no se volvia blanca al activarse la fila.
   En Windows de escritorio caia en Segoe UI Symbol, monocromo, y por eso el
   fallo solo se veia en el telefono.
   Con stroke="currentColor" en el SVG, el color y las transiciones de abajo
   siguen funcionando igual que con el glifo. */
.service-row__arrow {
  display: grid;

  place-items: center;

  width: 32px;
  height: 32px;

  border:
    1px solid #ccd5de;

  border-radius: 50%;

  color: #7c8997;

  transition:
    color .3s ease,
    background .3s ease,
    border-color .3s ease,
    transform .3s ease;
}


/* El tamano va aqui y no en atributos del <svg>, igual que en
   .commitment-card__icon svg: asi los 12 SVG del HTML son identicos y el
   tamano se cambia en un solo sitio, incluido el punto de ruptura de movil. */
.service-row__arrow svg {
  width: 18px;
  height: 18px;
}


.service-row.is-active .service-row__arrow {
  color: white;

  background: #2f9e38;

  border-color: #2f9e38;

  transform: rotate(45deg);
}


/* =========================================================
   HOVER — la otra mitad de las seis reglas .is-active de arriba
   =========================================================
   Van aparte y detras de una hover-query en vez de en el mismo par de
   selectores. En tactil, arrastrar empezando sobre una fila deja el :hover
   pegado (Android sobre todo), asi que esa fila se quedaba verde mientras el
   scroll activaba otra: dos filas verdes a la vez.
   Las declaraciones son identicas a las de .is-active y :hover pesa lo mismo
   (0,1,0), asi que en raton no cambia nada; por eso van DESPUES, para
   conservar el mismo desempate que habia cuando eran un solo selector.
   Nada de :focus aqui: el foco de teclado lo marca el JS con .is-active, que
   queda fuera de esta query. */

@media (hover: hover) {

  .service-row:hover::before {
    opacity: 1;
    transform: scaleY(1);
  }

  .service-row:hover {
    padding-left: var(--fila-sangrado);
    padding-right: var(--fila-sangrado);
  }

  .service-row:hover .service-row__number { color: #2f9e38; }

  .service-row:hover .service-row__main h3 { color: #2f9e38; }

  .service-row:hover .service-row__main p {
    opacity: 1;
    max-height: 100px;
    transform: translateY(0);
  }

  .service-row:hover .service-row__arrow {
    color: white;
    background: #2f9e38;
    border-color: #2f9e38;
    transform: rotate(45deg);
  }

}


/* =========================================================
   IMAGEN
   ========================================================= */

.services-list__visual {
  position: sticky;

  top: 110px;

  /* El aire de arriba va aqui como padding y no como margin-top en
     .services-list__image. Alla, combinado con su height:100%, dejaba la foto
     40px POR FUERA de esta caja: en escritorio acortaba el recorrido del
     sticky, y a partir de 950px (donde la foto va arriba de la lista) se comia
     40 de los 50px de hueco con la lista.
     Con box-sizing:border-box el padding sale de estos 610, asi que la foto
     sigue midiendo 570 y sigue empezando a 150px del borde de la ventana. */
  padding-top: 40px;

  height: 610px;
}


.services-list__image {
  position: relative;

  width: 100%;
  height: 100%;

  overflow: hidden;

  background: #0c2c52;
}


.services-list__image img {
  display: block;

  width: 100%;
  height: 100%;

  object-fit: cover;

  transform: scale(1.02);

  transition:
    opacity .3s ease,
    transform 1s
    cubic-bezier(.22, 1, .36, 1);
}


.services-list__image.is-changing img {
  opacity: .35;

  transform: scale(1.05);
}


/* =========================================================
   OVERLAY
   ========================================================= */

.services-list__image-overlay {
  position: absolute;

  inset: 0;

  background:
    linear-gradient(
      180deg,
      rgba(5,20,37,0) 50%,
      rgba(5,20,37,.72) 100%
    );

  pointer-events: none;
}


/* =========================================================
   CAPTION
   ========================================================= */

.services-list__image-caption {
  position: absolute;

  left: 30px;
  right: 30px;
  bottom: 28px;

  display: flex;

  flex-direction: column;

  gap: 7px;

  color: white;
}


.services-list__image-caption span {
  font-family:
    "Barlow Semi Condensed",
    sans-serif;

  font-size: 10px;

  font-weight: 800;

  letter-spacing: .2em;

  color: #45b64d;
}


.services-list__image-caption strong {
  font-family:
    "Barlow Semi Condensed",
    sans-serif;

  font-size: 17px;

  font-weight: 700;

  text-transform: uppercase;
}


/* =========================================================
   TABLET
   ========================================================= */

@media (max-width: 950px) {

  .services-list {
    padding: 90px 0;
  }

  .services-list__container {
    width: calc(100% - 64px);
  }

  .services-list__header {
    display: block;

    margin-bottom: 50px;
  }

  .services-list__header > p {
    margin-top: 25px;
  }

  /* flex y NO grid. En grid el bloque contenedor de un item es su CELDA, y la
     celda de la foto mide lo que la foto: cero recorrido, el sticky no tendria
     donde pegarse. En flex el bloque contenedor es el contenedor entero, o sea
     todo lo que mide la lista. */
  .services-list__body {
    display: flex;
    flex-direction: column;

    gap: 30px;
  }

  .services-list__items {
    /* Colchon para que la foto aguante pegada hasta el final de la lista. El
       sticky se despega cuando al contenedor le quedan por debajo top + alto
       de la foto (~370px); esto queda a proposito MAS CORTO, mismo criterio
       que en escritorio: el hueco vacio de un colchon completo se ve peor que
       las dos ultimas filas sin foto. */
    padding-bottom: 140px;
  }

  /* La foto arriba y pegada, con la lista pasando por debajo.
     SIN clase que lo active y SIN candados de alto ni de prefers-reduced-motion,
     a diferencia de la primera version. Motivo: 'position: sticky' YA es
     progressive enhancement — un navegador que no lo entiende ignora la
     declaracion y el elemento queda estatico, que es justo el fallback que se
     queria. Protegerlo con condiciones solo conseguia que desapareciera en
     silencio en cuanto fallaba una: telefono en horizontal (mas de 600px de
     ancho), navegador dentro de una app (menos de 560px de alto), "reducir
     animaciones" encendido, o el JS bloqueado. */
  .services-list__visual {
    order: -1;

    /* -webkit-sticky para iOS 12 y anteriores, que no entienden el sin
       prefijo. La segunda linea pisa a la primera donde las dos valen. */
    position: -webkit-sticky;
    position: sticky;

    /* En px y NO en var(): sin soporte de variables CSS la declaracion seria
       invalida, y un sticky con top:auto no se pega nunca. */
    top: 125px;                 /* header de 115 + aire */

    /* IMPRESCINDIBLE, no es un retoque. En flex, 'order' no solo cambia el
       orden de MAQUETADO: tambien el de PINTADO (los items se pintan en orden
       de documento *modificado por order*). Con order:-1 la foto se pintaba la
       primera, o sea DEBAJO, y como tanto ella como las .service-row son
       elementos posicionados con z-index:auto, las filas le pasaban por ENCIMA
       con su fondo transparente: se veian los titulos atravesados sobre la
       foto. Aqui maquetado y pintado piden cosas opuestas —la foto va primera
       arriba pero tiene que pintarse la ultima— y z-index es lo que desempata.
       Queda muy por debajo del z-index:50 del header, que la sigue tapando. */
    z-index: 2;

    flex: none;

    /* Aqui la foto ya va arriba del todo, no hace falta el aire que la separa
       del header en escritorio. */
    padding-top: 0;

    /* Las dos lineas hacen falta: min() es de 2020 y -webkit-sticky apunta a
       2018, asi que un navegador que entienda el prefijo pero no min() se
       quedaria sin alto y la foto (height:100%) colapsaria a cero.
       El min() sustituye al candado min-height:560px que habia antes: en una
       pantalla baja la foto se encoge sola en vez de perderse la funcion. */
    height: 280px;
    height: min(280px, 32vh);

    /* Las filas pasan POR DEBAJO de la foto (es un elemento posicionado, se
       pinta encima). Es intencionado, y la sombra es lo que hace que se lea
       como profundidad en vez de como un fallo de pintado. */
    box-shadow: 0 18px 28px -18px rgba(7, 22, 43, .55);
  }

  /* Los tres selectores y no solo el primero, aunque las declaraciones sean
     identicas. La regla de escritorio `.service-row.is-active
     .service-row__main p { max-height: 100px }` pesa (0,3,1) y le ganaba a un
     (0,1,1) — las media queries no suman especificidad — asi que el parrafo
     volvia a recortarse a 100px en cuanto la fila se activaba.
     Y como no se puede interpolar desde 'none', el recorte era SECO: en el
     servicio 09 (~9 lineas) todo lo de abajo saltaba 70px arriba de un
     fotograma al otro, y volvia al desactivarse. Peor, ese salto metia otra
     fila en la banda del observer, que activaba esa, que descolapsaba la 09...
     La lista oscilaba sola mientras se hacia scroll. */
  .service-row .service-row__main p,
  .service-row:hover .service-row__main p,
  .service-row.is-active .service-row__main p {
    opacity: 1;

    max-height: none;

    transform: none;
  }

}


/* =========================================================
   MOBILE
   ========================================================= */

@media (max-width: 600px) {

  .services-list {
    padding: 75px 0;
  }

  .services-list__container {
    width: calc(100% - 32px);
  }

  .services-list__heading h2 {
    font-size: 44px;
  }

  /* Sin alto propio para .services-list__visual a proposito: el
     min(280px, 32vh) del bloque de 950px ya se encoge solo en las pantallas
     pequenas. Un valor fijo aqui lo pisaria y volveria a romperlo en las
     bajas. */

  .service-row {
    grid-template-columns:
      35px
      1fr
      30px;

    gap: 12px;

    padding: 23px 0;
  }

  /* 12 y no los 20 de escritorio: a este ancho el contenedor solo deja 16px
     de margen a cada lado (width: calc(100% - 32px), arriba), y con 20 el
     panel blanco de ::before se salia 4px por la derecha. Como .services-list
     no puede llevar overflow:hidden, esos 4px hacian aparecer y desaparecer
     la barra de scroll horizontal segun que fila estuviera activa: la pagina
     temblaba de lado al hacer scroll.
     Basta con mover la variable — el sangrado del ::before y el padding de la
     fila activa salen los dos de ella. */
  .service-row { --fila-sangrado: 12px; }

  .service-row__main h3 {
    font-size: 24px;
  }

  .service-row__main p {
    font-size: 12px;

    line-height: 1.6;
  }

  .service-row__arrow {
    width: 28px;
    height: 28px;
  }

  .service-row__arrow svg {
    width: 16px;
    height: 16px;
  }

}


/* =========================================================
   TELEFONO Y TABLET — remates de la foto pegada
   =========================================================
   El grueso esta arriba, en el bloque de 950px: la foto se pega sin depender
   de ninguna clase ni de ningun candado. Aqui van solo dos remates. */

/* El top sigue al HEADER, que cambia de alto a los 640px — no a los 600 ni a
   los 950 de esta seccion. La fuente de verdad es .nav-spacer (115px arriba,
   77px aqui). Sin esto, la foto se metia 38px por debajo del header. */
@media (max-width: 640px) {
  .services-list__visual { top: 87px; }   /* header de 77 + aire */
}

/* Que la foto se quede QUIETA no es "motion" en el sentido vestibular: nadie
   condiciona un header pegajoso a este ajuste, y en la primera version esto
   dejaba sin la funcion entera a cualquiera con "reducir animaciones"
   encendido. Lo que si es animacion aqui es el fundido de la foto al cambiar
   de servicio y las transiciones de las filas, que es lo que se apaga.
   Sin !important: misma especificidad que las reglas base, gana por ir
   despues en el archivo. */
@media (prefers-reduced-motion: reduce) {
  .services-list__image img,
  .service-row,
  .service-row::before,
  .service-row__number,
  .service-row__main h3,
  .service-row__main p,
  .service-row__arrow { transition: none; }
}

/* ---------- 8d. Compromiso ---------- */
/* =========================================================
   COMPROMISO
========================================================= */

.commitment {
  background: #f5f8fb;
  padding: 110px 0;

  /* SIN overflow:hidden. El sello lleva un parallax que lo sube sobre el
     padding de arriba (data-parallax en index.html, seccion 3 de site.js), y
     recortar aqui obligaba a dejar el recorrido en un valor tan bajo que el
     efecto no se notaba. Nada de aqui dentro necesita recortarse: el
     contenedor va centrado con ancho acotado y no hay nada posicionado que se
     escape. Si el sello asoma unos pixeles por encima del borde, cae en el
     espacio en blanco de la seccion anterior. */
}

.commitment__container {
  width: min(1240px, calc(100% - 96px));
  margin: 0 auto;

  display: grid;
  grid-template-columns: minmax(360px, 0.85fr) minmax(0, 1.15fr);
  gap: 80px;
  align-items: center;
}


/* =========================================================
   SELLO
========================================================= */

.commitment__visual {
  display: flex;
  align-items: center;
  justify-content: center;

  /* --avance es el progreso del scroll, de 0 a 1, y lo escribe site.js en
     cada fotograma sobre este mismo elemento (el que lleva data-parallax):
     0 cuando el borde superior del sello asoma por abajo de la ventana, 1
     cuando llega al 30% del alto. Es EXACTAMENTE la misma cuenta que mueve
     el parallax, asi que el sello se abre mientras baja en vez de hacer dos
     cosas descoordinadas.

     El 1 de aqui es el valor de reserva, para cuando nadie lo escribe: si
     site.js no carga o falla, el sello se ve entero. Mejor sin efecto que
     invisible. */
  --avance: 1;
}

/* Solo arranca cerrado si el JS esta vivo. Mismo criterio -y mismo motivo-
   que el estado oculto de .reveal, que tambien va prefijado con .js
   (styles.css:35-40): sin JS el contenido se ve, no desaparece. */
.js .commitment__visual {
  --avance: 0;
}

/* Aviso al navegador de que aqui se va a mover el transform en cada
   fotograma, para que lo pinte en su propia capa y solo la desplace en vez de
   repintar. Va con el atributo y no con la clase: si algun dia se le quita el
   data-parallax al sello, esta pista deja de aplicarse sola. */
[data-parallax] { will-change: transform; }

/* El border-radius:50% recorta el JPEG cuadrado a circulo. Funciona porque el
   anillo exterior del sello (radio ~570 de los 627 que mide medio lado) cae
   holgadamente dentro del circulo inscrito: solo se van las esquinas de fondo
   crema. Si algun dia se cambia la imagen por otra con contenido cerca de las
   esquinas, ese contenido se perderia. */
.commitment__seal {
  width: min(100%, 470px);

  background: #fff;
  border-radius: 50%;

  box-shadow:
    0 24px 60px rgba(12, 44, 82, 0.10),
    0 8px 20px rgba(12, 44, 82, 0.06);

  /* El disco y su sombra se funden con el scroll; el recorte de la imagen va
     aparte, en la regla de abajo. SIN transition a proposito: el valor lo
     mueve el scroll fotograma a fotograma, y una transicion encima lo dejaria
     persiguiendo al dedo con retraso.
     Tampoco se toca transform: aqui ya lo usa el hover. */
  opacity: var(--avance);

  transition:
    transform 0.45s ease,
    box-shadow 0.45s ease;
}

.commitment__seal:hover {
  transform: translateY(-6px);
  box-shadow:
    0 32px 70px rgba(12, 44, 82, 0.14),
    0 12px 25px rgba(12, 44, 82, 0.08);
}

/* EL IRIS. La imagen se abre desde el centro a medida que se hace scroll,
   como un obturador.

   El recorte va AQUI y no en .commitment__seal porque clip-path recorta
   tambien la box-shadow, y la sombra vive en el sello: recortando alli, la
   sombra desapareceria. En la imagen no hay sombra que perder.

   Y a --avance 1 el recorte NO quita ni un pixel: el JPEG es 800x800 y se
   pinta con width:100%; height:auto, o sea una caja cuadrada, y en una caja
   cuadrada el radio 50% de circle() resuelve a medio lado — el circulo
   inscrito, que es el mismo que ya dibuja el border-radius de abajo. El
   estado final es identico al que habia antes de este efecto.

   Si --avance fuese invalido, el calc() falla en tiempo de valor computado y
   clip-path cae a none: imagen entera. Fallo seguro. */
.commitment__seal img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 50%;

  -webkit-clip-path: circle(calc(var(--avance) * 50%));
  clip-path: circle(calc(var(--avance) * 50%));
}


/* SIN ESTO EL SELLO SE QUEDA INVISIBLE PARA SIEMPRE. El motor de parallax de
   site.js entero esta detras de un if (!motionReducido), asi que con
   movimiento reducido nadie escribe --avance y se quedaria en el 0 de la
   regla .js de arriba. El !important es para ganarle a esa regla, que tiene
   mas especificidad. Mismo patron que el bloque de reduced-motion de las
   apariciones al hacer scroll (styles.css:42-44). */
@media (prefers-reduced-motion: reduce) {
  .commitment__visual { --avance: 1 !important; }
}


/* =========================================================
   CONTENIDO
========================================================= */

.commitment__content {
  max-width: 700px;
}

.commitment__eyebrow {
  display: block;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;

  color: #2f9e38;

  margin-bottom: 12px;
}

.commitment__title {
  margin: 0;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: clamp(38px, 4vw, 54px);
  line-height: 0.98;
  font-weight: 800;
  text-transform: uppercase;

  color: #0c2c52;
}

.commitment__title span {
  display: block;
  color: #2f9e38;
}

.commitment__intro {
  max-width: 620px;

  margin: 22px 0 0;

  font-size: 16px;
  line-height: 1.7;

  color: #4a5a6e;
}


/* =========================================================
   CARDS
========================================================= */

.commitment__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;

  margin-top: 34px;
}

.commitment-card {
  position: relative;

  padding: 24px 24px 26px;

  background: #fff;
  border: 1px solid #e6ecf3;
  border-radius: 16px;

  transition:
    transform 0.3s ease,
    border-color 0.3s ease,
    box-shadow 0.3s ease;
}

.commitment-card:hover {
  transform: translateY(-4px);

  border-color: rgba(47, 158, 56, 0.35);

  box-shadow:
    0 15px 35px rgba(12, 44, 82, 0.07);
}

.commitment-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.commitment-card__number {
  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 0.06em;

  color: #2f9e38;
}

.commitment-card__icon {
  width: 42px;
  height: 42px;

  display: flex;
  align-items: center;
  justify-content: center;

  border-radius: 11px;

  background: #eaf6e8;
  color: #2f9e38;
}

.commitment-card__icon svg {
  width: 21px;
  height: 21px;
}

.commitment-card h3 {
  margin: 18px 0 0;

  font-family: "Barlow Semi Condensed", sans-serif;
  font-size: 20px;
  line-height: 1.05;
  font-weight: 700;
  text-transform: uppercase;

  color: #0c2c52;
}

.commitment-card p {
  margin: 9px 0 0;

  font-size: 14px;
  line-height: 1.55;

  color: #4a5a6e;
}


/* =========================================================
   TABLET
========================================================= */

@media (max-width: 1000px) {

  .commitment {
    padding: 90px 0;
  }

  .commitment__container {
    grid-template-columns: 340px minmax(0, 1fr);
    gap: 50px;

    width: min(900px, calc(100% - 60px));
  }

  .commitment__title {
    font-size: 42px;
  }

}


/* =========================================================
   MOBILE
========================================================= */

@media (max-width: 760px) {

  .commitment {
    padding: 75px 0;
  }

  .commitment__container {
    width: min(100% - 40px, 560px);

    grid-template-columns: 1fr;
    gap: 55px;
  }

  .commitment__visual {
    order: 1;
  }

  .commitment__content {
    order: 2;
  }

  .commitment__seal {
    width: min(100%, 390px);
  }

  /* Los !important de aqui abajo NO son por gusto: la seccion 9 cierra el
     archivo con `h2 { font-size: 26px !important }` y `h3 { 22px !important }`
     a partir de 640px, pensados para los titulares que todavia llevan el
     tamano en un style= inline (una declaracion inline solo se puede pisar
     con !important). Como esos selectores son de ELEMENTO, tambien pisan a
     .commitment__title y a .commitment-card h3, que ya no son inline — y sin
     esto los tamanos de abajo no se aplicarian en ningun telefono: el titular
     saldria a 26px en vez de 40, y los de tarjeta a 22 en vez de 20. */
  .commitment__title {
    font-size: 40px !important;
  }

  .commitment-card h3 {
    font-size: 20px !important;
  }

  .commitment__grid {
    grid-template-columns: 1fr;
  }

}


/* =========================================================
   MOBILE PEQUEÑO
========================================================= */

@media (max-width: 450px) {

  .commitment__container {
    width: calc(100% - 30px);
  }

  .commitment {
    padding: 60px 0;
  }

  /* !important por lo mismo que arriba */
  .commitment__title {
    font-size: 34px !important;
  }

  .commitment__intro {
    font-size: 15px;
  }

  .commitment-card {
    padding: 22px;
  }

}

/* ---------- 8e. Onda — empalme entre bandas ---------- */
/* =========================================================
   ONDA — EMPALME ENTRE BANDAS

   QUE ES
   Una pieza que corta la union entre dos bandas de color, en curva o en
   angulo. Un <div> vacio con dos pseudo-elementos recortados por
   clip-path: dos de las instancias usan ellipse() y la tercera
   polygon(). Toda la geometria vive aqui; en el HTML solo queda una
   linea por instancia y ni un solo numero. Eso importa en este repo: no
   hay build ni plantillas, asi que cualquier coordenada escrita en el
   markup se duplica a mano y se desincroniza sola.

   LA REGLA DEL SISTEMA, sin excepciones
   La onda se coloca ENTRE las dos bandas y se rellena con el color de
   la banda de ABAJO. Es la banda de abajo subiendo en arco sobre la de
   arriba, nunca una forma con color propio. Gracias a eso la banda de
   arriba no hay que igualarla jamas: puede ser un color plano o el
   linear-gradient(135deg,#0c2c52,#071b34) de CIFRAS, que ningun relleno
   plano podria imitar. La onda no lo replica, lo muerde.

   POR QUE clip-path Y NO UN SVG EN LINEA
   Un svg en linea obliga a llevar el path completo en el HTML y a
   repetirlo en cada instancia. Con clip-path la forma es una linea de
   CSS reutilizable, las coordenadas van en porcentaje -tanto los radios
   de ellipse() como los vertices de polygon()- asi que la silueta es la
   misma de 360 a 2560px, y no hay ningun nodo con geometria dentro del
   markup.
   Descartadas las otras tres vias:
   - border-radius al 50%: la especificacion escala a la baja todos los
     radios cuando la suma de los dos de un lado supera el largo de ese
     lado, asi que la curva no puede ser mas ancha que la caja. Para un
     arco tan tendido habria que poner el elemento a width:200% con
     left:-50%, y eso saca barra de scroll horizontal.
   - mask-image con radial-gradient: la parada del degradado se
     rasteriza sin suavizado y en una curva tan tendida el borde sale
     escalonado; ademas obliga a duplicarlo todo con -webkit-mask-.
   - clip-path: path(): solo admite coordenadas absolutas en px, no
     acepta porcentajes. Habria que reescribirlo en cada punto de
     ruptura. Es tambien el motivo de que la instancia quebrada use
     polygon() y no path(), teniendo solo tramos rectos.

   POR QUE NO VA ENTRE SERVICIOS Y PROYECTO DESTACADO
   Que es donde se probo primero, con un svg de generador. Alli arriba
   hay #f4f6f7 y abajo #ffffff: ratio de contraste 1.08:1, poco mas de
   tres puntos de L*. Con el color CORRECTO la onda ahi es invisible en
   un portatil con brillo medio o en un movil a plena luz. Las dos
   fronteras que si funcionan son CIFRAS -> SERVICIOS (15.9:1) y
   CLIENTES -> PIE (17.3:1), y son las dos que cubre este bloque.

   DONDE NO REUTILIZARLA
   - .featured-project lleva overflow:hidden (styles.css:198). Como
     hermana en el flujo la onda funciona igual, pero NO se puede colgar
     de ella como hija absoluta: la recortaria al ras.
   - .commitment no lleva overflow:hidden, pero su sello va con
     data-parallax="110" y cruza esa frontera hacia arriba hasta 110px
     mientras se hace scroll: la onda se solaparia con una imagen en
     movimiento.

   NO ANIMA NADA
   Ni transition, ni keyframes, ni data-parallax, ni .reveal. Por eso no
   necesita bloque de prefers-reduced-motion.
   ========================================================= */

.onda {
  /* LOS DOS UNICOS NUMEROS DE LA PIEZA.

     Variables LOCALES a este bloque, con el precedente exacto de
     --fila-sangrado en .service-row (styles.css:971 y 1516) y por el
     mismo motivo: varias declaraciones que tienen que moverse juntas en
     cada punto de ruptura. :root sigue vacio y debe seguirlo.

     --onda-subida es lo UNICO que se ve: cuanto asoma la cresta por
     encima de la linea de union. Su techo lo pone el padding inferior
     del bloque de arriba, que son 76px en la banda de CIFRAS
     (index.html:233) y 70px en el .wrap de CLIENTES (index.html:977).
     Con 48px de subida y un filo de 3px la cresta sube 51px: quedan
     25px de aire bajo las etiquetas de los contadores y 19px bajo la
     rejilla de logos. Esos dos paddings NO cambian en ningun ancho: el
     bloque 9 solo les pisa padding-left y padding-right, asi que la
     holgura es la misma de 320 a 2560px. */
  --onda-subida: 48px;

  --onda-filo: 3px;

  position: relative;

  /* EL ALTO SE DERIVA DE LA SUBIDA Y NO SE DECLARA APARTE. La relacion
     subida/alto = 0.4 es la que fija DONDE apoya la curva sobre la linea
     de union: con 0.4 apoya al 99.6% del ancho, o sea justo en la
     esquina. Con 0.5 apoyaria antes y quedaria un tramo recto visible a
     la derecha; con 0.3 se saldria por el borde y dejaria una cuna clara
     contra la banda de arriba. Atando los dos numeros con calc, esa
     relacion no se puede romper por descuido: cada media query cambia UN
     valor y la silueta se conserva entera.

     OJO, el alto NO es constante. No depende del ancho de forma continua
     -no hay relacion de aspecto en juego, esto es un <div> vacio y no un
     elemento reemplazado-, pero si cambia en escalones, porque los
     @media de mas abajo reescriben --onda-subida:

       > 950px    subida 48px -> caja 120px  (cresta 48, enterrado 72)
       641-950    subida 42px -> caja 105px  (cresta 42, enterrado 63)
       451-640    subida 34px -> caja  85px  (cresta 34, enterrado 51)
       <= 450     subida 28px -> caja  70px  (cresta 28, enterrado 42)

     Esos escalones son OBLIGATORIOS, no cosmeticos, y quien los borre
     rompe la pieza: .services-list baja su padding a 90px a 950px
     (styles.css:1362) y a 75px a 600px (styles.css:1481), y con los
     72px enterrados de escritorio quedarian 3px de holgura antes del
     eyebrow. Ademas, como los radios de la elipse van en porcentaje, la
     pendiente en el punto de apoyo vale 1.626 * alto / ancho: mantener
     el alto fijo empinaria la curva al estrecharse la ventana. */
  height: calc(var(--onda-subida) * 2.5);

  /* ALTURA NETA CERO. -1 + 2.5 - 1.5 = 0.
     El margen de arriba mete la pieza dentro del padding inferior del
     bloque de arriba; el de abajo sube el bloque siguiente para que
     empiece exactamente donde empezaba antes. Anadir la onda no alarga
     la pagina ni un pixel, que es justo lo contrario de lo que hacia el
     svg del generador que habia aqui (sumaba ~317px a un hueco que ya
     tenia 260px).
     Los dos margenes colapsan con hermanos sin margen propio, asi que el
     resultado es el valor negativo tal cual. La pieza tiene altura
     declarada, asi que sus dos margenes NO colapsan a traves de ella.

     En la instancia del pie el margen inferior colapsa ademas a traves
     de <main>, que no tiene ninguna regla en la hoja. No pasa nada: al
     colapsar el margen del ultimo hijo con el del padre, la altura auto
     del padre se mide hasta el borde INFERIOR DE BORDE del hijo, o sea
     <main> crece los mismos 72px que el margen resta. El <footer> queda
     exactamente donde estaba sin la onda. */
  margin-top: calc(var(--onda-subida) * -1);

  margin-bottom: calc(var(--onda-subida) * -1.5);

  /* Decoracion que cubre area: no debe interceptar ni un clic ni un
     hover de lo que quede debajo. Mismo criterio que
     .featured-project__media::after (styles.css:370). */
  pointer-events: none;
}


/* El @supports evita que un navegador sin recorte por forma pinte dos
   rectangulos de colores atravesando la banda oscura. Sin soporte no se
   dibuja nada y queda el corte recto de siempre, que es el estado que
   tenia el sitio antes de esta pieza: degradar a lo que ya habia no es
   una regresion. Y como la regla .onda de arriba queda FUERA del
   @supports, la suma de margenes sigue dando cero: en ese caso es un div
   vacio invisible que no mueve nada. */
@supports (clip-path: ellipse(82% 100% at 34% 100%)) or (-webkit-clip-path: ellipse(82% 100% at 34% 100%)) {

  .onda::before,
  .onda::after {
    content: "";

    position: absolute;

    /* left:0 + right:0 y JAMAS un ancho mayor. Ninguna de las dos
       secciones vecinas puede recortar: .services-list no admite
       overflow:hidden porque dentro usa position:sticky, y el bloque de
       CLIENTES es un .wrap pelado. Lo que se saliera por la derecha
       sacaria barra de scroll horizontal en toda la pagina; ya paso con
       4px del panel de .service-row::before y la pagina temblaba de lado
       al hacer scroll (styles.css:1508-1516).
       Aqui el desbordamiento es imposible por construccion: la caja mide
       exactamente lo que el bloque contenedor y clip-path solo QUITA
       superficie, nunca la anade. La curva "mas ancha que la pantalla"
       se consigue con el radio de la elipse, no agrandando la caja. */
    left: 0;

    right: 0;

    height: 100%;

    /* LA CURVA, leida de izquierda a derecha:
       82%  radio horizontal, o sea 1.64 anchos de ventana de diametro.
            La elipse se sale por los dos lados y de ella solo se ve el
            casquete central: por eso el arco sale tendido y no parece un
            rectangulo con las esquinas redondeadas.
       100% radio vertical, con el centro en el borde inferior de la
            caja: la cresta toca justo el borde superior.
       34%  centro horizontal. Es lo que lo convierte en oleaje y no en
            cupula: sube deprisa por la izquierda, cresta al 34% y una
            barrida larga que baja a apoyarse en el 99.6% del ancho.
            Poniendo 50% saldria un arco simetrico.
       El prefijo -webkit- va delante por iOS 12 y los Safari anteriores
       al 13.1, que solo entienden la version prefijada. */
    -webkit-clip-path: ellipse(82% 100% at 34% 100%);

    clip-path: ellipse(82% 100% at 34% 100%);
  }


  /* EL FILO. Es la MISMA forma subida --onda-filo pixeles y pintada con
     el degradado de acento de la casa, el mismo de
     .featured-project__content::before (styles.css:458) y primo del
     guion de 34x2px de los eyebrow. No es un adorno inventado: hermana
     la onda con piezas que el ojo ya ha visto en la misma pagina.

     Va en ::before y no en ::after a proposito: entre dos
     pseudo-elementos posicionados con z-index automatico manda el orden
     del documento, asi que ::before pinta debajo y de el solo asoma la
     franja que queda por encima del relleno. Nada de calcular una curva
     paralela ni un segundo path.

     Como las formas son tendidisimas -el arco de las elipses no pasa de
     7.7 grados a 1440px de ancho, y los dos tramos de la quebrada van a
     4.5 y 0.58 grados-, un desplazamiento vertical de 3px da un trazo de
     ~2.99px medido en perpendicular: constante a simple vista de punta a
     punta, en las tres instancias. Si se sube --onda-subida hay que
     rehacer esa cuenta, porque la pendiente crece con el alto. */
  .onda::before {
    top: calc(var(--onda-filo) * -1);

    background: linear-gradient(90deg, #2f9e38 0%, #45b64d 100%);
  }


  /* EL RELLENO. Sin color aqui A PROPOSITO: obliga a declarar el
     modificador de rol en cada instancia, que es lo que documenta a que
     banda pertenece la pieza. Si alguien lo olvida, el fallo es
     escandaloso -se ve la forma entera en verde macizo- en vez de
     silencioso, que es lo que pasaria con un color por defecto
     equivocado. */
  .onda::after {
    top: 0;
  }


  /* =========================================================
     INSTANCIAS

     Una por frontera, nombradas por el ROL que cumplen y no por su
     color, para que el dia que cambie un fondo se sepa cual hay que
     tocar. El relleno de cada una y el background de su seccion son el
     MISMO valor repetido en dos declaraciones que deben cambiar juntas.
     Ojo al elegir frontera: los tres fondos claros del sitio (#ffffff,
     #f4f6f7, #f5f8fb) estan a menos de 3.5 puntos de L* entre si, asi
     que entre dos de ellos el RELLENO no se ve y lo unico que queda es
     el filo verde. Eso puede quererse -es el caso de --destacado- pero
     hay que saberlo de antemano: no es lo mismo que las instancias que
     cortan una frontera oscuro/claro.
     ========================================================= */

  /* CIFRAS -> SERVICIOS. Relleno #f4f6f7, el mismo background de
     .services-list (styles.css:799). Contraste contra el #071b34 del
     borde inferior de la banda oscura: 15.9:1.
     Sin z-index: .services-list es position:relative, asi que pinta
     despues y tapa por si sola los 72px de arco que quedan enterrados
     dentro de ella. Da igual: son del mismo gris. */
  .onda--servicios::after {
    background: #f4f6f7;
  }


  /* LA VOLTEADA. El centro de la elipse pasa del 34% al 66%, o sea la
     imagen especular: apoya en el 0.4% del ancho y crece hacia la
     derecha, al reves que .onda--servicios. El criterio es que dos
     separadores SEGUIDOS en el scroll no repitan silueta. */
  .onda--pie::before,
  .onda--pie::after {
    -webkit-clip-path: ellipse(82% 100% at 66% 100%);

    clip-path: ellipse(82% 100% at 66% 100%);
  }


  /* CLIENTES -> PIE. Relleno #071b34, el mismo background del <footer>.
     Contraste contra el blanco del body: 17.3:1, el mayor de la pagina. */
  .onda--pie::after {
    background: #071b34;
  }


  /* LA QUEBRADA. Unica instancia que no es una curva: dos tramos rectos
     que se encuentran en un quiebre descentrado.

     No es un capricho, es lo que pide el sitio donde va. En esta
     frontera el relleno no se ve (ver mas abajo) y el separador se
     reduce al filo verde; con la elipse, esa linea era indistinguible de
     las otras dos ondas de la pagina. Una recta quebrada se diferencia
     de un vistazo, y ademas es la familia de forma que el diseno pedia
     desde el principio.

     Los vertices, de abajo a la izquierda y en el sentido del reloj:
       0% 100%   esquina inferior izquierda
       0%  40%   sube por el borde izquierdo HASTA LA COSTURA
       34%  8%   el quiebre: hasta aqui ha subido 38.4px de los 48
       100% 0%   esquina superior derecha, los 9.6px que faltaban
       100% 100% baja por el borde derecho y cierra por abajo

     EL 40% NO ES UN NUMERO SUELTO: ES LA COSTURA. La caja mide
     subida * 2.5 y el margen superior es -subida, asi que la linea de
     union entre las dos secciones cae siempre en 1/2.5 = 40% del alto,
     valga lo que valga --onda-subida. Por eso este poligono no necesita
     puntos de ruptura propios: los cuatro escalones le salen gratis.
     TRAMPA: si alguien cambia el multiplicador 2.5 de height, este 40%
     deja de ser la costura y hay que recalcularlo.

     Reparto de la subida a proposito desigual -38.4px en el primer 34%
     del ancho y 9.6px en el 66% restante-: con la subida repartida por
     igual saldria una recta sola y el quiebre no se notaria.

     polygon() y no path() por lo mismo que se explica arriba: acepta
     porcentajes, asi que escala sola igual que la elipse. */
  .onda--destacado::before,
  .onda--destacado::after {
    -webkit-clip-path: polygon(0% 100%, 0% 40%, 34% 8%, 100% 0%, 100% 100%);

    clip-path: polygon(0% 100%, 0% 40%, 34% 8%, 100% 0%, 100% 100%);
  }


  /* SERVICIOS -> PROYECTO DESTACADO. Relleno #ffffff, el mismo
     background de .featured-project (styles.css:196).

     ESTA INSTANCIA NO SE VE COMO LAS OTRAS DOS, Y ES CORRECTO. Arriba
     hay #f4f6f7 y abajo #ffffff: 1.08:1, poco mas de tres puntos de L*.
     El relleno no se lee, y no hay implementacion que lo salve; es
     fisica del color. Lo que si se lee es el filo verde siguiendo la
     quebrada, con un aclarado muy sutil por debajo: aqui el separador es
     una linea verde con un quiebre, a proposito.

     Y el relleno NO sobra aunque no se vea: es lo que recorta el
     ::before y lo deja en una linea de 3px. Quitandolo se veria la cuna
     verde entera, maciza.

     Si algun dia se quiere mas presente, la palanca es el filo -no el
     relleno-: .onda--destacado { --onda-filo: 5px }.

     Sin z-index: .featured-project es position:relative y va despues en
     el arbol, asi que tapa por si sola los 72px que quedan enterrados,
     que ademas son del mismo blanco. Su overflow:hidden (styles.css:198)
     no pinta nada aqui: la onda es HERMANA de la seccion, no hija. */
  .onda--destacado::after {
    background: #ffffff;
  }

}


/* z-index NEGATIVO, solo en la instancia del pie, y fuera del @supports
   porque es una cuestion de orden de pintado y no de recorte.

   El motivo es concreto: el arco se entierra 72px dentro del bloque de
   abajo, y el <footer> solo tiene 60px de padding superior
   (index.html:993). Sin esto, los pseudo-elementos -que van
   position:absolute y por tanto pintan en la capa de los elementos
   posicionados- taparian los 12px de mas por encima del logo del pie.
   Con z-index:-1 la pieza entera baja por debajo de los fondos de los
   bloques normales: el footer la tapa donde solapa (mismo color, no se
   nota) y la cresta se sigue viendo sobre el blanco del body, porque el
   fondo del <body> se propaga al lienzo y el lienzo pinta por debajo de
   todo, tambien de las capas negativas. Funciona porque ningun ancestro
   -ni html, ni body, ni main- crea contexto de apilamiento, asi que el
   z-index negativo llega hasta la raiz.

   La instancia de servicios NO lo lleva y no debe llevarlo: ahi el
   bloque de arriba es la banda oscura de CIFRAS, un div normal, y con
   z-index negativo la onda quedaria escondida detras de el.

   Precedente en el repo: .service-row::before usa z-index:-1 por el
   mismo motivo (styles.css:1015). */
.onda--pie {
  z-index: -1;
}


/* =========================================================
   TABLET

   A 950px porque es donde ya reacciona .services-list (styles.css:1359),
   la seccion a la que se pega la instancia principal. Un solo numero: la
   silueta no cambia porque las coordenadas van en porcentaje y la
   relacion subida/alto la mantiene el calc.
   Holgura: cresta de 45px contra los 76px de CIFRAS y los 70px de
   CLIENTES. Enterrado 63px contra los 90px de padding superior que tiene
   .services-list a este ancho (styles.css:1362).
   ========================================================= */

@media (max-width: 950px) {

  .onda {
    --onda-subida: 42px;
  }

}


/* =========================================================
   MOVIL

   A 640px y no a 600px, por lo mismo que ya esta escrito en
   .featured-project: es el ancho en el que entra el bloque global de
   rupturas, y con el corte en 600 queda una franja de 40px en la que el
   global ya pisa y la pieza todavia no reacciona.

   OJO al desfase con .services-list, que si corta en 600
   (styles.css:1478): entre 601 y 640px la seccion conserva los 90px de
   padding del escalon de 950, asi que la onda entierra 51px y quedan
   39px; de 600 hacia abajo el padding baja a 75px (styles.css:1481) y
   quedan 24px. Las dos holguras son buenas, pero la cuenta hay que
   hacerla con el padding que toque, no con el de este breakpoint.

   El filo baja a 2px porque 3 sobre una cresta de 34 pesa demasiado.
   ========================================================= */

@media (max-width: 640px) {

  .onda {
    --onda-subida: 34px;

    --onda-filo: 2px;
  }

}


/* =========================================================
   MOVIL ESTRECHO

   Tercer escalon a 450px, un corte que el sitio ya usa en .commitment
   (styles.css:1869). No es cosmetico: la elipse conserva su silueta en
   porcentajes, asi que al estrecharse la ventana la curva se EMPINA. La
   pendiente en el punto de apoyo es 1.626 * alto / ancho, o sea 7.7
   grados a 1440px y 22 grados a 360px si se dejase el alto del escalon
   anterior. Con 28px la pendiente en un movil de 360px baja a 17.5
   grados y el arco se sigue leyendo tendido en vez de como una cuna.
   ========================================================= */

@media (max-width: 450px) {

  .onda {
    --onda-subida: 28px;
  }

}

/* ---------- 9. Puntos de ruptura globales ---------- */
@media (max-width: 1024px) {
  .wrap { padding-left: 28px !important; padding-right: 28px !important; }
  .grid-4 { grid-template-columns: repeat(2,1fr) !important; }
  .grid-6 { grid-template-columns: repeat(3,1fr) !important; }
  h1, .hero-title { font-size: 44px !important; }
}
@media (max-width: 860px) {
  .nav-links, .nav-cta { display: none !important; }
  .hamburger-btn { display: flex !important; }
  .row-2 { grid-template-columns: 1fr !important; }
  .footer-grid { grid-template-columns: repeat(2,1fr) !important; }
}
@media (max-width: 640px) {
  .wrap { padding-left: 18px !important; padding-right: 18px !important; }
  .grid-3, .grid-4 { grid-template-columns: 1fr !important; }
  .grid-6 { grid-template-columns: repeat(2,1fr) !important; }
  .footer-grid { grid-template-columns: 1fr !important; }
  .util-bar { display: none !important; }
  .nav-spacer { height: 77px; }
  html { scroll-padding-top: 77px; }
  .hero-cta-row { flex-direction: column !important; align-items: stretch !important; }
  .hero-cta-row > a, .hero-cta-row > span { justify-content: center !important; }
  .footer-tags { flex-wrap: wrap !important; gap: 8px 14px !important; }
  h1, .hero-title { font-size: 32px !important; }
  h2 { font-size: 26px !important; }
  h3 { font-size: 22px !important; }
}