/* ============================================================================
   Páginas internas

   Salió de styles.css el 2026-09-06 por cobertura, no por orden: son 41,4 KB crudos que index.html bloqueaba en su primer pintado
   sin usar una sola regla.
   Lo cargan: servicios.html, como-trabajamos.html, contacto.html y 404.html.

   Los tokens (:root), la base y todo lo compartido siguen en styles.css, que
   se carga siempre y va primero. El orden de los bloques acá es el que tenían
   allá, y el <link> va donde corresponde para que la cascada no cambie: ver
   la cabecera de cada página.

   El gate audita este archivo con las mismas reglas de color y tipografía que
   styles.css (HOJAS_CON_TOKENS en tests/gate.mjs).
   ========================================================================= */

/* ============================================================================
   Aparición al scrollear
   ========================================================================= */

/* --revelar-y/--revelar-escala en vez de un transform fijo: una sección con
   más ganas de movimiento (.paso, más abajo) sube el valor sin declarar
   `transform` de nuevo. Importa porque .revelar también se resetea desde
   <noscript> con un selector de la misma especificidad (0,1,0) — cualquier
   regla que declarara `transform` directo con un selector más específico
   (".paso.revelar", 0,2,0) le ganaría a ese reset y la tarjeta quedaría
   corrida para siempre en un visitante sin JavaScript. Los custom properties
   no tienen ese problema: el `transform` sigue viviendo acá, una sola vez. */
.revelar {
  --revelar-y: 18px;
  --revelar-escala: 1;
  opacity: 0;
  transform: translateY(var(--revelar-y)) scale(var(--revelar-escala));
  transition:
    opacity var(--dur-lenta) var(--ease),
    transform var(--dur-lenta) var(--ease);
}
.revelar.visible { opacity: 1; transform: none; }

/* ============================================================================
   Movimiento reducido

   La sección de scroll colapsa a un viewport con el cordón ya conectado, la
   lámpara encendida y la tecla visible. No se pierde información: se pierde
   el espectáculo.
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  .revelar { opacity: 1; transform: none; }
}

/* ============================================================================
   El hero-lienzo de .mostrador (contacto). Hasta el 2026-09-30 también lo
   usaba .metodo; Cómo trabajamos ahora tiene su propio hero (metodo.css).

   Las reglas que definen el MECANISMO van agrupadas; las que dependen del
   arte de cada página (el recorte, el largo del desvanecido) van separadas
   abajo. Duplicar el mecanismo entero para la segunda página era garantizar
   que se separaran solos en el tercer cambio.

   Mismo mecanismo que el tablero: el fondo de la sección es --negro-lienzo,
   el negro del JPG, así el borde del archivo no existe y la consola entra
   borde a borde debajo del titular. El titular y la bajada son HTML real
   sobre ese negro; la imagen no lleva texto horneado.

   Sin botones propios: el riel siempre tiene "Hablar" (sticky, en las cuatro
   páginas) y el paso 01 de esta misma página repite el CTA a un scroll de
   distancia. Un tercer botón acá abajo no abría ningún camino nuevo, solo
   competía con el titular por el mismo negro. El 2026-09-03 tenían un botón
   propio y checkHero() lo exigía adentro de .metodo — ver más abajo por qué
   ese requisito se movió al riel en vez de borrarse.

   Apilado y no superpuesto a propósito: la consola ocupa el 60% inferior del
   cuadro, y a 16:9 en un teléfono el cuadro mide 210px de alto. Texto encima
   de eso es texto encima de la consola. Apilado, el titular cae en el primer
   viewport a cualquier ancho y la imagen entra entera debajo.
   ========================================================================= */

.mostrador {
  background: var(--negro-lienzo);
  padding-block: calc(var(--u) * 5) 0;
  overflow: hidden;
}

.mostrador__intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--u) * 2);
  padding-inline: var(--tablero-margen);
  padding-bottom: calc(var(--u) * 3);
  text-align: center;
}

/* --t-hero, como el tablero: el tipo más grande de la página no es el que
   abre. Con 20ch y balance el titular real cae en dos líneas parejas. */
.mostrador__titular {
  font-size: var(--t-hero);
  max-width: 20ch;
  text-wrap: balance;
}

.mostrador__bajada {
  max-width: 54ch;
  color: var(--tinta-suave);
}

.mostrador__lienzo { line-height: 0; }

.mostrador__imagen { width: 100%; height: auto; }

/* 4% arriba, y el número sale de medir el archivo. La fotografía se recortó en origen (2752×1536
   → 2752×1316, 160px de arriba) para sacarle la banda de luz del cielorraso,
   que medía 60/255 de media por fila contra 8 del resto del cuadro: era lo
   más brillante de la imagen justo donde el desvanecido tiene que arrancar
   en negro. Después de ese recorte quedan ~104px de aire sobre su pelo; un
   10% serían 132px y le comería la cabeza. 4% son 53px y cae entero en el
   negro de arriba. Si se cambia el arte, se vuelve a medir. */
.mostrador__imagen {
  -webkit-mask-image: linear-gradient(to bottom,
    transparent 0, rgba(0, 0, 0, 1) 4%,
    rgba(0, 0, 0, 1) 95%, transparent 100%);
  mask-image: linear-gradient(to bottom,
    transparent 0, rgba(0, 0, 0, 1) 4%,
    rgba(0, 0, 0, 1) 95%, transparent 100%);
}

/* ============================================================================
   La pantalla — unidad 1 de servicios.html

   Reemplaza al titular de display: el comercial en un monitor, montado sobre
   un campo de circuito. El fondo se dibuja entero con gradientes (retícula
   fina, nodos en las intersecciones, barrido) — cero bytes de red, escala sin
   pixelarse, y una sola animación de transform que la GPU compone sola.

   La máscara radial apaga el campo contra los bordes. Sin ella la retícula
   corta en seco contra el riel de arriba y contra la primera unidad de
   servicios, y se lee como un PNG mal recortado en vez de como profundidad.
   ========================================================================= */

.pantalla {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: var(--unidad) var(--tablero-margen);
  background: var(--negro-lienzo);
  border-top: 1px solid var(--hud-borde);
}

.pantalla__campo {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    radial-gradient(circle at 0 0, var(--circuito-nodo) 1.5px, transparent 1.6px),
    repeating-linear-gradient(90deg, var(--circuito-linea) 0 1px, transparent 1px 24px),
    repeating-linear-gradient(0deg,  var(--circuito-linea) 0 1px, transparent 1px 24px);
  background-size: 96px 96px, auto, auto;
  background-position: 12px 12px, 0 0, 0 0;
  -webkit-mask-image: radial-gradient(ellipse 78% 74% at 50% 46%, black 30%, transparent 100%);
  mask-image: radial-gradient(ellipse 78% 74% at 50% 46%, black 30%, transparent 100%);
}

/* El barrido: una banda de luz cálida que baja por la sección cada 9 segundos.
   Es el único movimiento del fondo.

   Va como pseudo de .pantalla y no como hijo de .pantalla__campo por una razón
   de costo, no de estilo: el campo lleva una máscara radial, y una animación
   adentro de un elemento enmascarado obliga a recalcular la máscara de toda la
   sección en cada cuadro. Acá arriba la banda es su propia capa, se mueve con
   transform, y el recorte se lo hace el overflow de la sección. La luz se
   apaga sola en los dos extremos del gradiente: no necesita máscara. */
.pantalla::after {
  content: "";
  position: absolute;
  z-index: -1;
  left: 0;
  right: 0;
  top: 0;
  height: 22%;
  background: linear-gradient(180deg, transparent 0%, var(--barrido) 50%, transparent 100%);
  will-change: transform;
  animation: pantalla-barrido 9s linear infinite;
  pointer-events: none;
}

@keyframes pantalla-barrido {
  from { transform: translateY(-100%); }
  to   { transform: translateY(560%); }
}

.pantalla__pieza {
  position: relative;
  margin: 0 auto;
  /* 1000px y no más: a 1366 de ancho la pieza entera —monitor mas placa— entra
     en el primer viewport sin scrollear, y quedan 180px de campo a cada lado.
     Con el monitor mas ancho el circuito se ve solo como un filo y la seccion
     se lee como un video pegado, no como un equipo encendido. */
  max-width: 1000px;
}

/* El monitor. Vidrio HUD como el riel y el pie, con dos escuadras de saffron
   en las esquinas opuestas: la misma marca de encuadre que usa el equipo de
   video, no un borde decorativo. */
.pantalla__marco {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--negro);
  border: 1px solid var(--hud-borde-fuerte);
  border-radius: var(--radio);
  box-shadow:
    0 0 90px 10px var(--hud-glow),
    inset 0 0 0 1px var(--costura-luz);
}

.pantalla__marco::before,
.pantalla__marco::after {
  content: "";
  position: absolute;
  z-index: 2;
  width: calc(var(--u) * 3);
  height: calc(var(--u) * 3);
  border: 2px solid var(--saffron);
  pointer-events: none;
}

.pantalla__marco::before {
  top: -1px;
  left: -1px;
  border-right: 0;
  border-bottom: 0;
}

.pantalla__marco::after {
  right: -1px;
  bottom: -1px;
  border-top: 0;
  border-left: 0;
}

.pantalla__video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--negro);
}

/* La tecla ocupa todo el monitor: tocar en cualquier parte del cuadro
   arranca el video con sonido, que es lo que la gente intenta hacer igual.
   Nace con hidden puesto y solo la muestra pantalla.js — sin JavaScript los
   controles nativos del <video> siguen ahí y esta capa nunca aparece. */
.pantalla__tecla {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 0;
  border: 0;
  background: var(--velo);
  color: var(--tinta);
  cursor: pointer;
  transition: background var(--dur-media) var(--ease);
}

.pantalla__tecla[hidden] { display: none; }

.pantalla__disparo {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--u) * 1.5);
  padding: calc(var(--u) * 1.5) calc(var(--u) * 3);
  border-radius: var(--radio-tecla);
  background: var(--saffron);
  color: var(--negro);
  font: 700 var(--t-menor)/1 var(--fuente-titulo);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  box-shadow: 0 0 40px var(--hud-glow);
  transition:
    background var(--dur-rapida) var(--ease),
    transform var(--dur-rapida) var(--ease-tecla);
}

.pantalla__glifo {
  width: 0.72em;
  height: 0.86em;
  background: currentColor;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

.pantalla__tecla:hover .pantalla__disparo { background: var(--saffron-hover); }
.pantalla__tecla:active .pantalla__disparo { transform: scale(0.97); }
.pantalla__tecla:focus-visible { outline: 2px solid var(--saffron); outline-offset: -6px; }

/* Mientras corre en silencio el velo se va y la tecla se corre a una esquina:
   el video se tiene que ver, y la invitación al sonido tiene que seguir
   estando. Es el mismo botón, no aparece uno nuevo. */
.pantalla__pieza.reproduciendo .pantalla__tecla {
  align-items: flex-end;
  justify-content: flex-end;
  padding: calc(var(--u) * 2);
  background: transparent;
}

.pantalla__pieza.reproduciendo .pantalla__disparo {
  padding: var(--u) calc(var(--u) * 2);
  font-size: var(--t-placa);
}

.pantalla__placa {
  margin: calc(var(--u) * 2) 0 0;
  text-align: center;
  color: var(--tinta-suave);
  font: 600 var(--t-placa)/1 var(--fuente-cuerpo);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

@media (max-width: 620px) {
  .pantalla { padding-inline: calc(var(--u) * 1.5); }
  .pantalla__disparo { padding: calc(var(--u) * 1.25) calc(var(--u) * 2); }
}

/* Movimiento reducido: el campo se queda quieto. El video no se toca acá —
   no arranca solo con esta preferencia puesta, lo decide pantalla.js. */
@media (prefers-reduced-motion: reduce) {
  .pantalla::after { animation: none; opacity: 0; }
}

/* ============================================================================
   Páginas internas — cada bloque es una unidad más del mismo rack
   ========================================================================= */

/* .servicios salio de este grupo con las cinco tarjetas: servicios.html ahora
   arma sus propias unidades (.diagnostico, .fugas, .cierre--columnas). Y
   .vias se fue con el rediseño de contacto.html: eran cuatro tarjetas iguales
   en un auto-fit, o sea la lectura más plana posible de cuatro vías que no
   pesan lo mismo. Lo reemplazan .vitrina (el agente) y .mesa (las otras
   tres). Lo que queda acá es de como-trabajamos.html. */

/* --- El proceso: cinco pasos unidos por un riel ---------------------------
   Antes eran cinco <article> iguales en una grilla de una columna: una lista
   de tarjetas, no un proceso. Ahora es un <ol> con un riel saffron de un
   pixel que atraviesa la columna de números, en el mismo lenguaje que la
   costura de las áreas del tablero (.area::after). El riel va detrás de las
   cajas: se ve a través del tinte del 8% y desaparece detrás del número, que
   es negro sólido. */

.pasos {
  display: grid;
  gap: calc(var(--u) * 4);
  justify-items: center;
  padding: var(--unidad) calc(var(--u) * 2.5);
}

.pasos__titulo { text-align: center; }

.pasos__lista {
  position: relative;
  display: grid;
  gap: calc(var(--u) * 2);
  width: 100%;
  max-width: 68rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Arranca en el centro del primer número (borde 1px + padding 32px + mitad
   del chip de 48px = 57px) y se apaga antes del final de la última caja.
   Nace en escala 0 y se dibuja hacia abajo apenas el primer paso se revela
   (:has() lo nota sin JS nuevo): la columna no aparece completa de un
   golpe, crece con la misma secuencia que describe. */
.pasos__lista::before {
  content: "";
  position: absolute;
  top: calc(var(--u) * 7 + 1px);
  bottom: calc(var(--u) * 4);
  left: calc(var(--u) * 6 + 1px);
  width: 1px;
  background: linear-gradient(to bottom,
    var(--saffron),
    var(--hud-borde-fuerte) 60%,
    transparent);
  pointer-events: none;
  transform: scaleY(0);
  transform-origin: top;
  transition: transform calc(var(--dur-lenta) * 1.6) var(--ease);
}
.pasos__lista:has(.paso.visible)::before { transform: scaleY(1); }

/* --- Diagnóstico: la pregunta -------------------------------------------
   1000px es el mismo ancho que .pantalla__pieza. El video, la pregunta y las
   cinco fugas comparten eje vertical, así la página se lee como una pieza y no
   como tres bloques apilados. */

.diagnostico {
  border-top: 1px solid var(--hud-borde);
}

.diagnostico__interior {
  max-width: 1000px;
  margin: 0 auto;
  padding: var(--unidad) var(--tablero-margen) calc(var(--u) * 2.5);
}

.diagnostico__kicker {
  margin: 0;
  color: var(--granito);
  font: 700 var(--t-placa)/1 var(--fuente-titulo);
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

/* 24ch y no 22: a 22 la palabra "clientes" cae sola en un tercer renglón. */
.diagnostico__titulo {
  margin: calc(var(--u) * 2) 0 0;
  max-width: 24ch;
  font-size: clamp(2.2rem, 1.4rem + 3vw, 3.75rem);
  line-height: 1;
  text-wrap: balance;
}

.diagnostico__bajada {
  margin: calc(var(--u) * 2.5) 0 0;
  max-width: 58ch;
  color: var(--tinta-suave);
}

/* --- Las cinco fugas -----------------------------------------------------
   El acordeón es <details name="fugas">: exclusividad nativa, sin una línea de
   JavaScript. El sitio es progressive enhancement por decisión; un acordeón en
   JS deja las cinco cajas cerradas y sin forma de abrirlas cuando el script no
   llega. Teclado y lector de pantalla salen correctos de fábrica. */

.fugas__interior {
  max-width: 1000px;
  margin: 0 auto;
  display: grid;
  gap: calc(var(--u) * 1.25);
  padding: 0 var(--tablero-margen) var(--unidad);
}

.fuga {
  border: 1px solid var(--hud-borde-suave);
  border-radius: var(--radio);
  background: var(--hud-superficie-tenue);
  transition:
    border-color var(--dur-rapida) var(--ease),
    background var(--dur-rapida) var(--ease);
}

.fuga[open] {
  border-color: var(--hud-borde-fuerte);
  background: var(--hud-superficie-viva);
}

/* La cabecera. Los tres reset del marcador son obligatorios: si falta uno queda
   el triangulito del navegador al lado del número. */

/* Dos filas y áreas, en vez de un .fuga__identidad envolviendo voz + servicio.
   El motivo es de HTML, no de layout: el nombre del servicio tiene que ser un
   <h3> —esta es la página que trabaja el SEO local y las cinco tarjetas viejas
   sí lo tenían—, y el modelo de contenido de <summary> admite encabezados como
   hijo directo, pero no un <h3> adentro de un <span>. Con las áreas, el número
   y el signo abarcan las dos filas y siguen centrados, así que la geometría no
   se mueve: medido en las cinco cabeceras, x/y/ancho/alto idénticos.
   column-gap y row-gap separados: con el gap único, el salto entre la voz y el
   rótulo pasaba de 8px a 28px. */
.fuga__cabecera {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "num voz sig"
    "num srv sig";
  column-gap: clamp(14px, 2.5vw, 28px);
  row-gap: var(--u);
  align-items: center;
  padding: clamp(20px, 2.5vw, 28px) clamp(18px, 2.5vw, 26px);
  cursor: pointer;
  list-style: none;
}

.fuga__cabecera::-webkit-details-marker { display: none; }
.fuga__cabecera::marker { content: ""; }

.fuga__numero {
  grid-area: num;
  color: var(--granito-claro);
  font: 700 0.8125rem/1 var(--fuente-titulo);
  letter-spacing: 0.18em;
  font-variant-numeric: tabular-nums;
}

/* La voz del cliente. IBM Plex 600 y no Space Grotesk uppercase saffron: es una
   frase entre comillas dicha por una persona, no un rótulo grabado. En
   mayúsculas dejaba de sonar a alguien hablando, y en saffron era el quinto
   elemento del acento en cada fila, robándoselo al único CTA. */
.fuga__voz {
  grid-area: voz;
  color: var(--tinta);
  font: 600 clamp(1.15rem, 1rem + 0.7vw, 1.5rem)/1.35 var(--fuente-cuerpo);
  text-wrap: pretty;
}

.fuga__servicio {
  grid-area: srv;
  color: var(--granito-claro);
  font: 700 var(--t-placa)/1.3 var(--fuente-titulo);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition: color var(--dur-rapida) var(--ease);
}

.fuga[open] .fuga__servicio { color: var(--saffron); }

.fuga__signo {
  grid-area: sig;
  color: var(--saffron);
  font: 700 1.375rem/1 var(--fuente-titulo);
}

/* El signo es el isotipo. Cerrada, en blanco. Abierta, se enciende: la tapa
   saffron con la S calada, la versión principal del manual. */
.fuga__signo::after {
  content: "";
  display: block;
  width: var(--marca-tapa);
  height: var(--marca-tapa);
  border-radius: var(--radio);
  background: var(--tinta);
  -webkit-mask: var(--isotipo-en-tapa);
  mask: var(--isotipo-en-tapa);
}
.fuga[open] .fuga__signo::after {
  background: var(--saffron);
  -webkit-mask: var(--isotipo-en-tapa), linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 1));
  -webkit-mask-composite: xor;
  mask: var(--isotipo-en-tapa), linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 1));
  mask-composite: exclude;
}

/* La caja. */

.fuga__cuerpo {
  display: grid;
  /* min(230px, 100%): misma razón que .cierre__interior. Acá el reflow de
     860px ya fuerza una columna, así que el desborde no llega a pasar, pero un
     piso duro esperando a que alguien mueva el breakpoint es una trampa
     puesta, no un caso que no ocurre. */
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
  gap: clamp(20px, 3vw, 36px);
  padding: calc(var(--u) * 0.5) clamp(18px, 2.5vw, 26px) clamp(24px, 3vw, 32px);
  border-top: 1px solid var(--hud-borde-suave);
}

.fuga__columna {
  display: grid;
  gap: calc(var(--u) * 1.25);
  align-content: start;
}

/* Los tres párrafos con nombre van calificados con el elemento y anidados bajo
   la columna a propósito: .fuga__columna p es 0-1-1 y le gana a un .clase
   suelta de 0-1-0. Escritos sin calificar, el rótulo salía en tinta suave a
   15px en vez de saffron a 10px, y la línea perdía color y tamaño — con la
   regla en la hoja, a la vista, y sin un solo error. Medido en el navegador,
   no deducido. Es la misma trampa que ya tenía documentada p.servicio__precio
   en el bloque que este reemplaza. */

.fuga__columna p {
  margin: 0;
  color: var(--tinta-suave);
  font-size: 0.9375rem;
  line-height: 1.6;
  max-width: 42ch;
}

/* --t-placa (11px) y no los 0.625rem (10px) que pedía el handoff. Son quince
   rótulos, en mayúsculas y con 0.18em de tracking, y son lo que le dice al
   visitante qué está mirando dentro de la caja: no puede ser el texto más
   chico de la página. El proyecto ya tomó esta decisión una vez —ver el
   comentario largo de p.servicio__precio, que bajó de --t-placa a --t-menor
   por lo mismo—, así que meter 10px en una sección nueva es volver atrás.
   Además queda en la escala en vez de ser un valor suelto. */
.fuga__columna p.fuga__rotulo {
  color: var(--saffron);
  font: 700 var(--t-placa)/1 var(--fuente-titulo);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  max-width: none;
}

.fuga__columna p.fuga__linea {
  color: var(--tinta);
  font: 600 1.0625rem/1.45 var(--fuente-cuerpo);
  max-width: 40ch;
}

/* Sin uppercase y a 18px: es el único dato factual que la página puede mostrar
   hoy, así que no puede ser también lo más difícil de leer. Es la misma razón
   que tenía el bloque viejo de .servicio__precio y sigue valiendo. */
.fuga__columna p.fuga__precio {
  color: var(--saffron);
  font: 600 1.125rem/1.4 var(--fuente-cuerpo);
}

/* max-width acá también, no solo en los párrafos. La lista se había quedado
   afuera de las dos reglas de medida, y en un teléfono apaisado (844×390) las
   viñetas se estiraban a 717px: 95 caracteres por línea, contra los 67 del
   párrafo de al lado que sí está capado. Nadie lee 95. */
.fuga__lista {
  margin: 0;
  padding-left: calc(var(--u) * 2);
  max-width: 42ch;
  color: var(--tinta-suave);
  font-size: 0.9375rem;
  line-height: 1.7;
}

/* El CTA por caja, que es lo que más cambia de este rediseño. El agente es toda
   la tesis de conversión del sitio y estaba solo al final de la página, después
   de cinco bloques largos de lectura. El que abrió una caja ya se autocalificó,
   y el botón que tiene enfrente abre la charla con ese tema (data-tema). */

.fuga__cta {
  justify-self: start;
  min-height: calc(var(--u) * 5.5);
  padding: calc(var(--u) * 1.5) calc(var(--u) * 2.25);
  border: 1px solid var(--hud-borde-fuerte);
  border-radius: var(--radio);
  background: transparent;
  color: var(--saffron);
  font: 700 0.75rem/1 var(--fuente-titulo);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  transition:
    background var(--dur-rapida) var(--ease),
    border-color var(--dur-rapida) var(--ease);
}

.fuga__cta:hover { background: var(--hud-superficie); }

/* La 01 es el producto que demuestra la tesis, y su CTA es el único que no dice
   "preguntar" sino "probar". Sólido, como la tecla. */
.fuga__cta--solida {
  background: var(--saffron);
  color: var(--negro);
  box-shadow: 0 0 26px var(--hud-glow);
}

.fuga__cta--solida:hover { background: var(--saffron-hover); }

/* --- Paso --- */

.paso {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: calc(var(--u) * 3);
  align-items: start;
  padding: calc(var(--u) * 4) calc(var(--u) * 3);
  border: 1px solid var(--hud-borde);
  border-radius: var(--radio);
  background: var(--hud-superficie);
  transition:
    opacity var(--dur-lenta) var(--ease),
    transform var(--dur-lenta) var(--ease),
    border-color var(--dur-rapida) var(--ease),
    background var(--dur-rapida) var(--ease),
    box-shadow var(--dur-rapida) var(--ease);
}

/* El .revelar genérico del sitio es opacity + 18px, pensado para un párrafo.
   Esta lista es la columna vertebral de la página y con ese movimiento
   quedaba la sección más chata del sitio. Acá cada paso sube más y entra con
   una leve escala — se asienta en vez de solo aparecer. Solo toca los custom
   properties (ver el comentario de .revelar): así no hay dos selectores
   distintos disputándose `transform` cuando :hover entra en la ecuación. */
.paso.revelar { --revelar-y: 40px; --revelar-escala: 0.96; }

/* Decorativo, no un botón: nada del 02 al 05 lleva a ningún lado por su
   cuenta (el 01 ya tiene su propio chip, "Empezar la entrevista"). El lift
   es chico a propósito — alcanza para sentirse vivo sin prometer un click
   que no existe.
   Va DESPUÉS de .revelar.visible a propósito: los dos declaran `transform`
   con la misma especificidad (0,2,0), y en un empate manda el orden en el
   archivo. Antes de esto acá había un .paso.revelar.visible con especificidad
   0,3,0 puesto para "asentar" la tarjeta, y ganaba siempre — hover nunca se
   veía una vez que el paso ya había entrado en pantalla, que es la mayor
   parte del tiempo que alguien pasa el mouse por encima. */
.paso:hover {
  transform: translateY(-6px);
  border-color: var(--hud-borde-fuerte);
  background: color-mix(in srgb, var(--hud-superficie), var(--saffron) 4%);
  box-shadow:
    0 24px 48px -24px rgba(0, 0, 0, 0.7),
    0 0 32px -6px var(--hud-glow);
}

/* Chip de 48px, no una caja que mide lo mismo que el h3 (27px los dos,
   medido): el número indexa, el título manda. Negro sólido y no al 70%: el
   riel pasa por detrás y tiene que desaparecer, no transparentarse. Borde
   a --hud-borde: cinco bordes al 75% eran cinco acentos compitiendo con la
   única tecla de la página, el mismo problema que servicios corrigió. */
.paso__numero {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: calc(var(--u) * 6);
  height: calc(var(--u) * 6);
  border: 1px solid var(--hud-borde);
  border-radius: var(--radio);
  background: var(--negro);
  color: var(--saffron);
  font: 700 var(--t-menor)/1 var(--fuente-titulo);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  transition:
    transform var(--dur-rapida) var(--ease-tecla),
    border-color var(--dur-rapida) var(--ease),
    box-shadow var(--dur-rapida) var(--ease);
}

.paso:hover .paso__numero {
  transform: scale(1.08);
  border-color: var(--saffron);
  box-shadow: 0 0 22px var(--hud-glow);
}

.paso__texto { display: grid; gap: var(--u); justify-items: start; }
.paso__texto p { color: var(--tinta-suave); }
.paso__texto .chip { margin-top: var(--u); }

/* --- La vitrina: el agente a la vista, sin hacer click ---------------------

   Unidad 2 de contacto.html. Es la única página donde el producto tiene que
   verse ANTES de que alguien decida abrirlo, así que el saludo real está
   dibujado en la página y no detrás de un botón.

   El panel reusa .agente__marca y .agente__fila--agente, las clases del
   <dialog> real, en vez de imitarlas con clases propias. Es a propósito: una
   vitrina que se parece al producto se separa del producto en el primer
   retoque, y entonces la página promete una cosa y el botón entrega otra.
   Acá el globo del saludo ES un globo del agente.

   El texto del saludo tampoco se tipeó: es la constante SALUDO de
   chat-core.mjs, y el check `vitrina` del gate falla si las dos se separan. */

.vitrina {
  display: grid;
  gap: calc(var(--u) * 4);
  justify-items: center;
  padding: var(--unidad) calc(var(--u) * 2.5);
}

.vitrina__intro {
  display: grid;
  gap: calc(var(--u) * 2);
  justify-items: center;
  text-align: center;
}

.vitrina__titulo { font-size: var(--t-titulo); max-width: 20ch; text-wrap: balance; }
.vitrina__bajada { max-width: 54ch; color: var(--tinta-suave); }

/* 46ch y no el ancho de la columna: es una conversación, y una conversación
   ancha se lee como un documento. El <dialog> real mide 440px — este panel
   se le parece de cerca a propósito, porque es el mismo panel.

   El alto es un rango, no un número. Adentro va .agente__panel, que es una
   columna flex con la lista de mensajes en `flex: 1; min-height: 0; overflow-y:
   auto`: sin un techo, la página entera crecería con cada mensaje; con un alto
   fijo, una conversación de un solo turno deja media pantalla de negro vacío
   debajo del saludo. Con min/max el panel arranca compacto, crece con la
   charla y a partir del máximo scrollea por dentro.

   El mínimo es lo que ocupan el saludo, el campo y un turno más: por debajo, el
   campo de texto queda pegado al saludo y no se lee como una conversación que
   sigue. El máximo baja con la altura de pantalla para que el campo nunca
   termine debajo del pliegue en un teléfono. */
.vitrina__panel {
  width: min(46ch, 100%);
  min-height: 19rem;
  max-height: min(30rem, 70vh);
  border: 1px solid var(--hud-borde-fuerte);
  border-radius: var(--radio);
  background: var(--hud-vidrio);
  backdrop-filter: blur(24px) saturate(140%);
  -webkit-backdrop-filter: blur(24px) saturate(140%);
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.9), 0 0 60px var(--hud-glow);
  overflow: hidden;
  color: var(--tinta);
}

/* El respaldo sin JavaScript no tiene campo de texto ni handoff: se achica a lo
   que ocupa el saludo en vez de reservar el mínimo de una conversación que ahí
   no va a pasar. */
.vitrina__panel:not([data-agente-montado]) { min-height: 0; }

/* La X de cerrar no tiene sentido en un agente que es parte de la página:
   no hay nada que cerrar. */
[data-agente-inline] .agente__cerrar { display: none; }

.vitrina__atajos {
  display: grid;
  gap: var(--u);
  width: min(46ch, 100%);
}

.vitrina__rotulo {
  font: 700 var(--t-placa)/1 var(--fuente-titulo);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--granito-claro);
  margin-bottom: calc(var(--u) * 0.5);
}

/* Deliberadamente NO son .chip: un chip va en versalitas a 11px, y estas son
   preguntas de 30 a 40 caracteres. Tres preguntas en mayúsculas es el
   all-caps-body que el critique ya marcó en dos páginas. Van en cuerpo, en
   caja normal, que además es como se ve una sugerencia en un chat de verdad. */
.vitrina__atajo {
  display: block;
  width: 100%;
  min-height: calc(var(--u) * 5.5);
  padding: calc(var(--u) * 1.25) calc(var(--u) * 1.75);
  border: 1px solid var(--hud-borde-suave);
  border-radius: var(--radio);
  background: var(--hud-superficie-tenue);
  color: var(--tinta-suave);
  font: 400 var(--t-menor)/1.4 var(--fuente-cuerpo);
  text-align: left;
  cursor: pointer;
  transition:
    color var(--dur-rapida) var(--ease),
    border-color var(--dur-rapida) var(--ease),
    background var(--dur-rapida) var(--ease);
}

.vitrina__atajo:hover,
.vitrina__atajo:focus-visible {
  color: var(--tinta);
  border-color: var(--hud-borde-fuerte);
  background: var(--hud-superficie-viva);
}

/* --- La mesa: las otras tres vías -----------------------------------------

   Tres columnas y no cuatro cajas iguales. Sin caja: una regla de un pixel
   arriba de cada columna, el mismo idioma que la costura de .area::after y el
   riel de .pasos__lista. Tres cajas HUD acá abajo competirían con la vitrina,
   que es la unidad que tiene que ganar. */

/* repeat(3) explícito y no auto-fit. Con auto-fit medía 4 columnas de 276px a
   1440 —los tres canales en tres, y el cuarto de la fila vacío— porque el h2
   lleva `grid-column: 1 / -1` y ningún track queda vacío para colapsar. Y
   además auto-fit fingía que la cantidad de columnas sale del contenido: no
   sale, son tres vías y van a seguir siendo tres. */
.mesa {
  display: grid;
  gap: calc(var(--u) * 3);
  align-items: start;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  padding: 0 calc(var(--u) * 2.5) var(--unidad);
  max-width: 76rem;
  margin-inline: auto;
}

/* Tres a una, sin escala intermedia: dos columnas dejan una vía huérfana
   abajo, que es lo que el auto-fit hacía sin que nadie lo pidiera. */
@media (max-width: 760px) {
  .mesa { grid-template-columns: minmax(0, 1fr); }
}

.mesa__titulo {
  grid-column: 1 / -1;
  font: 700 var(--t-placa)/1 var(--fuente-titulo);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--saffron);
}

.canal {
  display: grid;
  gap: calc(var(--u) * 1.5);
  justify-items: start;
  align-content: start;
  padding-top: calc(var(--u) * 2.5);
  border-top: 1px solid var(--hud-borde-suave);
}

/* 26px de trazo de un pixel en saffron, dibujados en el SVG del HTML. Los
   PNG que había acá antes eran clip-art de un pack, con una caja blanca
   redondeada horneada en el archivo: sobre la tarjeta negra se leían como
   calcomanías, y nada más en el sitio tiene una caja blanca. */
.canal__glifo { display: block; color: var(--saffron); }

.canal p { color: var(--tinta-suave); font-size: var(--t-menor); }

/* Las tres ciudades no son un pie de tarjeta: es lo único que una agencia
   remota barata no puede copiar, así que sube un escalón sobre el cuerpo.
   Un escalón, no dos: a --t-sub quedaba empatada con el h3 de su propia
   columna, que es una jerarquía de dos elementos que no existe. Y en caja
   normal, no en versalitas: la misma cadena en mayúsculas ya está registrada
   como excepción de all-caps-body en el pie, y una segunda no se justifica. */
/* Calificada con el elemento: `.canal p` es 0-1-1 y le gana a un `.canal__zona`
   de 0-1-0, así que las tres ciudades salían a 14px, o sea del mismo tamaño
   que el párrafo que tenían que encabezar. Mismo modo de falla que
   `.cierre p.cierre__nota` más abajo, y medido igual: en el navegador, no a
   ojo — computaba 14px donde el token dice 18. */
.canal p.canal__zona {
  font: 600 var(--t-cuerpo)/1.4 var(--fuente-cuerpo);
  color: var(--tinta);
}

/* .chip pone text-transform: uppercase, y un mail en versalitas es un mail que
   se tipea mal. Lo marcó el critique de index el 2026-09-02 y seguía puesto. */
.canal__correo { text-transform: none; letter-spacing: 0.02em; }

/* 44px y no los 24 del .chip. 24 es el piso exacto de WCAG 2.5.8 y pasa por
   cero, y medido a 375 estos eran 126×24 y 150×24: la vía de contacto humano
   de una página de contacto con la mitad del área de pulgar que un atajo del
   chat. El chip inerte de otras páginas se queda en 24 — lo que sube es el
   que hay que poder tocar. */
.canal__accion {
  min-height: calc(var(--u) * 5.5);
  padding-inline: calc(var(--u) * 2);
}

/* --- El remate: qué pasa después de que escribes --------------------------

   Cierra la duda operativa en vez de repetir el CTA. Hasta el 2026-09-04 acá
   había un .cierre idéntico palabra por palabra al de como-trabajamos.html: la
   última pantalla de contacto era la última pantalla de otra página, y el
   mismo botón aparecía tres veces (riel, vías, cierre) sin escalar nada.

   Sin tecla propia: la vitrina de arriba ES la puerta, y el riel sticky tiene
   "Hablar" en todo momento (lo garantiza checkAgenteEnRiel). */

.remate {
  padding: var(--unidad) calc(var(--u) * 2.5);
  background: var(--hud-vidrio);
  border-top: 1px solid var(--hud-borde);
}

.remate__interior {
  max-width: 60rem;
  margin-inline: auto;
  display: grid;
  gap: calc(var(--u) * 4);
}

.remate__titulo { font-size: var(--t-titulo); max-width: 22ch; text-wrap: balance; }

.remate__lista { display: grid; gap: calc(var(--u) * 3); margin: 0; }

/* auto/1fr en escritorio: el "cuándo" queda en una columna propia y los tres
   plazos se leen en vertical de un vistazo. Abajo de 620px pasa a una sola
   columna, porque a 320px "EL MISMO DÍA" y el párrafo no entran al lado. */
.remate__punto {
  display: grid;
  grid-template-columns: minmax(9rem, auto) 1fr;
  gap: calc(var(--u) * 2);
  align-items: baseline;
}

.remate__cuando {
  font: 700 var(--t-placa)/1.4 var(--fuente-titulo);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--saffron);
}

/* El <dd> del navegador trae margin-inline-start: 40px. Sin este reset los
   tres párrafos arrancan corridos y la columna del "cuándo" deja de alinear
   con nada. */
.remate__punto dd { margin: 0; }
.remate__punto p { color: var(--tinta-suave); }

.remate__nota { color: var(--granito-claro); font-size: var(--t-menor); }

@media (max-width: 620px) {
  .remate__punto { grid-template-columns: 1fr; gap: var(--u); }
}

@media (prefers-reduced-motion: reduce) {
  .agente__pulso { animation: none; }
}

/* --- Cierre --- */

.cierre {
  display: grid;
  gap: calc(var(--u) * 3);
  justify-items: center;
  text-align: center;
  padding: var(--unidad) calc(var(--u) * 3);
}

.cierre--hud {
  background: var(--hud-vidrio);
  border-top: 1px solid var(--hud-borde);
}

.cierre p { color: var(--tinta-suave); max-width: 52ch; }

/* --- Cierre en dos columnas: solo servicios.html -------------------------
   El handoff pedía reescribir .cierre entero a dos columnas. No se puede:
   .cierre lo comparten como-trabajamos.html y contacto.html, que ponen h2, p y
   tecla como hijos directos y dependen del centrado y del padding de la base.
   Reescribirla les sacaba el aire a las dos y las dejaba alineadas a la
   izquierda contra el borde de la ventana. El layout nuevo vive en un
   modificador y la base no se toca. */

.cierre--columnas {
  display: block;
  padding: 0;
  text-align: left;
}

/* min(300px, 100%) y no 300px pelado. El piso de un minmax() es un mínimo
   DURO: por debajo de 348px de espacio disponible el auto-fit no baja a una
   columna, mantiene las dos de 300 y el contenedor crece a 648px. Medido a
   360px de ancho: 288px de desborde horizontal, con body { overflow-x: hidden }
   tapándolo, así que la página no scrollea de costado y el defecto es
   invisible salvo que se mida el scrollWidth. Con min(...) el piso cede
   cuando el contenedor es más chico que el piso, y a 360 da una columna
   de 336. */
.cierre__interior {
  max-width: 1000px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: clamp(24px, 4vw, 48px);
  align-items: center;
  padding: var(--unidad) var(--tablero-margen);
}

.cierre__texto { display: grid; gap: calc(var(--u) * 2); }

.cierre__texto h2 { font-size: clamp(2rem, 1.4rem + 2vw, 3rem); }

.cierre__texto p { color: var(--tinta-suave); max-width: 56ch; }

.cierre__accion {
  display: grid;
  gap: calc(var(--u) * 1.75);
  justify-items: start;
}

/* Calificada con el elemento y anidada: .cierre p es 0-1-1 y le ganaba a un
   .cierre__nota de 0-1-0, así que la nota salía en --tinta-suave, o sea del
   mismo peso que el párrafo que tiene al lado. La nota es la salida de
   escape, no un segundo argumento: tiene que leerse más callada que la tecla.
   Medido en el navegador, no deducido de la hoja. */
.cierre p.cierre__nota {
  margin: 0;
  color: var(--granito);
  font-size: var(--t-menor);
  max-width: none;
}

/* Un <a> sin href no es un enlace: no se enfoca, no se activa, no tiene rol.
   El href de este lo completa chat.js en runtime desde WHATSAPP_NUMERO, que es
   la única constante del número en el repo (gate test 6), así que con los
   scripts caídos el elemento existe y no lleva a ninguna parte — y hasta acá
   se dibujaba en el mismo saffron que todos los enlaces reales de la página.
   Un señuelo, justo en la única salida a una persona. Sin href se lee como lo
   que es: texto. Con JavaScript vuelve a ser el enlace de siempre. */
.cierre__nota a:not([href]) {
  color: inherit;
  text-decoration: none;
}

/* --- Reflow de servicios.html --- */

@media (max-width: 860px) {
  .fuga__cuerpo { grid-template-columns: minmax(0, 1fr); }
  .fuga__columna p,
  .fuga__columna p.fuga__linea,
  .fuga__lista { max-width: 56ch; }
}

@media (max-width: 620px) {
  .paso {
    grid-template-columns: minmax(0, 1fr);
    gap: calc(var(--u) * 2);
  }

  /* En una columna el número es ítem de grilla y sin esto se estira al ancho
     completo: medido a 375px, una barra de 285px con "01" centrado arriba de
     cada título. El ancho fijo del chip ya lo frena; esto lo declara. */
  .paso__numero { justify-self: start; }

  .diagnostico__interior,
  .fugas__interior,
  .cierre__interior { padding-inline: calc(var(--u) * 1.5); }

  /* Declarada, no deducida. min(300px, 100%) alcanza hasta 360px, pero a 320
     el auto-fit vuelve a pedir 322px de pista y desborda 26px. Por debajo de
     620 el cierre es de una columna por definición: decirlo saca al navegador
     de la ecuación. Medido: a 320px el desborde pasa de 26px a 0. */
  .cierre__interior { grid-template-columns: minmax(0, 1fr); }

  /* El cuerpo de las cajas vuelve al piso del sitio. En una columna sola, los
     0.9375rem (15px) son el único texto de la página que baja de 16px —el
     resto, bajada y cierre incluidos, lo pisa --t-cuerpo—, y son los pasajes
     más largos que hay acá. El visitante de esta página lee en un teléfono en
     la calle (PRODUCT.md), que es el peor lugar para ahorrarse un píxel.
     Medido a 390px: 43 caracteres por línea a 15px, 40 a 16px. Los dos entran
     cómodos, así que el ahorro no compraba nada. */
  .fuga__columna p,
  .fuga__lista { font-size: var(--t-cuerpo); }

  /* La voz más larga es "No entran consultas nuevas y espero a que caigan.":
     es la que decide si la cabecera aguanta a 360px. */
  .fuga__voz { font-size: 1.0625rem; }
  .fuga__cabecera { gap: calc(var(--u) * 1.5); padding: calc(var(--u) * 2.5) calc(var(--u) * 2); }
}
