/* ==========================================================================
   PSTBN Abogados — Design System
   Palette: #2d62ea #292d96 #1c1c1c #35dfff #2e3092 #3366ee #231f20

   ⚠️ ESTE ARCHIVO ES LA UNION DE LAS DOS PARTES DEL SITIO (pstbn-part1 y
   pstbn-part2). La base —tokens, reset, tipografia, botones, header, nav,
   lang-switcher, reveal— era IDENTICA en las dos, asi que se conservo una sola
   copia. Los bloques propios de cada parte estan rotulados con su origen.
   Ver project_reference.md en la raiz del proyecto.

   Tipografía: MONTSERRAT (300/400/500/600/700/800 + italic 400), cargada desde
   Google Fonts en index.html y expuesta en --font-body. El 300 lo usa SOLO la
   cita de #testimonios; venia de la part-2 y es el unico peso que la part-1 no
   cargaba. Es la ÚNICA familia del
   sitio: `body` la aplica y todo lo demás hereda; los controles de formulario
   llevan `font-family: inherit` porque si no el navegador les mete la suya.
   No declarar font-family en ninguna regla nueva.
   (Este comentario decía "Open Sans", que no es ni fue la fuente del proyecto.)

   Escala de titulares — usar SIEMPRE estos niveles, no tamaños sueltos:
     h1 / .h1   clamp(2.4rem, 5.5vw, 4.6rem)   800   un solo h1 por página
     h2 / .h2   clamp(1.9rem, 3.6vw, 2.9rem)   800   titular de sección
     h3 / .h3   clamp(1.2rem, 1.8vw, 1.5rem)   700
     .lede      clamp(1.05rem, 1.6vw, 1.25rem) 400   bajada
     .eyebrow   .8rem                          700   volanta sobre el h2
   El único override deliberado es `.hero-content h1`, que baja el tamaño para
   que el titular del hero conviva con la coreografía.
   ========================================================================== */

:root{
  /* --- Brand palette (client-supplied) --- */
  --c-blue:        #2d62ea;
  --c-blue-2:      #3366ee;
  --c-indigo:      #292d96;
  --c-indigo-2:    #2e3092;
  --c-cyan:        #35dfff;
  --c-ink:         #1c1c1c;
  --c-ink-2:       #231f20;
  /* Azul marino de las tarjetas oscuras de Áreas y Reconocimientos (2026-09-18,
     pedido del cliente: «tarjetas gris oscuro / cambiar a azul marino»). Es el
     mismo tono del header con fondo, rgba(20,21,52): no se inventó un color. */
  --c-navy:        #141534;
  --c-white:       #ffffff;

  /* --- Derived neutrals (tinted off the indigo, for section alternation) --- */
  --c-mist:        #f4f6fc;
  --c-mist-2:      #e9ecf9;
  --c-line:        #dde1f2;
  --c-grey-text:   #5b5f72;

  /* --- Semantic roles --- */
  --bg-body:       var(--c-white);
  --text-body:     var(--c-ink);
  --text-muted:    var(--c-grey-text);

  --gradient-brand:  linear-gradient(135deg, var(--c-blue) 0%, var(--c-blue-2) 45%, var(--c-cyan) 100%);
  --gradient-dark:   linear-gradient(160deg, var(--c-ink) 0%, var(--c-indigo) 55%, var(--c-indigo-2) 100%);
  --gradient-text:   linear-gradient(100deg, var(--c-blue) 0%, var(--c-cyan) 100%);

  --shadow-soft:    0 10px 30px rgba(28,28,28,.08);
  --shadow-med:     0 20px 45px rgba(41,45,150,.16);
  --shadow-glow:    0 12px 30px rgba(53,223,255,.35);

  /* ✏️ UN SOLO RADIO PARA TODO EL SITIO — el único número a tocar.
     Pedido del cliente (2026-08-13): "todos los border radius de todas las
     cajas y botones, más sutiles, sólo un leve bordeado, y que todos coincidan
     en toda la web". Antes había cuatro escalones —10, 20, 32 y 999px— y en
     una misma pantalla convivían tarjetas muy redondeadas con píldoras y con
     campos casi rectos.

     ⚠️ LOS CUATRO NOMBRES SE CONSERVAN, COMO ALIAS. Están repetidos en ~25
     reglas y renombrarlos no aportaba nada: lo que importa es que ahora haya
     un solo valor y un solo lugar donde cambiarlo. Si algún día se quiere
     volver a escalonarlos, se les devuelve un valor propio acá y el resto de
     la hoja no se toca.

     ⚠️ NO ALCANZA A LOS ELEMENTOS CIRCULARES (`border-radius: 50%`): los
     botones de ícono, el WhatsApp flotante y la miniatura del perfil son
     círculos, no cajas redondeadas, y
     convertirlos en cuadraditos cambiaba el lenguaje de toda la interfaz.
     Decisión del cliente al plantearle las dos opciones.

     ⚠️ TAMPOCO ALCANZA A LOS REDONDEOS DE 2-4px NI AL MOUSE DIBUJADO. Los de
     2-4px son anillos de foco, el `<mark>` del buscador y barritas decorativas:
     no son cajas ni botones, y llevarlos a 6px les cambia la forma. El
     indicador de scroll (`.hero-mouse-cuerpo`, 13px, y su anillo de 16px) es un
     mouse dibujado, del mismo grupo que los circulares. Si aparece un radio a
     mano que SÍ sea una caja o un botón, va a `var(--radius)`: fue el caso de
     `.busca-form`, `.busca-lista`, `.ally-card img` y `.dato-copiar`, cuatro
     componentes que part1 construyó después de esta decisión y nunca la
     recibieron. */
  --radius:         6px;
  /* ⚠️ EL ALTO DEL SEPARADOR DE MARCA VIVE ACÁ Y NO EN `.team-banner`.
     Lo consumen el banner de equipo/novedades/nosotros, la portada de las
     fichas y —desde 2026-08-20— la sección que sigue al banner en
     /nosotros/, que necesita descontar el sobrante de curva de su propio
     relleno. Esa sección es HERMANA del banner, y las custom properties
     bajan por el árbol pero no cruzan entre hermanos, así que tenía que
     subir. Estaba escrito con el mismo valor en tres lugares distintos.
     `.perfil-portada` puede seguir pisándolo si algún día necesita otro. */
  --curva-h:        clamp(64px, 9vw, 140px);
  --radius-sm:      var(--radius);
  --radius-md:      var(--radius);
  --radius-lg:      var(--radius);
  --radius-pill:    var(--radius);

  --ease-soft:      cubic-bezier(.25,.74,.22,.99);
  --dur-micro:      .3s;
  --dur-normal:     .7s;
  --dur-macro:      1.3s;

  --max-width:      1280px;
  --gutter:         clamp(1.25rem, 4vw, 3rem);

  --font-body: "Montserrat", "Segoe UI", Helvetica, Arial, sans-serif;
}

/* ==========================================================================
   Reset
   ========================================================================== */
*, *::before, *::after{ box-sizing: border-box; }
html{
  /* Sin scroll-behavior:smooth a proposito: el smooth scroll lo maneja Lenis
     (js/main.js) y las dos cosas juntas se pelean. Los anchors pasan por
     lenis.scrollTo(). Si algun dia se saca Lenis, hay que reponerlo aca. */
  scroll-padding-top: 90px;
}
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior: auto; }
  *, *::before, *::after{
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
body{
  margin: 0;
  font-family: var(--font-body);
  color: var(--text-body);
  background: var(--bg-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img{ max-width: 100%; display: block; }
a{ color: inherit; text-decoration: none; }
ul{ margin: 0; padding: 0; list-style: none; }
button{ font-family: inherit; cursor: pointer; }
input, textarea, select{ font-family: inherit; font-size: 1rem; }
h1,h2,h3,h4,p{ margin: 0; }

.skip-link{
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--c-blue);
  color: #fff;
  padding: .75rem 1.25rem;
  z-index: 999;
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus{ left: 0; }

:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 3px; }

/* ==========================================================================
   Typography
   ========================================================================== */
h1, .h1{
  font-size: clamp(2.4rem, 5.5vw, 4.6rem);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -.02em;
}
h2, .h2{
  font-size: clamp(1.9rem, 3.6vw, 2.9rem);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -.015em;
}
h3, .h3{
  font-size: clamp(1.2rem, 1.8vw, 1.5rem);
  font-weight: 700;
  line-height: 1.3;
}
.lede{
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  line-height: 1.65;
  color: var(--text-muted);
}
.eyebrow{
  display: inline-flex;
  align-items: center;
  gap: 0;
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c-blue);
}
/* ⚠️ LA VOLANTA NO LLEVA RAYA, EN NINGUNA PARTE DEL SITIO (2026-08-18).
   `.eyebrow::before` pintaba un trazo de 28px a la izquierda. El cliente pidió
   que ningún subtítulo tenga línea decorativa: primero sólo en el hero, después
   en todo el sitio. El `gap: .6em` de `.eyebrow` existía para separar ese trazo
   del texto, así que también se va: sin él la volanta arrancaba corrida.
   Si algún día vuelve, es acá y en el `gap` de `.eyebrow`. */
.eyebrow--light{ color: var(--c-cyan); }

.section-head{
  max-width: 760px;
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
}
.section-head h2{ margin-top: .75rem; }
.section-head p{ margin-top: 1rem; }
.section-head--center{ margin-left: auto; margin-right: auto; text-align: center; }

/* ==========================================================================
   Layout helpers
   ========================================================================== */
.container{
  /* ⚠️ `width: 100%` NO ES REDUNDANTE. Sin esto, el sitio se desalinea solo en
     las secciones que GSAP pinea y en las que son flex.

     Que pasa: ScrollTrigger, al pinear un elemento, le pone `display: flex`
     (lo hace para preservar el layout mientras el elemento queda fixed). Eso
     convierte a este .container en ITEM FLEX, y un item flex sin ancho se
     encoge a su contenido —`fit-content`, no el 100%— porque el
     `margin-inline: auto` cancela el `stretch` del eje transversal. El
     contenedor pasaba a medir lo que media su texto y el `auto` lo centraba,
     asi que cada seccion arrancaba en una x distinta.

     Se veia en #equipo (pin del recorrido horizontal) y en #novedades
     (`display: flex` propio): a 1920 el contenido caia en x=484 y x=466 en vez
     de x=368 como el resto del sitio y como el logo del header.

     La part-2 ya habia tenido que parchear el sintoma a mano con
     `.reconocimientos > .container{ width: 100% }`, sin identificar la causa.
     Esa regla queda mas abajo pero ahora es redundante.

     Con `width: 100%` el contenedor toma el ancho del padre, `max-width` lo
     corta en 1280 y `margin-inline: auto` lo centra — en flujo normal, como
     item flex y como item grid, todos igual. */
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
section{ position: relative; }
/* El padding vertical se expone además como variable. Hasta el 2026-09-18 lo
   usaba #alianzas para posicionar su palabra de fondo respecto de la fila de
   tarjetas; hoy ese título va en flujo (ver .allies-word), pero la variable se
   conserva por si otra sección la necesita. */
.section-pad{
  --pad-block: clamp(4rem, 9vw, 7.5rem);
  padding-block: var(--pad-block);
}

.section--light{ background: var(--bg-body); }
.section--mist{ background: var(--c-mist); }
.section--dark{
  background: var(--gradient-dark);
  color: #fff;
}
.section--dark .text-muted{ color: rgba(255,255,255,.72); }
/* ⚠️ `.lede` TRAE `--text-muted`, QUE ES TINTA OSCURA. Sobre una sección oscura
   eso da ~2:1 y el párrafo de entrada queda ilegible. Era un hueco del sistema y
   no se notaba porque el único `.lede` sobre fondo oscuro que había —el de
   #contacto— se lo tapaba con un color propio (`.contact-lede`). Lo destapó la
   página /nosotros/, que usa `.lede` en dos secciones sobre foto.
   ⚠️ EL VALOR DE `--dark` ES EXACTAMENTE EL QUE YA USABA `.contact-lede`: así
   esta regla, que le gana en especificidad (0,2,0 contra 0,1,0), no cambia ni un
   píxel de la sección de contacto. Sobre foto se sube a .82 porque ahí compite
   con la imagen, no con un degradado plano. */
.section--dark .lede{ color: rgba(255,255,255,.72); }
.section--photo .lede{ color: rgba(255,255,255,.82); }

.grid-split{
  display: grid;
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: center;
}
@media (min-width: 900px){
  .grid-split{ grid-template-columns: 1.1fr .9fr; }
  .grid-split--reverse{ grid-template-columns: .9fr 1.1fr; }
  .grid-split--reverse > *:first-child{ order: 2; }
}

.media-fade{
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  aspect-ratio: 4 / 5;
}
.media-fade img{ width: 100%; height: 100%; object-fit: cover; }

/* Full-bleed photographic section backgrounds */
.bg-photo{
  position: absolute;
  inset: 0;
  z-index: 0;
}
.bg-photo img{ width: 100%; height: 100%; object-fit: cover; }
.bg-photo::after{
  content: "";
  position: absolute;
  inset: 0;
}
.bg-photo--dark::after{ background: linear-gradient(180deg, rgba(28,28,28,.82), rgba(28,28,28,.9)); }
.bg-photo--indigo::after{ background: linear-gradient(160deg, rgba(28,28,28,.55) 0%, rgba(41,45,150,.82) 65%, rgba(46,48,146,.92) 100%); }
.bg-photo--brand::after{ background: linear-gradient(120deg, rgba(45,98,234,.88) 0%, rgba(41,45,150,.9) 100%); }
.section--photo{ color: #fff; overflow: hidden; }
.section--photo > .container{ position: relative; z-index: 1; }

/* ==========================================================================
   Buttons
   ========================================================================== */
.btn{
  display: inline-flex;
  align-items: center;
  gap: .6em;
  padding: 1.05em 2em;
  border-radius: var(--radius-pill);
  font-weight: 700;
  font-size: .98rem;
  letter-spacing: -.01em;
  border: none;
  white-space: nowrap;
  transition: transform var(--dur-micro) var(--ease-soft),
              box-shadow var(--dur-micro) var(--ease-soft),
              background var(--dur-micro) var(--ease-soft),
              color var(--dur-micro) var(--ease-soft);
}
.btn--primary{
  background: var(--gradient-brand);
  background-size: 160% 160%;
  background-position: 0% 50%;
  color: #fff;
  box-shadow: var(--shadow-med);
}
.btn--primary:hover{
  background-position: 100% 50%;
  transform: translateY(-3px);
  box-shadow: var(--shadow-glow);
}
.btn--ghost{
  background: transparent;
  color: currentColor;
  box-shadow: inset 0 0 0 1.5px rgba(28,28,28,.18);
}
.btn--ghost:hover{
  box-shadow: inset 0 0 0 1.5px var(--c-blue);
  color: var(--c-blue);
  transform: translateY(-3px);
}
.section--dark .btn--ghost,
.section--photo .btn--ghost{
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,.35);
  color: #fff;
}
.section--dark .btn--ghost:hover,
.section--photo .btn--ghost:hover{
  box-shadow: inset 0 0 0 1.5px var(--c-cyan);
  color: var(--c-cyan);
}
.btn--sm{ padding: .75em 1.5em; font-size: .88rem; }
.btn-row{ display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; }
.link-arrow{
  display: inline-flex;
  align-items: center;
  gap: .5em;
  font-weight: 700;
  color: var(--c-blue);
  position: relative;
}
.link-arrow svg{ width: 18px; height: 18px; transition: transform var(--dur-micro) var(--ease-soft); }
.link-arrow:hover svg{ transform: translateX(5px); }
.section--dark .link-arrow, .section--photo .link-arrow{ color: var(--c-cyan); }

/* ==========================================================================
   Header / Navigation
   ========================================================================== */
/* ⚠️ El padding compacto es un token porque `dibujarArcos` (js/main.js) necesita
   saber cuánto medirá el header ENCOGIDO mientras todavía está expandido: la
   banda de rayas se coloca contra el header de la pantalla 2, que ya lleva
   `.is-scrolled`. Si cambia acá, el cálculo lo sigue solo. */
:root{ --header-pad-compacto: .8rem; }
.site-header{
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  padding-block: 1.35rem;
  background: transparent;
  transition: padding var(--dur-micro) var(--ease-soft);
}
.site-header .container{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

.header-actions{
  display: flex;
  align-items: center;
  /* Mismo motivo que el hueco entre ítems: el contenedor no crece más allá de
     1280, así que a 1920 cada punto de holgura cuenta. */
  gap: clamp(1rem, 2vw, 1.5rem);
  /* Que el bloque de la derecha pueda encogerse: si no, con ocho ítems empuja
     al logo fuera del contenedor en vez de apretarse. */
  min-width: 0;
}

/* --------------------------------------------------------------------------
   Barra horizontal — las ocho secciones desplegadas
   --------------------------------------------------------------------------
   Pedido del cliente (2026-08-13) con Marval como referencia: los ítems a la
   vista en vez de escondidos tras el botón de hamburguesa. Y con las OCHO
   secciones, que fue decisión suya sabiendo que quedan justas.

   ⚠️ EL CORTE DE 1200px NO ES REDONDO NI ELEGIDO A OJO. Las ocho etiquetas suman
   ~700px de texto —"Áreas de práctica" y "Reconocimientos" son las que mandan— y
   hay que sumarles el logo (~148px), el buscador y los huecos. Por debajo de ese
   ancho no entran sin apretarlas hasta hacerlas ilegibles, así que ahí vuelve el
   botón y el panel lateral, que se conservan enteros.

   El `clamp` del tamaño y del hueco es lo que hace que entren entre 1200 y 1440
   sin desbordar: se estrechan juntos y de forma continua. */
.nav-inline{ display: none; }
.nav-inline ul{
  display: flex;
  align-items: center;
  /* ⚠️ EL TOPE DE 1.5rem ESTÁ MEDIDO. Con 1.75rem, a 1920 el conjunto pedía más
     de lo que deja el contenedor —que está capado en 1280 y no crece con la
     pantalla— y lo de la derecha se salía. Por debajo de 1900 el `clamp` usa el
     valor en vw y este tope ni se toca. */
  /* ⚠️ El tope bajó de 1.5rem a 1.3rem el 2026-08-16: las flechas de los tres
     desplegables suman ancho y a 1920 el conjunto volvía a pasarse del borde
     interno del contenedor, que está capado en 1280 y no crece. */
  gap: clamp(.8rem, 1.5vw, 1.3rem);
}
/* --------------------------------------------------------------------------
   DESPLEGABLES DEL MENÚ — panel a todo el ancho (2026-08-17)
   --------------------------------------------------------------------------
   Rehecho contra la referencia que pasó el cliente (marval.com). Lo que cambió
   respecto de la primera versión, y por qué:

     · Era una TARJETA FLOTANTE de 964px centrada bajo el ítem; ahora es una
       FRANJA a todo el ancho, pegada al header, como en la referencia.
     · Era OSCURA translúcida; ahora es clara. Los valores no salen de la
       referencia sino de nuestros tokens: `--c-mist` de fondo, `--text-body`
       de texto, `--c-blue` en las viñetas.
     · Tenía radio de 14px, borde y sombra; ahora va a ras, sin radio.
     · No tenía columna de encabezado; ahora la primera columna lleva el nombre
       de la sección, que además es el enlace a ella —en la referencia está
       subrayado, o sea que es un enlace— y reemplaza al «Ver todas» que había
       al pie.
     · Los ítems no tenían viñeta; ahora llevan el cuadrito de la referencia.
     · Eran 3 columnas y peso 600; ahora 5 y peso normal.

   ⚠️ SE ABREN CON EL MOUSE Y CON EL TECLADO. `:hover` solo deja fuera a quien
   navega con Tab, así que el `<li>` también responde a `:focus-within`. El
   botón de flecha que agregaba un tercer camino se retiró el 2026-08-18 a
   pedido del cliente; `.nav-inline` sólo existe de 1200px para arriba, y en
   pantallas chicas el menú es el panel lateral.
   -------------------------------------------------------------------------- */
.nav-tiene-sub{ position: relative; }

.nav-sub[hidden]{ display: none; }
/* ⚠️ ARRANCA DONDE TERMINA EL HEADER, SIN HUECO. Ese hueco era el bug que
   marcó el cliente: el panel se separaba .55rem con `margin-top` y ese margen
   es tierra de nadie —al mover el cursor del ítem al panel se cruzan 9px donde
   no hay ninguno de los dos, salta el `pointerleave` del <li> y el panel se
   cierra antes de llegar—. Medido con un recorrido real del cursor: se cerraba
   en el segundo de ocho pasos. Pegado al header no hay nada que cruzar.
   `--header-h` lo publica el ResizeObserver de js/main.js. */
/* ⚠️ `fixed` A TODO EL ANCHO, Y VIVE DENTRO DE SU <li>.
   Que funcione depende de que NINGÚN ancestro esté transformado: un ancestro
   con `transform` se vuelve el bloque contenedor de sus descendientes `fixed`,
   y con el reparto de la portada aplicado al <li> esto daba 147px de ancho.
   Por eso el reparto pasó a moverse sobre los HIJOS del <li> y no sobre el
   <li> (ver js/main.js). Si alguien vuelve a transformar el <li> o
   `.header-actions`, este panel se rompe otra vez.
   Se mantiene dentro del <li> porque es lo que da orden natural de tabulación
   —sacarlo al final del header hacía que un Tab desde el ítem saltara al ítem
   siguiente y a los subítems no se llegara nunca— y hover en CSS. */
.nav-sub{
  position: fixed;
  top: var(--header-h, 115px);
  left: 0;
  right: 0;
  z-index: 10;
  /* ⚠️ EL HUECO QUE SE VEÍA NO ESTABA ENTRE EL HEADER Y EL PANEL: medido, ese
     hueco es 0 —el panel arranca exactamente en `top: var(--header-h)`—. Lo que
     se leía como espacio era ESTE relleno de arriba, que separaba el borde del
     panel de su primera línea de contenido. Bajó de 2.6rem a 1.35rem, y el
     2026-08-18 a CERO: el cliente lo siguió viendo como un hueco. El contenido
     ahora empieza en el borde mismo del panel. */
  padding: 0 0 clamp(1.8rem, 3.5vw, 3rem);
  background: var(--c-mist);
  border-top: 1px solid var(--c-line);
  box-shadow: 0 18px 40px rgba(28,28,28,.12);
  opacity: 0;
  transform: translateY(-8px);
  pointer-events: none;
  transition: opacity var(--dur-micro) var(--ease-soft), transform var(--dur-micro) var(--ease-soft);
}
/* `.nav-abierto` lo pone js/main.js y sobrevive 260ms a la salida del cursor:
   es lo que permite cruzar el hueco en diagonal sin que el puente tenga que
   taparle los clicks a la fila de enlaces. Ver el módulo de desplegables. */
.nav-tiene-sub:hover > .nav-sub,
.nav-tiene-sub:focus-within > .nav-sub,
.nav-tiene-sub.nav-abierto > .nav-sub{ opacity: 1; transform: none; pointer-events: auto; }
/* ⚠️ PUENTE HACIA ARRIBA — ES EL ARREGLO DEL BUG QUE MARCÓ EL CLIENTE.
   Entre el ítem del menú y el panel quedan ~40px de la franja del header que no
   pertenecen a ninguno de los dos: al bajar el cursor se pasa por ahí, salta el
   `pointerleave` del ítem y el panel se cierra antes de que se pueda tocar.
   Medido con un recorrido real del cursor, se cerraba en el segundo paso de
   ocho.
   Este bloque transparente pertenece AL PANEL y va a todo el ancho, así que
   cubre la franja entera —también si el cursor baja en diagonal hacia la
   primera columna, que es por donde se escapaba un puente del ancho del ítem—.
   Entrar en él dispara el `pointerenter` del panel, que cancela el cierre.
   Sólo existe con el panel visible: el resto del tiempo no le roba un click a
   nadie.

   ⚠️ EL ALTO LO PONE JS, NO UN NÚMERO FIJO (2026-09-15). Eran 3.5rem —56px—
   elegidos para el header expandido, donde el hueco es 40.4px y lo que sobra
   cae fuera de los enlaces. Con el header COMPACTO el hueco es 33.2px y esos
   56px suben hasta y=43, dentro de la fila de enlaces (y 32.6→65.8): con un
   desplegable abierto, «Contacto», «Profesionales», «Testimonios», «Áreas de
   práctica», «Alianzas», «Reconocimientos», «Novedades» y el logo dejaban de
   recibir el click. Lo marcó el cliente en «Contacto»; era además la causa de
   los siete fallos de «Profesionales» de la batería.
   `--puente-h` lo publica el ResizeObserver de js/main.js y vale exactamente el
   hueco, medido sobre los controles reales del header. El respaldo de 2.5rem
   —40px— es para el header expandido, que es el estado de arranque. */
.nav-tiene-sub:hover > .nav-sub::before,
.nav-tiene-sub:focus-within > .nav-sub::before,
.nav-tiene-sub.nav-abierto > .nav-sub::before{
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: var(--puente-h, 2.5rem);
}

/* ⚠️ NO USA LA CLASE `.container`, replica sus medidas. Dentro del header,
   `.site-header .container` —especificidad 0,2,0— le gana a cualquier regla de
   clase simple y le impone `display: flex; align-items: center`: el encabezado
   quedaba centrado a media altura y las cinco columnas colapsadas en una sola
   contra el borde derecho. Los valores son los mismos que usa `.container`, así
   que la alineación con el resto del sitio se mantiene. */
.nav-sub-int{
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--gutter);
  /* ⚠️ AIRE ARRIBA — Y ESTO REVIERTE EL AJUSTE DEL 2026-08-18. Aquel día el
     relleno superior del PANEL (`.nav-sub`) se bajó a cero porque el cliente lo
     leía como un hueco entre el header y el desplegable. El 2026-08-19 pidió lo
     contrario: «los títulos están muy arriba, pegados al borde».
     ⚠️ Por eso el aire va acá, en el CONTENIDO, y no en `.nav-sub`: el panel
     sigue arrancando pegado al header —no reaparece el hueco que molestaba— y
     lo que se separa del borde es el texto, que es lo que se pidió. Si alguien
     lo mueve a `.nav-sub`, vuelve el reclamo viejo.
     0 → 32px a 1440. */
  padding-block-start: clamp(1.5rem, 2.2vw, 2.25rem);
  display: grid;
  grid-template-columns: minmax(9rem, 14rem) 1fr;
  gap: clamp(1.5rem, 3vw, 3rem);
  align-items: start;
}
/* ⚠️ `.site-header` EN EL SELECTOR NO SOBRA. `.site-header .nav-inline a` tiene
   especificidad 0,2,1 y está declarada más abajo en este archivo: sin igualar
   esa especificidad, el blanco del menú gana y TODO el texto del panel —que es
   claro— queda blanco sobre blanco. Es lo que reportó el cliente: «los textos
   del submenú no se ven». */
.site-header .nav-sub-encabezado a{
  display: inline-block;
  padding: 0 0 .3rem;
  /* ⚠️ NO ES EL h3 DE LA ESCALA. Lo era —clamp(1.2rem,1.8vw,1.5rem), 24px a
     1440— y contra ítems de 13.44px dominaba el panel entero. Un encabezado de
     submenú no es un título de sección: sólo tiene que leerse por encima de sus
     ítems, y para eso alcanza con la distancia que ya dan el peso 700 y el
     subrayado. 24px → 17.28px a 1440. */
  font-size: clamp(1rem, 1.2vw, 1.15rem);
  font-weight: 700;
  line-height: 1.2;
  color: var(--text-body);
  white-space: normal;
  /* Sin subrayado: el cliente pidió que ningún subtítulo lleve línea. La
     jerarquía la sostienen el peso 700 y el tamaño. */
  transition: color var(--dur-micro) var(--ease-soft);
}
.site-header .nav-sub-encabezado a:hover{ color: var(--c-blue); }
.nav-sub-encabezado a::after{ content: none; }

/* ⚠️⚠️ CAUSA RAÍZ DE LA SUPERPOSICIÓN — LEER ANTES DE TOCAR NADA DE ACÁ.
   `.nav-inline ul{ display: flex; align-items: center; gap: … }` —la regla que
   arma la barra horizontal del header— tiene especificidad 0,1,1 y alcanza a
   TODOS los <ul> que haya dentro de `.nav-inline`, incluidas las columnas de
   este panel. Una regla de clase simple (0,1,0) no le gana.

   El efecto medido: cada columna se volvía una FILA horizontal y sus tres o
   cuatro ítems se ponían uno al lado del otro, desbordando la pista de 204px
   hasta 221px e invadiendo la columna vecina. Seis pares de ítems superpuestos
   en los tres anchos probados. En los paneles en fila el síntoma era otro pero
   la causa la misma: heredaban `align-items: center` y los ítems arrancaban a
   distinta altura (y158 contra y176).

   Por eso TODAS las reglas de disposición del panel llevan `.site-header`
   delante: para llegar a 0,3,0 y ganarle. Si se agrega una regla nueva de
   layout acá y se olvida el prefijo, la superposición vuelve. */
.site-header .nav-sub ul{
  display: block;
  align-items: initial;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* ⚠️ EL REPARTO EN COLUMNAS LO DECIDE EL CSS, NO EL HTML.
   Antes el generador troceaba las áreas en cinco <ul> y acá se armaba una grilla
   de cinco pistas. Eso obliga a que dos archivos distintos estén de acuerdo, y
   dejaron de estarlo: al bajar a cuatro pistas en pantallas medianas, la quinta
   lista envolvía y las columnas arrancaban a dos alturas distintas.
   Ahora es UNA lista y `column-count`: el navegador reparte los ítems entre las
   columnas que haya, y no existe forma de que sobre o falte una.
   `break-inside: avoid` evita que un nombre de tres renglones —«Derecho de las
   Telecomunicaciones»— se parta entre el pie de una columna y la cabeza de la
   siguiente. */
/* ⚠️ GRILLA, NO `column-count` — CAMBIADO EL 2026-08-19.
   Con `column-count` cada columna FLUYE POR SEPARADO: los ítems de una columna
   no tienen por qué empezar a la misma altura que los de la vecina, y como los
   nombres miden uno, dos o tres renglones el panel quedaba escalonado. Medido:
   16 ítems en 5 columnas daban **6 alturas distintas** cuando deberían ser 4.
   Lo marcó el cliente («no mantienen una alineación o distribución uniforme»).
   Con grilla el reparto es por FILAS: todos los de una fila arrancan en la misma
   y, y todas las columnas tienen el mismo ancho. `align-items: start` deja cada
   ítem pegado al techo de su fila en vez de centrado respecto del más alto.
   ⚠️ EL SELECTOR NECESITA `ul` PARA LLEGAR A 0,3,1. La regla de arriba
   —`.site-header .nav-sub ul`, 0,3,0— pone todas las listas del panel en
   `display: block`; sin subir la especificidad, el `display: grid` de acá no
   aplicaba. Es el mismo motivo por el que `.nav-sub-fila` ya lo hacía.
   ⚠️ `minmax(0, 1fr)` y no `1fr`: con `1fr` la pista hereda `min-width: auto` y
   un nombre largo la ensancha por encima de su parte, desbordando el panel. */
.site-header .nav-sub ul.nav-sub-cols{
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  column-gap: clamp(1rem, 2vw, 2rem);
  align-items: start;
}
.site-header .nav-sub-cols > li{
  break-inside: avoid;
  -webkit-column-break-inside: avoid;   /* Safari todavía lo pide con prefijo */
}
/* Por debajo de 1400px cinco columnas dejan los nombres en cuatro renglones. */
@media (max-width: 1399px){ .site-header .nav-sub ul.nav-sub-cols{ grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 1100px){ .site-header .nav-sub ul.nav-sub-cols{ grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.nav-sub li{ margin: 0; }
/* Misma razón que el encabezado: hay que igualar 0,2,1 para que el blanco del
   menú no se lleve puesto el texto del panel. */
/* ⚠️ `minmax(0, 1fr)` Y NO `1fr` en la segunda pista: con `1fr` a secas la
   pista hereda `min-width: auto` y una palabra larga la ensancha por encima de
   su parte, sacando el enlace de su columna. Es la otra mitad del desborde.
   `align-items: start` deja la viñeta a la altura de la PRIMERA línea del
   texto, no centrada respecto de un ítem de tres renglones. */
.site-header .nav-sub-cols a,
.site-header .nav-sub-fila a{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: .55rem;
  /* Ritmo vertical uniforme: todos los ítems separan lo mismo, tengan uno o
     tres renglones. Historia del valor, porque es el tercer aumento y conviene
     no volver atrás por error: .4rem → .65rem (los renglones de un ítem de tres
     líneas quedaban tan juntos entre sí como los ítems entre ellos) → .85rem el
     2026-08-18 → **1.45rem el 2026-08-19**, a pedido del cliente: «los ítems
     necesitan MUCHO más espaciado».
     Entre el texto de un ítem y el del siguiente: 12.8px → 27.2px → **46.4px**.
     ⚠️ Este número también fija el ALTO del panel de Áreas de práctica, que es
     el más alto de los tres (16 ítems en 4-5 columnas): subirlo lo agranda y
     bajarlo lo achica. Era el otro pedido del mismo día («el panel de Áreas es
     demasiado bajo»), y se resuelve con este mismo valor en vez de con un alto
     fijo, que se desincronizaría del contenido. */
  padding: 1.45rem 0;
  font-size: .84rem;
  font-weight: 400;
  line-height: 1.4;
  white-space: normal;          /* los nombres de las áreas son largos */
  color: var(--text-body);
  transition: color var(--dur-micro) var(--ease-soft);
}
/* La viñeta cuadrada de la referencia. Va en `::before` y no como carácter para
   que no la lea un lector de pantalla. */
.nav-sub-cols a::before,
.nav-sub-fila a::before{
  content: "";
  width: 7px; height: 7px;
  margin-top: .45em;
  background: var(--c-blue);
}
.site-header .nav-sub-cols a:hover,
.site-header .nav-sub-fila a:hover,
.site-header .nav-sub-cols a:focus-visible,
.site-header .nav-sub-fila a:focus-visible{ color: var(--c-blue); }
.nav-sub a:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 2px; }
.nav-sub a::after{ content: none; }   /* sin el subrayado de los ítems de arriba */

/* Paneles de pocos ítems —Profesionales, Novedades—: en fila, como el
   desplegable «Contenido» de la referencia. */
/* ⚠️ Con `.site-header` delante por la misma razón: `.nav-sub-fila` ES un <ul>,
   así que `.nav-inline ul` lo alcanza directamente y le imponía
   `align-items: center` —los ítems arrancaban a distinta altura—. Acá se
   alinean todos arriba, que es lo que los pone en la misma línea. */
/* ⚠️ `ul.nav-sub-fila` para llegar a 0,3,1: la regla de arriba
   —`.site-header .nav-sub ul`, 0,3,0— pone todas las listas del panel en
   `display: block`, y sin subir la especificidad acá también aplanaba ésta, que
   sí tiene que ser flex. */
/* ⚠️ GRILLA TAMBIÉN ACÁ, Y CON EL ANCHO DE PISTA COMO VARIABLE (2026-08-19).
   Era flex con `flex: 0 1 22rem` en cada <li>. Para las novedades —bloques de
   tres renglones— esos 22rem están bien, pero el panel de Nosotros usa la misma
   lista con etiquetas de 14 caracteres: cada ítem se quedaba con 352px de ancho
   y «Quiénes Somos» y «Qué Hacemos» terminaban separados ~400px, leyéndose
   dispersos en vez de como una lista. Lo marcó el cliente.
   Con `auto-fit` + `minmax(var(--sub-col), 1fr)` el ancho de pista lo fija cada
   panel según su contenido, sin duplicar la regla ni tocar el HTML de los otros.
   `align-items: start` mantiene todos los ítems de una fila arrancando arriba. */
.site-header .nav-sub ul.nav-sub-fila{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--sub-col, 22rem), 1fr));
  align-items: start;
  gap: .2rem clamp(1.5rem, 3vw, 3rem);
}
/* Paneles de etiquetas cortas. Novedades no lo declara y se queda con los 22rem
   por defecto, que es lo que necesitan sus bloques de tema + título + fecha.
   ⚠️ 15rem ES UN ANCHO DE PISTA, PERO LO QUE FIJA ES EL NÚMERO DE COLUMNAS: 3.
   El cliente pidió que los cinco ítems de Nosotros queden 3 arriba y 2 abajo
   —«Alcance Internacional» abajo y «Responsabilidad» a su lado— en vez de 4 + 1
   huérfano (2026-08-19). Con `auto-fit` eso se consigue por el ancho de pista,
   no contando columnas a mano, así que el panel sigue degradando solo en
   pantallas angostas.
   ⚠️ EL VALOR ESTÁ EN EL CENTRO DE SU RANGO A PROPÓSITO. Barrido en 1920, 1600,
   1440, 1366 y 1280: **de 13rem a 17rem** dan 3 columnas en todos; 12.5rem ya se
   va a 4 en 1280 y 18rem cae a 2. Se eligió 15rem para tener 2rem de margen a
   cada lado, que es lo que aguanta que otra máquina renderice la fuente distinto
   o aparezca la barra de scroll. Si se toca, volver a barrer. */
.nav-sub-fila--compacta{ --sub-col: 15rem; }

/* ⚠️ LOS TRES <span> DE UNA NOTA VAN APILADOS EN LA SEGUNDA COLUMNA. El enlace
   es un grid de `auto 1fr` —la viñeta y el texto—, y con tres hijos además del
   `::before` el flujo automático los repartía entre las dos columnas: la
   etiqueta quedaba al lado de la viñeta, el título debajo y la fecha flotando a
   la derecha. Fijándolos a la columna 2 se apilan en filas, que es lo que son:
   tema, título y fecha de la misma nota. */
.site-header .nav-sub-fila a > span{ grid-column: 2; }
/* Y una nota no puede ocupar todo el ancho del panel: son tres en fila. */
/* ⚠️ Ya no hace nada: la lista pasó a grilla y el ancho lo fija la pista, no el
   ítem. Se deja anulado en vez de borrado porque el valor 22rem sobrevive como
   `--sub-col` por defecto, y así se ve de dónde salía. */
.site-header .nav-sub ul.nav-sub-fila > li{ min-width: 0; }

.nav-sub-tema{
  display: block;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--c-blue);
}
.nav-sub-titulo{ display: block; margin-top: .15rem; font-weight: 600; max-width: 22rem; }
.nav-sub-fecha{ display: block; margin-top: .15rem; font-size: .74rem; color: var(--text-muted); }

@media (prefers-reduced-motion: reduce){
  .nav-sub{ transition: none; }
}

.nav-inline a{
  display: block;
  white-space: nowrap;
  /* ⚠️ El tope de .9rem también está medido: con .95rem las ocho etiquetas
     sumaban más de lo que deja el contenedor a 1920. */
  font-size: clamp(.78rem, .92vw, .9rem);
  font-weight: 600;
  letter-spacing: .01em;
  color: rgba(255,255,255,.88);
  padding-block: .35rem;
  position: relative;
  transition: color var(--dur-micro) var(--ease-soft);
}
.nav-inline a:hover,
.nav-inline a:focus-visible{ color: #fff; }
/* Subrayado que crece desde la izquierda: marca el ítem sin mover el texto ni
   cambiar el ancho, que con ocho ítems justos reflowearía la barra entera. */
.nav-inline a::after{
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--c-cyan);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-micro) var(--ease-soft);
}
.nav-inline a:hover::after,
.nav-inline a:focus-visible::after{ transform: scaleX(1); }
.nav-inline a[aria-current="true"]{ color: #fff; }
.nav-inline a[aria-current="true"]::after{ transform: scaleX(1); }

@media (min-width: 1200px){
  .nav-inline{ display: block; }
  /* Con la barra desplegada, el botón y su panel dejan de tener sentido. */
  .site-header .menu-btn{ display: none; }
}
/* ⚠️ PERO EN PANTALLAS TÁCTILES VA EL PANEL LATERAL, AUNQUE MIDAN ≥1200PX
   (2026-09-19). Los desplegables de la barra se abren al pasar el mouse y en
   un iPad Pro o una Surface en horizontal quedaban abiertos tras el toque,
   tapando la sección. `hover: none` o `pointer: coarse` es una tablet; una
   portátil con mouse (aunque tenga pantalla táctil) sigue viendo la barra. */
@media (min-width: 1200px) and (hover: none), (min-width: 1200px) and (pointer: coarse){
  .nav-inline{ display: none; }
  .site-header .menu-btn{ display: inline-flex; }
}

/* --------------------------------------------------------------------------
   Buscador del header
   --------------------------------------------------------------------------
   Pedido del cliente (2026-08-13), como en la referencia. Arranca como un icono
   y se abre al pulsarlo, para no robarle ancho a los ocho ítems mientras no se
   usa — que es justamente el recurso escaso de esta barra.

   ⚠️ ACÁ VIVE SÓLO LA LUPA. El campo y los resultados están en la capa centrada
   (#busca, más abajo en este archivo). Hasta el 2026-08-16 el campo se desplegaba
   dentro de la barra y se montaba sobre "Reconocimientos".
   -------------------------------------------------------------------------- */
.buscador{ position: relative; display: flex; align-items: center; }
.buscador-btn{
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px; height: 34px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 50%;
  color: rgba(255,255,255,.9);
  cursor: pointer;
  transition: background var(--dur-micro) var(--ease-soft), color var(--dur-micro) var(--ease-soft);
}
.buscador-btn svg{ width: 19px; height: 19px; }
.buscador-btn:hover,
.buscador-btn:focus-visible{ background: rgba(255,255,255,.12); color: #fff; }
.buscador-btn:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 2px; }

/* --------------------------------------------------------------------------
   BUSCADOR — capa centrada
   --------------------------------------------------------------------------
   ⚠️ EL CAMPO YA NO SE DESPLIEGA EN LA BARRA. Lo hacía hasta el 2026-08-16 y
   al abrirse se montaba sobre "Reconocimientos": el ancho de la barra está al
   límite (ver §1bis del project_reference) y no hay lugar para un campo de
   19rem. Ahora la lupa abre esta capa, centrada y con el fondo desenfocado.
   -------------------------------------------------------------------------- */
.busca[hidden]{ display: none; }
/* ⚠️ CENTRADA EN EL VIEWPORT, en los dos ejes. Estaba con
   `place-items: start center` y un `padding-top` grande: quedaba centrada en
   horizontal pero colgada del borde de arriba, y en una pantalla alta se veía
   claramente descolgada. `center` centra la caja; el `padding` pasa a ser
   simétrico y sólo actúa de margen mínimo contra los bordes.
   ⚠️ `100dvh` y no `100vh` en móvil: con la barra de direcciones a la vista,
   `100vh` es más alto que lo que se ve y el centro cae por debajo del pliegue.
   El `100vh` queda de reserva para los navegadores sin `dvh`. */
/* ⚠️ SE DESPLIEGA DESDE EL HEADER, NO SE CENTRA EN PANTALLA (2026-08-18).
   Era una caja centrada a media pantalla —pedido del 2026-08-16— y el cliente
   la cambió por el comportamiento de la referencia (marval.com): baja desde el
   borde inferior del header y toma el ancho de SU CONTENEDOR, ni más ni menos.
   De ahí que el marco use `max-width: var(--max-width)` y el mismo gutter que
   `.container`: así el panel arranca y termina en la misma x que el logo y que
   el último ítem del menú. */
.busca{
  position: fixed;
  inset: 0;
  z-index: 120;                 /* por encima del header (100) y del panel */
  display: grid;
  align-content: start;
  justify-items: center;
  height: 100vh;
  height: 100dvh;
  padding: 0;
  padding-top: var(--header-h, 115px);
  /* ⚠️ LA FRANJA QUE QUEDA SOBRE EL HEADER NO PUEDE INTERCEPTAR EL CURSOR. La
     capa va a pantalla completa para que el velo cubra la página, pero su parte
     de arriba se superpone al header: sin esto, con el buscador abierto la lupa
     y el menú dejaban de recibir clicks —ni siquiera se podía volver a tocar la
     lupa para cerrar—. Se apaga en la capa y se reactiva en las dos piezas que
     sí tienen que recibirlos. */
  pointer-events: none;
  /* Si la lista de resultados crece más que la pantalla, la capa entera
     scrollea en vez de recortarse. */
  overflow-y: auto;
}
/* ⚠️ A TODO EL ANCHO DE LA VENTANA, NO AL DEL CONTENEDOR. La captura de
   marval.com que pasó el cliente muestra una banda que cruza la pantalla entera
   pegada al header; lo que se alinea con el contenido del header es el CAMPO,
   no la banda. Antes esto medía `--max-width` menos los gutters y quedaba una
   tarjeta flotando. */
/* ⚠️ SIN 100VW (2026-09-19). `100vw` incluye la barra de scroll clásica de
   Windows: con el buscador abierto aparecía una barra horizontal abajo y el
   campo quedaba corrido 7–8px respecto del logo. La capa `.busca` ya ocupa toda
   la ventana, así que la banda sólo tiene que estirarse dentro de ella. */
.busca-marco{
  pointer-events: auto;
  width: auto;
  max-width: none;
  margin-inline: 0;
  justify-self: stretch;
  overflow: hidden;             /* recorta el deslizamiento — ver el HTML */
  background: var(--c-mist);
  border-bottom: 1px solid var(--c-line);
  box-shadow: 0 18px 40px rgba(28,28,28,.12);
}
/* Con la capa centrada, el bloque no puede pasarse del alto de la pantalla: la
   lista cede antes que el campo, que es lo que siempre tiene que verse. */
.busca-caja{ max-height: 100%; display: flex; flex-direction: column; }
/* El desenfoque es del FONDO, no de la caja: `backdrop-filter` toma lo que hay
   detrás de este elemento, que es la página entera. */
/* ⚠️ YA NO OSCURECE NADA: ES SÓLO EL CAPTADOR DEL CLICK DE AFUERA.
   Era un velo con blur —la capa entera funcionaba como modal—. En la referencia
   que pasó el cliente (marval.com) la banda del buscador baja del header y la
   página sigue a la vista, sin atenuar. Se conserva el elemento porque es lo que
   cierra al tocar fuera del panel. */
.busca-fondo{
  position: absolute;
  inset: var(--header-h, 115px) 0 0;
  pointer-events: auto;
  background: none;
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  animation: none;
}
.busca-caja{
  position: relative;
  /* La BANDA cruza la pantalla; lo que se alinea con el logo y con la lupa es
     este bloque, que copia el ancho útil de `.container`. */
  width: min(calc(100% - 2 * var(--gutter)), calc(var(--max-width) - 2 * var(--gutter)));
  margin-inline: auto;
  padding-block: clamp(1rem, 2vw, 1.6rem);
  animation: busca-caja-in var(--dur-normal) var(--ease-soft) backwards;
}
@keyframes busca-fondo-in{ from{ opacity: 0; } }
@keyframes busca-caja-in{ from{ opacity: 0; transform: translateY(-100%); } }
@media (prefers-reduced-motion: reduce){
  .busca-fondo, .busca-caja{ animation: none; }
}

/* El campo toma el ancho completo del panel: lo pidió el cliente. */
.busca-form{
  position: relative;
  width: 100%;
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .35rem .35rem .35rem 1.1rem;
  background: #fff;
  border: 1px solid var(--c-line);
  border-radius: var(--radius-pill);
  box-shadow: 0 24px 60px rgba(4,6,26,.5);
}
.busca-form:focus-within{ border-color: var(--c-cyan); }
.busca-lupa{ flex: none; width: 22px; height: 22px; color: var(--c-grey-text); }
.busca-campo{
  flex: 1 1 auto;
  min-width: 0;
  padding: .85rem .2rem;
  font: inherit;
  font-size: clamp(1rem, 1.5vw, 1.15rem);
  color: var(--c-ink);
  background: none;
  border: 0;
}
.busca-campo:focus{ outline: none; }   /* el foco lo marca el borde de la caja */
.busca-campo::placeholder{ color: var(--c-grey-text); }
/* La X nativa de `type="search"` duplica el botón de cerrar. */
.busca-campo::-webkit-search-cancel-button{ -webkit-appearance: none; }
.busca-cerrar{
  flex: none;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  color: var(--c-grey-text);
  background: rgba(28,28,28,.06);
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: background var(--dur-micro) var(--ease-soft), color var(--dur-micro) var(--ease-soft);
}
.busca-cerrar svg{ width: 20px; height: 20px; }
.busca-cerrar:hover{ background: rgba(28,28,28,.12); color: var(--c-ink); }
.busca-cerrar:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 2px; }

/* ⚠️ EL COLOR SUBIÓ DE .62 A .88 Y EL VELO DE .55 A .74. Medido sobre las
   secciones claras del home —donde el fondo desenfocado que se cuela es casi
   blanco— el texto daba 3,42:1, por debajo del 4,5:1 que exige AA para texto
   normal, y fallaba en 10 de 25 posiciones de scroll. */
.busca-estado{
  margin: .9rem .2rem 0;
  font-size: .85rem;
  color: var(--c-grey-text);
  text-align: center;
}
.busca-lista{
  margin: .9rem 0 0;
  padding: 0;
  list-style: none;
  max-height: min(46vh, 26rem);
  overflow-y: auto;
  border-radius: var(--radius);
}
.busca-lista:not(:empty){
  background: #fff;
  border: 1px solid var(--c-line);
}
.busca-lista a{
  display: block;
  padding: .8rem 1.1rem;
  color: var(--c-ink);
  text-decoration: none;
  border-bottom: 1px solid var(--c-line);
}
.busca-lista li:last-child a{ border-bottom: 0; }
.busca-lista a:hover,
.busca-lista a:focus-visible{ background: var(--c-mist); color: var(--c-ink); }
.busca-lista a:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: -2px; }
.busca-res-seccion{
  display: block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--c-blue);
}
.busca-res-texto{ display: block; margin-top: .2rem; font-size: .92rem; line-height: 1.45; }
.busca-res-texto mark{ padding: 0 .1em; color: var(--c-ink); background: rgba(45,98,234,.18); border-radius: 3px; }

/* Realce de la sección a la que se llega desde un resultado. */
@keyframes busca-destello{ from{ box-shadow: inset 0 0 0 3px var(--c-cyan); } }
.busca-destino{ animation: busca-destello 1.6s var(--ease-soft); }
@media (prefers-reduced-motion: reduce){ .busca-destino{ animation: none; } }

/* ⚠️ EN PANTALLAS CHICAS EL BOTÓN DE MENÚ PIERDE LA PALABRA Y QUEDA SÓLO EL
   ICONO. A 390px el conjunto —logo, buscador y botón— no entra con ella: el
   botón mide 115px con la palabra y ~44 sin ella. Conserva su `aria-label`, así
   que para un lector de pantalla no cambia nada. */
@media (max-width: 479px){
  .menu-btn-label{ display: none; }
  .menu-btn{ padding-inline: .75rem; }
}


.site-header.is-scrolled{ padding-block: var(--header-pad-compacto); }
/* Fondo del header a partir del final del hero. La clase la pone js/main.js
   (ver onScrollHeader) y NO se ata a .is-scrolled a propósito: esa se activa a
   los 40px, en medio de la coreografía del hero, donde el storyboard pide que
   solo se vea el botón de menú. Sin esto, el logo —que es blanco— quedaba
   invisible sobre las bandas claras de #areas y #alianzas.
   Solo toca background/shadow: la opacidad y el transform de .brand siguen
   siendo exclusivos de la timeline de GSAP. */
/* ⚠️ EL HEADER NO INTERCEPTA CLICKS EN SU FRANJA VACIA. Viene de la part-2 y
   hay que conservarlo: el header es fijo, transparente y ocupa todo el ancho,
   asi que sin esto se tragaba los clicks de lo que pasa por debajo. El caso
   concreto son las flechas de #testimonios, que quedan a la altura del header
   y se volvian inalcanzables. Solo los controles listados reciben clicks.
   ⚠️ SI SE AGREGA OTRO CONTROL AL HEADER, HAY QUE SUMARLO ACA. Ya pasó una vez:
   la barra horizontal y el buscador se agregaron el 2026-08-13 y quedaron fuera
   de la lista, asi que durante el hero NINGUN enlace del menu respondia — el
   click lo recibia el fondo del hero, que esta por debajo. No es un fallo de
   destino ni de z-index: los enlaces sencillamente no eran clickeables.

   ⚠️⚠️ Y SE LISTAN LOS CONTROLES, NO SUS CONTENEDORES. Al arreglar lo anterior
   se pusieron `.nav-inline` y `.buscador`, que son cajas anchas: el hueco vacío
   entre los enlaces volvía a tragarse los clicks, y se llevó puestas otra vez
   las flechas de #testimonios —justo lo que esta regla existe para proteger—.
   Un contenedor reactivado deshace la regla en toda su superficie. Van los <a>
   y los <button>, que son lo único que tiene que recibir el click. */
.site-header{ pointer-events: none; }
.site-header .brand,
.site-header .nav-inline a,
.site-header .buscador-btn,
.site-header .menu-btn{ pointer-events: auto; }
/* El panel abierto sí recibe eventos en toda su superficie —es una caja opaca,
   no una franja vacía— y se vuelve inalcanzable en cuanto se cierra. */
.site-header .nav-tiene-sub:hover > .nav-sub,
.site-header .nav-tiene-sub:focus-within > .nav-sub{ pointer-events: auto; }


/* La transición va en .site-header y no en .has-bg para que valga en los dos
   sentidos: al entrar y al volver hacia arriba. Se suma a la de `padding` que ya
   estaba; no toca opacity ni transform, que son de la timeline de GSAP. */
.site-header{
  transition: padding var(--dur-micro) var(--ease-soft),
              background var(--dur-normal) var(--ease-soft),
              box-shadow var(--dur-normal) var(--ease-soft);
}
.brand{
  display: flex;
  align-items: center;
  gap: .7rem;
  z-index: 2;
  /* Sin transition sobre opacity/transform a proposito: la timeline scrubeada de
     GSAP escribe estas dos propiedades cuadro a cuadro, y una transition de CSS
     encima hace que el valor pintado quede retrasado respecto del scroll (el
     logo se apagaba y prendia con lag). GSAP es el unico dueño de .brand. */
}
/* OJO: el logo del header ya NO se desvanece por clase.
   Antes habia aqui un `.site-header.is-scrolled .brand{opacity:0}` que lo ocultaba
   a los 40px de scroll, justo cuando los arcos del hero tienen que aterrizar sobre
   el. Ahora la opacidad la maneja exclusivamente la timeline de GSAP
   (js/main.js -> "Coreografia del hero"): se va al empezar el scroll y vuelve
   cuando los arcos encajan. No volver a animar .brand desde CSS: se pelean.

   Del 2026-08-06 al 2026-08-16 hubo un SEGUNDO dueño, en un tramo de scroll
   distinto: un ScrollTrigger aparte en initTeamJourney() (js/main.js) apagaba el
   logo al llegar a #equipo y lo dejaba asi hasta el final de la pagina (pedido
   del cliente: de ahi en adelante el header solo muestra el boton de menu). Se
   retiró el 2026-08-16 y hoy el logo se queda; el código de entonces está en
   docs/recorrido-equipo-pin-hasta-2026-09-17.md, por si el pedido vuelve.

   ⚠️ SI VUELVE, LOS DOS DUEÑOS TIENEN QUE ESCRIBIR EN ELEMENTOS DISTINTOS. La
   timeline del hero anima `.brand`; aquel ScrollTrigger animaba SUS HIJOS.
   Antes los dos tocaban `.brand` y se justificaba con que nunca coincidian en
   el tiempo — dejo de ser cierto el 2026-08-16, cuando la portada paso a
   ocultar el logo del header durante TODA la pantalla 1: el `onLeaveBack` del
   equipo le arrancaba el control con `overwrite: true` y el logo reaparecia en
   la portada, encima de los items del menu que ahora ocupan su lugar.
   Animando elementos distintos las opacidades se multiplican y nadie pisa a
   nadie. Si hace falta tocar esto, seguir usando GSAP, no CSS. */
.brand img{ height: 34px; width: auto; }
.brand-logo{
  height: 72px; width: auto; display: block; color: #fff;
  /* ⚠️ HALO OSCURO, Y NO ES DECORATIVO. Desde que el logo se enciende en el
     prólogo (2026-08-12) convive con TODO el recorrido del hero, no sólo con el
     índigo del final. Y ahí lo cruza el arco cian, que es claro: medida la
     luminancia detrás de la caja del logo, en progress 0.21-0.25 el p95 sube a
     0.741 y un logo blanco sin halo quedaba en ~1,8:1.
     `drop-shadow` y no `box-shadow`: el logo es un SVG con transparencia, así
     que la sombra tiene que seguir el contorno de los glifos y del swoosh, no el
     rectángulo de la caja. Dos pasadas: una cerrada que recorta y una abierta
     que oscurece el entorno. */
  filter: drop-shadow(0 1px 2px rgba(8,10,35,.85))
          drop-shadow(0 2px 14px rgba(8,10,35,.6));
}

@media (max-width: 719px){
  .brand-logo{ height: 54px; }
}
.brand-word{
  font-weight: 800;
  font-size: 1.25rem;
  letter-spacing: -.01em;
  color: #fff;
  line-height: 1;
}
.brand-word span{
  display: block;
  font-size: .58rem;
  font-weight: 700;
  letter-spacing: .22em;
  color: var(--c-cyan);
  margin-top: .3em;
}

/* ⚠️ `.header-actions` YA ESTÁ DEFINIDO MÁS ARRIBA, junto a la barra horizontal.
   Acá había una segunda definición de una línea que, por venir después, pisaba
   el `gap` medido y el `min-width: 0` de aquella. Se quitó: una sola definición.
   Si hace falta tocar el hueco del bloque derecho, es la de arriba. */

/* Menu trigger — pill button */
.menu-btn{
  display: inline-flex;
  align-items: center;
  gap: .65rem;
  padding: .75rem 1.5rem .75rem 1.2rem;
  border-radius: var(--radius-pill);
  background: var(--c-indigo-2);
  border: none;
  z-index: 2;
  color: #fff;
  font-weight: 700;
  font-size: .92rem;
  letter-spacing: .01em;
  box-shadow: 0 10px 26px rgba(46,48,146,.35);
  transition: background var(--dur-micro) var(--ease-soft),
              box-shadow var(--dur-micro) var(--ease-soft),
              transform var(--dur-micro) var(--ease-soft);
}
.menu-btn:hover{ background: #3639b5; transform: translateY(-2px); box-shadow: 0 14px 32px rgba(46,48,146,.45); }
.menu-btn-icon{
  width: 17px; height: 13px;
  position: relative;
  flex: none;
}
.menu-btn-icon span{
  position: absolute;
  left: 0; right: 0;
  height: 2px;
  background: #fff;
  border-radius: 2px;
  transition: transform var(--dur-micro) var(--ease-soft), opacity var(--dur-micro) var(--ease-soft), top var(--dur-micro) var(--ease-soft);
}
.menu-btn-icon span:nth-child(1){ top: 0; }
.menu-btn-icon span:nth-child(2){ top: 50%; margin-top: -1px; }
.menu-btn-icon span:nth-child(3){ top: 100%; margin-top: -2px; }
.menu-btn.is-open .menu-btn-icon span:nth-child(1){ top: 50%; margin-top: -1px; transform: rotate(45deg); }
.menu-btn.is-open .menu-btn-icon span:nth-child(2){ opacity: 0; }
.menu-btn.is-open .menu-btn-icon span:nth-child(3){ top: 50%; margin-top: -1px; transform: rotate(-45deg); }

.nav-panel-overlay{
  position: fixed;
  inset: 0;
  z-index: 89;
  background: rgba(12,13,36,.55);
  backdrop-filter: blur(2px);
  opacity: 0;
  visibility: hidden;
  transition: opacity .5s var(--ease-soft), visibility .5s;
}
.nav-panel-overlay.is-open{ opacity: 1; visibility: visible; }

.nav-panel{
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: min(420px, 88vw);
  background: var(--c-indigo-2);
  z-index: 90;
  display: flex;
  flex-direction: column;
  /* ⚠️ `safe center` (2026-09-19): con `center` a secas, cuando la lista no
     entra (ventanas de menos de ~675px de alto) el exceso se repartía también
     hacia arriba, fuera del alcance del scroll, y «Nosotros» subía hasta la
     fila del header. `safe` vuelve a arrancar arriba si no entra; la primera
     línea es el respaldo para navegadores sin `safe`. El padding de arriba
     nunca es menor que el header. */
  justify-content: center;
  justify-content: safe center;
  overflow-y: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding: max(calc(var(--header-h, 98px) + .75rem), clamp(6rem, 14vh, 7.5rem)) var(--gutter) var(--gutter);
  box-shadow: -20px 0 60px rgba(0,0,0,.35);
  transform: translateX(100%);
  opacity: 0;
  visibility: hidden;
  transition: transform .55s var(--ease-soft), opacity .55s var(--ease-soft), visibility .55s;
}
.nav-panel.is-open{ transform: translateX(0); opacity: 1; visibility: visible; }
.nav-panel::-webkit-scrollbar{ display: none; }
.nav-panel ul{ display: flex; flex-direction: column; gap: .7rem; }
.nav-panel a{
  font-size: clamp(1.1rem, 2.6vw, 1.5rem);
  font-weight: 800;
  color: #fff;
}
.nav-panel a:hover{ color: var(--c-cyan); }
.nav-panel-foot{
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgba(255,255,255,.15);
}
/* En ventanas bajas y no tan angostas (tablets y portátiles con zoom) el panel
   se compacta para entrar sin scroll. Sólo achica, y no alcanza a los
   teléfonos en vertical. (2026-09-19) */
@media (min-width: 600px) and (max-height: 700px){
  .nav-panel ul{ gap: .45rem; }
  .nav-panel a{ font-size: clamp(1.05rem, min(2.6vw, 3.4vh), 1.5rem); }
  .nav-panel-foot{ margin-top: 1.25rem; padding-top: 1rem; }
}
.nav-panel-foot .nav-panel-contacts{
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin-bottom: 1.25rem;
}
.nav-panel-foot .nav-panel-contacts a{ font-size: .95rem; font-weight: 600; color: rgba(255,255,255,.75); }
.nav-panel-foot .nav-panel-contacts a:hover{ color: var(--c-cyan); }

/* Social icons — base styles. Shared: the nav panel overrides the colours below. */
.social-row{ display: flex; gap: .7rem; }
.social-row a{
  width: 42px; height: 42px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--c-mist);
  border: 1px solid var(--c-line);
  transition: background var(--dur-micro), transform var(--dur-micro);
}
.social-row a svg{ width: 18px; height: 18px; color: var(--c-ink); }
.social-row a:hover{ background: var(--gradient-brand); transform: translateY(-3px); }
.social-row a:hover svg{ color: #fff; }

.nav-panel-foot .social-row a{ background: rgba(255,255,255,.1); border-color: rgba(255,255,255,.18); }
.nav-panel-foot .social-row a svg{ color: #fff; }
.nav-panel-foot .social-row a:hover{ background: var(--gradient-brand); }
body.nav-open{ overflow: hidden; }

/* ==========================================================================
   Language switcher — demonstrative, fixed to viewport
   ========================================================================== */
/* ==========================================================================
   ⚠️ SÓLO ESPAÑOL VISIBLE — INTERRUPTOR TEMPORAL (2026-08-19)
   ==========================================================================
   El cliente pidió mostrar únicamente Español «por el momento», dejando la
   infraestructura lista para volver a habilitar los otros idiomas.
   Por eso NO se borró nada: los botones de English y Português siguen en el
   HTML de las seis páginas y `js/main.js` los sigue enlazando. Esta única regla
   es todo lo que los oculta.
   ⚠️ `display: none` y no `visibility`/`opacity`: además de esconderlos los saca
   del orden de tabulación y del árbol de accesibilidad, así que tampoco se
   pueden seleccionar con teclado ni los anuncia un lector de pantalla — que es
   lo que se pidió («ni visibles ni seleccionables»).
   PARA VOLVER A HABILITARLOS: borrar este bloque. Nada más. */
.lang-switcher button:not([data-lang="es"]){ display: none; }

.lang-switcher{
  position: fixed;
  top: 50%;
  right: clamp(.6rem, 2vw, 1.1rem);
  transform: translateY(-50%);
  z-index: 80;
  display: flex;
  flex-direction: column;
  gap: .6rem;
}
.lang-switcher button{
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  padding: 0;
  background: transparent;
  border: none;
  opacity: .92;
  transition: opacity var(--dur-micro), transform var(--dur-micro);
}
.lang-switcher button svg{
  width: 24px;
  height: 18px;
  border-radius: 3px;
  box-shadow: 0 4px 12px rgba(12,13,36,.3), 0 0 0 1px rgba(255,255,255,.75);
  display: block;
}
.lang-switcher button:hover{ opacity: 1; transform: translateX(-2px); }
.lang-switcher button.is-active{
  opacity: 1;
  transform: scale(1.12);
}
.lang-switcher button.is-active svg{
  box-shadow: 0 4px 14px rgba(12,13,36,.35), 0 0 0 2px var(--c-cyan);
}

@media (max-width: 900px){
  .container{ padding-right: calc(var(--gutter) + 28px); }
  .lang-switcher button{ width: 26px; }
  .lang-switcher button svg{ width: 21px; height: 15px; }
}
/* ⚠️ Y DE 901 A 1340PX LA BANDERA SE ACHICA Y SE ARRIMA AL BORDE (2026-09-19).
   Ahí el margen lateral (`--gutter`, 36–48px) es menor que lo que ocupa la
   bandera, y la reserva de arriba sólo existe hasta 900: la bandera quedaba
   montada sobre el borde derecho de tarjetas, fotos del directorio y el
   formulario de Contacto (1024x768), o pegada a 0–3px hasta ~1330. Son los
   anchos de los monitores 4:3 y de las tablets. Se usa el mismo tamaño que en
   ≤900 y no se toca el ancho del contenido. Aire medido con el contenido:
   ~10px a 1024, ~15 a 1152, ~17 a 1280. */
@media (min-width: 901px) and (max-width: 1340px){
  .lang-switcher{ right: .4rem; }
  .lang-switcher button{ width: 26px; }
  .lang-switcher button svg{ width: 21px; height: 15px; }
}


/* ==========================================================================
   Hero
   ========================================================================== */
.hero{
  background: var(--gradient-dark);
  color: #fff;
  padding-top: clamp(8.5rem, 16vw, 11rem);
  padding-bottom: clamp(4rem, 8vw, 6rem);
  /* Alto completo de viewport: el hero se pinea mientras corre la coreografia, y
     si mide menos de 100vh se asoma la seccion siguiente por abajo durante el pin.
     svh evita el salto por la barra de direcciones en mobile. */
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
  position: relative;
}
/* ⚠️ EL VIDEO VA POR DEBAJO DE LA FOTO (z-index 0 contra 1). El relevo entre las
   dos pantallas es un fundido de la foto por encima del video, no un intercambio
   de capas: así no hay ni un cuadro con las dos apagadas. El velo va sobre el
   video y no sobre el <video> mismo para que `object-fit` no lo afecte. */
.hero-video{
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: var(--gradient-dark);   /* lo que se ve mientras el video carga */
}
/* ⚠️ EN ESCRITORIO, MIENTRAS EL VIDEO CARGA SE VE SU PRIMER CUADRO (2026-09-16).
   Es el fondo de esta caja y no el atributo `poster` del <video>, por dos cosas
   medidas: con el póster anterior —la foto de la sala de reuniones— al entrar se
   veía la sala y después la ciudad; y como el video no se oculta en móvil (sólo
   lo tapa la foto), un `poster` nuevo se descargaría también en celulares. Un
   fondo CSS sólo se baja cuando la regla aplica, y `.hero-dos-pantallas` existe
   únicamente en escritorio con movimiento normal.
   Es el cuadro t=0: el mismo en que arranca el video y al que vuelve el bucle,
   así que el relevo entre imagen y video no se nota. 1600px y 147 KB: va bajo el
   velo oscuro y sólo hasta que arranca el video. Si se cambia el video, hay que
   volver a sacar este cuadro. */
.hero-dos-pantallas .hero-video{
  background: url("../img/hero-asuncion-poster.webp") center / cover no-repeat, var(--gradient-dark);
}
.hero-video video{
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* ⚠️ DOS VELOS, Y LOS DOS ESTÁN MEDIDOS, NO ELEGIDOS.
   El video es una vista aérea de Asunción a pleno día: tiene cuadros con el
   cielo casi blanco, y encima va texto blanco. Medido con
   `_tools/medir_contraste_video.js` a lo largo de los 59s del clip, con el velo
   anterior (.55) el menú del header quedaba en 3,03:1 — por debajo del 4,5:1 que
   exige AA— en el segundo 46.

   1. El velo general levanta el piso en toda la sección.
   2. El segundo, concentrado arriba, protege la franja del header sin oscurecer
      el resto: el menú es lo que peor la pasa porque cae justo sobre el cielo, y
      subir el velo general lo suficiente para salvarlo apagaba el video entero.

   Si se cambia el video hay que VOLVER A MEDIR: estos valores dependen de lo
   claro que sea el clip, no del diseño. */
.hero-video::after{
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(4,6,22,.82) 0%, rgba(4,6,22,.34) 26%, rgba(4,6,22,0) 40%),
    linear-gradient(180deg, rgba(6,8,26,.62) 0%, rgba(6,8,26,.52) 45%, rgba(6,8,26,.74) 100%);
}
/* Sin JS el video se queda puesto y la pantalla 2 va debajo, en flujo normal:
   ahí el video no puede ocupar toda la sección o taparía el párrafo. */
.hero-bg{
  position: absolute;
  inset: 0;
  z-index: 1;
}
.hero-bg img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.15);
  /* ⚠️ EN COLOR Y CON POCO DESENFOQUE — pedido del cliente (2026-08-13), que
     revierte el blanco y negro que habían tenido estos fondos.
     Las BANDAS del hero siguen en blanco y negro: la diferencia es deliberada,
     no un olvido. Los fondos son otra cosa —atmósfera detrás del texto— y el
     cliente los quiere con color.

     El 8px sale de medir, no de gusto: se probó el contraste del titular en el
     cierre —el peor caso, con el fondo al 100% detrás del texto— con 16, 12, 10,
     8, 6 y 4px, y da 19,6–19,8:1 en TODOS. O sea que el desenfoque no es lo que
     sostiene la legibilidad; eso lo hace el velo de `.hero-bg::after`. Con esa
     restricción fuera, se eligió la mitad del valor anterior: se nota que hay
     menos blur y la foto sigue leyéndose como fondo y no como una imagen que
     compite con el titular. Si se baja mucho más, el problema deja de ser el
     contraste y pasa a ser el ruido visual detrás del texto. */
  filter: blur(8px) saturate(1.15);
}
.hero-bg::after{
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(8,8,10,.35) 0%, rgba(8,8,10,.22) 45%, rgba(8,8,10,.5) 100%);
}
/* ⚠️ APAGADO POR CSS, NO POR JS. El segundo fondo sólo existe para el relevo del
   titular, que es cosa del epílogo de desktop: por debajo de 980px y con
   movimiento reducido no hay timeline que lo encienda, y sin este `opacity: 0`
   se quedaría tapando al primero —van los dos en `z-index: 0` y éste va después
   en el DOM—. Lo enciende la timeline y sólo ahí. */
.hero-bg--alt{ opacity: 0; }

/* --------------------------------------------------------------------------
   PROLOGO — velo indigo + logo centrado (3er boceto)
   ORDEN DEL APILADO DEL HERO. Si se agrega una capa nueva, ubicarla en esta
   escala; el hueco entre el velo y el logo es lo que hace que los arcos se
   lean "saliendo por detras" del logo:
       .hero-panels        0    fotos en bandas
       .hero-bg / velo     1    fondo desenfocado + velo indigo
       .hero-arcs-svg      2    arcos de marca
       .hero-intro-logo    3    logo del prologo
       .hero-content       4    titular, eyebrow, botones
       .hero-counter       5    caja de vidrio con los datos
       .hero-notes         5    textos de las bandas (comparte nivel con el
                                contador: van en las esquinas, nunca se pisan)
       .hero-scroll-hint   6    flecha
   -------------------------------------------------------------------------- */
.hero-intro-veil{
  position: absolute;
  inset: 0;
  z-index: 1;
  display: none;              /* lo enciende el JS solo en desktop */
  /* El radial oscurece el centro: sin el, el arco indigo del logo (#2e3092) se
     pierde contra el tramo indigo del degradado, que termina en ese mismo color. */
  background:
    radial-gradient(closest-side at 50% 46%, rgba(6,6,16,.60), rgba(6,6,16,0) 78%),
    var(--gradient-dark);
}
.hero-intro-logo{
  position: absolute;
  left: 50%;
  top: 46%;
  z-index: 3;
  display: none;              /* lo enciende el JS solo en desktop */
  /* Bajado de min(38rem, 62vw) por pedido del cliente: ocupaba casi todo el
     ancho del encuadre. OJO: este ancho no es solo estético — los arcos NACEN
     sobre el swoosh de este logo (matForLogo(introLogo) en js/main.js lo mide
     con getBoundingClientRect), así que tocarlo cambia el tamaño inicial de los
     arcos. Se recalcula solo; lo que hay que rever al cambiarlo es que el
     crecimiento hasta STEEP siga leyéndose bien. */
  width: min(24rem, 40vw);
  height: auto;
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.hero-panels-on .hero-intro-veil,
.hero-panels-on .hero-intro-logo{ display: block; }

/* --------------------------------------------------------------------------
   Paneles de foto en bandas curvas (cuadro 1 del storyboard)
   Tres capas a pantalla completa, cada una recortada por su <clipPath> en
   px del hero. GSAP reescribe el `d` de esos paths con el
   scroll: las curvas arrancan empinadas y se acuestan hasta seguir la
   curvatura del swoosh.
   Sin blur a proposito: el fondo unico si va desenfocado, pero en una
   composicion de paneles las fotos tienen que leerse. El contraste del texto
   no sufre porque los textos aparecen recien al final, cuando el fondo ya es
   el degradado indigo.
   -------------------------------------------------------------------------- */
.hero-panels{
  position: absolute;
  inset: 0;
  z-index: 0;
  display: none;            /* se enciende solo en desktop, desde el JS */
}
.hero-panel{
  position: absolute;
  inset: 0;
  overflow: hidden;
  will-change: clip-path;
}
.hero-panel--1{ clip-path: url(#heroBand1); }
.hero-panel--2{ clip-path: url(#heroBand2); }
.hero-panel--3{ clip-path: url(#heroBand3); }
.panel-ph{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Blanco y negro por pedido del cliente (2026-08-12). Va acá, sobre las seis
     fotos de los tres paneles, y no retocando los archivos: así el material
     original queda intacto y cambiarlo es una línea.
     ⚠️ En el <img> y no en el .hero-panel: el panel lleva el clip-path del arco
     y además el velo de color de abajo, que SÍ tiene que seguir en color. */
  filter: grayscale(1);
}
.panel-ph--b{ opacity: 0; }
/* Velo por panel: unifica fotos de exposiciones distintas y sostiene el
   contraste del boton de menu, que flota encima desde el primer cuadro. */
.hero-panel::after{
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(8,8,10,.45) 0%, rgba(8,8,10,.30) 50%, rgba(8,8,10,.55) 100%);
}
/* Linea de luz en el borde de cada banda: marca el corte entre paneles. */
.hero-panel--2::before,
.hero-panel--3::before{
  content: "";
  position: absolute;
  inset: 0;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14);
}

/* En desktop con animacion, los paneles tapan al fondo unico. La clase la
   pone js/main.js una vez que confirma que hay GSAP y ancho suficiente. */
.hero-panels-on .hero-panels{ display: block; }
/* El fondo desenfocado ya NO se apaga por clase: durante el prologo tiene que
   verse, y lo desvanece la timeline al terminarlo. */
.hero > .container{ position: relative; z-index: 1; }
.hero-top{
  display: flex;
  align-items: center;
  gap: 2rem;
}
/* --------------------------------------------------------------------------
   Arcos de marca — SVG a pantalla completa sobre las fotos
   Los `d` los escribe js/main.js en px del hero (el SVG no tiene viewBox, asi
   que sus unidades de usuario SON px). Los mismos numeros alimentan los
   clipPath de las bandas, por eso arcos y cortes nunca se despegan.
   -------------------------------------------------------------------------- */
.hero-arcs-svg{
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  overflow: visible;
}
#arcsGroup{ will-change: transform; }

/* Estado previo a que corra el JS: los arcos todavia no tienen `d`, asi que no
   se ve nada. Si el JS no corre nunca, el hero queda con su fondo unico. */
.js-anim .hero-arcs-svg{ opacity: 0; }

.hero-content{ position: relative; z-index: 4; max-width: 640px; flex: 1 1 420px; min-width: 0; }
/* Override deliberado del h1 global (clamp(2.4rem,5.5vw,4.6rem)): el titular
   del hero convive con la coreografia y a 4.6rem se comia el encuadre.
   Pero estaba en 3.1rem, o sea 49.6px a 1440 — contra 46.4px de los h2. Tres
   pixeles de diferencia no son una jerarquia: el h1 y los titulares de seccion
   se leian del mismo tamano. Subido a 3.5rem (56px) para que quede un escalon
   claro (1.21x sobre el h2) sin volver al tamano completo, que agregaba lineas
   y desbordaba el hero. Medido: sigue entrando en 3 lineas a 1440. */
/* --------------------------------------------------------------------------
   TITULAR ROTATIVO DEL HERO — dos frases en la misma celda
   --------------------------------------------------------------------------
   La 2da frase trae el mensaje de la seccion "Nosotros" de la part-2, que se
   elimino como seccion aparte: su contenido vive aca. El relevo entre las dos
   lo hace la timeline del hero atado al scroll (js/main.js, tramo EPILOGO).

   ⚠️ LAS DOS OCUPAN LA MISMA CELDA DE GRID, no van una debajo de la otra. Si
   se apilaran en flujo normal, el bloque mediria el alto de las dos sumadas y
   el hero saltaria al cambiar de frase; asi mide el alto de la mas larga y
   queda quieto. Es el mismo recurso que usan .counter-item y .note-item.

   El tamano (3.5rem) es el override deliberado del h1 global que documenta el
   encabezado de este archivo: a 4.6rem el titular se comia el encuadre. -->
   -------------------------------------------------------------------------- */
.hero-titles{
  display: grid;
  margin-top: 1.1rem;
}
.hero-titles > .hero-title{
  grid-area: 1 / 1;
  margin: 0;
  font-size: clamp(2.1rem, 4.2vw, 3.5rem);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -.02em;
  text-shadow: 0 4px 24px rgba(10,10,28,.45);
}
/* Sin pin no hay scroll que gobierne el relevo, asi que las dos frases tienen
   que poder leerse a la vez: el bloque vuelve a flujo normal y la 2da frase
   baja a tamano de bajada, debajo del titular. De esta forma el mensaje de
   "Nosotros" no se pierde en mobile ni con reduced-motion —seria el unico
   lugar del sitio donde vive— y no hace falta JS para que se vea. */
@media (max-width: 979px){
  .hero-titles{ display: block; }
  .hero-titles > .hero-title--alt{
    margin-top: 1rem;
    font-size: clamp(1.05rem, 3.2vw, 1.35rem);
    font-weight: 600;
    line-height: 1.5;
    letter-spacing: 0;
    color: rgba(255,255,255,.92);
  }
}
@media (prefers-reduced-motion: reduce){
  .hero-titles{ display: block; }
  .hero-titles > .hero-title--alt{
    margin-top: 1rem;
    font-size: clamp(1.05rem, 1.6vw, 1.25rem);
    font-weight: 600;
    line-height: 1.6;
    letter-spacing: 0;
    color: rgba(255,255,255,.92);
  }
}

/* --------------------------------------------------------------------------
   Reveal del titulo (SplitType con types:'lines, words')
   Cada .line actua de mascara y las .word entran desde abajo en cascada.
   El padding/margin negativo evita que la mascara recorte las colas de las
   letras (j, g, y) y los acentos.
   -------------------------------------------------------------------------- */
.hero-title .line{
  display: block;
  overflow: hidden;
  overflow: clip;
  padding: .12em 0 .14em;
  margin: -.12em 0 -.14em;
}
.hero-title .word{ display: inline-block; will-change: transform; }
.hero-content .eyebrow{ text-shadow: 0 2px 12px rgba(10,10,28,.4); }
.hero-content .btn-row{ margin-top: 2rem; }

/* --------------------------------------------------------------------------
   Contadores del centro (cuadros 1 y 2 del 2do storyboard)
   Los cuatro datos ocupan la MISMA celda de grid y se muestra uno por vez, asi
   la caja toma el tamano del mas grande y no salta al cambiar de dato.
   -------------------------------------------------------------------------- */
/* ⚠️ SIN VIDRIO Y AL COSTADO — cambio pedido por el cliente.
   Antes esto era una caja de vidrio esmerilado (backdrop-filter) centrada en el
   encuadre. Ahora el dato va suelto sobre la composición y anclado al BORDE
   IZQUIERDO, con el número grande al estilo de la referencia del cliente.
   Comparte la columna izquierda con .hero-note--left, que va justo debajo: los
   dos usan el mismo `left` y el mismo ancho, así se leen como un solo bloque.
   Si se vuelve a mover, moverlos a los DOS. */
/* ⚠️ ESTA POSICIÓN NO ES ESTÉTICA, ES GEOMÉTRICA. NO MOVER SIN VOLVER A MEDIR.
   Los arcos barren TODO el encuadre al pasar de diagonal a horizontal, así que
   casi ninguna caja fija queda libre de ellos. Se midió con `isPointInFill`
   sobre los tres <path> a lo largo de todo el recorrido, y la única zona que
   ningún arco pisa mientras se ven los contadores es un TRIÁNGULO en la esquina
   inferior izquierda. A 1440x900 ese triángulo es x < 165 e y > 695; se angosta
   rápido hacia la derecha (en x=300 ya llega hasta abajo de todo).
   De ahí salen el ancho tope de 9rem y el `bottom` de estos dos bloques.
   El script de medición quedó en las notas de la Etapa 7 del changelog. */
.hero-counter{
  position: absolute;
  /* ⚠️ ALINEADO AL LOGO — pedido del cliente (2026-08-12). Misma fórmula que el
     .container del header, que es lo que posiciona al logo. VER LA NOTA
     GEOMÉTRICA DE ABAJO ANTES DE TOCARLO: correrlo a la derecha lo mete en la
     parte angosta del triángulo libre de arcos, así que este valor NO se puede
     cambiar sin volver a correr _tools/medir_contador.js. */
  left: calc(max(0px, (100% - var(--max-width)) / 2) + var(--gutter));
  /* El triángulo libre se ENSANCHA hacia abajo, así que cuanto más pegado al
     borde inferior, más grande puede ser el número. De ahí el 4%: es lo que
     permite el tamaño que pidió el cliente sin pisar el arco verde. */
  /* ⚠️ BAJADO DE 4% A 2%, y no por gusto: el triangulo libre se ENSANCHA hacia
     abajo, asi que cada px que baja el bloque compra ancho, y el ancho es lo
     que limita el tamano del numero. */
  bottom: 2%;
  z-index: 5;                 /* sobre los arcos (2) y el logo del prologo (3) */
  display: none;              /* lo enciende el JS solo en desktop */

  /* ==== ESCALA DEL CONTADOR — MEDIDA, NO ELEGIDA ====================
     El cliente pidio el contador "mas grande" al unificar las dos partes del
     sitio, y pidio el maximo que permitiera la geometria. Esto es ese maximo.
     Antes: .hero-counter width min(10rem,12vw) y .counter-num font-size
     clamp(2.2rem, min(6vw,9vh), 6rem).

     El `font-size` vive ACA y no en .counter-num, para que el ancho de la caja
     pueda expresarse en `em` y quedar atado al numero por construccion (ver
     `width` abajo). .counter-num es `font-size: 1em`.

     ---- COMO SE MIDIO ----
     El bloque tiene que entrar entero en el triangulo libre de arcos de la
     esquina inferior izquierda (leer la nota geometrica de arriba). Se
     construyo una MASCARA DE AREA de ese triangulo con isPointInFill sobre los
     tres <path>, en 40 puntos del recorrido y en seis tamanos de pantalla, y se
     busco el rectangulo maximo anclado en esta posicion.

     ⚠️ Muestrear solo el PERIMETRO del rectangulo NO sirve: los arcos son
     bandas rellenas y una banda puede cruzar el rectangulo de lado a lado sin
     tocar ningun punto del borde. El primer intento de medicion daba resultados
     no monotonos por esto.

     Frontera medida — alto del bloque -> ancho disponible:

                     alto 72px   96px   120px   144px
         1920x1080        312    296     280     264
         1600x900         232    224     208     192
         1440x900         216    200     192     176
         1366x768         184    168     152     144
         1280x800         184    168     152     136
         1024x700         144    128     112      96

     ---- POR QUE LA MEJORA ES MODESTA EN PANTALLAS CHICAS ----
     ⚠️ EL TERMINO vw YA ESTABA CASI EN SU TOPE. El presupuesto de ancho es, en
     los seis tamanos, entre el 11.6% y el 13.8% del ancho del viewport, y la
     caja necesita 1.9em: de ahi que el vw no pueda pasar de ~6.3. El margen que
     habia estaba en el termino vh —las pantallas ALTAS tenian sitio de sobra y
     el 9vh anterior lo desperdiciaba—, y de ahi sale casi toda la mejora.

     ---- ⚠️ COMO SE MIDE, Y COMO NO ----
     El ScrollTrigger del hero usa `scrub: 1`: interpola hacia el valor objetivo
     con ~1 segundo de retardo. Medir haciendo scroll y leyendo unos milisegundos
     despues devuelve estados INTERMEDIOS, y como el retardo depende del ritmo de
     los rAF, el resultado cambia entre corridas: hubo valores que pasaban una vez
     y fallaban la siguiente. _tools/medir_contador.js toma la timeline y la
     recorre con animation.progress(), que escribe los valores de forma sincrona.
     Cualquier medicion de esta zona tiene que hacerse asi.

     Resultado (numero en px, antes -> ahora), comprobado en 16 resoluciones:
         1920x1080   96 -> 109  (+14%)      1366x768   69 -> 78  (+13%)
         1600x900    81 ->  91  (+12%)      1280x800   72 -> 77  (+7%)
         1440x900    81 ->  86  (+6%)       1024x700   61 -> 61  (=)

     ⚠️ A 1024x700 NO SE PUEDE AGRANDAR NADA, y no es un olvido: en ese tamano el
     termino que manda es el vw y el presupuesto de ancho da justo para lo que ya
     tenia. Lo que si se gano ahi es margen: la caja pasa de 123px a 117px para
     los mismos glifos, porque ahora esta atada al numero con `em` en vez de a un
     12vw suelto. La mejora sale de las pantallas ALTAS, que es donde habia sitio
     y donde el 9vh anterior lo desperdiciaba.

     ⚠️ Y NO SE PUEDE MUCHO MAS EN ESTA POSICION. Medido: el hueco de la esquina
     inferior izquierda da, con un 10% de holgura, un tope de 110px a 1920x1080 y
     de 60px a 1024x700 — o sea que en las pantallas chicas el tamano ANTERIOR ya
     estaba en el limite. Si hace falta un numero bastante mas grande hay que
     mover el bloque: el rectangulo libre de arcos MAS GRANDE del encuadre esta
     ARRIBA A LA DERECHA (a 1440x900 mide 368x176px y admitiria un numero de
     ~150px), pero ahi hoy estan el boton de menu y las frases rotativas
     (.hero-note--right). Es una decision de diseno, no un ajuste de valor.

     ⚠️ NO SUBIRLO "UN POCO MAS" A OJO. Un intento con 8.6rem/17vw fallaba en
     cuatro de los seis tamanos; otro con min(13rem,12.5vw) fallaba en 1280x800.
     Cualquier cambio se comprueba con:
         node _tools/medir_contador.js
     Si hace falta un numero visiblemente mas grande, el TAMANO no da mas de si
     en esta posicion: hay que cambiar la GEOMETRIA. La via con mas margen es
     poner la ETIQUETA ARRIBA y el numero abajo —el triangulo se ensancha hacia
     abajo, asi que los glifos grandes caerian en la parte ancha—: da un 25-35%
     mas. Es un cambio de diseno, no un cambio de valor.
     ================================================================== */
  /* ⚠️ YA ESTÁ EN EL TECHO. NO INTENTAR AGRANDARLO OTRA VEZ SIN LEER ESTO.
     El 2026-08-12 el cliente volvió a pedir el contador "más visible" y se
     buscó el máximo por bisección con _tools/medir_contador.js, 16 tamaños:

         +10%  → falla en 8 tamaños (arcGreen)
         + 8%  → falla en 5
         + 6%  → falla en 6
         + 5%  → pasa, pero con bottom bajado a 0.6% (5px del borde: feo)
         + 3%  → pasa con el bottom actual

     O sea que lo disponible con margen razonable son ~3 puntos: 109→112px a
     1920 y 86→89px a 1440. No se percibe, y deja el bloque pegado al arco
     verde. Se descartó y se dejó el valor original.
     Lo que sí resolvió el pedido fue la etiqueta en cian (ver .counter-label):
     el problema nunca fue el tamaño ni el contraste, era el peso visual. */
  font-size: clamp(2.6rem, min(6.0vw, 10.1vh), 8rem);

  /* ⚠️ EN `em`, NO EN vw. La caja tiene que medir al menos el ancho de los
     GLIFOS del numero (~1.84em para "58+" en Montserrat 800). Si mide menos, el
     numero se derrama fuera y el rect del bloque deja de representar lo que se
     pinta — y es sobre ese rect que se mide la colision con los arcos, asi que
     la verificacion pasaria estando mal. Con `em` van atados por construccion;
     con dos formulas separadas en vw habia que mantenerlas en sincro a mano.
     El 1.9 son los 1.84 de los glifos mas un pelo de aire a cada lado. */
  width: 1.9em;
  pointer-events: none;
}
.hero-panels-on .hero-counter{ display: block; }

/* Ya no es una "tarjeta": lo único que hace es apilar los cuatro datos en la
   misma celda para que se muestre uno por vez sin que el bloque salte de alto.
   Se conserva el nombre de clase para no tocar los selectores del JS. */
.counter-card{ display: grid; }

.counter-item{
  grid-area: 1 / 1;           /* los cuatro apilados en la misma celda */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  gap: .15rem;
  will-change: transform, opacity;
}
.counter-num{
  /* Grande, como en la web de referencia del cliente. El tope real no es
     estético sino geométrico: el bloque tiene que entrar entero en el triángulo
     libre de arcos de la esquina inferior izquierda (ver la nota de
     .hero-counter). Se acota también por ALTO de viewport —el min() con vh—
     porque en pantallas bajas ese triángulo se achica y el número se salía. */
  /* La escala esta en .hero-counter (leer su nota) y aca solo se hereda: asi el
     `width: 1.9em` del contenedor y los glifos del numero no pueden separarse.
     ⚠️ No poner un tamano concreto aca. */
  font-size: 1em;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.03em;
  color: #fff;
  font-variant-numeric: tabular-nums;   /* que el ancho no baile al contar */
  /* ⚠️ Blanco sólido, no el --gradient-text de las demás cifras del sitio.
     Sin la caja de vidrio detrás, el número se apoya directo sobre las fotos y
     sobre los arcos; el degradado azul→cian se perdía por completo contra el
     arco cian y contra el verde. El blanco se lee sobre las tres bandas y sobre
     cualquier foto. */
  /* Tres sombras y no una: la cerrada (2px) recorta el glifo contra la foto, la
     media (10px) lo despega y la abierta (34px) oscurece el entorno inmediato.
     Hace el trabajo que antes hacía la caja de vidrio, sin caja. */
  text-shadow: 0 2px 10px rgba(8,8,20,.95), 0 0 2px rgba(8,8,20,.9), 0 6px 34px rgba(8,8,20,.6);
}
.counter-label{
  /* ⚠️ EN rem/vw, NO EN em: .hero-counter ahora tiene el font-size del numero y
     un `em` aca daria una etiqueta gigante.
     Sube poco a proposito. La etiqueta ocupa DOS lineas, asi que cada px que
     crece son 2.7px de alto de bloque, y el alto se paga en ancho disponible
     (ver la frontera en la nota de .hero-counter). */
  font-size: clamp(.64rem, .8vw, .78rem);
  font-weight: 800;
  line-height: 1.35;
  letter-spacing: .12em;
  text-transform: uppercase;
  /* ⚠️ CIAN DE MARCA, NO BLANCO — pedido del cliente ("más visible y estético").
     El problema medido NO era de contraste: en blanco el contador ya daba 12,2:1
     sobre el peor tramo de la timeline. Lo que le faltaba era PESO VISUAL sobre
     una composición muy cargada de bandas y foto. El cian resuelve eso sin
     agregar ningún objeto —el cliente hizo sacar la caja de vidrio del hero— y
     de paso separa el dato de su etiqueta.
     Se probaron también halos degradados detrás del bloque: sobre la banda
     índigo plana se leen como una mancha, no como un efecto. Descartado. */
  color: var(--c-cyan);
  text-shadow: 0 2px 10px rgba(8,8,20,.9);
}

/* --------------------------------------------------------------------------
   Textos de las bandas (cuadro 2) — rellenan los dos huecos vacios
   --------------------------------------------------------------------------
   Comparten el nivel 5 del apilado con .hero-counter. Pueden compartirlo porque
   ocupan regiones distintas del encuadre y nunca se superponen: el contador va
   centrado y estos dos van pegados a las esquinas.
   Los cuatro .note-item de cada lado se apilan en la MISMA celda de grid y se
   muestra uno por vez, asi el bloque no salta de alto al cambiar de texto.
   -------------------------------------------------------------------------- */
.hero-notes{
  position: absolute;
  inset: 0;
  z-index: 5;
  display: none;              /* lo enciende el JS solo en desktop */
  pointer-events: none;
}
.hero-panels-on .hero-notes{ display: block; }

.hero-note{
  position: absolute;
  display: grid;
}
/* Derecha: se separa del borde lo suficiente para no chocar con el
   .lang-switcher, que es fixed y esta centrado en vertical. */
.hero-note--right{
  /* max() y no un % pelado: con 15% en un viewport bajo (portatiles de 700px)
     el texto se metia debajo del boton de menu. El piso de 7rem garantiza que
     siempre quede por debajo del header, mida lo que mida la pantalla. */
  top: max(7rem, 15%);
  /* ⚠️ ALINEADA AL BOTÓN «MENÚ» — pedido del cliente (2026-08-12).
     No es un valor a ojo: reproduce exactamente la caja interna del .container
     del header, que es lo que posiciona al botón. `.container` centra un
     max-width y le mete `padding-inline: var(--gutter)`, así que su borde
     interno derecho está a (100% - max-width)/2 + gutter del borde del viewport
     —y a `gutter` a secas cuando la pantalla es más angosta que el max-width,
     de ahí el max() con 0—.
     Medido antes del cambio: la frase caía 264px a la derecha del botón a 1920 y
     42px a 1440. Si cambian --max-width o --gutter, esto se mueve solo. */
  right: calc(max(0px, (100% - var(--max-width)) / 2) + var(--gutter));
  width: min(15rem, 19vw);
  text-align: right;
}
/* ⚠️ CÓDIGO MUERTO, se conserva a propósito. No existe ningún .hero-note--left
   en el HTML: el cliente pidió que la columna izquierda la ocupara solo el
   contador (ver la nota del bloque .hero-notes en index.html). Queda por si esa
   frase vuelve algún día.
   La nota original decía "misma left y mismo ancho que .hero-counter; si se
   mueve uno, mover el otro", y eso YA NO SE CUMPLE: al agrandar el contador su
   `bottom` bajó de 4% a 2% y su ancho pasó a estar atado al tamaño del número.
   Si esta frase vuelve, hay que recalcular su sitio y volver a correr
   _tools/medir_contador.js: las dos comparten el mismo triángulo libre de arcos
   y ahora el contador ocupa más. */
/* Justo debajo del contador, dentro del mismo triángulo libre de arcos.
   Leer la nota geométrica de .hero-counter antes de mover esto. */
.hero-note--left{
  bottom: 3%;
  left: clamp(.75rem, 1.5vw, 1.5rem);
  width: min(9rem, 11vw);
  font-size: clamp(.7rem, .8vw, .8rem);
  text-align: left;
}
.note-item{
  grid-area: 1 / 1;           /* los cuatro apilados en la misma celda */
  font-size: clamp(.88rem, 1.12vw, 1.05rem);
  font-weight: 700;
  line-height: 1.45;
  letter-spacing: .01em;
  color: #fff;
  /* Las bandas de foto que quedan detras cambian de exposicion durante el
     recorrido; sin sombra, el texto se pierde sobre las mas claras. */
  text-shadow: 0 2px 10px rgba(8,8,20,.95), 0 0 2px rgba(8,8,20,.8);
  will-change: transform, opacity;
}
/* Filete cian sobre la frase — mismo pedido que el contador. Ancla el bloque al
   borde derecho y lo hace leer como un elemento de diseño y no como un texto
   suelto sobre la foto.
   ⚠️ Sólo en el bloque de la derecha. El de la izquierda es código muerto (ver
   la nota de .hero-note--left) y además comparte el triángulo libre de arcos con
   el contador: agregarle alto ahí le robaría ancho al número. */
.hero-note--right .note-item::before{
  content: "";
  display: block;
  width: 34px;
  height: 2px;
  background: var(--c-cyan);
  margin: 0 0 .55rem auto;    /* auto a la izquierda: queda pegado a la derecha */
}

/* --------------------------------------------------------------------------
   Flecha de scroll — indica que hay que scrollear y saltea la animacion
   -------------------------------------------------------------------------- */
/* ⚠️ ACÁ ESTABA `.scroll-cue` (etiqueta «Scroll» + flecha animada con
   `@keyframes scroll-nudge`). Se retiró el 2026-09-17 junto con su último
   consumidor, el atajo del equipo #teamSkip: el hero ya usaba `.hero-mouse`
   desde antes. Archivado en docs/recorrido-equipo-pin-hasta-2026-09-17.md. */

.hero-scroll-hint{
  position: absolute;
  left: 50%;
  bottom: clamp(1.5rem, 4vh, 2.75rem);
  transform: translateX(-50%);
  z-index: 6;
}
.hero-panels-on .hero-scroll-hint{ display: flex; }

/* En desktop los datos se muestran en el centro, no en la fila del pie: la fila
   se oculta VISUALMENTE pero sigue en el DOM para lectores de pantalla. */
.hero-panels-on .hero-stats{
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

.hero-stats{
  position: relative;
  z-index: 1;
  margin-top: clamp(3rem, 7vw, 5rem);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.5rem 2rem;
  padding-top: 2.5rem;
  border-top: 1px solid rgba(255,255,255,.14);
}
@media (min-width: 720px){ .hero-stats{ grid-template-columns: repeat(4, 1fr); } }
.stat-num{
  font-size: clamp(1.9rem, 3vw, 2.6rem);
  font-weight: 800;
  background: var(--gradient-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  line-height: 1;
}
.stat-label{
  display: block;
  margin-top: .5rem;
  font-size: .82rem;
  color: rgba(255,255,255,.68);
  font-weight: 600;
}

/* ==========================================================================
   Reveal-on-scroll
   ========================================================================== */
[data-reveal]{
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .9s var(--ease-soft), transform .9s var(--ease-soft);
}
[data-reveal].is-visible{ opacity: 1; transform: translateY(0); }
[data-reveal-group] > *{ transition-delay: calc(var(--i, 0) * 90ms); }

/* ==========================================================================
   Misc utilities
   ========================================================================== */
.text-muted{ color: var(--text-muted); }
.mt-lg{ margin-top: clamp(2rem, 4vw, 3rem); }
.visually-hidden{
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ==========================================================================
   EQUIPO — recorrido horizontal
   ==========================================================================
   Desktop (>=980px): la sección ocupa exactamente un viewport y la pista se
   desplaza en horizontal con el gesto lateral, el arrastre y las flechas
   (js/equipo-recorrido.js); el scroll vertical sigue de largo a #testimonios.
   Hasta el 2026-09-17 la sección se pineaba y la rueda movía la pista.
   Mobile (<980px) y movimiento reducido: la pista es un carrusel nativo con
   scroll-snap, que se arrastra con el dedo.

   ⚠️ ALTURA DE LAS FIGURAS. Los recortes salen todos con el MISMO alto (778px)
   pero con anchos distintos (369–580px), porque cada persona ocupa lo suyo.
   Por eso la foto se dimensiona por ALTO (--fig-h) y el ancho queda en auto: si
   se dimensionara por ancho, la figura más angosta se renderizaría MÁS ALTA que
   las demás y se rompería la línea de piso.

   Los dos socios fundadores fallecidos NO están acá: por pedido del cliente se
   mudan a la sección "Nosotros". Sus recortes siguen en img/equipo/ y sus datos
   en _tools/equipo.json, listos para esa sección.
   ========================================================================== */
.team{
  background: var(--gradient-dark);
  color: #fff;
  overflow: hidden;
  padding-block: clamp(3.5rem, 8vw, 5.5rem);
}
/* ⚠️ LA UNIÓN CON LA FRANJA DEL HERO (2026-09-17). Esta capa es del HERO, no
   del recorrido del equipo: si se toca, volver a medir la unión.
   El cliente pidió que el negro de la franja «se combine con el de abajo». El
   problema es que `--gradient-dark` va a 160°: la primera fila de #equipo NO es
   de un solo color (tinta a la izquierda, casi índigo a la derecha), así que
   ningún pie de franja empataba en todo el ancho. Esta capa pinta de tinta pura
   los primeros 6px —la franja termina en ese mismo tono y con los mismos 6px
   planos (TINTA_PLANO en js/main.js)— y se desvanece hasta 60vh; de ahí para
   abajo #equipo queda idéntico al píxel.
   Sólo con `.hero-dos-pantallas`, que es cuando existe la franja: por debajo de
   980px, con movimiento reducido o sin JS el hero no la tiene y #equipo sigue
   como siempre. */
.hero-dos-pantallas .team{
  background:
    linear-gradient(180deg, var(--c-ink) 0, var(--c-ink) 6px, transparent 60vh),
    var(--gradient-dark);
}
.team-head{ position: relative; z-index: 2; }
.team-head h2{ margin-top: .75rem; }
.team-lede{ color: rgba(255,255,255,.72); margin-top: 1rem; max-width: 46ch; }

/* El estado POR DEFECTO es un carrusel nativo que se arrastra con el dedo, y el
   recorrido lo reemplaza recién cuando js/equipo-recorrido.js confirma que hay
   GSAP y ancho suficiente (clase .team-pin-on). Al revés —overflow:hidden por
   defecto— si el JS no corre quedarían 24 de los 30 profesionales inalcanzables. */
.team-viewport{
  position: relative;
  margin-top: clamp(2rem, 4vw, 3rem);
  overflow-x: auto;
  overflow-y: hidden;
  /* ⚠️ `contain` (2026-09-17): al llegar al extremo del carrusel, el gesto
     lateral no se encadena a la página, que en Chrome/Mac lo convertía en
     «atrás» del navegador. Inocuo en modo recorrido (overflow:hidden). */
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* Difumina los dos extremos para que las figuras entren y salgan de cuadro
     en vez de cortarse a filo. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
}
.team-viewport::-webkit-scrollbar{ display: none; }
.team-member{ scroll-snap-align: center; }
.team-pin-on .team-viewport{
  overflow: hidden;
  scroll-snap-type: none;
  /* ⚠️ GESTOS DEL RECORRIDO (2026-09-17). El dedo en VERTICAL es de la página
     (scroll nativo) y el pellizco sigue siendo zoom; el horizontal lo toma
     js/equipo-recorrido.js con Pointer Events. Hasta esa fecha, con el pin, el
     dedo vertical movía la pista. */
  touch-action: pan-y pinch-zoom;
}
/* Arrastrar con el mouse no selecciona nombres ni arrastra fotos o el enlace de
   la ficha como archivo (decisión 11 del plan). Los nombres se copian desde
   equipo.html. */
.team-pin-on .team-track{ -webkit-user-select: none; user-select: none; }
.team-pin-on .member-photo{ -webkit-user-drag: none; }
/* Mientras se arrastra, nada bajo el cursor toma :hover (color y nombre
   parpadeaban al pasar cada ficha). Lo pone el JS sólo pasado el umbral. */
.team-arrastrando .team-track{ pointer-events: none; }
/* El anillo global de :focus-visible va 3px AFUERA y quedaría bajo la máscara
   que difumina los costados: se lo mete adentro. */
.team-viewport:focus-visible{ outline-offset: -4px; }
@media (hover: hover) and (pointer: fine){
  .team-pin-on .team-viewport{ cursor: grab; }
  .team-arrastrando .team-viewport{ cursor: grabbing; }
}

/* --------------------------------------------------------------------------
   Flechas del recorrido (#teamPrev / #teamNext)
   --------------------------------------------------------------------------
   Para quien usa mouse: sin pin la rueda vertical pasa de sección y ya no
   recorre el equipo (pedido expreso del cliente, 2026-09-17). El aspecto es el
   de Testimonios: ver `.testi-arrow, .team-arrow`.
   ⚠️ LA VISIBILIDAD LA GOBIERNA `.team-pin-on`, NO `hidden`. Un `[hidden]` con
   `display:flex` encima necesita una regla aparte, y no hace falta ningún JS que
   las encienda: existen sólo en modo recorrido.
   ⚠️ POSICIÓN ABSOLUTA, NO GRILLA. `.team-head` es `position: relative`; meter
   las flechas en el flujo movía la volanta, que _tools/verificar.js alinea con
   las del resto de las secciones. */
.team-nav{ display: none; }
.team-pin-on .team-nav{
  display: flex;
  gap: .7rem;
  position: absolute;
  right: var(--gutter);
  bottom: 0;
}
/* El extremo se marca con aria-disabled (no `disabled`, que perdería el foco). */
.team-arrow[aria-disabled="true"]{ opacity: .35; cursor: default; }
.team-arrow[aria-disabled="true"]:hover{ background: transparent; border-color: rgba(255,255,255,.3); }
.team-track{
  /* Alto de la figura EN REPOSO. La activa crece por transform, sin tocar el
     layout: ver .team-member.is-active .member-photo. */
  /* ⚠️ `--fig-h-base` ES EL TAMAÑO EN REPOSO QUE HUBO HASTA EL 2026-09-16, y de
     él salen los dos tamaños que se ven hoy (ver el bloque @media de abajo).
     Su tope de 348px era LA NITIDEZ: las fotos miden 329x460 y la activa del
     recorrido se escala x1.32, así que 348 daban 459px, justo bajo el alto del
     archivo. El 2026-09-15 el cliente eligió ese límite; el 2026-09-16 pidió
     las fotos más grandes y eligió, entre tres opciones, agrandarlas AUNQUE
     PIERDAN NITIDEZ. Se buscaron originales más grandes antes de aceptarlo: los
     30 del sitio actual miden también 329x460 (29 de 30). Con fotos de la
     sesión en mayor resolución esto dejaría de ser un compromiso.
     Antes: clamp(185px, 28vh, 310px). */
  /* ⚠️ Y EL ALTO DE LA VENTANA TAMBIÉN ACOTA, Y ESE LÍMITE NO SE NEGOCIA. En el
     recorrido .team mide la pantalla y centra su contenido; con 39vh a secas, a
     1366x768 y 1280x700 el bloque crecía tanto que la volanta quedaba debajo del
     header fijo. El contenido medía unos `--fig-h × --fig-scale + 205px`
     (volanta, título, pista, barra) y tiene que dejar libre el alto del header
     arriba y abajo: de ahí los 400px. Desde el 2026-09-17 no hay barra y el
     bloque mide ~47px menos: los 400px quedaron con margen de sobra, y la
     volanta ya no toca el borde del header (a 1440x900 estaba a 0px). */
  --fig-scale: 1.32;
  --fig-h-base: clamp(185px, min(39vh, calc((100svh - 400px) / var(--fig-scale))), 348px);
  --fig-h: var(--fig-h-base);
  /* Cuánto se abre cada lado cuando una figura crece. Las 28 fotos comparten la
     proporción 329:460, así que el ancho sale del alto sin medir en JS. */
  --fig-w: calc(var(--fig-h) * 329 / 460);
  --crece: calc(var(--fig-w) * (var(--fig-scale) - 1) / 2);
  /* Ancho de celda UNIFORME. Cada celda lleva la columna del nombre a la
     izquierda —invisible mientras la ficha está inactiva— y la figura a la
     derecha. Es lo que permite que la activa se agrande y muestre su nombre sin
     que cambie ni un ancho: si las celdas se expandieran como en la referencia,
     habría que recalcular la geometría del recorrido cada vez que cambia el foco
     y la pista se correría sola bajo el gesto. */
  --cell-w: clamp(255px, 25vw, 400px);
  --name-w: clamp(6.5rem, 9.5vw, 10.5rem);
  display: flex;
  align-items: flex-end;
  gap: 0;                     /* las celdas se tocan: las separa el filete */
  padding-left: var(--gutter);
  /* Aire arriba para que la figura activa crezca sin que la recorte el
     viewport, que en modo recorrido va con overflow:hidden. */
  padding-top: calc(var(--fig-h) * (var(--fig-scale) - 1) + 1.5rem);
  /* Sin línea de piso: la sacó el cliente. Las figuras siguen apoyadas en la
     misma base porque la pista alinea por abajo (`align-items: flex-end`) y
     todas las fichas miden lo mismo — la línea era decorativa, no estructural.
     Los filetes VERTICALES entre celdas se mantienen. */
}
/* ⚠️ FOTOS MÁS GRANDES EN ESCRITORIO (2026-09-16), pedido del cliente sobre la
   vista inicial de la sección. Dos tamaños, los dos a partir de `--fig-h-base`:

   1. VISTA SIN RECORRIDO (hasta el 2026-09-17 era la vista de todo visitante
      antes de pulsar «Recorré el equipo completo»; desde que el recorrido
      arranca solo, en escritorio sólo se ve con movimiento reducido, sin JS o
      en los ≤2,5 s que el recorrido espera a las webfonts): base × 1.32, o sea
      el tamaño que alcanza la activa en el recorrido. Ahí ninguna foto crece,
      pero la pista igual reservaba arriba el espacio del crecimiento
      (`--fig-h × 0.32`): eran los 120–180px vacíos que se veían sobre las fotos.
      Se usa ese espacio y la reserva baja a 1.5rem, así que la sección medía lo
      mismo que antes (medido en 5 tamaños; desde el 2026-09-17, sin la barra de
      avance, mide 42–56px menos). +32% en todos los anchos de
      escritorio, y hasta 459px de alto: sigue siendo nítida.
      Las celdas se ensanchan solas —el `<li>` no puede quedar más angosto que
      nombre + hueco + foto— y no chocan: medido, 0 cruces nombre/foto y 0
      invasiones de la celda vecina. A 1000px de ancho entran 2 fichas y no 3.

   2. RECORRIDO: las fotos en reposo, base × 1.15, y la activa sigue creciendo
      x1.32 sobre ellas — ahí está la pérdida de nitidez que eligió el cliente:
      hasta 528px de alto con un archivo de 460 (un 15% estirada).
      ⚠️ PERO EL +15% SÓLO SE DA SI ENTRA EN LA VENTANA. El `min()` con
      `(100svh - 400px) / --fig-scale` es el mismo límite de alto de siempre:
      en ventanas bajas ya estaba al tope, y pasarlo metería la volanta debajo
      del header. Medido: +15% a 1920x1080 y 1920x940, +9% a 1440x900, nada a
      1366x768, 1280x720 ni a ~800px de alto. Para ganar ahí habría que cambiar
      cómo se centra el recorrido en la pantalla, no este número.

   En móvil (<980px) no había cambiado nada; desde el 2026-09-19 el carrusel
   tampoco reserva el crecimiento (ver el bloque de ≤979px). */
@media (min-width: 980px){
  .team-track{
    --fig-h: max(185px, min(calc(var(--fig-h-base) * 1.15), calc((100svh - 400px) / var(--fig-scale))));
  }
  html:not(.team-pin-on) .team-track{ padding-top: 1.5rem; }
  html:not(.team-pin-on) .member-photo{ height: calc(var(--fig-h-base) * var(--fig-scale)); }
  /* ⚠️ EL NOMBRE BAJA LO MISMO QUE CRECE LA FOTO EN EL RECORRIDO (2026-09-16).
     Lo marcó el cliente con dos capturas: «los textos primero están arriba y
     luego bajan; deben estar siempre como el segundo, abajo». En el recorrido
     el nombre está arriba de la celda, pero la foto activa crece desde su base
     y lo sobrepasa en `--fig-h × (--fig-scale − 1)`: el nombre queda al 28% de
     la foto. En la vista inicial la foto ya viene grande y NO crece, así que el
     nombre quedaba pegado al borde de arriba, al 4%, y al arrancar el recorrido
     "bajaba". Este margen es ese mismo crecimiento, y deja el nombre a la misma
     altura relativa en los dos estados (medido, ±1% en 5 tamaños). */
  html:not(.team-pin-on) .member-caption{ margin-top: calc(var(--fig-h-base) * (var(--fig-scale) - 1)); }
}
.team-member{
  flex: 0 0 var(--cell-w);
  align-self: stretch;
  display: flex;
  align-items: flex-end;
  position: relative;
}
/* Filete divisorio entre celdas, como en la referencia.
   ⚠️ ES UN PSEUDO-ELEMENTO Y NO UN `border-left` (2026-09-15): el borde no se
   puede desplazar solo, y el filete tiene que abrirse cuando la figura de al
   lado crece. Ver el bloque "la figura crece desde el centro de su base". */
.team-member::before{
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 1px;
  background: rgba(255,255,255,.09);
  pointer-events: none;
  transition: transform .55s var(--ease-soft);
}
.team-member:first-child::before{ display: none; }
/* La activa se pinta por encima: al crecer invade la columna del nombre de la
   celda siguiente, que está vacía porque su pie es invisible. */
.team-member.is-active{ z-index: 2; }

.member-figure{
  margin: 0;
  width: 100%;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;      /* la figura, pegada a la derecha de su celda */
  gap: clamp(.4rem, .8vw, .9rem);
  padding-inline: clamp(.5rem, .9vw, 1rem);
}
.member-photo{
  height: var(--fig-h);
  width: auto;
  max-width: none;
  flex: none;
  display: block;
  /* ⚠️ origen abajo-CENTRO (2026-09-15). Abajo, para que al crecer la figura no
     despegue los pies de la línea de piso —que es justo lo que costó alinear—.
     Hasta esa fecha era abajo-IZQUIERDA y crecía hacia la derecha, pisando el
     filete de la celda siguiente. El cliente pidió que crezca de abajo hacia
     arriba, parejo a los dos lados, y que lo de alrededor se corra: eso lo hacen
     las reglas de "la figura crece desde el centro de su base". */
  transform-origin: bottom center;
  /* Fuera de foco van desaturadas para que la fila se lea como un conjunto;
     la que está en el centro del recorrido (o bajo el cursor) toma color.

     La sombra de apoyo va como drop-shadow DENTRO del filter, no como
     pseudo-elemento. Dos motivos: sigue el contorno real del recorte en vez de
     ser una elipse genérica, y sobre todo se ancla a la imagen. Antes era un
     ::after sobre .member-figure —que es `static`, así que se posicionaba
     contra .team-member— y la sombra terminaba cayendo debajo del NOMBRE en
     lugar de a los pies de la figura.
     El drop-shadow transparente en el estado base existe para que las dos
     listas de filter tengan las mismas funciones y la transición interpole en
     vez de saltar. */
  filter: grayscale(1) contrast(1.04) brightness(.92) drop-shadow(0 0 0 rgba(0,0,0,0));
  opacity: .5;
  transition: filter .55s var(--ease-soft), opacity .55s var(--ease-soft),
              transform .55s var(--ease-soft);
}
/* ⚠️ El único transform permitido acá es el `scale`, y con origen abajo. Hubo un
   `translateY(6px)` que dejaba a la figura en foco fuera de la línea de piso y
   la fila se leía desalineada. Nada que desplace en vertical. */
.team-member.is-active .member-photo,
.team-member:hover .member-photo,
.team-member:focus-within .member-photo{
  filter: grayscale(0) contrast(1) brightness(1) drop-shadow(0 14px 16px rgba(6,6,20,.5));
  opacity: 1;
}
/* ⚠️ ESCALA SÓLO LA FICHA EN FOCO DEL RECORRIDO, NO LA QUE ESTÁ BAJO EL CURSOR
   (2026-09-15). El color de arriba sigue siendo para las tres; el tamaño, no.
   Dos motivos, medidos en la revisión de ese día:
     · En el recorrido el cursor suele quedar quieto sobre la pista mientras
       pasan las fichas: una en foco por scroll (desde el 2026-09-17, por el
       gesto lateral o las flechas) y la vecina bajo el cursor
       crecían a la vez, el filete se corría para el lado equivocado y una foto
       tapaba el nombre de la otra.
     · Fuera del recorrido `html:not(.team-pin-on) .member-photo{transform:none}`
       perdía por especificidad contra `:hover`, así que la foto SÍ escalaba y,
       con el origen abajo-centro, tapaba su propio nombre, que ahí está visible. */
.team-pin-on .team-member.is-active .member-photo{
  transform: scale(var(--fig-scale));
}

/* --------------------------------------------------------------------------
   Pie de la ficha — nombre y cargo, A LA IZQUIERDA de la figura
   --------------------------------------------------------------------------
   Solo se ve el de la ficha ACTIVA, como en la referencia: las demás muestran
   únicamente la silueta. Se oculta con `opacity`, no con `display:none` ni
   `visibility`, para que siga estando en el árbol de accesibilidad: los 28
   nombres se leen igual con lector de pantalla.

   ⚠️ FILAS FIJAS. La pista alinea por abajo, así que el alto del pie decide
   dónde queda la figura. Con el pie en flujo normal, los nombres que envuelven
   a dos o tres líneas empujaban su figura hacia arriba y la fila se
   desalineaba. Con filas de alto fijo —nombre / cargo— todas las fichas miden
   lo mismo, envuelva o no el nombre. Si se agrega una línea, sumarle su fila.
   -------------------------------------------------------------------------- */
.member-caption{
  flex: 0 0 var(--name-w);
  /* ⚠️ `min-width: var(--name-w)`, NO `0` (2026-09-17). Es redundante en Chrome,
     pero Safari lo necesita: para calcular el ancho mínimo de la celda usa el
     de las PALABRAS del pie e ignora su `flex-basis`, así que la celda le salía
     más angosta que nombre + foto y el pie sobresalía por la izquierda, encima
     de la foto anterior. Medido en WebKit: 27 de 28 pies pisaban la foto
     vecina, hasta 91px a 1920. Con el mínimo explícito, WebKit da las mismas
     celdas que Chrome en 7 tamaños, de 390 a 1920. */
  min-width: var(--name-w);
  align-self: flex-start;
  display: grid;
  /* 2.7rem = dos líneas de nombre, que es el máximo que necesita cualquiera de
     los 28 con el ancho de --name-w (medido, no estimado). Con tres reservadas
     quedaba un hueco visible entre el nombre y el cargo. */
  grid-template-rows: 2.7rem auto;
  align-content: start;
  padding-top: clamp(.5rem, 2vh, 1.75rem);
  text-align: left;
  /* Solo opacidad, sin deslizamiento de entrada. Un `translateY` acá dejaba el
     pie de la ficha activa 8px más arriba que el de las demás — el mismo tipo
     de desalineación que ya hubo que corregir en la figura. La aparición por
     opacidad alcanza y mantiene la fila perfectamente alineada. */
  opacity: 0;
  transition: opacity .45s var(--ease-soft), transform .55s var(--ease-soft);
}
.team-member.is-active .member-caption,
.team-member:hover .member-caption,
.team-member:focus-within .member-caption{
  opacity: 1;
}

/* --------------------------------------------------------------------------
   La figura crece desde el centro de su base, y lo de alrededor se abre
   --------------------------------------------------------------------------
   Pedido del cliente (2026-09-15): que la foto en foco crezca de abajo hacia
   arriba y que "sus elementos se muevan con ese crecimiento (la línea blanca,
   textos de los costados)".

   Al crecer desde el centro, la figura avanza `--crece` hacia cada lado. Sin
   estas reglas se comería su propio nombre por la izquierda y el filete de la
   celda siguiente por la derecha. Así que, exactamente esa distancia y con la
   misma curva y duración que el escalado:
     · a la izquierda se corren el nombre y el filete propios, y TODAS las
       celdas anteriores enteras;
     · a la derecha se corren TODAS las celdas siguientes enteras, y la tarjeta
       de cierre.
   Los huecos quedan medidos igual que en reposo.

   ⚠️ SE CORREN LAS CELDAS ENTERAS, NO SÓLO EL FILETE Y LA FOTO VECINA
   (2026-09-17). Hasta esa fecha a la derecha sólo se corría el filete de la
   celda siguiente, y a la izquierda sólo la foto anterior: como el nombre de
   las vecinas está oculto, no se notaba. Pero el cursor lo muestra (`:hover`)
   y el cliente lo marcó sobre captura: con la activa agrandada, el nombre de
   la celda siguiente quedaba DEBAJO de la foto que crece. Correr sólo ese
   nombre no alcanza: medido, con los nombres largos («José Alberto Ríos»,
   «Elba Britez de Ortiz») pisaba su propia foto hasta 29px. Corriendo la celda
   entera nada cambia de lugar respecto de sus vecinas, salvo la activa, que es
   la que crece. Y al pasar el foco de una ficha a la siguiente sólo se mueven
   esas dos: las demás ya estaban corridas para el mismo lado.

   ⚠️ TODO CON `transform`, NADA QUE MUEVA EL LAYOUT. El recorrido horizontal
   cachea el centro de cada ficha y los recalcula sólo al refrescar: agrandar
   anchos de verdad corría la pista entera cada vez que cambiaba el foco. Un
   transform no toca `offsetLeft`, así que las medidas siguen valiendo.

   Sólo en modo recorrido (`.team-pin-on`): fuera de él las figuras no escalan
   (ver `html:not(.team-pin-on) .member-photo`). */
.team-pin-on .team-member.is-active .member-caption,
.team-pin-on .team-member.is-active::before{
  transform: translateX(calc(-1 * var(--crece)));
}
.team-pin-on .team-member,
.team-pin-on .team-outro{
  transition: transform .55s var(--ease-soft);
}
.team-pin-on .team-member:has(~ .team-member.is-active){
  transform: translateX(calc(-1 * var(--crece)));
}
.team-pin-on .team-member.is-active ~ .team-member,
.team-pin-on .team-member.is-active ~ .team-outro{
  transform: translateX(var(--crece));
}
.member-name{
  align-self: start;
  font-weight: 700;
  font-size: clamp(.88rem, 1.05vw, 1.05rem);
  line-height: 1.25;
  letter-spacing: -.01em;
}
.member-role{
  align-self: start;
  font-size: .7rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--c-cyan);
  opacity: .85;
}

/* --------------------------------------------------------------------------
   Apertura y cierre del recorrido
   --------------------------------------------------------------------------
   El recorrido empieza con el PRIMER profesional centrado y termina con el
   ÚLTIMO centrado, para que a los dos les toque el foco igual que al resto.
   Centrar los extremos deja medio viewport vacío a cada lado, y estas dos
   tarjetas son las que ocupan esos huecos: la de apertura lleva la bajada de la
   sección y la de cierre el conteo y el CTA. `align-self: stretch` para que
   tomen el alto de una ficha completa y su contenido pueda centrarse.

   ⚠️ El ANCHO de .team-intro en modo recorrido lo escribe
   js/equipo-recorrido.js (ajustarApertura()), calculado para que el primer
   profesional caiga exactamente en el centro. El valor del CSS es el que vale en
   el carrusel nativo (móvil), donde no hay recorrido.
   -------------------------------------------------------------------------- */
.team-intro{
  flex: 0 0 auto;
  width: min(22rem, 78vw);
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* ⚠️ EL CONTENIDO ARRANCA DONDE ARRANCA EL LOGO (2026-08-18).
     Estaba pegado a la DERECHA de la tarjeta —`align-items: flex-end`— porque a
     la izquierda caía dentro del 6% que el .team-viewport difumina y se leía
     cortado. El cliente lo pidió alineado con el logo, así que ahora arranca a
     la izquierda pero DESPLAZADO hasta el borde del contenedor de la página, que
     es exactamente donde está el logo: ahí ya no hay difuminado.
     El desplazamiento se calcula, no se escribe a mano (ver .intro-card). */
  align-items: flex-start;
  padding-inline: clamp(1rem, 2vw, 2.5rem);
  scroll-snap-align: center;
}
/* ⚠️ LA CUENTA, PORQUE NO ES OBVIA. El objetivo es que el texto empiece en la
   misma x que el logo del header, que vale `borde del contenedor + gutter`.
   El <li> ya arranca en el gutter y agrega su propio `padding-inline`, así que
   lo que falta es `borde del contenedor − ese padding`. El `max(0px, …)` es lo
   que impide que en pantallas sin margen lateral —1280 y menos, donde el
   contenedor pega contra el borde— la tarjeta se meta en el 6% difuminado:
   ahí se queda donde estaba. Medido: 1920 → x368, 1440 → x128, ambos iguales
   al logo. */
.intro-card{
  max-width: 21rem;
  margin-left: max(0px, calc(max(0px, (100vw - var(--max-width)) / 2) - clamp(1rem, 2vw, 2.5rem)));
}
/* ⚠️ UNIFICADO A 1rem — TAREA DEL 2026-08-19: «no debe haber párrafos grandes
   y pequeños». La prosa corrida del sitio estaba en CINCO tamaños distintos a
   1440px: 18,72 / 16,56 / 16 / 15,84 / 15,2. Ahora toda va a 16px. NO se tocaron
   los rótulos de componente (volanta, cargo en la tarjeta, bajada de tarjeta,
   contador) ni `.lede`, que ya era uniforme en sus 8 usos y es el escalón de
   entrada deliberado. */
.intro-text{
  font-size: 1rem;
  line-height: 1.6;
  color: rgba(255,255,255,.78);
}
/* ⚠️ VOLVIÓ A SER UN RÓTULO <p> (2026-09-17). Del 2026-08-12 al 2026-09-17 fue
   un <button> que enganchaba el recorrido; desde que el recorrido arranca solo
   al llegar a la sección, no hay nada que pulsar. Ver index.html. */
.intro-hint{
  display: flex;
  align-items: center;
  gap: .6rem;
  margin-top: 1.5rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--c-cyan);
}
.intro-hint svg{ width: 20px; height: 20px; flex: none; }

.team-outro{
  flex: 0 0 auto;
  width: clamp(15rem, calc(var(--cell-w) * 1.15), 26rem);
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-left: clamp(1rem, 2vw, 2.5rem);
  scroll-snap-align: center;
}
.outro-card{
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .35rem;
  padding-left: clamp(1.25rem, 2vw, 2rem);
  border-left: 1px solid rgba(255,255,255,.18);
  transition: transform .55s var(--ease-soft);
}
/* ⚠️ CÓDIGO MUERTO, se conserva a propósito (mismo criterio que
   .hero-note--left). El cliente hizo sacar el «+28 / profesionales» de la
   tarjeta de cierre el 2026-08-12 —"también hay que borrar, dejar solo la
   frase"— así que hoy no hay ningún .outro-num ni .outro-label en el HTML.
   Queda por si el dato vuelve. Si vuelve, acordarse de que el número lo escribía
   el JS contando las fichas reales (#teamCount; hoy en js/equipo-recorrido.js),
   para que no quede viejo. */
.outro-num{
  font-size: clamp(2.8rem, 5vw, 4.2rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.03em;
  background: var(--gradient-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-variant-numeric: tabular-nums;
}
.outro-label{
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--c-cyan);
  opacity: .85;
}
.outro-text{
  margin-top: .75rem;
  font-size: 1rem;
  line-height: 1.5;
  color: rgba(255,255,255,.75);
}
.outro-card .btn{ margin-top: 1.35rem; }

/* ⚠️ NO HAY BARRA DE AVANCE (2026-09-17). Había una `.team-progress` bajo la
   pista —riel blanco de 2px con un relleno en degradé— y el cliente la hizo
   quitar sobre captura: «eliminar esta línea blanca». No volver a ponerla sin
   pedirlo. (La OTRA línea blanca, la de la unión con Testimonios, es otra cosa:
   ver la nota en `.testimonios`.) */

/* ⚠️ NO HAY ATAJO «Scroll» (2026-09-17). `.team-skip` (+ `.team-skip-on`)
   saltaba el recorrido con pin; sin pin el scroll vertical ya pasa de sección y
   no queda nada que saltear. Archivado en
   docs/recorrido-equipo-pin-hasta-2026-09-17.md. */

/* --- Desktop: la sección mide un viewport exacto, para que el recorrido entre
   en una pantalla --- */
@media (min-width: 980px) and (prefers-reduced-motion: no-preference){
  .team-pin-on .team{
    height: 100vh;
    height: 100svh;
    padding-block: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0;
  }
  .team-pin-on .team-viewport{ flex: 0 0 auto; }
  /* ⚠️ Aire al final SOLO en modo recorrido. La pista frena con el ÚLTIMO
     profesional en el centro del encuadre, para que le toque el foco igual que
     a todos; sin este aire la pista no tiene por dónde seguir corriendo y el
     recorrido se frenaba con los últimos tres pegados al borde derecho, sin que
     ninguno llegara nunca al centro.
     Va solo bajo .team-pin-on porque en el carrusel táctil este relleno sería
     medio viewport de vacío al que se podría arrastrar. */
  .team-pin-on .team-track{
    will-change: transform;
    /* Aire tras la tarjeta de cierre, para que al centrar al último profesional
       el contenido llegue igual hasta el borde derecho. Va solo en modo
       recorrido: en el carrusel táctil sería espacio muerto al que se podría
       arrastrar. */
    padding-right: max(var(--gutter), 14vw);
  }
  /* ⚠️ LA APERTURA RESERVA A LA DERECHA LO QUE SE ABRE LA PRIMERA FICHA
     (2026-09-19). La ficha activa corre su filete y su nombre `--crece` px a la
     izquierda (hasta 46px), y la apertura sólo tenía `clamp(1rem, 2vw, 2.5rem)`
     de resguardo: el filete cruzaba el texto y el primer renglón se pegaba al
     cargo. En 4:3 se leía «Somos una firma integral,SOCIO SENIOR» (1024x768);
     en 16:9 el filete también cruzaba «integral,» (1920x1080), menos. Sólo el
     padding DERECHO: el izquierdo es el que alinea el texto con el logo, y
     ajustarApertura() ya descuenta el padding, así que la primera figura sigue
     centrada. Medido: +16px de aire en 13 tamaños, Chromium y WebKit. */
  .team-pin-on .team-intro{ padding-right: max(clamp(1rem, 2vw, 2.5rem), calc(var(--crece) + 1rem)); }
  /* Con la columna algo más angosta, el rótulo terminaba en «EQUIPO» solo
     (1920x1080, 1024x768). Repartido parejo: mismos renglones, sin viuda. */
  .team-pin-on .intro-hint span{ text-wrap: balance; }
}
/* ⚠️ PANTALLAS MÁS ALTAS QUE ANCHAS (iPad Pro 12,9" vertical, monitor girado):
   la sección se ajusta al contenido (2026-09-19). Con 100svh y el contenido
   centrado —que mide ~690px porque la figura tiene tope— a 1024x1366 quedaban
   ~350px vacíos arriba y abajo; entrando por «Profesionales», una franja oscura
   vacía bajo el header. Ningún apaisado entra en este media query.
   ⚠️ El selector va atado al modo del hero y no sólo a la proporción: en una
   ventana EXACTAMENTE cuadrada (1:1) se cumplen las dos condiciones —la del
   hero, `min-aspect-ratio: 1/1`, y esta— y el hero arma las dos pantallas;
   ahí #equipo tiene que seguir midiendo una pantalla, como en apaisado. */
@media (min-width: 980px) and (max-aspect-ratio: 1/1) and (prefers-reduced-motion: no-preference){
  html.team-pin-on:not(.hero-dos-pantallas) .team{ height: auto; padding-block: 8rem 6rem; }
}
/* ⚠️ VENTANAS MUY BAJAS (zoom de Windows al 150–175%, o 1366x768 al 125%: menos
   de ~644px de alto útil) (2026-09-19). Ahí el piso de 185px de la figura ya no
   entraba entre el header y el borde: la foto activa se cortaba abajo al entrar
   por el menú. Se baja el piso a 130px y el bloque arranca arriba en vez de
   centrarse. De 644px de alto para arriba no cambia nada. */
@media (min-width: 980px) and (max-height: 643px) and (prefers-reduced-motion: no-preference){
  .team-pin-on .team{ justify-content: flex-start; padding-top: 1.25rem; }
  /* Y la tarjeta de cierre se compacta en vertical: es el ítem más alto de la
     pista (212px), y con la foto más chica sus celdas se estiraban a ese alto
     y dejaban una banda vacía entre el título y las fotos. Sin ensancharla:
     más ancha se pasaba del final del recorrido. */
  .team-pin-on .outro-text{ margin-top: 0; }
  .team-pin-on .outro-card .btn{ margin-top: 0; }
  .team-pin-on .outro-card .btn-row{ margin-top: .75rem; gap: .5rem; }
  .team-track{
    --fig-h: max(130px, min(calc(var(--fig-h-base) * 1.15), calc((100svh - 400px) / var(--fig-scale))));
  }
}

/* --- Mobile / tablet y movimiento reducido: carrusel nativo, sin recorrido --- */
@media (max-width: 979px), (prefers-reduced-motion: reduce){
  /* ⚠️ SIN RESERVA PARA EL CRECIMIENTO (2026-09-19, aprobado por el cliente).
     La pista reserva arriba `--fig-h × 0,32` para que la ficha activa crezca,
     pero en el carrusel ninguna foto crece: eran ~160px vacíos entre el título
     y las fotos, en teléfonos y tablets. Es la misma regla que ya valía en
     escritorio sin recorrido (ver el bloque de ≥980px). */
  html:not(.team-pin-on) .team-track{ padding-top: 1.5rem; }
  /* La tarjeta de cierre está dimensionada para el recorrido de desktop (dos
     anchos de ficha ≈ 420px), que en un móvil de 375 es más que la pantalla y
     dejaba el texto cortado. Acá se la limita al viewport y se le saca el
     filete divisorio, que sin la fila al lado no separa nada. */
  .team-outro{ width: min(20rem, 84vw); padding-left: 0; }
  .outro-card{ border-left: 0; padding-left: 0; }
  /* Sin hover confiable en táctil no hay ficha "activa", así que las figuras
     van siempre legibles y TODOS los nombres visibles: si se mostrara solo el
     de la activa, en móvil no se vería ninguno. */
  .member-photo{ filter: none; opacity: 1; transform: none; }
  .member-caption{ opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   La pista EN REPOSO, sin recorrido
   --------------------------------------------------------------------------
   Sin `team-pin-on` no hay recorrido ni foco: en escritorio pasa con movimiento
   reducido, sin JS o sin GSAP, y durante los ≤2,5 s que el recorrido espera a
   las webfonts. (Del 2026-08-12 al 2026-09-17 también era el estado de todo
   visitante hasta pulsar «Recorré el equipo completo»; hoy el recorrido
   arranca solo.) Ahí el tratamiento apagado de las figuras —que existe para
   destacar a quien está en el centro DURANTE el recorrido— dejaría a las 28
   personas en penumbra a la vez y la sección se vería deslavada, como rota.

   Así que las figuras van legibles y los nombres visibles. Es el mismo criterio
   que en móvil, y por el mismo motivo: sin ficha "activa", mostrar sólo la
   activa no muestra ninguna. */
html:not(.team-pin-on) .member-photo{ filter: none; opacity: 1; transform: none; }
html:not(.team-pin-on) .member-caption{ opacity: 1; transform: none; }

/* ==========================================================================
   ÁREAS DE PRÁCTICA
   ========================================================================== */
/* --------------------------------------------------------------------------
   Grilla de 8 + 8, con expansión al pasar el cursor
   --------------------------------------------------------------------------
   Rediseño 2026-08-13, pedido del cliente con la referencia de guyer.com.uy:
   las 16 áreas en dos filas de ocho, y al pasar el cursor la tarjeta CRECE y
   descubre su descripción. Expresamente SIN el desplazamiento horizontal que
   tiene guyer.

   ⚠️ LO QUE SE FUE, Y NO HAY QUE REPONER SIN PENSARLO:
   · el carrusel paginado de a 4 (`.areas-viewport`, `.areas-track`, `--per`) y
     sus flechas (`.areas-nav`);
   · `initAreas()` en js/main.js, que las gobernaba. La sección es ahora HTML y
     CSS solos: sin JS se ve y se usa igual.

   ⚠️ EL ALTO Y EL CRECIMIENTO SON VARIABLES, no números sueltos: el escalonado
   vertical, el hueco entre filas y la expansión salen todos de ellas y no
   pueden desincronizarse.
   -------------------------------------------------------------------------- */
.areas-grid{
  /* ⚠️ A SANGRE: LA GRILLA VIVE FUERA DEL `.container` (2026-08-13).
     Pedido del cliente: "que agarre todo el ancho de la pantalla, así queda
     mejor en tamaño y distribución". Dentro del contenedor las ocho tarjetas
     se repartían 1184px y quedaban en 140px cada una; a pantalla completa, en
     1920 pasan a 236px.

     ⚠️ SE HIZO MOVIENDO EL `<ul>` EN EL HTML, no con el truco de
     `margin-inline: calc(50% - 50vw)`. Ese truco necesita `100vw`, que en la
     mayoría de los navegadores INCLUYE el ancho de la barra de scroll: con la
     página scrolleada verticalmente —siempre— sobra ~15px y aparece barra
     horizontal. Sacando el nodo del contenedor el ancho lo da el flujo normal
     y el problema no existe.

     El encabezado y el CTA siguen cada uno en su `.container`, alineados a las
     guías del resto del sitio. */
  margin-top: clamp(2rem, 5vw, 3.5rem);
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: clamp(.35rem, .7vw, .6rem);

  /* ✏️ Alto de la tarjeta en reposo. */
  --area-alto: clamp(190px, 18.5vw, 255px);
  /* ✏️ Cuánto baja la tarjeta par respecto de la impar (el escalonado). */
  --area-salto: clamp(16px, 2.2vw, 34px);
  /* ✏️ Cuánto crece al pasar el cursor, por lado.
     ⚠️ EL HORIZONTAL NO PUEDE PASARSE DEL GUTTER. La tarjeta de la punta crece
     hacia afuera del .container, y si crece más que el margen lateral de la
     página asoma barra de scroll horizontal. Medido: a 1440 el gutter es 128px
     y esto da 43px; a 700px el gutter es 28px y esto da 21px. */
  --area-crece-x: clamp(20px, 3vw, 56px);
  /* Tope de 50px y no 70 (2026-09-19): desde ~1334px el crecimiento superaba
     la separación con la bajada (56px) y una tarjeta alta de la primera fila
     tapaba la última línea del texto de arriba («negocio.»). */
  --area-crece-y: clamp(28px, 4.2vw, 50px);
  /* ✏️ Cuánto tarda en crecer. NO usa `--dur-normal` (.7s) a propósito: a esa
     velocidad el texto —que aparece de una, sin animación propia— se iba
     descubriendo despacio detrás del `overflow: hidden` de la tarjeta y se
     leía como si estuviera CARGANDO. El cliente lo marcó comparando con la
     referencia: "debe salir de una". A .22s el crecimiento se sigue viendo
     pero el texto ya está entero antes de que el ojo lo registre. */
  --area-vel: .22s;
}
@media (max-width: 1180px){ .areas-grid{ grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 700px){  .areas-grid{ grid-template-columns: repeat(2, 1fr); } }

.area-card{
  position: relative;
  min-width: 0;
  height: var(--area-alto);
}
/* El escalonado de guyer: las pares bajan.
   ⚠️ ESTE COMENTARIO DECÍA QUE, POR IR SOBRE EL ÍNDICE GLOBAL, LAS FILAS QUEDABAN
   DESFASADAS «porque la de abajo arranca en la 9na, que es impar». Era al
   revés: justamente por ser impar, cada fila repetía la de arriba —columnas
   impares arriba e índigo, pares abajo y azul marino— y la grilla se leía como
   franjas verticales, muy notorio con 4 columnas (4 filas calcadas). Desde el
   2026-09-19 las filas se alternan en DAMERO (ver el bloque de abajo, uno por
   cada cantidad de columnas), aprobado por el cliente también para 8. */
.area-card:nth-child(even){ margin-top: var(--area-salto); }
/* El hueco entre filas tiene que absorber ese salto: si no, la fila de abajo
   sube contra la de arriba. Atado a la misma variable. */
.areas-grid{ row-gap: calc(clamp(.35rem, .7vw, .6rem) + var(--area-salto)); }

.area-card-inner{
  /* ⚠️ ABSOLUTA, y de eso depende TODO el efecto: al crecer no puede empujar a
     las vecinas ni cambiar el alto de la fila. La tarjeta (.area-card) es la
     ranura fija de la grilla; esto es lo que se dibuja y lo único que se mueve. */
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  /* En reposo el nombre se apoya abajo, como en la referencia. */
  justify-content: flex-end;
  gap: .55rem;
  padding: clamp(.85rem, 1.15vw, 1.15rem);
  border-radius: var(--radius);
  color: #fff;
  overflow: hidden;
  /* Se anima cada lado por separado y no el atajo `inset`: así queda explícito
     qué se está moviendo. */
  transition: top var(--area-vel) var(--ease-soft),
              right var(--area-vel) var(--ease-soft),
              bottom var(--area-vel) var(--ease-soft),
              left var(--area-vel) var(--ease-soft),
              box-shadow var(--area-vel) var(--ease-soft);
}
/* ALTERNANCIA DE COLOR — la misma de .badge-card en #reconocimientos, por
   pedido del cliente al unificar las dos partes: impar índigo, par azul marino
   (`--c-navy`; hasta el 2026-09-18 era el gris casi negro `--c-ink-2`, y el
   cliente la pidió azul marino en las DOS secciones, que siguen iguales). Acá
   ya NO alterna también el alto: con ocho en fila el ritmo lo da el escalonado
   vertical, y dos alturas encima ensuciaban la grilla. */
.area-card:nth-child(odd) .area-card-inner{ background: var(--c-indigo-2); }
.area-card:nth-child(even) .area-card-inner{ background: var(--c-navy); }

/* ⚠️ DAMERO (2026-09-19): en las filas pares se invierte el escalonado y el
   color, así ninguna fila repite a la de arriba. Hay un bloque por cantidad de
   columnas —8 y 4— porque cambia qué índices abren cada fila; si se agrega un
   breakpoint de la grilla, sumar el suyo. Con 2 columnas (≤700) queda el
   escalonado simple. Los altos no cambian: sólo qué tarjeta baja. */
@media (min-width: 1181px){
  .area-card:nth-child(16n+9),  .area-card:nth-child(16n+11),
  .area-card:nth-child(16n+13), .area-card:nth-child(16n+15){ margin-top: var(--area-salto); }
  .area-card:nth-child(16n+10), .area-card:nth-child(16n+12),
  .area-card:nth-child(16n+14), .area-card:nth-child(16n+16){ margin-top: 0; }
  .area-card:nth-child(16n+9)  .area-card-inner, .area-card:nth-child(16n+11) .area-card-inner,
  .area-card:nth-child(16n+13) .area-card-inner, .area-card:nth-child(16n+15) .area-card-inner{ background: var(--c-navy); }
  .area-card:nth-child(16n+10) .area-card-inner, .area-card:nth-child(16n+12) .area-card-inner,
  .area-card:nth-child(16n+14) .area-card-inner, .area-card:nth-child(16n+16) .area-card-inner{ background: var(--c-indigo-2); }
}
@media (min-width: 701px) and (max-width: 1180px){
  .area-card:nth-child(8n+5), .area-card:nth-child(8n+7){ margin-top: var(--area-salto); }
  .area-card:nth-child(8n+6), .area-card:nth-child(8n+8){ margin-top: 0; }
  .area-card:nth-child(8n+5) .area-card-inner, .area-card:nth-child(8n+7) .area-card-inner{ background: var(--c-navy); }
  .area-card:nth-child(8n+6) .area-card-inner, .area-card:nth-child(8n+8) .area-card-inner{ background: var(--c-indigo-2); }
}

/* La descripción: existe siempre en el DOM —un lector de pantalla la lee— pero
   no ocupa alto hasta el hover. `max-height` y no `display:none` justamente
   porque se anima; el `overflow: hidden` del contenedor la recorta mientras
   crece. */
/* La descripción existe siempre en el DOM —un lector de pantalla la lee— pero
   no ocupa alto hasta el hover.

   ⚠️ SIN TRANSICIÓN, Y ES EL PEDIDO. El cliente comparó con la referencia: "el
   texto sale de una, ubicado y cargado". Antes se animaban `opacity` y
   `max-height` y el texto se desplegaba mientras crecía la tarjeta: se leía
   como dos animaciones encimadas. Ahora aparece entero y en su lugar de una
   vez, y lo que se ve crecer es sólo la tarjeta — que es lo que hace la
   referencia.

   El `max-height: 0` con `overflow: hidden` del contenedor es lo que evita que
   en reposo empuje al nombre fuera de la tarjeta. Al pasar a `none` no anima
   (no es un valor interpolable), que acá es justamente lo que se busca. */
.area-desc{
  margin: 0;
  font-size: clamp(.78rem, .89vw, .9rem);
  line-height: 1.55;
  color: rgba(255, 255, 255, .82);
  opacity: 0;
  max-height: 0;
  overflow: hidden;
}

/* ⚠️ `:focus-within` ADEMÁS de `:hover`: las tarjetas no son enlaces todavía,
   pero el día que lo sean, quien navegue con teclado tiene que ver lo mismo que
   quien usa mouse. Cuesta una línea ahora y se olvida después. */
.area-card:hover,
.area-card:focus-within{ z-index: 3; }
.area-card:hover .area-card-inner,
.area-card:focus-within .area-card-inner{
  top: calc(var(--area-crece-y) * -1);
  bottom: calc(var(--area-crece-y) * -1);
  left: calc(var(--area-crece-x) * -1);
  right: calc(var(--area-crece-x) * -1);
  /* Al crecer, el nombre sube al techo y la descripción queda debajo. */
  justify-content: flex-start;
  box-shadow: 0 26px 54px rgba(6, 6, 20, .38);
}
.area-card:hover .area-desc,
.area-card:focus-within .area-desc{ opacity: 1; max-height: none; }

/* ⚠️ LAS TARJETAS DE LOS EXTREMOS CRECEN SÓLO HACIA ADENTRO.
   Desde que la grilla sangra, la primera de cada fila arranca pegada al borde
   izquierdo de la pantalla y la última al derecho: creciendo hacia los dos
   lados, la mitad de la tarjeta —y de su texto— se iba fuera de la pantalla.
   Se vio en la primera prueba: el nombre quedaba en "echo Corporativo y
   Comercial" y la descripción cortada por la mitad. El `overflow-x: clip` de
   la sección evita la barra de scroll, pero no hace legible lo que quedó
   afuera.

   La solución es correr todo el crecimiento al lado que tiene lugar: el doble
   hacia adentro y cero hacia afuera, así la tarjeta termina midiendo lo mismo
   que cualquier otra.

   ⚠️ HAY QUE REPETIRLO EN CADA BREAKPOINT porque cambia cuántas columnas hay
   —8, 4 y 2— y con eso cuáles son las tarjetas de los extremos. Si se agrega o
   se cambia un breakpoint de la grilla, sumar acá su par de reglas. */
.area-card:nth-child(8n+1):hover .area-card-inner,
.area-card:nth-child(8n+1):focus-within .area-card-inner{
  left: 0;
  right: calc(var(--area-crece-x) * -2);
}
.area-card:nth-child(8n):hover .area-card-inner,
.area-card:nth-child(8n):focus-within .area-card-inner{
  right: 0;
  left: calc(var(--area-crece-x) * -2);
}
@media (max-width: 1180px){
  .area-card:nth-child(4n+1):hover .area-card-inner,
  .area-card:nth-child(4n+1):focus-within .area-card-inner{
    left: 0;
    right: calc(var(--area-crece-x) * -2);
  }
  .area-card:nth-child(4n):hover .area-card-inner,
  .area-card:nth-child(4n):focus-within .area-card-inner{
    right: 0;
    left: calc(var(--area-crece-x) * -2);
  }
}
@media (max-width: 700px){
  .area-card:nth-child(odd):hover .area-card-inner,
  .area-card:nth-child(odd):focus-within .area-card-inner{
    left: 0;
    right: calc(var(--area-crece-x) * -2);
  }
  .area-card:nth-child(even):hover .area-card-inner,
  .area-card:nth-child(even):focus-within .area-card-inner{
    right: 0;
    left: calc(var(--area-crece-x) * -2);
  }
}

/* Sin animación: la tarjeta crece igual —la descripción tiene que poder
   leerse— pero de una vez, sin recorrido. */
@media (prefers-reduced-motion: reduce){
  .area-card-inner{ transition: none; }
}

/* El numero, en el chip de .badge-card-years. Mismo alfa, mismo radio y mismo
   peso: es literalmente el mismo componente con otro contenido. */
.area-num{
  align-self: flex-start;
  padding: .18rem .45rem;
  border-radius: var(--radius);
  background: rgba(255,255,255,.14);
  font-size: .64rem;
  font-weight: 600;
  letter-spacing: .02em;
  color: #fff;
  font-variant-numeric: tabular-nums;
}/* Del mismo componente que .badge-card-title, pero UN PASO MAS GRANDE, y la
   diferencia es deliberada: la tarjeta de #areas mide 284px con --per:4, contra
   los 177px de la de #reconocimientos con seis en fila. Es 1.6x mas ancha, asi
   que aguanta un cuerpo mayor sin partir palabras.
   ⚠️ No igualarlo al de .badge-card-title "por consistencia": a 1.25rem el
   nombre queda chico para el ancho de esta tarjeta, y a 1.55rem —el valor
   original de .badge-card-title— "Telecomunicaciones" y "Inversion" se partian
   con guion en dos lineas cada una. 1.4rem es lo que entra sin hyphenar. */
.area-name{
  /* ⚠️ MUCHO MÁS CHICO QUE ANTES (era clamp(1.1rem, 1.5vw, 1.4rem)), y no es
     gusto: con OCHO tarjetas en fila el ancho de contenido pasó de ~220px a
     ~112px. Al tamaño viejo, once de los dieciséis nombres se partían a mitad
     de palabra —"Corporati/vo", "Telecom/unicacio/nes"— porque entraba a
     actuar el `word-break` de abajo, que es la última red y corta sin guion.

     ⚠️ SIN `hyphens: auto`, a diferencia de .badge-card-title. Se sacó en su
     momento porque no espera a que la palabra no entre: parte para RELLENAR la
     línea, y dejaba cortes innecesarios ("Cum-plimiento") con la palabra
     entera cabiendo en el renglón siguiente. Las pocas palabras que de verdad
     no entran llevan `&shy;` en el HTML, que corta DONDE CORRESPONDE y sólo si
     hace falta.

     ⚠️ SI SE TOCA ESTE TAMAÑO, EL PADDING DE LA TARJETA O LA CANTIDAD DE
     COLUMNAS, HAY QUE VOLVER A MEDIR palabra por palabra y revisar qué `&shy;`
     sobran o faltan. La suite lo vigila ("ninguna palabra se parte sin guion").
     `overflow-wrap`/`word-break` quedan sólo como última red. */
  font-size: clamp(.85rem, 1.02vw, 1.02rem);
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -.01em;
  overflow-wrap: break-word;
  word-break: break-word;
}

/* ⚠️ ACA NO VA UNA TARJETA DESTACADA. NO REPONERLA SIN PREGUNTAR.
   Habia una `.area-card.is-featured .area-card-inner` con el degradado de marca
   —una destacada por pagina, heredada de la referencia de guyer.com.uy que habia
   pasado el cliente— y se QUITO a pedido explicito del cliente: metia un tercer
   tono donde el pedido era que estas tarjetas alternaran exactamente como las de
   #reconocimientos, que solo tienen dos (indigo y negro).
   El JS que marcaba la clase tambien se saco (ver initAreas en js/main.js), para
   no dejar una clase que se sigue poniendo y no pinta nada.
   Si algun dia se quiere volver a destacar una, la forma de hacerlo SIN romper la
   alternancia es un realce que no compita con los fondos —un filete, una sombra—,
   no un tercer color. */

/* ⚠️ ACÁ HABÍA UN `.area-card-inner:hover{ transform: translateY(-6px) }`.
   Se quitó el 2026-08-13: ahora el hover lo resuelve la EXPANSIÓN de la
   tarjeta (ver el bloque de la grilla, más arriba), y las dos cosas juntas
   daban un salto encima del crecimiento. */

/* ⚠️ ACÁ VIVÍA LA NAVEGACIÓN DE LA SECCIÓN — SE FUE ENTERA (2026-08-13).
   Eran las flechas (`.areas-nav`, `.areas-arrow`), el contador `1 / 4`
   (`.areas-count`) y una grilla sobre `.areas > .container` que existía sólo
   para colocarlas arriba a la derecha del encabezado.

   Con la grilla fija de 8 + 8 no hay páginas que pasar, así que no hay nada que
   navegar. Se quitó también el JS que las gobernaba (`initAreas()` en
   js/main.js).

   ⚠️ Y CON LA GRILLA SE FUE EL PROBLEMA DE MÁRGENES QUE VENÍA CON ELLA. Aquella
   grilla anulaba el colapso entre el `margin-bottom` del `.section-head` y el
   `margin-top` de las tarjetas, y por eso el del encabezado estaba forzado a 0.
   Al volver el `.container` a flujo normal los dos vuelven a colapsar y gana el
   mayor, que es el comportamiento de siempre del resto del sitio. Por eso el
   `margin-bottom: 0` también se fue: si se repone sin la grilla, el encabezado
   queda pegado a las tarjetas. */

/* ⚠️ LA SECCIÓN RECORTA EN HORIZONTAL, Y HACE FALTA DESDE QUE LA GRILLA SANGRA.
   Las tarjetas de las puntas arrancan pegadas al borde de la pantalla y al
   crecer se van hacia afuera: sin esto aparece barra de scroll horizontal.
   `clip` y no `hidden`: `hidden` crea un contenedor de scroll y eso rompe el
   `position: sticky` de cualquier hijo, además de permitir scrollear la
   sección por programa. Con `clip` en un eje y `visible` en el otro, el
   crecimiento vertical de la tarjeta sigue saliendo de la sección. */
.areas{ overflow-x: clip; }

/* ⚠️ EL MARGEN DE ARRIBA ES EL MISMO RELLENO QUE LA SECCIÓN DEJA ABAJO.
   Estaba en `clamp(2.5rem, 5vw, 3.5rem)` mientras que debajo del bloque queda
   el `padding-bottom` de `.section-pad`: medido, **56px arriba contra 120px
   abajo** a 1440 (y 51/92, 40/69, 40/64 en los otros anchos). El cliente lo vio
   como que el bloque no estaba equilibrado verticalmente.
   ⚠️ SE USA `var(--pad-block)` Y NO UN VALOR COPIADO. `.section-pad` declara esa
   variable y la sección la hereda, así que arriba y abajo miden lo mismo POR
   CONSTRUCCIÓN en todos los anchos — no hay que mantener dos clamps en sincronía
   ni poner un margen distinto por breakpoint. Si un día cambia el relleno del
   sistema, esto lo sigue solo. */
.areas-cta{
  margin-top: var(--pad-block, clamp(2.5rem, 5vw, 3.5rem));
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.25rem 2rem;
  /* Centrado: lo pidió el cliente (2026-08-18). Antes heredaba el alineado a la
     izquierda del contenedor y quedaba colgando del borde. */
  justify-content: center;
  text-align: center;
}
.areas-cta p{ font-weight: 600; color: var(--text-muted); }

/* ==========================================================================
   ALIANZAS
   ==========================================================================
   Banda CLARA: los cinco logos del cliente tienen el texto en tinta oscura y
   sobre el degradado índigo tres de ellos desaparecen. Ver la nota en el HTML.
   ========================================================================== */
.allies{
  background: var(--gradient-dark);
  color: #fff;
  position: relative;
  overflow: hidden;
  /* Separación entre el título «Alianzas globales» y la fila de tarjetas. Hasta
     el 2026-09-18 era el hueco (hasta 9.5rem) donde la palabra de fondo quedaba
     a medias detrás de las tarjetas; hoy el título va arriba y entero. */
  --allies-row-gap: clamp(1.5rem, 3vw, 2.75rem);
}
/* ⚠️ «ALIANZAS GLOBALES»: TÍTULO CENTRADO, ARRIBA Y SIN SUPERPOSICIÓN (2026-09-18).
   Pedido del cliente en reunión: «poner Alianzas globales en vez de Somos
   globales; la letra está muy grande, mejor centrar y colocar arriba sin
   superposición». Hasta ese día era una palabra de fondo enorme (hasta 13rem)
   posicionada en absoluto y cortada por el borde de las tarjetas de vidrio,
   que la tapaban en su 10% inferior; toda la geometría de ese corte (el `top`
   atado a `--pad-block + --allies-row-gap`, los `-0.08em`/`-0.30em`) se retiró
   con el pedido. Ahora va EN FLUJO, antes del contenedor, centrada y con
   ~la mitad del tamaño.
   ⚠️ SIGUE IDÉNTICA A .novedades-title (regla del cliente: las dos palabras
   iguales), que cambió igual y en el mismo pedido. `_tools/medir_global.js`
   controla que compartan tamaño, peso, color, opacidad y tracking, y ahora
   además que ninguna tarjeta las pise.
   El color claro (#a8c4ff) al 28% se conserva: el pedido fue tamaño y
   posición. Es decorativa (aria-hidden); el nombre de la sección lo da el
   `aria-label` del <section>.
   Puede partirse en dos renglones en celulares muy angostos (`text-wrap:
   balance`) en vez de cortarse por los costados. */
.allies-word{
  position: relative;
  z-index: 1;
  display: block;
  pointer-events: none;
  user-select: none;
  color: #a8c4ff;
  opacity: .28;
  font-weight: 800;
  font-size: clamp(1.75rem, 6vw, 6.5rem);
  line-height: 1.05;
  letter-spacing: -.03em;
  margin: 0;
  padding-inline: var(--gutter);
  text-align: center;
  text-wrap: balance;
}
.allies > .container{ position: relative; z-index: 1; }
.allies .lede{ color: rgba(255,255,255,.75); }

/* Cinco tarjetas en una sola fila. `auto-fit` con un mínimo chico dejaba la
   quinta sola en una segunda fila en pantallas medianas; con 5 columnas
   explícitas la fila se mantiene y solo baja de a dos pasos en los breakpoints. */
/* Separación entre el título «Alianzas globales» y las tarjetas: sale de
   `--allies-row-gap`, declarada en .allies. Hasta el 2026-09-18 este margen
   decidía en qué fracción del alto de la palabra de fondo cortaba el borde de
   las tarjetas; desde que el título va arriba y entero, sólo separa. */
.allies-grid{
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: clamp(.75rem, 1.4vw, 1.35rem);
  margin-top: var(--allies-row-gap);
}
@media (max-width: 1100px){ .allies-grid{ grid-template-columns: repeat(3, 1fr); } }
/* ⚠️ EN 3 + 2 LA SEGUNDA FILA VA CENTRADA (2026-09-19). Con 3 columnas las dos
   últimas quedaban a la izquierda con un hueco a la derecha, bajo un título
   centrado (monitores 4:3 de 1024 y tablets). Seis pistas, cada tarjeta ocupa
   dos, y la cuarta arranca en la segunda pista: las dos de abajo quedan
   centradas bajo las tres de arriba, del mismo ancho. */
@media (min-width: 701px) and (max-width: 1100px){
  .allies-grid{ grid-template-columns: repeat(6, 1fr); }
  .allies-grid > .ally{ grid-column: span 2; }
  .allies-grid > .ally:nth-child(4){ grid-column: 2 / span 2; }
}
@media (max-width: 700px){ .allies-grid{ grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 460px){ .allies-grid{ grid-template-columns: 1fr; } }

.ally-card{
  height: 100%;
  display: flex;
  flex-direction: column;
  /* stretch, no center: la placa del logo tiene que ocupar todo el ancho de la
     tarjeta para que las cinco queden alineadas entre sí. */
  align-items: stretch;
  text-align: center;
  gap: 1.25rem;
  padding: clamp(1.75rem, 3vw, 2.5rem) clamp(1rem, 1.6vw, 1.5rem);
  border-radius: var(--radius-md);
  /* ⚠️ VIDRIO DE VERDAD: alfa BAJO. La legibilidad de los logos NO la resuelve
     esta capa —la resuelve la placa clara de .ally-card img—, y por eso acá se
     puede bajar hasta .12 sin perder nada.

     El camino largo, para no repetirlo: primero se probó subir el alfa hasta que
     los logos se leyeran (se llegó a .82) y la tarjeta terminó pareciendo un
     panel blanco opaco. Se midió con capturas comparadas —una con la palabra
     "Global" de fondo y otra sin ella, midiendo la diferencia dentro de la
     tarjeta— y bajar el alfa a secas tampoco servía: a .15 SIN placa el peor
     contraste caía a 2.2:1 y tres logos se perdían.
     Con placa, a .12 el peor contraste es 6.2:1 (WCAG pide 4.5) y la tarjeta se
     transparenta casi el doble que a .82. Mejora en las dos cosas a la vez.
     El script de medición está descrito en la Etapa 10 del changelog. */
  background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.26);
  -webkit-backdrop-filter: blur(16px) saturate(1.2);
          backdrop-filter: blur(16px) saturate(1.2);
  box-shadow: 0 18px 45px rgba(8,8,20,.3);
  color: #fff;
  transition: transform var(--dur-micro) var(--ease-soft),
              background var(--dur-micro) var(--ease-soft),
              box-shadow var(--dur-micro) var(--ease-soft);
}
/* Sin backdrop-filter no hay desenfoque y la palabra de fondo se leería nítida
   por detrás del texto de la tarjeta: se sube un poco el alfa para tapar eso.
   Sigue siendo translúcida, solo que sin el esmerilado. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))){
  .ally-card{ background: rgba(255,255,255,.3); }
}
/* ⚠️ EL <img> ES LA PLACA. No lleva un contenedor aparte: los logos son WebP con
   canal alfa, así que darle fondo, padding y radio a la propia imagen ya produce
   la placa clara sobre la que se apoyan. Es lo que permite que la tarjeta sea
   MUY translúcida sin perder los logos de tinta oscura.
   `height` fija + `object-fit: contain` para que las cinco placas midan igual,
   con el logo centrado dentro sea cual sea su proporción. */
.ally-card img{
  height: clamp(80px, 6.4vw, 96px);
  width: 100%;
  object-fit: contain;
  padding: clamp(.8rem, 1.1vw, 1rem) clamp(.9rem, 1.2vw, 1.1rem);
  box-sizing: border-box;
  background: rgba(255,255,255,.95);
  border-radius: var(--radius);
  box-shadow: 0 8px 20px rgba(8,8,20,.2);
  transition: background var(--dur-micro) var(--ease-soft);
}
.ally-desc{
  font-size: .86rem;
  line-height: 1.55;
  text-align: center;
  /* Blanco pleno y con sombra, no blanco al 82%: este texto tiene por detrás el
     vidrio Y la palabra "Global", que es clara. Con .82 y sin sombra su
     contraste quedaba por debajo del mínimo cuando la palabra pasaba justo ahí. */
  color: #fff;
  text-shadow: 0 1px 8px rgba(8,8,20,.8), 0 0 2px rgba(8,8,20,.55);
}
a.ally-card:hover{
  transform: translateY(-5px);
  background: rgba(255,255,255,.2);
  box-shadow: 0 24px 55px rgba(8,8,20,.4);
}
a.ally-card:hover img{ background: #fff; }
/* Iconekta va sin enlace mientras el cliente no publique su URL: se muestra
   igual, pero sin las affordances de algo clickeable. */
.ally-card--nolink{ cursor: default; }

/* ==========================================================================
   CONTACTO
   ========================================================================== */
/* ⚠️ `stretch` Y NO `start`: ES LO QUE HACE QUE EL MAPA ENCAJE.
   El cliente pidió que la columna de la izquierda termine exactamente donde
   termina el formulario, sin pasarse. Con `start` la columna medía lo que su
   contenido —613px contra los 663 del formulario a 1440— y el mapa no tenía
   dónde ir. Estirada, la columna vale lo que la fila y el mapa se queda con lo
   que sobre (ver `.contact-mapa`). */
.contact-grid{
  display: grid;
  gap: clamp(2.5rem, 5vw, 4.5rem);
  align-items: stretch;
}
@media (min-width: 940px){
  .contact-grid{ grid-template-columns: .85fr 1.15fr; }
}
/* Columna flex para que el mapa sea el único hijo que crece. */
.contact-aside{ display: flex; flex-direction: column; }
.contact-aside h2{ margin-top: .75rem; }
.contact-lede{ color: rgba(255,255,255,.72); margin-top: 1rem; }

.contact-data{
  margin-top: clamp(2rem, 4vw, 2.75rem);
  display: grid;
  gap: 1.35rem;
}
.contact-label{
  display: block;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c-cyan);
  margin-bottom: .3rem;
}
.contact-value{
  display: block;
  font-size: .98rem;
  font-weight: 600;
  line-height: 1.5;
  color: rgba(255,255,255,.9);
}
a.contact-value:hover{ color: var(--c-cyan); }
/* ⚠️ Acá iba `.contact-wa`, el botón «Escribir por WhatsApp» sobre el mapa. El
   cliente lo hizo quitar el 2026-09-17 «para ampliar el mapa», y su función
   pasó al botón «Enviar por WhatsApp» del formulario (`.form-wa`). Con los
   58px del botón y sus 32 de margen, el mapa estaba en su mínimo de 150px en
   todos los anchos de escritorio y el formulario se estiraba 18–30px vacíos. */

/* --- Mapa de la ubicación (Leaflet + teselas de CARTO) --- */
/* ⚠️ DE 940 PARA ARRIBA LOS DATOS VAN EN DOS COLUMNAS, Y ES PARA EL MAPA.
   Apilados ocupaban ~227px de los 613 del aside, y contra un formulario de 663
   sobraban 50px: un mapa de 50px no se entiende, que era justo la condición del
   cliente. En 2×2 el bloque baja a ~110px y el mapa se queda con ~167. */
@media (min-width: 940px){
  .contact-data{ grid-template-columns: 1fr 1fr; column-gap: 1.5rem; }
}
/* ⚠️ NO LLEVA ALTURA FIJA: CRECE CON LO QUE SOBRA. `flex: 1` dentro del aside
   estirado hace que el bloque entero mida lo mismo que el formulario, ni un
   píxel más, que es el pedido. El `min-height` es el piso por debajo del cual
   el mapa dejaría de leerse; si alguna vez se llega a él, lo que hay que
   recortar es el contenido de arriba, no bajar este número. */
.contact-mapa{
  position: relative;
  flex: 1 1 auto;
  min-height: 150px;
  margin-top: 1.5rem;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid rgba(255,255,255,.12);
  /* Índigo y no `--c-ink`: es el color sobre el que se apoyan las teselas
     semitransparentes, o sea el que hace que el mapa pertenezca a la paleta.
     Ver la nota larga más abajo. */
  background: var(--c-indigo-2);
}
/* En una sola columna no hay formulario al lado que igualar, así que el mapa
   pasa a una altura propia. */
@media (max-width: 939.98px){
  .contact-mapa{ flex: none; height: 240px; }
}

/* ⚠️ EL COLOR DEL MAPA SE HACE CON BRILLO + CONTRASTE Y DESPUÉS OPACIDAD.
   Lo reportó el cliente el 2026-09-16 («el mapa no utiliza los colores de la
   web») y tenía razón: el mapa medía #040614 —negro— a distancia 134 del índigo
   de la sección. Antes de llegar acá se probaron y se DESCARTARON MIDIENDO tres
   caminos, y conviene no repetirlos:

   1. `mix-blend-mode` (screen, lighten, multiply), sobre el panel de teselas y
      sobre cada tesela: NO COMPONE. Las teselas viven dentro de
      `.leaflet-tile-container`, que lleva `transform`, y eso aísla la fusión:
      el blend nunca ve el fondo índigo. Todos quedaron en distancia ~140.
   2. Una capa `::after` sobre el CONTENEDOR: compone, pero queda por encima de
      TODO el mapa. `.leaflet-map-pane` es un contexto de apilamiento en
      z-index 400, así que sus hijos se pintan DENTRO de ese 400 aunque Leaflet
      apile los marcadores en 600: un `::after` en 450 les pasa por arriba.
      Es lo que hacía la versión anterior y por eso el pin medía #0a2a92 en vez
      del cian #35dfff. ⚠️ El comentario que vivía acá afirmaba exactamente lo
      contrario —que el 450 quedaba por debajo del pin— y era falso.
   3. Cadenas de filtros solas: contradicción de fondo. Para levantar los negros
      hace falta `contrast(<1)`, y eso mismo aplasta el rango. Lo mejor dio
      distancia 54 pero rango 28, con las calles casi indistinguibles.

   Lo que sí funciona es componer por ALFA, que no depende de ningún contexto de
   apilamiento. El ORDEN de la cadena es lo que la hace funcionar:
     1. `brightness(6)` sube el contenido de la tesela —casi negro— hasta cerca
        del gris medio. Sin este paso `contrast()`, que pivotea justamente en el
        gris medio, aplasta todo contra el negro.
     2. `contrast(1.2)` abre la diferencia entre el terreno y las calles.
     3. `opacity: .28` apoya el resultado sobre el índigo del contenedor: los
        negros suben AL índigo y las calles quedan por encima de él.
   Los tres números salen de medir 22 combinaciones, no de probar a ojo. El
   equilibrio es éste: cuanto MÁS BAJA la opacidad, más índigo de fondo se ve y
   más cerca queda el mapa de la paleta; el brillo alto es lo que compensa, para
   que las calles sigan destacando pese a esa transparencia. Por eso van juntos
   un brillo muy alto y una opacidad muy baja, que por separado parecen raros.
   Medido contra el índigo de la sección (#2e3092): distancia de color **29**
   (era 134) y rango de luz dentro del mapa **55** (era 22), con las calles a
   +33 de luz sobre el terreno.
   El pin, el popup y los botones no se tocan: el filtro vive en el panel de
   teselas y ellos están fuera de ese panel. */
.contact-mapa .leaflet-container{
  height: 100%;
  background: var(--c-indigo-2);
  font: inherit;
}
.contact-mapa .leaflet-tile-pane{
  filter: saturate(0) brightness(6) contrast(1.2);
  opacity: .28;
}
.contact-mapa .leaflet-control-zoom a{
  background: rgba(10,10,26,.85);
  color: #fff;
  border-color: rgba(255,255,255,.18);
}
.contact-mapa .leaflet-control-zoom a:hover{ background: var(--c-indigo); color: #fff; }
.contact-mapa .leaflet-control-attribution{
  background: rgba(10,10,26,.72);
  color: rgba(255,255,255,.55);
  font-size: .62rem;
}
.contact-mapa .leaflet-control-attribution a{ color: var(--c-cyan); }
.contact-mapa .leaflet-popup-content-wrapper,
.contact-mapa .leaflet-popup-tip{
  background: var(--c-ink);
  color: #fff;
  border-radius: var(--radius-sm);
}
.contact-mapa .leaflet-popup-content{ font-size: .85rem; line-height: 1.5; }
.contact-mapa .leaflet-popup-content a{ color: var(--c-cyan); }

/* El pin se dibuja acá y no con los PNG de Leaflet: así toma los colores de la
   marca por variable y no hay que copiar imágenes de la librería a img/. */
.mapa-pin-punto{
  position: absolute;
  inset: 0;
  margin: auto;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--c-cyan);
  border: 2px solid #fff;
  box-shadow: 0 0 0 2px rgba(10,10,26,.6);
}
.mapa-pin-pulso{
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--c-cyan);
  opacity: .35;
  animation: mapaPulso 2.4s var(--ease-soft) infinite;
}
@keyframes mapaPulso{
  0%{ transform: scale(.45); opacity: .5; }
  70%{ transform: scale(1.7); opacity: 0; }
  100%{ opacity: 0; }
}
@media (prefers-reduced-motion: reduce){
  .mapa-pin-pulso{ animation: none; }
}

/* --- Formulario --- */
.contact-form-wrap{
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.12);
  border-radius: var(--radius-lg);
  padding: clamp(1.5rem, 3.5vw, 2.75rem);
}
.field{ margin-bottom: 1.25rem; }
.field-row{ display: grid; gap: 1.25rem; }
@media (min-width: 620px){ .field-row{ grid-template-columns: 1fr 1fr; } }
.field label{
  display: block;
  margin-bottom: .45rem;
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .02em;
  color: rgba(255,255,255,.82);
}
.field input[type="text"],
.field input[type="email"],
.field input[type="tel"],
.field select,
.field textarea{
  width: 100%;
  padding: .85rem 1rem;
  color: #fff;
  background: rgba(10,10,26,.35);
  border: 1px solid rgba(255,255,255,.18);
  border-radius: var(--radius-sm);
  transition: border-color var(--dur-micro) var(--ease-soft),
              background var(--dur-micro) var(--ease-soft);
}
.field textarea{ resize: vertical; min-height: 7rem; }
.field select option{ color: #1c1c1c; background: #fff; }
.field input::placeholder, .field textarea::placeholder{ color: rgba(255,255,255,.4); }
.field input:focus, .field select:focus, .field textarea:focus{
  outline: none;
  border-color: var(--c-cyan);
  background: rgba(10,10,26,.55);
}
/* Estado de error: lo marca js/main.js con aria-invalid, así el estilo y la
   semántica no se pueden desincronizar. */
.field [aria-invalid="true"]{ border-color: #ff8080; }
/* Al enviar con errores se enfoca el primer campo inválido y el navegador lo
   trae a la vista respetando `scroll-padding-top` (90px, menos que el header
   compacto): el rótulo quedaba escondido detrás del header (1024x768,
   1366x768). Este margen extra deja visible también el rótulo. (2026-09-19) */
.contact-form .field :is(input, select, textarea){ scroll-margin-top: 3rem; }
.field-error{
  display: block;
  margin-top: .4rem;
  font-size: .78rem;
  font-weight: 600;
  color: #ffb3b3;
}
/* ⚠️ EL CHECKBOX SE CENTRA CONTRA LA PRIMERA LÍNEA DEL TEXTO, CON UNA CUENTA.
   Antes llevaba `margin-top: .28rem` a ojo y quedaba 3px más abajo que el
   renglón (medido a 1440 y a 390 el 2026-09-15; lo marcó el cliente).
   No sirve `align-items: center`: el texto envuelve a tres renglones en móvil y
   el checkbox se iría al medio del párrafo. Tampoco `1lh` en el input: el input
   tiene su PROPIO tamaño de letra, así que su `lh` no es el del texto.
   Por eso tamaño y alto de línea del texto viven en dos variables, y el margen
   del checkbox es la mitad de lo que sobra entre ese alto de línea y sus 17px.
   Si cambia la letra del texto, el checkbox se reacomoda solo. */
.field--check{
  --check-fs: .85rem;
  --check-lh: 1.6;
  --check-box: 17px;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: .7rem;
}
/* ⚠️ EL AVISO VA DEBAJO, ALINEADO CON EL TEXTO (2026-09-19). js/main.js lo
   agrega DENTRO de esta fila flex, y sin wrap entraba como tercera columna al
   lado del texto: en un teléfono, una columna de 88px con una palabra por
   renglón. Sin error no cambia nada, porque el aviso no existe. */
.field--check .field-error{
  flex: 0 0 100%;
  margin-top: -.3rem;
  padding-left: calc(var(--check-box) + .7rem);
}
.field--check input{
  margin-top: calc((var(--check-fs) * var(--check-lh) - var(--check-box)) / 2);
  /* Sin el margen lateral del navegador (distinto en Chromium y WebKit): así el
     aviso de error, sangrado `--check-box + gap`, arranca exactamente donde el
     texto. (2026-09-19) */
  margin-inline: 0;
  flex: none;
  width: var(--check-box);
  height: var(--check-box);
  accent-color: var(--c-blue);
}
/* ⚠️ `flex: 1 1 0` ES LO QUE MANTIENE EL TEXTO AL LADO DE LA CASILLA desde que
   la fila lleva `flex-wrap` (para que el aviso de error baje). Con la base
   `auto` el texto medía su ancho en una sola línea (~470px) y, en campos más
   angostos —teléfonos y 960–1152px—, bajaba entero debajo de la casilla. */
.field--check label{ flex: 1 1 0; min-width: 0; margin: 0; font-weight: 600; font-size: var(--check-fs); line-height: var(--check-lh); color: rgba(255,255,255,.72); }

/* Campo cebo anti-spam: fuera de pantalla, no display:none — algunos bots
   ignoran los campos ocultos por display y así caerían igual en la trampa. */
.hp-field{
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-actions{ margin-top: 1.75rem; }
/* Dos caminos de envío (2026-09-17): «Enviar consulta vía mail» y «Enviar por
   WhatsApp». Lado a lado donde entran (≥1280 y de 600 a 939px); de 940 a
   1279 no entran y se apilan solos. `stretch` + `line-height` igualan el alto
   del <button> y del <a>: el <a> heredaba el 1.6 del body y medía 58px contra
   52. */
.form-botones{
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 1rem 1.5rem;
}
.form-botones .btn{ line-height: 1.2; }
/* ⚠️ En celular a ancho completo y pudiendo partir en dos renglones: `.btn`
   lleva `white-space: nowrap`, y a 320px «Enviar por WhatsApp» mide 259px
   contra 202 disponibles —el formulario se ensanchaba y la página desbordaba
   9px en horizontal—. Acotado a `.form-botones`: no tocar `.btn` global. */
@media (max-width: 599.98px){
  .form-botones .btn{
    flex: 1 1 100%;
    justify-content: center;
    white-space: normal;
    text-align: center;
    padding-inline: 1.25em;
  }
}
/* El margen sólo con mensaje: vacío, el párrafo no ocupa nada y no cambia el
   alto del formulario (del que depende el del mapa). */
.form-status{
  font-size: .88rem;
  font-weight: 600;
  line-height: 1.5;
}
.form-status:not(:empty){ margin-top: 1rem; }
.form-status.is-ok{ color: #7ee2a8; }
.form-status.is-error{ color: #ffb3b3; }
button[disabled]{ opacity: .6; cursor: progress; }


/* ==========================================================================
   ↓↓↓  BLOQUES QUE VIENEN DE pstbn-part2  ↓↓↓
   ==========================================================================
   Testimonios, Reconocimientos, Novedades y Footer. Todo lo de arriba viene de
   pstbn-part1. La seccion "Nosotros" de la part-2 NO esta: su contenido se
   mudo al titular rotativo del hero (ver .hero-titles) por pedido del cliente,
   y la seccion se elimino.
   ========================================================================== */

/* ==========================================================================
   Testimonios — una sola pantalla: foto a sangre + recuadro de vidrio
   ========================================================================== */
/* ⚠️ UNA SOLA PANTALLA (2026-09-17). Pedido del cliente: «que sea solo una
   pantalla, no tener las tres divisiones… puede estar con un recuadro
   semitransparente en un costado. Que sea lo mejor UX/UI». Reemplaza la grilla
   de 3 paneles (panel índigo con el título, cita sobre #231f20 y foto al 30%),
   con su columna calculada de `gutter + 341px`: ya no hay nada que calcular.
   Es la opción «vidrio a la izquierda» + barra de progreso, prototipada y
   aprobada: docs/plan-hero-testimonios-2026-09-17.md §3.
   Capas, de atrás hacia adelante:
     · .testi-media: la foto a sangre con la transición «gallery» y un velo
       oscuro del lado del recuadro (::after);
     · .testi-cont (un .container) > .testi-vidrio: el recuadro. Al vivir en un
       .container su borde izquierdo cae en la x del logo, como todo el sitio.
   ⚠️ ALTO: UNA PANTALLA MENOS EL HEADER, no 100vh. Los enlaces internos dejan la
   sección a 90px del borde de arriba (`scroll-padding-top` y el handler de
   anchors de js/main.js): con 100vh quedaban 90px de la sección fuera de
   pantalla, abajo. Si cambia esa constante, cambia acá. */
.testimonios{
  --testi-velo: 14, 15, 38;          /* tinta azulada del velo, en canales rgb */
  display: flex;
  align-items: center;
  min-height: calc(100vh - 90px);
  padding-block: clamp(2.5rem, 7vh, 5rem);
  background: var(--c-ink-2);
  color: #fff;
}
/* ⚠️ LA LÍNEA BLANCA ENTRE NUESTRO EQUIPO Y TESTIMONIOS (2026-09-17). La marcó el
   cliente sobre captura, y es la misma que había reportado el 2026-08-06 y
   entonces no se pudo reproducir: sólo aparece con el escalado de pantalla de
   Windows en 110–175% (medido; al 100% no está), y sólo con el recorrido del
   equipo pineado.
   Por qué: al terminar el pin, GSAP deja a #equipo desplazado con `transform`,
   en su propia capa. Con escala fraccionaria el borde de abajo de esa capa y el
   de arriba de #testimonios caen en MEDIA fila de píxel cada uno, y el
   antialiasing de los dos deja ver el fondo blanco de <body> por la fila de la
   unión (medido: luminancia 106–122 contra ~60 alrededor; con el body en rojo, la
   línea salía rojiza).
   Arreglo, las dos cosas hacen falta:
     · una franja índigo DETRÁS de la unión (z-index -1, 3px arriba y 3px abajo),
       así lo que se ve por la fila parcial es índigo y no blanco. Al ras no
       alcanzaba: dos bordes antialiasados que se tocan igual dejan pasar el
       fondo;
     · el panel de la foto sin su fondo gris claro (`--c-mist`), que era lo que
       asomaba sobre la foto por la misma fila.
   Medido en 7 escalas de 100 a 175%: la fila de la unión queda entre los colores
   vecinos en los tres paneles, y al 100% no cambia ni un píxel.
   ⚠️ DESDE EL 2026-09-17 EL EQUIPO NO SE PINEA, así que la causa medida (el
   `transform` que dejaba el pin) ya no está. La regla SE CONSERVA igual: al
   100% no cambia nada, y sólo se retira después de volver a medir la unión con
   escalado de 125% y 150% sin pin. Sigue colgada de `.team-pin-on`, que hoy
   marca el modo recorrido. */
.team-pin-on #testimonios::before{
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -3px;
  height: 6px;
  background: var(--c-indigo-2);
  z-index: -1;
  pointer-events: none;
}

/* La foto a sangre. ⚠️ El `overflow: hidden` va ACÁ y nunca en la sección: la
   sección no debe recortar lo que asome por encima de su borde (ver la nota de
   la unión con #equipo, arriba). El fondo oscuro, nunca claro: es lo que se ve
   si una foto tarda y lo que asomaría por una fila de píxel parcial. */
.testi-media{
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--c-ink-2);
}
/* El velo que asienta el recuadro: oscuro a la izquierda, nada a la derecha,
   así la foto se sigue viendo entera del otro lado. ⚠️ `pointer-events: none`:
   es una capa sobre toda la sección, y una capa así no puede robarle el click a
   las flechas (lo prueba _tools/verificar_regresiones.js §6). */
.testi-media::after{
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* ⚠️ Desde que el recuadro ocupa todo el contenedor (2026-09-17), la cita
     queda en la mitad DERECHA, donde antes el velo ya no oscurecía nada: el
     velo cubre ahora todo el ancho, más denso detrás del recuadro, y la foto
     sigue viéndose arriba y abajo de él. */
  background: linear-gradient(90deg,
    rgba(var(--testi-velo), .55) 0%,
    rgba(var(--testi-velo), .4) 50%,
    rgba(var(--testi-velo), .5) 100%);
}
/* Encima de la foto: la foto es `absolute`, así que el contenedor tiene que ser
   posicionado para pintarse después de ella. */
.testi-cont{ position: relative; z-index: 1; }

/* ⚠️ EL RECUADRO DE VIDRIO. Tinta índigo translúcida + desenfoque de lo que pasa
   por detrás. `position: relative` NO ES DECORATIVO: la reserva de alto de
   js/main.js mide las citas en un molde `absolute` que agrega a este recuadro.
   Contraste medido el 2026-09-17 con las 5 fotos, en reposo y congelando la
   transición cuadro a cuadro, a 1280, 1440, 1920 y 390 (método de
   _tools/medir_contraste_video.js: tinta oculta, p95 del fondo): el peor caso
   es la fuente en cian, ≥6,6:1. Si se baja la opacidad del fondo o la del
   velo, hay que volver a medir: sala-reuniones.webp (pizarra blanca) y
   biblioteca.webp son las fotos que más lo bajan. */
.testi-vidrio{
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 1.4rem;
  width: 100%;
  padding: clamp(1.75rem, 2.8vw, 2.6rem);
  background: rgba(20, 21, 52, .5);
  -webkit-backdrop-filter: blur(20px) saturate(1.15);
  backdrop-filter: blur(20px) saturate(1.15);
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: var(--radius-md);
  box-shadow: 0 24px 60px rgba(8, 8, 20, .35);
}
/* Sin desenfoque (navegadores viejos) el fondo va más opaco: la foto nítida
   detrás de la cita la haría ilegible con la mitad de tinta. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))){
  .testi-vidrio{ background: rgba(20, 21, 52, .85); }
}
/* El h2 conserva el tamaño del sistema (mismo que «El equipo detrás de cada
   respuesta»): no pisar su font-size. */
.testi-titulo{ color: #fff; }

/* ⚠️ RECUADRO CENTRADO, CASI CUADRADO (2026-09-18). Pedido del cliente en
   reunión: «Testimonios cuadrado transparente centrado y el resto dejar igual».
   Reemplaza al recuadro a lo ancho del contenedor de la segunda vuelta del
   2026-09-17 (título a la izquierda, cita a la derecha). Ahora es una columna:
   título arriba, cita en el medio y el pie (contador, pase y flechas) abajo,
   repartidos en un recuadro de hasta 640px de ancho y casi el mismo de alto.
   El alto se acota a la ventana (menos el header y el aire de la sección) para
   que a 1280x720 entre entero. Vidrio, velo, foto, pase y flechas: sin cambios.
   Sólo desde 900px; debajo el recuadro ya ocupa el ancho y va en una columna.
   ⚠️ `_tools/verificar.js` comprueba que desde 900px esté CENTRADO (antes
   comprobaba que arrancara en el borde del contenedor). */
@media (min-width: 900px){
  .testi-vidrio{
    width: min(100%, 40rem);
    min-height: min(38rem, calc(100vh - 90px - 2 * clamp(2.5rem, 7vh, 5rem)));
    margin-inline: auto;
    justify-content: space-between;
    gap: 1.6rem;
  }
}

/* El pie: contador a la izquierda, barra del pase en el medio, flechas a la
   derecha, debajo de un filete. */
.testi-pie{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 1.2rem;
  border-top: 1px solid rgba(255, 255, 255, .16);
}
/* ⚠️ LA BARRA DEL PASE AUTOMÁTICO. Oculta de base: sólo existe si el pase existe
   (clase `testi-con-pase`, la pone js/main.js), así que sin JS o con movimiento
   reducido no queda una barra vacía que no significa nada. El relleno lo anima
   js/main.js desde `programarPase` con la duración real del pase (PASE_MS): no
   tiene tiempo propio en el CSS a propósito, para que nunca se desfase. */
.testi-pase{
  display: none;
  flex: 1;
  height: 2px;
  background: rgba(255, 255, 255, .18);
  border-radius: 2px;
  overflow: hidden;
}
.testi-con-pase .testi-pase{ display: block; }
.testi-pase > span{
  display: block;
  height: 100%;
  background: var(--c-cyan);
  transform-origin: 0 50%;
  transform: scaleX(0);
}
@media (prefers-reduced-motion: reduce){ .testi-con-pase .testi-pase{ display: none; } }
.testi-nav{ display: flex; gap: .7rem; flex-shrink: 0; }
/* `.team-arrow` (flechas del recorrido del equipo, 2026-09-17) comparte el
   aspecto a propósito. El JS de Testimonios toma sus flechas sólo por id
   (#testiPrev/#testiNext), así que compartir la clase visual no lo afecta. */
.testi-arrow, .team-arrow{
  width: 42px; height: 42px;
  border-radius: 50%;
  background: transparent;
  border: 1.5px solid rgba(255,255,255,.3);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--dur-micro), border-color var(--dur-micro);
}
.testi-arrow svg, .team-arrow svg{ width: 16px; height: 16px; color: #fff; transition: color var(--dur-micro); }
.testi-arrow:hover, .team-arrow:hover{ background: var(--c-indigo-2); border-color: var(--c-indigo-2); }
.testi-arrow:hover svg, .team-arrow:hover svg{ color: #fff; }

/* Dentro del recuadro las flechas miden 44px (tamaño de toque) y el borde es un
   poco más visible sobre el vidrio que sobre el fondo plano de antes. Va con la
   clase del recuadro para no cambiar las del equipo, que comparten el aspecto. */
.testi-vidrio .testi-arrow{ width: 44px; height: 44px; border-color: rgba(255, 255, 255, .4); }
.testi-vidrio .testi-arrow:hover{ border-color: var(--c-indigo-2); }

/* ⚠️ LA CITA OCUPA SIEMPRE EL ALTO DE LA MÁS LARGA, centrada en ese alto, A
   CUALQUIER ANCHO. Así el recuadro no cambia de tamaño cada 3 s y ni el
   contador ni las flechas se mueven de una cita a otra (0px de salto). El valor
   lo mide js/main.js («reserva el alto»). Antes valía sólo bajo 900px, porque en
   escritorio las flechas iban fijas arriba del panel; en el recuadro van abajo,
   así que vale siempre. */
.testi-quote{
  margin: 0;
  min-height: var(--testi-cita-alto, auto);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* ⚠️ LA CITA VA CON EL CUERPO DE `.lede` (2026-09-18). El cliente marcó que «el
   tamaño de las fuentes de testimonio no coincide con los demás del sitio»:
   medido, la cita iba a 24px / 300 en escritorio mientras el texto destacado de
   Áreas, Reconocimientos y Contacto va a 20px / 400. Ahora usa exactamente la
   misma escala (clamp y peso); sólo el color es propio, blanco sobre el vidrio.
   No volver a agrandarla sólo en escritorio. */
.testi-quote p{
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  line-height: 1.65;
  font-weight: 400;
  color: #fff;
}
/* ⚠️ La fuente va en CIAN y no en `--c-blue`: el azul daba 3,14:1 sobre el
   fondo oscuro y es texto de 14,7px (pide 4,5:1). El cian es el color que más
   exige al vidrio: con él se midió el contraste de las 5 fotos. */
.testi-quote footer{
  margin-top: 1rem;
  font-size: .92rem;
  font-weight: 700;
  color: var(--c-cyan);
}

/* `min-width` con el ancho de «15 / 15»: sin él la barra del pase se estiraba y
   encogía unos px al pasar de 9 a 10. */
.testi-counter{
  min-width: 3.6em;
  font-size: .85rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: rgba(255, 255, 255, .72);
  letter-spacing: .02em;
}

.testi-media-img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* ⚠️ TRANSICIÓN "GALLERY", RÉPLICA DE foodcomplianceinternational.com
   (2026-09-16, pedido del cliente). La imagen nueva va dentro de esta máscara,
   que se descubre desde un borde con `clip-path`, mientras la imagen actual
   —la de abajo— queda quieta. En reposo la máscara está cerrada del todo
   (`inset(0 0 0 100%)`). La anima js/main.js cuadro a cuadro.
   El recorte va en la MÁSCARA y la escala en la IMAGEN, y no se pueden juntar:
   `clip-path` se aplica en el sistema de coordenadas del propio elemento, así
   que sobre la imagen transformada el borde del recorte se escalaría y correría
   con ella en vez de avanzar derecho. */
.testi-media-mascara{
  position: absolute;
  inset: 0;
  overflow: hidden;
  clip-path: inset(0 0 0 100%);
}
.testi-media-img--top{ transform-origin: 50% 50%; }
/* ⚠️ LA FRANJA DE ABAJO. En la referencia cada celda tiene DOS copias de la foto
   apiladas —la segunda justo debajo, fuera de vista— y el efecto escala las dos,
   cada una DESDE SU PROPIO CENTRO. Al ampliarse, la de abajo sube su borde y
   asoma por el pie de la foto: se ve el principio de la foto repetido abajo, en
   una franja de ½ × alto × (escala − 1) que desaparece al asentarse. La marcó el
   cliente con una captura («fijate cómo entra y se divide»), y se midió en su
   sitio en cámara lenta: a escala 1,245 y 700px de alto, 86px de franja.
   Esta copia la reproduce: mismo tamaño, pegada debajo y con el mismo transform.
   La máscara la recorta igual que a la otra.
   Desde 2026-09-17 la foto cubre la sección entera, así que el corrimiento
   (25% del ancho, js/main.js) y la franja se miden sobre la pantalla completa:
   es la misma fórmula sobre una foto más grande. */
.testi-media-img--bajo{ top: 100%; bottom: auto; }

/* MÓVIL (<900px): la foto sigue a sangre, el velo va de abajo hacia arriba y el
   recuadro ocupa el ancho del contenido, apoyado abajo. Arriba queda una franja
   de foto limpia (el `padding-top`).
   ⚠️ `padding-bottom` = gutter + 4,5rem: el botón flotante de WhatsApp mide 56px
   a 1rem del borde (.wa-float); sin ese aire, con la sección al pie de la
   pantalla, tapaba la flecha «siguiente». */
@media (max-width: 899px){
  .testimonios{
    align-items: flex-end;
    min-height: calc(100vh - 90px);
    min-height: calc(100svh - 90px);
    padding-top: clamp(12rem, 50vw, 20rem);
    padding-bottom: calc(var(--gutter) + 4.5rem);
  }
  .testi-media::after{
    background: linear-gradient(180deg,
      rgba(var(--testi-velo), 0) 20%,
      rgba(var(--testi-velo), .55) 50%,
      rgba(var(--testi-velo), .85) 100%);
  }
  .testi-vidrio{ width: 100%; padding: 1.6rem 1.4rem 1.3rem; gap: 1.1rem; }
}

/* ==========================================================================
   Reconocimientos — flows normally in the page; all 6 cards shown at once.
   ========================================================================== */
/* ⚠️ FONDO BLANCO SÓLIDO (2026-09-18, pedido del cliente en reunión:
   «Reconocimientos internacionales fondo sólido blanco»). Hasta ese día llevaba
   la foto de la estatua de la justicia (img/sobrenosotros.webp) fija a la
   derecha; la imagen no la usa ninguna otra regla y quedó sin referencias. */
.reconocimientos{
  position: relative;
  color: var(--c-indigo-2);
  overflow: hidden;
  background: #fff;
  /* ⚠️ COMO MÍNIMO UNA PANTALLA, PERO NUNCA MÁS QUE UNA 16:9 DEL MISMO ANCHO
     (2026-09-19). El 100vh venía de cuando la sección tenía la foto de la
     estatua con `fixed`; con fondo blanco liso sólo agregaba blanco en las
     pantallas más altas que 16:9 (1280x1024: ~300px; tablet vertical 1024x1366:
     casi una pantalla vacía al entrar desde el menú). 56.25vw es el alto de un
     16:9 de ese ancho: en toda ventana 16:9 da lo mismo que antes. */
  min-height: min(100vh, 56.25vw);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: clamp(4rem, 8vw, 7rem);
}
.reconocimientos > .container{ width: 100%; }
.reconocimientos .section-head{ margin-bottom: 0; }
/* ⚠️ SIN override de tamano. Antes esto pisaba la escala global con
   clamp(2.2rem, 4.4vw, 3.4rem) —3.4rem contra los 2.9rem de todos los demas
   h2 del sitio— y al unificar las dos partes quedaba el unico titular de
   seccion de otro tamano. Ahora hereda `h2` (ver "Typography"): mismo peso,
   mismo tamano, misma jerarquia que #areas, #equipo y #contacto.
   El color si es propio: la seccion tiene fondo claro. */
/* .78 y no .7 desde el fondo blanco: con .7 daba 4,6:1, al límite de AA. */
.reconocimientos .lede{ color: rgba(46,48,146,.78); }

.badges-track-wrap{
  width: 100%;
  margin-top: clamp(1.5rem, 3vw, 2.5rem);
  margin-inline: auto;
}
.badges-track{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 1.75rem;
}
/* ⚠️ ENTRE 700 Y 999PX, TRES POR FILA (2026-09-19). Con el mínimo de 220px a
   768 entraban 2: tres filas de tarjetas enormes (220x396) para un título de
   12,8px, y la sección medía casi una pantalla y media. */
@media (min-width: 700px) and (max-width: 999px){
  .badges-track{ gap: 1rem; }
  .reconocimientos .badge-card{ width: min(220px, calc((100% - 2rem) / 3)); }
}
.badge-card{
  flex: 0 0 auto;
  width: clamp(220px, 20vw, 320px);
  min-width: 0;
  height: auto;
  aspect-ratio: 3 / 4.8;
  border-radius: var(--radius-md);
  color: #fff;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 2rem 1.75rem 1.75rem;
  overflow: hidden;
  user-select: none;
}
/* Las 6 en una sola fila. La alternancia de tamano/color (nth-child odd/even)
   funciona igual con las 6.
   ⚠️ EL BREAKPOINT ERA 700px Y ES DEMASIADO PRONTO. Con seis columnas a 768px
   de viewport cada tarjeta queda en 104px de ancho —69px de contenido—, el
   titulo se hyphena en cada palabra y el line-clamp lo corta: a 768 se leia
   "Lideres en Derecho Financi...". Seis en fila necesitan ~150px por tarjeta
   como minimo, o sea 6x150 + 5 huecos de 16 = 980px de contenido, y de ahi sale
   el 1000px. Por debajo, .badges-track sigue siendo el flex con wrap de arriba
   y las tarjetas se acomodan de a dos o tres por fila, que se lee bien.
   Comprobado con _tools/verificar.js (compara scrollHeight/clientHeight de los
   titulos) a 768 y a 1024. */
@media (min-width: 1000px){
  .badges-track{
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 1rem;
  }
  .badge-card{ width: 100%; padding: 1.5rem 1.1rem 1.1rem; }
}
@media (min-width: 1100px){
  .badges-track{ gap: 1.5rem; }
  .badge-card{ padding: 1.75rem 1.4rem 1.4rem; }
}
.badge-card:nth-child(odd){ background: var(--c-indigo-2); }
.badge-card:nth-child(even){
  /* every other card stands out — taller, featured, dark. Azul marino desde el
     2026-09-18 (antes #231f20), igual que las tarjetas pares de #areas. */
  background: var(--c-navy);
  aspect-ratio: 3 / 5.4;
}

.badge-card-years{ display: flex; flex-wrap: wrap; gap: .35rem; }
.badge-card-years span{
  padding: .3rem .65rem;
  border-radius: var(--radius-pill);
  background: rgba(255,255,255,.14);
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .02em;
}

.badge-card-title{
  /* ⚠️ BAJADO de clamp(1.2rem, 1.7vw, 1.55rem) y el line-clamp SUBIDO de 4 a 5.
     Los dos cambios van juntos y arreglan lo mismo: a 1.55rem en una tarjeta de
     177px de ancho (que es lo que mide con seis en fila a 1440), "Lideres en
     Derecho Financiero" ocupaba 7 lineas hyphenadas y el line-clamp de 4 lo
     cortaba con puntos suspensivos — se leia "Lideres en Dere-cho Finan-...".
     Pasaba en 3 de las 6 tarjetas y ya venia asi de la part-2.
     A 1.25rem las palabras largas del set —Financiero, Recomendada,
     Intelectual, Impuestos— entran sin partirse en los 132px de contenido de la
     tarjeta, y en 5 lineas cabe el titulo mas largo.
     ⚠️ El line-clamp NO se saca: es la red de seguridad si algun dia entra un
     titulo mas largo. Lo que no puede volver a pasar es que corte los actuales;
     _tools/verificar.js lo comprueba comparando scrollHeight con clientHeight.

     ⚠️ SIN hyphens:auto A PARTIR DEL 2026-08-06 — pedido del cliente: no
     quería ver "Recomen-" en una línea y "dada" en la siguiente (pasaba en
     los anchos angostos del grid de 6 columnas, 1000-1100px, donde la
     tarjeta es más angosta que los 177px con los que se afinó el tamaño de
     letra de arriba). Ahora una palabra larga se envuelve ENTERA a la línea
     siguiente en vez de partirse. `word-break: break-word` sigue como red de
     seguridad para el caso límite de una palabra más ancha que la tarjeta
     (partiría sin guion, pero eso ya lo vigila _tools/verificar.js con "ninguna
     palabra se parte sin guion" — antes ese chequeo se saltaba este elemento
     porque tenía hyphens:auto).

     ⚠️ EL CLAMP TAMBIÉN SE ACHICÓ (de 1.05rem–1.25rem a 0.8rem–1rem), y no es
     el mismo motivo que el de arriba. Sin hyphens:auto, "Recomendada" tiene
     que entrar ENTERA en el ancho de contenido de la tarjeta a CUALQUIER
     ancho de pantalla, no solo en el más angosto: medido con
     _tools/verificar.js, al tamaño viejo "Recomendada" desbordaba su caja
     (y por lo tanto se partía SIN guion, vía word-break) en 1920, 1440 Y
     1024 — en los dos primeros porque `.badges-track` tiene un ancho tope
     (hereda el `max-width` del `.container` en el que vive) mientras el
     font-size seguía creciendo con el viewport; en 1024 porque ahí el
     font-size ya estaba en el piso del clamp viejo (1.05rem) y la tarjeta
     todavía se achica hasta 1100px. Este tamaño nuevo se verificó sin fallos
     en los 6 anchos que prueba esa herramienta. */
  font-size: clamp(.8rem, 1.1vw, 1rem);
  font-weight: 700;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 5;
  line-clamp: 5;
  overflow: hidden;
  overflow-wrap: break-word;
  word-break: break-word;
}

.badge-card-logo{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: flex-start;
  max-width: 100%;
}
/* Each logo sets its own --logo-h inline (see index.html) so every mark
   reads at a consistent visual weight regardless of its native proportions. */
.badge-card-logo img{ max-height: var(--logo-h, 46px); max-width: 100%; width: auto; object-fit: contain; display: block; pointer-events: none; }
/* ⚠️ LOGOS DE TINTA OSCURA, EN BLANCO (2026-09-18). IFLR1000 es negro puro e
   IP STARS azul marino: sobre sus tarjetas (índigo y azul marino) casi no se
   veían. Se pasan a una silueta blanca, que es como ya se ven los otros cuatro
   (Legal 500 e ITR son blancos de origen). Se eligió esto y no una placa clara
   como la de #alianzas porque una placa en 2 de 6 tarjetas rompía la fila. */
.badge-card-logo img.logo-claro{ filter: brightness(0) invert(1); }

/* ==========================================================================
   Novedades — solid blue background, huge centered title, glass cards
   ========================================================================== */
.novedades-section{
  background: var(--c-indigo-2);
  overflow: hidden;
  /* Mismo tope que `.reconocimientos` (2026-09-19): 47.8vw es el 85% de un
     16:9 del mismo ancho. Sólo cambia en pantallas más altas que 16:9. */
  min-height: min(85vh, 47.8vw);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.novedades-title{
  /* ⚠️ Título centrado ARRIBA de las tarjetas y sin superposición desde el
     2026-09-18, igual que «Alianzas globales» (regla del cliente: las dos
     palabras iguales, controlada por _tools/medir_global.js). Hasta ese día era
     una palabra de fondo enorme en absoluto, detrás de las tarjetas. Mismo
     color #a8c4ff al 28%, peso 800 y tamaño que .allies-word. */
  position: relative;
  z-index: 1;
  pointer-events: none;
  color: #a8c4ff;
  opacity: .28;
  font-weight: 800;
  font-size: clamp(1.75rem, 6vw, 6.5rem);   /* igual que .allies-word */
  line-height: 1.05;
  letter-spacing: -.03em;
  margin: 0 0 clamp(1.5rem, 3vw, 2.75rem);
  padding-inline: var(--gutter);
  text-align: center;
  text-wrap: balance;
}
.novedades-section .btn--ghost{
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,.35);
  color: #fff;
}
.novedades-section .btn--ghost:hover{
  box-shadow: inset 0 0 0 1.5px var(--c-cyan);
  color: var(--c-cyan);
}

.news-grid{
  position: relative;
  z-index: 1;
  margin-top: 3rem;
  display: grid;
  gap: 1.6rem;
  max-width: 1180px;
  margin-inline: auto;
}
@media (min-width: 760px){ .news-grid{ grid-template-columns: repeat(3, 1fr); gap: 2rem; } }

.news-grid--glass .news-card{
  border-radius: var(--radius-md);
  background: rgba(255,255,255,.08);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border: 1px solid rgba(255,255,255,.16);
  box-shadow: 0 20px 45px rgba(12,13,36,.25);
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  transition: transform var(--dur-micro) var(--ease-soft), box-shadow var(--dur-micro) var(--ease-soft), background var(--dur-micro) var(--ease-soft);
}
.news-grid--glass .news-card:hover{
  transform: translateY(-6px);
  background: rgba(255,255,255,.13);
  box-shadow: 0 26px 55px rgba(12,13,36,.3);
}
/* Image sits inset within the card's own padding (not edge-to-edge),
   with its own smaller radius nested inside the card's rounded corners. */
.news-grid--glass .news-thumb{ position: relative; aspect-ratio: 1/1; overflow: hidden; border-radius: var(--radius-sm); }
.news-grid--glass .news-thumb img{ width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease-soft); }
.news-grid--glass .news-card:hover .news-thumb img{ transform: scale(1.06); }
.news-tag{
  position: absolute;
  top: .85rem;
  left: .85rem;
  z-index: 2;
  background: var(--c-blue);
  color: #fff;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  padding: .35rem .7rem;
  border-radius: var(--radius-pill);
}
.news-grid--glass .news-body{ padding: 0; margin-top: 1rem; display: flex; flex-direction: column; }
/* ⚠️ EN 3 COLUMNAS ANGOSTAS LA ETIQUETA SE ACHICA (2026-09-19). Mide lo mismo
   en px en todos los anchos, pero entre 760 y 999 la miniatura baja a ~150px y
   la etiqueta tapaba el primer renglón del titular dibujado en la imagen (en la
   del Mundial desaparecía «¿Sabías que hablar del»). */
@media (min-width: 760px) and (max-width: 999px){
  .news-tag{ top: .4rem; left: .4rem; font-size: .5rem; padding: .2rem .42rem; }
}
.news-foot{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .35rem 1rem;
}
/* ⚠️ LA FECHA NO SE PARTE (2026-09-19). Con 3 columnas angostas (tablets
   verticales, 760–990px) «Leer más» no cede (`nowrap`) y la fecha se partía
   palabra por palabra: «11 de / junio / de / 2026». Ahora la fecha va entera
   y, si no entra al lado, «Leer más» baja a un segundo renglón. Donde ya
   entraban en uno —≥1000px y móvil— no cambia nada. Vale para las dos
   variantes de tarjeta (vidrio del home y clara del listado). */
.news-foot .news-date{ white-space: nowrap; }
.news-grid--glass .news-date{ font-size: .78rem; color: rgba(255,255,255,.5); }
.news-grid--glass .link-arrow{ font-size: .88rem; color: var(--c-cyan); white-space: nowrap; }

.news-cta{ position: relative; z-index: 1; margin-top: 3rem; text-align: center; }

/* ⚠️ LAS UNIONES OSCURO↔OSCURO SE SUPERPONEN 1PX (2026-09-19). Con el
   escalado de Windows al 125% o 150% el borde entre dos secciones cae a mitad
   de una fila física, ninguna de las dos la cubre entera y asoma el blanco del
   <body>: una línea gris clara a todo el ancho entre Novedades y Contacto y
   entre Contacto y el pie (la misma «línea blanca» que el cliente ya marcó
   entre Equipo y Testimonios, que tiene su propio parche). Subiendo 1px la
   sección de abajo, su fondo tapa esa fila. A escala 100% no se nota nada. */
#contacto, .site-footer{ margin-top: -1px; }

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer{
  /* ⚠️ EL COLOR DEL PIE DEL SITIO ACTUAL (2026-09-18, pedido del cliente en
     reunión: «footer color de fondo igual al de la web actual»). pstbn.com.py
     (WordPress + Elementor, plantilla de pie 2367) pinta el pie en #141714 —un
     negro grafito— y el crédito en una franja #000 a todo el ancho; acá se
     replican las dos (ver .footer-credit). Hasta ese día era #232463, un
     índigo propio pedido el 2026-08-06. Con el fondo más oscuro el contraste
     de todos los textos del pie sólo mejora (el más bajo, el crédito, ~6:1). */
  background: #141714;
  color: rgba(255,255,255,.85);
  padding-block: clamp(3.5rem, 7vw, 5rem) 0;
}
.footer-top{
  display: grid;
  gap: 2.5rem;
  padding-bottom: 3rem;
  border-bottom: 1px solid rgba(255,255,255,.2);
}
@media (min-width: 860px){ .footer-top{ grid-template-columns: 1.3fr 1fr 1fr 1fr; } }
/* ⚠️ PASO INTERMEDIO (2026-09-19): entre 560 y 859 el pie iba en una sola
   columna, con más de la mitad del ancho vacío, y medía más que una pantalla
   (768x1024, 820x1180). La marca arriba a todo el ancho y las tres columnas de
   enlaces en fila. Desde 600 y no desde 560: más angosto, «info@pstbn.com.py»
   (que no se parte) se salía de su columna. */
@media (min-width: 600px) and (max-width: 859.98px){
  .footer-top{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .footer-brand{ grid-column: 1 / -1; }
}
.footer-brand-logo{ margin-bottom: 1.1rem; }
/* El logo del footer es el SVG (img/assets/logo-pstbn-light.svg), no el PNG de
   150x74 que traia la part-2: a 68px de alto el raster se veia blando. El
   wordmark de la variante -light ya viene en blanco, que es lo que hace falta
   sobre el fondo oscuro del footer. */
.footer-brand-logo img{ height: 68px; width: auto; }
.footer-brand p{ font-size: .9rem; line-height: 1.6; max-width: 320px; color: rgba(255,255,255,.72); }
.footer-col h4{
  font-size: .8rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(255,255,255,.65);
  margin-bottom: 1.1rem;
}
.footer-col ul{ display: flex; flex-direction: column; gap: .7rem; }
.footer-col a{ font-size: .92rem; color: rgba(255,255,255,.85); }
.footer-col a:hover{ color: var(--c-cyan); }
.footer-bottom{
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
  align-items: center;
  padding-top: 1.8rem;
  font-size: .82rem;
  color: rgba(255,255,255,.65);
}
.footer-bottom .social-row a{ background: rgba(255,255,255,.1); border-color: rgba(255,255,255,.2); }
.footer-bottom .social-row a:hover{ background: rgba(255,255,255,.2); }
.footer-bottom .social-row a svg{ color: #fff; }
.footer-credit{
  /* 2.5rem y no 1.5 (2026-09-19): con 1.5 la fila social quedaba a la altura
     del botón flotante de WhatsApp y, en anchos de 1280 o menos —donde el
     contenedor llega al borde—, el círculo verde tapaba el ícono de LinkedIn al
     llegar al final de la página. */
  margin-top: 2.5rem;
  padding-block: 1.1rem;
  text-align: center;
  font-size: .82rem;
  color: rgba(255,255,255,.55);
  /* Franja negra a TODO el ancho, como en el sitio actual, aunque el crédito
     vive dentro de .container: la sombra la extiende a los costados y el
     clip-path la recorta a su propio alto. Una sombra no genera scroll
     horizontal, así que no hace falta tocar el HTML de las 35 páginas. */
  background: #000;
  box-shadow: 0 0 0 100vmax #000;
  clip-path: inset(0 -100vmax);
}
.footer-credit a{ color: rgba(255,255,255,.85); font-weight: 700; }
.footer-credit a:hover{ color: var(--c-cyan); }

/* ==========================================================================
   Botón flotante de WhatsApp
   ==========================================================================
   Abajo a la derecha. El .lang-switcher también está fijo a la derecha pero
   centrado en vertical, así que no se pisan: si alguna vez se mueve el
   switcher, revisar esta convivencia.
   ========================================================================== */
.wa-float{
  position: fixed;
  right: clamp(1rem, 2.5vw, 1.75rem);
  bottom: clamp(1rem, 2.5vw, 1.75rem);
  z-index: 85;
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #25d366;
  color: #fff;
  box-shadow: 0 12px 30px rgba(37,211,102,.4);
  transition: transform var(--dur-micro) var(--ease-soft),
              box-shadow var(--dur-micro) var(--ease-soft);
}
.wa-float svg{ width: 30px; height: 30px; }
.wa-float:hover{ transform: translateY(-3px) scale(1.05); box-shadow: 0 16px 38px rgba(37,211,102,.55); }
/* El pulso venia de la part-2 (ahi el boton era de 60px y sin hover-lift). Al
   unificar se conservo la geometria de la part-1 —56px, z-85, para no pisar el
   .lang-switcher— y de la part-2 solo el pulso, que es lo unico que aportaba.
   El aro late por fuera del box-shadow del reposo, asi que no se pelea con el
   del hover: ese lo reemplaza mientras dura. */
@keyframes wa-pulse{
  0%, 100%{ box-shadow: 0 12px 30px rgba(37,211,102,.4); }
  50%{ box-shadow: 0 12px 30px rgba(37,211,102,.4), 0 0 0 10px rgba(37,211,102,.12); }
}
.wa-float{ animation: wa-pulse 2.6s ease-in-out infinite; }
.wa-float:hover{ animation: none; }
@media (prefers-reduced-motion: reduce){
  .wa-float{ animation: none; }
}
@media (max-width: 900px){
  .wa-float{ width: 50px; height: 50px; }
  .wa-float svg{ width: 26px; height: 26px; }
}

/* ==========================================================================
   EQUIPO — DIRECTORIO COMPLETO (pagina aparte, equipo.html)
   ==========================================================================
   Pagina nueva (2026-08-10): reutiliza el header/nav/footer y el sistema de
   diseño de arriba tal cual. Este bloque cubre solo lo propio de la pagina:
   el banner "Equipo" y la grilla de tarjetas con buscador y filtros.
   Datos de las tarjetas: _tools/equipo.json + _tools/gen_equipo_directorio.js
   (ver project_reference.md).
   ========================================================================== */

/* ⚠️ ESTA PÁGINA USA EL MISMO HEADER QUE LA FICHA DE PROFESIONAL desde el
   2026-08-12, por pedido del cliente: transparente sobre el banner oscuro y con
   fondo en cuanto el banner deja de estar detrás. Lo alterna `onScrollHeader()`
   en js/main.js, que reconoce `.team-banner` como zona oscura igual que
   reconoce `.perfil-portada` (ver el bloque de PÁGINAS INTERNAS).

   Antes el planteo era el contrario —header sin fondo en todo el alto, pedido
   del 2026-08-10, y el logo APAGÁNDOSE al bajar del banner porque el cuerpo es
   claro y el logo blanco—. Ese listener se retiró de js/equipo-directorio.js:
   con fondo, el logo se lee y no hace falta esconderlo, y dos dueños del mismo
   elemento se pelean.

   ⚠️ CÓDIGO MUERTO, se conserva a propósito (mismo criterio que .hero-note--left
   y .outro-num): ya nadie pone `is-hidden-brand`. Queda por si el planteo
   anterior vuelve. */
.page-equipo .brand{ transition: opacity .3s var(--ease-soft); }
.page-equipo .brand.is-hidden-brand{ opacity: 0; pointer-events: none; }

/* --- Banner ---
   Versión final (2026-08-11): recurso provisto por el cliente,
   img/fondoazul.png — azul sólido con un hueco en forma de arco recortado
   con transparencia real (canal alfa verificado: el hueco da alpha 0, no
   es blanco opaco). Reemplaza a las versiones anteriores hechas a mano con
   SVG clipPath/mask (esas quedan documentadas en changelog.md, con el
   motivo de cada descarte). */
.team-banner{
  position: relative;
  overflow: hidden;
  background: var(--c-indigo-2);
  color: #fff;
  /* .section-pad ya pone el padding vertical del sistema; se le suma el alto
     del header fijo (90px: la misma constante que scroll-padding-top y el
     offset de lenis.scrollTo en js/main.js) para que el titulo no arranque
     tapado por el header. */
  padding-top: calc(var(--pad-block) + 90px);
  min-height: clamp(320px, 50vh, 560px);
  display: flex;
  align-items: flex-start;
}
.team-banner .container{ position: relative; z-index: 2; padding-top: clamp(1.5rem, 4vw, 2.5rem); }
.team-banner h1{ max-width: 14ch; }

/* ==========================================================================
   ✏️  POSICIÓN DE LA PALABRA "Equipo" — LOS ÚNICOS DOS VALORES A TOCAR
   ==========================================================================
   Cambiá los dos números de acá abajo y la palabra se mueve. Nada más.

       --equipo-x    +   la mueve a la DERECHA      −  a la IZQUIERDA
       --equipo-y    +   la mueve para ABAJO        −  para ARRIBA

   Ejemplo: `--equipo-y: 90px` la baja 90 píxeles.

   ⚠️ DESDE EL 2026-08-13 ESTO MUEVE SÓLO LA PALABRA. Antes el mismo número
   entraba también en el `min-height` del banner, así que al subir la palabra el
   banner se achicaba y la foto se re-encuadraba. El alto ahora vive en su propia
   variable, `--banner-extra` (ver "EL BANNER TIENE QUE RESERVARLE LA BANDA A LA
   CURVA", más abajo en este archivo). Bajar la palabra más allá de
   `--banner-extra` sí sigue agrandando el banner, y tiene que seguir haciéndolo:
   es lo que evita que el titular blanco caiga sobre el relleno blanco de la curva.

   ⚠️ EL LÍMITE HACIA ARRIBA es el header fijo, que termina a 115px del techo del
   banner (97px en móvil). Medido con `--equipo-y: -60px`, el título arranca a
   162px en el ancho más ajustado (1024×700): quedan 47px de aire. Cerca de
   −100px se empieza a meter debajo del header.

   ⚠️ POR QUÉ ESTO NO ROMPE NADA, Y POR QUÉ NO SE HACE CON padding/margin.
   `transform` es la única propiedad que mueve un elemento SIN participar del
   layout: el navegador reserva el lugar original y después lo dibuja corrido.
   O sea que el alto del banner, el recorte de fondoazul.png, el parallax de la
   foto y el resto de la página no se enteran — no es que estén "calibrados"
   para aguantarlo, es que literalmente no pueden verse afectados.

   Con padding o margin sí se rompen cosas, y ya pasó: subir el padding empuja
   el contenido y a partir de cierto punto EL BANNER CRECE; y bajar el
   padding-bottom para anclar el texto al pie hizo que en 1024×700 el banner
   pasara de 375px a 350px (ahí el alto lo daba el contenido, no el
   min-height). Con transform nada de eso puede pasar.

   Verificado además que ningún JS mide este <h1>: `js/equipo-directorio.js`
   mide `#equipoBanner` (la sección) y `.team-banner-photo img` (la foto del
   parallax) — nunca el título.

   ⚠️ EL LÍMITE: `.team-banner` tiene `overflow: hidden`, así que si la corrés
   más allá del borde del banner se RECORTA. Margen real hasta que empieza a
   recortarse, medido cuando el banner NO tenía la curva:

       ancho        alto del banner    podés bajar hasta
       1920×1080         540px              +211px
       1440×900          450px              +121px
       1024×700          375px               +92px   ← el más ajustado
        768×1024         512px              +277px
        390×844          422px              +203px

   ⚠️ ESA TABLA QUEDÓ DESACTUALIZADA EL 2026-08-12, y hacia el lado bueno: al
   sumarse el separador de marca, el `min-height` del banner pasó a incluir el
   alto de la curva **y este mismo desplazamiento**, así que el banner crece con
   lo que bajes y el recorte por `overflow` dejó de ser el límite real.
   El límite ahora es OTRO: la palabra no puede meterse en la banda de la curva,
   porque el relleno es blanco y la palabra también. Medida la distancia entre el
   pie del titular y el techo de la curva con `--equipo-y: 97px`:

       1920×1080  210px      1440×900  120px      1024×700   66px   ← el ajustado
        768×1024  276px       390×844  202px

   O sea que hay margen para bajarla bastante más, pero el que manda es el 66px
   de 1024×700. Si la tocás, correr la comprobación de la curva: mide justamente
   que el titular no entre en la banda.

   ⚠️ SI LO QUE BUSCÁS ES QUE QUEDE SOBRE EL AZUL: hoy la palabra cae en el
   hueco del arco, o sea encima de la foto. Lo que haría falta bajar para
   llegar a la cuña azul de abajo, medido sobre los píxeles en cada ancho:

       1920 → +241px      1440 → +121px      1024 → +72px
        768 → +242px       390 → +198px

   Como ves NO hay un solo número que sirva para todos (la cuña se mueve con el
   recorte de `object-fit: cover`, no linealmente): si querés eso, hay que dar
   valores distintos por ancho con los media queries de abajo. Y ojo que en
   1440 y 1920 la palabra igual no entra ENTERA en la cuña: es diagonal y
   "Equipo" mide 266px de ancho, así que la cola queda sobre la foto.
   ========================================================================== */
.team-banner{
  --equipo-x: 0px;
  /* NEGATIVO: el bloque SUBE. Pedido del cliente (2026-08-13): "la palabra
     Profesionales más arriba, en la parte azul, sin mover ni agrandar el
     banner; el filtro también más arriba".
     Con -100px el titular arranca a 150px del techo del banner —35px por
     debajo del header, que termina en 115— y, sobre todo, el FILTRO ENTERO
     queda dentro del azul: con el valor anterior caía justo sobre el borde
     donde asoma la foto y se leía peor.
     ⚠️ El alto del banner NO cambia: la reserva es
     `max(--banner-extra, --equipo-y)` y con un valor negativo manda
     `--banner-extra`. Verificado en 8 anchos. */
  --equipo-y: -70px;
}
/* ⚠️ LA TRANSFORMACIÓN VA EN EL `.container`, NO EN EL `<h1>` (2026-08-13).
   Desde que el filtro vive dentro del banner, el titular y el filtro son UN
   bloque y tienen que moverse juntos. Si el transform siguiera en el `h1`, el
   filtro se colocaría según la caja ORIGINAL del titular —el transform no
   participa del layout, que es toda su gracia— y los dos se pisarían: el
   filtro dibujado justo donde estaba el título antes de correrse. */
.team-banner .container{
  transform: translate(var(--equipo-x), var(--equipo-y));
}

/* ✏️ CUÁNTO SUBE EL TITULAR **SOLO** (2026-08-13). Pedido del cliente: "que la
   palabra Profesionales se suba más sin afectar ninguna otra cosa".

   ⚠️ ES UN TRANSFORM PROPIO DEL h1, Y ESO ES TODO EL TRUCO. `--equipo-y` mueve
   el `.container`, o sea el titular Y el filtro juntos; con esto el titular se
   corre por su cuenta y el filtro se queda donde está, porque un `transform` no
   participa del layout y la caja del h1 no se mueve.

   ⚠️ SÓLO DE 1101px PARA ARRIBA, y no por gusto: abajo de eso el banner es más
   corto y el aire que queda entre el titular y el header fijo ya es de 27-32px
   (medido a 860 y 900). Restarle 30px más lo metería debajo del header. */
.team-banner{ --titulo-sube: 0px; }
@media (min-width: 1101px){
  .team-banner{ --titulo-sube: clamp(0px, 2.2vw, 34px); }
}
.team-banner h1{ transform: translateY(calc(var(--titulo-sube) * -1)); }

/* ⚠️ VALORES DISTINTOS POR ANCHO, Y ACÁ SÍ HACEN FALTA (2026-08-13).
   Van DESPUÉS de la regla de arriba, así que la pisan.

   El techo no es el mismo en todos lados: el header fijo termina siempre a
   ~115px del borde del banner, pero el banner se ACHICA al angostarse la
   pantalla (777px a 1920, 568px a 900), así que el mismo -100px que a 1440 deja
   35px de aire, más abajo mete el titular DEBAJO del header. Medido con -100px
   en todos lados: 900px → -8px, 768px → -25px, 390px → -19px, o sea el titular
   tapado por el header en los tres.

   Los tres tramos dejan entre 32 y 47px de aire bajo el header. Si se cambia
   alguno, medir de nuevo: `h1.top - header.bottom` tiene que quedar en positivo
   con margen, no al ras. */
@media (max-width: 1100px){
  .team-banner{ --equipo-y: -60px; }
}
/* 820 y no 760: a 768px —el ancho de tablet que mide la suite— los -60px del
   tramo de arriba dejaban el titular a 15px del header. Con -40px quedan 35. */
@media (max-width: 820px){
  .team-banner{ --equipo-y: -40px; }
}

/* Foto a pantalla completa, DEBAJO de fondoazul.png — se ve solo por el
   hueco transparente de esa imagen. Por eso el blur/oscurecido de acá abajo
   y el parallax de js/equipo-directorio.js (que solo mueve este <img>)
   quedan automáticamente limitados a esa porción: el resto de la foto sigue
   tapado por el azul opaco de encima, sin necesidad de recortar nada a mano. */
.team-banner-photo{ position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.team-banner-photo img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Oscurecido leve, sin blur (pedido del cliente, 2026-08-11, 9no ajuste:
     "quitale el blur, dejalo con un poco de filtro oscuro" — reemplaza al
     blur(6px)+saturate+grayscale del 8vo ajuste). Foto nítida, un solo
     filtro de brillo. */
  filter: brightness(.75);
  /* Zoom base: le da a js/equipo-directorio.js margen para desplazar la foto
     en el parallax sin que se lleguen a ver bordes vacíos (o el fondo
     índigo de `.team-banner`) en ninguno de los cuatro costados. Subido a
     1.55 junto con el RANGE del parallax (70px, 9no ajuste, 2026-08-11) para
     seguir cubriendo el recorrido como buffer en el caso más angosto
     (`.team-banner` con `min-height: 320px`: recorrido máximo 70px por lado
     necesita scale >= 1 + 2*70/320 = 1.4375, con margen de seguridad da
     1.55). Si se cambia el RANGE en ese archivo, este valor tiene que
     seguir cubriendo el nuevo recorrido como buffer. */
  transform: scale(1.55);
  will-change: transform;
  /* Suavizado del parallax: en vez de saltar 1:1 con cada tick de scroll,
     el movimiento "arrastra" un poco detrás — se lee más premium y hace más
     perceptible el desplazamiento (9no ajuste, 2026-08-11, pedido del
     cliente: "mejora el parallax"). js/equipo-directorio.js solo escribe
     valores nuevos de transform; esta transition los interpola. */
  transition: transform .5s cubic-bezier(.16, 1, .3, 1);
}
@media (prefers-reduced-motion: reduce){
  .team-banner-photo img{ transition: none; }
}

/* fondoazul.png ENCIMA de la foto, a pantalla completa. object-position
   centrado en el hueco (que en el archivo original cae un poco por encima
   de la mitad vertical) para que quede bien encuadrado en cualquier alto
   de banner. */
.team-banner-bg{
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 40%;
  pointer-events: none;
}

/* --- Directorio -------------------------------------------------------------
   ⚠️ ARRANCA MÁS ARRIBA QUE UNA SECCIÓN NORMAL, Y ES A PROPÓSITO.
   `.section-pad` le daba el relleno genérico del sistema —clamp(4rem, 9vw,
   7.5rem), 120px de 1333px para arriba—, que está pensado para una sección que
   empieza contra otra sección. Ésta no: arriba tiene la banda de la curva del
   banner, que del lado izquierdo es blanca (el relleno del path es `--bg-body`,
   igual que el fondo de acá) y ya aporta 131px de aire a 1440. Los dos se
   sumaban y quedaban 251px de blanco antes de los filtros — pedido del cliente
   (2026-08-13): "queda mucho espacio blanco al pedo".

   Sólo se pisa el relleno de ARRIBA. El de abajo sigue siendo el del sistema:
   ahí sí hay una sección normal debajo y tiene que respirar como el resto.

   Blanco total medido después del cambio (banda + este relleno), contra lo que
   había antes:

       1920  181px (era 261)    1440  171px (era 251)    1024  124px (era 185)
        768   94px (era 139)     390   89px (era 129)

   ⚠️ Al medir esta zona hay que ESPERAR EL REVEAL: `.team-filters` lleva
   `[data-reveal]`, que arranca con `translateY(28px)` hasta que el
   IntersectionObserver le pone `.is-visible`. Sin esperarlo, la primera
   medición da 28px de más y parece que el relleno fuera otro.

   ⚠️ ESTE RELLENO RECORTADO VUELVE A SER LO QUE ERA. Entre el 2026-08-13 y el
   2026-08-19 el filtro vivió en el banner y lo primero de esta sección era el
   contador; desde que el filtro volvió acá (pedido del cliente), lo que queda
   debajo de la curva es otra vez la banda de controles, que es el caso para el
   que se midieron los números de arriba. */
.team-directory{ padding-top: clamp(1.5rem, 3vw, 2.5rem); }

/* --- Filtros del directorio — ABREN LA SECCIÓN, ANTES DE LAS TARJETAS --------
   ⚠️ ESTE BLOQUE YA SE MUDÓ DOS VECES. Nació acá; el 2026-08-13 el cliente lo
   mandó al banner ("adaptar el filtro en el área del banner"); el 2026-08-19 lo
   mandó de vuelta acá ("que el filtro quede abajo… antes de las tarjetas"). Si
   vuelve a mudarse, lo que hay que mover es TODO ESTE BLOQUE: el markup no
   cambia —los mismos id y clases, y js/equipo-directorio.js los busca por ahí,
   así que le da igual dónde estén— pero **los estilos sí dependen del sitio**,
   porque el banner es oscuro y esta sección es clara.

   EL DISEÑO SE CONSERVA, SÓLO CAMBIA LA PALETA. El criterio lo fijó el cliente
   en agosto ("un estilo agradable, profesional y elegante, más tradicional") y
   sigue valiendo:

   · SIN CAJAS NI PÍLDORAS ALREDEDOR DE CADA CONTROL. Todo se apoya en LÍNEAS
     FINAS: un subrayado bajo el buscador y bajo el selector, y separadores
     verticales de 1px entre los tres. Es el recurso de los directorios impresos
     y es lo que da el aire tradicional que se pidió.
   · VERSALITAS ESPACIADAS para los botones de posición (`.06em`, el mismo
     `letter-spacing` de `.eyebrow`), en vez de negritas grandes.
   · EL ACTIVO NO SE PINTA: SE SUBRAYA. Un fondo sólido volvería a meter una
     forma cerrada, que es lo que este bloque evita.

   LO QUE SÍ CAMBIÓ AL BAJARLO:
   · Se fue el VIDRIO ESMERILADO. Existía para dar base al texto sobre la foto
     de la biblioteca, que tiene mucho detalle; acá abajo el fondo es plano y un
     `backdrop-filter` no tendría nada que desenfocar — sería coste de pintado
     sin efecto.
   · La banda pasa a `--c-mist`, el mismo gris azulado de las secciones alternas
     y de las tarjetas de organizaciones de /nosotros/. Agrupa los controles y
     los separa de las tarjetas sin cerrar una caja pesada.
   · Blancos con opacidad → tokens de tinta: `--text-body` lo activo,
     `--text-muted` lo inactivo, `--c-line` las líneas, `--c-blue` el acento.
     Medido sobre `--c-mist`: texto atenuado 6,0:1 y acento azul 5,0:1.
   ---------------------------------------------------------------------------- */
.team-directory .team-filters{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 2rem);
  padding: clamp(.9rem, 1.5vw, 1.25rem) clamp(1rem, 1.9vw, 1.6rem);
  background: var(--c-mist);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  /* ⚠️ A TODO EL ANCHO DEL CONTENEDOR, para que la banda quede al ras de la
     grilla de tarjetas que va justo debajo. En el banner llevaba `max-width:
     68rem` porque ahí flotaba sobre una foto y no tenía con qué alinearse; acá
     sí lo tiene, y una banda 100px más angosta que las fichas se lee como un
     descuido. */
  margin: 0 0 clamp(1.75rem, 3.5vw, 2.75rem);
}

/* Separadores verticales entre los tres controles. Van con ::before sobre el
   propio control y no como <hr>: no hay nada que agregar al HTML y desaparecen
   solos cuando la fila se apila en móvil (ver el media query del final). */
.team-directory .team-filter-group,
.team-directory .team-area-select{ position: relative; }
.team-directory .team-filter-group::before,
.team-directory .team-area-select::before{
  content: "";
  position: absolute;
  left: calc(clamp(1rem, 2.2vw, 2rem) / -2);
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 1.6em;
  background: var(--c-line);
}
/* Un <select> no admite ::before: el separador de su lado lo pone el elemento
   anterior con un ::after. */
.team-directory .team-area-select::before{ content: none; }
.team-directory .team-filter-group::after{
  content: "";
  position: absolute;
  right: calc(clamp(1rem, 2.2vw, 2rem) / -2);
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 1.6em;
  background: var(--c-line);
}

/* Buscador */
.team-directory .team-search{
  position: relative;
  flex: 1 1 15rem;
  min-width: 12rem;
  max-width: 20rem;
}
.team-directory .team-search svg{
  position: absolute;
  left: 0; top: 50%;
  transform: translateY(-50%);
  width: 17px; height: 17px;
  color: var(--text-muted);
  pointer-events: none;
  transition: color var(--dur-micro) var(--ease-soft);
}
.team-directory .team-search input{
  width: 100%;
  padding: .6rem 0 .6rem 1.7rem;
  border: 0;
  border-bottom: 1px solid var(--c-line);
  border-radius: 0;
  background: transparent;
  color: var(--text-body);
  font-size: .95rem;
  transition: border-color var(--dur-micro) var(--ease-soft);
}
.team-directory .team-search input::placeholder{ color: var(--text-muted); }
.team-directory .team-search input:focus{ outline: none; border-bottom-color: var(--c-blue); }
.team-directory .team-search input:focus + svg,
.team-directory .team-search:focus-within svg{ color: var(--c-blue); }
/* Cruz nativa de limpiar en Chrome/Edge (input[type=search]): la reemplaza el
   boton "Borrar filtros" del propio grupo, asi los dos caminos no compiten. */
.team-directory .team-search input::-webkit-search-cancel-button{ display: none; }

/* Posición: Todos · Socios · Asociados */
.team-directory .team-filter-group{ display: flex; flex-wrap: wrap; gap: clamp(.9rem, 1.8vw, 1.5rem); }
.team-directory .team-filter-btn{
  padding: .35rem 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--text-muted);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  position: relative;
  transition: color var(--dur-micro) var(--ease-soft);
}
/* El subrayado del activo se anima de ancho: entra desde el centro en vez de
   aparecer de golpe. `scaleX` y no `width` para que no reflowee la fila. */
.team-directory .team-filter-btn::after{
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transition: transform var(--dur-normal) var(--ease-soft);
}
.team-directory .team-filter-btn:hover{ color: var(--c-blue); }
/* ⚠️ EL ACTIVO SE DISTINGUE POR COLOR **Y** POR SUBRAYADO, no sólo por color:
   un usuario con daltonismo tiene que poder ver cuál está elegido. */
.team-directory .team-filter-btn.is-active{ color: var(--c-blue); }
.team-directory .team-filter-btn.is-active::after{ transform: scaleX(1); }
.team-directory .team-filter-btn:focus-visible{ outline: 2px solid var(--c-blue); outline-offset: 4px; }

/* Áreas de práctica */
.team-directory .team-area-select{
  flex: 0 1 16rem;
  min-width: 12rem;
  padding: .6rem 1.6rem .6rem 0;
  border: 0;
  border-bottom: 1px solid var(--c-line);
  border-radius: 0;
  background: transparent;
  color: var(--text-body);
  font-size: .88rem;
  /* La flecha nativa no se puede recolorear: se apaga y se dibuja una propia con
     un SVG inline, del mismo gris que el resto de los rótulos. */
  -webkit-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235b5f72' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .1rem center;
  background-size: 15px 15px;
  cursor: pointer;
  transition: border-color var(--dur-micro) var(--ease-soft);
}
.team-directory .team-area-select:focus{ outline: none; border-bottom-color: var(--c-blue); }
/* El desplegable abierto lo pinta el sistema; acá el <select> ya va con tinta
   oscura sobre claro, así que hereda bien y no hace falta forzar las <option>
   como sí hacía falta sobre el banner. Se dejan declaradas igual: en Windows con
   tema oscuro el menú nativo puede venir oscuro. */
.team-directory .team-area-select option{ color: var(--text-body); background: #fff; }

/* Borrar filtros — enlace discreto, no botón */
.team-directory .team-filter-clear{
  margin-left: auto;
  white-space: nowrap;
  border: 0;
  background: none;
  padding: .35rem 0;
  color: var(--text-muted);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  border-bottom: 1px solid transparent;
  transition: color var(--dur-micro) var(--ease-soft),
              border-color var(--dur-micro) var(--ease-soft);
}
.team-directory .team-filter-clear:hover:not(:disabled){ color: var(--c-blue); border-bottom-color: var(--c-blue); }
/* Deshabilitado no se esconde: se atenúa. Que se vea dónde está el botón antes
   de que haga falta evita que el usuario lo busque cuando quiera limpiar.
   ⚠️ .45 y no el .35 que tenía sobre el banner: sobre fondo claro el mismo alfa
   se lee bastante más flojo. */
.team-directory .team-filter-clear:disabled{ opacity: .45; cursor: default; }

/* Apilado: al cortar la fila, los separadores verticales sobran —quedarían
   colgando entre renglones— y el "Borrar filtros" pierde su empuje a la
   derecha. */
@media (max-width: 1180px){
  .team-directory .team-filters{ gap: 1.1rem 1.4rem; }
  .team-directory .team-filter-group::before,
  .team-directory .team-filter-group::after,
  .team-directory .team-area-select::before{ content: none; }
  .team-directory .team-search{ flex: 1 1 100%; max-width: none; }
  .team-directory .team-area-select{ flex: 1 1 100%; }
  .team-directory .team-filter-clear{ margin-left: 0; }
}

.team-results-count{
  font-size: .88rem;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 1.5rem;
}

/* --- Grilla de tarjetas --- */
.lawyer-grid{
  display: grid;
  grid-template-columns: 1fr;

  /* ✏️ CUÁNTO ASOMA LA FOTO POR ARRIBA Y POR ABAJO DEL PANEL — el único número
     a tocar para regular el efecto. Subilo para un salto más marcado.
     ⚠️ Desde el 2026-08-13 asoma por LOS DOS LADOS (antes sólo por arriba), así
     que este valor entra DOS VECES en el hueco entre filas. */
  --foto-salto: clamp(20px, 2.4vw, 34px);
  /* ✏️ ANCHO DE LA FOTO dentro de la tarjeta. El resto es el panel de info.
     ⚠️ EL TOPE DE ARRIBA LO PONE EL NOMBRE, no la foto. Lo que se le suma acá
     se le resta al texto (el `padding-right` del panel sale de esta variable), y
     `.lawyer-name` recorta a DOS LÍNEAS con `-webkit-line-clamp`: pasado cierto
     ancho los nombres largos —"Mario Aguilar Blaires", "Belén Salinas
     Espinoza"— empiezan a cortarse con puntos suspensivos.
     Al subirlo de 11vw/152px a 12vw/168px (2026-08-13, pedido del cliente: "un
     poco más anchas, con el mismo alto") se comprobó que ninguno de los 28 pasa
     de dos líneas en 6 anchos. El ancho más ajustado NO es el más chico sino
     **1024px**, donde la grilla ya tiene 3 columnas pero la pantalla todavía es
     angosta: ahí el texto queda en 139px. Si se vuelve a tocar, medir ahí. */
  --foto-ancho: clamp(118px, 12vw, 168px);

  /* El alto de la tarjeta vive acá, y no suelto en `.lawyer-card`, porque la
     columna de la foto necesita leerlo para calcular su ancho (ver
     `.lawyer-photo-wrap`). Una sola definición: no se pueden desincronizar. */
  --tarjeta-alto: clamp(165px, 13.5vw, 195px);
  /* Alto real de la foto = el panel más lo que asoma ARRIBA Y ABAJO. */
  --figura-alto: calc(var(--tarjeta-alto) + var(--foto-salto) * 2);

  column-gap: clamp(1.5rem, 3vw, 2.25rem);
  /* ⚠️ El hueco ENTRE FILAS tiene que incluir el salto DE LAS DOS FILAS que se
     miran: la foto de abajo asoma hacia arriba y la de arriba hacia abajo. Por
     eso va × 2 desde el 2026-08-13, cuando la foto empezó a sobresalir por los
     dos lados. Atado por fórmula a la misma variable justamente para que no
     puedan desincronizarse — si alguien sube `--foto-salto`, el hueco lo
     acompaña solo. */
  row-gap: calc(clamp(1.5rem, 3vw, 2.25rem) + var(--foto-salto) * 2);
}
@media (min-width: 640px){
  .lawyer-grid{ grid-template-columns: repeat(2, 1fr); }
}
/* Mismo umbral de 1000px que ya usan las filas de #reconocimientos para
   pasar a su layout de escritorio (ver nota de --per en ese bloque). */
@media (min-width: 1000px){
  .lawyer-grid{ grid-template-columns: repeat(3, 1fr); }
}

/* Tarjeta horizontal: PANEL DE INFO SÓLIDO a la izquierda —correo+LinkedIn
   arriba, posición y nombre abajo— y la FOTO a la derecha, montada encima y
   asomando por arriba y por abajo.

   ⚠️ REDISEÑO 2026-08-13, pedido del cliente con una referencia visual: "a las
   imágenes aplicales el border radius como tienen todos, para el sentido de la
   web" y "que la parte de la información tenga fondo sólido coherente con la
   paleta y encima que tenga contraste el color de los textos".
   Antes la tarjeta era una caja SIN fondo con borde apenas visible, y la foto
   iba apoyada en el piso, con esquinas rectas salvo la inferior derecha
   (recortada con `clip-path` para no pisar el radio de la tarjeta).

   Lo que cambió, y por qué:
   · el fondo pasó al PANEL (`.lawyer-content`), no a la tarjeta: la foto se
     monta encima y la tarjeta en sí ya no dibuja nada;
   · el borde exterior desapareció — con un panel sólido no hace falta, y con
     la foto sobresaliendo quedaba un rectángulo cortado a la vista;
   · la foto es ahora un rectángulo redondeado de verdad (`border-radius` +
     `overflow: hidden`), en vez de un recorte con `clip-path`.

   ⚠️ Alto FIJO (no `min-height`): pedido del cliente, mismo alto Y mismo ancho
   en las 28 tarjetas. `.lawyer-name` lleva `line-clamp: 2` como red de
   seguridad — con altura fija, un nombre de tres líneas se saldría del panel. */
.lawyer-card{
  position: relative;
  display: flex;
  align-items: stretch;
  height: var(--tarjeta-alto);
  /* La foto sobresale por arriba y por abajo: el desborde tiene que quedar a
     la vista. El hueco entre filas lo contempla (ver .lawyer-grid). */
  overflow: visible;
}
.lawyer-card.is-hidden{ display: none; }

.lawyer-content{
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1.25rem;
  /* ⚠️ EL RELLENO DERECHO RESERVA LA COLUMNA DE LA FOTO. La foto va absoluta y
     no ocupa lugar en el flujo, así que sin esto el nombre pasa por debajo de
     ella. El `1rem` extra es el aire entre el texto y el borde de la foto:
     medido sobre el texto PINTADO (no sobre la caja, que es más ancha), el peor
     caso de los 28 nombres en 6 anchos queda en 17px. Con `.75rem` bajaba a
     13px y "María Emilia Almada" quedaba casi tocando la foto. */
  padding: 1.25rem calc(var(--foto-ancho) + 1rem) 1.25rem 1.25rem;
  background: var(--c-ink-2);
  color: #fff;
  border-radius: var(--radius-lg);
}

.lawyer-links{ display: flex; gap: .5rem; }
.lawyer-link{
  width: 34px; height: 34px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  /* Sobre el panel negro (2026-08-13): el gris perla y el índigo que tenían
     antes eran para un panel claro y acá desaparecían. Un velo blanco muy
     tenue da la pastilla sin meter un color nuevo en la paleta. */
  background: rgba(255, 255, 255, .10);
  color: #fff;
  transition: background var(--dur-micro) var(--ease-soft),
              color var(--dur-micro) var(--ease-soft);
}
.lawyer-link svg{ width: 16px; height: 16px; }
a.lawyer-link:hover{ background: var(--c-blue); color: #fff; }
/* El LinkedIn individual todavia no existe (pedido del cliente, 2026-08-10):
   se deja el icono en su lugar pero INERTE —<span>, no <a>— hasta que se
   cargue la URL real en el campo "linkedin" de equipo.json y se vuelva a
   correr gen_equipo_directorio.js. Ver project_reference.md. */
.lawyer-link--pending{ opacity: .35; cursor: default; }

.lawyer-meta{ display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
/* La posición (Socio/Socia/Asociado/Asociada/Socio Senior/Abogado...) se
   muestra UNA sola vez acá, con el texto EXACTO de "cargo" en equipo.json
   (ya viene en el género correcto) — antes había además una etiqueta con el
   bucket sin género (SOCIO/ASOCIADO), duplicando la info y mostrando mal el
   género de varias mujeres del equipo. El color que tenía esa etiqueta
   (azul socios / índigo asociados) pasó directo a este texto. */
.lawyer-role{
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
/* ⚠️ LOS DOS EN EL MISMO AZUL, a propósito (cliente, 2026-08-12: "que los que
   dicen asociada/o tengan el mismo color de socio"). El `--asociado` era
   `var(--c-indigo)`, heredado del chip SOCIO/ASOCIADO que se quitó el
   2026-08-10.

   Las dos clases se conservan aunque hoy pinten igual —y NO es un descuido—
   porque son el único punto donde el bucket socio/asociado llega al CSS: si
   mañana se quiere volver a distinguir la posición, se cambia acá y listo, sin
   tocar el generador. La posición en sí no se pierde nunca: el texto ya dice
   "Socio Senior" / "Asociada". */
/* ⚠️ CIAN Y NO AZUL DESDE EL 2026-08-13, por el panel negro. El `--c-blue`
   (#2d62ea) sobre `--c-ink-2` (#231f20) da 3,0:1 — por debajo del 4,5:1 que
   pide WCAG AA para texto chico, y este va en .74rem. El `--c-cyan` (#35dfff)
   sobre el mismo fondo da 11,4:1. Sigue siendo el color de acento de la marca,
   el mismo que usan las volantas sobre fondo oscuro en el resto del sitio. */
.lawyer-role--socio{ color: var(--c-cyan); }
.lawyer-role--asociado{ color: var(--c-cyan); }
.lawyer-name{
  color: #fff;
  /* Bajado de 1.05rem a pedido del cliente (2026-08-12). */
  font-size: .95rem;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  /* ⚠️ ALTO FIJO DE DOS LÍNEAS — es lo que ALINEA los nombres entre tarjetas.
     El bloque cargo+nombre está anclado abajo (`space-between` en
     `.lawyer-content`), así que si el nombre ocupa 1 ó 2 líneas el bloque
     entero sube o baja y el cargo y el nombre arrancan a distinta altura en
     cada tarjeta — medido: "SOCIO SENIOR" caía en tres `y` distintas dentro de
     la misma fila. Con la caja del nombre siempre de dos líneas, el bloque
     mide siempre igual, así que el cargo y la primera línea del nombre caen
     SIEMPRE en la misma altura, y el bloque sigue anclado abajo como se pidió
     en su momento. Un nombre de una línea deja libre la segunda; como la
     tarjeta no tiene fondo, no se nota.
     Va en `em` (2 × el line-height 1.3) para que siga al font-size solo. */
  height: 2.6em;
}

/* --- LA FIGURA SALE POR ARRIBA DE LA TARJETA ------------------------------
   Pedido del cliente (2026-08-12), con una referencia: la figura recortada
   apoyada en el piso de la tarjeta y asomando por encima del borde superior,
   cruzando la línea. Se controla con UNA variable, `--foto-salto` (definida
   en .lawyer-grid): cuántos píxeles asoma por arriba.

   ⚠️ POR QUÉ AHORA SE DIMENSIONA POR ALTO (`height:100%; width:auto`) Y NO
   CON `object-fit: contain`, QUE ERA LO QUE HABÍA.
   Las 28 fotos comparten EXACTAMENTE el mismo alto de origen (778px) y sólo
   varían de ancho (369 a 580, o sea la más ancha es 57% más ancha que la más
   angosta). Con `contain` en una caja más angosta que alta, quien manda es el
   ANCHO: cada foto terminaba con un alto distinto según su proporción
   (169px la más ancha, 266px la más angosta). Para un salto parejo eso no
   sirve — cada figura cruzaría la línea a una altura distinta. Dimensionando
   por ALTO, las 28 quedan a la misma escala y cortan la línea a la misma
   altura, que es justo el efecto de la referencia.

   ⚠️ Y NO REINTRODUCE EL BUG DE DEFORMACIÓN de 2026-08-10. Aquel era
   `height:100%; width:auto; max-width:100%`: cuando el `max-width` entraba en
   juego recortaba el ANCHO sin recalcular el ALTO y la foto salía estirada.
   Acá va `max-width: none` EXPLÍCITO y el wrap se dimensiona ancho suficiente
   para la más ancha del set, así que el tope nunca llega a actuar. Si algún
   día se suma un recorte con otra proporción, revisar esa cuenta.

   ⚠️ REESCRITO EL 2026-08-13. Lo de arriba describe el planteo VIEJO —figura
   recortada apoyada en el piso, dimensionada por alto para que las 28 cortaran
   la línea a la misma altura— y se deja porque explica por qué NO volver a
   `object-fit: contain` ni a `max-width` en la foto.

   Lo que hay ahora: la foto es un RECTÁNGULO REDONDEADO, del mismo radio que
   el resto del sitio, montado sobre el panel y asomando por arriba y por abajo
   (pedido del cliente, con referencia visual). Tres consecuencias:

   · Va ABSOLUTA, no como item flex. Así no ocupa lugar en el flujo y puede
     desbordar el alto de la tarjeta por los dos lados sin estirarla. El lugar
     que necesita se lo reserva el `padding-right` de `.lawyer-content`.
   · `overflow: hidden` + `border-radius` en el wrap, en vez del `clip-path`
     que había: ahora los cuatro lados son iguales, así que no hay ninguna
     esquina que proteger — y el `hidden` es además lo que mantiene el zoom del
     hover dentro de la forma.
   · La foto pasa a `object-fit: cover`. Las 28 son 329×460 (una sola es 658×920,
     el mismo encuadre al doble), así que el recorte es idéntico en todas y el
     `cover` no descuadra nada. `object-position: center 22%` para que el
     recorte se coma el pecho y no la cabeza. */
.lawyer-photo-wrap{
  position: absolute;
  right: 0;
  /* Asoma lo mismo arriba que abajo: es lo que le da el aire de la referencia
     y lo que evita tener que elegir un anclaje. */
  top: calc(var(--foto-salto) * -1);
  bottom: calc(var(--foto-salto) * -1);
  width: var(--foto-ancho);
  border-radius: var(--radius-lg);
  overflow: hidden;
  /* Encima del panel: el panel llega hasta el borde derecho de la tarjeta y sus
     esquinas quedan por debajo de la foto — ese solape es el efecto buscado. */
  z-index: 1;
}
.lawyer-photo{
  width: 100%;
  height: 100%;
  max-width: none;      /* ⚠️ ver la nota de deformación de arriba */
  display: block;
  object-fit: cover;
  object-position: center 22%;
  /* Pedido del cliente (2026-08-10): sin el efecto blanco y negro — color
     siempre, con un acercamiento suave al pasar el mouse en vez del filtro. */
  transition: transform .45s var(--ease-soft);
}
.lawyer-card:hover .lawyer-photo,
.lawyer-card:focus-within .lawyer-photo{ transform: scale(1.06); }

.team-empty{ text-align: center; padding: 3rem 1rem; color: var(--text-muted); }
.team-empty .btn{ margin-top: 1rem; }

/* --- Tarjeta que lleva a la ficha individual (equipo/<slug>.html) -----------
   La clase la pone gen_equipo_directorio.js SOLO si existe
   _tools/perfiles/<slug>.json, así que una tarjeta sin ficha se sigue viendo y
   comportando exactamente como antes de esto.

   ⚠️ PATRÓN DE ENLACE ESTIRADO, no una tarjeta envuelta en <a>. El <a> rodea
   nada más que el NOMBRE —así el enlace tiene texto real y un lector de
   pantalla anuncia a dónde va, en vez de leer la tarjeta entera— y este
   ::after lo estira sobre toda la superficie para que se pueda hacer clic en
   cualquier parte. Envolver el <li> entero era la opción obvia y NO sirve:
   adentro ya hay dos enlaces (correo y LinkedIn) y anidar interactivos es HTML
   inválido — el navegador rompe el anidamiento al parsear.

   ⚠️ Los dos íconos se levantan con z-index por encima del ::after; sin esto
   la capa del enlace les roba el clic y "escribir por correo" termina abriendo
   la ficha.

   ⚠️ Y LA FOTO NO PUEDE RECIBIR CLICS (2026-08-13). Desde que va absoluta y con
   `z-index: 1`, queda EMPATADA con esta capa de enlace y gana ella por venir
   después en el DOM: hacer clic en la foto dejaba de abrir la ficha. Con
   `pointer-events: none` el clic la atraviesa y llega al enlace, que es lo que
   siempre se quiso acá. La foto es decorativa (`alt=""`), así que no se pierde
   nada. El zoom del hover sigue andando: lo dispara `.lawyer-card:hover`, y el
   puntero encuentra la tarjeta por debajo. */
.lawyer-card--con-ficha{ cursor: pointer; }
.lawyer-ficha{ color: inherit; text-decoration: none; }
.lawyer-ficha::after{ content: ""; position: absolute; inset: 0; z-index: 1; }
.lawyer-card--con-ficha .lawyer-links{ position: relative; z-index: 2; }
.lawyer-photo-wrap{ pointer-events: none; }
/* Cian y no azul: el nombre vive sobre el panel negro (ver la nota de
   `.lawyer-role`, mismo motivo de contraste). */
.lawyer-card--con-ficha:hover .lawyer-name{ color: var(--c-cyan); }
.lawyer-name{ transition: color var(--dur-micro) var(--ease-soft); }
/* El foco se dibuja sobre el nombre y no sobre la tarjeta entera: con
   :focus-within, tabular hasta el ícono de correo encendería el mismo anillo y
   no se distinguiría qué elemento está enfocado. */
.lawyer-ficha:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 2px; border-radius: 3px; }

/* --- Enlace nuevo en el home: "Ver equipo completo" (.outro-card, #equipo) ---
   .team (la sección del recorrido animado) es oscura por CSS propio
   (background: var(--gradient-dark)) pero no lleva la clase .section--dark,
   así que no hereda el estilo claro que .btn--ghost ya tiene para fondos
   oscuros (ver ese bloque en Buttons, más arriba). Se repite la misma regla
   acá, acotada a .team, en vez de agregarle la clase a la sección: esa
   sección tiene su propio CSS muy afinado (ver project_reference.md,
   "Las tarjetas") y sumarle una clase nueva es más riesgo del que hace falta
   para un solo botón. */
.team .btn--ghost{ box-shadow: inset 0 0 0 1.5px rgba(255,255,255,.35); color: #fff; }
.team .btn--ghost:hover{ box-shadow: inset 0 0 0 1.5px var(--c-cyan); color: var(--c-cyan); }


/* ==========================================================================
   PÁGINAS INTERNAS — ficha de perfil del equipo (equipo/<slug>.html)
   ==========================================================================
   Las genera _tools/gen_perfil.js a partir de los datos de _tools/perfiles/ y
   del cascarón del home (header, menú, selector de idioma, footer), así que
   cualquier cambio de esos bloques se propaga volviendo a generar las fichas.
   ========================================================================== */

/* ⚠️ ESTA REGLA ES DE part1 Y EL PORTE DE part2 SE LA LLEVÓ PUESTA (2026-08-18).
   part2 tenía `.has-bg` acotada a `.pagina-interna` y `.page-equipo`; el home
   quedaba sin fondo al scrollear y se perdía el glassmorphism que pidió el
   cliente. Al traer el bloque de la ficha de part2 desapareció, y lo cazaron
   las 16 comprobaciones de verificar_hero («el fondo del header no es
   translúcido» / «falta el blur»). Se repone la versión general: vale para
   TODAS las páginas, home incluido. No volver a acotarla.

/* ⚠️ EL HEADER DE UNA INTERNA NECESITA FONDO, PERO NO DESDE EL PRIMER PÍXEL.
   El logo es blanco y el cuerpo de la ficha es claro: sin fondo, el wordmark
   queda invisible al bajar. Pero ARRIBA DEL TODO la portada es oscura y ahí la
   barra sobra — el cliente la marcó: "el header no es el mismo que el del home,
   tiene esa barra azul".

   Así que ahora hace lo mismo que en el home: transparente mientras la zona
   oscura está detrás, con fondo en cuanto deja de estarlo. Lo alterna
   `onScrollHeader()` en js/main.js, usando `.perfil-portada` como referencia
   igual que usa `.hero` en el home.

   ⚠️ VALE PARA TODAS LAS PÁGINAS, HOME INCLUIDO (2026-08-16). Antes el selector
   nombraba sólo a las internas y en el home la clase se ponía pero no pintaba
   nada: el header quedaba transparente en todo el recorrido. El cliente pidió
   "un fondo tipo glassmorphism al desplazarse hacia abajo, en su estado inicial
   como está ahora", que es exactamente lo que hace `has-bg` — y el momento en
   que entra ya estaba resuelto: no puede encenderse durante el pin del hero,
   porque ahí el bottom del hero vale el alto del viewport (ver `onScrollHeader`
   en js/main.js). O sea que la portada no se toca y la barra aparece recién
   cuando el hero empezó a salir de verdad.

   El fondo es translúcido y NO opaco a propósito: con `backdrop-filter` se ve
   pasar el contenido por debajo, que es lo que lo hace glassmorphism y no una
   barra sólida. */
.site-header.has-bg{
  background: rgba(20,21,52,.72);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
          backdrop-filter: blur(16px) saturate(1.4);
  border-bottom: 1px solid rgba(255,255,255,.10);
  box-shadow: 0 6px 24px rgba(8,8,20,.22);
}

/* ⚠️ CON EL MENÚ ABIERTO, EL HEADER SE QUEDA SIN FONDO.
   El panel es `top: 0` y ocupa toda la altura, pero el header (z-index 100) le
   pinta encima su barra: el panel se veía cortado y arrancando recién a los
   98px, como si saliera de abajo del header. El cliente lo marcó.

   No se resuelve subiendo el z-index del panel: el botón «✕ Menú» vive DENTRO
   del header, que es un contexto de apilado, así que subir el panel por encima
   del header se lleva puesto el botón de cerrar. Lo que se saca es sólo el
   FONDO, y entonces el azul del panel llega hasta arriba con el logo y el botón
   flotando por encima.

   El logo sigue legible sobre el panel gracias al drop-shadow de .brand-logo
   —el mismo que se le puso para el hero—; medido con el menú abierto. */
body.nav-open .site-header.has-bg{
  background: transparent;
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  border-bottom: 0;
  box-shadow: none;
}

/* --------------------------------------------------------------------------
   Barra del nombre — acompaña el recorrido de la ficha
   --------------------------------------------------------------------------
   Pedido del cliente: "acá puede ir una barra que aparezca y se quede fija en
   el recorrido hacia abajo". Entra en el mismo momento en que el header toma
   fondo —cuando la portada deja de estar detrás— y se lee como una extensión
   suya: mismo tono, mismo blur. De ahí que no lleve fondo propio distinto.

   ⚠️ Va `position: fixed` y no `sticky`: el header también es fixed, así que
   sticky la dejaría pasar por debajo. El `top` la apoya justo debajo del
   header, y se lee del alto real por variable para que no queden dos números
   que mantener sincronizados a mano. */
.perfil-barra{
  position: fixed;
  top: var(--header-h, 115px);
  left: 0;
  right: 0;
  /* ⚠️ 88: DEBAJO DEL PANEL DEL MENÚ (90) Y DE SU VELO (89).
     Estaba en 99 y el panel se abría POR DEBAJO de la barra: quedaba cortado
     arriba y sin oscurecer, como si el menú saliera de atrás. El cliente lo
     marcó. Con 88 el velo la atenúa igual que al resto del contenido —que es lo
     que la barra es— y el panel la cubre entera. Sigue por encima del cuerpo de
     la ficha, que es lo único que necesitaba tapar. */
  z-index: 88;
  /* ⚠️ VIDRIO CLARO, NO ÍNDIGO. Pedido del cliente: "debe ser traslúcido
     glassmorphism" y "que el color sea del gris del fondo". Es el gris claro del
     sitio (--c-mist) al 72%: con el blur detrás, el contenido se insinúa y la
     barra se lee como una lámina y no como una banda opaca.
     Sin `border-top`: el filete blanco que había marcaba una costura contra el
     header oscuro y quedaba feo (también marcado). La separación la da el propio
     salto de color contra el header, y abajo un hairline del gris de líneas. */
  background: rgba(244,246,252,.72);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
          backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid var(--c-line);
  box-shadow: 0 6px 20px rgba(20,21,52,.10);
  opacity: 0;
  transform: translateY(-100%);
  pointer-events: none;
  transition: opacity var(--dur-micro) var(--ease-soft),
              transform var(--dur-micro) var(--ease-soft);
}
.perfil-barra.is-visible{ opacity: 1; transform: translateY(0); pointer-events: auto; }
.perfil-barra > .container{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: .6rem;
}
.perfil-barra-nombre{
  font-size: clamp(.95rem, 1.3vw, 1.15rem);
  font-weight: 800;
  letter-spacing: .01em;
  /* Tinta oscura: la barra pasó a vidrio CLARO, y el blanco de antes se volvía
     invisible sobre él. */
  color: var(--text-body);
  margin: 0;
  /* Un nombre largo no puede empujar a la foto fuera de la barra. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.perfil-barra-cargo{
  display: block;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  /* Azul de marca y no el cian: sobre el vidrio claro el cian queda en ~1,6:1.
     Es el mismo color que usan las volantas del sitio sobre fondo claro. */
  color: var(--c-blue);
}
.perfil-barra-foto{
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
  /* La foto de la ficha es un retrato de cuerpo entero: encuadrada al centro,
     el círculo caía en el torso. `top` deja la cara dentro. */
  object-position: center top;
  /* Aro claro contra el vidrio: sin él, un retrato de fondo claro se funde con
     la barra y el círculo desaparece. */
  background: #fff;
  box-shadow: 0 0 0 1px var(--c-line);
}
/* Por debajo de 560px el cargo y el nombre no entran junto a la foto sin
   apretarse; se cae el cargo, que es el dato secundario. */
@media (max-width: 559px){
  .perfil-barra-cargo{ display: none; }
  .perfil-barra-foto{ width: 36px; height: 36px; }
}
@media (prefers-reduced-motion: reduce){
  .perfil-barra{ transition: none; transform: none; }
}

/* LinkedIn: botón redondo, sin texto — pedido del cliente. El nombre accesible
   lo pone el aria-label del enlace (ver la nota del generador).
   38px de lado: por encima del mínimo cómodo para el dedo en el resto del sitio
   y en línea con los otros círculos sociales del footer. */
.dato-linkedin{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--c-white);
  border: 1px solid var(--c-line);
  color: var(--c-blue);
  transition: background var(--dur-micro) var(--ease-soft),
              color var(--dur-micro) var(--ease-soft),
              border-color var(--dur-micro) var(--ease-soft),
              transform var(--dur-micro) var(--ease-soft);
}
.dato-linkedin svg{
  width: 18px;
  height: 18px;
  flex: none;
  fill: currentColor;
}
.dato-linkedin:hover,
.dato-linkedin:focus-visible{
  background: var(--c-blue);
  border-color: var(--c-blue);
  color: #fff;
  transform: translateY(-1px);
}

/* --------------------------------------------------------------------------
   Entrada de la portada
   --------------------------------------------------------------------------
   Pedido del cliente: "animaciones de entrada" sobre la portada. Entran las
   CUATRO piezas de texto, escalonadas desde la izquierda.

   ⚠️ LA FOTO NO ENTRA, Y ES A PROPÓSITO. Se probó con una entrada desde la
   derecha y el cliente la hizo sacar ("elimina la animación aquí", 2026-08-12).
   No volver a agregarla. Además de ser una decisión suya, le viene bien a la
   métrica: la foto es el elemento LCP de la página —lleva `fetchpriority="high"`—
   y animarla desde `opacity: 0` retrasaba el momento en que se considera
   pintada. Sin animación, se ve apenas llega.
   Lo que la foto SÍ conserva es su zoom al pasar el puntero, que es anterior a
   todo esto y vive en el bloque de la portada, más abajo.

   ⚠️ VA EN CSS Y NO CON EL SISTEMA `data-reveal` DEL RESTO DEL SITIO. Ese
   sistema es un IntersectionObserver: sirve para lo que aparece al scrollear,
   pero la portada está SOBRE EL PLIEGUE y se ve desde el primer frame. Con
   observer, el reveal depende de que el JS haya llegado a correr; en CSS, la
   animación arranca con el primer pintado y no depende de nada.

   ⚠️ EL FILL ES `backwards`, NO `both`. El `backwards` hace falta: mantiene el
   estado inicial durante el retardo, y sin él los elementos se ven un instante
   en su sitio y recién ahí saltan al arranque.
   Pero `forwards` NO va: una animación con fill hacia adelante gana sobre
   cualquier declaración normal, incluidas las de `:hover`. Se pisó cuando la
   foto todavía animaba —el `transform: none` final quedaba clavado y mataba su
   `scale(1.02)` al pasar el puntero—, y la trampa sigue viva para cualquier
   elemento con hover al que se le agregue una entrada. Como el último fotograma
   ya coincide con el estado natural, con `backwards` no hay salto al terminar. */
@keyframes perfil-entra-izq{
  from{ opacity: 0; transform: translateX(-26px); }
  to{ opacity: 1; transform: none; }
}
.perfil-volver,
.perfil-portada-txt > *{
  animation: perfil-entra-izq .7s var(--ease-soft) backwards;
}
/* La cascada sigue el orden nuevo del bloque (2026-08-13): nombre, cargo,
   contacto, botón y áreas. Antes eran tres elementos (volanta, nombre,
   resumen); el resumen se fue al cuerpo y el cargo pasó a ir debajo del nombre. */
.perfil-volver{ animation-delay: .05s; }
.perfil-portada-txt > .perfil-nombre{ animation-delay: .14s; }
.perfil-portada-txt > .perfil-cargo{ animation-delay: .22s; }
.perfil-portada-txt > .perfil-contacto{ animation-delay: .30s; }
.perfil-portada-txt > .perfil-areas-bloque{ animation-delay: .36s; }

/* Sin animación: los cuatro textos aparecen ya puestos. `animation: none` y no
   una duración de 0 — con fill, una duración 0 dejaría clavado el estado inicial
   (opacity 0) y la portada se vería vacía. */
@media (prefers-reduced-motion: reduce){
  .perfil-volver,
  .perfil-portada-txt > *{ animation: none; }
}

/* --------------------------------------------------------------------------
   Portada de la ficha
   -------------------------------------------------------------------------- */
.perfil-portada{
  background: var(--gradient-dark);
  color: #fff;
  overflow: hidden;
  /* El header es fixed: este padding es lo que evita que la volanta le quede
     debajo. */
  /* ⚠️ El MÍNIMO y el vw NO se tocan: son los que sostienen el enlace "Volver"
     por debajo del header fijo en pantallas chicas (a 1024 el relleno da 123px
     contra un header de 115). Se probó bajarlos el 2026-08-13 y el enlace quedó
     3px POR ENCIMA del borde del header, o sea tapado. Lo que sí se bajó es el
     tope, de 10rem a 9rem, que es el que actúa de 1200px para arriba. */
  padding-top: clamp(7.5rem, 12vw, 8.25rem);
}
.perfil-volver{
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c-cyan);
  transition: gap var(--dur-micro) var(--ease-soft);
}
.perfil-volver svg{ width: 18px; height: 18px; }
.perfil-volver:hover{ gap: .85rem; }

.perfil-portada-grid{
  display: grid;
  gap: clamp(1.5rem, 3vw, 3rem);
  align-items: end;
  margin-top: clamp(1rem, 2vw, 1.5rem);
}
@media (min-width: 900px){
  /* ⚠️ TODO ALINEADO A LAS GUÍAS DE .container, no centrado.
     El texto arranca en el borde interno izquierdo —la misma vertical que
     "Volver al equipo"— y la foto termina en el borde interno derecho. Se
     probaron antes dos variantes centradas (el par junto en el medio, y cada
     bloque centrado en su mitad) y las dos se descartaron: dejaban el bloque de
     texto desalineado del resto de la página.
     Por eso NO va `justify-self` ni `max-width` acá: cualquiera de los dos
     despega el texto de la guía. */
  .perfil-portada-grid{ grid-template-columns: 1fr 1fr; }

}
/* Menos que antes (era clamp(2rem, 5vw, 4rem)): con el bloque de contacto y
   las áreas adentro, la columna ya es alta y este relleno se sumaba al de la
   portada. Lo que tiene que garantizar es que el último contenido no toque la
   banda de la curva — medido, quedan 26–34px en todos los anchos. */
/* ⚠️ ARRANCA ARRIBA, NO AL PIE. La grilla lleva `align-items: end` porque la
   FOTO tiene que apoyarse en la curva; la columna de texto es más corta, así
   que ese mismo `end` la empujaba hacia abajo y dejaba un hueco muerto sobre
   el nombre — medido: 31px a 1440, más lo que sumaban los márgenes. El
   cliente lo marcó ("queda un espacio grande de balde sobre el nombre").
   `align-self: start` lo saca sin tocar el anclaje de la foto. */
.perfil-portada-txt{
  align-self: start;
  padding-bottom: clamp(1.25rem, 3vw, 2.5rem);
  /* ✏️ EL AIRE ENTRE BLOQUES DE INFORMACIÓN — un solo valor para los tres
     saltos (nombre→cargo, cargo→contacto, contacto→áreas). Pedido del cliente:
     "que entre informaciones tengan el mismo espacio". Antes eran 10px, 26px
     y 26px. */
  --perfil-gap: clamp(1.1rem, 2vw, 1.6rem);
}
.perfil-nombre{
  margin-top: 0;
  letter-spacing: -.03em;
  /* ⚠️ ACÁ SÍ HAY UN TAMAÑO PROPIO, Y ES DELIBERADO (2026-08-13). Antes heredaba
     la escala h1 del sistema —clamp(2.4rem, 5.5vw, 4.6rem)— y con el nombre en
     UNA sola línea, que es como lo pidió el cliente, "Victoria Burt" a 4.6rem
     medía ~500px de los 592 de su columna: cualquier nombre un poco más largo
     se partía igual.
     ⚠️ EL TOPE BAJÓ DE 3.2rem A 3rem EL 2026-08-19, Y ES UN NÚMERO MEDIDO.
     Cuando esto se escribió existía UNA sola ficha; al generarse las 28 aparecieron
     nombres más largos y a 3.2rem se partían en dos renglones «Belén Salinas
     Espinoza» y «Graciela Narvaja Jones», a 1920 y a 1440. El cliente pidió el
     nombre completo en una sola línea.
     Se barrieron 3.2 / 3 / 2.9rem sobre las 28 fichas en 4 anchos: **3rem es el
     tope más grande con el que las 28 entran en un renglón**.
     ⚠️ AL MEDIR ESTO HAY QUE ESPERAR A `document.fonts.ready`. El ancho del texto
     depende de la tipografía, y con Montserrat todavía sin cargar la medición se
     hace con la de reserva y da otro resultado: el primer barrido, sin esa espera,
     dijo que a 3.2rem sólo se partía un nombre; con la fuente puesta eran cuatro.
     Si mañana entra alguien con un nombre más largo, volver a barrer.
     Es el ÚNICO h1 del sitio con tamaño propio, y no choca con ninguna
     comprobación: la de verificar.js mide los h2 de sección, no los h1. */
  font-size: clamp(2rem, 3.6vw, 3rem);
  line-height: 1.05;
}
/* ⚠️ Acá estaba `.perfil-resumen`, el texto de bajada de la portada. Se quitó
   el 2026-08-13: el resumen pasó al cuerpo como "Descripción" (boceto del
   cliente) y ninguna ficha lo emite ya en la portada. */
/* El recorte se apoya en el borde inferior de la portada, como en la
   referencia: llega a sangre y el cuerpo claro arranca justo debajo. */
.perfil-foto{
  display: block;
  width: auto;
  max-width: 100%;
  /* ✏️ ALTO DE LA FOTO — hoy es lo que fija el alto de la portada, así que es el
     número a tocar para subirla o bajarla.

     ⚠️ EL TOPE ES 460px PORQUE ES EL ALTO REAL DEL ARCHIVO. Las 28 fotos de
     img/profesionales/ son de 329×460 (una sola viene al doble, 658×920, con el
     mismo encuadre). Estaba en 520px, o sea que el navegador las AMPLIABA un
     13%: la portada era 60px más alta y la foto, más blanda. Bajarlo a 460
     acorta la sección y de paso la muestra a resolución nativa.
     Si algún día se quiere más grande, hay que reexportar los recortes; subir
     este número solo agranda píxeles. */
  /* ⚠️ EL TOPE YA NO ES EL ALTO DEL ARCHIVO. Estuvo en 460px justamente porque
     ese era el alto del recorte viejo (329×460) y subirlo sólo agrandaba
     píxeles. El archivo nuevo mide 1448 de alto, así que a 560px se sigue
     PINTANDO REDUCIDA (x0,39) y hay margen de sobra para crecer más.

     ⚠️ LO QUE LIMITA AHORA ES EL ALTO DE LA PORTADA, no la nitidez. La foto va
     anclada al piso y crece hacia arriba, así que en cuanto pasa el alto de la
     columna de texto empieza a estirar la portada: medido, cada 40px de foto
     son 40px más de portada (460→648, 560→743, 640→823 a 1440). Se subió a 560
     a pedido del cliente —"que no quede más grande el texto del nombre que la
     imagen"—: la relación ancho de foto / ancho del nombre pasa de 0,60 a 0,74.
     Igualarlas del todo pediría 767px de foto y una portada de ~950px. */
  /* ⚠️ ESTE ALTO ES EL DEL LAYOUT, NO EL QUE SE VE. Volvió a 460px porque es el
     tope exacto con el que la portada mide 648px: pasado eso la foto empieza a
     estirarla (medido: la columna de texto ocupa 369px y la foto aporta
     alto − 97px, así que desde 466px manda la foto). El cliente pidió subirla
     y agrandarla PERO manteniendo el alto de sección, y eso sólo se puede con
     un transform, que no participa del layout. Ver el bloque de abajo. */
  height: clamp(300px, 46vw, 460px);
  object-fit: contain;
  object-position: bottom;
  /* Centrada por defecto: en mobile la columna ocupa todo el ancho y la foto
     tiene que quedar en el medio. El pegado a la guía derecha se hace solo en
     desktop, dentro del media query de abajo. */
  margin-inline: auto;
  filter: drop-shadow(0 24px 40px rgba(6,6,20,.45));
}
/* ⚠️ Este media query va DESPUÉS de la regla de arriba, no junto al del grid.
   Los media queries no suman especificidad: puesto antes, el `margin-inline:
   auto` de la regla base lo pisaba por orden de cascada y la foto seguía
   centrada en su columna, unos 120px corta de la guía. */
@media (min-width: 900px){
  /* La foto cierra sobre el borde interno derecho de .container, la misma guía
     donde alinea el resto de la página. */
  .perfil-foto{ margin-left: auto; margin-right: 0; }
  /* ⚠️ SUBIR Y AGRANDAR LA FOTO SIN TOCAR EL ALTO DE LA SECCIÓN (2026-08-13).
     Pedido del cliente: "subí un poco más la foto y que siga quedando el mismo
     alto que tenía antes la sección". Las dos cosas juntas sólo salen con un
     transform: el alto del layout queda en 460px —el tope que mantiene la
     portada en 648px— y lo que se ve es 1,14 veces más grande y 36px más arriba.

     ⚠️ `transform-origin: bottom` NO es opcional. Con el origen por defecto
     (el centro) la escala también baja el pie de la figura, y el corte recto del
     recorte asoma por debajo del relleno blanco de la curva. Anclando abajo, la
     figura crece hacia ARRIBA, que es hacia donde hay sitio.

     ⚠️ El `translateY` tiene techo: cada píxel que sube acerca el corte del
     recorte al borde del relleno de la curva. Medido, a 1440 quedan ~93px de
     margen; con 36 estamos holgados. Si se sube más, revisar que el pie de la
     figura siga tapado en TODOS los anchos.

     La escala no ablanda la imagen: el archivo mide 1448 de alto y esto la pinta
     a ~524, o sea sigue reduciéndose. */
  /* ⚠️ EL ORIGEN ES `bottom right`, NO `bottom center` — Y LA MITAD DERECHA DEL
     VALOR IMPORTA TANTO COMO LA IZQUIERDA.
     · `bottom` es lo que ya estaba y sigue haciendo falta: con el origen en el
       centro vertical la escala también BAJA el pie de la figura y el corte
       recto del recorte asoma por debajo del relleno blanco de la curva.
       Anclando abajo, la figura crece hacia ARRIBA, que es hacia donde hay sitio.
     · `right` es el arreglo del 2026-08-19. Con `center` la escala ensanchaba la
       foto hacia LOS DOS lados, así que el borde derecho se iba 23px más allá de
       la guía del contenedor — la misma vertical donde termina la lupa del
       header y donde cierra el resto de la página. Medido en 1920, 1440 y 1280:
       +23px en los tres. El `margin-right: 0` de arriba alinea la CAJA, pero la
       caja no es lo que se ve cuando hay un `scale`.
       Anclando a la derecha, ese borde queda clavado en la guía y la figura
       crece hacia la izquierda, que es donde sobra sitio.
     ⚠️ Si algún día se cambia la escala, el borde derecho NO se mueve: ésa es la
     gracia de este origen. Pero el izquierdo sí, así que conviene mirar que no
     se meta bajo la columna de texto. */
  .perfil-foto{
    transform-origin: bottom right;
    transform: translateY(-36px) scale(1.14);
  }
}

/* --------------------------------------------------------------------------
   Cuerpo de la ficha
   -------------------------------------------------------------------------- */
/* ⚠️ ARRANCA MÁS ARRIBA QUE UNA SECCIÓN NORMAL, Y ES A PROPÓSITO.
   `.section-pad` le daba el relleno genérico del sistema —clamp(4rem, 9vw,
   7.5rem), 120px de 1333px para arriba—, pensado para una sección que empieza
   contra otra. Ésta no: arriba tiene la banda de la curva de la portada, que
   del lado izquierdo es blanca (el relleno del path es `--bg-body`, el mismo
   fondo de acá) y ya aporta 130px de aire a 1440. Los dos se sumaban: **249px
   de blanco** entre el techo de la curva y el título «Formación».
   Pedido del cliente (2026-08-13): "subir un poco lo de Formación y Descripción
   para aprovechar espacio, pero sin pegar excesivamente a la sección
   principal".

   Es el mismo criterio que ya usa `.team-directory` en el directorio, pero con
   un valor algo más generoso: allá abre un contador chico y acá abren dos `h2`
   grandes, que piden más aire para no quedar montados sobre la curva.

   Sólo se pisa el relleno de ARRIBA; el de abajo sigue siendo el del sistema.

   Blanco total medido después del cambio (banda + relleno), contra lo que
   había: 1920 197px (era 259) · 1440 186px (era 249) · 1024 133px (era 183) ·
   768 101px (era 137) · 390 96px (era 155). */
.perfil-cuerpo{
  background: var(--bg-body);
  padding-top: clamp(2rem, 4vw, 3.5rem);
}
.perfil-grid{
  display: grid;
  gap: clamp(2.5rem, 5vw, 4.5rem);
  align-items: start;
}
@media (min-width: 900px){
  /* Izquierda: Formación e Idiomas. Derecha: Descripción, Testimonio, Premios
     y Trayectoria. La derecha es la que lleva el texto corrido, y por eso es
     la ancha (reparto 2026-08-13, del boceto del cliente).
     ⚠️ Acá vivía además un `position: sticky` para la tarjeta de contacto, que
     desde el rediseño está en la portada. Se sacó junto con ella: las dos
     columnas de acá son listas, y una lista pegajosa que se despega de su par
     al scrollear se lee como un error, no como una ayuda. */
  .perfil-grid{ grid-template-columns: .8fr 1.2fr; }
}
/* Las dos columnas apilan sus secciones. El primer bloque de cada una arranca
   sin margen: el aire de arriba ya lo pone el `section-pad` del cuerpo. */
.perfil-col > .perfil-bloque:first-child{ margin-top: 0; }

/* --- Contacto y áreas DENTRO DE LA PORTADA ---------------------------------
   Rediseño 2026-08-13, sobre un boceto a mano del cliente: en la portada, a la
   izquierda y uno debajo del otro, van NOMBRE → cargo → contacto → áreas de
   práctica; a la derecha la foto. Antes el contacto era una tarjeta gris
   (`.perfil-datos`) pegajosa en el cuerpo, sobre fondo claro, y las áreas eran
   un bloque más del cuerpo.

   ⚠️ TODO ESTO VIVE AHORA SOBRE EL DEGRADADO OSCURO. Los colores de `.dato-*`
   están pensados para fondo claro, así que acá se pisan en un bloque scopeado a
   `.perfil-portada`. Si mañana alguien reutiliza `.dato-label` o `.dato-valor`
   en otra parte clara, siguen funcionando como siempre. */
.perfil-cargo{
  margin-top: var(--perfil-gap);
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--c-cyan);
}
/* ⚠️ EN FILA, NO APILADO (2026-08-13). Pedido del cliente: "los datos de manera
   horizontal, uno al lado del otro, sin alargar demasiado la sección, así queda
   más chica". Apilados ocupaban tres renglones (~165px); en fila ocupan uno
   (~55px), que es de dónde sale la mayor parte de lo que se acortó la portada.
   ⚠️ Se le sacó el `max-width: 24rem` que tenía: con ese tope la fila se
   partía igual en tres renglones y el cambio no se veía. El ancho lo limita
   ahora la propia columna de la portada. Cuando no entra —pantalla angosta o un
   email largo— envuelve solo, que es el comportamiento que se quiere. */
.perfil-contacto{
  margin-top: var(--perfil-gap);
  display: flex;
  flex-wrap: wrap;
  gap: .9rem clamp(1.25rem, 2.6vw, 2.25rem);
  align-items: flex-start;
}
.perfil-portada .dato-label{ color: rgba(255, 255, 255, .62); }
.perfil-portada .dato-valor{ color: #fff; }
.perfil-portada a.dato-valor:hover{ color: var(--c-cyan); }
/* ⚠️ EL BOTÓN DE COPIAR Y EL DE LINKEDIN TRAEN FONDO BLANCO. Están diseñados
   para la tarjeta clara que había en el cuerpo, y sobre el degradado oscuro
   quedaban dos manchas blancas —el de copiar, además, con el ícono blanco
   sobre blanco: invisible—. Acá toman el mismo velo tenue que las pastillas de
   las áreas, para que los tres controles del bloque se lean como un juego. */
.perfil-portada .dato-copiar{
  background: rgba(255, 255, 255, .10);
  border-color: rgba(255, 255, 255, .22);
  color: rgba(255, 255, 255, .72);
}
.perfil-portada .dato-copiar:hover{ background: rgba(255, 255, 255, .20); color: #fff; }
.perfil-portada .dato-linkedin{
  background: rgba(255, 255, 255, .10);
  border-color: rgba(255, 255, 255, .22);
  color: #fff;
}
.perfil-portada .dato-linkedin:hover,
.perfil-portada .dato-linkedin:focus-visible{ background: #fff; color: var(--c-indigo); }

.perfil-areas-bloque{ margin-top: var(--perfil-gap); }
.perfil-areas-tit{
  /* No es un h2 del sistema: es la etiqueta de un grupo de pastillas, y con el
     tamaño de h2 competía con el nombre. Mismo tratamiento que `.dato-label`.
     ⚠️ Va con `font-size` propio y por eso NO entra en la comprobación de
     "todos los h2 miden igual" de verificar.js, que sólo mira `.section-head h2`
     y `#equipo h2`. */
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .62);
  margin-bottom: .9rem;
}

/* Las pastillas, sobre oscuro: velo blanco en vez del gris perla del cuerpo.
   ⚠️ LA PÍLDORA LA PINTA EL <a>, NO EL <li>. Está así desde que las áreas
   enlazan a #areas del home (ver "Las áreas ahora enlazan a #areas" más abajo):
   el `li` quedó en `padding: 0; background: none` y el `a` toma toda la
   superficie para que el clic valga en toda la píldora, no sólo sobre el texto.
   Pintar acá el `li` no cambia NADA visible y esconde el bug: se probó y las
   píldoras seguían saliendo casi blancas —el gris perla del `a`— con texto
   blanco encima, o sea ilegibles. */
.perfil-portada .perfil-areas a{
  background: rgba(255, 255, 255, .10);
  border-color: rgba(255, 255, 255, .22);
  color: #fff;
  font-size: .82rem;
}
.perfil-portada .perfil-areas a:hover{
  background: rgba(255, 255, 255, .22);
  border-color: rgba(255, 255, 255, .38);
  color: #fff;
}

.dato-label{
  display: block;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: .2rem;
}
.dato-valor{
  display: block;
  font-size: .95rem;
  font-weight: 600;
  line-height: 1.45;
  word-break: break-word;
}
a.dato-valor:hover{ color: var(--c-blue); }
/* ⚠️ Ya NO va a ancho completo. Servía cuando cerraba una tarjeta de 1 columna
   (`.perfil-datos`); dentro de la portada, estirado, quedaba una barra azul de
   24rem cruzando el bloque. Ahora mide lo que su texto. */
/* ⚠️ `.perfil-cta` y `.perfil-areas-head` ya no existen: el botón "Consultar
   con el estudio" se quitó el 2026-08-13 a pedido del cliente. Estuvo primero
   en renglón propio y después compartiendo fila con el rótulo de áreas. El
   contacto directo ya vive arriba: teléfono, email y LinkedIn. */

.perfil-texto > p{
  font-size: clamp(1rem, 1.4vw, 1.12rem);
  line-height: 1.75;
  color: var(--text-muted);
}
.perfil-texto > p + p{ margin-top: 1.1rem; }
/* La primera va en color de marca y algo más grande, como en la referencia:
   hace de bajada del texto largo. */
.perfil-texto > p:first-child{
  font-size: clamp(1.1rem, 1.7vw, 1.35rem);
  font-weight: 600;
  line-height: 1.6;
  color: var(--c-indigo);
}

.perfil-cita{
  margin: clamp(2rem, 4vw, 2.75rem) 0 0;
  padding-left: clamp(1.25rem, 2vw, 1.75rem);
  border-left: 3px solid var(--c-cyan);
}
.perfil-cita blockquote{
  margin: 0;
  font-size: clamp(1.05rem, 1.5vw, 1.2rem);
  font-style: italic;
  line-height: 1.6;
  color: var(--c-ink);
}
.perfil-cita figcaption{
  margin-top: .6rem;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c-blue);
}

.perfil-bloque{ margin-top: clamp(2.5rem, 5vw, 3.5rem); }
/* Sin tamaño propio: los h2 de todo el sitio miden lo mismo y hay una
   comprobación en _tools/verificar.js que lo vigila. */
/* ⚠️ TAMAÑO PROPIO, MÁS CHICO QUE EL h2 DEL SISTEMA (2026-08-13, pedido del
   cliente: "bajá más el tamaño de los títulos, quedan muy grandes"). El global
   es clamp(1.9rem, 3.6vw, 2.9rem) —46px a 1440—, pensado para un titular que
   abre una sección de pantalla completa; acá son rótulos que encabezan listas
   cortas dentro de una columna, y a ese tamaño competían con el nombre de la
   portada.
   No choca con la comprobación de "todos los h2 miden igual" de verificar.js:
   esa mira `.section-head h2` y `#equipo h2`, las dos de index.html. */
.perfil-bloque h2{
  font-size: clamp(1.2rem, 1.7vw, 1.5rem);
  letter-spacing: -.01em;
  margin-bottom: .85rem;
}

.perfil-areas{
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
}
.perfil-areas li{
  padding: .55rem 1.1rem;
  border-radius: var(--radius-pill);
  background: var(--c-mist);
  border: 1px solid var(--c-line);
  font-size: .9rem;
  font-weight: 600;
}

.perfil-lista li{
  display: grid;
  gap: .15rem;
  padding: 1.05rem 0;
  border-bottom: 1px solid var(--c-line);
}
.perfil-lista li:first-child{ border-top: 1px solid var(--c-line); }
.dato-titulo{ font-weight: 700; font-size: 1rem; line-height: 1.35; }
.dato-casa{ font-size: .92rem; color: var(--text-muted); line-height: 1.45; }
.dato-anio{
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--c-blue);
  font-variant-numeric: tabular-nums;
}


/* Ficha del equipo que SÍ tiene página propia (hoy solo Victoria Burt).
   El enlace va superpuesto y sin contenido: no aporta caja al layout, así que
   el recorrido horizontal sigue midiendo lo mismo. Ver la nota del HTML. */
.member-enlace{
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: var(--radius-sm);
}
.team-member--con-ficha{ cursor: pointer; }
/* Afordancia mínima: al pasar por encima, el nombre toma el color de marca.
   No se le pone subrayado ni ícono para no romper la uniformidad de la fila,
   donde las otras 27 fichas no llevan a ningún lado. */
.team-member--con-ficha:hover .member-name{ color: var(--c-cyan); }
.member-enlace:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 4px; }


/* Sin párrafos de texto corrido, la cita queda como primer elemento de la
   columna: ahí no corresponde el margen superior que la separa del texto. */
.perfil-texto > .perfil-cita:first-child{ margin-top: 0; }


/* --------------------------------------------------------------------------
   Curva de marca de la portada — la figura sale de esta línea
   --------------------------------------------------------------------------
   Ver la nota del HTML: es la curva cian real del logo, cortada por su línea
   media igual que los arcos del hero.

   ORDEN DEL APILADO DE LA PORTADA. Si se agrega una capa, ubicarla en esta
   escala; el hueco entre la foto y el texto es lo que hace que la figura se lea
   saliendo de la curva sin que el relleno se coma el titular:
       fondo (gradiente)   0
       .perfil-foto        1
       .perfil-curva       2   relleno del cuerpo + arco de marca
       .container (texto)  3
   -------------------------------------------------------------------------- */
.perfil-portada{ position: relative; }
/* ⚠️ EL z-index VA EN EL TEXTO, NO EN EL .container.
   Con `z-index: 3` en el .container, ese contenedor crea un CONTEXTO DE APILADO
   y todo lo que hay dentro —la foto incluida— pinta por encima de la curva, por
   más que la foto tenga `z-index: 1`: el z-index de un hijo solo compite dentro
   del contexto de su padre, no contra los hermanos del padre.
   El síntoma era que el relleno de la curva no tapaba la parte baja de la
   figura ni su sombra: se veía un rectángulo grisáceo por debajo de la línea.
   Poniendo el z-index en el bloque de texto, los tres quedan en el MISMO
   contexto —el de .perfil-portada— y el orden se respeta:
       .perfil-foto  1  <  .perfil-curva  2  <  .perfil-portada-txt  3 */
.perfil-portada > .container{ position: relative; }
.perfil-portada-txt{ position: relative; z-index: 3; }
.perfil-foto{ position: relative; z-index: 1; }

/* ⚠️ DOS ENTRADAS, UNA SOLA DEFINICIÓN. La misma curva cierra la portada de la
   ficha y el banner del directorio (`equipo.html`). Se comparten las reglas en
   vez de duplicarlas para que no puedan desincronizarse: si cambia el alto o el
   relleno, cambia en los dos a la vez. Lo único propio de cada una es el
   `z-index`, más abajo. */
.perfil-curva,
.team-banner-curva{
  position: absolute;
  left: 0; right: 0; bottom: -1px;   /* -1px: tapa la costura de redondeo */
  z-index: 2;
  height: var(--curva-h);
  pointer-events: none;
}
.perfil-curva svg,
.team-banner-curva svg{ display: block; width: 100%; height: 100%; }
/* ⚠️ El banner del directorio tiene `overflow: hidden` —está ahí para acotar el
   desplazamiento de la palabra "Equipo"—, así que el `bottom: -1px` de arriba se
   recorta y la costura vuelve a quedar expuesta. Se compensa estirando la curva
   1px por debajo del borde en vez de moverla. */
.team-banner-curva{ height: calc(var(--curva-h) + 1px); bottom: 0; }

/* ⚠️ EL BANNER TIENE QUE RESERVARLE LA BANDA A LA CURVA. NO ES OPCIONAL.
   El relleno de la curva arranca en el borde SUPERIOR IZQUIERDO de su caja —el
   path abre en (0,0)—, así que del lado izquierdo el blanco cubre TODO el alto
   de la banda. Y ahí es justo donde vive «Equipo», que además es blanco: al
   agregar la curva sin más, el titular desapareció por completo (medido a 1440:
   el h1 terminaba en 426 y la curva empezaba en 319).
   ⚠️ Y NO SIRVE UN `padding-bottom`: la palabra se mueve con `transform`, que a
   propósito NO participa del layout (ver la nota de `--equipo-y`), así que
   ningún relleno la empuja hacia arriba. Se probó y la curva sólo bajó de 319 a
   350, con el titular todavía terminando en 426.
   Lo que sí funciona es que el banner CREZCA: la banda de la curva es alto
   nuevo, por debajo de donde ya cae la palabra. Todo sale de las mismas
   variables —el alto de la curva y el propio desplazamiento del titular— para
   que no puedan desincronizarse: si mañana alguien baja más la palabra o
   agranda la curva, la reserva lo acompaña sola.

   ⚠️ EL `max()` NO ES UN ADORNO — ARREGLA UN ACOPLE (2026-08-13).
   La reserva era `+ var(--equipo-y)` a secas, y eso le daba DOS trabajos a una
   sola variable: mover la palabra y fijar el alto del banner. Servía para
   bajarla (ahí la reserva hace falta), pero al SUBIRLA el banner se achicaba lo
   mismo: de `97px` a `0px` pasaba de 677px a 580px a 1440. Y como la foto usa
   `object-fit: cover` y el arco de fondoazul.png se encuadra sobre ese alto,
   cambiaba todo el fondo — el cliente lo vio enseguida al probar valores.

   Con `max()` cada variable vuelve a tener UN trabajo:

       --equipo-y     mueve SOLO la palabra
       --banner-extra fija SOLO el aire del banner

   · Si subís la palabra (`--equipo-y` < `--banner-extra`), gana el segundo: el
     banner y el fondo no se mueven.
   · Si la bajás más allá de `--banner-extra`, gana `--equipo-y` y la reserva
     vuelve a crecer sola — la protección de arriba sigue entera.
   · Si lo que querés es un banner más bajo, tocás `--banner-extra` y nada más.

   Efecto lateral bueno: el margen entre el pie del titular y la banda blanca
   (66px en el peor ancho, 1024×700) pasó a ser un PISO. Subir la palabra sólo
   lo agranda; ya no hay forma de reducirlo desde acá.

   ⚠️ `--banner-extra` arranca en 97px, que era el valor de `--equipo-y` al hacer
   este cambio. NO es casualidad: así el banner mide exactamente lo que medía
   antes y el arreglo no movió un píxel de la página. */
.team-banner{
  --banner-extra: 97px;
  min-height: calc(clamp(320px, 50vh, 560px) + var(--curva-h)
                   + max(var(--banner-extra), var(--equipo-y)));
  /* ⚠️ LA RESERVA DE LA CURVA INCLUYE EL DESPLAZAMIENTO DEL BLOQUE, y hace
     falta desde que el filtro vive acá adentro (2026-08-13).
     El `min-height` de arriba sólo manda mientras el contenido entre; cuando el
     contenido es más alto —y el filtro APILADO mide 185px—, el alto lo da el
     contenido y el `min-height` deja de intervenir. En ese caso los píxeles que
     `--equipo-y` corre el bloque hacia abajo se comen la banda de la curva: se
     midió el filtro metido 21px dentro del blanco a 1024 y a 1180, con
     `--equipo-y: 20px`. Sumarlo al relleno hace que el bloque siempre termine
     por encima de la banda, venga el alto del min-height o del contenido.
     `max(0px, …)` para que un valor negativo —subir la palabra— no reste
     reserva.

     El tercer sumando es aire: sin él el bloque termina EXACTAMENTE en el techo
     de la banda (medido: 0px de separación entre el filtro apilado y el blanco
     de 900 a 1180px) y se lee pegado. Con `box-sizing: border-box` este relleno
     no agranda el banner en los anchos donde manda el `min-height`. */
  padding-bottom: calc(var(--curva-h) + max(0px, var(--equipo-y)) + clamp(1rem, 2.5vw, 2.25rem));
}
/* El relleno tiene que ser EXACTAMENTE el fondo del cuerpo, o se ve el escalón
   entre la curva y la sección de abajo. */
.curva-piso{ fill: var(--bg-body); }
.curva-arco{ fill: var(--c-cyan); }

/* ⚠️ ACÁ NO VA EL `padding-bottom` DE LA PORTADA, AUNQUE LO PAREZCA.
   Había uno —`clamp(4rem, 9vw, 9rem)`— y era CÓDIGO MUERTO: unas líneas más
   abajo, en el bloque del separador de marca, hay otro atado a `--curva-h` que
   lo pisaba por orden. Se descubrió el 2026-08-13 al intentar ajustarlo acá y
   ver que el valor computado no cambiaba.
   El que manda es `calc(var(--curva-h) * .75)`, y va en pareja con el
   `margin-bottom: calc(var(--curva-h) * -.75)` de la foto: ese par es lo que
   hace que la figura emerja de la curva. Tocar uno sin el otro rompe el efecto.
   Quien mantiene el TEXTO por encima de la banda es el `padding-bottom` propio
   de `.perfil-portada-txt`. */


/* ⚠️ LA FIGURA TIENE QUE METERSE DENTRO DE LA BANDA DE LA CURVA.
   Sin esto la foto termina en el borde del contenido, con un corte recto, y la
   curva queda debajo como una franja aparte: la figura no "sale" de la línea,
   solo está encima de ella.
   El alto de la curva y lo que baja la foto salen de la MISMA variable, así que
   no se pueden desincronizar: la foto baja exactamente hasta el borde inferior
   de la portada y el relleno blanco le tapa lo que queda por debajo de la línea
   media. El texto conserva ese mismo margen de separación, y como a su altura la
   línea media pasa más abajo, nunca lo alcanza el relleno. */
.perfil-portada{ padding-bottom: calc(var(--curva-h) * .75); }
.perfil-curva{ height: var(--curva-h); }
.perfil-foto{ margin-bottom: calc(var(--curva-h) * -.75); }

/* ⚠️ ACÁ HUBO DOS INTENTOS DE PONER LA FOTO A SANGRE sobre la mitad derecha
   —el segundo con la curva de marca como separación entre las dos mitades— y
   los dos se revirtieron a pedido del cliente (2026-08-13). La foto es la
   figura contenida en su columna, apoyada en la curva.

   Si alguna vez se retoma, tres cosas que costaron encontrarlas:
   · el <img> tiene que salir del `.container` en el generador —ese div lleva
     `position: relative` por el apilado con la curva, así que es ÉL el
     contenedor de posicionamiento y el `right: 0` se frena en 1280px—;
   · la regla tiene que ir al FINAL de esta hoja: `.perfil-foto` tiene cuatro
     reglas repartidas, todas con la misma especificidad, y las de más abajo
     pisan el `position: absolute` por orden de fuente;
   · la curva se hace con un solo `path` en un SVG de `viewBox="0 0 1 1"`, que
     sirve a la vez de `clipPath` (unidades de caja) y de trazo cian, con
     `vector-effect="non-scaling-stroke"` para que el grosor no se deforme. */

/* --------------------------------------------------------------------------
   Ficha de perfil — interacción
   -------------------------------------------------------------------------- */

/* Copiar teléfono / email. El botón vive al lado del enlace, no lo reemplaza.
   ⚠️ Este `display: flex` es lo que mantiene el botón A LA DERECHA del dato. Sin
   él la fila vuelve a ser un bloque y el botón cae debajo del número, partiendo
   el ítem en dos renglones. Se perdió una vez al recortar el bloque vecino y el
   síntoma fue justamente ese. */
.dato-fila{
  display: flex;
  align-items: center;
  gap: .5rem;
}
.dato-fila .dato-valor{ min-width: 0; }
.dato-copiar{
  flex: none;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  background: #fff;
  color: var(--text-muted);
  transition: color var(--dur-micro) var(--ease-soft),
              border-color var(--dur-micro) var(--ease-soft),
              background var(--dur-micro) var(--ease-soft);
}
.dato-copiar svg{ width: 15px; height: 15px; }
.dato-copiar:hover{ color: var(--c-blue); border-color: var(--c-blue); }
.dato-copiar:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 2px; }
/* Confirmación visible. El anuncio para lector de pantalla lo hace el <span>
   con aria-live que va dentro del botón (ver js/main.js). */
.dato-copiar.is-copiado{
  color: #fff;
  background: #1f9d55;
  border-color: #1f9d55;
}
.dato-copiar.is-error{
  color: #fff;
  background: #c0392b;
  border-color: #c0392b;
}

/* Las áreas ahora enlazan a #areas del home. */
.perfil-areas a{
  display: block;
  padding: .55rem 1.1rem;
  border-radius: var(--radius-pill);
  background: var(--c-mist);
  border: 1px solid var(--c-line);
  font-size: .9rem;
  font-weight: 600;
  transition: background var(--dur-micro) var(--ease-soft),
              border-color var(--dur-micro) var(--ease-soft),
              color var(--dur-micro) var(--ease-soft),
              transform var(--dur-micro) var(--ease-soft);
}
/* El <li> ya no pinta la píldora: la pinta el <a>, para que toda la superficie
   sea clickeable y no solo el texto. */
.perfil-areas li{ padding: 0; background: none; border: 0; }
.perfil-areas a:hover{
  background: var(--gradient-brand);
  border-color: transparent;
  color: #fff;
  transform: translateY(-2px);
}
.perfil-areas a:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 2px; }

/* Formación y trayectoria: realce al pasar, para que se lea fila por fila. */
.perfil-lista li{
  padding-inline: .5rem;
  margin-inline: -.5rem;
  border-radius: var(--radius-sm);
  transition: background var(--dur-micro) var(--ease-soft);
}
.perfil-lista li:hover{ background: var(--c-mist); }

/* ⚠️ LA FOTO NO SE ANIMA. NI AL ENTRAR NI AL PASAR EL PUNTERO.
   Acá vivía un `scale(1.02)` en hover —escalado desde abajo para no despegarse
   de la curva— y el cliente lo hizo sacar el 2026-08-12, después de haber hecho
   sacar también su animación de entrada. Las dos decisiones van juntas: la foto
   se queda quieta.
   No volver a agregar ninguna de las dos sin pedirlo. Lo vigila la suite de la
   ficha, que comprueba que el `transform` no cambie al pasar el puntero.

   Nota para quien vuelva por acá: la entrada del TEXTO de la portada sí existe
   (ver el bloque "Entrada de la portada"), y su `animation-fill-mode` es
   `backwards` justamente porque un `forwards` pisa cualquier `:hover`. Ese
   detalle sigue importando aunque la foto ya no tenga ninguno. */


/* ==========================================================================
   HERO — DOS PANTALLAS (rediseño 2026-08-13)
   ==========================================================================
   Reemplaza al hero de 3,5 pantallas con bandas de foto, contadores y frases
   laterales. El cliente pidió dos pantallas y no saturar de elementos.
   ========================================================================== */

/* ⚠️ LAS DOS PANTALLAS COMPARTEN CELDA DE GRID, no van una debajo de otra.
   Apiladas en flujo normal el bloque mediría la suma de las dos y el hero
   saltaría de alto al cruzar; así mide el alto de la más alta y queda quieto.
   Es el mismo recurso que usaban el titular rotativo y los contadores del hero
   anterior, y que siguen usando .counter-item y .note-item en otras secciones. */
/* ⚠️ EL APILADO EN LA MISMA CELDA ES CONDICIONAL, NO LA REGLA BASE. Era base y
   dejaba un agujero: en escritorio (≥980px) SIN JavaScript —o si GSAP no
   carga— nadie pone `.hero-dos-pantallas`, así que no había cruce que ordenara
   las pantallas y el logo se imprimía ENCIMA del párrafo institucional; no se
   leía ninguno de los dos. El media query que las desapila cubría sólo móvil y
   movimiento reducido, y ese caso caía justo en el medio.
   Por defecto van una debajo de la otra, que es lo legible pase lo que pase;
   se apilan sólo cuando hay una coreografía que las alterne. */
/* ⚠️ `.hero > .hero-cont` Y NO `.hero-cont` A SECAS. Más arriba está
   `.hero > .container{ position: relative; z-index: 1 }` —especificidad 0,2,0—
   y este contenedor lleva las dos clases: con un selector de clase simple
   (0,1,0) el 4 no se aplicaba y el contenido quedaba en el nivel 1, POR DEBAJO
   del SVG de los arcos (nivel 2). Mientras el SVG sólo tenía curvas finas no se
   notaba, porque todo lo demás era transparente; en cuanto la pantalla 2 sumó
   la franja azul opaca (2026-08-18), esa franja tapó el párrafo y los botones.
   El nivel 4 es el que dice la tabla de apilado del hero. */
.hero > .hero-cont{
  position: relative;
  z-index: 4;
}
.hero-dos-pantallas .hero-cont{ display: grid; }
.hero-dos-pantallas .hero-pantalla{ grid-area: 1 / 1; }
.hero-pantalla--2{ margin-top: clamp(2.5rem, 8vw, 4rem); }
.hero-dos-pantallas .hero-pantalla--2{ margin-top: 0; }

/* ⚠️ `.hero-armando`: EL HERO YA ARMADO DESDE EL PRIMER CUADRO (2026-09-16).
   La pone el script del <head> de index.html antes del primer pintado y la quita
   js/main.js cuando termina de fijar el estado inicial con GSAP. Mientras está,
   el CSS esconde exactamente lo mismo que esconde el JS al arrancar —pantalla 2,
   foto y logo del header—, así que el primer cuadro ya es la pantalla 1.
   Antes se pintaba el diseño de respaldo hasta que el JS armaba, y el JS espera a
   que baje la fuente: el cliente veía el hero desarmado entre 0,2 y 0,9 s.
   ⚠️ Los valores del JS (`gsap.set`) van en línea y le ganan a estas reglas, así
   que quitar la clase no cambia nada de lo que el JS ya fijó: no hay salto. */
.hero-armando #heroP2,
.hero-armando #brandLink{ opacity: 0; visibility: hidden; }
.hero-armando .hero-bg{ opacity: 0; }
/* El menú se reparte midiendo el hueco que deja el logo, y eso sólo lo sabe el
   JS. En vez de mostrarlo en su sitio natural y correrlo después —se veía el
   desplazamiento—, arranca invisible y aparece ya repartido, con un fundido.
   Decisión del cliente entre las dos opciones. */
.hero-armando .site-header .nav-inline{ opacity: 0; visibility: hidden; }
.site-header .nav-inline{ transition: opacity .4s var(--ease-soft); }

/* ---------- Pantalla 1 ---------- */
/* ⚠️ SÓLO EL LOGO SOBRE EL AZUL DE MARCA. Pedido del cliente el 2026-08-16, que
   revierte la carta de presentación del día anterior: se fueron la sigla PSTBN,
   "+58 años de trayectoria", la frase y los dos botones. El fondo azul es el
   `--gradient-dark` que ya trae `.hero`; la foto queda apagada y sólo entra en
   la pantalla 2 (lo hace el JS, para que sin JS y en móvil la foto se siga
   viendo). Si vuelve a hacer falta un CTA en la portada, va en la pantalla 2 o
   en la sección siguiente: acá el pedido es que no haya nada más que la marca. */
/* Los tres bloques —logo, contador y botones— apilados y centrados como un
   conjunto. `align-content: center` centra el GRUPO en la celda; `justify-items`
   centra cada uno en su fila. */
.hero-pantalla--1{
  display: grid;
  justify-items: center;
  align-content: center;
  gap: clamp(1.1rem, 2.4vh, 2rem);
  text-align: center;
}
/* ⚠️ EL LOGO SE LIMITA TAMBIÉN POR EL ALTO, no sólo por el ancho. Con `width`
   como único tope, en una ventana baja (1535x724, la del cliente) el logo medía
   416px y, sumado al `padding-top` del hero, estiraba la sección MÁS ALLÁ DE LA
   VENTANA. Y como el indicador de scroll está posicionado contra el borde de
   abajo del hero —no de la pantalla—, se iba fuera de cuadro: por eso "el logo
   debe estar centrado en pantalla así como el scroll de abajo".
   `object-fit: contain` es lo que evita que el tope de alto lo deforme: la caja
   se achata pero el dibujo conserva su proporción dentro. */
/* ⚠️ ACHICADO EL 2026-08-16 a pedido del cliente, y además tenía que dejar sitio
   al contador y a los botones que se sumaron en la misma pantalla. El tope de
   alto sigue siendo imprescindible: es lo que evita que en una ventana baja el
   conjunto desborde y arrastre al indicador de scroll fuera de cuadro. */
.hero-logo-1{
  width: min(44vw, 400px);
  height: auto;
  max-height: min(26vh, 250px);
  object-fit: contain;
  /* La sombra despega la marca del azul sin bajarle opacidad: el logo tiene que
     leerse nítido, no como marca de agua. */
  filter: drop-shadow(0 10px 40px rgba(4,6,26,.55));
}

/* ---------- Contador de años ---------- */
.hero-anios{
  margin: 0;
  font-size: clamp(1rem, 1.5vw, 1.3rem);
  font-weight: 600;
  letter-spacing: .01em;
  color: rgba(255,255,255,.9);
  text-shadow: 0 2px 14px rgba(8,8,20,.6);
}
.hero-anios-num{
  color: var(--c-cyan);
  font-weight: 800;
  font-size: 1.35em;
  /* ⚠️ CIFRAS DE ANCHO FIJO. Sin esto el número BAILA mientras cuenta: al pasar
     de una cifra a dos, y con tipografías proporcionales también entre dígitos
     —el 1 es más angosto que el 8—, la frase entera se corre a cada cuadro.
     `tabular-nums` le da a todos los dígitos el mismo ancho y el renglón queda
     quieto. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
/* «ASU, PY» — la ciudad, debajo del contador.
   ⚠️ USA `.eyebrow` DEL SISTEMA, no valores propios. La primera versión traía
   su propio `font-size`, su `letter-spacing` y su color: tres valores inventados
   para un rol que el sistema ya tiene resuelto (volanta: .8rem / 700 / .14em /
   mayúsculas). Acá sólo queda lo que es específico de estar sobre el video —la
   sombra que lo despega del fondo— y el margen. Si cambia la volanta del
   sistema, esto la sigue.
   `.eyebrow--light` es la variante cian, la misma que ya usaba el hero. */
.hero-lugar{
  margin: -.2rem 0 0;
  /* Sin raya: hasta el 2026-08-18 `.eyebrow::before` pintaba un trazo a la
     izquierda y acá se apagaba; desde entonces ninguna volanta del sitio lleva
     raya (ver `.eyebrow` y `.nos-seccion-rotulo`). El `gap: 0` repite el de
     `.eyebrow` y no cambia nada. */
  gap: 0;
  text-shadow: 0 2px 12px rgba(8,8,20,.7);
}
/* Ya no hay `.btn-row` en la pantalla 1 —sus botones bajaron a la 2 el
   2026-08-18—, así que este selector quedó sólo para la pantalla 2. */
.hero-p2-botones{
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .9rem;
}
.hero-p2-botones{ margin-top: clamp(1.2rem, 3vh, 2rem); }
/* ⚠️ EL PRIMARIO SE INVIERTE SOBRE LA FRANJA, Y SIGUE HACIENDO FALTA AUNQUE LA
   FRANJA YA NO SEA `--c-blue`. Nació porque el degradado de `.btn--primary`
   arranca justo en `--c-blue`, que entonces era el color de la franja: medido,
   el relleno del botón daba rgb(46,99,235) contra rgb(45,98,234) del fondo
   —1.01:1—, o sea que el botón no tenía borde visible de ningún tipo. Desde el
   2026-08-19 la franja es el índigo `#2e3092` y ese empate exacto ya no se da,
   pero el azul del botón sobre índigo sigue siendo azul sobre azul —vecinos en
   la misma paleta— y se lee como una mancha, no como un botón. Sobre color de
   marca el primario va al revés: relleno blanco y texto azul, que además es el
   par de más contraste posible. El fantasma no necesita nada, su borde blanco
   ya se lee. */
.hero-p2-botones .btn--primary{
  background: #fff;
  color: var(--c-blue);
}
.hero-p2-botones .btn--primary:hover{
  background: var(--c-mist);
  color: var(--c-indigo-2);
}
/* ⚠️ EL FANTASMA LLEVA EL TRATAMIENTO DE FONDO OSCURO (2026-09-17). Heredaba el
   de fondo claro: borde de tinta al 18% —invisible sobre el azul— y, al pasar
   el cursor, texto `--c-blue` sobre `--c-indigo-2`, que da 2,1:1 y no se lee.
   Es el mismo par que ya usan `.section--dark` y `.team`. */
.hero-p2-botones .btn--ghost{
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,.35);
  color: #fff;
}
.hero-p2-botones .btn--ghost:hover{
  box-shadow: inset 0 0 0 1.5px var(--c-cyan);
  color: var(--c-cyan);
}
/* ⚠️ CON DOS PANTALLAS LA FRANJA ES CLARA DETRÁS DEL TEXTO (2026-09-17). Pedido
   del cliente: «el degradado debe ser con más blanco y las letras azules». El
   párrafo va en índigo y sin la sombra oscura, que sobre fondo claro ensucia.
   Los botones quedan sobre la bajada hacia la tinta, así que llevan fondo
   PROPIO y se leen igual en cualquier punto del degradado: primario índigo con
   texto blanco, fantasma blanco con texto índigo. Sólo con `.hero-dos-pantallas`:
   en móvil, con movimiento reducido o sin JS el párrafo sigue sobre la foto y
   conserva el blanco de arriba. El contraste lo mide _tools/verificar_hero.js. */
.hero-dos-pantallas .hero-nosotros{
  color: var(--c-indigo-2);
  text-shadow: none;
}
.hero-dos-pantallas .hero-nosotros.esta-escribiendo::after{ background: var(--c-indigo-2); }
.hero-dos-pantallas .hero-p2-botones .btn--primary{
  background: var(--c-indigo-2);
  color: #fff;
}
.hero-dos-pantallas .hero-p2-botones .btn--primary:hover{
  background: var(--c-blue);
  color: #fff;
}
.hero-dos-pantallas .hero-p2-botones .btn--ghost{
  background: rgba(255, 255, 255, .92);
  box-shadow: inset 0 0 0 1.5px var(--c-indigo-2);
  color: var(--c-indigo-2);
}
.hero-dos-pantallas .hero-p2-botones .btn--ghost:hover{
  background: #fff;
  box-shadow: inset 0 0 0 1.5px var(--c-blue);
  color: var(--c-blue);
}

/* ⚠️ PADDING SIMÉTRICO MIENTRAS DURAN LAS DOS PANTALLAS. El hero trae
   `padding-top` de 176px contra 96px abajo: con esa diferencia el centro óptico
   del contenido cae ~40px por debajo del centro de la ventana, que es lo que se
   veía como "el logo no está centrado". Acá arriba sólo hay que dejar libre el
   header, así que las dos caras valen lo mismo y el centrado vuelve a ser real.
   El párrafo de la pantalla 2 no depende de esto: lo coloca el JS. */
.hero-dos-pantallas .hero{
  padding-top: clamp(6rem, 11vh, 8.5rem);
  padding-bottom: clamp(6rem, 11vh, 8.5rem);
  /* ⚠️ ALTO DEFINIDO, NO `min-height`. `min-height: 100vh` es un piso, no un
     techo: con la pantalla 2 alta el hero igual crecía —a 1535x724 llegaba a
     786— y como su centro es el del logo, el logo bajaba y el indicador de
     scroll se iba de cuadro. Con alto definido el contenedor de adentro
     (`flex: 1; min-height: 0`) recibe exactamente lo que sobra y nada empuja.
     Sólo mientras hay dos pantallas: sin JS el hero vuelve a crecer con su
     contenido, que es lo correcto ahí. */
  height: 100vh;
  height: 100svh;
}

/* ---------- Pantalla 2 ---------- */
/* Centrada y con medida de lectura acotada, como en el boceto del cliente. */
/* ⚠️ Cursor de la animación de escritura. Vive en `::after` del párrafo y sólo
   existe mientras dura la clase, que pone y quita el JS: un cursor permanente
   sobre un texto ya escrito parece un error de maquetación. Los `span` que crea
   SplitType no necesitan estilo propio; el efecto es la aparición escalonada. */
.hero-nosotros.esta-escribiendo::after{
  content: "";
  display: inline-block;
  width: .06em;
  height: 1em;
  margin-left: .06em;
  vertical-align: -.12em;
  background: var(--c-cyan);
  animation: hero-cursor .75s steps(1) infinite;
}
@keyframes hero-cursor{ 50%{ opacity: 0; } }
@media (prefers-reduced-motion: reduce){
  .hero-nosotros.esta-escribiendo::after{ display: none; }
}
.hero-nosotros{
  max-width: 46ch;
  margin-inline: auto;
  text-align: center;
  font-size: clamp(1.05rem, 1.75vw, 1.5rem);
  font-weight: 600;
  line-height: 1.6;
  color: #fff;
  text-shadow: 0 2px 16px rgba(8,8,20,.6);
}
/* Las rayas ocupan la franja de arriba, así que la pantalla 2 se descuelga para
   no quedar debajo de ellas. Sólo cuando hay dos pantallas: sin JS el bloque
   va en su sitio natural. */
/* ⚠️ EL TEXTO TIENE QUE CAER POR DEBAJO DE LAS RAYAS: son opacas y el párrafo es
   blanco, así que al cruzarse se vuelve ilegible. Pasó dos veces.
   Acá el párrafo manda y las rayas se acomodan: esta separación es fija y es el
   JS el que coloca la banda de rayas para que termine por encima de ella
   (`dibujarArcos` en js/main.js). Al revés —rayas fijas y párrafo esquivándolas—
   se entra en un círculo, porque mover el párrafo cambia el alto del bloque y
   con él la posición de todo lo demás. */
/* ⚠️ EL CONTENEDOR DEL HERO TIENE ALTO FIJO MIENTRAS DURAN LAS DOS PANTALLAS.
   `flex: 1` le da exactamente el espacio que sobra dentro del hero y
   `min-height: 0` le impide crecer con su contenido. Es lo que evita el fallo
   de 1535x724: sin esto la pantalla 2 estiraba la celda, el hero superaba los
   100vh, y como las dos pantallas comparten celda, el logo de la pantalla 1 se
   iba con ella fuera de cuadro junto con el indicador de scroll.
   Además vuelve estable el cálculo del JS: el borde superior de la celda ya no
   depende de lo que mida el párrafo. */
.hero-dos-pantallas .hero-cont{
  flex: 1 1 auto;
  min-height: 0;
  grid-template-rows: minmax(0, 1fr);
}
/* `--p2-top` lo escribe `dibujarArcos`: es la posición completa del párrafo,
   medida desde el borde de la celda. El `clamp` queda sólo como valor razonable
   para el instante anterior a que corra el JS. */
.hero-dos-pantallas .hero-pantalla--2{
  padding-top: var(--p2-top, clamp(5rem, 22vh, 14rem));
}

/* ---------- Indicador de desplazamiento ---------- */
/* ⚠️ SIN LA PALABRA "SCROLL" — al cliente no le convence el término. Un mouse
   dibujado con una flecha bajando en bucle: se entiende sin texto y no hay que
   traducirlo a los tres idiomas. */
.hero-mouse{
  position: absolute;
  left: 50%;
  bottom: clamp(1.5rem, 4vh, 3rem);
  transform: translateX(-50%);
  z-index: 5;
  display: none;              /* lo enciende el JS sólo en desktop */
  padding: .5rem;
  background: none;
  border: 0;
  cursor: pointer;
}
.hero-dos-pantallas .hero-mouse{ display: block; }
.hero-mouse-cuerpo{
  display: block;
  width: 26px;
  height: 42px;
  border: 2px solid rgba(255,255,255,.75);
  border-radius: 13px;
  position: relative;
  transition: border-color var(--dur-micro) var(--ease-soft);
}
/* ⚠️ UNA FLECHA HACIA ABAJO, NO LA RUEDITA (2026-09-16). Hasta ese día había
   una barrita de 3×8px bajando, que imitaba la rueda del mouse; el cliente
   pidió una flecha «porque es más entendible».
   Medidas: el interior del cuerpo es 22×38px (26×42 menos el borde de 2px). La
   flecha ocupa 12×16 y recorre 9px, así que va de y=6 a y=31 y nunca toca el
   borde de abajo. Mismo trazo de 2px y puntas redondeadas que el contorno del
   mouse, para que se lean como una sola pieza. */
.hero-mouse-flecha{
  position: absolute;
  top: 6px;
  left: 50%;
  width: 12px;
  height: 16px;
  margin-left: -6px;
  overflow: visible;
  fill: none;
  stroke: #fff;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke var(--dur-micro) var(--ease-soft);
  animation: hero-flecha 1.8s var(--ease-soft) infinite;
}
/* Aparece arriba, baja y se desvanece al llegar: el movimiento es lo que dice
   "hacia abajo", la punta lo confirma. Se sostiene visible la mayor parte del
   recorrido —con la barrita se apagaba antes— porque ahora la forma también
   comunica y conviene que se alcance a ver. */
@keyframes hero-flecha{
  0%   { transform: translateY(0);   opacity: 0; }
  15%  { transform: translateY(1px); opacity: 1; }
  60%  { opacity: 1; }
  80%  { transform: translateY(9px); opacity: 0; }
  100% { transform: translateY(9px); opacity: 0; }
}
.hero-mouse:hover .hero-mouse-cuerpo,
.hero-mouse:focus-visible .hero-mouse-cuerpo{ border-color: var(--c-cyan); }
/* La flecha acompaña al borde: si sólo cambiara el contorno, el mouse quedaría
   de dos colores al pasar el cursor. */
.hero-mouse:hover .hero-mouse-flecha,
.hero-mouse:focus-visible .hero-mouse-flecha{ stroke: var(--c-cyan); }
.hero-mouse:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 6px; border-radius: 16px; }
/* RED DE SEGURIDAD. Hoy, con movimiento reducido, el hero no usa las dos
   pantallas y el indicador NI SIQUIERA SE MUESTRA (medido el 2026-09-16: queda
   en `display: none`). Esta regla está por si eso cambia: sin ella la flecha
   quedaría clavada en su primer fotograma, que es `opacity: 0`, o sea un mouse
   vacío. Se la baja 5px para que en reposo quede CENTRADA en el cuerpo. */
@media (prefers-reduced-motion: reduce){
  .hero-mouse-flecha{ animation: none; opacity: 1; transform: translateY(5px); }
}

/* ---------- Los arcos ---------- */
.hero-arcs-svg{
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

/* ---------- Móvil y movimiento reducido ---------- */
/* Sin pin no hay cruce: las dos pantallas se leen seguidas, el logo arriba y el
   párrafo debajo, sobre la foto de fondo —que acá sí se ve, porque el JS sólo
   la apaga en modo dos pantallas—.
   El desapilado ya no vive acá: ahora es el estado POR DEFECTO (ver .hero-cont),
   justamente para que también valga en el caso que este media query no cubría,
   que era escritorio sin JavaScript. Acá queda sólo lo propio de móvil. */
@media (max-width: 979px), (prefers-reduced-motion: reduce){
  .hero-arcs-svg{ display: none; }
}
/* ⚠️ EL PÁRRAFO VA A LA IZQUIERDA SÓLO DONDE LLENA EL ANCHO (2026-09-19). Estaba
   en el bloque de arriba y valía para toda tablet: desde ~650px la columna de
   46ch es más angosta que el contenedor y, sin `margin-inline: auto`, quedaba
   pegada a la izquierda bajo un logo y unos botones centrados (768x1024, y en
   escritorio con movimiento reducido). En teléfonos no cambia nada. */
@media (max-width: 599px){
  .hero-nosotros{ text-align: left; margin-inline: 0; }
}
/* Sin dos pantallas no hay arcos, tampoco a ≥980px: pasa en una pantalla más
   alta que ancha (ver `min-aspect-ratio` en js/main.js). Sin esta regla, un
   resize redibuja los arcos y aparecían opacos sobre el hero apilado. */
html:not(.hero-dos-pantallas) .hero-arcs-svg{ display: none; }

/* ==========================================================================
   NOVEDADES — listado y vista individual (2026-08-17)
   ==========================================================================
   ⚠️ TODO SALE DE LOS TOKENS. No hay un solo color, radio, sombra ni tamaño
   suelto en este bloque: la tipografía viene de la escala de titulares que
   documenta la cabecera de este archivo, los colores de las variables de
   :root y los botones de `.btn`. Si algo hace falta y no existe como token,
   se agrega arriba, no acá.

   La estructura de la vista individual sigue la referencia que pasó el cliente
   (guyer.com.uy) — orden de bloques, imagen principal, migas de pan,
   relacionadas — pero NADA de su tratamiento visual.
   ========================================================================== */

/* ---------- Listado ---------- */
/* ⚠️ LA SECCIÓN DE TARJETAS ES BLANCA, NO AZUL. La primera versión reusaba
   `.news-grid--glass` sobre el índigo del home y el cliente lo marcó: "todo el
   listado es azul". El azul se queda SÓLO en el banner de portada; de la curva
   de marca para abajo el fondo es el del cuerpo del sitio.
   La tarjeta es la misma en estructura —mismo markup, mismo generador— con la
   variante clara de abajo. */
.blog-seccion{ background: var(--bg-body); }
.blog-seccion .news-grid{ margin-top: 0; }
/* ⚠️ SÓLO EL LISTADO, NO LAS «VER OTROS BLOGS» DE LAS NOTAS. La misma clase
   `.blog-seccion` se usa en los dos sitios, pero el problema es de uno solo: en
   `novedades.html` la sección va debajo de la curva del banner, cuyo relleno del
   lado izquierdo YA ES BLANCO y aporta su propio aire; sumado al
   `clamp(4rem,9vw,7.5rem)` genérico de `.section-pad` daban 120px y las tarjetas
   quedaban muy abajo (lo marcó el cliente el 2026-08-19). En las notas, en
   cambio, esa sección viene después del cuerpo del artículo y ahí los 120px son
   los que la separan del texto: tocarlos sería empeorarla.
   Por eso el selector es el HERMANO ADYACENTE del banner —«la sección de blogs
   que va justo después de la curva»— y no una clase nueva en el HTML: no hay que
   acordarse de ponerla, la estructura ya lo dice.
   ⚠️ El valor es el MISMO que usa `.team-directory`, que resuelve exactamente la
   misma situación bajo la misma curva. Si un día se ajusta uno, ajustar los dos.
   120px → 40px a 1440. */
.team-banner + .blog-seccion{ padding-top: clamp(1.5rem, 3vw, 2.5rem); }

/* ---------- Tarjeta clara ----------
   Todos los valores salen de los tokens: la superficie es blanca sobre el
   cuerpo del sitio, el borde es `--c-line` —el mismo que separa bloques en el
   resto— y la sombra es `--shadow-soft`, que ya usan las demás tarjetas
   claras. Al pasar el cursor sube igual que la de vidrio, para que el gesto sea
   el mismo en las dos. */
.news-grid--claro .news-card{
  border-radius: var(--radius-md);
  background: var(--c-white);
  border: 1px solid var(--c-line);
  box-shadow: var(--shadow-soft);
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  transition: transform var(--dur-micro) var(--ease-soft),
              box-shadow var(--dur-micro) var(--ease-soft),
              border-color var(--dur-micro) var(--ease-soft);
}
.news-grid--claro .news-card:hover{
  transform: translateY(-6px);
  border-color: var(--c-blue);
  box-shadow: var(--shadow-med);
}
.news-grid--claro .news-thumb{
  position: relative;
  aspect-ratio: 1/1;
  overflow: hidden;
  border-radius: var(--radius-sm);
}
.news-grid--claro .news-thumb img{
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .7s var(--ease-soft);
}
.news-grid--claro .news-card:hover .news-thumb img{ transform: scale(1.06); }
.news-grid--claro .news-body{ padding: 0; margin-top: 1rem; display: flex; flex-direction: column; flex: 1 1 auto; }
.news-grid--claro .news-title{ color: var(--text-body); }
.news-grid--claro .news-resumen{ color: var(--text-muted); }
.news-grid--claro .news-foot{ margin-top: auto; }
.news-grid--claro .news-date{ font-size: .78rem; color: var(--text-muted); }
.news-grid--claro .link-arrow{ font-size: .88rem; color: var(--c-blue); white-space: nowrap; }

/* Título de las tarjetas. ⚠️ HOY VA SIEMPRE CON `.visually-hidden`, o sea que
   estas dos declaraciones no se ven en ninguna parte del sitio: quedan porque el
   día que el título vuelva a mostrarse son las que valen. El porqué del ocultado
   está en `_tools/gen_novedades.js` (resumen: la imagen de la tarjeta ya trae el
   título dibujado y se leía dos veces). Usa el nivel h3 de la escala, sin
   tamaño propio. */
.news-title{
  margin: 0 0 .5rem;
  color: #fff;
}
/* ⚠️ ESTO NO ES REDUNDANTE. `.visually-hidden` trae `margin: -1px` como parte de
   su receta, pero está declarada ~3900 líneas más arriba y tiene la MISMA
   especificidad (0,1,0) que `.news-title`: gana la de abajo, así que el
   `margin: 0 0 .5rem` de acá le pisaba el suyo. En la práctica no se veía nada
   —el elemento sale del flujo y va recortado a 1x1— pero dejaba la utilidad a
   medias, que es justo lo que después nadie entiende. Se repone su valor. */
.news-title.visually-hidden{ margin: -1px; }
.news-resumen{
  margin: 0 0 1rem;
  font-size: .92rem;
  line-height: 1.55;
  color: rgba(255,255,255,.72);
}
/* El pie queda abajo aunque los títulos midan distinto: si no, las fechas de
   una fila quedan a alturas distintas y la grilla se ve desprolija. */
.news-grid--glass .news-body{ flex: 1 1 auto; }
.news-grid--glass .news-foot{ margin-top: auto; }

/* ---------- Vista individual ---------- */
/* ⚠️ DOS COLUMNAS: artículo y sidebar de autores, como en la referencia. Antes
   era una sola columna centrada de 74ch. El artículo conserva su medida de
   lectura —el `ch` la ata al cuerpo de la tipografía— pero ahora vive en la
   primera columna y queda alineado a la IZQUIERDA, no centrado.
   Por debajo de 900px el sidebar pasa abajo: no hay ancho para dos columnas y
   partir el texto en 30ch no se lee. */
.blog-detalle-cont{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
@media (min-width: 900px){
  .blog-detalle-cont{ grid-template-columns: minmax(0, 1fr) minmax(15rem, 20rem); }
  /* Las migas cruzan las dos columnas. */
  .blog-detalle-cont > .blog-migas{ grid-column: 1 / -1; }
}
.blog-cuerpo-col{ max-width: 74ch; }

/* ---------- Sidebar de autores ---------- */
.blog-autores{ margin: 0; padding: 0; list-style: none; display: grid; gap: 1.1rem; }
.blog-autor-item{
  display: grid;
  grid-template-columns: 64px 1fr;
  align-items: center;
  gap: .9rem;
  color: var(--text-body);
  transition: color var(--dur-micro) var(--ease-soft);
}
.blog-autor-item:hover{ color: var(--c-blue); }
.blog-autor-item:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 4px; border-radius: var(--radius-sm); }
.blog-autor-foto{
  width: 64px; height: 64px;
  object-fit: cover;
  object-position: top center;
  border-radius: var(--radius-sm);
  background: var(--c-mist);
  display: block;
}
.blog-autor-foto--vacia{ display: block; }
.blog-autor-nombre{ display: block; font-weight: 700; font-size: .95rem; line-height: 1.25; }
.blog-autor-cargo{ display: block; margin-top: .15rem; font-size: .82rem; color: var(--text-muted); }

/* ---------- Compartir ---------- */
.blog-compartir{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.blog-compartir a{
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  border-radius: 50%;
  color: var(--text-muted);
  transition: background var(--dur-micro) var(--ease-soft), color var(--dur-micro) var(--ease-soft);
}
.blog-compartir svg{ width: 18px; height: 18px; }
.blog-compartir a:hover{ background: var(--c-mist); color: var(--c-blue); }
.blog-compartir a:focus-visible{ outline: 2px solid var(--c-cyan); outline-offset: 2px; }
/* ⚠️ AIRE ARRIBA. Las migas quedaban a 4px del borde del header —medido: header
   hasta 116, migas en 120— porque el `section-pad` del artículo no alcanza a
   despegarlas de una barra que es fija y opaca. El cliente lo marcó como
   "demasiado alto". El ajuste va en el margen SUPERIOR de las migas y no en el
   padding del contenedor, para no mover también el sidebar. */
/* ⚠️ Y UN PISO CONTADO DESDE EL HEADER (2026-09-19). Ese ajuste se midió en
   escritorio: por debajo de ~900px el aire del artículo (`--pad-block` + este
   margen, que escalan con el ancho) no llegaba al alto del header, fijo en
   116px, y las migas quedaban medio tapadas por su vidrio en tablets y
   teléfonos. El piso usa el alto del header SIN compactar a propósito: el
   compacto cambia al hacer scroll y haría saltar el contenido. En escritorio
   gana el clamp y no cambia nada. */
.blog-migas{
  margin-top: max(clamp(1.5rem, 4vw, 2.5rem), calc(116px + 1.25rem - var(--pad-block)));
  margin-bottom: clamp(1.5rem, 4vw, 2.5rem);
  font-size: .82rem;
}
.blog-migas ol{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.blog-migas li{ display: flex; align-items: center; gap: .5rem; }
.blog-migas li + li::before{
  content: "";
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--c-line);
}
.blog-migas a{ color: var(--text-muted); }
.blog-migas a:hover{ color: var(--c-blue); }
.blog-migas [aria-current]{ color: var(--text-body); font-weight: 600; }

.blog-cabecera{ margin-bottom: clamp(1.5rem, 4vw, 2.5rem); }
/* ⚠️ EL TITULAR DEL ARTÍCULO BAJA AL NIVEL h2 DE LA ESCALA, y no es un tamaño
   inventado: es `clamp(1.9rem, 3.6vw, 2.9rem)`, el valor que el sistema ya
   define para h2, aplicado a un h1 que sigue siendo h1 por semántica.

   El motivo: la escala de h1 —clamp(2.4rem, 5.5vw, 4.6rem) a peso 800— está
   dimensionada para titulares de una o dos palabras («Equipo», «Novedades»).
   Los titulares de estas notas tienen hasta 110 caracteres y a 4.6rem ocupan
   la pantalla entera antes de que se vea una sola línea del cuerpo.

   [PENDIENTE: confirmar]. El sistema no tiene un nivel propio para titulares
   de artículo. Si se prefiere uno nuevo, va declarado arriba con el resto de
   la escala, no acá. */
.blog-cabecera h1{
  margin: .6rem 0 0;
  font-size: clamp(1.9rem, 3.6vw, 2.9rem);
  line-height: 1.15;
}
/* Fecha a la izquierda, compartir a la derecha, como en la referencia. */
.blog-meta{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem 1.2rem;
  margin: 1.2rem 0 clamp(1.8rem, 4vw, 2.5rem);
  font-size: .88rem;
  color: var(--text-muted);
}
.blog-autor{ position: relative; padding-left: 1.2rem; }
.blog-autor::before{
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 5px; height: 5px;
  margin-top: -2.5px;
  border-radius: 50%;
  background: var(--c-line);
}

.blog-portada{
  margin: 0 0 clamp(1.8rem, 5vw, 3rem);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
}
.blog-portada img{
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* Cuerpo del artículo. Los niveles son los de la escala del sistema; acá sólo
   se define el RITMO vertical, que es lo propio de un texto largo. */
.blog-cuerpo > * + *{ margin-top: 1.2em; }
.blog-cuerpo p{
  font-size: 1rem;
  line-height: 1.75;
  color: var(--text-body);
}
/* ⚠️ LOS SUBTÍTULOS DEL CUERPO BAJAN AL NIVEL h3 DE LA ESCALA. No es un tamaño
   nuevo: es `clamp(1.2rem, 1.8vw, 1.5rem)`, el que el sistema define para h3.
   El motivo es de jerarquía, no de gusto: el titular del artículo ya usa el
   nivel h2 —porque el de h1 está pensado para titulares de una o dos palabras—
   así que un subtítulo interno al MISMO nivel compite con él y el texto pierde
   escalón. Con contenido cargado se ve enseguida: los subtítulos ocupaban tres
   renglones cada uno. */
.blog-cuerpo h2{
  margin-top: 2em;
  font-size: clamp(1.2rem, 1.8vw, 1.5rem);
  line-height: 1.3;
}
.blog-cuerpo ul{ padding-left: 1.2rem; }
.blog-cuerpo li + li{ margin-top: .5rem; }
.blog-cuerpo blockquote{
  margin: 2em 0;
  padding: 1.4rem 1.6rem;
  background: var(--c-mist);
  border-left: 3px solid var(--c-blue);
  border-radius: var(--radius-sm);
}
.blog-cuerpo blockquote p{ margin: 0; font-style: italic; }
.blog-cuerpo blockquote cite{
  display: block;
  margin-top: .8rem;
  font-size: .85rem;
  font-style: normal;
  font-weight: 700;
  color: var(--c-blue);
}
.blog-cuerpo a{ color: var(--c-blue); text-decoration: underline; text-underline-offset: .18em; }

.blog-areas{
  margin-top: clamp(2rem, 5vw, 3rem);
  padding-top: clamp(1.5rem, 4vw, 2rem);
  border-top: 1px solid var(--c-line);
}
.blog-aside-titulo{
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 1rem;
}
.blog-areas ul{
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.blog-areas a{
  display: inline-block;
  padding: .45rem 1rem;
  font-size: .82rem;
  font-weight: 600;
  color: var(--c-indigo);
  background: var(--c-mist);
  border-radius: var(--radius-pill);
  transition: background var(--dur-micro) var(--ease-soft), color var(--dur-micro) var(--ease-soft);
}
.blog-areas a:hover{ background: var(--c-mist-2); color: var(--c-blue); }

.blog-volver{ margin-top: clamp(2rem, 5vw, 3rem); }

/* ⚠️ TINTA OSCURA. Era `#fff`, de cuando esta sección iba sobre el índigo; al
   pasar el listado a fondo blanco quedó blanco sobre blanco y las tarjetas se
   veían sueltas, sin nada que las presentara. El cliente lo marcó. */
/* ⚠️ EL HUECO ERA DOBLE, NO GRANDE. El artículo cierra con el `padding-bottom`
   de `section-pad` (120px) y la sección de relacionadas abre con su
   `padding-top` (otros 120): entre el final del cuerpo y el título quedaban
   240px, mientras que del título a las tarjetas hay 40. El título se leía como
   colgado en medio de la nada y no como el encabezado de lo que sigue.
   Se anula el cierre del artículo y queda UNA separación de sección, que es el
   ritmo que usa el resto del sitio. 240px → 120px. */
.blog-detalle{ padding-bottom: 0; }

.blog-otras-titulo{
  color: var(--text-body);
  text-align: center;
  margin: 0 0 clamp(1.5rem, 4vw, 2.5rem);
}

/* --------------------------------------------------------------------------
   BARRA FIJA DE LECTURA EN EL BLOG (2026-08-17)
   --------------------------------------------------------------------------
   Reusa `.perfil-barra` —el vidrio claro, la posición bajo el header, la
   transición y el momento en que aparece— y sólo cambia lo que es propio de una
   nota: en vez de un nombre y una foto, el título del artículo y las caras de
   quienes lo firman. Si se retoca el vidrio o el alto de la barra, se retoca en
   `.perfil-barra` y las dos cambian juntas.
   -------------------------------------------------------------------------- */
.blog-barra-autores{
  display: flex;
  align-items: center;
  /* Superpuestas, como una pila de caras: con dos o tres autores una fila suelta
     ocupa demasiado de una barra que mide 44px de alto. */
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  flex: none;
}
.blog-barra-autores li + li{ margin-left: -12px; }
/* El aro es el del vidrio, no blanco: sobre la barra clara un aro blanco no
   separa una cara de la siguiente. */
.blog-barra .perfil-barra-foto{ box-shadow: 0 0 0 2px var(--c-mist); }
.blog-barra-autores li:hover{ z-index: 1; }
.blog-barra-autores li{ position: relative; }
.perfil-barra-foto--vacia{ display: block; background: var(--c-mist-2); }
/* El título de una nota es largo: la barra le da el ancho que sobre y lo corta
   con puntos suspensivos, igual que hace con un nombre largo en la ficha. */
/* La cara de la barra enlaza a la ficha (2026-08-19). El <a> sólo envuelve: no
   agrega caja ni cambia el tamaño, así el diseño de la barra queda igual. */
.blog-barra-cara{ display: block; line-height: 0; cursor: pointer; }
.blog-barra-cara .perfil-barra-foto{ transition: transform var(--dur-micro) var(--ease-soft); }
.blog-barra-cara:hover .perfil-barra-foto{ transform: scale(1.08); }
.blog-barra .perfil-barra-nombre{ font-size: clamp(.85rem, 1.1vw, 1rem); }
@media (max-width: 559px){
  .blog-barra-autores li + li{ margin-left: -10px; }
}

/* ==========================================================================
   NOSOTROS — página institucional /nosotros/  (2026-08-19)
   ==========================================================================
   La genera _tools/gen_nosotros.js. Todo lo estructural sale de componentes que
   ya existían —.team-banner sin buscador, .section-pad, .section--mist,
   .section--photo + .bg-photo, .grid-split, .section-head, .eyebrow, .lede,
   [data-reveal]— y lo de acá abajo es sólo lo que la página estrena.

   ⚠️ SE ELIGIÓ EL PREFIJO `nos-` EN VEZ DE REUSAR `.area-card` Y `.ally-card`.
   Parecen calzar, pero traen comportamiento pegado: `.area-card` vive dentro del
   carrusel de #areas (flechas, de a cuatro, con su JS) y `.ally-card` dentro de
   la fila con la palabra "Global" detrás. Reusar la clase habría arrastrado ese
   JS y esos media queries a una página que no los quiere. Los TOKENS sí se
   comparten —colores, radio, sombras, easing—, que es donde importa la
   consistencia.
   ========================================================================== */

/* ==========================================================================
   EL BANNER — ⚠️ SIN NINGÚN OVERRIDE, Y ES A PROPÓSITO (2026-08-19)
   ==========================================================================
   Esta página usa `.team-banner` TAL CUAL: mismo cuerpo de titular, mismo alto,
   misma foto (`libros-pstbn.webp`) y mismo encuadre que Profesionales y
   Novedades. Lo pidió el cliente: "que tenga el mismo tamaño de la página
   profesionales y también el alto de la sección".

   ⚠️ SI VUELVE UN TITULAR LARGO, VUELVE EL PROBLEMA — Y NO ES SÓLO CUESTIÓN DE
   BAJARLE EL CUERPO. Hubo una versión con el H1 del brief de SEO («Estudio
   jurídico en Paraguay con experiencia local y alcance internacional», 73
   caracteres). Con el `max-width: 14ch` del componente daba CINCO renglones de
   397px y tres se salían del azul, encima de la foto. Lo medido entonces, por si
   hace falta:

     · El titular entra en 3 renglones con `max-width: 28ch` y
       `clamp(1.25rem, 2.5vw, 2.5rem)`. Probado en 11 anchos muestreando el píxel
       real debajo de cada renglón. 26ch/2.9vw se ve mejor pero falla a 1600x900.
     · Con eso NO alcanza: el alto sale de `clamp(320px,50vh,560px) + …`, así que
       en un viewport bajo manda el `50vh` (a 1024x700 el banner quedaba en
       539px), y como fondoazul.png va con `object-fit: cover` **al achicarse el
       banner se achica el azul**. Había que subir el piso del clamp a 440px.
     · NO sirve mover `object-position` de fondoazul.png para descubrir más azul:
       el PNG es 2819x953 y el `cover` lo escala por alto, o sea que
       verticalmente ya entra entero. Es geometría, no un número a afinar.

   La historia completa está en changelog.md (2026-08-19).
   ========================================================================== */

/* ---------- Bloques de texto ---------- */
/* Ancho de lectura acotado, el mismo criterio que el cuerpo del blog: un párrafo
   a todo el ancho del contenedor en una pantalla de 1440 son ~150 caracteres por
   renglón, y el ojo pierde el hilo al bajar de línea. */
.nos-entrada,
.nos-cierre,
.nos-compromiso > .container > .lede,
.nos-compromiso > .container > p,
.nos-alianzas > .container > .lede,
.nos-alianzas > .container > p{
  max-width: 70ch;
}
/* ⚠️ AIRE ENTRE PÁRRAFOS SEGUIDOS. El reset del sitio deja los <p> sin margen y
   cada componente pone el suyo; en los bloques que van sueltos dentro del
   `.container` —alianzas y compromiso— no había ninguno y los dos párrafos de
   entrada se leían como un solo bloque pegado. Va sobre `p + p` y no sobre todo
   `p` para no separar el primero de su <h2>, que ya tiene su propio espaciado. */
.nos-alianzas > .container > p + p,
.nos-compromiso > .container > p + p{
  margin-top: 1rem;
}
.nos-cierre{
  margin-top: clamp(1.75rem, 3vw, 2.5rem);
  color: var(--text-muted);
}
.section--photo .nos-cierre{ color: rgba(255,255,255,.78); }

/* Rótulo que presenta una lista. NO es un encabezado —no abre una sección, sólo
   introduce la lista que sigue— así que va como <p> con `id`, y la lista lo toma
   con `aria-labelledby`. Un <h3> acá ensuciaría el esquema de encabezados. */
.nos-rotulo{
  margin: clamp(2rem, 4vw, 3rem) 0 1.25rem;
  font-weight: 700;
  /* 1rem como el resto de la prosa (2026-08-19): es una frase, no un rótulo de
     componente. Lo distingue el peso 700, no el tamaño. .95rem -> 1rem. */
  font-size: 1rem;
  letter-spacing: .01em;
}
.nos-rotulo--claro{ color: rgba(255,255,255,.9); }

/* ---------- Los cuatro valores que gobiernan la página ----------
   ⚠️ SON TOKENS DE PÁGINA A PROPÓSITO: las cinco secciones tienen que verse del
   mismo sistema, y la única forma de que no se separen con el tiempo es que
   compartan el número, no que cada una repita el mismo `clamp()`. */
.page-nosotros{
  /* Alto de la caja de los rótulos de sección. Lo comparten el rótulo de
     sección y el «Publicaciones del estudio» de Experiencia: con la misma caja
     y los dos centrados dentro, los dos textos quedan a la misma altura óptica
     aunque tengan cuerpos distintos. */
  --nos-rot-alto: 1.85rem;
  /* Del rótulo al <h2>. */
  --nos-rot-gap: .85rem;
  /* Del bloque de encabezado al cuerpo. Lo usan `.section-head` en las cuatro
     secciones normales y la prosa de Experiencia, que no tiene `.section-head`
     porque su título vive en otra celda de la grilla. */
  --nos-cabeza-gap: clamp(2rem, 5vw, 3.5rem);
  /* Aire entre párrafos seguidos, en toda la página. */
  --nos-parrafo-gap: 1rem;
  /* Color de la unión hero → foto de Quiénes somos. En componentes r,g,b para
     que el degradado pueda terminar en el MISMO color con alfa 0. Ver el bloque
     «LA UNIÓN ENTRE EL HERO Y LA FOTO» más abajo: lo comparten el piso de la
     curva del banner y el arranque de la sección, y por eso no hay costura. */
  --nos-union: 35, 35, 64;
}

/* ---------- El rótulo de sección ----------
   ⚠️ ES UN COMPONENTE ÚNICO PARA LAS CINCO SECCIONES: `.nos-seccion-rotulo`, que
   el generador cuelga de la misma volanta en `encabezado()` y en `casos()`. No
   hay un tamaño para Quiénes somos y otro para Experiencia — hay un solo lugar
   donde se define, y si se toca, cambian las cinco.

   El cliente lo pidió más grande el 2026-08-20: pasó de .8rem a .95rem. Con más
   cuerpo el `letter-spacing` baja de .14em a .11em, porque el tracking de una
   versalita se percibe proporcional al cuerpo y a .14em quedaba desarmada.

   ⚠️ NINGUNA VOLANTA DEL SITIO LLEVA RAYA, NI A LA IZQUIERDA NI A LA DERECHA.
   El 2026-08-18 se sacó `.eyebrow::before` (un trazo a la izquierda) de todas;
   el 2026-08-20 esta página sumó una barrita a la DERECHA (`::after`) como marca
   de cada sección, y el 2026-09-17 el cliente pidió quitarla también: «eliminar
   la raya final de los títulos en todas las páginas». No volver a agregar
   ninguna. La clase se queda por el tamaño y por la caja (`--nos-rot-alto`),
   que es la que alinea Experiencia con «Publicaciones del estudio». */
.nos-seccion-rotulo{
  min-height: var(--nos-rot-alto);
  margin-bottom: var(--nos-rot-gap);
  font-size: .95rem;
  font-weight: 700;
  line-height: 1.45;
  letter-spacing: .11em;
}

/* ⚠️ EL `margin-top` DEL <h2> SE ANULA ACÁ Y NO ES UN CAPRICHO. El sistema lo
   pone en `.section-head h2` y en esta página el aire entre volanta y título lo
   define `--nos-rot-gap`, que también gobierna la fila 1 de Experiencia. Con
   los dos sumando, el título de las cuatro secciones normales quedaba 12px más
   abajo que el de Experiencia. */
.page-nosotros .section-head h2{ margin-top: 0; }
.page-nosotros .section-head{ margin-bottom: var(--nos-cabeza-gap); }

/* ---------- Cuerpo de texto: un solo estilo para toda la página ----------
   ⚠️ EL PATRÓN ES EL SEGUNDO PÁRRAFO DE «ALCANCE INTERNACIONAL» —«Estas
   relaciones permiten complementar…»—, que es el que señaló el cliente el
   2026-08-20: **1rem / 400 / 1.6 y el color PLENO de la sección**. Medido antes
   del cambio, la página tenía SEIS combinaciones distintas de cuerpo: 20px y
   16px conviviendo, y tres blancos (#fff, .82 y .80) más dos grises (#1c1c1c y
   --text-muted) repartidos sin criterio entre secciones.

   ⚠️ `color: inherit` ES LA PIEZA CLAVE, NO UN ATAJO. El párrafo de referencia
   no tiene color propio: hereda el `#fff` de `.section--photo`. Poniendo
   `inherit` cada párrafo toma el color pleno de SU sección —blanco sobre foto,
   la tinta del cuerpo sobre fondo claro— que es exactamente la misma regla que
   sigue el patrón. Un valor fijo obligaría a una excepción por fondo y volvería
   a abrir la puerta a los grises sueltos.

   ⚠️ ESTO NO ALCANZA A TÍTULOS, CIFRAS, RÓTULOS, NOMBRES DE PUBLICACIÓN NI
   ETIQUETAS DE LISTA. Esos tienen jerarquía propia y el cliente pidió
   explícitamente no tocarlos: la lista de selectores de abajo es la lista
   completa de lo que en esta página es «párrafo de cuerpo».

   ⚠️ `.lede` QUEDA IGUAL QUE UN PÁRRAFO NORMAL, Y ES DELIBERADO. Traía 1.25rem;
   el cliente eligió como patrón un párrafo que NO es lede, y pidió que no haya
   párrafos notablemente más grandes que otros. La jerarquía de entrada la sigue
   marcando la negrita del texto, no el cuerpo. */
.page-nosotros .nos-prosa > p,
.page-nosotros .nos-prosa > .lede,
.page-nosotros .nos-entrada,
.page-nosotros .nos-cierre,
.page-nosotros .nos-alianzas > .container > p,
.page-nosotros .nos-alianzas > .container > .lede,
.page-nosotros .nos-compromiso > .container > p,
.page-nosotros .nos-compromiso > .container > .lede,
.page-nosotros .nos-red-txt p,
.page-nosotros .nos-cta-txt{
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: normal;
  color: inherit;
}

/* Y un solo ritmo entre párrafos seguidos, en las cuatro estructuras donde los
   hay. Antes eran 1rem, 1.15rem y .75rem según el bloque. */
.page-nosotros .nos-prosa > p + p,
.page-nosotros .nos-prosa > .lede + p,
.page-nosotros .nos-alianzas > .container > p + p,
.page-nosotros .nos-compromiso > .container > p + p,
.page-nosotros .nos-red-txt p + p{
  margin-top: var(--nos-parrafo-gap);
}

/* ---------- 1 · Quiénes somos: foto velada, igual que Experiencia ----------
   ⚠️ ESTA SECCIÓN NO TIENE TRATAMIENTO PROPIO Y ESO ES EL PUNTO. El cliente
   pidió (2026-08-19) que use EXACTAMENTE el mismo velo azul que la sección del
   martillo, así que reusa `.section--photo` + `.bg-photo--indigo` tal cual: acá
   abajo no hay ni un color ni un degradado nuevo. Si algún día se retoca ese
   velo, se retoca en `.bg-photo--indigo` y las dos secciones cambian juntas.

   Lo que se fue: la banda de foto a sangre con un panel índigo montado encima
   (`.nos-intro-banda`, `.nos-intro-foto`, `.nos-panel`, `.nos-panel-txt`,
   `.nos-raya`). Eran ~130 líneas que ya no las usa ningún HTML. */

/* ---------- LA UNIÓN ENTRE EL HERO Y LA FOTO DE QUIÉNES SOMOS ----------
   Acá conviven dos pedidos que, tal como está construido el banner, se estorban:
   el hero tiene que verse EXACTAMENTE como el de Profesionales, y la foto de la
   sección siguiente tiene que empezar inmediatamente, sin ninguna franja arriba.

   ⚠️ QUÉ LO IMPIDE, MEDIDO. El piso de la curva (`.curva-piso`) es una FORMA
   DENTRO DEL BANNER que se pinta ENCIMA del fondo del propio banner. Muestreando
   el píxel real de equipo.html con la curva oculta y con la curva visible:

     · Detrás del piso hay azul de `fondoazul.png` a la izquierda y la FOTO del
       banner de la mitad hacia la derecha — nunca nada de la sección de abajo.
     · Con la curva visible, ese piso tapa todo eso y deja blanco: a 1365px el
       blanco arranca en y=430 sobre el borde izquierdo y ocupa casi los 124px de
       la banda.

   O sea que lo que hay debajo del arco es SIEMPRE banner. Sólo puede ser blanco
   (Profesionales), transparente (y entonces asoma el azul del PNG a la izquierda
   y la foto del banner a la derecha, que es peor: se ve sucio) o un color plano.
   Para que fuera la foto de la sección, esa foto tendría que pintarse por encima
   del fondo del banner, y ese fondo es justamente el que dibuja la ola azul y la
   ventana de foto que hacen legible la curva. No hay forma de recortarlo por la
   ola de manera responsive con este markup: el `clip-path` necesitaría una
   proporción fija y la banda mide `--curva-h` sobre un alto de sección variable.

   ⚠️ CÓMO SE RESUELVE: EL PISO Y EL ARRANQUE DE LA SECCIÓN COMPARTEN COLOR.
   El piso se pinta con `--nos-union` y la sección abre con un degradado que
   arranca EXACTAMENTE en ese mismo color y se abre a la foto. Como los dos lados
   del borde son el mismo color, **la costura no existe**: no hay franja, no hay
   escalón, y la foto emerge sola unos 200px más abajo. El hero de arriba del
   arco —azul, ventana de foto, ola y arco cian— no se toca ni un píxel.

   Esto es «desplazamiento interno del fondo», que es lo que el cliente autorizó
   para ajustar la unión; no es espacio en blanco ni un margen entre secciones.

   ⚠️ EL COLOR SE ELIGIÓ MIDIENDO, no a ojo: se probaron cuatro candidatos
   (#1c1c2e, #232340, #2a2b4d, #33345c) capturando la unión a 1365px. Los más
   claros dejan ver un escalón contra la foto; #232340 es el más alto que todavía
   funde sin costura, y es coherente con el primer tramo del velo de
   `.bg-photo--indigo`. Va en componentes r,g,b para que el degradado pueda
   terminar en el MISMO color con alfa 0 — con otro color el desvanecido vira.

   ⚠️ VA ACOTADO A ESTA PÁGINA. La misma curva la usan profesionales, novedades y
   las fichas, y ahí abajo sigue habiendo fondo claro: su piso sigue blanco. */
.page-nosotros .curva-piso{ fill: rgb(var(--nos-union)); }

/* El degradado va en un `::before` de la sección y no en la foto: la foto la
   mueve el parallax, y el arranque tiene que quedarse quieto contra el borde del
   banner. `z-index: 1` lo pone sobre `.bg-photo` (z-index 0) y debajo del
   `.container`, que va después en el markup y gana con el mismo z-index. */
.nos-intro::before{
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: clamp(150px, 15vw, 230px);
  z-index: 1;
  background: linear-gradient(to bottom,
              rgb(var(--nos-union)) 0%,
              rgba(var(--nos-union), 0) 100%);
  pointer-events: none;
}

/* ⚠️ Y LA SECCIÓN SUBE 1px, QUE NO ES UN AJUSTE FINO SINO UN PARCHE DE
   SUBPÍXEL. El banner mide 676,6px —alto fraccionario— y lleva `overflow:
   hidden`, así que el SVG de la curva se recorta a MITAD DE PÍXEL: esa última
   fila queda antialiaseada contra el fondo del banner y se lee como una línea
   un 25% más oscura (medido: 35,35,64 contra 26,27,48). No se puede estirar el
   SVG hacia abajo —el `overflow: hidden` lo recorta igual, ya se intentó; ver la
   nota de `.team-banner-curva`— así que se tapa desde abajo. El `z-index` queda
   muy por debajo del header (100), del buscador (120) y del WhatsApp (200). */
.page-nosotros .nos-intro{ z-index: 3; margin-top: -1px; }
/* ⚠️ Y CON ESCALADO FRACCIONARIO LA FOTO SE RECORTA 1PX ARRIBA (2026-09-19). A
   125%/150% de Windows la foto —capa compuesta por el parallax, recortada por
   `.nos-fondo`— redondea su recorte hacia afuera y pinta la fila parcial del
   borde: una línea blanca brillante (la pared clara de la sala) que además
   titilaba con el scroll. Ese píxel lo cubre el degradado `::before`, que
   arranca en el mismo color del piso de la curva. A escala 100% no cambia. */
.page-nosotros .nos-intro .bg-photo{ clip-path: inset(1px 0 0 0); }

/* ⚠️ ESTA SECCIÓN LLEVA MENOS RELLENO ARRIBA QUE LAS OTRAS CUATRO, Y ES PARA
   QUE SE VEA IGUAL, NO DISTINTO. El hero termina VISUALMENTE en el arco cian,
   pero su caja sigue 54px más abajo (medido a 1440): ese sobrante es el resto
   de la curva. Con el `--pad-block` completo encima, el aire hasta el rótulo se
   leía como 190px contra los 136px de las demás secciones — el mismo relleno,
   apilado sobre un pedazo de banner.

   ⚠️ EL 0.42 NO ES UN NÚMERO A OJO: es la fracción de `--curva-h` que queda por
   debajo del arco. El borde inferior del arco toca su punto más bajo en y≈110
   del viewBox de 190, así que sobra (190−110)/190 = 0,42. Al descontarlo, el
   aire medido DESDE EL ARCO queda igual que el de las otras cuatro secciones en
   todos los anchos, y sigue el clamp del sistema en vez de estrenar un valor
   propio que habría que recalibrar en cada breakpoint.

   ⚠️ SI SE TOCA EL `d` DEL ARCO HAY QUE REVISAR ESTE 0.42. Sale de la curva
   real, no de una proporción arbitraria. */
.page-nosotros .nos-intro{
  padding-top: calc(var(--pad-block) - var(--curva-h) * .42);
  /* Abajo, el 40% del relleno del sistema con piso de 2.5rem (2026-09-19,
     dos pedidos del cliente seguidos): bajo los rótulos de las cifras quedaban
     ~140px hasta el final de la sección (120 de relleno + un renglón que el
     rótulo reserva por si se parte); primero bajó a ~96 y después, «reducí aún
     más el espacio que hay al final», a ~48 a 1440 (con el renglón reservado
     fuera desde 1000px, ver `.nos-cifra-rotulo`). En móvil queda ~43. */
  padding-bottom: max(2.5rem, calc(var(--pad-block) * .4));
}

/* ⚠️ LA FOTO DE FONDO SE DIBUJA MÁS ALTA QUE LA SECCIÓN A PROPÓSITO: ES LO QUE
   HACE POSIBLE EL PARALLAX. `.bg-photo img` mide 100% del alto, y moverla
   descubriría el borde; acá mide 118% con -9% arriba, o sea 9% de sobrante por
   lado. js/nosotros.js la desplaza ±6% de SU alto, que es ±7,1% del alto de la
   sección: entra en ese 9% con margen.
   ⚠️ SI SE TOCA UNO DE LOS DOS NÚMEROS HAY QUE TOCAR EL OTRO (y el ±6 del JS).
   Sin JS, o con `prefers-reduced-motion`, la foto queda quieta y el sobrante
   simplemente no se ve. */
.nos-fondo{ overflow: hidden; }
/* ⚠️ EL DESPLAZAMIENTO VA EN `top`, NO EN `margin-top`, Y NO ES INTERCAMBIABLE.
   Un `margin` en % se resuelve contra el **ancho** del contenedor: a 1440x816
   ese -9% daban -129,6px en vez de -73,4px, y el sobrante quedaba 133px arriba
   contra 14px abajo. Con ±6% de recorrido el borde de abajo se destapaba. En
   `top`, con la caja posicionada, el % se resuelve contra el **alto** y el
   sobrante queda repartido en partes iguales. Medido después del cambio. */
.nos-fondo img{ position: relative; top: -9%; height: 118%; }

/* La prosa de las secciones que no van sueltas dentro del `.container`. Mismo
   criterio de ancho de lectura que `.nos-entrada`. */
.nos-prosa{ max-width: 70ch; }
.nos-prosa > p{ margin: 0; }
.nos-prosa > p + p{ margin-top: 1rem; }
.nos-prosa > .lede + p{ margin-top: 1.15rem; }

/* ⚠️ LAS CIFRAS NACIERON PARA FONDO CLARO Y AHORA VAN SOBRE EL VELO ÍNDIGO.
   El rótulo usa `--text-muted` (tinta oscura) y el número el degradado
   azul→cian de marca: sobre el índigo el rótulo desaparece y el arranque del
   número queda casi del color del fondo. Se repintan SÓLO cuando la sección va
   sobre foto —le ganan por especificidad (0,2,0 contra 0,1,0)— así el resto del
   sitio no se entera. */
.section--photo .nos-cifras{ border-top-color: rgba(255, 255, 255, .28); }
/* ⚠️ Y EL NÚMERO VA EN BLANCO LISO (2026-09-18). Hasta entonces era un degradado
   blanco→cian; el cliente pidió en reunión «números dejar en color blanco».
   Hay que anular el recorte al texto, no sólo el color: con `background-clip:
   text` vivo y `color: transparent` heredado, el número desaparece. */
.section--photo .nos-cifra-num{
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: #fff;
}
.section--photo .nos-cifra-rotulo{ color: rgba(255, 255, 255, .75); }

/* ---------- Las cifras ----------
   ⚠️ `tabular-nums` NO ES OPCIONAL: sin él los dígitos tienen anchos distintos y
   el número TIEMBLA mientras el contador sube.

   ⚠️ LA ALINEACIÓN LA HACE LA GRILLA, NO UN MARGEN POR BLOQUE. Cuatro pistas
   `minmax(0, 1fr)` —iguales y que no se desbordan aunque el rótulo sea largo—,
   un solo `gap`, `align-items: start` para que los cuatro apoyen arriba, y cada
   bloque es a su vez una grilla de dos filas con su propio `row-gap`. De ahí
   salen, sin tocar nada más: las cuatro cifras en la misma línea, los cuatro
   rótulos empezando a la misma altura y la misma distancia cifra→rótulo en los
   cuatro.

   ⚠️ EL RÓTULO RESERVA DOS RENGLONES (`min-height`), Y ESO ES LO QUE MANTIENE LA
   FILA PAREJA. «Redes internacionales» y «Años de trayectoria» se parten en dos
   en cuanto la columna se angosta y «Profesionales» nunca; sin la reserva, los
   cuatro bloques miden distinto y la fila se ve desarmada aunque las cifras
   estén alineadas. Va en `em` para que siga al cuerpo del propio rótulo. */
/* ⚠️ MENOS AIRE ARRIBA DESDE EL 2026-09-19. El cliente marcó «mucho espacio
   entre donde termina [el texto] y empiezan los números». Eran 113px a 1440
   (72 hasta el filete + 41 hasta el número); ahora ~72 (44 + 28), y en móvil de
   77 a ~52. El aire de abajo se recortó en el padding de la sección
   (`.page-nosotros .nos-intro`). */
.nos-cifras{
  list-style: none;
  margin: clamp(2rem, 3.6vw, 2.75rem) 0 0;
  padding: clamp(1.25rem, 2vw, 1.75rem) 0 0;
  border-top: 1px solid var(--c-line);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.75rem, 4vw, 2.5rem);
  align-items: start;
  text-align: center;
}
@media (min-width: 760px){
  .nos-cifras{ grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.nos-cifra{
  display: grid;
  grid-template-rows: auto auto;
  row-gap: .55rem;
  justify-items: center;
}
.nos-cifra-num{
  font-size: clamp(2.1rem, 4.5vw, 3.2rem);
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  background: var(--gradient-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.nos-cifra-rotulo{
  min-height: calc(2 * 1.6em);
  font-size: .82rem;
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
/* ⚠️ DESDE 1000PX LA RESERVA DE DOS RENGLONES SOBRA (2026-09-19): ahí los
   cuatro rótulos entran siempre en uno (medido de 1000 a 1920) y el segundo
   renglón vacío sumaba 24px de aire bajo las cifras, que el cliente pidió
   reducir. Por debajo se mantiene: «Años de trayectoria» y «Redes
   internacionales» se parten y la reserva es la que empareja la fila. */
@media (min-width: 1000px){
  .nos-cifra-rotulo{ min-height: 0; }
}
/* ---------- 2 · Áreas de práctica ---------- */
/* `auto-fit` y no un número fijo de columnas: son quince, y con columnas fijas
   la última fila queda coja en la mitad de los anchos. */
.nos-areas{
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .75rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
}
/* ⚠️ EL CONTENIDO VA CENTRADO EN ALTO (2026-09-17, pedido del cliente: «todos
   los ítems deben estar en el medio del cuadro»). Las cajas de una misma fila
   miden lo que la más alta, y con el contenido arriba las de un renglón se
   veían corridas hacia arriba. GRID Y NO FLEX CON `align-items: center`: así el
   número queda en la línea de base del PRIMER renglón del texto aunque el texto
   ocupe dos o tres (`baseline` entre las dos celdas) y lo que se centra es el
   bloque entero (`align-content`). */
/* ⚠️ `align-items: center`, NO `baseline` (2026-09-18, pedido del cliente: «los
   números deben estar en el medio»). Con baseline el número quedaba pegado al
   primer renglón y en las áreas de dos o tres líneas se veía arriba. */
.nos-area{
  display: grid;
  grid-template-columns: auto 1fr;
  align-content: center;
  align-items: center;
  column-gap: .9rem;
  padding: 1rem 1.15rem;
  background: #fff;
  border: 1px solid var(--c-line);
  border-radius: var(--radius-sm);
  transition: transform .35s var(--ease-soft), border-color .35s var(--ease-soft),
              box-shadow .35s var(--ease-soft);
}
.nos-area:hover{
  transform: translateY(-3px);
  border-color: var(--c-blue);
  box-shadow: var(--shadow-soft);
}
.nos-area-num{
  flex: none;
  font-size: .78rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--c-blue);
}
.nos-area-txt{ font-weight: 600; line-height: 1.4; }

/* ---------- 3 · Experiencia: texto + publicaciones en dos columnas ----------
   Reemplaza al split con foto enmarcada. La foto lateral (`biblioteca.webp`) la
   pidió fuera el cliente (2026-08-19) y con ella se fueron `.nos-split-txt`,
   `.nos-foto` y `.nos-foto--marco`, que ya no las usa ningún HTML.

   ⚠️ CUATRO CELDAS EN UNA GRILLA, NO DOS COLUMNAS APILADAS. Los cuatro hijos son
   hermanos directos —rótulo izq., rótulo der., contenido izq., contenido der.—
   así que los dos rótulos comparten la FILA 1 y los dos contenidos la FILA 2.
   Las dos alineaciones que pidió el cliente salen de ahí y no de un margen:

       «Experiencia»            ─── misma fila que ───  «Publicaciones del estudio»
       el <h2>                  ─── misma fila que ───  la primera caja

   Si mañana el rótulo de la derecha pasa a dos renglones, la fila 1 crece y los
   dos contenidos bajan JUNTOS. Con un div por columna eso no pasa: cada una
   corre por su cuenta y hay que recalibrar a mano.

   ⚠️ EL REPARTO ES ~66/34 Y NO ES CAPRICHO: a la izquierda van tres párrafos y a
   la derecha tres cajas de dos renglones. A 50/50 las cajas quedaban enormes y
   el texto con renglones cortos; a 75/25 los títulos de las publicaciones se
   partían en tres.

   ⚠️ EL CORTE ES 1000px Y NO EL 900px HABITUAL DEL SISTEMA. Entre 900 y 1000 la
   columna derecha baja de 21rem y «Temas de Derecho Tributario» se parte feo;
   por eso el `minmax(21rem, 1fr)` y por eso el corte más alto. */
.nos-exp{
  display: grid;
  row-gap: var(--nos-rot-gap);
  column-gap: clamp(2.5rem, 5vw, 4rem);
}
@media (min-width: 1000px){
  .nos-exp{
    grid-template-columns: minmax(0, 1.95fr) minmax(21rem, 1fr);
    align-items: start;
  }
}
/* ⚠️ EN UNA SOLA COLUMNA EL `row-gap` NO ALCANZA. Ahí las cuatro celdas se
   apilan y ese gap —pensado para separar el rótulo de su propio contenido—
   quedaría también entre la prosa de la izquierda y el rótulo de la derecha,
   que son dos bloques distintos y necesitan respirar. */
/* ⚠️ Y EL RÓTULO «Publicaciones del estudio» VA JUSTO ANTES DE SUS TARJETAS
   (2026-09-19). En el HTML está entre la volanta y el <h2> —así comparte fila
   con ella en dos columnas— y al apilar en ese orden parecía el subtítulo de la
   sección, a ~480px de las tarjetas que presenta. `order` lo lleva al lugar
   correcto. El selector es más específico a propósito: esta regla existía pero
   no hacía nada, porque el `margin: 0` de `.nos-exp-rotulo`, más abajo y con la
   misma especificidad, la pisaba. */
@media (max-width: 999.98px){
  .nos-exp > .nos-exp-rotulo{ order: 1; margin-top: clamp(1.75rem, 4vw, 2.5rem); }
  .nos-exp > .nos-pubs{ order: 2; }
}

/* El rótulo de la derecha comparte caja con el de la izquierda —el mismo
   `--nos-rot-alto`, los dos centrados dentro— y por eso los dos textos quedan a
   la misma altura óptica aunque tengan cuerpos distintos. Sin la caja común
   habría que compensar la diferencia de interlineados con un margen, que es
   justo lo que se quiere evitar. */
.nos-exp-rotulo{
  display: flex;
  align-items: center;
  min-height: var(--nos-rot-alto);
  margin: 0;
}
.nos-exp-txt > h2{ margin-top: 0; }
/* El mismo aire encabezado→cuerpo que `.section-head` en las otras cuatro
   secciones, desde el mismo token. */
.nos-exp-txt > .nos-prosa{ margin-top: var(--nos-cabeza-gap); }

/* ---------- 3 · Publicaciones ---------- */
/* ⚠️ APILADAS, DEL MISMO ALTO Y SOBRE EL MISMO EJE IZQUIERDO. Antes eran tres
   cajas en fila a lo ancho de la sección (`auto-fit`); ahora viven en una
   columna de ~1/3, así que van una debajo de otra. Una sola pista de `1fr` les
   da el mismo ancho y el mismo borde izquierdo, y `grid-auto-rows: 1fr` las
   iguala en alto: los tres títulos tienen largos distintos y sin eso la primera
   queda más alta que las otras dos. */
.nos-pubs{
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  grid-auto-rows: 1fr;
  gap: 1rem;
}
/* Vidrio esmerilado sobre la foto: el mismo tratamiento que las tarjetas de
   novedades en el home. `backdrop-filter` es un extra —donde no exista, el
   fondo semitransparente ya da el contraste que hace falta. */
.nos-pub{
  display: flex;
  flex-direction: column;
  gap: .4rem;
  padding: 1.35rem 1.5rem;
  border-radius: var(--radius-md);
  background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.22);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.nos-pub-titulo{ font-weight: 700; font-size: 1.05rem; line-height: 1.35; color: #fff; }
.nos-pub-nota{ font-size: .85rem; line-height: 1.5; color: rgba(255,255,255,.72); }

/* ⚠️ HOY NINGUNA PUBLICACIÓN TIENE URL Y POR ESO NO HAY NINGÚN `.nos-pub-link`
   EN EL HTML. El cliente nunca pasó los destinos y no se inventan. Esta regla
   queda lista para cuando se carguen: el generador envuelve el contenido en un
   <a> que ocupa la caja entera, sin cambiar nada del layout. */
.nos-pub-link{
  display: flex;
  flex-direction: column;
  gap: .4rem;
  color: inherit;
  text-decoration: none;
}
.nos-pub-link:hover .nos-pub-titulo,
.nos-pub-link:focus-visible .nos-pub-titulo{
  color: var(--c-cyan);
  text-decoration: underline;
  text-underline-offset: .18em;
}
/* ---------- 4 · Alianzas ---------- */
.nos-redes{
  list-style: none;
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 0;
  padding: 0;
  display: grid;
  gap: clamp(1rem, 2.5vw, 1.5rem);
}
.nos-red{
  display: grid;
  gap: clamp(1.25rem, 3vw, 2rem);
  align-items: start;
  padding: clamp(1.5rem, 3vw, 2rem);
  border-radius: var(--radius-md);
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.18);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
@media (min-width: 820px){
  .nos-red{ grid-template-columns: 15rem 1fr; align-items: center; }
}
.nos-red-marca{
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .75rem;
  text-decoration: none;
  color: inherit;
}
/* ⚠️ LA PLACA BLANCA DETRÁS DEL LOGO NO ES DECORACIÓN. Es el mismo problema que
   ya resolvió #alianzas en el home: los cinco WebP tienen tinta oscura —Club de
   Abogados e Iconekta son prácticamente texto negro— y sobre el fondo oscuro de
   esta sección desaparecen. La solución NO es aclarar la tarjeta hasta volverla
   un panel opaco: es darle al logo su propia placa. Antes de tocar esto, leer la
   nota de `.ally-card`. */
.nos-red-logo{
  width: 100%;
  padding: 1rem 1.25rem;
  background: #fff;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
}
.nos-red-logo img{
  max-width: 100%;
  width: auto;
  height: auto;
  max-height: 3.25rem;
  object-fit: contain;
}
.nos-red-ir{
  display: inline-flex;
  align-items: center;
  gap: .4em;
  font-size: .82rem;
  font-weight: 700;
  color: var(--c-cyan);
}
.nos-red-ir svg{ width: 1em; height: 1em; transition: transform .3s var(--ease-soft); }
.nos-red-marca:hover .nos-red-ir svg{ transform: translateX(4px); }
.nos-red-nombre{ margin: 0 0 .75rem; color: #fff; font-size: clamp(1.15rem, 2vw, 1.4rem); }
/* El nombre de la red enlaza a su sitio (2026-08-19). Hereda el color del <h3>
   y sólo se marca al pasar el cursor: subrayarlo siempre metería una línea en
   cada tarjeta y el bloque se llenaría de rayas. */
.nos-red-nombre a{ color: inherit; text-decoration: none; transition: color var(--dur-micro) var(--ease-soft); }
.nos-red-nombre a:hover{ color: var(--c-cyan); text-decoration: underline; text-underline-offset: .18em; }
.nos-red-txt p{ color: rgba(255,255,255,.8); }
.nos-red-txt p + p{ margin-top: .75rem; }

/* ---------- 5 · Compromiso ---------- */
/* ⚠️ DOS COLUMNAS, NO `auto-fit` LIBRE. Con 20rem de mínimo entraban TRES
   columnas en escritorio y las organizaciones son DIEZ: la última quedaba sola
   en su fila, con dos huecos al lado. Con dos columnas dan 5 y 5, que además le
   viene mejor a nombres largos como «Fundación Paraguaya de Cooperación y
   Desarrollo». Si algún día son nueve o doce, revisar este número. */
.nos-orgs{
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .75rem;
  grid-template-columns: 1fr;
}
@media (min-width: 780px){
  .nos-orgs{ grid-template-columns: repeat(2, 1fr); }
}
/* La barra de color a la izquierda es el único adorno de la lista, y usa el
   degradado de marca para que las diez se lean como un conjunto y no como diez
   ítems sueltos.
   ⚠️ DESDE EL 2026-09-18 CADA TARJETA LLEVA EL LOGO («en las tarjetitas colocar
   los logos»): una placa blanca de medida FIJA a la izquierda y el nombre al
   lado. La placa es fija para que los diez nombres arranquen en la misma
   vertical aunque los logos vayan de cuadrados (GBC, CAPACHI) a muy apaisados
   (Cámara Paraguay Brasil, 5:1); el logo se ajusta ADENTRO con `object-fit:
   contain`. Blanca pura porque dos logos traen fondo blanco opaco (ver
   _tools/fetch_organizaciones.py) y sobre el `--c-mist` se les vería el
   recuadro. */
.nos-org{
  position: relative;
  font-weight: 600;
  line-height: 1.45;
  background: var(--c-mist);
  border-radius: var(--radius-sm);
  transition: transform .35s var(--ease-soft), box-shadow .35s var(--ease-soft);
}
/* ⚠️ LA TARJETA ENTERA ES EL ENLACE (2026-09-19): logo y nombre llevan a la web
   de la organización (ver `url` en COMPROMISO, _tools/gen_nosotros.js). La
   grilla y el relleno viven en el <a> para que toda la superficie sea
   clicable. El marcado al pasar el mouse es el de las tarjetas de áreas de esta
   misma página: sube 3px, sombra suave y el nombre en azul. */
.nos-org-link{
  display: grid;
  grid-template-columns: clamp(6.5rem, 22vw, 8.5rem) minmax(0, 1fr);
  align-items: center;
  gap: 1rem;
  padding: .7rem 1rem .7rem 1.35rem;
  color: inherit;
  text-decoration: none;
  border-radius: inherit;
}
.nos-org:hover{ transform: translateY(-3px); box-shadow: var(--shadow-soft); }
.nos-org-link:hover .nos-org-nombre,
.nos-org-link:focus-visible .nos-org-nombre{ color: var(--c-blue); }
.nos-org-link:focus-visible{ outline: 2px solid var(--c-blue); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce){
  .nos-org{ transition: none; }
  .nos-org:hover{ transform: none; }
}
.nos-org-logo{
  display: flex;
  align-items: center;
  justify-content: center;
  height: 4rem;
  padding: .5rem .65rem;
  background: #fff;
  border-radius: var(--radius-sm);
  box-shadow: inset 0 0 0 1px var(--c-line);
}
.nos-org-logo img{
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.nos-org::before{
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  background: var(--gradient-brand);
}

/* ---------- 1b · Socios fundadores (2026-09-18) ----------
   Pedido del cliente: «agregar Guillermo y Tellechea con info conmemorativa
   breve» y «estarán en Nosotros, con páginas internas conmemorativas, ya que
   es póstumo». Los textos están en FUNDADORES, en _tools/gen_nosotros.js.
   ⚠️ LA FOTO VA EN BLANCO Y NEGRO, Y ES POR EL TONO, NO POR ESTÉTICA: es un
   homenaje. Son los mismos recortes (fondo transparente) que usaba el
   recorrido del equipo; van sobre un gris neutro, apoyados abajo, como en las
   fichas. Tarjeta blanca sobre `section--mist`, igual que el resto del sitio. */
.nos-fund-lista{
  list-style: none;
  margin: clamp(1.75rem, 3.5vw, 2.5rem) 0 0;
  padding: 0;
  display: grid;
  gap: clamp(1.25rem, 3vw, 2rem);
  grid-template-columns: 1fr;
}
/* ⚠️ DOS COLUMNAS RECIÉN DESDE 1200PX (2026-09-19; antes, 900). Entre 900 y
   1199 —monitores 4:3 de 1024 y 1152, tablets en horizontal— la celda de la
   foto quedaba de ~146px y la tarjeta alta: la figura se veía chica, apoyada
   abajo, con media celda gris vacía encima. En una columna vuelve a llenarla;
   el ancho se acota para que el texto no quede en renglones kilométricos. */
@media (max-width: 1199.98px){
  .nos-fund-lista{ max-width: 52rem; }
}
@media (min-width: 1200px){
  .nos-fund-lista{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.nos-fund{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  background: #fff;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}
@media (min-width: 560px){
  .nos-fund{ grid-template-columns: clamp(9rem, 32%, 13rem) minmax(0, 1fr); }
}
.nos-fund-foto,
.nos-hom-foto{
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: linear-gradient(180deg, #eceef3 0%, #d9dce5 100%);
}
.nos-fund-foto{ aspect-ratio: 4 / 3; }
@media (min-width: 560px){
  .nos-fund-foto{ aspect-ratio: auto; min-height: 100%; }
}
.nos-fund-foto img,
.nos-hom-foto img{
  display: block;
  width: auto;
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  object-fit: contain;
  object-position: center bottom;
  filter: grayscale(1);
}
@media (min-width: 560px){
  /* La tarjeta la define el texto; la foto llena su celda sin estirarla. */
  .nos-fund-foto{ position: relative; }
  /* Centrado con `left/right: 0` + márgenes automáticos y no con `transform`:
     el revelado de la página anima transform en los hijos del grupo. */
  .nos-fund-foto img{ position: absolute; bottom: 0; left: 0; right: 0; margin-inline: auto; height: 86%; }
}
.nos-fund-txt{
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  display: flex;
  flex-direction: column;
  gap: .6rem;
}
.nos-fund-nombre{ margin: 0; font-size: clamp(1.15rem, 1.8vw, 1.35rem); line-height: 1.3; }
.nos-fund-nombre a{ color: inherit; text-decoration: none; }
.nos-fund-nombre a:hover{ color: var(--c-blue); text-decoration: underline; text-underline-offset: .18em; }
.nos-fund-anios,
.nos-hom .nos-seccion-rotulo{
  margin: 0;
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.page-nosotros .nos-fund-txt > p:not(.nos-fund-anios){
  margin: 0;
  font-size: 1rem;
  line-height: 1.6;
  color: inherit;
}
.nos-fund-ir{ margin-top: auto; padding-top: .4rem; align-self: flex-start; }

/* ---------- Página conmemorativa: nosotros/<fundador>.html ----------
   Una sola sección: la foto y la semblanza. El banner es el de Nosotros; lo
   único distinto es el piso de su curva, que acá es blanco porque abajo sigue
   una sección clara y no la foto de «Quiénes somos» (ver `--nos-union`). */
.page-homenaje .curva-piso{ fill: var(--bg-body); }
/* ⚠️ EL TÍTULO SE ACOTA TAMBIÉN POR EL ALTO (2026-09-19). El nombre ocupa dos
   renglones y la franja azul del banner mide según el ALTO de la ventana,
   mientras el titular escala con el ANCHO: en ventanas bajas (1366x768,
   1280x720, 1024x768) el segundo renglón quedaba cortado por la diagonal, mitad
   sobre el azul y mitad sobre la foto. Con el tope en vh queda entero sobre el
   azul; en las ventanas donde ya estaba bien (1920x1080, 1280x1024, tablets,
   móvil) no cambia. El tramo de 901–1100 lleva su propio tope porque ahí el
   titular arranca más abajo. */
.page-homenaje .team-banner h1{ font-size: clamp(2.4rem, min(5.5vw, 7vh), 4.6rem); }
@media (min-width: 901px) and (max-width: 1100px){
  .page-homenaje .team-banner h1{ font-size: clamp(2rem, min(5.5vw, 5.2vh), 4.6rem); }
}
/* El mismo parche de subpíxel que `.page-nosotros .nos-intro` (ver ahí): el
   banner tiene alto fraccionario y su última fila se lee como una línea gris
   sobre el blanco. La sección sube 1px y la tapa. */
.page-homenaje .nos-homenaje{ position: relative; z-index: 3; margin-top: -1px; background: var(--bg-body); }
.nos-hom{
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 860px){
  .nos-hom{ grid-template-columns: minmax(0, 5fr) minmax(0, 8fr); }
  .nos-hom-foto{ position: sticky; top: 110px; }
}
.nos-hom-foto{
  aspect-ratio: 4 / 5;
  max-width: 26rem;
  border-radius: var(--radius-md);
  overflow: hidden;
}
.nos-hom h2{ margin: 0 0 var(--nos-rot-gap); }
.nos-hom .nos-seccion-rotulo{ min-height: 0; }
.nos-hom-subt{
  margin: clamp(2rem, 4vw, 2.75rem) 0 .85rem;
  font-size: clamp(1.1rem, 1.6vw, 1.25rem);
}
.nos-hom-lista{
  margin: 0;
  padding-left: 1.2rem;
  display: grid;
  gap: .45rem;
  line-height: 1.55;
}
.nos-hom-lista li::marker{ color: var(--c-blue); }
.nos-hom-volver{ margin-top: clamp(2rem, 4vw, 3rem); }

/* ---------- 6 · Cierre ---------- */
.nos-cta > .container{ text-align: center; }
.nos-cta-tit{ margin: 0; }
.nos-cta-txt{ margin: 1rem auto 0; max-width: 52ch; color: var(--text-muted); }
.nos-cta-btns{
  margin-top: clamp(1.75rem, 3vw, 2.5rem);
  display: flex;
  flex-wrap: wrap;
  gap: .9rem;
  justify-content: center;
}
