/* css/main.css */
/* =========================================================================
   GALOPANTE MEDIA — Intro interactiva + Hero
   FASE 1: sólo estilos necesarios para el pin + scrub del Video 1.
   Las clases de las secuencias (seq1, seq2, seq3, seq4, hero) se agregan
   en las fases siguientes; acá sólo dejamos la paleta y el reset listos
   para que no haya que reescribir nada después.
   ========================================================================= */

:root {
  /* Paleta corporativa Galopante — única fuente de verdad en CSS.
     No introducir colores nuevos sin necesidad (sección 5 del brief). */
  --petro-galopante: #09121C;
  --aquamarina: #B3ECE6;
  --coral: #EB455D;
  --hueso: #F1F0F0;
  --cuarzo-ahumado: #89837A;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--petro-galopante);
  color: var(--hueso);
  font-family: 'Montserrat', -apple-system, BlinkMacSystemFont, sans-serif;
  overflow-x: hidden;
}

/* Preparado para GOAT vía @font-face en cuanto estén los archivos web.
   No sustituir automáticamente por otra tipografía (sección 6). */
@font-face {
  font-family: 'GOAT';
  src: url('../assets/fonts/GOAT.woff2') format('woff2'),
       url('../assets/fonts/GOAT.woff') format('woff');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* -------------------------------------------------------------------
   VIDEO 1 — sección pinneada, controlada por scroll

   OJO: #intro-scrub NO define su propia altura acá. La distancia de
   scroll (cuántos vh dura el recorrido completo) es una única fuente
   de verdad: GALOPANTE_CONFIG.SCROLL.distanceVh en config.js. GSAP
   (ScrollTrigger pin + pinSpacing) es quien reserva ese espacio en el
   documento automáticamente. Si esta sección tuviera además una
   altura fija en CSS, el espacio de scroll quedaría duplicado.
   ------------------------------------------------------------------- */
#intro-scrub {
  position: relative;
  width: 100%;
}

#intro-scrub .pin-wrap {
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  /* Mismo color que el primer frame del Video 1: evita cualquier
     flash negro mientras el video todavía está cargando metadata. */
  background: var(--coral);
}

#video1 {
  position: absolute;
  inset: 0;
  width: 100vw;
  height: 100vh;
  object-fit: cover;
  /* El video nunca se reproduce por sí mismo: sólo currentTime. */
  pointer-events: none;
}

/* -------------------------------------------------------------------
   SECUENCIA 1 — "scrolleá hacia el origen de las buenas ideas"

   Capa HTML por encima del video (mismo sistema de coordenadas
   fullscreen). pointer-events: none porque es puramente decorativa —
   nunca debe interceptar el scroll ni clicks futuros.
   ------------------------------------------------------------------- */
.seq {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

.seq1 {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

/* FASE 7.3 — isotipo de Galopante arriba de "scrolleá", pedido del
   cliente con una imagen de referencia (ver también sequence1.js: se
   anima en el MISMO timeline que .seq1-copy/.seq1-arrow, así que
   desaparece junto con el resto apenas arranca el scroll, no por
   separado). Medido sobre la referencia: ancho ~95px sobre 1920px de
   viewport (~5vw) — de ahí el clamp de abajo.

   FASE 7.4 — pedido del cliente: no quería un margen fijo respecto a
   "scrolleá", sino el isotipo centrado en el espacio vacío entre el
   borde superior de la pantalla y donde arranca "scrolleá". Por eso
   pasa a position:absolute (sale del flujo de flexbox de .seq1 — así
   .seq1-copy/.seq1-arrow se centran solos como si el isotipo no
   existiera, que es justo la referencia para medir ese hueco) y
   sequence1.js le calcula el "top" en cada carga/resize — ver
   positionIsotype() ahí. */
.seq1-isotype {
  position: absolute;
  /* top real lo calcula sequence1.js (positionIsotype) midiendo el
     hueco real hasta "scrolleá" — este 15% es sólo el valor de
     arranque antes de que corra ese cálculo, para que no haya un
     salto visible apenas carga la página. */
  top: 15%;
  left: 50%;
  width: clamp(3.5rem, 5vw, 6rem);
  height: auto;
  will-change: transform, opacity;
}

.seq1-copy {
  color: var(--hueso);
  will-change: transform, opacity;
}

.seq1-line {
  margin: 0;
}

.seq1-line--lead {
  font-weight: 300;
  font-size: clamp(2.75rem, 6vw, 4.5rem);
  letter-spacing: 0.01em;
  line-height: 1;
  margin-bottom: 1.25rem;
}

.seq1-line--sub {
  font-weight: 400;
  font-size: clamp(1.15rem, 2.1vw, 1.5rem);
  line-height: 1.4;
  letter-spacing: 0.005em;
}

.seq1-arrow {
  margin-top: 3rem;
  color: var(--hueso);
  will-change: transform, opacity;
}

.seq1-arrow-glyph {
  display: block;
  will-change: transform;
}

/* -------------------------------------------------------------------
   SECUENCIA 2 — "BIENVENIDO / A [logo]" (antes "GALOPAMOS / MARCAS")

   Sin fondo sólido detrás (se descartó): el texto queda directamente
   sobre el Video 1.

   .seq2-copy: BIENVENIDO arriba, "A [logo]" abajo, sin gap entre
   ambos — el borde compartido es el "eje horizontal invisible" del
   brief. Cada línea se revela con clip-path (ver sequence2.js), nunca
   con opacity, y vuelve a cerrarse (salida) antes de que termine el
   capítulo "galopamos". Los nombres de clase (--galopamos/--marcas)
   quedaron igual que antes del cambio de copy (FASE 9.2): sequence2.js
   selecciona por clase, no por el texto que contienen.
   ------------------------------------------------------------------- */
.seq2 {
  display: flex;
  align-items: center;
  justify-content: center;
}

.seq2-copy {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.seq2-word {
  margin: 0;
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--hueso);
}

.seq2-word--galopamos {
  font-weight: 300;
  /* Subido (pedido del cliente, con una imagen de referencia): el techo
     viejo (4.25rem) frenaba el tamaño mucho antes de lo que el 6vw
     hubiera dado en pantallas anchas — por eso se veía chico en
     desktop. Medido sobre la referencia (altura de mayúscula ~130px
     sobre una imagen de 1920x1080, prácticamente IGUAL entre GALOPAMOS
     y MARCAS pese al distinto peso) y llevado a clamp() para que siga
     respondiendo al viewport en vez de quedar fijo.
     FASE 9.2.7 — el cliente pidió achicar el sobreimpreso "a la
     mitad": clamp(2.75rem, 9.5vw, 10rem) → clamp(1.375rem, 4.75vw,
     5rem) (los tres valores exactamente a la mitad, así se mantiene
     la misma curva de escalado responsive, sólo que más chica). */
  font-size: clamp(1.375rem, 4.75vw, 5rem);
}

.seq2-word--marcas {
  /* FASE 9.2.7 — el cliente pidió que la "A" esté en Montserrat Light
     "tal como BIENVENIDO": 800 → 300, igual que .seq2-word--galopamos
     de acá arriba. Sólo afecta a la "A" (el peso de fuente no aplica
     sobre la imagen del logo). */
  font-weight: 300;
  /* Mismo criterio que .seq2-word--galopamos: los tres valores del
     clamp a la mitad. */
  font-size: clamp(1.5rem, 4.75vw, 5rem);
  /* FASE 9.2: ahora es "A" + el isotipo/wordmark en vez de la palabra
     MARCAS — se vuelve un contenedor flex en vez de texto plano para
     poder alinear verticalmente la letra "A" con el logo. El clip-path
     y el yPercent de sequence2.js siguen aplicando sobre esta misma
     caja (el mecanismo de revelación no distingue display:flex de
     texto normal), así que la animación no se tocó. */
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 0.18em;
  /* FASE 9.2.5 — el cliente pidió agrandar el logo "hasta la O de
     BIENVENIDO" (FASE 9.2.3) y eso se logró con margin-top negativo en
     este renglón, pero al verlo en vivo pidió lo contrario: "A
     Galopante debe quedar más abajo pq está superpuesto a BIENVENIDO
     ... como si fuese una misma línea de texto sobre un renglón" — o
     sea, SIN superposición entre los dos renglones, cada uno en su
     propio lugar (el logo agrandado alcanza igual bastante altura por
     sí solo — ver .seq2-word__logo más abajo — así que ya no hace
     falta forzarlo a invadir el renglón de arriba). Se saca el
     margin-top negativo; el renglón vuelve a su posición natural
     dentro de .seq2-copy (flex-column), sin tocar nada del mecanismo
     de alineación interna "A"/"Galopante" (eso sigue en
     .seq2-word__a, más abajo, sin cambios). */
}

.seq2-word__a {
  /* FASE 9.2.4 — el logo trae "Galopante" (+ el punto rojo) arriba y
     "media" chico abajo, como una sola imagen. El cliente pidió que el
     renglón de abajo de "Galopante" (no el de "media") quede alineado
     con la "A", y que "media" cuelgue suelto debajo de todo el
     bloque. Medido en el PNG real (assets/images/logo-galopante-
     wordmark-white.png, 3268×640): "Galopante" + el punto terminan en
     el pixel 431 de 640 (67.34% del alto de la imagen) — el 32.66%
     restante es el hueco + "media".

     OJO — por qué esto vive en la "A" y no en la imagen: la primera
     versión de este ajuste le daba margin-bottom NEGATIVO a la
     imagen para "estirarla" hacia abajo más allá de su propio
     renglón (y así asomar "media"), pero .seq2-word--marcas queda con
     clip-path: inset(0%) fijo como estado "revelado" de la animación
     de sequence2.js — y clip-path SIEMPRE recorta al borde exacto de
     la caja del elemento, aunque sea "0% de inset" (no es lo mismo
     que clip-path:none). Cualquier desborde -la imagen agrandada, o
     "media"- quedaba invisible, recortado por esa máscara. La imagen
     ahora vive ENTERA dentro de su propio renglón (sin overflow), y en
     cambio es la "A" la que se corre hacia arriba con este
     margin-bottom POSITIVO (empuja su propio borde inferior hacia
     arriba dentro del renglón, sin sacarla de la caja) hasta calzar
     con el final real de "Galopante" — así nada se desborda de
     .seq2-word--marcas y el clip-path nunca tiene nada que recortar. */
  margin-bottom: 0.36em;
}

.seq2-word__logo {
  /* Alto en em (relativo al font-size fluido de .seq2-word--marcas)
     para seguir escalando en cualquier breakpoint. Sin "width" fijo:
     así el navegador respeta el aspect-ratio intrínseco del PNG. Este
     elemento NUNCA lleva margin negativo (ver el comentario grande en
     .seq2-word__a arriba) — toda la imagen, "media" incluida, queda
     siempre dentro de su propio renglón. */
  height: 1.3em;
  width: auto;
  display: block;
}

/* -------------------------------------------------------------------
   SECUENCIA 3 — "HACEMOS" + disciplinas

   .seq3-exit-mask: máscara exterior (clip-path animado sólo en la
   salida). .seq3-block: HACEMOS + disciplinas como bloque único, es lo
   que se desplaza hacia arriba en la salida. .seq3-hacemos-wrap: su
   propia máscara de revelación (independiente de la de salida).
   .seq3-discipline-wrap: overflow:hidden individual por disciplina.
   ------------------------------------------------------------------- */
.seq3 {
  display: flex;
  align-items: center;
  justify-content: center;
}

.seq3-exit-mask {
  display: flex;
}

.seq3-block {
  display: flex;
  flex-direction: row;
  align-items: center;
  /* HACEMOS pegado casi contra el bloque tipográfico (pedido del
     cliente: "más grande y más cerca de este bloque"). */
  gap: clamp(0.3rem, 1vw, 0.75rem);
}

.seq3-hacemos-wrap {
  overflow: hidden;
  display: flex;
  align-items: center;
}

.seq3-hacemos {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.35em;
  /* Vuelto a achicar (pedido del cliente, según referencia): HACEMOS
     acompaña al bloque tipográfico pero no compite en peso visual con
     él — es una etiqueta lateral, no un título más. */
  font-size: clamp(0.85rem, 1.3vw, 1.1rem);
  color: var(--hueso);
  white-space: nowrap;
}

/* Línea delgada entre HACEMOS y el bloque ESTRATEGIA/BRANDING/CONTENIDO/
   GROWTH (pedido del cliente, según referencia). Se estira a la altura
   del wrap de HACEMOS (align-self: stretch dentro de .seq3-block, que
   es flex row align-items: center) para leerse como un separador, no
   como un adorno suelto. */
.seq3-divider {
  align-self: stretch;
  width: 1px;
  background: var(--hueso);
  opacity: 0.35;
}

/* -------------------------------------------------------------------
   Bloque tipográfico ESTRATEGIA/BRANDING/CONTENIDO/GROWTH

   Igual que en la referencia del cliente: cada palabra tiene su propio
   tamaño de fuente (no un tamaño único para las 4), calculado para que
   las 4 líneas ocupen un ancho similar entre sí y el conjunto se lea
   como un bloque prolijo — no como una lista con tamaños parejos.
   align-items: flex-start alinea los 4 renglones por su borde
   IZQUIERDO (igual que la referencia — todas las palabras arrancan
   pegadas a la línea divisoria/HACEMOS), dejando el borde derecho
   escalonado según el largo de cada palabra.

   FASE 30 — color: originalmente cada palabra tenía un color distinto
   (Estrategia hueso, Branding aquamarina, Contenido coral, Growth
   cuarzo ahumado) para diferenciarlas visualmente. A pedido del
   cliente ("podras dejar todas las letras color hueso?") las 4 pasan
   a compartir el mismo color var(--hueso) — sólo cambia el color,
   los tamaños por palabra se mantienen igual que antes.
   ------------------------------------------------------------------- */
.seq3-disciplines {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(0.15rem, 0.6vw, 0.4rem);
}

.seq3-discipline-wrap {
  overflow: hidden;
}

.seq3-discipline {
  display: block;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.seq3-discipline--estrategia {
  color: var(--hueso);
  font-size: clamp(2rem, 5.5vw, 3.75rem);
}

.seq3-discipline--branding {
  color: var(--hueso);
  font-size: clamp(2.3rem, 6.4vw, 4.4rem);
}

.seq3-discipline--contenido {
  color: var(--hueso);
  font-size: clamp(2.1rem, 5.75vw, 4rem);
}

.seq3-discipline--growth {
  color: var(--hueso);
  font-size: clamp(2.75rem, 7.5vw, 5.25rem);
}

/* -------------------------------------------------------------------
   SECUENCIA 4 — "POTENCIAMOS" (letra por letra, detrás de Galopardo)

   FASE 7 — migrado desde dev/potenciamos-prototype.html (versión v3.8,
   la aprobada tras varias rondas de prueba — ver NOTES.md). El propio
   prototipo aislado sigue en dev/ como referencia histórica, pero deja
   de tocarse: esta es ahora la única versión que se edita.

   #seq4-bg-frame: un freeze-frame de Video 1 (exportado del mismo
   frame exacto al que llega el scrub cuando el progreso del scroll
   maestro es 1 — ver VIDEO1.trimEndFrames en config.js). Tapa a
   #video1 apenas arranca este capítulo: el recorte de Galopardo
   (#seq4-fg-mask) sólo calza pixel-perfect con ESE frame, y #video1
   sigue recibiendo su propio currentTime (mapeado 1:1 al progreso
   0..1 del scroll maestro, no al capítulo) durante todo este tramo —
   no se pausa ni se le pide nada especial. En vez de tocar esa lógica
   (que ya está pixel-perfect calibrada para el final del recorrido),
   es más simple y más seguro taparla con esta imagen fija — ver el
   corte casi instantáneo de opacity en sequence4.js.

   #seq4-text / #seq4-word / .letter: mismo modelo 3D que el prototipo
   — "fila india" (sharedMotion en sequence4.js), perspective 1600px,
   cada letra con su propia cara + canto (dos capas en Z, ver
   .letter-face/.letter-edge).

   BUG encontrado en vivo (POTENCIAMOS no aparecía detrás de la cabra
   — ver NOTES.md) y su fix: Chrome NO ordena por profundidad real
   entre hermanos que están a distinta PROFUNDIDAD DE ANIDAMIENTO
   dentro de la cadena preserve-3d, aunque ambos cuelguen en algún
   punto del mismo ancestro con perspective. Antes, #seq4-fg-mask
   colgaba directo de #seq4-text (1 nivel) pero cada .letter colgaba
   de #seq4-word dentro de #seq4-text (2 niveles) — con esa asimetría
   el navegador pintaba SIEMPRE las letras por encima del recorte,
   sin importar su z real (comprobado con el propio prototipo
   aislado, que tenía el mismo problema desde siempre — nunca se
   había verificado el occlusion visualmente, sólo valores numéricos
   de z/x). Fix: sequence4.js mide la posición natural de cada letra
   dentro de #seq4-word (que sigue existiendo sólo como scaffold de
   medición, ver measureNatural) y después las saca de ahí,
   insertándolas como HIJAS DIRECTAS de #seq4-text (mismo nivel que
   #seq4-fg-mask) con position:absolute + left/top calculados. Recién
   ahí preserve-3d compara profundidad real entre hermanos del mismo
   nivel y el recorte tapa correctamente a las letras que quedan
   detrás (ver translateZ(2px) más abajo, el desempate mínimo para
   que el recorte gane cuando una letra llega a z≈0, su lugar de
   reposo). Por eso los selectores de abajo son "#seq4-text .letter"
   y no "#seq4-word .letter": tienen que seguir aplicando después de
   que JS mueve la letra fuera de #seq4-word. Las propiedades
   tipográficas (font, color, etc.) están puestas directo en .letter
   y no en #seq4-word por la misma razón: dejan de heredar de
   #seq4-word en cuanto la letra se muda de contenedor.

   FASE 7.6 — root cause real de por qué el occlusion seguía fallando
   en vivo pese al fix de arriba y al de font-swap-race: #seq4-text ya
   NO es simplemente "inset:0" (el viewport completo) — sequence4.js
   (positionStage) le fija left/top/width/height por JS para que
   coincida EXACTAMENTE con el rectángulo que ocuparía la imagen
   1920x1080 completa bajo el mismo cálculo que hace el navegador para
   object-fit:cover en #seq4-bg-frame/#seq4-fg-mask (por eso puede
   terminar más grande que el viewport, con left/top negativos: el
   recorte visual lo hace el overflow:hidden de .seq4, igual que a la
   imagen). El inset:0 de acá abajo queda sólo como fallback
   antes de que corra JS (evita un salto/flash visible, mismo patrón
   que .seq1-isotype/top:15%). Ver el comentario largo al principio de
   sequence4.js para la explicación completa. Por la misma razón,
   #seq4-word ya NO tiene "transform: translateY(-4vh)" fijo acá (ver
   más abajo) — sequence4.js se lo aplica escalado por el mismo
   factor.
   ------------------------------------------------------------------- */
.seq4 {
  /* .seq ya pone position:absolute + inset:0 + z-index:2 (ver arriba)
     — alcanza para tapar #video1 y quedar por encima de seq1/2/3 (que
     para cuando este capítulo empieza ya terminaron de revelarse y
     ocultarse). Acá sólo hace falta el layout interno. */
  overflow: hidden;
}

#seq4-bg-frame {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

#seq4-text {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  transform-style: preserve-3d;
  perspective: 1600px;
}

#seq4-word {
  /* Scaffold de medición SOLAMENTE: sequence4.js arma acá las letras
     con flexbox para leer su posición de reposo natural (measureNatural)
     y enseguida las muda a ser hijas directas de #seq4-text (ver el
     bloque de comentarios de más arriba) — #seq4-word queda vacío en
     régimen normal, sin tamaño ni efecto visual. Se conserva el
     transform de acá para que la medición inicial ya incluya el mismo
     desplazamiento vertical que tenía el diseño aprobado. */
  display: flex;
  flex-direction: row;
  white-space: nowrap;
  /* FASE 7.6 — el nudge vertical fino (pedido del cliente: "mayor
     legibilidad" — la mitad de la letra queda tras el sofá y la otra
     mitad tras los cuernos de la cabra) ya NO es un "translateY(-4vh)"
     fijo acá: sequence4.js se lo aplica por JS (referenceYNudgePercent
     en config.js) escalado por el mismo factor que usa para el
     recorte de la imagen — ver el comentario grande de FASE 7.6 en
     sequence4.js. Si hace falta volver a ajustar ese valor tras un
     cambio de frame/composición, se toca en config.js, no acá.
     transform-style se mantiene: sigue haciendo falta para que el
     3D de las letras funcione mientras están en este scaffold. */
  transform-style: preserve-3d;
}

#seq4-text .letter {
  position: relative;
  display: inline-block;
  transform-style: preserve-3d;
  will-change: transform;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.005em;
  line-height: 1;
  /* "POTENCIAMOS" ocupa ~80% del ancho del frame (medido en la
     referencia) — bastante más grande que el resto de los overprints,
     a propósito, porque acá es una sola línea larga.

     FASE 7.6 — este clamp() queda sólo como fallback pre-JS (antes de
     que corra sequence4.js, mismo patrón que el resto del archivo):
     el tamaño real que se ve en pantalla lo fija JS por inline style
     (applyBaseLetterSize/fitWordToStage), escalado por el mismo
     factor que usa positionStage() para el recorte de la imagen — no
     por vw directo, que es justo lo que rompía la calibración en
     viewports que no son 1920x1080 exacto. Ver el comentario grande
     de FASE 7.6 en sequence4.js. */
  font-size: clamp(4.25rem, 11vw, 8.5rem);
  color: var(--hueso);
  /* A propósito SIN backface-visibility:hidden: cuando la letra está
     de espaldas a cámara (rotationY inicial muy negativo) se ve
     espejada horizontalmente — es el efecto pedido, no un caso a
     esconder. */
}

#seq4-text .letter-face {
  position: relative;
  display: block;
  transform: translateZ(0);
}

/* Canto de la letra: una segunda copia del mismo carácter, apenas
   detrás en Z (chapita fina) y de otro color — de frente queda tapada
   por .letter-face; sólo se nota cuando la letra pasa de canto durante
   el giro (rotationY ≈ 90°), leyéndose como un borde 3D real. */
#seq4-text .letter-edge {
  position: absolute;
  inset: 0;
  display: block;
  color: var(--aquamarina);
  transform: translateZ(-9px);
}

#seq4-fg-mask {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  /* Desempate mínimo (2px, imperceptible en escala): cuando una letra
     termina de asentarse en z=0 (su lugar de reposo), el recorte gana
     el empate de forma consistente y la tapa — sin esto, z=0 contra
     z=0 podría alternar según el navegador. */
  transform: translateZ(2px);
}

/* -------------------------------------------------------------------
   FASE 7.7/7.7.1/7.7.2 — etiqueta "POTENCIAMOS" / "MARCAS" (dos
   líneas) bajo la mesita/pocillo del freeze-frame, alineada a la
   derecha con la "S" final de POTENCIAMOS.

   Pedido del cliente: como el grupo "hidden" (ENCIA) queda tapado
   detrás de Galopardo, agregar esta etiqueta, más chica y en
   Montserrat Light, que refuerce el concepto apenas termina de
   asentarse la palabra grande. FASE 7.7.2 (corrección sobre una
   captura real de mobile): en una sola línea "POTENCIAMOS MARCAS"
   quedaba escrito literalmente encima de la mesita/pocillo del
   freeze-frame — pasa a dos líneas ("POTENCIAMOS" / "MARCAS",
   sequence4.marcas.lines en config.js, fuente única de verdad),
   alineadas a la derecha ENTRE SÍ y con el borde derecho de la S
   (ya no centradas ni ancladas bajo "OS"), y la posición vertical deja
   de perseguir a las letras — pasa a ser un punto fijo calibrado
   contra la imagen nativa, bien debajo del borde inferior de la mesa
   (ver sequence4.marcas.referenceTopYPx en config.js). Se revela con
   el mismo tipo de máscara (clip-path) que ya usa GALOPAMOS/MARCAS en
   sequence2.js — nunca opacity — descubriéndose de arriba hacia abajo
   a medida que el borde inferior del clip-path retrocede (con dos
   líneas, de paso, ese descubrirse hacia abajo se nota más: primero
   aparece "POTENCIAMOS", después "MARCAS").

   display:flex column + align-items:flex-end: alinea las dos líneas a
   la derecha ENTRE SÍ (el bloque completo mide el ancho de la línea
   más larga, "POTENCIAMOS"; "MARCAS", más corta, queda pegada al
   mismo borde derecho) sin depender de text-align. position:absolute
   con left/top calculados por JS (positionMarcas en sequence4.js,
   relativo a #seq4-text — el mismo sistema de coordenadas
   "cover-scale" que usan las letras, ver FASE 7.6) — acá sólo
   transform-origin y el resto de las propiedades que no dependen del
   layout. FASE 7.7.2: xPercent pasa de -50 (centrado) a -100 (el
   "left" que fija JS es ahora el borde DERECHO del bloque, para que
   cuelgue hacia la izquierda desde ahí, alineado con la S) — el
   clip-path/y de la animación los sigue fijando GSAP (sequence4.js),
   nunca CSS estático, para poder animarlos.

   z: por encima de #seq4-fg-mask (que vive en translateZ(2px)) — a
   propósito, esta etiqueta NO debe quedar ocluida por Galopardo (se
   ancla sobre la S, letra del grupo "right", siempre visible). El
   translateZ(6px) real lo fija GSAP (sequence4.js, ver el gsap.set
   inicial con z:6) junto con xPercent/clipPath/y — no acá, porque un
   transform estático en CSS quedaría pisado apenas corra ese
   gsap.set (GSAP escribe su propio transform inline). */
.seq4-marcas {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  font-weight: 300;
  text-transform: uppercase;
  white-space: nowrap;
  /* FASE 7.7.1 — bajado de 0.22em (calibrado para "MARCAS" suelto, 6
     caracteres) a 0.12em: sobre "POTENCIAMOS" (11 caracteres) 0.22em
     por caracter sumaba demasiado ancho extra y se leía
     innecesariamente espaciado. */
  letter-spacing: 0.12em;
  line-height: 1;
  color: var(--hueso);
  pointer-events: none;
  will-change: transform, clip-path;
  /* Fallback pre-JS: el tamaño real lo fija sequence4.js
     (positionMarcas), escalado por el mismo factor "cover" que el
     resto de la secuencia. */
  font-size: clamp(0.75rem, 1.7vw, 1.1rem);
}

/* FASE 7.7.2 — separación entre las dos líneas: la fija sequence4.js
   por JS (marginTop en px, sequence4.marcas.lineGapPx escalado) sobre
   la segunda línea en adelante, no acá — mismo criterio que el resto
   de esta calibración (escala con "cover", no con una unidad de CSS
   fija). Acá sólo lo que no depende de esa escala. */
.seq4-marcas-line {
  display: block;
}

/* -------------------------------------------------------------------
   FASE 8.2 — VIDEO 2 (HOME), continuación después de POTENCIAMOS.

   Corrección sobre FASE 8: el cliente probó en vivo y avisó que el
   video aparecía "debajo, como una continuación de la página" — había
   que seguir scrolleando para verlo, y mientras tanto la pantalla SÍ
   se movía (se veía la página desplazándose desde la escena congelada
   hacia esta sección). La idea del cliente es lo opuesto: simular que
   el "viaje" dentro de la misma escena sigue, y el video es un nuevo
   plano de ESE mismo recorrido — tiene que aparecer exactamente en el
   mismo lugar de pantalla donde quedó congelado Video 1, sin que la
   página se desplace ni haya que scrollear más para descubrirlo.

   Primer intento descartado: `position: sticky`. En teoría "se pega"
   al tope de pantalla, pero en la práctica seguía habiendo un tramo de
   scroll (exactamente 1 viewport de alto) en el que esta sección
   todavía se desliza hacia arriba ENTRANDO en pantalla como un bloque
   normal ANTES de llegar a pegarse — porque el .pin-wrap de
   #intro-scrub, apenas el pin de GSAP libera, vuelve a flujo normal
   (deja de estar fixed) y sigue ocupando su propio alto (100vh) en el
   documento; recién después de que ESE bloque termina de desplazarse
   fuera de vista es que esta sección alcanza el punto en el que
   "sticky" empieza a hacer algo — o sea, se seguía viendo exactamente
   el mismo movimiento de página que se quería evitar.

   Solución real: `position: fixed`, superpuesta en el mismo lugar de
   pantalla que #intro-scrub, y oculta (visibility:hidden/opacity:0)
   hasta que el progreso maestro llega a 1 (el pin liberó) — recién ahí
   `js/video2-home.js` le agrega `.home-video-section--active` (ver
   showSection() ahí). Como el primer frame de #video2 es, a propósito,
   IDÉNTICO al freeze-frame en el que queda Video 1, este "corte" es
   invisible aunque no haya transición: no hace falta esconder nada
   gradualmente, sólo evitar que aparezca ANTES de tiempo (por eso
   sigue el mismo gate de progreso≥1 que ya usa arm() en
   video2-home.js) ni tampoco DESPUÉS de que el usuario scrollee para
   atrás por debajo de ese punto (showSection()/hideSection() ahí
   mismo, según el progreso suba o baje de 1 — soporta scroll reverso
   como el resto del sitio).

   El pin-spacer que arma GSAP para #intro-scrub YA reserva, por su
   cuenta, un tramo extra de scroll (exactamente 1 viewport, lo que
   tarda el propio .pin-wrap en volver a flujo normal tras liberarse)
   AUNQUE esta sección ya no ocupe espacio en el documento (al ser
   fixed) — ese tramo extra sigue generando eventos nativos `scroll`
   reales mientras el usuario scrollea después de progreso=1, que es
   justo lo que necesita el trigger "scroll o clic" de
   video2-home.js — con la diferencia de que ahora, al estar esta
   sección fixed y ya visible tapando todo, ese scroll de fondo queda
   completamente oculto: el usuario no ve absolutamente ningún
   movimiento de página mientras tanto.

   z-index alto (por encima de .seq, que usa 2) para tapar por completo
   #intro-scrub una vez activa. pointer-events:none (igual que #video1)
   porque el gesto que dispara la reproducción lo escucha
   video2-home.js en window, no esta sección — nunca debe interceptar
   ningún click/scroll. width/height 100vw/100vh + overflow:hidden para
   el mismo tratamiento object-fit:cover que #video1. background: mismo
   color que el freeze-frame de POTENCIAMOS para que, si #video2 tarda
   un instante en pintar su primer frame, no haya flash de otro color
   de por medio. */
/* FASE 8.2 — ver el comentario grande junto a #post-intro-scroll-buffer
   en index.html: alto fijo de 1 viewport, puramente para reservar
   distancia de scroll real (el trigger de video2-home.js depende de
   eventos nativos "scroll", que sólo se disparan si scrollY puede
   seguir cambiando) — nunca debe verse, así que mismo color de fondo
   que el resto por las dudas. */
#post-intro-scroll-buffer {
  width: 100vw;
  height: 100vh;
  background: var(--petro-galopante);
}

.home-video-section {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background: var(--petro-galopante);
  z-index: 10;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.home-video-section--active {
  visibility: visible;
  opacity: 1;
}

#video2 {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

/* =========================================================================
   FASE 9 — HEADER FIJO + MENÚ (offcanvas) + REDES SOCIALES FIJAS
   Réplica del patrón de galopante.uy (sitio de producción actual) — ver
   el comentario grande en index.html (justo antes de <header>) para el
   detalle completo de qué se replicó y por qué. Acá sólo el CSS.

   z-index: por encima de TODO lo demás del sitio (.home-video-section
   usa 10, que es el valor más alto que había hasta ahora) — el header,
   el menú y las redes tienen que quedar SIEMPRE visibles sin importar
   en qué parte del recorrido esté el usuario.
   ========================================================================= */

html {
  /* Necesario para que los links del menú (window.scrollTo/
     scrollIntoView en js/header-menu.js) scrolleen con animación en vez
     de saltar de golpe. No afecta el scroll nativo por rueda/trackpad/
     touch del usuario (sigue instantáneo, "1:1" como pide el brief) ni
     la lectura de posición de scroll que hace ScrollTrigger cuadro a
     cuadro — scroll-behavior sólo entra en juego en scrolls disparados
     por código o por un <a href="#ancla">. */
  scroll-behavior: smooth;
}

/* ---------------------------------------------------------------------
   Header
   --------------------------------------------------------------------- */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  padding: 18px 24px 0;
  transition: background-color 0.25s ease;
}

.site-header.is-scrolled {
  background: rgba(9, 18, 28, 0.82);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  padding-bottom: 10px;
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.site-header__logo {
  display: inline-flex;
  line-height: 0;
}

.site-header__logo img {
  width: 28px;
  height: auto;
}

.site-header__menu-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--hueso);
  cursor: pointer;
}

.site-header__menu-btn:hover .site-header__hamburger span {
  background-color: var(--coral);
}

.site-header__hamburger {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  width: 26px;
  height: 20px;
}

.site-header__hamburger span {
  display: block;
  width: 100%;
  height: 2px;
  background-color: currentColor;
  border-radius: 1px;
  transition: transform 0.25s ease, opacity 0.25s ease, background-color 0.2s ease;
}

/* Hamburguesa -> X mientras el menú está abierto */
.site-header__menu-btn[aria-expanded="true"] .site-header__hamburger span:nth-child(1) {
  transform: translateY(8px) rotate(45deg);
}

.site-header__menu-btn[aria-expanded="true"] .site-header__hamburger span:nth-child(2) {
  opacity: 0;
}

.site-header__menu-btn[aria-expanded="true"] .site-header__hamburger span:nth-child(3) {
  transform: translateY(-8px) rotate(-45deg);
}

/* ---------------------------------------------------------------------
   Menú (overlay de pantalla completa) + backdrop
   FASE 9.3 — rediseño pedido por el cliente tomando como referencia el
   menú de kochol.com/es-ES: en vez de un panel angosto deslizando desde
   la derecha con fondo claro, ahora es una superposición a pantalla
   completa, fondo oscuro (--petro-galopante), texto en mayúscula
   Montserrat Light (--hueso), que al pasar el mouse cambia a
   --cuarzo-ahumado. La mecánica de apertura/cierre (botón hamburguesa,
   ESC, click en backdrop, cierre al clickear un link) es la misma de
   siempre — js/header-menu.js no cambió nada, sólo CSS.

   El backdrop (#menuBackdrop) queda debajo del menú en z-index: como el
   menú ahora cubre TODA la pantalla al abrirse, el backdrop nunca llega
   a verse ni a poder clickearse — se deja el elemento y su lógica
   intactos (no hace daño, y evita tocar el JS) pero ya no cumple
   función visual.
   --------------------------------------------------------------------- */
/* Bloquea el scroll de fondo mientras el panel está abierto (igual que
   cualquier modal) — la clase la agrega/saca js/header-menu.js. */
body.site-menu-open {
  overflow: hidden;
}

.site-menu-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1100;
  background: rgba(9, 18, 28, 0.55);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.site-menu-backdrop.is-open {
  opacity: 1;
}

/* ---------------------------------------------------------------------
   FASE 9.4 — menú con video interactivo (referencia estática enviada por
   el cliente + video "GALOPARDO girando"): el fondo oscuro liso de FASE
   9.3 pasa a ser un <video id="menuVideo"> a pantalla completa
   (object-fit: cover) con la cabra arrancando de frente (frame 1, mismo
   encuadre que la referencia estática) y girando de perfil hacia el
   final del clip. Un scrim (gradiente oscuro) sobre el video asegura
   contraste de lectura para la lista, que ahora se ancla arriba a la
   derecha (igual que la referencia) en vez de centrada a pantalla
   completa. El scrubbing del video (mousemove sobre el menú) lo maneja
   js/header-menu.js — ver initMenuVideoScrub() ahí; este bloque sólo
   define capas y estática/hover.

   Los 6 <li> arrancan invisibles/desplazados y se revelan uno tras otro
   (transition-delay incremental por :nth-child, sólo bajo .is-open) para
   el efecto de aparición secuencial pedido por el cliente.
   --------------------------------------------------------------------- */
.site-menu {
  position: fixed;
  inset: 0;
  z-index: 1200;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  background: var(--petro-galopante);
  transform: translateX(100%);
  transition: transform 0.4s ease;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.site-menu.is-open {
  transform: translateX(0);
}

.site-menu__video {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

.site-menu__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    100deg,
    rgba(9, 18, 28, 0.4) 0%,
    rgba(9, 18, 28, 0.1) 40%,
    rgba(9, 18, 28, 0.35) 65%,
    rgba(9, 18, 28, 0.72) 100%
  );
  pointer-events: none;
}

.site-menu__header {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: flex-end;
  padding: 1.5rem 1.75rem 0.5rem;
}

.site-menu__close {
  border: none;
  background: transparent;
  color: var(--hueso);
  font-size: 2.5rem;
  font-weight: 300;
  line-height: 1;
  padding: 0;
  margin: 0;
  cursor: pointer;
  transition: color 0.2s ease;
}

.site-menu__close:hover {
  color: var(--cuarzo-ahumado);
  opacity: 1;
}

/* ---------------------------------------------------------------------
   FASE 22 — "Centro de Marca" (acceso clientes)
   ---------------------------------------------------------------------
   Bloque nuevo arriba a la derecha del panel del menú, debajo del botón
   de cerrar. Se posiciona con position:absolute — mismo truco que
   .site-menu__footer más abajo — para no interferir con el auto-margin
   que centra verticalmente .site-menu__nav. El "top" está calculado a
   ojo contra la altura real de .site-menu__header (padding 1.5rem +
   botón de 2.5rem + padding 0.5rem ≈ 4.5rem) más un pequeño respiro.

   Es un botón CON BORDE (outline), no relleno — a propósito distinto
   del coral sólido de .somos-section__cta / .hacemos-section__cta /
   .hp-cta, para que se lea como un acceso secundario/utilitario y no
   como otro CTA de conversión.
   --------------------------------------------------------------------- */
.site-menu__clients {
  position: absolute;
  z-index: 2;
  top: 5.5rem;
  right: clamp(1.5rem, 5vw, 4rem);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.6rem;
}

.site-menu__clients-label {
  margin: 0;
  font-family: 'Montserrat', sans-serif;
  font-weight: 400;
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cuarzo-ahumado);
}

.site-menu__clients-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.55em 1.3em;
  border: 1px solid var(--aquamarina);
  border-radius: 999px;
  font-family: 'Montserrat', sans-serif;
  font-weight: 500;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--aquamarina);
  text-decoration: none;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.site-menu__clients-link:hover {
  background-color: var(--aquamarina);
  color: var(--petro-galopante);
}

.site-menu__clients-icon {
  width: 0.85em;
  height: 0.85em;
  flex-shrink: 0;
}

.site-menu__nav {
  position: relative;
  z-index: 2;
  margin: auto 0 auto auto;
  padding: 1.5rem clamp(1.5rem, 7vw, 5.5rem);
  max-width: min(92vw, 640px);
  max-height: 100%;
  overflow-y: auto;
}

.site-menu__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: clamp(0.35rem, 1.6vh, 0.85rem);
}

.site-menu__list li {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}

.site-menu.is-open .site-menu__list li:nth-child(1) { transition-delay: 0.15s; }
.site-menu.is-open .site-menu__list li:nth-child(2) { transition-delay: 0.22s; }
.site-menu.is-open .site-menu__list li:nth-child(3) { transition-delay: 0.29s; }
.site-menu.is-open .site-menu__list li:nth-child(4) { transition-delay: 0.36s; }
.site-menu.is-open .site-menu__list li:nth-child(5) { transition-delay: 0.43s; }
.site-menu.is-open .site-menu__list li:nth-child(6) { transition-delay: 0.5s; }

.site-menu.is-open .site-menu__list li {
  opacity: 1;
  transform: none;
}

.site-menu__link {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 0.55em;
  padding: 0.3em 0;
  font-family: 'Montserrat', sans-serif;
  font-weight: 300;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: clamp(1.25rem, 3.3vw, 2.3rem);
  color: var(--hueso);
  text-decoration: none;
  transition: color 0.2s ease;
}

.site-menu__link:hover,
.site-menu__link.is-active {
  color: var(--cuarzo-ahumado);
}

.site-menu__link-num {
  font-size: 0.42em;
  font-weight: 400;
  letter-spacing: 0.05em;
  color: currentColor;
  opacity: 0.55;
}

.site-menu__link-divider {
  display: inline-block;
  width: 1px;
  height: 0.85em;
  background: currentColor;
  opacity: 0.4;
}

.site-menu__link-label {
  color: currentColor;
}

.site-menu__footer {
  position: absolute;
  z-index: 2;
  right: clamp(1.5rem, 5vw, 4rem);
  bottom: clamp(1.25rem, 4vh, 2.25rem);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  pointer-events: none;
}

/* Isotipo: el PNG de origen es un silueta blanca lisa con canal alfa
   (un solo color, sin degradés — verificado con PIL antes de este
   cambio), así que en vez de mostrarlo como <img> — lo que dejaría el
   ícono blanco fijo, sin poder cambiarle el color — se usa como
   mask-image sobre un <span> vacío con background-color: se pinta con
   el color de marca que haga falta (acá cuarzo ahumado, igual que pidió
   el cliente) simplemente cambiando esa variable, sin tocar el PNG. */
.site-menu__footer-logo {
  display: block;
  width: clamp(26px, 2.8vw, 38px);
  height: clamp(23px, 2.48vw, 34px); /* respeta el aspect-ratio real del PNG (643x570) */
  background-color: var(--cuarzo-ahumado);
  -webkit-mask-image: url('../assets/images/isotipo-galopante.png');
  mask-image: url('../assets/images/isotipo-galopante.png');
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

.site-menu__footer-divider {
  width: clamp(60px, 6vw, 90px);
  height: 1px;
  margin: 0.5rem 0;
  background: var(--cuarzo-ahumado);
}

.site-menu__footer-tagline {
  margin: 0;
  font-family: 'Montserrat', sans-serif;
  font-weight: 300;
  font-size: clamp(0.58rem, 0.95vw, 0.72rem);
  letter-spacing: 0.09em;
  line-height: 1.45;
  color: var(--cuarzo-ahumado);
  text-transform: uppercase;
  text-align: right;
}

@media (max-width: 640px) {
  .site-menu__nav {
    margin: auto auto auto auto;
    max-width: 100%;
    padding: 1.5rem 1.5rem;
  }

  .site-menu__list {
    align-items: flex-end;
  }

  .site-menu__footer {
    right: 1.25rem;
    bottom: 1.1rem;
  }

  .site-menu__clients {
    top: 5.25rem;
    right: 1.25rem;
    gap: 0.45rem;
  }

  .site-menu__clients-label {
    font-size: 0.6rem;
  }

  .site-menu__clients-link {
    padding: 0.5em 1.1em;
    font-size: 0.7rem;
  }
}

/* ---------------------------------------------------------------------
   Redes sociales fijas
   --------------------------------------------------------------------- */
.social-fixed {
  position: fixed;
  left: 2.91vw;
  bottom: 4vh;
  z-index: 900;
  display: flex;
  flex-direction: column;
  gap: 5px;
  opacity: 1;
  transition: opacity 0.25s ease;
}

/* FASE 11.1 — ver el comentario grande en js/header-menu.js sobre por
   qué se oculta mientras el footer está en pantalla (el footer trae
   su propio bloque de redes/contacto, y al ser #socialFixed
   position:fixed quedaba superpuesto arriba de esos mismos elementos).
   pointer-events:none además de opacity:0 para que, ya invisible,
   tampoco intercepte clicks sobre lo que quedó debajo. */
.social-fixed--hidden {
  opacity: 0;
  pointer-events: none;
}

.social-fixed a {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: var(--petro-galopante);
  color: var(--hueso);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.social-fixed a svg {
  width: 26px;
  height: 26px;
}

.social-fixed a:hover {
  opacity: 0.9;
  transform: scale(0.95);
}

.social-fixed__whatsapp {
  background: #25d366 !important;
}

@media (max-width: 767px) {
  .social-fixed {
    left: 0;
    right: 0;
    bottom: 0;
    flex-direction: row;
    justify-content: center;
    gap: 0;
    padding: 0.5rem;
    background: rgba(9, 18, 28, 0.85);
  }

  .social-fixed a {
    width: 44px;
    height: 44px;
    margin: 0 4px;
  }

  .social-fixed a svg {
    width: 20px;
    height: 20px;
  }
}

/* ---------------------------------------------------------------------
   Sección "SOMOS" (ver comentario grande en index.html). z-index:20 por
   el mismo motivo que las secciones placeholder de abajo: Video 2 es
   position:fixed y se queda cubriendo toda la pantalla en loop de fondo
   aunque el usuario siga scrolleando, así que esta sección (en flujo
   normal) necesita quedar por encima para taparlo visualmente.
   --------------------------------------------------------------------- */
.somos-section {
  position: relative;
  z-index: 20;
  min-height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: var(--petro-galopante);
  border-top: 1px solid rgba(241, 240, 240, 0.08);
  padding: 7rem 0;
}

.somos-section__bg-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}

.somos-section__overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  /* FASE 9.1.1 — el overlay original (0.8-0.94 de opacidad) era
     demasiado oscuro y prácticamente tapaba el video de fondo (el
     cliente: "el video que está por detras de SOMOS apenas se ve").
     Se bajó bastante la opacidad para que el collage se vea con
     claridad, dejando sólo el mínimo necesario para que el texto siga
     siendo legible (más oscuro en los bordes, donde vive el texto y el
     gráfico, más claro al centro). */
  background:
    linear-gradient(90deg, rgba(9, 18, 28, 0.55) 0%, rgba(9, 18, 28, 0.4) 45%, rgba(9, 18, 28, 0.62) 100%);
}

.somos-section__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 3rem;
  display: grid;
  grid-template-columns: minmax(220px, 380px) 1fr;
  gap: 3rem;
  align-items: center;
}

.somos-section__graphic {
  width: 100%;
  max-width: 340px;
  height: auto;
  justify-self: start;
  filter: drop-shadow(0 4px 22px rgba(9, 18, 28, 0.5));
}

.somos-section__content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.25rem;
  /* Antes 620px — quedaba mucho margen sin usar del lado derecho
     (el grid ya le da todo el espacio de 1fr, ver .somos-section__inner
     más arriba). Se lo estira bastante para aprovechar ese margen. */
  max-width: 820px;
}

.somos-section__logo {
  height: 42px;
  width: auto;
  margin-bottom: 0.5rem;
  /* Con el overlay más liviano (FASE 9.1.1) el video de fondo puede
     tener zonas claras justo detrás del isotipo — este drop-shadow
     sutil le da separación sin necesidad de oscurecer todo el fondo. */
  filter: drop-shadow(0 2px 10px rgba(9, 18, 28, 0.55));
}

.somos-section__heading {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.05em;
  /* Columna de texto más ancha (FASE 9.1.3) -> título bastante más
     grande que antes, para que siga viéndose proporcionado al resto
     del bloque. Base en Montserrat Light (300); "marcas memorables"
     va en bold — ver .somos-section__heading strong más abajo. */
  font-size: clamp(1.6rem, 2.9vw, 2.5rem);
  font-weight: 300;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--hueso);
  line-height: 1.15;
  /* El font-weight:300 (Light) ya se aplica bien (Montserrat Light SÍ
     está cargada, ver el <link> de Google Fonts), pero el cliente lo
     veía "regular" — el text-shadow grande que tenía antes (mismo que
     el párrafo, pensado para un fondo más oscuro) rellenaba los trazos
     finos de la tipografía light y la engordaba visualmente. Se achicó
     bastante (menos blur, menos opacidad) para que el peso liviano se
     note de verdad; ya alcanza para separarse del video de fondo. */
  text-shadow: 0 1px 6px rgba(9, 18, 28, 0.45);
}

.somos-section__heading strong {
  font-weight: 700;
}

.somos-section__text {
  margin: 0;
  /* Un poco más grande que antes (0.88-1rem) — el cliente lo pidió como
     ajuste de "pieza de diseño cuidada" junto con el interlineado
     parejo de acá abajo. */
  font-size: clamp(1rem, 1.1vw, 1.125rem);
  line-height: 1.75;
  color: var(--hueso);
  font-weight: 400;
  text-shadow: 0 2px 16px rgba(9, 18, 28, 0.6);
}

.somos-section__text strong {
  font-weight: 700;
}

/* ---------------------------------------------------------------------
   "Ventanas" de foto dentro del párrafo (inspirado en kochol.com/es-ES,
   referencia que pasó el cliente): pequeños recortes rectangulares
   incrustados en medio del texto corrido, con la foto paneando dentro
   de esa "máscara" — el contenedor (.somos-window) tiene
   overflow:hidden con un tamaño fijo, más chico que la imagen real,
   que sólo se mueve en el eje Y.

   FASE 9.1.3 — el pan ya NO es una animación CSS en loop propio: el
   cliente pidió que vaya acompasado con el scroll (baja al scrollear
   hacia abajo, sube al scrollear hacia arriba). Ahora lo maneja
   js/somos-section.js leyendo --pan-dist de cada ventana (sigue como
   variable CSS, así el breakpoint mobile de abajo redefine el recorrido
   sin tocar JS) y seteando transform directo según qué tan avanzado
   está el scroll de la sección — ver ese archivo para el detalle.

   FASE 9.1.5 — interlineado parejo: cada ventana es más alta que una
   línea normal del párrafo (line-height: 1.75 × font-size, ver
   .somos-section__text más arriba), así que sin corregir nada el
   line-box de esa línea puntual crecía para poder mostrarla completa
   —y eso desparejaba el interlineado del resto del párrafo, que el
   cliente notó ("el interlineado desparejo"). El margin-block negativo
   de .somos-window (más abajo) "le resta" al cálculo de layout ese
   excedente sin recortar ni achicar nada (se sigue viendo a tamaño
   completo, sólo ocupa menos lugar en el flujo del texto). Se calcula
   con 1.75em (mismo múltiplo que el line-height del párrafo) en vez de
   un valor fijo en px: como .somos-window hereda el mismo font-size
   fluido del párrafo (clamp() de acá arriba), "1.75em" siempre
   equivale exactamente al alto real de una línea a cualquier ancho de
   pantalla, sin necesitar recalcularlo a mano por breakpoint — sólo el
   alto FIJO de la ventana (46px acá, 32px en mobile) cambia en el
   media query de abajo.

   FASE 9.2.1 — vuelven a ser dos ventanas sueltas en puntos distintos
   del párrafo (no un par unido): el cliente pidió específicamente que
   la cabra quede junto a la palabra "locura" y el isotipo junto a
   "reversos" — dos anclas de texto bien separadas entre sí, así que ya
   no tiene sentido agruparlas (el problema que resolvía el .somos-
   window-pair de FASE 9.1.6, que quedaran "una bajo la otra", era
   porque ANTES las dos vivían juntas en el mismo punto del texto; acá
   ni siquiera están cerca una de la otra). El margin-block/vertical-
   align que vivía en .somos-window-pair vuelve a .somos-window, que es
   de nuevo el elemento embebido directamente en el flujo inline del
   párrafo.
   --------------------------------------------------------------------- */
.somos-window {
  display: inline-block;
  position: relative;
  overflow: hidden;
  border-radius: 6px;
  vertical-align: middle;
  margin-inline: 0.3em;
  margin-block: calc((1.75em - 46px) / 2);
  transform: translateY(-0.05em);
}

/* FASE 9.6 y 9.6.1 (abandonadas) — se había probado agrandar la foto
   dentro de la ventana (--pan-zoom, muy por encima de 100% del ancho)
   para ganar alto de sobra y paneear más, con un --pan-offset para
   saltear las zonas "muertas" (sin el rasgo reconocible) de los
   recortes fuente, que eran muy chicos (400px de ancho). El cliente
   reportó que el zoom "destrozó la forma": al agrandar tanto un
   recorte tan chico, buena parte del recorrido del pan caía en zonas
   borrosas/sin contenido reconocible de la foto.

   FASE 9.7 — el cliente mandó las fotos originales a resolución
   completa (cabra 1254×1254, cristal 1370×1148) con una instrucción
   explícita: "el ancho es el de la foto, el recorrido del scrolling es
   abarcando toda su extension de altura". Se vuelve entonces al modelo
   simple, SIN zoom ni offset: la imagen se muestra a 100% del ancho
   del contenedor (sin recorte horizontal) y el pan recorre el alto
   completo disponible (alto renderizado de la imagen a ese ancho menos
   el alto fijo de la ventana). Los nuevos archivos fuente
   (somos-window-goat-v2.jpg 620×620, somos-window-crystal-v2.jpg
   620×520 — reescalados sin recortar desde los originales del
   cliente) tienen contenido reconocible en prácticamente toda su
   altura (cabra: sombrero → cuernos → anteojos → hocico → boca →
   mentón → saco/corbata; cristal: el objeto facetado en distintos
   ángulos), así que ya no hace falta esquivar ninguna zona "muerta" —
   el pan a alto completo es a la vez más radical (mucho más recorrido
   que con el zoom, porque las fotos nuevas son mucho más altas a
   igual ancho) y coherente en todo el trayecto. --pan-dist se
   recalculó para cada ventana/breakpoint a partir del alto real que
   rendariza cada foto nueva a ese ancho, con un pequeño margen de
   seguridad para que el pan nunca llegue a mostrar un borde vacío. */
.somos-window img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: auto;
  will-change: transform;
}

.somos-window--goat {
  width: 184px;
  height: 46px;
  --pan-dist: 134px;
}

.somos-window--crystal {
  width: 184px;
  height: 46px;
  --pan-dist: 104px;
}

.somos-section__cta {
  margin-top: 0.5rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.9rem 1.75rem;
  background: var(--coral);
  color: var(--hueso);
  font-family: inherit;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.somos-section__cta:hover {
  opacity: 0.88;
  transform: translateY(-1px);
}

@media (max-width: 900px) {
  .somos-section {
    padding: 5.5rem 0;
  }

  .somos-section__inner {
    grid-template-columns: 1fr;
    text-align: center;
    gap: 2rem;
  }

  .somos-section__graphic {
    justify-self: center;
    max-width: 220px;
    margin: 0 auto;
  }

  .somos-section__content {
    align-items: center;
    max-width: 100%;
  }
}

@media (max-width: 600px) {
  .somos-section {
    padding: 4.5rem 0;
  }

  .somos-section__inner {
    padding: 0 1.5rem;
  }

  .somos-section__graphic {
    max-width: 170px;
  }

  /* Ventanas de foto (ver bloque .somos-window más arriba en este mismo
     archivo) más chicas en mobile, con --pan-dist recalculado para la
     nueva proporción (FASE 9.7: modelo simple sin zoom, foto a 100%
     del ancho del contenedor, pan a lo largo de todo el alto de sobra
     que rendariza cada foto a este ancho, con un margen de seguridad
     para que el pan nunca llegue a mostrar un borde vacío). El pan en
     sí lo sigue manejando js/somos-section.js — acá sólo se redefine
     cuánto recorrido tiene disponible a este tamaño. El margin-block
     también se redefine acá porque depende del alto FIJO de la ventana
     (32px en vez de 46px) — el "1.75em" del cálculo se sigue ajustando
     solo al font-size real en este breakpoint. */
  .somos-window {
    margin-block: calc((1.75em - 32px) / 2);
  }

  .somos-window--goat,
  .somos-window--crystal {
    width: 120px;
    height: 32px;
  }

  .somos-window--goat {
    --pan-dist: 84px;
  }

  .somos-window--crystal {
    --pan-dist: 65px;
  }
}

/* ---------------------------------------------------------------------
   FASE 17 — Sección "HACEMOS", entre el video del Galopardo
   (#como-galopamos) y la galería. Mismo motivo de z-index:20 +
   background petro-galopante + border-top que ya usan
   .marca-circle-section (arriba) y .gallery-section (abajo): Video 2
   es position:fixed y sigue cubriendo la pantalla en loop de fondo
   aunque el usuario haya scrolleado más abajo de su propio buffer —
   estas secciones, en flujo normal, necesitan ese z-index más alto
   para "taparlo" visualmente al subir por encima (ver el detalle
   completo en el comentario grande de FASE 9/FASE 11 más abajo).

   Layout: mismo criterio de 2 columnas que .somos-section__inner (más
   arriba) — gráfico angosto a la izquierda + columna de texto a la
   derecha — pero sin video de fondo, sin overlay y sin CTA (el
   cliente no pidió ninguno acá, sólo el gráfico "HACEMOS" + el texto).
   --------------------------------------------------------------------- */
.hacemos-section {
  position: relative;
  z-index: 20;
  /* El header fijo (.site-header, ~90px con el fondo ya "scrolled")
     queda por encima de todo (z-index:1000) — sin este scroll-margin,
     saltar acá desde el menú (scrollIntoView) dejaría el título pegado
     contra el header y parcialmente tapado. */
  scroll-margin-top: 90px;
  padding: 6rem 0;
  background: var(--petro-galopante);
  border-top: 1px solid rgba(241, 240, 240, 0.08);
  overflow: hidden;
}

.hacemos-section__inner {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 3rem;
  display: grid;
  grid-template-columns: minmax(220px, 380px) 1fr;
  gap: 3rem;
  align-items: center;
}

.hacemos-section__graphic {
  width: 100%;
  max-width: 340px;
  height: auto;
  justify-self: start;
}

.hacemos-section__content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.25rem;
  max-width: 820px;
}

.hacemos-section__heading {
  margin: 0;
  font-size: clamp(1.6rem, 2.9vw, 2.5rem);
  font-weight: 300;
  letter-spacing: 0.02em;
  color: var(--hueso);
  line-height: 1.15;
}

.hacemos-section__text {
  margin: 0;
  font-size: clamp(1rem, 1.1vw, 1.125rem);
  line-height: 1.75;
  color: var(--hueso);
  font-weight: 400;
}

.hacemos-section__text strong {
  font-weight: 700;
  color: var(--aquamarina);
}

/* FASE 18 — mismo patrón visual que .somos-section__cta (botón coral,
   pill, uppercase por CSS). Sin destino/acción todavía, igual que ese
   otro CTA cuando se agregó.

   FASE 25 — dos ajustes pedidos por el cliente: (1) es un <a> (desde
   la FASE 20, cuando pasó a linkear a hacemos.html), así que por
   default el navegador le pone subrayado — .somos-section__cta nunca
   lo tuvo porque es un <button>, no un link. Se agrega
   text-decoration:none acá para que se vean iguales. (2) se agrega la
   flechita "→" al final del texto en el HTML (index.html), mismo
   recurso que ya usa .somos-section__cta ("COMENZÁ TU BRIEF →") — el
   cliente pidió explícitamente "tal como el CTA comenzá tu brief". */
.hacemos-section__cta {
  margin-top: 0.5rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.9rem 1.75rem;
  background: var(--coral);
  color: var(--hueso);
  font-family: inherit;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.hacemos-section__cta:hover {
  opacity: 0.88;
  transform: translateY(-1px);
}

@media (max-width: 900px) {
  .hacemos-section__inner {
    grid-template-columns: 1fr;
    gap: 2.5rem;
    text-align: left;
  }

  .hacemos-section__graphic {
    max-width: 220px;
  }
}

@media (max-width: 520px) {
  .hacemos-section {
    padding: 4rem 0;
  }

  .hacemos-section__inner {
    padding: 0 1.5rem;
  }

  .hacemos-section__graphic {
    max-width: 170px;
  }
}

/* ---------------------------------------------------------------------
   FASE 11 — Galería (carrousel) + footer, cierre del home.
   Reemplaza las 3 secciones placeholder que había acá (LABORATORIO /
   EL REBAÑO / HABLEMOS, FASE 9) — ver el comentario grande en
   index.html sobre esa decisión. z-index:20 por el mismo motivo que
   ya explicaba el comentario de las secciones placeholder: Video 2 es
   position:fixed y se queda cubriendo toda la pantalla en loop de
   fondo aunque el usuario siga scrolleando más abajo de su propio
   buffer; con z-index:20 estas secciones (en flujo normal) "suben"
   por encima visualmente a medida que se scrollea, tapándolo sin
   necesidad de tocar su máquina de estados de visibilidad (FASE 8.2/8.3).

   FASE 11.1 — el cliente pasó una captura de referencia del footer y
   carrousel actuales de galopante.uy (producción) y pidió repetir ese
   mismo diseño acá (mismas fotos, fondo petro galopante). Ver el
   comentario grande en index.html sobre qué se pudo replicar 1:1 (el
   footer, texto exacto de la captura) y qué quedó como placeholder
   (las 6 fotos del carrousel — no están publicadas todavía en
   galopante.uy, no se pudieron traer los archivos reales).
   --------------------------------------------------------------------- */
.gallery-section {
  position: relative;
  z-index: 20;
  padding: 5rem 0;
  background: var(--petro-galopante);
  border-top: 1px solid rgba(241, 240, 240, 0.08);
  overflow: hidden;
}

/* Acordeón de "máscara" (FASE 15.1, corrige el primer intento de FASE
   15): por defecto cada tarjeta es una MÁSCARA (overflow:hidden) que
   ocupa 1/--gallery-cols del ancho visible del track (ver
   .gallery-card) — pero la <img> de adentro NO se reescala nunca: mide
   siempre 100vw fijo (el ancho que tendría a pantalla completa) y
   queda centrada con left:50% + translateX(-50%) (ver
   .gallery-card__img). Lo único que anima es el ANCHO DE LA MÁSCARA
   (.gallery-card--expanded lleva su flex-basis a ~100% del track): al
   crecer esa máscara simétricamente hacia los dos lados, la ventana
   visible se corre sobre la foto QUIETA y de tamaño fijo, revelando
   más foto a cada lado — nunca se ve un zoom/reescalado, sólo se
   "descubre" más foto. La primera versión de FASE 15 usaba
   width:100%/object-fit:cover en la propia tarjeta (que sí reescalaba
   la imagen al expandir — un efecto de zoom que el cliente pidió
   explícitamente sacar); esta versión lo reemplaza por el mecanismo de
   máscara fija descrito arriba.

   FASE 34.2 — el cliente pidió ver 6 tarjetas a la vez en vez de 3 (en
   desktop). Como --gallery-cols ya manejaba el ancho de cada máscara
   como fracción del track (ver .gallery-carousel__track) y tanto
   js/gallery-carousel.js (dots/páginas se recalculan por
   scrollWidth/clientWidth reales, sin ningún "3" fijo en el código)
   como el propio mecanismo de máscara de arriba son agnósticos a
   cuántas columnas haya, el cambio fue de una sola línea:
   --gallery-cols pasó de 3 a 6. Cada máscara ahora muestra una porción
   más angosta (centrada) de la misma foto de 100vw — verificado con
   captura local que ninguna de las 19 fotos queda irreconocible o
   demasiado "zoomeada" con el recorte más angosto. El breakpoint
   mobile (≤700px, más abajo) se dejó en 2 columnas — 6 en una pantalla
   angosta dejaría cada foto en una tira de unos px, ilegible.

   El resto de las tarjetas, con flex-shrink:0, queda empujado hacia el
   costado al expandir una (scrolleable, no desaparece). El track en sí
   sigue siendo overflow-x:auto + scroll-snap-type:x, que da swipe
   táctil nativo gratis en mobile (el cliente pidió mantenerlo así); en
   desktop además se puede arrastrar con el mouse (mousedown +
   mousemove sobre el track) — ver js/gallery-carousel.js. */
.gallery-carousel {
  position: relative;
}

.gallery-carousel__track {
  --gallery-cols: 6;
  display: flex;
  gap: 4px;
  list-style: none;
  margin: 0;
  padding: 0;
  height: clamp(320px, 38vw, 560px);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  cursor: grab;
}

.gallery-carousel__track::-webkit-scrollbar {
  display: none;
}

.gallery-carousel__track--dragging {
  cursor: grabbing;
  scroll-snap-type: none;
  scroll-behavior: auto;
}

.gallery-card {
  position: relative;
  flex: 0 0 calc((100% - (var(--gallery-cols) - 1) * 4px) / var(--gallery-cols));
  height: 100%;
  scroll-snap-align: start;
  overflow: hidden;
  transition: flex-basis 0.5s cubic-bezier(0.65, 0, 0.35, 1);
}

.gallery-card--expanded {
  flex-basis: 100%;
}

.gallery-card__trigger {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  border: none;
  padding: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  overflow: hidden;
  -webkit-user-drag: none;
}

.gallery-card__trigger:focus-visible {
  outline: 2px solid var(--aquamarina);
  outline-offset: -2px;
}

/* Máscara fija: la foto mide 100vw SIEMPRE (colapsada o expandida) y
   está centrada dentro de la tarjeta — ver el comentario grande más
   arriba. object-fit:cover acá sólo define el recorte vertical (con
   el alto del track), nunca cambia de escala horizontal porque el
   ancho es un valor fijo (100vw), no un porcentaje del contenedor. */
.gallery-card__img {
  position: absolute;
  top: 0;
  left: 50%;
  height: 100%;
  width: 100vw;
  max-width: none;
  transform: translateX(-50%);
  object-fit: cover;
  display: block;
  -webkit-user-drag: none;
  user-select: none;
}

.gallery-card__expand-icon {
  position: absolute;
  right: 10px;
  bottom: 10px;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(9, 18, 28, 0.55);
  backdrop-filter: blur(2px);
  color: var(--hueso);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.2s ease, transform 0.2s ease, background 0.2s ease;
  pointer-events: none;
}

.gallery-card__expand-icon svg {
  width: 15px;
  height: 15px;
}

.gallery-card__trigger:hover .gallery-card__expand-icon,
.gallery-card__trigger:focus-visible .gallery-card__expand-icon {
  opacity: 1;
  transform: translateY(0);
}

.gallery-card--expanded .gallery-card__expand-icon {
  background: var(--coral);
}

.gallery-carousel__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: none;
  background: rgba(9, 18, 28, 0.55);
  backdrop-filter: blur(2px);
  color: var(--hueso);
  cursor: pointer;
  transition: background 0.2s ease, opacity 0.2s ease;
}

.gallery-carousel__arrow--prev {
  left: 28px;
}

.gallery-carousel__arrow--next {
  right: 28px;
}

.gallery-carousel__arrow svg {
  width: 20px;
  height: 20px;
}

.gallery-carousel__arrow:hover {
  background: var(--coral);
}

.gallery-carousel__arrow:disabled {
  opacity: 0.35;
  cursor: default;
  background: rgba(9, 18, 28, 0.55);
}

/* Dots por "página" (ancho visible del track), no uno por foto — igual
   criterio que la referencia, donde son pocos indicadores anchos en
   vez de un dot por imagen (ver computePages() en
   js/gallery-carousel.js). El activo es una píldora más larga; el
   resto, guiones finos. */
.gallery-carousel__dots {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1.75rem;
}

.gallery-carousel__dot {
  width: 22px;
  height: 4px;
  border-radius: 999px;
  border: none;
  padding: 0;
  background: rgba(241, 240, 240, 0.25);
  cursor: pointer;
  transition: background 0.2s ease, width 0.2s ease;
}

.gallery-carousel__dot--active {
  background: var(--hueso);
  width: 34px;
}

@media (max-width: 700px) {
  .gallery-carousel__arrow {
    display: none;
  }

  .gallery-carousel__track {
    --gallery-cols: 2;
    height: 60vw;
  }
}

/* ---------------------------------------------------------------------
   Footer — 7 bloques (marca / navegación / hacemos / laboratorio /
   centro de marca / comenzá tu brief / hablemos) + barra inferior,
   replicando el layout de la captura de referencia del cliente. Ver
   el comentario grande en index.html sobre qué contenido es real vs.
   placeholder.
   --------------------------------------------------------------------- */
.site-footer {
  position: relative;
  z-index: 20;
  background: #060d15; /* un toque más oscuro que --petro-galopante para separarse visualmente de la galería */
  border-top: 1px solid rgba(241, 240, 240, 0.08);
  padding: 4.5rem 2.5rem 2rem;
}

.site-footer__top {
  display: grid;
  grid-template-columns: 1.3fr 0.85fr 0.85fr 0.85fr 0.95fr 0.95fr 1fr;
  gap: 2rem;
  max-width: 1600px;
  margin: 0 auto;
  padding-bottom: 3.5rem;
}

.site-footer__brand {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  grid-column: span 1;
}

/* FASE 16: logo oficial (antes era texto "GALOPANTE / MEDIA" armado
   con CSS — ver FASE 14/16 en el comentario del footer en index.html
   para el detalle). Mismo archivo que ya usaban la secuencia
   "BIENVENIDO A [logo]" y la sección "Somos". */
.site-footer__logo {
  display: block;
  width: 100%;
  max-width: 210px;
  height: auto;
}

.site-footer__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--coral);
}

.site-footer__divider {
  display: block;
  width: 40px;
  height: 2px;
  background: rgba(241, 240, 240, 0.25);
}

.site-footer__tagline {
  margin: 0;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.5;
  color: var(--cuarzo-ahumado);
}

.site-footer__social {
  display: flex;
  gap: 1rem;
  margin-top: 0.25rem;
}

.site-footer__social a {
  display: flex;
  color: var(--hueso);
  opacity: 0.8;
  transition: opacity 0.2s ease, color 0.2s ease;
}

.site-footer__social svg {
  width: 17px;
  height: 17px;
}

.site-footer__social a:hover {
  opacity: 1;
  color: var(--aquamarina);
}

.site-footer__col {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}

.site-footer__col-title {
  margin: 0 0 0.15rem;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--hueso);
}

.site-footer__nav-link {
  color: var(--cuarzo-ahumado);
  text-decoration: none;
  font-size: 0.88rem;
  transition: color 0.2s ease;
  width: fit-content;
}

.site-footer__nav-link:hover {
  color: var(--aquamarina);
}

.site-footer__promo {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}

.site-footer__promo-text {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--cuarzo-ahumado);
}

.site-footer__promo-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  width: fit-content;
  padding: 0.55rem 1rem;
  border: 1px solid var(--aquamarina);
  border-radius: 6px;
  color: var(--aquamarina);
  text-decoration: none;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: background 0.2s ease, color 0.2s ease;
}

.site-footer__promo-btn:hover {
  background: var(--aquamarina);
  color: var(--petro-galopante);
}

.site-footer__promo-thumb {
  width: 100%;
  max-width: 220px;
  border-radius: 8px;
  display: block;
  margin-top: 0.25rem;
}

.site-footer__col--contact {
  gap: 0.85rem;
}

.site-footer__contact-line {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--hueso);
  text-decoration: none;
  font-size: 0.88rem;
  transition: color 0.2s ease;
}

.site-footer__contact-line svg {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  color: var(--aquamarina);
}

a.site-footer__contact-line:hover {
  color: var(--aquamarina);
}

.site-footer__contact-line--static {
  cursor: default;
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  max-width: 1600px;
  margin: 0 auto;
  padding-top: 1.75rem;
  border-top: 1px solid rgba(241, 240, 240, 0.08);
}

.site-footer__copyright {
  margin: 0;
  font-size: 0.78rem;
  color: var(--cuarzo-ahumado);
}

.site-footer__legal {
  display: flex;
  gap: 1.5rem;
}

.site-footer__legal a {
  color: var(--cuarzo-ahumado);
  text-decoration: none;
  font-size: 0.78rem;
  transition: color 0.2s ease;
}

.site-footer__legal a:hover {
  color: var(--aquamarina);
}

.site-footer__signature {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: 0.78rem;
  color: var(--cuarzo-ahumado);
}

.site-footer__signature .site-footer__dot {
  position: static;
  flex: 0 0 auto;
}

@media (max-width: 1300px) {
  .site-footer__top {
    grid-template-columns: 1fr 1fr 1fr;
  }

  .site-footer__brand {
    grid-column: 1 / -1;
  }
}

@media (max-width: 900px) {
  .site-footer {
    padding: 3.5rem 1.5rem 2rem;
  }

  .site-footer__top {
    grid-template-columns: 1fr 1fr;
    gap: 2.5rem;
  }

  .site-footer__brand {
    grid-column: 1 / -1;
  }

  .site-footer__bottom {
    flex-direction: column;
    align-items: flex-start;
  }

  /* padding-bottom extra: en mobile .social-fixed (ver esa regla más
     arriba) pasa a ser una barra FIJA de ~60px pegada al borde
     inferior real de la pantalla — al final del todo de la página
     (scroll máximo), el contenido de acá abajo quedaba tapado por esa
     barra porque el padding normal no alcanzaba para despejarla.
     Mismo tipo de ajuste que ya se hizo para el CTA/mute del círculo
     de video (FASE 10.1) por el mismo motivo. */
  .site-footer {
    padding-bottom: 5.5rem;
  }
}

@media (max-width: 560px) {
  .site-footer__top {
    grid-template-columns: 1fr;
  }
}

/* ---------------------------------------------------------------------
   FASE 10 — "DIAGNOSTICAR MI MARCA": círculo que se abre a un video EN
   PANTALLA COMPLETA (FASE 10.1: el cliente pidió que el círculo no se
   quede en un tamaño chico/mediano — tiene que crecer hasta que el
   video ocupe TODA la pantalla, rectangular, con el CTA superpuesto
   arriba del video). Ver comentario grande en index.html sobre el
   reemplazo del stub "CÓMO GALOPAMOS" y ver js/marca-circle.js para
   toda la mecánica de scroll.

   Técnica — "iris wipe" con clip-path, no con width/height: el video
   (`.marca-circle__video`) SIEMPRE ocupa el 100% del alto/ancho del
   contenedor sticky (pantalla completa) — lo que crece y se achica es
   la VENTANA CIRCULAR por la que se lo ve, vía
   `clip-path: circle(var(--circle-radius) at 50% 50%)` en
   `.marca-circle`. JS interpola --circle-radius entre un radio chico
   (círculo, "cerrado") y un radio lo bastante grande como para cubrir
   toda la diagonal de la pantalla (en ese punto el clip-path ya no
   recorta nada visible — el círculo "desaparece" porque sus bordes
   quedan fuera de cualquier lado de la pantalla, y lo que se ve es el
   video ocupando el rectángulo completo, tal como pidió el cliente).
   Cerrar es exactamente lo mismo al revés. Un solo mecanismo cubre
   "círculo chico" y "video fullscreen": no hace falta animar
   width/height por separado.
   --------------------------------------------------------------------- */
.marca-circle-section {
  position: relative;
  z-index: 20;
  min-height: 130vh;
  background: var(--petro-galopante);
  border-top: 1px solid rgba(241, 240, 240, 0.08);
  overflow: hidden;
}

/* position:sticky (no GSAP pin) — el contenido queda centrado respecto
   al VIEWPORT mientras dura el recorrido de scroll de la sección
   (130vh), en vez de centrarse respecto a la caja de la sección (que,
   al ser más alta que el viewport, haría que el punto central del
   iris se corriera verticalmente a medida que se scrollea dentro de
   la meseta de apertura). Con sticky, ese punto se mantiene centrado
   en la pantalla durante todo ese recorrido, tal como si estuviera
   "pineado" — pero sin el costo/complejidad de un pin real de
   ScrollTrigger, ver comentario grande en js/marca-circle.js sobre
   por qué esta sección no usa un pin. */
.marca-circle-section__inner {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100vh;
  overflow: hidden;
}

.marca-circle {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background: #000;
  clip-path: circle(var(--circle-radius, 100px) at 50% 50%);
  -webkit-clip-path: circle(var(--circle-radius, 100px) at 50% 50%);
}

.marca-circle__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.marca-circle__mute {
  /* position:fixed (no absolute) a propósito: este botón es un hermano
     de .marca-circle dentro de .marca-circle-section__inner, que es
     position:sticky — pero un elemento sticky sólo queda con su caja
     alineada al viewport MIENTRAS está efectivamente "pegado" (top:0);
     durante la transición de entrada/salida (todavía en flujo normal,
     acercándose al punto de pegado) su caja se desplaza hacia abajo,
     y un bottom:% en position:absolute se mide contra ESA caja, no
     contra el viewport real — el botón terminaba corriéndose varias
     decenas de píxeles hacia abajo (y chocando con la barra fija de
     redes sociales en mobile) durante esa transición. position:fixed
     se mide siempre contra el viewport real, sin este problema. */
  position: fixed;
  left: 50%;
  bottom: 8%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid rgba(241, 240, 240, 0.35);
  background: rgba(9, 18, 28, 0.55);
  color: var(--hueso);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, background 0.2s ease;
  z-index: 950;
}

.marca-circle__mute--visible {
  opacity: 1;
  pointer-events: auto;
}

.marca-circle__mute:hover {
  background: rgba(9, 18, 28, 0.85);
}

.marca-circle__mute-icon {
  width: 18px;
  height: 18px;
}

.marca-circle__mute-icon--off {
  display: none;
}

/* JS agrega esta clase al botón (no al ícono) cuando el video está
   silenciado — ver updateMuteIcon() en js/marca-circle.js. */
.marca-circle__mute--is-muted .marca-circle__mute-icon--on {
  display: none;
}

.marca-circle__mute--is-muted .marca-circle__mute-icon--off {
  display: block;
}

/* CTA superpuesto arriba del video (no debajo, en flujo, como en la
   FASE 10 original) — position:fixed (mismo motivo que .marca-circle__mute
   arriba: mide contra el viewport real, no contra la caja de .inner
   durante su transición de entrada/salida como sticky). */
.marca-circle__cta {
  position: fixed;
  left: 50%;
  bottom: 16%;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.95rem 2rem;
  background: var(--coral);
  color: var(--hueso);
  font-family: inherit;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  opacity: 0;
  transform: translateX(-50%) translateY(14px);
  transition: opacity 0.3s ease, transform 0.3s ease;
  z-index: 950;
  pointer-events: none;
}

.marca-circle__cta--visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}

.marca-circle__cta:hover {
  opacity: 0.88;
}

.marca-circle__cta--visible:hover {
  opacity: 0.88;
}

@media (max-width: 900px) {
  .marca-circle__cta {
    padding: 0.85rem 1.6rem;
    font-size: 0.78rem;
    bottom: 12%;
  }

  /* bottom subido de 6% a 9%: en mobile la barra fija de redes
     sociales (.social-fixed, ver esa regla más arriba) ocupa una
     franja horizontal de ~60px pegada al borde inferior real del
     viewport — con 6% (~51px en un viewport típico de 844px) el
     botón de mute quedaba parcialmente tapado por esa barra. */
  .marca-circle__mute {
    bottom: 9%;
  }
}

/* css/hacemos-page.css */
/* =====================================================================
   FASE 20 — css/hacemos-page.css
   Estilos EXCLUSIVOS de hacemos.html (página nueva, separada del home).
   Reutiliza las variables de marca y el reset/tipografía base de
   css/main.css (que se carga ANTES que este archivo en hacemos.html),
   así que acá no se repite --petro-galopante/--coral/--aquamarina/etc,
   ni el reset de *, body, etc. Ver el comentario grande en hacemos.html
   para el contexto completo de esta fase (por qué es una página nueva
   y no una sección más del home, y qué queda como placeholder).
   ===================================================================== */

.hacemos-page {
  overflow-x: hidden;
}

.hacemos-page__container {
  width: 100%;
  max-width: 1360px;
  margin: 0 auto;
  padding: 0 3rem;
}

/* -------------------------------------------------------------------
   HEADER — FASE 21: se sacaron todas las reglas .hp-header/.hp-nav/
   .hp-menu-toggle/.hp-nav--mobile/.hp-mobile-close/.hp-nav-scrim de la
   FASE 20 (esa barra propia con nav inline). El header de esta página
   ahora es el mismo .site-header/.site-menu offcanvas del home — esas
   clases YA están definidas en css/main.css (que esta página ya
   cargaba desde la FASE 20 para las variables de marca), así que no
   hace falta agregar nada acá para el header en sí. Lo único que sigue
   siendo de esta página es el ajuste de espaciado del hero para que no
   quede tapado por el header fijo (ver .hp-hero más abajo) y, por
   supuesto, .hp-cta (se mantiene: lo sigue usando el botón "Ver todos
   los casos" del cierre, aunque ya no lo use ningún header).
   ------------------------------------------------------------------- */
.hp-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 1.4rem;
  background: var(--coral);
  color: var(--hueso);
  font-family: inherit;
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.hp-cta:hover,
.hp-cta:focus-visible {
  opacity: 0.88;
  transform: translateY(-1px);
}

/* -------------------------------------------------------------------
   HERO — el padding-top extra (contra el 5.5rem original de la FASE 20)
   es para no quedar tapado por el .site-header del home, que es
   position:fixed (ver css/main.css) y por lo tanto no empuja el resto
   del contenido — a diferencia de la barra propia de la FASE 20, que
   era sticky/normal y sí reservaba su propio espacio. En el home esto
   nunca hizo falta porque lo primero que hay debajo del header es el
   video pineado a pantalla completa (se supone que quede detrás,
   efecto buscado); acá el hero tiene texto real pegado arriba, así que
   si necesita el despeje.
   ------------------------------------------------------------------- */
.hp-hero {
  padding: 9rem 0 4rem;
}

/* -------------------------------------------------------------------
   FASE 23 — hero full-bleed: una sola foto panorámica a todo el ancho
   del contenedor, con el texto superpuesto arriba a la izquierda sobre
   un degradé oscuro y una etiqueta chica arriba a la derecha ("IDEAS /
   PERSONAS / MARCAS / RESULTADOS"). Reemplaza el grid de 2 columnas de
   la FASE 20 (texto | foto en caja redondeada) — ver el comentario
   grande en hacemos.html justo antes de esta sección para el resto del
   contexto del pedido.
   ------------------------------------------------------------------- */
/* El contenedor fija su propia altura con min-height (no con el
   aspect-ratio de la imagen) para que el texto real de adentro nunca
   se desborde ni quede recortado si en una pantalla angosta el bloque
   de texto termina siendo más alto que lo que daría una foto panorámica
   pura — la imagen, el scrim y la etiqueta van todos position:absolute
   llenando el contenedor (inset:0), y el texto real queda al frente en
   flujo normal (position:relative + padding), empujando la altura hacia
   arriba del mínimo si hiciera falta.

   FASE 25 — full-bleed de verdad: .hp-hero__media ya NO está adentro
   de .hacemos-page__container (se sacó ese wrapper en hacemos.html) —
   ahora es hijo directo de <section class="hp-hero">, que no tiene
   max-width propio, así que llega borde a borde del viewport. Por eso
   se saca el border-radius (una foto a todo el ancho de la pantalla no
   lleva esquinas redondeadas — sólo tenía sentido cuando quedaba
   inset dentro del contenedor angosto). */
.hp-hero__media {
  position: relative;
  width: 100%;
  min-height: clamp(420px, 42vw, 560px);
  overflow: hidden;
  isolation: isolate;
}

/* FASE 24 — object-position corrido hacia la derecha (en vez del
   center por defecto): con la foto real del cliente (2103×748, más
   ancha que el contenedor en desktop), el recorte de object-fit:cover
   por defecto centrado se comía el mate/estatua de cabra del lado
   derecho de la foto — el detalle de marca más lindo de la imagen. La
   franja oscura de la izquierda es donde va el texto real (tapado por
   el scrim de todos modos), así que no pasa nada si se recorta un poco
   más de ese lado para mostrar más del lado derecho. */
.hp-hero__media img {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 78% center;
  display: block;
}

/* FASE 28 — el <img> de la FASE 23/24 (foto fija) se reemplazó por un
   <video> (ver el comentario grande en hacemos.html antes de esta
   sección para el contexto completo). Mismas reglas base que el img
   de acá arriba (absolute+inset:0+cover), pero con su propio
   object-position: los 4 íconos 3D del video quedan agrupados un
   poco a la derecha del centro del cuadro (a diferencia de la foto de
   la oficina, acá no hay un detalle puntual del lado derecho que
   "salvar" — el criterio es mantener visible el racimo de íconos
   enteros en vez de la mitad izquierda, que es sólo fondo oscuro). */
.hp-hero__video {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 65% center;
  display: block;
}

/* Degradé de izquierda a derecha (no de arriba a abajo) porque el texto
   real va pegado a la izquierda — mismo criterio que el scrim de
   .site-menu__scrim en css/main.css, adaptado a horizontal acá. */
.hp-hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(
    100deg,
    rgba(9, 18, 28, 0.9) 0%,
    rgba(9, 18, 28, 0.74) 34%,
    rgba(9, 18, 28, 0.32) 58%,
    rgba(9, 18, 28, 0.06) 78%
  );
  pointer-events: none;
}

/* FASE 28 — 4 etiquetas flotantes (una por ícono del video: Estrategia/
   Branding/Growth/Contenido), posicionadas en % sobre .hp-hero__media
   calculados a mano midiendo el mockup que mandó el cliente (2092×752px
   — ver el comentario grande en hacemos.html para el detalle completo
   de cómo se midieron y sus limitaciones de precisión).

   Por qué sólo se muestran desde 1600px de ancho: el bloque de texto
   principal (.hp-hero__content) tiene max-width:600px FIJO (no en %),
   mientras que estas etiquetas están en % del ancho total — a
   cualquier ancho por debajo de ~1600px la etiqueta de Estrategia
   (la más cercana al texto, al 42.5%) termina invadiendo el bloque de
   texto principal. En vez de intentar una fórmula de posicionamito
   más compleja que se adapte en cada ancho (imposible de calibrar bien
   sin re-renderizar el video con el texto quemado adentro — ver
   advertencia en hacemos.html), se opta por un corte simple: estas 4
   etiquetas son un "extra" que aparece sólo en monitores grandes
   (≥1600px), y se ocultan en cualquier laptop/tablet común. El hero
   sigue funcionando perfectamente sin ellas (video + heading + párrafo
   + CTA), así que no es una pérdida grave.

   FASE 29 — corrección: antes esto dependía de video.currentTime (sólo
   se mostraban durante el tramo "asentado" del loop). El cliente pidió
   que dejen de depender del video: ahora animan una sola vez al cargar
   la página (js/hacemos-hero-video.js agrega .is-visible una sola vez,
   con un pequeño delay, y nunca la saca) y quedan fijas para siempre.
   Cada etiqueta tiene su propio transition-delay para que entren de a
   una (efecto escalonado) en vez de las 4 juntas. */
.hp-hero__orbit-labels {
  display: none;
}

@media (min-width: 1600px) {
  .hp-hero__orbit-labels {
    display: block;
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
  }
}

.hp-hero__orbit-label {
  position: absolute;
  max-width: 230px;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.hp-hero__orbit-labels.is-visible .hp-hero__orbit-label {
  opacity: 1;
  transform: translateY(0);
}

.hp-hero__orbit-labels.is-visible .hp-hero__orbit-label--estrategia {
  transition-delay: 0.1s;
}

.hp-hero__orbit-labels.is-visible .hp-hero__orbit-label--branding {
  transition-delay: 0.3s;
}

.hp-hero__orbit-labels.is-visible .hp-hero__orbit-label--growth {
  transition-delay: 0.5s;
}

.hp-hero__orbit-labels.is-visible .hp-hero__orbit-label--contenido {
  transition-delay: 0.7s;
}

.hp-hero__orbit-heading {
  margin: 0 0 0.45rem;
  padding-bottom: 0.5rem;
  border-bottom: 2px solid var(--coral);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--hueso);
}

.hp-hero__orbit-text {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.5;
  color: rgba(241, 240, 240, 0.8);
}

.hp-hero__orbit-label--estrategia {
  left: 42.5%;
  top: 12%;
}

.hp-hero__orbit-label--branding {
  left: 78.5%;
  top: 18.5%;
}

.hp-hero__orbit-label--growth {
  left: 34.5%;
  top: 66%;
}

.hp-hero__orbit-label--contenido {
  left: 78.5%;
  top: 66%;
}

/* FASE 24 — .hp-hero__corner-tag (el label "Ideas/Personas/Marcas/
   Resultados" con el subrayado coral que arma la FASE 23 acá abajo, en
   CSS) SE SACÓ de hacemos.html: la foto real que mandó el cliente para
   este hero ya trae ese mismo texto impreso arriba a la derecha (es
   parte de la decoración de la oficina en la foto, no un gráfico
   agregado). Se deja la regla comentada en vez de borrarla — si en
   algún momento cambian la foto por otra que NO lo traiga incluido,
   alcanza con descomentarla y volver a poner el <p class="hp-hero__
   corner-tag"> en el HTML (ver el historial de la FASE 23 en NOTES.md
   para el markup exacto).
.hp-hero__corner-tag {
  position: absolute;
  z-index: 1;
  top: clamp(1.25rem, 3vw, 2.25rem);
  right: clamp(1.25rem, 3vw, 2.5rem);
  display: inline-block;
  margin: 0;
  padding-bottom: 0.55rem;
  border-bottom: 2px solid var(--coral);
  font-size: clamp(0.6rem, 0.85vw, 0.7rem);
  font-weight: 700;
  letter-spacing: 0.1em;
  line-height: 1.6;
  text-align: right;
  text-transform: uppercase;
  color: rgba(241, 240, 240, 0.78);
}
*/

/* FASE 25: se había puesto un padding-left en clamp(...,3rem) pensando
   que "mismo tope que .hacemos-page__container" alcanzaba para quedar
   alineados. No alcanza: .hacemos-page__container tiene max-width:1360px
   y se centra con margin:0 auto, así que a partir de 1360px de ancho su
   contenido ya no arranca a 3rem del borde del viewport sino a 3rem +
   el margen de centrado — y ese margen crece con la pantalla. Un clamp
   con tope fijo no puede seguir ese crecimiento, así que en pantallas
   anchas el heading del hero quedaba visiblemente más a la izquierda
   que el heading de "Estrategia" más abajo (mismo bug, más notorio
   cuanto más ancha la pantalla).

   FASE 26 — fix: en vez de padding-left fijo, se usa margin-left con la
   MISMA fórmula que produce el centrado de .hacemos-page__container
   (max(3rem, (100% - 1360px)/2 + 3rem) — el 100% acá es el ancho de
   .hp-hero__media, que al ser full-bleed equivale al viewport). Por
   debajo de 1360px de ancho la resta da negativo y gana el piso de
   3rem (mismo resultado de antes); por encima, crece exactamente al
   mismo ritmo que el contenedor. El cliente pidió esto explícitamente
   ("que esté alineado al texto de Estrategia") y aceptó que en
   pantallas anchas el texto pase a quedar por encima de la foto en vez
   de pegado al borde izquierdo — ver el comentario grande en
   hacemos.html antes de esta sección. El padding vertical y el
   max-width del bloque de texto (600px, para que no se estire) se
   mantienen igual que en la FASE 25. */
.hp-hero__content {
  position: relative;
  z-index: 1;
  max-width: 600px;
  margin-left: max(3rem, calc((100% - 1360px) / 2 + 3rem));
  padding: clamp(2.5rem, 7vw, 4.75rem) 1.5rem clamp(2.5rem, 7vw, 4.75rem) 0;
}

.hp-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(241, 240, 240, 0.65);
  margin: 0 0 1.5rem;
}

.hp-eyebrow::before {
  content: '';
  display: inline-block;
  width: 28px;
  height: 2px;
  background: var(--coral);
}

.hp-hero__heading {
  margin: 0 0 1.25rem;
  font-size: clamp(2.4rem, 4.2vw, 3.6rem);
  font-weight: 800;
  line-height: 1.08;
  color: var(--hueso);
}

.hp-hero__heading em {
  font-style: italic;
  color: var(--aquamarina);
  font-weight: 700;
}

.hp-hero__text {
  margin: 0 0 2.25rem;
  font-size: 1.05rem;
  line-height: 1.7;
  color: rgba(241, 240, 240, 0.72);
  max-width: 460px;
}

/* FASE 28 — .hp-explore (el link "Explorá nuestras capacidades ↓" de
   la FASE 20/23) se reemplazó por .hp-hero__cta ("CONOCÉ CÓMO →", ver
   más abajo), tomado del mockup que mandó el cliente para el nuevo
   hero con video. Se deja la regla comentada, no borrada, por si
   hiciera falta un link con flecha hacia abajo en otro lado más
   adelante.
.hp-explore {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  background: none;
  border: none;
  color: var(--hueso);
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
}

.hp-explore__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid rgba(241, 240, 240, 0.35);
  flex-shrink: 0;
  transition: transform 0.2s ease, border-color 0.2s ease;
}

.hp-explore:hover .hp-explore__icon,
.hp-explore:focus-visible .hp-explore__icon {
  transform: translateY(3px);
  border-color: var(--aquamarina);
}
*/

/* FASE 28 — mismo patrón de píldora con borde que
   .site-menu__clients-link (FASE 22, css/main.css), pero en coral en
   vez de aquamarina — así lo trae el mockup del cliente. */
.hp-hero__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.85em 1.6em;
  border: 1px solid var(--coral);
  border-radius: 999px;
  font-family: inherit;
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--hueso);
  text-decoration: none;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.hp-hero__cta:hover,
.hp-hero__cta:focus-visible {
  background-color: var(--coral);
  color: var(--petro-galopante);
}

.hp-hero__cta-icon {
  transition: transform 0.2s ease;
}

.hp-hero__cta:hover .hp-hero__cta-icon,
.hp-hero__cta:focus-visible .hp-hero__cta-icon {
  transform: translateX(3px);
}

/* FASE 28 — etiqueta "Good brands / go further" del mockup, debajo del
   CTA. Mismo patrón visual que .hp-eyebrow (rayita coral + texto chico
   mayúscula), pero acá va después del CTA en vez de antes del heading. */
.hp-hero__tagline {
  display: block;
  width: fit-content;
  margin: 2rem 0 0;
  padding-top: 0.9rem;
  border-top: 2px solid var(--coral);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.6;
  color: rgba(241, 240, 240, 0.65);
}

/* -------------------------------------------------------------------
   BLOQUES DE CAPACIDAD (Estrategia / Branding / Contenido / Growth)
   ------------------------------------------------------------------- */
.hp-capability {
  padding: 4.5rem 0;
  border-top: 1px solid rgba(241, 240, 240, 0.08);
  scroll-margin-top: 90px;
}

/* FASE 27 — el bloque de capacidad pasó de un grid de 3 columnas
   (texto | lista | foto chica) a una sola foto panorámica de ancho
   completo con TODO el texto (num/heading/subheading/párrafo/lista)
   superpuesto arriba, igual que el hero (ver .hp-hero__media más
   arriba en este archivo — es el mismo patrón: img + scrim en
   position:absolute llenando el contenedor, contenido real en
   position:relative encima). El pedido del cliente fue explícito: las
   4 fotos que mandó ya venían con un degradado propio pensado
   justamente para que el texto se escriba encima, no para recortarlas
   en un cuadrado chico al costado (eso fue lo que se hizo primero, en
   la FASE 26, y el cliente pidió corregirlo). A diferencia del hero,
   esto NO es full-bleed — se queda adentro de .hacemos-page__container
   (mismo ancho que el resto de la página) porque acá no hubo pedido de
   ocupar todo el viewport, sólo de que el texto quede sobre la foto en
   vez de al costado. */
.hp-capability__media {
  position: relative;
  width: 100%;
  min-height: clamp(480px, 42vw, 640px);
  overflow: hidden;
  isolation: isolate;
  border-radius: 8px;
}

.hp-capability__media img {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* object-position por bloque: cada foto tiene su contenido
   concentrado en una franja distinta del lado derecho (el resto es la
   franja oscura del degradado, pensada para que quede tapada por el
   scrim de acá abajo de todos modos) — mismo criterio que
   .hp-hero__media img más arriba. */
#estrategia .hp-capability__media img {
  object-position: 68% center;
}

#branding .hp-capability__media img {
  object-position: 66% center;
}

#contenido .hp-capability__media img {
  object-position: 62% center;
}

#growth .hp-capability__media img {
  object-position: 80% center;
}

.hp-capability__scrim {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(
    100deg,
    rgba(9, 18, 28, 0.93) 0%,
    rgba(9, 18, 28, 0.8) 32%,
    rgba(9, 18, 28, 0.4) 56%,
    rgba(9, 18, 28, 0.08) 76%
  );
  pointer-events: none;
}

.hp-capability__content {
  position: relative;
  z-index: 1;
  max-width: 520px;
  padding: clamp(2rem, 5vw, 3.5rem);
}

.hp-capability__num {
  display: block;
  font-size: 1.1rem;
  font-weight: 800;
  color: var(--coral);
  letter-spacing: 0.04em;
  margin-bottom: 0.5rem;
}

.hp-capability__heading {
  margin: 0 0 0.9rem;
  font-size: clamp(1.9rem, 3.2vw, 2.6rem);
  font-weight: 800;
  letter-spacing: 0.01em;
  color: var(--aquamarina);
}

.hp-capability__subheading {
  margin: 0 0 1rem;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--hueso);
}

/* FASE 25 — .hp-accent (coral) se sacó del "más" en la bajada de
   Growth ("Hacemos que llegue más lejos.") — el cliente pidió que esa
   palabra tenga el mismo tono blanco que el resto de la frase, sin
   acento de color. La regla queda comentada, no borrada, por si se
   usa en otra bajada más adelante — con el <span class="hp-accent">
   sacado del HTML, ahora mismo no se aplica en ningún lado.
.hp-capability__subheading .hp-accent {
  color: var(--coral);
}
*/

.hp-capability__text {
  margin: 0;
  font-size: 0.98rem;
  line-height: 1.7;
  color: rgba(241, 240, 240, 0.85);
  max-width: 460px;
}

/* FASE 27 — margin-top subido de 0.35rem a 1.25rem: en el layout viejo
   la lista vivía en su propia columna del grid, al lado del texto, así
   que casi no necesitaba separación propia. Ahora que va apilada
   debajo del párrafo (ambos adentro de .hp-capability__content, sobre
   la foto), hace falta más aire para que no se lean pegados. */
.hp-capability__list {
  list-style: none;
  margin: 1.25rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.hp-capability__list li {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  font-size: 0.92rem;
  color: rgba(241, 240, 240, 0.92);
}

.hp-capability__list li::before {
  content: '\2192';
  color: var(--aquamarina);
  font-size: 0.85rem;
  flex-shrink: 0;
}

/* Casos de cada capacidad */
.hp-cases {
  margin-top: 2.75rem;
}

.hp-cases__label {
  display: block;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(241, 240, 240, 0.5);
  margin: 0 0 1rem;
}

.hp-cases__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}

.hp-case-card {
  display: flex;
  align-items: stretch;
  gap: 1rem;
  background: rgba(241, 240, 240, 0.03);
  border: 1px solid rgba(241, 240, 240, 0.08);
  border-radius: 6px;
  overflow: hidden;
  text-decoration: none;
  transition: border-color 0.2s ease, background 0.2s ease;
}

.hp-case-card:hover,
.hp-case-card:focus-visible {
  border-color: rgba(179, 236, 230, 0.4);
  background: rgba(241, 240, 240, 0.06);
}

.hp-case-card__img {
  width: 38%;
  min-width: 110px;
  height: auto;
  object-fit: cover;
  flex-shrink: 0;
}

.hp-case-card__body {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.9rem 1.1rem 0.9rem 0;
}

.hp-case-card__text {
  min-width: 0;
}

.hp-case-card__title {
  margin: 0 0 0.2rem;
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--hueso);
}

.hp-case-card__desc {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.4;
  color: rgba(241, 240, 240, 0.6);
}

.hp-case-card__arrow {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid rgba(241, 240, 240, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--hueso);
  font-size: 0.9rem;
}

/* -------------------------------------------------------------------
   CIERRE — "las capacidades se combinan" + CTA, con fondo de montañas
   hecho en CSS puro (clip-path), no es una foto: evita depender de un
   asset real todavía y da la misma sensación de fondo con textura de
   paisaje que tiene la referencia.
   ------------------------------------------------------------------- */
.hp-closing {
  position: relative;
  padding: 6rem 0 4.5rem;
  border-top: 1px solid rgba(241, 240, 240, 0.08);
  overflow: hidden;
}

.hp-closing__mountains {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 55%;
  pointer-events: none;
  z-index: 0;
}

.hp-closing__mountains span {
  position: absolute;
  bottom: 0;
  display: block;
}

.hp-closing__mountains .m1 {
  left: -5%;
  width: 60%;
  height: 100%;
  background: rgba(179, 236, 230, 0.05);
  clip-path: polygon(0% 100%, 15% 35%, 34% 68%, 52% 18%, 74% 55%, 100% 100%);
}

.hp-closing__mountains .m2 {
  right: -8%;
  width: 65%;
  height: 85%;
  background: rgba(241, 240, 240, 0.04);
  clip-path: polygon(0% 100%, 20% 40%, 40% 75%, 58% 22%, 80% 60%, 100% 100%);
}

.hp-closing__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 3rem;
  align-items: center;
}

.hp-closing__heading {
  margin: 0;
  font-size: clamp(2rem, 3.6vw, 2.9rem);
  font-weight: 800;
  color: var(--hueso);
  line-height: 1.15;
}

.hp-closing__heading em {
  font-style: normal;
  color: var(--aquamarina);
}

.hp-closing__right {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  align-items: flex-start;
}

.hp-closing__text {
  margin: 0;
  font-size: 1rem;
  line-height: 1.7;
  color: rgba(241, 240, 240, 0.75);
}

/* FASE 21 — se sacó .hp-minifooter (barra final angosta de la FASE 20):
   el cierre ahora usa el <footer class="site-footer"> grande del home,
   cuyo estilo ya vive entero en css/main.css (nada que agregar acá). */

/* -------------------------------------------------------------------
   RESPONSIVE
   ------------------------------------------------------------------- */
@media (max-width: 980px) {
  /* .hp-hero__content y .hp-hero__text mantienen su max-width (definido
     más arriba) incluso acá: a diferencia del viejo layout de 2
     columnas de la FASE 20 (donde el ancho lo daba el grid y hacía
     falta soltarlo en tablet), ahora el texto va superpuesto sobre la
     foto — si se suelta el max-width, el párrafo se estira hasta pisar
     la etiqueta "IDEAS/PERSONAS/MARCAS/RESULTADOS" y el ícono de la
     imagen placeholder del lado derecho. */

  /* FASE 27 — .hp-capability__top (grid de 3 columnas) y los overrides
     de .hp-capability__media/img que había acá quedaron obsoletos: ese
     grid se sacó (ver el comentario grande junto a .hp-capability__media
     más arriba). .hp-capability__content mantiene su max-width por el
     mismo motivo que .hp-hero__content lo mantiene (comentario un poco
     más arriba en este mismo media query) — el texto va superpuesto
     sobre la foto, así que soltar el ancho lo estira hasta pisar el
     lado visible de la imagen. */
  .hp-capability__media {
    min-height: clamp(520px, 58vw, 680px);
  }

  .hp-cases__grid {
    grid-template-columns: 1fr;
  }

  .hp-closing__inner {
    grid-template-columns: 1fr;
    text-align: left;
  }

  .hp-closing__right {
    align-items: flex-start;
  }
}

@media (max-width: 600px) {
  .hacemos-page__container {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
  }

  .hp-hero {
    padding: 7rem 0 3rem;
  }

  .hp-hero__media {
    min-height: 0;
  }

  /* Abajo de 600px el degradé pasa a cubrir toda la foto de forma
     pareja en vez de sólo la izquierda, ya que el texto real ahora
     ocupa prácticamente todo el ancho angosto. (La regla que ocultaba
     .hp-hero__corner-tag acá se sacó en la FASE 24 junto con el resto
     de esa clase — ver el comentario grande más arriba, la etiqueta
     "Ideas/Personas/Marcas/Resultados" ahora viene impresa en la foto
     real, no es un elemento de CSS que haya que esconder en mobile.) */
  .hp-hero__scrim {
    background: linear-gradient(
      180deg,
      rgba(9, 18, 28, 0.55) 0%,
      rgba(9, 18, 28, 0.86) 55%,
      rgba(9, 18, 28, 0.94) 100%
    );
  }

  /* FASE 26 — bajo 600px, .hacemos-page__container pasa a padding
     1.5rem fijo (ver arriba en este mismo media query), así que acá se
     vuelve a un margin-left:0 + padding-left:1.5rem en vez de la
     fórmula de centrado de la versión desktop (que a este ancho ya no
     aplica: no hay margen de centrado que igualar, container y
     viewport miden lo mismo). */
  .hp-hero__content {
    margin-left: 0;
    padding: 2.25rem 1.5rem 2rem;
  }

  .hp-capability {
    padding: 3.25rem 0;
  }

  /* FASE 27 — mismo criterio que .hp-hero__scrim/.hp-hero__content acá
     arriba: bajo 600px el degradado pasa a vertical (pareja en toda la
     foto) porque el contenido ya ocupa prácticamente todo el ancho
     angosto, y el bloque de texto suelta el margin-left de centrado
     (no aplica a este ancho). */
  .hp-capability__media {
    min-height: 0;
  }

  .hp-capability__scrim {
    background: linear-gradient(
      180deg,
      rgba(9, 18, 28, 0.6) 0%,
      rgba(9, 18, 28, 0.88) 45%,
      rgba(9, 18, 28, 0.95) 100%
    );
  }

  .hp-capability__content {
    max-width: none;
    padding: 1.75rem 1.25rem 1.5rem;
  }

  .hp-case-card {
    flex-direction: column;
  }

  .hp-case-card__img {
    width: 100%;
    height: 140px;
  }

  .hp-case-card__body {
    padding: 0.9rem 1.1rem;
  }
}

/* css/hacemos-biraden.css */
.biraden-preview{position:relative;width:38%;min-width:110px;flex-shrink:0;overflow:hidden;min-height:160px;background:#09121c}.biraden-preview video,.biraden-preview img{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:cover;object-position:60% center}.biraden-preview [hidden]{display:none!important}@media(max-width:600px){.biraden-preview{width:100%;height:140px;min-height:140px}}

/* css/hacemos-cortina.css */
/* Cortinas sucesivas: hero → Estrategia → Branding → Contenido → Growth. */
html.hacemos-document,
body.hacemos-page {
  overflow-x: clip;
}
.hp-curtain-sequence {
  position: relative;
  isolation: isolate;
}
.hp-curtain-sequence > .hp-hero,
.hp-curtain-sequence > .hp-capability:not(#growth) {
  position: sticky;
  top: var(--hp-curtain-top, 0px);
}
.hp-curtain-sequence > .hp-hero { z-index: 1; }
.hp-curtain-sequence > .hp-capability {
  background: var(--petro-galopante, #09121C);
}
.hp-curtain-sequence > #estrategia { z-index: 2; }
.hp-curtain-sequence > #branding { z-index: 3; }
.hp-curtain-sequence > #contenido { z-index: 4; }
.hp-curtain-sequence > #growth { position: relative; z-index: 5; }
@media (prefers-reduced-motion: reduce) {
  .hp-curtain-sequence > .hp-hero,
  .hp-curtain-sequence > .hp-capability:not(#growth) {
    position: relative;
    top: auto;
  }
}

/* css/hacemos-hueso.css */
/* Variante hueso, aplicada únicamente a Estrategia y Contenido. */
.hacemos-page .hp-capability--bone {
  --capability-bone: #F1F0F0;
  --capability-petro: #09121C;
  --capability-coral: #EB455D;
  background: var(--capability-bone);
  color: var(--capability-petro);
  border-top-color: rgba(9,18,28,.10);
}
.hp-capability--bone .hp-capability__media { background: var(--capability-bone); }
.hp-capability--bone .hp-capability__scrim {
  background:
    linear-gradient(0deg, #F1F0F0 0%, rgba(241,240,240,0) 22%),
    linear-gradient(90deg, #F1F0F0 0%, #F1F0F0 28%, rgba(241,240,240,.95) 36%, rgba(241,240,240,.65) 46%, rgba(241,240,240,.12) 62%, rgba(241,240,240,0) 76%);
}
.hp-capability--bone .hp-capability__heading,
.hp-capability--bone .hp-capability__subheading,
.hp-capability--bone .hp-capability__text,
.hp-capability--bone .hp-capability__list li,
.hp-capability--bone .hp-cases__label,
.hp-capability--bone .hp-case-card__title,
.hp-capability--bone .hp-case-card__desc { color: var(--capability-petro); }
.hp-capability--bone .hp-capability__num,
.hp-capability--bone .hp-capability__list li::before { color: var(--capability-coral); }
.hp-capability--bone .hp-case-card {
  background: transparent;
  border-color: rgba(9,18,28,.16);
}
.hp-capability--bone .hp-case-card:hover,
.hp-capability--bone .hp-case-card:focus-visible {
  background: rgba(255,255,255,.35);
  border-color: var(--capability-coral);
}
.hp-capability--bone .hp-case-card:focus-visible {
  outline: 2px solid var(--capability-coral);
  outline-offset: 4px;
}
.hp-capability--bone .hp-case-card__arrow {
  color: var(--capability-coral);
  border-color: var(--capability-coral);
}
.hp-capability--bone .hp-case-card__img[src$="case-thumb.jpg"] {
  filter: grayscale(1);
  opacity: .58;
}
/* La misma ventana de foto para los cuatro bloques. El JS ajusta la altura
   conjunta si el texto necesita más espacio en pantallas pequeñas. */
.hacemos-page .hp-capability__media {
  height: var(--hp-media-height, 640px);
  min-height: 640px;
}
@media (max-width: 980px) {
  .hp-capability--bone .hp-capability__scrim {
    background: linear-gradient(90deg, rgba(241,240,240,.98) 0%, rgba(241,240,240,.94) 48%, rgba(241,240,240,.80) 100%);
  }
}
@media (max-width: 600px) {
  .hp-capability--bone .hp-capability__scrim {
    background: linear-gradient(180deg, rgba(241,240,240,.93), rgba(241,240,240,.98));
  }
}

/* css/hacemos-cierre.css */
/* Banner editorial con Galopardo: fotografía sin letras y texto HTML nítido. */
.hp-closing.hp-closing--bone {
  background: #F1F0F0;
  color: #09121C;
  border-top-color: rgba(9,18,28,.10);
  min-height: 320px;
  padding: 3rem 0;
  display: flex;
  align-items: center;
  isolation: isolate;
}
.hp-closing--bone::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: min(100%, 1140px);
  z-index: -1;
  pointer-events: none;
  background: url('../assets/images/hacemos-page/cierre-continuo.webp?v=46') right center / cover no-repeat;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.01) 8%, rgba(0,0,0,.06) 18%, rgba(0,0,0,.18) 28%, rgba(0,0,0,.40) 38%, rgba(0,0,0,.69) 48%, rgba(0,0,0,.90) 58%, #000 70%);
  mask-image: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.01) 8%, rgba(0,0,0,.06) 18%, rgba(0,0,0,.18) 28%, rgba(0,0,0,.40) 38%, rgba(0,0,0,.69) 48%, rgba(0,0,0,.90) 58%, #000 70%);
}
.hp-closing--bone .hp-closing__inner { display: block; }
.hp-closing--bone .hp-closing__copy { width: 62%; max-width: 760px; }
.hp-closing--bone .hp-closing__invitation {
  color: #09121C;
  font-family: Montserrat, Arial, sans-serif;
  font-size: clamp(1rem, 1.5vw, 1.4rem);
  font-weight: 400;
  line-height: 1.5;
  margin: 0 0 .4rem;
}
.hp-closing--bone .hp-closing__heading {
  color: #09121C;
  font-size: clamp(2rem, 3.2vw, 3.2rem);
  margin: 0 0 1.3rem;
  text-wrap: balance;
}
.hp-closing--bone .hp-cta { background: #EB455D; color: #FFFFFF; }
.hp-closing--bone .hp-cta:hover,
.hp-closing--bone .hp-cta:focus-visible { background: #D83D54; color: #FFFFFF; }
.hp-closing--bone .hp-cta:focus-visible { outline: 2px solid #09121C; outline-offset: 4px; }
@media (max-width: 760px) {
  .hp-closing.hp-closing--bone { min-height: 560px; align-items: flex-start; padding: 2.5rem 0 300px; }
  .hp-closing--bone::before {
    top: auto;
    bottom: 0;
    width: 100%;
    height: 290px;
    background-size: cover;
    background-position: right center;
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, rgba(0,0,0,.01) 7%, rgba(0,0,0,.06) 16%, rgba(0,0,0,.20) 27%, rgba(0,0,0,.48) 39%, rgba(0,0,0,.78) 52%, #000 70%);
    mask-image: linear-gradient(180deg, transparent 0%, rgba(0,0,0,.01) 7%, rgba(0,0,0,.06) 16%, rgba(0,0,0,.20) 27%, rgba(0,0,0,.48) 39%, rgba(0,0,0,.78) 52%, #000 70%);
  }
  .hp-closing--bone .hp-closing__copy { width: 100%; max-width: 520px; }
}

/* css/footer-ajuste.css */
@media(min-width:1301px){.site-footer__top{grid-template-columns:1.3fr .85fr .95fr 1fr 1fr 1.1fr}}

.feedback-footer-link{margin-top:18px;align-self:flex-start}

/* css/hacemos-videos.css */
/* Los clips ya incluyen el degradado y el encuadre final del bloque. */
.hacemos-page .hp-capability__media--video .hp-capability__poster,
.hacemos-page .hp-capability__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
  pointer-events: none;
  z-index: 0;
}
.hacemos-page .hp-capability__video { opacity: 0; }
#estrategia .hp-capability__media--video img.hp-capability__poster,
#branding .hp-capability__media--video img.hp-capability__poster,
#contenido .hp-capability__media--video img.hp-capability__poster,
#growth .hp-capability__media--video img.hp-capability__poster {
  object-position: center;
}
.hacemos-page .hp-capability__media--video.is-video-ready > .hp-capability__video {
  opacity: 1;
}
@media (min-width: 981px) {
  .hacemos-page .hp-capability__media--video > .hp-capability__scrim {
    background: none;
  }
}
/* En celular conservamos el velo adicional que permite leer el texto. */
@media (prefers-reduced-motion: reduce) {
  .hacemos-page .hp-capability__video { display: none; }
}

/* css/hacemos-mobile.css */
/* 58: ventana visual independiente; el texto nunca cubre la animación. */
@media (max-width: 980px) {
  .hacemos-page .hp-capability { padding: 2rem 0; }
  .hacemos-page .hp-capability__media--video {
    --hp-mobile-bg: #09121C;
    --hp-mobile-visual-height: clamp(260px, 78vw, 420px);
    height: auto;
    min-height: 0;
    background: var(--petro-galopante, #09121C);
    border-radius: 0;
  }
  .hacemos-page .hp-capability--bone .hp-capability__media--video {
    --hp-mobile-bg: #F1F0F0;
    background: var(--hp-mobile-bg);
  }
  .hacemos-page .hp-capability__media--video .hp-capability__poster,
  .hacemos-page .hp-capability__media--video > .hp-capability__video {
    inset: 0 0 auto;
    height: var(--hp-mobile-visual-height);
    object-fit: cover;
    object-position: right center;
  }
  #estrategia .hp-capability__media--video img.hp-capability__poster,
  #branding .hp-capability__media--video img.hp-capability__poster,
  #contenido .hp-capability__media--video img.hp-capability__poster,
  #growth .hp-capability__media--video img.hp-capability__poster {
    object-position: right center;
  }
  .hacemos-page .hp-capability__media--video > .hp-capability__scrim {
    display: block;
    inset: 0 0 auto;
    height: var(--hp-mobile-visual-height);
    z-index: 1;
    background:
      linear-gradient(to top, var(--hp-mobile-bg) 0%, var(--hp-mobile-bg) 6%, transparent 34%),
      linear-gradient(to right, var(--hp-mobile-bg) 0%, transparent 16%);
  }
  .hacemos-page .hp-capability__media--video > .hp-capability__content {
    max-width: none;
    padding: calc(var(--hp-mobile-visual-height) + 16px) 0 8px;
  }
  .hacemos-page .hp-capability__heading { margin-bottom: .65rem; }
  .hacemos-page .hp-capability__subheading { margin-bottom: .75rem; }
  .hacemos-page .hp-capability__text { max-width: 65ch; }
  .hacemos-page .hp-capability__list { gap: .55rem; }
  .hacemos-page .hp-cases { margin-top: 1.5rem; }
}


@media (max-width: 980px) {
 .hp-closing--bone:not(.is-near)::before { background-image: none; }
}

/* La G original se usa como máscara: sin otra imagen ni video animado. */
.hp-media-loader {
  --load-progress: 0%;
  position: absolute;
  z-index: 3;
  top: 50%;
  right: 24px;
  transform: translateY(-50%);
  width: 96px;
  padding: 18px 14px 12px;
  box-sizing: border-box;
  border: 1px solid rgba(241,240,240,.16);
  border-radius: 16px;
  background: rgba(9,18,28,.88);
  color: #F1F0F0;
  box-shadow: 0 8px 28px rgba(0,0,0,.12);
  pointer-events: none;
  text-align: center;
  animation: hp-loader-appear .22s .18s both;
}
.hp-media-loader[hidden] { display: none !important; }
.hp-capability--bone .hp-media-loader {
  background: rgba(241,240,240,.94);
  border-color: rgba(9,18,28,.12);
  color: #09121C;
}
.hp-media-loader__mark {
  position: relative;
  display: block;
  width: 64px;
  height: 57px;
  overflow: hidden;
  background: rgba(241,240,240,.20);
  -webkit-mask: url('../assets/images/isotipo-galopante.png') center / contain no-repeat;
  mask: url('../assets/images/isotipo-galopante.png') center / contain no-repeat;
}
.hp-capability--bone .hp-media-loader__mark { background-color: rgba(9,18,28,.14); }
.hp-media-loader__fill {
  position: absolute;
  inset: 0;
  display: block;
  background: #EB455D;
  clip-path: inset(calc(100% - var(--load-progress)) 0 0 0);
  transition: clip-path .25s ease-out;
}
.hp-media-loader__fill::after {
  content: '';
  position: absolute;
  bottom: max(0px, calc(var(--load-progress) - 2px));
  inset-inline: 0;
  height: 2px;
  background: #B7E4DF;
  transition: bottom .25s ease-out;
}
.hp-media-loader__label {
  display: block;
  margin-top: 10px;
  font-family: Montserrat, Arial, sans-serif;
  font-size: 10px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: .04em;
}
.hp-media-loader.is-complete { animation: none; opacity: 0; transition: opacity .2s; }
@keyframes hp-loader-appear { from { opacity: 0; } to { opacity: 1; } }
@media (max-width: 980px) {
  .hp-capability__media--video > .hp-media-loader {
    top: calc(var(--hp-mobile-visual-height) / 2);
    right: 50%;
    transform: translate(50%, -50%);
  }
  .hp-hero__media > .hp-media-loader {
    top: auto;
    bottom: 18px;
    right: 18px;
    transform: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .hp-media-loader { display: none !important; animation: none; }
  .hp-media-loader__fill, .hp-media-loader__fill::after { transition: none; }
}


/* Agua dentro de la máscara original; no representa un porcentaje de descarga. */
.hp-media-loader__water {
  position: absolute;
  inset: 0;
  animation: hp-water-level 2.2s ease-in-out infinite;
}
.hp-media-loader__water::after {
  content: '';
  position: absolute;
  top: 11px;
  bottom: -60px;
  left: 0;
  right: 0;
  background: #EB455D;
}
.hp-media-loader__wave {
  position: absolute;
  top: 0;
  left: 0;
  width: 128px;
  height: 12px;
  fill: #EB455D;
  animation: hp-water-wave 1.3s linear infinite;
}
.hp-media-loader__wave--back {
  top: -3px;
  fill: #B7E4DF;
  opacity: .65;
  animation: hp-water-wave 1.8s linear infinite reverse;
}
@keyframes hp-water-level {
  0%,100% { transform: translateY(65%); }
  50% { transform: translateY(15%); }
}
@keyframes hp-water-wave {
  from { transform: translateX(0); }
  to { transform: translateX(-64px); }
}
@media (prefers-reduced-motion: reduce) {
  .hp-media-loader__water, .hp-media-loader__wave { animation: none; }
}
