/* DB Project — chrome compartido por las cinco páginas: barra de navegación,
   hilo conductor (línea vertical en desktop, barra de progreso en mobile) y
   footer. Nada específico de una página vive acá.

   Navbar portado de "Resizable Navbar" (db-project-biblioteca,
   references/navegacion.md): ancho normal arriba de todo, compactado + blur al
   pasar los 100px de scroll. Acá el umbral lo detecta un sentinel con
   IntersectionObserver (js/site.js), no un handler de scroll.

   Hilo conductor portado de "Tracing Beam" + "Timeline" (references/scroll.md):
   línea vertical al costado con un relleno que la recorre siguiendo el scroll. */

/* Las cinco páginas declaran viewport-fit=cover, así que el contenido llega
   hasta los bordes físicos de la pantalla. Todo lo que está fijo tiene que
   descontar el recorte: sin esto, en un iPhone con notch la píldora queda
   parcialmente debajo de la barra de estado, y en horizontal se mete abajo del
   recorte lateral. Los insets valen 0 en cualquier pantalla sin recorte, así
   que no cambian nada en el resto de los dispositivos. */
#site-nav {
  position: fixed;
  top: calc(var(--space-3) + env(safe-area-inset-top, 0px));
  left: 0;
  right: 0;
  z-index: var(--z-nav);
  display: flex;
  justify-content: center;
  padding-left: max(var(--container-pad), env(safe-area-inset-left, 0px));
  padding-right: max(var(--container-pad), env(safe-area-inset-right, 0px));
  pointer-events: none; /* solo la píldora recibe clicks */
}

/* ── El velo del tope ────────────────────────────────────────────────────────
   La píldora flota y su radio es 999px: sus dos puntas son semicírculos, así
   que arriba y abajo quedan huecos triangulares sin vidrio. Una línea de título
   que scrollea por ahí no pasa "detrás de la barra": se lee CORTADA, con las
   puntas asomando por los costados. Y a 1440 pasa algo peor: el titular de 96px
   queda seccionado a media palabra, entero a la izquierda de la píldora y
   cortado donde la píldora está.

   La versión anterior lo atacaba con tres efectos encima: un gradiente al 82%,
   un backdrop-filter de 6px y una máscara para que no terminara en borde recto.
   Seguía sin alcanzar —a 82% un blanco de 96px se lee igual— y el
   backdrop-filter es una capa de composición recalculada en cada frame de
   scroll, en un sitio cuyo problema medido es el hilo principal.

   Ahora es UNA cosa: grafito pleno a la altura de la barra, que se desvanece
   apenas debajo. Tapa de verdad, no cuesta nada por frame, y no hay máscara que
   mantener. */
#site-nav::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: calc(-1 * (var(--space-3) + env(safe-area-inset-top, 0px)));
  /* La banda opaca tiene que pasar el BORDE INFERIOR DE LA PÍLDORA antes de
     empezar a desvanecerse. Con el corte al 68% el degradado arrancaba a los
     88px y la píldora termina a los 88-93: las letras se leían justo en el
     tramo de desvanecido. Verificado pintando el velo de magenta: tapa bien,
     sólo empezaba a irse demasiado pronto. */
  height: calc(100% + var(--space-3) + env(safe-area-inset-top, 0px) + var(--space-6));
  background: linear-gradient(to bottom,
    var(--db-grafito) 0,
    var(--db-grafito) 74%,
    transparent 100%);
  pointer-events: none;
}


.nav__pill {
  pointer-events: auto;
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-1) var(--space-1) var(--space-1) var(--space-3);
  border-radius: 999px;
  transition: gap 0.35s cubic-bezier(0.22, 1, 0.36, 1),
              padding 0.35s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
  /* La barra es el único elemento que existe igual en las cinco páginas. Con un
     view-transition-name propio, el navegador la trata como el MISMO objeto al
     navegar y la interpola en vez de destruirla y reconstruirla: por eso deja
     de "saltar" entre Inicio, Servicios, Proceso y Proyectos. El sitio ya
     declara @view-transition en css/base.css; esto le dice qué continuar. */
  view-transition-name: db-barra;
}

/* El vidrio de la píldora es una capa aparte, no el fondo de .nav__pill.
   Dos razones, las dos concretas:
   1. En el Inicio la barra se materializa al scrollear. Si el fade fuera sobre
      .nav__pill, el logo que viaja adentro heredaría opacidad 0 y no se vería
      durante todo el viaje — que es justo el efecto principal de la página.
   2. backdrop-filter crea un contexto de apilado y un bloque contenedor; con
      el filtro en una capa hija, el subárbol que anima GSAP queda limpio. */
.nav__glass {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  /* OPACO. Tercer intento sobre lo mismo: 72% se leía sucio, se subió a 88% y
     el H1 del Inicio SEGUÍA leyéndose a través. Medido con sonda: el solape
     arranca en scrollY=100 a 1440px y en scrollY=140 a 375px, y dura hasta 700
     y 980 respectivamente — o sea toda la ventana en la que el titular de 96px
     pasa por detrás de la barra. Un blur de 14px no tapa tipografía de ese
     tamaño; ningún porcentaje intermedio lo iba a arreglar.
     De paso se va el backdrop-filter: una capa de composición recalculada en
     cada frame de scroll, en un sitio cuyo problema medido es el hilo
     principal. Grafito pleno hace el mismo trabajo por cero. */
  background: var(--db-grafito);
  border: 1px solid color-mix(in srgb, var(--db-blanco) 12%, transparent);
  transition: background-color 0.35s ease;
  pointer-events: none;
}
.nav__pill > *:not(.nav__glass) { position: relative; }

/* Compactado: la píldora baja de alto y se achica entera — el logo incluido,
   porque escala con ella. Se escala la píldora en vez de tocar el alto del logo
   a propósito: en el Inicio ese logo lo controla GSAP Flip, y cambiarle el alto
   por CSS le movería el piso a la medición de Flip a mitad del viaje. */
#site-nav.is-compact .nav__pill {
  gap: var(--space-2);
  padding: 2px 2px 2px var(--space-2);
  transform: scale(0.92);
}

/* El slot es el destino del logo cuando viaja desde el hero (GSAP Flip,
   js/home.js). En las otras cuatro páginas ya nace con el logo adentro. */
.nav__logo-slot {
  display: flex;
  align-items: center;
  min-width: 0;
}
/* El área táctil del logo se extiende con un ::after, no agrandando su caja:
   en el Inicio esta <a> es el objetivo de GSAP Flip, y cambiarle la caja le
   movería el piso a la medición del viaje. El pseudo-elemento no participa del
   layout, así que Flip mide exactamente lo mismo que antes.
   (js/home.js le saca el overflow:clip de la entrada cuando esta termina — con
   el clip puesto, este ::after quedaría recortado y el área no existiría.) */
.nav__logo {
  position: relative;
  display: block;
  line-height: 0;
}
.nav__logo::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  /* 48 y no 44, por lo mismo que .nav__links a: la barra compacta escala a 0.92
     y el objetivo que importa es el que termina en pantalla. 44 x 0,92 = 40,5px,
     por debajo del mínimo — medido con elementFromPoint y daba 41. 48 x 0,92 =
     44,2px, que sí cumple con la barra compactada, que es como pasa la mayor
     parte del tiempo. */
  height: 48px;
  transform: translateY(-50%);
}
.nav__logo img { height: 28px; width: auto; }

.nav__links {
  display: none;
  position: relative;
  /* El gap baja de 24 a 16 porque cada link ahora suma 7px de padding a cada
     lado: el espacio visible entre textos queda igual que antes. */
  gap: var(--space-2);
}

/* Indicador de página activa. Un solo elemento que se desliza: js/nav.js lo
   mide contra el link activo y lo mueve con translateX + scaleX, nunca con
   left/width — esas dos disparan recálculo de layout en cada frame, y esto se
   anima mientras la barra está fija sobre contenido que scrollea. */
.nav__indicador {
  position: absolute;
  left: 0;
  bottom: 6px;
  width: 1px;
  height: 2px;
  border-radius: 2px;
  background: var(--db-acento);
  transform-origin: left center;
  opacity: 0;
  pointer-events: none;
}
/* 48px, no 44: la barra compacta escala a 0.92, y el objetivo táctil que
   importa es el que termina en pantalla, no el nominal. 44 x 0.92 = 40,5px, por
   debajo del mínimo. 48 x 0.92 = 44,2px, que sí cumple con la barra compactada,
   que es como pasa la mayor parte del tiempo.
   El padding lateral es por lo mismo: "Inicio" medía 34px de ancho. */
.nav__links a {
  color: var(--db-texto-secundario-sobre-oscuro);
  text-decoration: none;
  font-size: var(--db-fs-small);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding-inline: 7px;
  transition: color 0.2s ease;
}
/* El link responde con algo más que un cambio de color: el texto se adelanta y
   sube apenas. Va sobre el <a>, que no anima GSAP, así que la transición de
   transform acá no le disputa el dueño a nadie. */
.nav__links a { transition: color 0.2s ease, transform 0.28s cubic-bezier(0.22, 1, 0.36, 1); }
.nav__links a:hover,
.nav__links a:focus-visible { color: var(--db-blanco); transform: translateY(-2px); }
.nav__links a[aria-current="page"] { color: var(--db-acento); }

@media (prefers-reduced-motion: reduce) {
  .nav__links a:hover,
  .nav__links a:focus-visible { transform: none; }
}

@media (min-width: 860px) {
  .nav__links { display: flex; }
}

/* ── Hilo conductor ───────────────────────────────────────────────────────
   Desktop: línea vertical fina a la izquierda, con un nodo por sección que se
   enciende al llegar. Mobile: la misma escala convertida en barra horizontal
   fina arriba de todo. Es un solo componente, no dos. */

.thread__list { list-style: none; margin: 0; padding: 0; }
.thread__fill {
  background: var(--db-acento);
  will-change: transform;
}

@media (min-width: 1024px) {
  #thread {
    position: fixed;
    /* 16 y no 32: el nodo mide 44px de ancho para poder tocarse, así que el
       índice ocupa de 16 a 60 y la columna de 64 —donde la 05 se sale de la
       grilla— queda libre. */
    left: max(var(--space-2), env(safe-area-inset-left, 0px));
    top: 50%;
    transform: translateY(-50%);
    z-index: var(--z-thread);
  }
  .thread__line {
    position: absolute;
    left: 3px;
    top: 4px;
    bottom: 4px;
    width: 1px;
    background: color-mix(in srgb, var(--db-gris-medio) 40%, transparent);
  }
  .thread__fill {
    position: absolute;
    inset: 0;
    transform: scaleY(0);
    transform-origin: top;
  }
  .thread__list {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
  }
  .thread__dot {
    position: relative;
    display: flex;
    align-items: center;
    text-decoration: none;
    padding-block: var(--space-1);
    /* 44px exactos: ni el ancho del nombre ni el del punto.
       Antes el <a> medía punto + nombre completo, y como el nombre vive con
       opacity:0 el resultado era una columna invisible de ~150px capturando el
       mouse sobre el contenido de la página. Al sacar el nombre del flujo el
       link quedó midiendo lo que mide el punto: 7px de ancho, un objetivo
       imposible. 44 es el piso de área táctil y deja libre la columna donde la
       05 se sale de la grilla (su contenido arranca en 64). */
    width: 44px;
  }
  .thread__dot::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
    background: var(--db-gris-medio);
    transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), background-color 0.25s ease;
  }
  .thread__dot:hover::before,
  .thread__dot:focus-visible::before,
  .thread__dot.is-active::before {
    background: var(--db-acento);
    transform: scale(1.6);
  }
  /* Al LLEGAR a una sección, su punto da un pulso corto y se queda quieto. Antes
     latía en loop infinito: un punto que late para siempre deja de señalar
     "llegaste acá" y pasa a ser un tic en el borde de la pantalla, compitiendo
     con el contenido durante todo el rato que dure la sección.
     Una sola vuelta, y se vuelve a disparar sólo cuando la clase se pone de
     nuevo — o sea, cada vez que se llega a la sección, que es cuando informa.
     El pulso va en box-shadow y no en escala para no pelearse con el scale(1.6)
     de arriba, que es el que marca "activo".
     La regla global de prefers-reduced-motion en css/base.css ya lo desactiva. */
  .thread__dot.is-active::before {
    animation: db-latido 0.9s ease-out 1;
  }

@keyframes db-latido {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--db-acento) 45%, transparent); }
  70%  { box-shadow: 0 0 0 7px color-mix(in srgb, var(--db-acento) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--db-acento) 0%, transparent); }
}
  /* El nombre sale del flujo del link: es una ayuda que aparece al lado, no
     parte del objetivo que se apunta. pointer-events:none para que nunca
     vuelva a robarle el mouse a lo que tiene detrás. */
  .thread__label {
    position: absolute;
    left: calc(7px + var(--space-2));
    top: 50%;
    color: var(--db-texto-sobre-oscuro);
    font-family: var(--db-font-mono);
    font-size: var(--db-fs-eti);
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transform: translate(-6px, -50%);
    transition: opacity 0.25s ease, transform 0.25s ease;
  }
  /* El nombre de la sección es una ayuda bajo demanda, no un rótulo fijo. Con
     .is-active incluido acá, el label de la sección en curso quedaba siempre
     encendido; como #thread es fixed contra el borde izquierdo y el label es
     nowrap, una palabra larga ("Comparación") se montaba sobre la columna de
     texto y se leía cortada. El punto activo ya se distingue por color y
     escala: el nombre aparece solo al apuntarlo o enfocarlo. */
  .thread__dot:hover .thread__label,
  .thread__dot:focus-visible .thread__label {
    opacity: 1;
    transform: translate(0, -50%);
  }
  .thread__dot.is-active:hover .thread__label,
  .thread__dot.is-active:focus-visible .thread__label { color: var(--db-acento); }
}

@media (max-width: 1023px) {
  #thread {
    position: fixed;
    /* Pegada al borde de la zona segura, no al borde físico: sin esto la barra
       de progreso queda tapada por la barra de estado y no se ve nunca. */
    top: env(safe-area-inset-top, 0px);
    left: 0;
    right: 0;
    height: 3px;
    z-index: var(--z-thread);
  }
  .thread__list { display: none; }
  .thread__line { position: absolute; inset: 0; display: block; }
  .thread__fill {
    position: absolute;
    inset: 0;
    transform: scaleX(0);
    transform-origin: left;
  }
}

/* ── Footer ───────────────────────────────────────────────────────────────────
   Era una franja enorme con todo pegado a la izquierda: 64px de padding arriba
   y abajo, cuatro bloques apilados en una sola columna al borde, y ninguna
   contención. Se leía como una sexta sección de la página en vez de como su
   cierre.

   Ahora es un borde de cierre: el mismo ancho y el mismo margen lateral que el
   resto del sitio (.container), tres columnas de links más la firma, y un pie
   separado por una línea fina con la firma y el año. El alto baja a la mitad. */

#site-footer {
  border-top: 1px solid var(--db-linea);
  /* El indicador de inicio del iPhone se superpone a lo último de la página: el
     pie del footer es justo lo último. */
  padding-block: var(--space-5) calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
}
/* Izquierda: todo lo que es navegación e información, en columnas.
   Derecha: la firma del estudio, sola. */
.footer__inner {
  display: grid;
  gap: var(--space-5);
}
@media (min-width: 960px) {
  .footer__inner {
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--space-6);
    align-items: start;
  }
}
.footer__cols {
  display: grid;
  gap: var(--space-5);
}
@media (min-width: 560px) {
  .footer__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 960px) {
  .footer__cols {
    /* La marca se lleva más ancho que las columnas de links: es lo único con
       prosa adentro. */
    grid-template-columns: minmax(0, 1.35fr) repeat(4, minmax(0, 1fr));
    column-gap: var(--space-4);
  }
}

.footer__logo { height: 24px; width: auto; margin-bottom: var(--space-2); }
/* Nombres y lugar: metadatos, no prosa. Van en mono como el resto de las
   etiquetas y los datos medidos del sitio. */
.footer__names {
  font-family: var(--db-font-mono);
  color: var(--db-gris-medio);
  font-size: 0.75rem;
  line-height: 1.6;
  letter-spacing: 0.04em;
  margin: 0;
  max-width: 26ch;
}
/* El rótulo de cada columna. Va en <p> y no en <h2>: son tres etiquetas de
   navegación, y meterlas en el esquema de encabezados de cada página agregaría
   tres h2 sin contenido debajo. El nombre accesible del grupo lo da el
   aria-labelledby que las apunta. */
.footer__eti {
  font-family: var(--db-font-mono);
  font-size: var(--db-fs-eti);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--db-gris-medio);
  margin: 0 0 var(--space-1);
}
.footer__links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
}
/* El mail es la única entrada larga de las columnas y sin esto se partía a
   mitad de palabra —"gmail.co / m"—. Con anywhere más el <wbr> del marcado, el
   corte cae después del arroba, que es donde una dirección se lee partida. */
.footer__links a {
  overflow-wrap: anywhere;
  color: var(--db-texto-secundario-sobre-oscuro);
  text-decoration: none;
  font-size: var(--db-fs-small);
  overflow-wrap: anywhere;
  display: inline-flex;
  align-items: center;
  /* El área táctil de 44px la da el min-height, no un padding: así el alto de la
     columna es previsible y las tres terminan a la misma altura.
     min-width por el otro eje: "Inicio" mide 37px de ancho, y un objetivo de
     37x44 no llega al mínimo. Redondearlo a 44 le agrega siete píxeles al
     subrayado que se dibuja, que a esa escala no se percibe. Medido con
     elementFromPoint, no con la caja del elemento — es lo que se toca lo que
     cuenta, y varios objetivos del sitio agrandan el suyo con un ::after. */
  min-height: 44px;
  min-width: 44px;
  position: relative;
  transition: color 0.25s ease;
}
/* El link del footer responde con un subrayado que se dibuja desde la izquierda,
   no solo con un cambio de color. Es el mismo idioma que el link interno de las
   tarjetas y que el botón de la ficha: una línea que crece con scaleX.
   El <a> no lo anima GSAP —la entrada del footer va sobre los hijos directos de
   .footer__inner y el <a> está dos niveles más adentro— así que la transición de
   transform no le disputa el dueño a nadie. */
.footer__links a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 10px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.footer__links a:hover,
.footer__links a:focus-visible { color: var(--db-acento); }
.footer__links a:hover::after,
.footer__links a:focus-visible::after { transform: scaleX(1); }
/* La página en la que ya estás no es un destino: se marca y no se subraya. */
.footer__links a[aria-current="page"] { color: var(--db-texto-sobre-oscuro); }
.footer__links a[aria-current="page"]::after { display: none; }
/* La columna de legales no tiene páginas de privacidad ni de términos —no
   existen, y un link a "#" es un link roto disfrazado— así que apunta a los dos
   lugares del sitio donde SÍ están escritas las condiciones: de quién es cada
   cosa (Proceso) y la letra chica (Servicios). Debajo queda la afirmación
   verificable sobre cookies. Cuando existan páginas propias, entran acá y
   heredan todo sin tocar una regla. */
.footer__legal {
  font-size: var(--db-fs-small);
  color: var(--db-gris-medio);
  line-height: 1.6;
  margin: var(--space-1) 0 0;
  max-width: 24ch;
}

/* ── LA FIRMA ────────────────────────────────────────────────────────────────
   Era un párrafo en mono al pie, del mismo tamaño y el mismo peso que el año
   que tenía al lado: la firma del estudio pesaba lo mismo que "2026".

   Ahora es un botón, a la derecha y solo. Y adentro, dos registros distintos a
   propósito: "Powered by" en la tipografía del sitio sin ningún tratamiento —es
   la parte que no se lee, la que sostiene la frase— y "DB Project" con los
   colores del logo, porque es la marca. La D blanca y la B en acento, que es
   exactamente cómo está construido el logotipo del archivo.

   48px de alto mínimo en desktop y 52 en mobile, como cualquier otro botón del
   sitio: es un enlace, no un sello. */
.footer__pw {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  min-height: 52px;
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--db-linea);
  border-radius: 12px;
  text-decoration: none;
  justify-self: start;
  transition: border-color 0.3s ease, background 0.3s ease;
}
@media (min-width: 960px) {
  .footer__pw { min-height: 48px; justify-self: end; }
}
.footer__pw:hover,
.footer__pw:focus-visible {
  border-color: color-mix(in srgb, var(--db-acento) 45%, transparent);
  background: color-mix(in srgb, var(--db-blanco) 3%, transparent);
}
.footer__pw:focus-visible { outline: 2px solid var(--db-acento); outline-offset: 3px; }
/* "Powered by": sin tratamiento. Ni mono, ni versalitas, ni interletrado. */
.footer__pw-eti {
  font-size: var(--db-fs-small);
  color: var(--db-gris-medio);
}
/* "DB Project": los colores del logo. */
.footer__pw-marca {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--db-texto-sobre-oscuro);
}
.footer__pw-marca b { font-weight: 600; color: var(--db-blanco); }
.footer__pw-marca i { font-style: normal; font-weight: 600; color: var(--db-acento); }

/* El pie: solo el año, separado por una línea fina. */
.footer__pie {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: baseline;
  gap: var(--space-2);
  margin-top: var(--space-5);
  padding-top: var(--space-3);
  border-top: 1px solid var(--db-linea);
}
.footer__anio {
  font-family: var(--db-font-mono);
  font-size: var(--db-fs-small);
  color: var(--db-gris-medio);
  margin: 0;
}

@media (prefers-reduced-motion: reduce) {
  .footer__links a::after { transition: none; }
}

/* ── Menú en mobile ──────────────────────────────────────────────────────────
   Debajo de 860px .nav__links es display:none, así que sin esto Servicios,
   Proceso, Proyectos y Contacto no existen para quien entra desde un teléfono
   — que es la mayoría. */
.nav__hamb {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  /* 52 y no 48: el piso del sitio es 48 en desktop y 52 en mobile, y este botón
     SOLO existe abajo de 860 — o sea que siempre está del lado de los 52.
     Medido con sonda en las nueve páginas: daba 48 en todas. */
  width: 52px;
  height: 52px;
  /* La píldora es un contenedor flex: sin esto el botón se comprime a 28px de
     ancho y el área táctil queda por debajo del piso. */
  flex-shrink: 0;
  padding: 0;
  border: 1px solid color-mix(in srgb, var(--db-blanco) 16%, transparent);
  border-radius: 999px;     /* la píldora es redonda: el botón la acompaña */
  background: transparent;
  cursor: pointer;
}
.nav__hamb:focus-visible { outline: 2px solid var(--db-blanco); outline-offset: 3px; }
.nav__hamb-linea {
  width: 18px;
  height: 1.5px;
  background: var(--db-blanco);
  border-radius: 2px;
}
/* Desde 860px vuelven los links y el botón sobra. Es el mismo corte que usa
   .nav__links: así no queda un rango sin ninguno de los dos. */
@media (min-width: 860px) { .nav__hamb { display: none; } }

.menu {
  position: fixed;
  inset: 0;                 /* sin 100vh: inset:0 sobre fixed ya da el viewport
                               visible, sin el problema de la barra de iOS */
  z-index: var(--z-overlay);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-6);
  padding: var(--space-6) var(--space-3);
  padding-top: max(var(--space-8), env(safe-area-inset-top, 0px));
  padding-bottom: max(var(--space-6), env(safe-area-inset-bottom, 0px));
  background: color-mix(in srgb, var(--db-grafito) 92%, transparent);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
/* Sin esto el atributo hidden queda decorativo: .menu{display:flex} y el
   [hidden]{display:none} del navegador tienen la misma especificidad, y gana
   el del autor. La capa seguía cubriendo la pantalla e interceptando los
   toques del visitante aunque estuviera "cerrada". */
.menu[hidden] { display: none; }

.menu__nav { display: flex; flex-direction: column; gap: var(--space-1); }
.menu__link {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  min-height: 56px;
  font-size: clamp(2rem, 9vw, 2.75rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--db-blanco);
  text-decoration: none;
}
.menu__num { font-size: 0.75rem; color: var(--db-acento); letter-spacing: 0.08em; }
.menu__link[aria-current="page"] { color: var(--db-acento); }
.menu__link:focus-visible { outline: 2px solid var(--db-blanco); outline-offset: 4px; }
.menu__pie { display: flex; flex-direction: column; gap: var(--space-1); }
.menu__pie a {
  display: flex;
  align-items: center;
  min-height: 44px;
  font-family: var(--db-font-mono);
  font-size: 0.875rem;
  color: var(--db-gris-claro);
  text-decoration: none;
}

/* El desenfoque va sobre el contenido, no sólo backdrop-filter en la capa: eso
   es lo que hace que el fondo se sienta empujado hacia atrás y no tapado. */
.menu-abierto main,
.menu-abierto #site-footer { filter: blur(7px); transition: filter 0.42s ease; }
.menu-abierto { overflow: hidden; }
.menu-abierto #thread { opacity: 0; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .menu-abierto main, .menu-abierto #site-footer { transition: none; }
}

/* ── Links de la barra: subrayado que se dibuja ──────────────────────────────
   Antes era sólo cambio de color más un translateY. El subrayado que crece
   desde la izquierda es la misma idea que usan los links del pie: el sitio se
   lee de una sola mano. */
.nav__links a { position: relative; }
.nav__links a::before {
  content: "";
  position: absolute;
  left: 7px;
  right: 7px;
  bottom: 2px;
  height: 1px;
  background: var(--db-acento);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
}
.nav__links a:hover::before,
.nav__links a:focus-visible::before { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) { .nav__links a::before { transition: none; } }

/* El cierre vive DENTRO de la capa, no en la barra. Subir el <header> por
   encima del overlay era la otra opción, pero arrastraba el logo del hero
   sobre el menú: el header crea contexto de apilado y sus hijos no pueden
   escapar de él por separado. */
.menu__cerrar {
  position: absolute;
  top: max(var(--space-3), env(safe-area-inset-top, 0px));
  right: var(--space-3);
  display: grid;
  place-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid color-mix(in srgb, var(--db-blanco) 16%, transparent);
  border-radius: 999px;
  background: transparent;
  color: var(--db-blanco);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}
.menu__cerrar:focus-visible { outline: 2px solid var(--db-blanco); outline-offset: 3px; }

/* ── Botón flotante de WhatsApp ──────────────────────────────────────────────
   El acceso rápido que la biblioteca da por supuesto en su ficha de dock
   ("no como navegación principal, como barra flotante de accesos rápidos —
   reemplazando o acompañando al botón único de WhatsApp"). Acá es el botón
   único: un solo canal, un solo círculo. Del dock no se porta la lupa por
   distancia al mouse — hace falta una fila de íconos para que se lea, y con uno
   solo sería matemática sin efecto.

   Aparece recién pasado el hero (js/flotante.js): antes, el hero ya tiene su
   propio CTA a un centímetro, y dos llamadas a la misma acción en la misma
   pantalla se anulan.

   56px, por encima del piso de 44 con margen: es un objetivo que se toca con el
   pulgar, sin mirar, mientras se scrollea. */
.flotante {
  position: fixed;
  z-index: var(--z-nav);
  right: max(var(--space-3), env(safe-area-inset-right, 0px));
  /* El indicador de inicio del iPhone vive justo acá abajo: sin el inset, el
     botón queda debajo de la barra del sistema y se toca a medias. */
  bottom: max(var(--space-3), calc(env(safe-area-inset-bottom, 0px) + var(--space-2)));
  display: grid;
  place-content: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--db-acento);
  color: var(--db-grafito);
  text-decoration: none;
  /* Sombra con desplazamiento y desenfoque, no un halo centrado: el botón tiene
     que despegarse del fondo, y un resplandor sin offset se lee como decoración
     encendida, no como un objeto por delante del plano. */
  box-shadow: 0 10px 28px -6px rgba(0, 0, 0, 0.55), 0 2px 8px -2px rgba(0, 0, 0, 0.4);
  /* Nace invisible y encogido: la entrada la juega GSAP con una escala corta
     desde cero. Si GSAP no carga, js/flotante.js lo deja visible igual — nunca
     se esconde un canal de contacto esperando un tween. */
  opacity: 0;
  transform: scale(0);
  transition: background-color 0.25s ease;
}
.flotante .ico-wa { width: 26px; height: 26px; }
.flotante:hover { background: color-mix(in srgb, var(--db-acento) 84%, var(--db-blanco)); }
.flotante:focus-visible { outline: 2px solid var(--db-blanco); outline-offset: 3px; }
/* Estado listo sin JS de animación (GSAP caído o movimiento reducido). */
.flotante.is-visible { opacity: 1; transform: scale(1); }

/* En mobile la barra de progreso del hilo conductor vive arriba y el botón
   abajo: no se cruzan. Lo que sí se cruzaría es el menú de pantalla completa,
   que tapa todo — ahí el flotante se va. */
.menu-abierto .flotante { opacity: 0; pointer-events: none; }

/* ── Barra en mobile: solo logo y menú ───────────────────────────────────────
   Debajo de 860px la píldora llevaba logo + "Contactanos" + hamburguesa, los
   tres pegados en 375px de ancho. El botón de contacto SALE: el flotante de
   WhatsApp (js/flotante.js) ya cumple esa función abajo a la derecha desde que
   el visitante pasa el hero, y tener el mismo llamado dos veces en una barra
   angosta la satura sin agregar nada.

   Lo que queda son dos objetos con aire real entre ellos. El gap se declara
   acá con !important sobre el estado compactado a propósito: .is-compact baja
   el gap a --space-2 para hacerle lugar a los links, y en mobile no hay links
   que acomodar — solo dos elementos que necesitan separarse. */
@media (max-width: 859px) {
  .nav__pill > .btn { display: none; }
  .nav__pill,
  #site-nav.is-compact .nav__pill {
    /* La píldora toma el ancho disponible y separa los dos objetos a los
       extremos, en vez de llevar un gap fijo. Con un gap fijo la píldora
       shrink-wrapea al contenido y por debajo de ~340px de pantalla el logo a
       tamaño natural más la separación más el botón no entran: se desborda.
       Así la separación es siempre la máxima posible y nunca genera desborde.
       El tope de 420px es para que cerca de 860 no quede una barra larguísima
       con dos cosas en las puntas. */
    width: 100%;
    max-width: 420px;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-1) var(--space-2) var(--space-1) var(--space-3);
  }
  /* El logo cede antes que el botón si la pantalla es muy angosta: el botón de
     menú es el único acceso a las otras cuatro páginas y no puede encogerse por
     debajo de su área táctil. Lo hace con max-width sobre la <img> y NO con un
     overflow:clip en el slot: ese clip recorta el ::after que le da al logo sus
     44px de alto táctiles (ver .nav__logo::after, más arriba) y el área caía a
     los 26px de la imagen. Medido con elementFromPoint. */
  /* max-width: 100% sobre la <img> no alcanzaba, y un tope fijo en píxeles
     tampoco: el slot se dimensionaba por su contenido, así que el 100% valía el
     ancho natural del logo y no el hueco que realmente queda al lado de la
     hamburguesa. Medido con sonda: el logo se metía 56px por debajo del botón de
     menú a 320px, 28px a 375 y 17px a 414.
     Lo que lo resuelve es repartir el ancho explícitamente: el slot toma el
     sobrante (flex: 1 1 0) y la hamburguesa no cede nunca (flex: 0 0 auto),
     porque es el único acceso a las otras páginas. Con el slot ya del tamaño
     correcto, el max-width:100% de la imagen por fin significa algo. */
  .nav__logo-slot {
    min-width: 0;
    flex: 1 1 0;
    display: flex;
    justify-content: flex-start;
  }
  .nav__logo { min-width: 0; display: inline-flex; }
  .nav__hamb { flex: 0 0 auto; }
  .nav__logo img {
    max-width: 100%;
    height: auto;
    object-fit: contain;
    object-position: left center;
  }
}

