/* DB Project — componentes compartidos por más de una página. Todo lo que vive
   en una sola página va en la hoja de esa página (home.css, servicios.css…).
   Los botones están en css/base.css porque los usan las cinco. */

/* Tarjeta base: borde sutil, sin fondo sólido de color. El acento nunca es
   fondo de bloque — solo borde, texto o ícono. */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  border: 1px solid var(--db-linea);
  border-radius: var(--db-radius-card);
  /* Un escalón más claro que la página, no transparente: la tarjeta es una
     superficie, no un recorte. Sale del token para que una tarjeta dentro de un
     tramo claro no quede en grafito. */
  background: var(--db-superficie);
  transition: border-color 0.3s ease;
}
.card h3 { margin: 0; }
/* --db-gris-medio está calibrado a 4,97:1 contra el grafito de la página, pero
   la tarjeta es una superficie un escalón más clara (#24262A) y ahí el mismo
   gris cae a 4,46 — justo por debajo de AA. Sube lo mínimo para volver a
   pasarlo (4,82) sin regresar al gris claro de antes, que era el que aplanaba
   la jerarquía entre título y apoyo. */
.card p {
  margin: 0;
  color: color-mix(in srgb, var(--db-gris-claro) 15%, var(--db-gris-medio));
}

/* Cuando la tarjeta entra en pantalla en un dispositivo sin mouse, el borde se
   aclara una vez: el mismo estado visual del hover, disparado por scroll. */
.card.is-entered { border-color: color-mix(in srgb, var(--db-acento) 32%, transparent); }

/* Glowing Effect (db-project-biblioteca, references/tarjetas.md): un arco de
   luz recorre el borde y "apunta" hacia el mouse. El original usa un
   repeating-conic-gradient de cuatro colores; acá el arco es el acento del
   proyecto, que es la única forma en que ese color puede aparecer (nunca de
   fondo de bloque).

   El anillo se construye con la misma técnica de mask-composite que ya usa
   .btn--lg en css/base.css: un conic-gradient recortado al ancho del padding.
   Se reusa a propósito — es el mismo lenguaje de borde en todo el sitio.

   El ángulo lo mueve js/glow.js. Este es el tratamiento ÚNICO de tarjeta del
   sitio: antes convivían tres (arco, spotlight y tarjeta pelada) y las
   secciones no se leían como una misma mano. La elevación la agrega
   initElevacion() sobre el mismo .card. */
@property --db-glow-angulo {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

/* Mismo criterio que en .comparacion__items li: la tarjeta la anima GSAP
   (entrada "cards" + parallax de data-speed), así que su transform tiene un
   solo dueño, GSAP. La elevación del hover la aplica js/glow.js con un tween,
   no una transición de CSS. Acá solo transiciona el borde, que no es transform. */
.card {
  --db-glow-angulo: 0deg;
  --db-glow-activo: 0;
  transition: border-color 0.3s ease;
}
.card::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: conic-gradient(
    from var(--db-glow-angulo),
    transparent 0deg,
    color-mix(in srgb, var(--db-acento) 70%, transparent) 22deg,
    var(--db-acento) 34deg,
    transparent 62deg
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: var(--db-glow-activo);
  transition: opacity 0.4s ease;
  pointer-events: none;
}

/* Elevación + desplazamiento del contenido interno. El título se adelanta un
   poco más que el párrafo: adentro de la tarjeta también hay jerarquía, y que
   se muevan distinto es lo que la vuelve un objeto con capas en vez de un
   rectángulo que sube entero. */
.card:hover,
.card:focus-within,
.card.is-lit {
  border-color: color-mix(in srgb, var(--db-acento) 38%, transparent);
}
.card h3,
.card p { transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1); }
.card:hover h3,
.card:focus-within h3,
.card.is-lit h3 { transform: translateY(-3px); }
.card:hover p,
.card:focus-within p,
.card.is-lit p { transform: translateY(-1px); }

@media (prefers-reduced-motion: reduce) {
  /* Sin movimiento el borde igual responde, solo que sin viaje ni arco: el
     estado de foco tiene que existir para quien navega con teclado. */
  .card:hover h3, .card:focus-within h3, .card.is-lit h3,
  .card:hover p, .card:focus-within p, .card.is-lit p { transform: none; }
}

/* La flecha. El comentario de arriba la prometía desde hace rondas y no
   existía: el "→" era texto suelto adentro del link, sin nada que animar.
   Ahora es un <span> propio, que es lo que permite moverlo. */
.card__flecha {
  display: inline-block;
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
}
.card:hover .card__flecha,
.card:focus-within .card__flecha,
.card.is-lit .card__flecha { transform: translateX(6px); }

@media (prefers-reduced-motion: reduce) {
  .card__flecha { transition: none; }
  .card:hover .card__flecha, .card.is-lit .card__flecha { transform: none; }
}

/* Columna comparativa: encabezado de columna + lista de ítems. La usa Proceso
   ("de quién es cada cosa"), dentro de un bloque con data-reveal="cross". El
   par título+párrafo por ítem se fue con el rediseño de esa sección: ahora es
   un ítem por renglón, en tipografía grande y sin párrafos. */
.comparacion__label {
  font-size: var(--db-fs-small);
  color: var(--db-gris-medio);
  margin: 0 0 var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--db-linea);
}
.comparacion__items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-4);
}
/* Los ítems de la comparación (los usa Proceso, "De quién es cada cosa").
   OJO: este <li> lo anima GSAP (entrada por pares, js/reveals.js). No puede
   llevar `transition: transform` — serían dos dueños escribiendo el mismo
   transform, y GSAP termina leyendo un valor contaminado al fijar el destino de
   su tween. Medido: con la transición puesta, la entrada llegaba a progreso 1
   con los ítems clavados en y=26.

   El resaltado emparejado (.is-par) se fue con js/comparacion.js, que se borró
   cuando la sección 03 pasó a ser un interruptor de dos estados. Quedaban 14
   reglas que no las ponía nadie. */
.comparacion__items li {
  position: relative;
  padding-left: var(--space-3);
}


/* Cierre de página: la misma llamada final en las cinco. Es una apertura de
   sección como cualquier otra —título grande a la izquierda, algo que ancle a la
   derecha— y acá lo que ancla son las dos vías de contacto. Antes el título
   estaba contenido a 780px y tenía su propio techo de 52px para no partirse en
   cinco renglones; con la caja de dos columnas se lleva dos tercios del ancho y
   entra en el rango de la ronda sin tratamiento especial. */
.cierre__inner { max-width: none; }
.cierre__texto h2 { margin: 0 0 var(--space-3); }
.cierre__texto p { margin: 0; max-width: 46ch; }
.cierre .btn { margin-top: 0; }
@media (min-width: 900px) {
  .cierre__inner {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
    column-gap: var(--space-6);
    align-items: end;
  }
}

/* Encabezado de las cuatro páginas internas: misma forma, distinto contenido. */
.pagina-hero { padding-block: calc(var(--nav-height) + var(--space-6)) var(--space-5); }
.pagina-hero .lead { margin-top: var(--space-3); color: var(--db-gris-claro); }

/* Link de texto con flecha, con área táctil de 44px */
/* .link-flecha se fue: era el nivel 3 sin nombre. Ahora es .btn--texto. */

/* Grilla de tarjetas cortas: 1 / 2 / 4 columnas sin tocar el contenido */
.conectable__list {
  list-style: none;
  margin: var(--space-5) 0 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}
@media (min-width: 700px) { .conectable__list { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .conectable__list { grid-template-columns: repeat(4, 1fr); } }


/* ═════════════════════════════════════════════════════════════════════════════
   Lenguaje de recorrido — compartido por las páginas que numeran sus secciones.
   Vivía en css/home.css, donde sólo lo veía el Inicio. Servicios abre cada uno
   de sus cinco bloques con la misma marca y cambia de tramo con las mismas
   costuras: si cada página escribiera su versión, la numeración dejaría de ser
   un idioma del sitio y pasaría a ser una decoración por página.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Marca de recorrido ──────────────────────────────────────────────────────
   Cada sección abre con su número en mono y una etiqueta corta. El número
   coincide con el del índice lateral: son el mismo recorrido visto de dos
   formas. El hero no la lleva a propósito — poner "01 Inicio" arriba del logo
   grande le robaría el primer golpe de vista. */
/* ── La etiqueta de sección ───────────────────────────────────────────────────
   Quedan DOS en todo el sitio, las dos en Servicios. Eran 29: cada sección de
   cada página abría con un número correlativo grande en acento, una etiqueta en
   mono con espaciado de letras y una línea al costado — cinco decisiones
   tipográficas donde alcanzaba una, repetidas 29 veces. Y las 29 decían lo
   mismo que el h2 que tenían tres centímetros abajo ("Qué incluye" sobre "Todo
   lo que entra en una página").

   Las dos que sobreviven son las únicas que orientan de verdad: Servicios tiene
   DOS precios distintos —el de armado y la mensualidad— y el h2 del segundo no
   dice "mensualidad". Ahí la etiqueta agrega el dato que falta.

   Sin número y sin línea: una etiqueta chica en mono, y nada más. */
.marca {
  margin: 0 0 var(--space-3);
}
.marca__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);
}


/* Las dos franjas donde cambia el tramo. No llevan contenido: son el cambio. */
.costura {
  height: clamp(88px, 11vw, 168px);
  position: relative;
  z-index: 0;
}
.costura--a-claro { background: linear-gradient(to bottom, var(--db-grafito), var(--db-tramo-claro)); }
.costura--a-hondo { background: linear-gradient(to bottom, var(--db-tramo-claro), var(--db-tramo-hondo)); }


/* Trazo fino y coherente entre todos los dibujos del sitio. fill:none y un
   stroke explícito son obligatorios: DrawSVG sólo actúa sobre el trazo, y sin
   stroke no dibuja nada. */
.trazo {
  fill: none;
  stroke: var(--db-acento);
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}


/* La tercera costura: del tramo claro de vuelta al grafito. En el Inicio el
   claro entrega el recorrido al tono hondo (--a-hondo); en Servicios entrega a
   la letra chica, que va en grafito. Es el mismo gradiente al revés — la
   costura no es un adorno, es el lugar donde el cambio de tramo ocurre sin
   texto encima. */
.costura--a-grafito { background: linear-gradient(to bottom, var(--db-tramo-claro), var(--db-grafito)); }

/* El número en mono arriba de la tarjeta. Parte del tratamiento único de
   tarjeta —fondo, borde, radio, número, borde que se enciende— así que vive acá
   y no en la hoja de una página: lo usan las tarjetas de "queda claro" del
   Inicio y los cuatro planes de Servicios. */
.card__num {
  font-size: var(--db-fs-eti);
  letter-spacing: 0.18em;
  color: var(--db-gris-medio);
}

/* ── La barra de una ventana de navegador ─────────────────────────────────────
   Tres puntos y una barra de dirección vacía. La usan el mockup del hero y la
   ficha de proyecto del Inicio, y la vista de sitio de la planilla en Servicios.
   Vivía en css/home.css, que Servicios no carga: la barra estaba en el HTML de
   la planilla y salía sin una sola regla aplicada — un renglón gris pelado
   arriba de la ventana. Encontrado mirando la captura, no el código. */
.mockup__barra {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: var(--space-1) var(--space-2);
  border-bottom: 1px solid color-mix(in srgb, var(--db-blanco) 10%, transparent);
}
.mockup__punto {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--db-gris-medio) 45%, transparent);
}
/* La barra de dirección va vacía: escribir una URL ahí sería inventar un dato. */
.mockup__url {
  flex: 1;
  height: 16px;
  margin-left: var(--space-1);
  border-radius: 999px;
  background: color-mix(in srgb, var(--db-blanco) 6%, transparent);
}


/* ═════════════════════════════════════════════════════════════════════════════
   Recorrido horizontal pineado (.ruta) — el momento scroll-linked del sitio.
   La sección se fija en pantalla y los pasos se desplazan de costado con el
   scroll: número gigante de marca de agua, paso activo iluminado, vecinos
   apagados e insinuados a los costados, barra de progreso con salto por paso.

   Vivía en css/home.css, donde sólo lo veía el Inicio. Ahora lo usan DOS
   páginas —Inicio (05, cinco pasos en una línea cada uno) y Proceso (01, los
   mismos cinco pasos abiertos en dos columnas más la pausa)— con el mismo
   mecanismo y el mismo JS (js/ruta.js). Duplicarlo habría sido tener dos
   recorridos que se parecen en vez de uno solo que el sitio sabe hacer.

   Lo específico de cada página vive en su hoja: la forma de un paso de Proceso
   (dos columnas, la pausa) está en css/proceso.css.
   ═══════════════════════════════════════════════════════════════════════════ */


.ruta {
  /* clip y no hidden: hidden convertiría la sección en contenedor de scroll y
     rompería cualquier position:sticky que entre más adelante. */
  overflow: clip;
  /* El ancho de un panel, en un solo lugar. La pista lo usa para calcular su
     sangrado de arranque y el paso para su flex-basis: si los dos números no son
     el mismo, el primer paso no nace centrado. El Inicio lo sube (css/home.css)
     porque sus paneles llevan dos columnas más una miniatura. */
  --ruta-ancho: min(78vw, 880px);
}

/* La ESCENA es lo que se pinea, y no la sección entera. La apertura de sección
   —marca, título de 110px, datos— vive arriba en flujo normal: un título de tres
   renglones más los paneles más la barra no entran en 100svh, y un elemento
   pineado más alto que la pantalla queda con la punta fija y el resto cortado.
   Así la escena se queda con la pantalla completa, que es lo que el recorrido
   necesita para que sus paneles se lean centrados y no bajos. */
.ruta__escena {
  /* svh y no vh: en iOS la barra del navegador se come el 100vh y el recorrido
     quedaría cortado por abajo. */
  min-height: 100svh;
  /* Mientras la escena está pineada, su rótulo queda a la altura de la barra
     flotante durante TODO el recorrido, y con el padding normal quedaba con las
     letras cortadas por detrás del vidrio. --nav-clearance incluye el recorte de
     pantalla del teléfono, que es donde peor se veía. */
  padding-top: calc(var(--nav-clearance) + var(--space-3));
  padding-bottom: var(--space-5);
  overflow: clip;
  /* El pin saca la escena del flujo (position:fixed mientras dura). Sin fondo
     opaco propio y sin un contexto de apilado por encima del índice lateral, los
     huecos entre pasos dejan ver lo que scrollea detrás y el hilo pinta sobre el
     texto. */
  z-index: calc(var(--z-thread) + 1);
  background: inherit;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* El rótulo que acompaña al recorrido mientras está pineado: dice en qué sección
   estás durante todo el trayecto, sin robarle alto a la escena. */
.ruta__rotulo {
  margin: 0;
  font-size: var(--db-fs-eti);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--db-gris-medio);
}

/* width:100% es obligatorio, no decorativo, en TODO .container que sea hijo de
   .ruta__escena: .container declara margin-inline:auto, y un margin automático en el eje
   transversal DESACTIVA el estirado de un ítem flex — el contenedor pasa a
   ancho-por-contenido. Se comió dos cosas distintas: el encabezado quedaba
   centrado en la pantalla en vez de alineado con el resto del sitio, y la barra
   de progreso colapsaba a unos píxeles, porque sus botones están vacíos y no
   tienen ancho propio. Es el mismo bug que ya estaba documentado para el mockup
   del hero. */
/* El momento que rompe la grilla. Todo el sitio respeta la misma columna de
   1280px y eso es lo que lo vuelve previsible: siete secciones que empiezan y
   terminan exactamente en la misma vertical. Acá —una sola vez en toda la
   página— el contenido se suelta de esa columna y se alinea contra el borde
   real de la pantalla. A 1440 son 80px de diferencia; a 1920, 264. Combinado
   con el cambio de tramo, la 05 se lee como otro lugar y no como la sección
   que sigue. */
.ruta__escena > .container {
  width: 100%;
  max-width: none;
  padding-inline: max(var(--container-pad), env(safe-area-inset-left, 0px));
}
@media (min-width: 1024px) {
  /* 64 y no 32: el índice lateral vive fijo en la columna de 32 a 39px, y con
     el contenido a 32 la línea del índice le pasaba por encima al título. 64
     deja esa columna libre y el corte contra la grilla sigue siendo de 72px
     a 1440 y de 264 a 1920 — se ve. */
  .ruta__escena > .container { padding-inline: var(--space-6); }
}
.ruta__cab { flex-shrink: 0; }

/* El recorrido se queda con todo el alto que sobra entre el encabezado y la
   barra, y los pasos se centran ahí adentro. Antes el viewport medía sólo lo que
   medían los pasos y quedaba un hueco muerto arriba y abajo. */
.ruta__viewport {
  overflow: clip;
  flex: 1;
  display: flex;
  align-items: center;
  min-height: 0;
  /* Los bordes se desvanecen en vez de cortar en seco. La pista mide más que la
     pantalla, así que en algún punto del recorrido SIEMPRE hay un vecino
     asomando por un costado; recortarlo con un canto duro es lo que producía
     medias palabras pegadas al borde. Con la máscara, lo que llega al borde se
     apaga antes de poder leerse, sea cual sea el ancho de pantalla y la
     posición del recorrido — se arregla la causa y no un caso.
     El paso centrado nunca toca la zona de desvanecido: mide 880 como techo y
     el desvanecido llega hasta 150. */
  --ruta-fundido: clamp(40px, 9vw, 150px);
  mask-image: linear-gradient(
    to right,
    transparent 0,
    #000 var(--ruta-fundido),
    #000 calc(100% - var(--ruta-fundido)),
    transparent 100%
  );
}
.ruta__pista {
  display: flex;
  align-items: stretch;
  gap: var(--space-4);
  width: max-content;
  /* El primer paso arranca centrado, no pegado al borde: sin esto el recorrido
     empieza con el paso 01 contra el canto izquierdo y no se lee que hay algo a
     los costados. El último padding hace lo mismo del otro lado. */
  padding-inline: max(var(--container-pad), calc((100vw - var(--ruta-ancho)) / 2));
  will-change: transform;
}

/* Cada paso ocupa casi toda la pantalla, pero no toda: ese resto es lo que deja
   ver el borde del anterior y del siguiente, que es lo que da la sensación de
   recorrido en vez de la de cinco pantallas sueltas. */
.ruta__paso {
  position: relative;
  flex: 0 0 var(--ruta-ancho);
  display: flex;
  align-items: center;
  min-height: min(52svh, 440px);
  /* Sangrado propio del paso. No es decorativo: el recorrido puede quedar
     parado en cualquier posición —no hay imán que lo centre— y sin este margen
     el texto se corta contra el borde de la pantalla apenas el paso se corre un
     poco del centro. Medido en 375: el paso activo quedaba hasta 66px corrido y
     se comía la primera letra de cada línea. Con el sangrado, el texto aguanta
     entero ese desvío y bastante más.
     El número, que es absoluto, se corre con el sangrado: su caja de referencia
     es la caja de padding del paso. */
  padding-inline: var(--space-3);
  /* El estado de reposo es el de un paso APAGADO: js/ruta.js enciende el activo
     leyendo su distancia al centro. Si el JS no corre, quedan todos legibles
     (la regla de reduced-motion de más abajo los deja en 1). */
  opacity: 0.3;
  will-change: transform, opacity;
}

/* El número gigante: marca de agua detrás del texto, en el acento muy apagado.
   Es la textura de fondo de la sección entera, no un rótulo. */
.ruta__num {
  position: absolute;
  z-index: 0;
  left: -0.06em;
  top: 50%;
  transform: translateY(-50%);
  /* 17rem y no 20: a 20 el número se comía el párrafo entero en vez de quedar
     detrás de él. Sigue siendo la textura de fondo de la sección. */
  font-size: clamp(8rem, 22vw, 17rem);
  font-weight: 600;
  line-height: 0.8;
  letter-spacing: -0.06em;
  /* 20% y no 13%: a 13 el número directamente no se veía y la sección se
     quedaba sin su única textura de fondo. A 20 se percibe la forma del número
     detrás del texto sin disputarle el peso — que era el bug del zigzag
     anterior, donde el número y el texto pesaban casi igual. */
  /* El número es la TEXTURA de la sección, no un rótulo: tiene que percibirse
     detrás del texto y nunca disputarle el cuadro. Sobre el claro el acento ya
     es el oscurecido (.tramo-claro), así que pesa bastante más que el mismo
     porcentaje sobre grafito: a 26 se leía como el elemento principal y el
     título quedaba atrás. 15 es donde se ve la forma sin ganarle al texto. */
  color: color-mix(in srgb, var(--db-acento) 15%, transparent);
  pointer-events: none;
  user-select: none;
  will-change: transform, opacity;
}

.ruta__texto {
  position: relative;
  z-index: 1;
  max-width: 46ch;
  /* El texto se corre a la derecha del número para que el número se lea como
     fondo y no como una letra pegada a la palabra. */
  margin-left: clamp(var(--space-4), 9vw, 148px);
}
.ruta__texto h3 {
  margin: 0 0 var(--space-2);
  /* Nivel 3 del sistema, como cualquier título de bloque. Valía 44px, que es
     tamaño de apertura de sección: un paso compitiendo con el título de la
     página es lo que hacía que nada resaltara. El peso del paso lo da su
     cuerpo, no su título. */
  font-size: var(--db-fs-h3);
  letter-spacing: -0.025em;
  line-height: 1.1;
}
/* Tamaño de lectura real, no chico: era la queja concreta del zigzag anterior. */
.ruta__texto p {
  margin: 0;
  font-size: clamp(1rem, 1.15vw, 1.1875rem);
  color: var(--db-gris-claro);
}

/* El cierre del recorrido: más angosto que un paso, porque es un remate, no un
   sexto paso. Y con aire propio a los dos lados: pegado al paso 05, el botón se
   leía como una parte más de ese paso en vez de como el final del recorrido.
   El aire va en margin-inline y no en el padding del paso, para que el sangrado
   del texto (que protege del recorte contra el borde) siga midiendo lo mismo. */
.ruta__paso--final {
  flex-basis: min(52vw, 460px);
  justify-content: center;
  margin-inline: var(--space-6);
}
/* El cuerpo del cierre es un envoltorio y no decoración: js/ruta.js apaga el
   TEXTO de cada paso por separado del paso entero, y este panel necesita el
   mismo gancho que .ruta__texto para que su remate tampoco se lea a medias
   contra el borde. */
.ruta__final-cuerpo {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-4);
}
/* Si alguien llega con el teclado a un paso que todavía no está centrado, ese
   paso se enciende entero. Sin esto el foco puede aterrizar en un link con
   opacidad 0 — invisible pero enfocado, que es peor que no poder alcanzarlo. */
.ruta__paso:focus-within .ruta__texto,
.ruta__paso:focus-within .ruta__final-cuerpo { opacity: 1 !important; }
.ruta__final-txt {
  margin: 0;
  font-size: clamp(1.25rem, 2vw, 1.75rem);
  font-weight: 600;
  color: var(--db-texto-sobre-oscuro);
  max-width: 16ch;
}

/* ── La barra de progreso ─────────────────────────────────────────────────── */
.ruta__barra {
  position: relative;
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}
.ruta__barra-pista {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 2px;
  transform: translateY(-50%);
  background: color-mix(in srgb, var(--db-gris-medio) 42%, transparent);
  pointer-events: none;
}
.ruta__barra-fill {
  position: absolute;
  inset: 0;
  background: var(--db-acento);
  transform: scaleX(0);
  transform-origin: left;
  will-change: transform;
}
/* Cada tramo es un botón. El área táctil es de 44px de alto aunque la línea sea
   de 1px: en un recorrido horizontal esto es lo único que permite volver a un
   paso, y tiene que poder tocarse con el pulgar. */
/* 44 cumplía WCAG pero no el piso del sitio, que es 48 en desktop y 52 en
   mobile. Son cinco controles de navegación del recorrido y valen lo mismo que
   cualquier otro botón: medidos, daban 44 en los dos anchos. */
.ruta__salto {
  flex: 1;
  min-height: 52px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  display: grid;
  align-items: center;
}
@media (min-width: 1024px) { .ruta__salto { min-height: 48px; } }
.ruta__salto-linea {
  display: block;
  height: 3px;
  border-radius: 2px;
  background: transparent;
  transition: background-color 0.3s ease;
}
.ruta__salto:hover .ruta__salto-linea,
.ruta__salto:focus-visible .ruta__salto-linea { background: var(--db-linea-fuerte); }
/* El tramo marcado va en acento bajado y el relleno en pleno: los dos son la
   misma barra de progreso, y el que informa "cuánto llevás" es el relleno. */
.ruta__salto[aria-current="true"] .ruta__salto-linea { background: color-mix(in srgb, var(--db-acento) 62%, transparent); }
.ruta__salto:focus-visible { outline: 2px solid var(--db-acento); outline-offset: 2px; }

@media (max-width: 899px) {
  /* En mobile el paso se ensancha (queda menos margen para vecinos, pero se
     siguen insinuando) y el número BAJA de tamaño: a 26vw tapaba el texto en
     vez de quedar detrás. El texto deja de correrse a la derecha y el número
     pasa a estar arriba, fuera de su camino. */
  /* 76vw y no 84: sin imán que centre los pasos, el recorrido puede quedar
     parado a mitad de camino, y con pasos casi tan anchos como la pantalla eso
     se lee como un texto cortado. A 76vw hay 12vw de aire a cada lado: el paso
     que llega se anuncia antes, el que se va sigue insinuado, y el conjunto se
     lee como un recorrido con vecinos —que es lo que es— en vez de como una
     sola pantalla mal encuadrada. */
  .ruta__paso { flex-basis: 76vw; align-items: flex-start; }
  .ruta__pista { padding-inline: max(var(--container-pad), calc((100vw - 76vw) / 2)); }
  .ruta__num { font-size: clamp(5rem, 22vw, 8rem); top: 0; transform: none; left: 0; }
  .ruta__texto { margin-left: 0; margin-top: clamp(var(--space-5), 15vw, 96px); }
  .ruta__paso--final { flex-basis: 72vw; margin-inline: var(--space-4); }
}

/* La tira que se arrastra: el recorrido sin pin. La clase la pone js/ruta.js en
   dos casos —sin movimiento, y en pantalla angosta, donde la geometría del pin no
   cierra— así que las reglas NO cuelgan de una media query: cuelgan de la clase,
   que es quien sabe cuál de los dos casos es.
   La barra de progreso se queda: con la tira, sus botones son la navegación. */
.ruta--quieta .ruta__viewport {
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}
.ruta--quieta .ruta__viewport::-webkit-scrollbar { display: none; }
.ruta--quieta .ruta__paso { opacity: 1; scroll-snap-align: center; }
/* Sin scrub que la llene, la barra pierde su relleno y se queda con las marcas,
   que es lo único que en la tira sigue diciendo algo. */
.ruta--quieta .ruta__barra-fill { display: none; }
/* La escena deja de tener que entrar entera en la pantalla: sin pin, puede medir
   lo que mida su contenido. */
.ruta--quieta .ruta__escena { min-height: 0; }


/* ── Cierre de dos vías ──────────────────────────────────────────────────
   Lo usan Servicios y Proceso: un solo llamado con dos vías, con el mismo idioma de botón que el resto del
   sitio: relleno con el acento y el ícono de WhatsApp, borde y el ícono de
   sobre. Las tres cifras de compromiso no se repiten — ya están en el Inicio y
   en Contacto. */
/* Las dos vías de contacto, apiladas en la columna del ancla. Antes iban en fila
   debajo del título, contenidas a 780px, y se partían en dos renglones por nueve
   píxeles de diferencia. Apiladas y al costado del título no dependen del largo
   de las etiquetas. */
.cierre__acciones {
  display: grid;
  gap: var(--space-2);
  justify-items: start;
  margin-top: var(--space-5);
}
@media (min-width: 900px) {
  .cierre__acciones { margin-top: 0; justify-items: stretch; }
}
.cierre__acciones .btn { margin-top: 0; }


/* ═════════════════════════════════════════════════════════════════════════════
   APERTURA DE SECCIÓN — la composición de dos partes que reemplaza al título
   solo. Es la corrección de fondo del sitio: hasta acá cada sección abría con
   su marca y un h2 de tamaño medio en el medio de un cuadro vacío, y eso es
   exactamente lo que se lee como "un título tirado en el aire". No se arregla
   subiendo el tamaño solo: un título de 110px solo en un fondo liso es un
   título tirado en el aire más grande.

   Son dos partes y ninguna es opcional:
     izquierda  la marca (número gigante en mono + etiqueta) y el título grande
     derecha    algo que ANCLE — un dato en número grande, una miniatura, o
                directamente el primer ítem del contenido de la sección subido
                a esa altura

   Sin lado derecho, el título se limita a dos tercios del ancho (.apertura--sola)
   y el tercio que sobra lo ocupa el primer contenido. Nunca un título centrado
   con aire alrededor.
   ═══════════════════════════════════════════════════════════════════════════ */

.apertura {
  display: grid;
  gap: var(--space-5);
  /* En mobile las dos partes se apilan y el ancla queda debajo del título. No se
     esconde: el dato que ancla la composición es también el dato más buscado de
     varias de estas secciones (los precios, la cantidad de proyectos), y
     esconderlo en el celular sería esconder justo eso. */
  margin-bottom: var(--space-6);
}
/* El h2 de la apertura NO lleva el margin-block de h2: el aire debajo lo pone
   .apertura, y el de arriba ya lo puso .marca. */
.apertura h2 { margin: 0; }
/* minmax(0, …) en las dos: sin el 0 de mínimo, una palabra larga del título o
   un número grande en el ancla fijan un mínimo de contenido y la columna deja
   de poder encogerse — que es el desborde horizontal clásico de un grid. */
.apertura__titulo { min-width: 0; }
.apertura__ancla { min-width: 0; }
/* El ancla apila datos y, a veces, un botón. Entre dato y dato la separación la
   pone `.dato + .dato`; el botón no la tenía y quedaba pegado al ras de la
   etiqueta de arriba: medido a 1440, el borde de "Ver todos los precios"
   arrancaba en el mismo píxel donde terminaba "SITIO WEB, DESDE" — 0px de aire,
   y se lee como una sola pieza rota. */
.apertura__ancla > .btn { margin-top: var(--space-4); }

@media (min-width: 900px) {
  .apertura {
    grid-template-columns: minmax(0, 1.65fr) minmax(0, 1fr);
    column-gap: var(--space-6);
    /* El ancla se apoya en la base del título, no en su tope: la composición se
       lee como un pie de página del título y no como dos bloques sueltos. */
    align-items: end;
  }
  /* Sin lado derecho: dos tercios de ancho y alineado a la izquierda. */
  .apertura--sola { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
}

/* ── Cuando el título es largo ────────────────────────────────────────────────
   A 110px, en una columna de 690px, entran doce caracteres por renglón. Un
   título de ocho palabras sale en cinco renglones de dos y deja de leerse como
   una frase: se lee como una lista. Los títulos de más de unos cuarenta
   caracteres bajan el techo a 84px —adentro del mismo rango— y vuelven a entrar
   en tres renglones.
   No es una excepción a la escala: es la escala respondiendo al largo del texto,
   que es lo que hace cualquier título bien puesto. Sólo toca desktop, que es
   donde el problema existe: abajo de 1024 el título ya entra bien. */
@media (min-width: 1024px) {
  /* Por NIVEL y no una medida sola para los dos: .titulo-largo se usa tanto en
     el h1 de Proyectos como en los h2 de sección de las otras páginas, así que
     un único font-size acá los volvería a igualar y devolvería el problema que
     la escala de tres niveles vino a resolver. Cada uno conserva su rampa y
     sólo baja el techo, que es lo que pedía el caso: el mismo rango, más corto.
       h1 largo · 1024 → 64px · techo 80 (en vez de 96)
       h2 largo · 1024 → 40px · techo 48 (en vez de 56) */
  h1.titulo-largo { font-size: clamp(4rem, -0.923rem + 7.692vw, 5rem); }
  h2.titulo-largo { font-size: clamp(2.5rem, 0.038rem + 3.846vw, 3rem); }
}

/* ── El ancla: uno o varios datos en número grande y mono ─────────────────────
   El número no compite con el título por tamaño —es la mitad— pero sí por
   material: mono contra sans, tabular contra proporcional. Esa diferencia es lo
   que lo hace leer como un dato y no como un subtítulo. */
.dato {
  display: block;
  border-top: 1px solid var(--db-linea);
  padding-top: var(--space-2);
}
.dato + .dato { margin-top: var(--space-4); }
.dato__num {
  display: block;
  font-family: var(--db-font-mono);
  font-size: clamp(2rem, 3.4vw, 3.25rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--db-texto-sobre-oscuro);
  font-variant-numeric: tabular-nums;
}
/* El acento se reserva para UN dato por sección: el que la sección quiere que
   se lleve la vista. Los demás van en blanco. */
.dato--foco .dato__num { color: var(--db-acento); }
.dato__eti {
  display: block;
  margin-top: var(--space-1);
  font-family: var(--db-font-mono);
  font-size: var(--db-fs-eti);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--db-gris-medio);
}


/* ═════════════════════════════════════════════════════════════════════════════
   FICHA DESPLEGABLE — el panel de detalle. Un solo componente para sus diez
   usos: las tres tarjetas de confianza del Inicio, los tres formatos de
   Servicios y los cuatro planes de mensualidad.

   Es un <dialog> nativo, no un div con clase. Esa elección resuelve gratis y
   sin una línea de JS cuatro de las cinco cosas que pide la spec: el foco
   atrapado adentro, el cierre con Escape, la devolución del foco al elemento
   que la abrió, y el resto de la página inerte para el lector de pantalla.
   Reconstruir eso a mano son ~60 líneas que se rompen en el primer caso raro.

   Mecánica de entrada portada de "Animated Modal" (db-project-biblioteca,
   references/overlays-utilidades.md): overlay que se opaca y desenfoca mientras
   la caja entra. En el original la caja entra rotando desde el centro; acá entra
   desde el borde derecho, porque lo que se abre es una ficha de detalle al lado
   de lo que se estaba leyendo, no un cartel que interrumpe.
   ═══════════════════════════════════════════════════════════════════════════ */

.ficha {
  /* El <dialog> por defecto se centra y se encoge al contenido. Acá es un panel
     al borde: margen 0 en tres lados y auto en el que sobra. */
  margin: 0 0 0 auto;
  padding: 0;
  border: 0;
  max-width: none;
  max-height: none;
  width: min(560px, 100%);
  height: 100%;
  /* 68ch de ancho de lectura adentro, no acá: el panel llega al borde de la
     pantalla y el texto se contiene con padding. */
  background: var(--db-superficie);
  color: var(--db-texto-sobre-oscuro);
  border-left: 1px solid var(--db-linea-fuerte);
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* El tramo del que salió la ficha manda su material. Una ficha abierta desde el
   tramo claro con el fondo del tramo oscuro se lee como otra página. */
.ficha--claro {
  /* Se repiten los tokens de .tramo-claro y no se reusa la clase: un <dialog>
     en la capa superior no es descendiente de la sección que lo abrió, así que
     no hereda nada de ella. */
  --db-texto-sobre-oscuro: var(--db-texto-sobre-claro);
  --db-gris-claro: var(--db-texto-secundario-sobre-claro);
  --db-gris-medio: var(--db-texto-secundario-sobre-claro);
  --db-acento: var(--db-acento-sobre-claro);
  --db-linea: color-mix(in srgb, var(--db-grafito) 14%, transparent);
  --db-linea-fuerte: color-mix(in srgb, var(--db-grafito) 30%, transparent);
  --db-superficie: var(--db-tramo-claro);
}
.ficha::backdrop {
  background: color-mix(in srgb, #0B0C0E 72%, transparent);
  /* El desenfoque va acá y no en el contenido: ::backdrop es la única capa fija
     de todo el mecanismo, que es la condición para que un backdrop-filter no
     cueste un repintado por frame de scroll. */
  backdrop-filter: blur(6px);
}

.ficha__inner {
  padding: var(--space-6) var(--space-4) var(--space-6);
  display: grid;
  gap: var(--space-3);
}
@media (min-width: 600px) {
  .ficha__inner { padding: var(--space-6) var(--space-5); }
}
.ficha__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;
}
/* El título de la ficha no toma --db-fs-h2: adentro de un panel de 560px, 110px
   son dos palabras por renglón. Es el título de un detalle, no de una sección. */
.ficha__titulo {
  font-size: clamp(1.5rem, 3.4vw, 2rem);
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0;
}
.ficha__sub {
  font-family: var(--db-font-mono);
  font-size: var(--db-fs-small);
  color: var(--db-acento);
  margin: 0;
}
.ficha h4 {
  font-size: var(--db-fs-eti);
  font-family: var(--db-font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--db-gris-medio);
  font-weight: 500;
  margin: var(--space-3) 0 0;
}
.ficha p { margin: 0; color: var(--db-gris-claro); }

/* La cruz. Sticky y no absolute: el panel scrollea, y una cruz absoluta se va
   con el contenido justo cuando alguien que llegó al final la necesita. */
.ficha__cerrar {
  position: sticky;
  top: 0;
  z-index: 1;
  justify-self: end;
  /* Se sale del padding del inner para quedar en la esquina real del panel. */
  margin: calc(var(--space-6) * -1 + var(--space-2)) calc(var(--space-2) * -1) 0 0;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--db-linea);
  border-radius: 10px;
  background: var(--db-superficie);
  color: var(--db-texto-sobre-oscuro);
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease;
}
.ficha__cerrar:hover { border-color: var(--db-acento); color: var(--db-acento); }
.ficha__cerrar::before,
.ficha__cerrar::after {
  content: "";
  position: absolute;
  width: 15px;
  height: 1.5px;
  background: currentColor;
}
.ficha__cerrar::before { transform: rotate(45deg); }
.ficha__cerrar::after  { transform: rotate(-45deg); }

/* En mobile entra desde abajo y ocupa casi toda la pantalla. dvh y no vh: con
   vh, la barra del navegador de iOS se come el último tramo del panel y la
   cruz —o el final del texto— queda debajo del borde. */
@media (max-width: 599px) {
  .ficha {
    margin: auto 0 0;
    width: 100%;
    height: 92dvh;
    border-left: 0;
    border-top: 1px solid var(--db-linea-fuerte);
    border-radius: var(--db-radius-card) var(--db-radius-card) 0 0;
  }
}

/* Texto que existe para el lector de pantalla y no se pinta. clip-path sobre
   una caja de 1px, no display:none ni visibility:hidden: esas dos lo sacan
   también del árbol de accesibilidad, que es justo lo contrario de lo que se
   busca. */
.solo-lectores {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── El objetivo es la tarjeta entera ────────────────────────────────────────
   Un enlace (o un botón) que vive dentro del título y estira su área hasta
   cubrir la tarjeta completa. Vivía sólo en css/home.css como .card__todo, para
   los tres formatos del Inicio; ahora lo usan también los formatos de Servicios
   y las cuatro tarjetas de entrega de Proceso, así que baja acá.

   REQUISITO DEL PATRÓN, y es el que se rompe siempre: entre el contenedor de la
   tarjeta y este elemento NO puede haber nada posicionado. El ::after se
   resuelve contra el ancestro posicionado más cercano, así que si el título —o
   el propio botón— lleva position:relative, el área se estira sobre esos 200px
   de texto y no sobre la tarjeta. Medido en Servicios y en Proceso: los cinco
   puntos de prueba daban ✗ salvo el que caía justo encima del texto.
   Por eso el elemento estirado va DENTRO del título (que queda estático) y no
   es el botón visible del pie, que sí está posicionado por sus propios efectos. */
.todo-clic {
  color: inherit;
  text-decoration: none;
  font: inherit;
  letter-spacing: inherit;
  background: none;
  border: 0;
  padding: 0;
  text-align: inherit;
  cursor: pointer;
}
.todo-clic::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Por encima de lo decorativo (miniaturas, números de agua): sin esto queda
     un hueco en el medio de la tarjeta que no responde al toque. */
  z-index: 3;
  border-radius: inherit;
}
/* El foco se dibuja sobre la tarjeta entera y no sobre el texto del título:
   quien tabula tiene que ver qué se va a activar, y lo que se activa es la
   tarjeta. El :has() va en cada contenedor, abajo. */
.todo-clic:focus-visible { outline: none; }

/* El pie de la tarjeta deja de ser un enlace propio cuando la tarjeta entera ya
   lo es: dos objetivos al mismo destino son dos paradas de tabulador para una
   sola acción. Queda como señal visual, en un <span>. */
.card__cta { pointer-events: none; }

/* Variante en capa. Hace falta cuando entre la tarjeta y el título hay un
   elemento con transform —un parallax de data-speed, por ejemplo—: un transform
   crea bloque contenedor, así que el ::after del título se estira sobre la
   columna de texto y no sobre la tarjeta. La capa es el enlace mismo, colgado
   como hijo directo de la tarjeta, fuera de todo lo que se mueva. */
.todo-clic--capa {
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
}
.todo-clic--capa::after { content: none; }

/* ── .ver-mas · el nivel 2 aplicado, no un cuarto nivel ──────────────────────
   Antes esto era un cuarto nivel de botón sin nombre: texto en acento con un
   subrayado que se dibuja, o sea EXACTAMENTE el idioma de .btn--texto, a 44px,
   en 22 lugares del sitio. Por eso "los botones se ven todos iguales" y por eso
   "ver qué incluye" y "ver el detalle" eran incómodos de tocar: no eran chicos
   por decisión, eran chicos porque nunca entraron al sistema.

   Ahora .ver-mas ES el nivel 2 (contorno, sin relleno, mismo alto que el
   primario). Sigue siendo secundario por su TRATAMIENTO —no tiene relleno de
   acento— y no por su tamaño.

   Pieza: db-project-biblioteca, references/botones-formularios.md, entrada
   "Brillo de borde en botón", variante 3 "Hover Border Gradient": el borde se
   enciende desde un lado en vez de dar la vuelta. Es la misma pieza que ya usa
   .btn--ghost, que es justamente el punto: un solo nivel, un solo tratamiento. */
.ver-mas {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: 48px;
  padding: 0 var(--space-3);
  border: 2px solid color-mix(in srgb, var(--db-blanco) 42%, transparent);
  border-radius: 10px;
  background: none;
  font-family: inherit;
  font-size: var(--db-fs-body);
  font-weight: 500;
  color: var(--db-texto-sobre-oscuro);
  cursor: pointer;
  position: relative;
  transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
/* Sobre el tramo claro, mismo criterio que .btn--ghost. */
.tramo-claro .ver-mas {
  border-color: color-mix(in srgb, var(--db-grafito) 38%, transparent);
  color: var(--db-texto-sobre-claro);
}
.ver-mas:hover,
.ver-mas:focus-visible {
  border-color: var(--db-acento);
  color: var(--db-acento);
  background: color-mix(in srgb, var(--db-acento) 10%, transparent);
}
.tramo-claro .ver-mas:hover,
.tramo-claro .ver-mas:focus-visible {
  border-color: var(--db-acento-sobre-claro);
  color: var(--db-acento-sobre-claro);
}

/* EL ARREGLO DEL BOTÓN ROTO DE PROCESO.
   En Proceso el "Ver el detalle" no es el control: el control es la tarjeta
   entera (.todo-clic dentro del <h3>), y este elemento es un <span> con
   aria-hidden y pointer-events:none. Medido con sonda: hover sobre él no
   cambiaba NI el color NI el signo — color idéntico antes y después. O sea,
   parecía un botón, se podía tocar (el área de la tarjeta lo cubre), y no
   acusaba recibo de nada. Eso es lo que se reporta como "no funciona".
   Sigue sin ser un control —dos paradas de tabulador para una sola acción es
   peor— pero ahora responde: lo enciende la tarjeta que sí lo es. */
.card:hover .ver-mas,
.card:focus-within .ver-mas,
.card:has(.todo-clic:focus-visible) .ver-mas {
  border-color: var(--db-acento);
  color: var(--db-acento);
  background: color-mix(in srgb, var(--db-acento) 10%, transparent);
}
.tramo-claro .card:hover .ver-mas,
.tramo-claro .card:focus-within .ver-mas,
.tramo-claro .card:has(.todo-clic:focus-visible) .ver-mas {
  border-color: var(--db-acento-sobre-claro);
  color: var(--db-acento-sobre-claro);
}
/* El signo. Un + que no gira ni se convierte en nada: la ficha no se despliega
   en su lugar, se abre al costado, y un + que rota a × prometería lo otro. */
.ver-mas__mas {
  font-family: var(--db-font-mono);
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
.ver-mas:hover .ver-mas__mas,
.card:hover .ver-mas .ver-mas__mas { transform: translateX(3px); }

/* El piso de 52 en teléfono. Va repetido acá y no sólo en css/base.css porque
   components.css se carga después y la regla de .ver-mas de arriba, con la
   misma especificidad, le ganaba: medido, los 11 "ver qué incluye"/"ver el
   detalle" quedaban en 48 en 375px. */
@media (max-width: 599px) {
  .ver-mas { min-height: 52px; }
}

/* ── .ver-mas--todo · la tarjeta entera, sin un segundo control ───────────────
   El patrón .todo-clic resuelve "toda la tarjeta es tocable" poniendo un botón
   invisible dentro del <h3> y dejando el "Ver el detalle" del pie como un <span>
   inerte. Funciona para el toque, pero deja el elemento que DICE la acción sin
   ser la acción: no se enfoca, no tiene aria-expanded, y el lector de pantalla
   nunca oye "Ver el detalle".

   Esta variante hace lo mismo con una sola pieza: el botón visible del pie es el
   control de verdad —enfocable, con nombre accesible, con aria-expanded— y
   además estira su área hasta cubrir la tarjeta. Un solo control, una sola
   parada de tabulador, y el área completa.

   REQUISITO: la tarjeta tiene position:relative y el botón queda ESTÁTICO. El
   ::after se resuelve contra el ancestro posicionado más cercano; si el botón se
   posiciona a sí mismo, el área se estira sobre sus propios 200px y no sobre la
   tarjeta. Es el mismo requisito que ya documenta .todo-clic más abajo. */
.ver-mas--todo { position: static; }
.ver-mas--todo::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Por encima de lo decorativo (número de agua, miniaturas) y por debajo de
     nada: en estas tarjetas no hay otro control. */
  z-index: 3;
  border-radius: inherit;
}
/* El foco se dibuja sobre la tarjeta entera: lo que se activa es la tarjeta. */
.ver-mas--todo:focus-visible { outline: none; }
.card:has(.ver-mas--todo:focus-visible) {
  outline: 2px solid var(--db-acento);
  outline-offset: 4px;
}
.tramo-claro .card:has(.ver-mas--todo:focus-visible) { outline-color: var(--db-grafito); }
/* El contenido de la tarjeta queda por encima del número de agua pero por debajo
   del área del botón, para que el centro de la tarjeta también responda. */
.card:has(.ver-mas--todo) > :not(.ver-mas) { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  .ver-mas, .ver-mas__mas { transition: none; }
  .ficha::backdrop { backdrop-filter: none; }
}


/* ═════════════════════════════════════════════════════════════════════════════
   MINIATURAS DE INTERFAZ — reemplazan a TODOS los íconos y dibujos del sitio.

   Los dibujos de línea abstractos fallaron dos veces y los íconos de servicios
   sacaban profesionalidad, y el diagnóstico de las dos veces es el mismo: lo
   abstracto dibujado con líneas no dice nada sobre un producto. Lo único de este
   tipo que funcionó en el sitio es el mockup del hero — una ventana de navegador
   con una web armándose adentro. Estas miniaturas son ese mismo lenguaje,
   aplicado a los tres formatos que se venden:

     landing  una página larga, bloques apilados, un solo botón al final
     web      una ventana con menú arriba y tres páginas unidas por líneas
     tienda   una grilla de productos y un carrito que suma

   No son ilustraciones de un producto: son la ESTRUCTURA del producto a escala.
   Todo lo que hay adentro es un rectángulo o una línea con una medida exacta —
   nada sombreado, nada en perspectiva, nada que imite un dibujo.

   Un solo componente en dos tamaños (.mini y .mini--grande): lo usan la sección
   de formatos del Inicio y la de Servicios.
   ═══════════════════════════════════════════════════════════════════════════ */

.mini {
  width: 100%;
  max-width: 260px;
  aspect-ratio: 4 / 3;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--db-linea-fuerte);
  border-radius: 10px;
  background: var(--db-superficie);
  /* clip y no hidden: hidden convierte al elemento en contenedor de scroll. Acá
     no hay sticky adentro, pero la regla del sitio es una sola. */
  overflow: clip;
}
.mini--grande { max-width: 480px; }

/* ── La miniatura tiene que leerse como una interfaz, no como un esqueleto ────
   En Servicios la columna izquierda de los tres formatos se leía vacía, y no era
   que faltara la miniatura: estaba, pero todas sus piezas eran del mismo gris,
   así que el dibujo entero era una escala de grises sin ninguna jerarquía. Un
   wireframe gris no dice "esto es una landing"; dice "acá no hay nada".
   Se le da el mismo idioma que al mockup del hero, que sí se lee: la pieza
   principal en acento (es la que el formato promete), las acciones en acento
   pleno, y el resto del esqueleto apagado. Es un cambio de peso, no de forma. */
.mini--grande .mini__pieza--fuerte {
  background: color-mix(in srgb, var(--db-acento) 34%, var(--db-grafito));
}
.mini--grande .mini__accion {
  background: var(--db-acento);
}
.mini--grande .mini__cuerpo { background: color-mix(in srgb, var(--db-blanco) 10%, var(--db-grafito)); }
.mini__cuerpo {
  flex: 1;
  min-height: 0;
  padding: 9%;
  display: grid;
  gap: 6%;
}
/* Los rectángulos de estructura. Dos pesos: el gris es esqueleto, el que lleva
   .mini__pieza--fuerte es contenido que ya llegó. */
.mini__pieza {
  border-radius: 3px;
  background: color-mix(in srgb, var(--db-gris-medio) 26%, transparent);
}
.mini__pieza--fuerte { background: color-mix(in srgb, var(--db-gris-medio) 52%, transparent); }
/* Lo único con acento en las tres miniaturas es la ACCIÓN: el botón de la
   landing, el punto que recorre las páginas de la web, el carrito de la tienda.
   Un acento por miniatura, igual que un acento por sección. */
.mini__accion { background: var(--db-acento); border-radius: 3px; }

/* ── landing ────────────────────────────────────────────────────────────────
   Cinco filas de alturas distintas: un encabezado alto, dos tramos de texto, un
   par de columnas, y el botón. El botón NO ocupa el ancho: es chico y está
   centrado al final, que es el argumento de una landing — todo el recorrido
   empuja a una sola acción. */
.mini--landing .mini__cuerpo { grid-template-rows: 2.4fr 0.8fr 0.8fr 1.6fr auto; }
.mini--landing .mini__par {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6%;
}
.mini--landing .mini__accion {
  /* aspect-ratio y no una altura en px: la miniatura existe en dos tamaños, y
     una medida fija dejaría el botón de la grande flaco. La altura sale del
     ancho, así las dos versiones son la misma forma escalada. */
  aspect-ratio: 6 / 1;
  width: 42%;
  justify-self: center;
}

/* ── web ────────────────────────────────────────────────────────────────────
   El menú arriba (cuatro pastillas), y debajo tres páginas unidas por dos
   líneas. Las uniones son hairlines de 1px con transform-origin a la izquierda:
   se "dibujan" con scaleX, sin DrawSVG y sin una petición de red. */
.mini--web .mini__cuerpo { grid-template-rows: auto 1fr; align-content: start; }
.mini--web .mini__menu {
  display: flex;
  gap: 5%;
}
.mini--web .mini__menu .mini__pieza { aspect-ratio: 8 / 1; flex: 1; }
.mini--web .mini__paginas {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: center;
  gap: 9%;
}
.mini--web .mini__pagina {
  aspect-ratio: 3 / 4;
  border: 1px solid color-mix(in srgb, var(--db-gris-medio) 45%, transparent);
  border-radius: 3px;
  /* Las tres páginas se insinúan con dos renglones adentro: sin eso son tres
     cuadrados y podrían ser cualquier cosa. */
  background:
    linear-gradient(to bottom,
      transparent 22%, color-mix(in srgb, var(--db-gris-medio) 34%, transparent) 22% 30%,
      transparent 30% 46%, color-mix(in srgb, var(--db-gris-medio) 34%, transparent) 46% 54%,
      transparent 54%);
}
.mini--web .mini__union {
  position: absolute;
  top: 50%;
  height: 1px;
  background: color-mix(in srgb, var(--db-gris-medio) 55%, transparent);
  transform-origin: left center;
}
.mini--web .mini__union--a { left: 30.3%; width: 9%; }
.mini--web .mini__union--b { left: 60.6%; width: 9%; }
/* El punto que recorre las uniones. Nace invisible: sólo existe mientras dura el
   gesto, igual que el punto de los dibujos que reemplaza. */
.mini--web .mini__punto {
  position: absolute;
  top: 50%;
  left: 30.3%;
  width: 5px;
  height: 5px;
  margin-top: -2.5px;
  border-radius: 50%;
  background: var(--db-acento);
  opacity: 0;
}

/* ── tienda ─────────────────────────────────────────────────────────────────
   Una grilla de seis productos y, arriba a la derecha, el carrito con su
   cuenta. La cuenta es un contador de verdad: dos dígitos apilados en una
   ventana recortada que ruedan de 0 a 1 cuando el producto entra. */
.mini--tienda .mini__cuerpo { grid-template-rows: auto 1fr; }
.mini--tienda .mini__cabecera {
  display: flex;
  align-items: center;
  gap: 5%;
}
.mini--tienda .mini__cabecera .mini__pieza { aspect-ratio: 12 / 1; flex: 1; }
.mini--tienda .mini__carrito {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 2px 5px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--db-acento) 22%, transparent);
  border: 1px solid var(--db-acento);
}
.mini--tienda .mini__carrito-caja {
  width: 7px;
  height: 6px;
  border: 1px solid var(--db-acento);
  border-top: 0;
  border-radius: 0 0 2px 2px;
}
.mini--tienda .mini__cuenta {
  position: relative;
  display: block;
  width: 6px;
  height: 10px;
  overflow: clip;
  font-family: var(--db-font-mono);
  font-size: 9px;
  line-height: 10px;
  font-weight: 600;
  color: var(--db-acento);
}
.mini--tienda .mini__cuenta b {
  position: absolute;
  inset-inline: 0;
  top: 0;
  font-weight: inherit;
}
/* El dígito de destino nace fuera de la ventana. Sin JS la cuenta dice 0, que es
   el estado verdadero de un carrito vacío. */
.mini--tienda .mini__cuenta b[data-v="b"] { transform: translateY(100%); }
.mini--grande .mini__cuenta { font-size: 11px; }
.mini--grande .mini__carrito-caja { width: 9px; height: 8px; }
.mini--tienda .mini__grilla {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: 6%;
}
.mini--tienda .mini__producto {
  border-radius: 3px;
  background: color-mix(in srgb, var(--db-gris-medio) 30%, transparent);
}
/* El producto que salta al carrito. Va relativo y con z-index para pasar por
   encima de sus vecinos durante el salto en vez de por debajo. */
.mini--tienda .mini__producto--salta {
  position: relative;
  z-index: 1;
  background: color-mix(in srgb, var(--db-gris-medio) 58%, transparent);
}


/* ═════════════════════════════════════════════════════════════════════════════
   EL MAPA — la Argentina, dibujada acá, sin ningún recurso externo.

   Antes había un permiso para cargar el mapa de Google, y antes de eso una
   silueta de Entre Ríos sola. Las dos fallaban por lo mismo: la silueta de una
   provincia no se reconoce si no sabés de antemano qué estás mirando, y un mapa
   que hay que aceptar para ver es un mapa que la mayoría no ve.

   El país sí se reconoce de un vistazo, y recién ahí el punto significa algo.
   El contorno son coordenadas reales simplificadas con corrección de ancho por
   el coseno de la latitud media; el punto está en la posición real de Paraná,
   calculada con la misma proyección.

   Mecánica del marcador portada de "World Map" (db-project-biblioteca,
   references/canvas-3d.md): territorio en SVG más un marcador con pulso tipo
   radar. En el original el pulso es un <animate> de SVG; acá son dos anillos en
   CSS que escalan y se apagan — transform y opacity, nada más.
   El trazado del contorno al entrar es stroke-dashoffset, que es la misma idea
   que DrawSVG sin necesitar el plugin: es un solo path cerrado.
   ═══════════════════════════════════════════════════════════════════════════ */

.mapa {
  margin: 0;
  display: grid;
  justify-items: center;
  gap: var(--space-3);
}
.mapa__svg {
  /* El alto manda y el ancho sale de él: el país es muy vertical, así que
     fijando el ancho el dibujo quedaba chiquito en una caja alta y con la mitad
     del bloque vacía al costado. */
  height: clamp(260px, 32vw, 420px);
  width: auto;
  max-width: 100%;
  display: block;
  overflow: visible;
}

.mapa__pais {
  fill: color-mix(in srgb, var(--db-acento) 11%, transparent);
  stroke: color-mix(in srgb, var(--db-acento) 78%, transparent);
  stroke-width: 1.8;
  stroke-linejoin: round;
  /* El trazo arranca sin dibujar y se completa al entrar en pantalla. 1400 es
     holgado sobre el largo real del path: de sobra no pasa nada, de menos el
     contorno arrancaría a medio dibujar. */
  stroke-dasharray: 1400;
  stroke-dashoffset: 1400;
  fill-opacity: 0;
  transition: stroke-dashoffset 1.6s cubic-bezier(0.22, 1, 0.36, 1),
              fill-opacity 0.9s ease 0.9s;
}
.mapa__pais--isla { transition-delay: 0.5s, 1.1s; }
.mapa.es-visible .mapa__pais { stroke-dashoffset: 0; fill-opacity: 1; }

/* El marcador aparece cuando el contorno ya se dibujó: primero el país, después
   dónde estamos. Al revés, el punto flota sobre nada. */
.mapa__marca { opacity: 0; transition: opacity 0.5s ease 1.2s; }
.mapa.es-visible .mapa__marca { opacity: 1; }

.mapa__nucleo { fill: var(--db-acento); }
.mapa__pulso {
  fill: none;
  stroke: var(--db-acento);
  stroke-width: 1.4;
  transform-origin: 126.1px 126.3px;
  opacity: 0;
}
.mapa.es-visible .mapa__pulso { animation: db-radar 3.2s ease-out 1.4s infinite; }
.mapa.es-visible .mapa__pulso--b { animation-delay: 3s; }
@keyframes db-radar {
  0%   { transform: scale(0.35); opacity: 0.9; }
  70%  { transform: scale(2.6);  opacity: 0; }
  100% { transform: scale(2.6);  opacity: 0; }
}

.mapa__pie {
  font-size: var(--db-fs-eti);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--db-acento);
}

/* Sin movimiento: el país queda dibujado y el punto puesto. No se pierde nada
   de la información, se pierde el trazado y el radar. */
@media (prefers-reduced-motion: reduce) {
  .mapa__pais { stroke-dashoffset: 0; fill-opacity: 1; transition: none; }
  .mapa__marca { opacity: 1; transition: none; }
  .mapa__pulso { animation: none !important; opacity: 0.35; }
}

/* ── Bloque de Paraná: mapa a un lado, texto al otro ──────────────────────────
   Lo usan el Inicio (antes del footer) y Contacto. La entrada la maneja el motor
   declarativo con data-reveal="cross" — los dos lados llegan de lados opuestos y
   se encuentran en el centro. No hace falta JS propio. */
.parana__grid {
  display: grid;
  gap: var(--space-5);
  align-items: center;
}
@media (min-width: 900px) {
  .parana__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); column-gap: var(--space-6); }
}
.parana__texto p { margin-bottom: var(--space-4); }


/* ═════════════════════════════════════════════════════════════════════════════
   UN PASO DEL PROCESO — las dos columnas de "lo hacemos nosotros" y "lo
   necesitamos de vos". Vivía en css/proceso.css, donde sólo lo veía Proceso.
   Ahora lo usan las dos páginas que cuentan los cinco pasos, cada una con su
   forma: el Inicio en el recorrido horizontal y Proceso en vertical con anclaje
   lateral. La partición en dos columnas de peso igual es la misma idea en las
   dos, y escribirla dos veces habría sido tener dos particiones que se parecen.
   ═══════════════════════════════════════════════════════════════════════════ */

/* El cuerpo ocupa el paso entero: acá el ancho es lo que sostiene las dos
   columnas, y correrlo a la derecha del número —como hace el Inicio— dejaba una
   de las dos contra el borde. El número queda detrás, que es su lugar. */
.paso__cuerpo {
  max-width: none;
  margin-left: 0;
}
.paso__cuerpo h3 {
  margin: 0 0 var(--space-4);
  font-size: var(--db-fs-h3);
  letter-spacing: -0.025em;
  line-height: 1.1;
}

.paso__cols {
  display: grid;
  gap: var(--space-4);
}
@media (min-width: 900px) {
  /* Ancho igual, a propósito: si la columna de "necesitamos de vos" fuera más
     angosta, la partición diría que su lado pesa menos — y el punto de esta
     página es exactamente que las dos partes se declaran con el mismo peso. */
  .paso__cols { grid-template-columns: 1fr 1fr; gap: var(--space-3); }
}

/* El filo izquierdo distingue de quién es cada columna. Va acompañado siempre
   de su etiqueta en palabras: el color no es el único canal que lo dice, así
   que la partición se entiende igual sin distinguir el teal del gris. */
.paso__col {
  padding-left: var(--space-3);
  border-left: 2px solid var(--db-linea-fuerte);
  transition: border-color 0.35s ease;
}
.paso__col--nuestro {
  border-left-color: color-mix(in srgb, var(--db-acento) 72%, transparent);
}
.paso__col--tuyo {
  border-left-color: color-mix(in srgb, var(--db-grafito) 45%, transparent);
}
/* Respuesta al mouse. El equivalente táctil de esta sección no es por columna:
   es el recorrido entero —arrastre lateral con el dedo y las seis marcas de la
   barra, que se tocan para saltar—. Encender una columna al tocarla competiría
   con el arrastre, que es el gesto que esta sección le pide al dedo. */
.paso__col:hover { border-left-color: var(--db-acento); }

.paso__eti {
  margin: 0 0 var(--space-2);
  font-family: var(--db-font-mono);
  font-size: var(--db-fs-small);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--db-gris-medio);
}
.paso__col p:not(.paso__eti) { margin: 0; max-width: 46ch; }
.paso__col p + p { margin-top: var(--space-2); }

/* "Nada." El único lugar de la página donde una respuesta corta se escribe
   grande. Es el dato que más tranquiliza al dueño de un negocio que está
   calculando cuánto le va a costar a él en tiempo, y escrito al mismo tamaño
   que el resto se perdía en el párrafo. */
.paso__nada {
  font-size: clamp(1.125rem, 1.7vw, 1.5rem);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.015em;
  color: var(--db-texto-sobre-oscuro);
}


/* ═════════════════════════════════════════════════════════════════════════════
   PASARELA DE PROYECTOS — un recorrido horizontal navegable, no una grilla.
   La usan el Inicio (versión resumida, hasta dos proyectos destacados y un link
   a la página) y Proyectos (todos).

   Está pensada para crecer sin rediseñarse: con un solo proyecto muestra un
   panel que ocupa el ancho completo y no se ve vacía; con diez, se recorre.
   Una grilla no puede hacer las dos cosas — con un ítem queda un hueco de dos
   tercios, y ese hueco dice "acá falta algo".

   Mecánica portada de "Apple Cards Carousel" (db-project-biblioteca,
   references/carruseles-galerias.md): tira con scroll horizontal nativo,
   scrollbar oculta, botones que hacen scrollBy y se deshabilitan en los
   extremos. El scroll nativo es lo que da gratis el arrastre táctil, la inercia
   del sistema y el llevar al foco a la vista al tabular — tres cosas que un
   carrusel con transform hay que reimplementar y siempre quedan peor.
   Se le suma scroll-snap, que el original no trae, para que ningún panel quede
   a medio camino.
   ═══════════════════════════════════════════════════════════════════════════ */

.pasarela { margin-top: var(--space-5); }

.pasarela__cab {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}
.pasarela__contador {
  font-family: var(--db-font-mono);
  font-size: var(--db-fs-small);
  color: var(--db-gris-medio);
  margin: 0;
  font-variant-numeric: tabular-nums;
}
.pasarela__contador b {
  color: var(--db-texto-sobre-oscuro);
  font-weight: 600;
}

/* Las flechas. Sólo en desktop: en táctil el gesto es el arrastre, y dos botones
   de 44px al lado de una tira que se arrastra compiten con el gesto en vez de
   sumarle. */
.pasarela__flechas { display: none; gap: var(--space-1); }
@media (hover: hover) and (pointer: fine) {
  .pasarela__flechas { display: flex; }
}
.pasarela__flecha {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--db-linea-fuerte);
  border-radius: 10px;
  background: none;
  color: var(--db-texto-sobre-oscuro);
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease, opacity 0.2s ease;
}
.pasarela__flecha:hover:not(:disabled) { border-color: var(--db-acento); color: var(--db-acento); }
/* Deshabilitada y no escondida: un botón que desaparece en el extremo mueve el
   otro de lugar, y el visitante termina apretando donde ya no hay nada. */
.pasarela__flecha:disabled { opacity: 0.32; cursor: default; }
/* La punta se dibuja con dos bordes girados, no con un glifo tipográfico. */
.pasarela__flecha::before {
  content: "";
  width: 9px;
  height: 9px;
  border-top: 1.6px solid currentColor;
  border-right: 1.6px solid currentColor;
  transform: rotate(45deg) translate(-1px, 1px);
}
.pasarela__flecha--prev::before { transform: rotate(-135deg) translate(-1px, 1px); }

.pasarela__pista {
  display: flex;
  gap: var(--space-4);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* La barra de scroll se esconde: el contador y las flechas ya dicen dónde
     estás y cómo avanzar, y una barra nativa debajo de una ventana de navegador
     se lee como parte de la captura. */
  scrollbar-width: none;
  /* El sangrado de arranque tiene que ir en padding y no en margin: con margin,
     el primer panel no puede quedar pegado al borde del área scrolleable y el
     snap del último no llega. */
  padding-bottom: var(--space-2);
}
.pasarela__pista::-webkit-scrollbar { display: none; }
.pasarela__pista:focus-visible { outline: 2px solid var(--db-acento); outline-offset: 4px; }

.pasarela__panel {
  flex: 0 0 100%;
  scroll-snap-align: center;
  display: grid;
  gap: var(--space-4);
  align-items: center;
  /* min-width:0 en un ítem flex con contenido de ancho propio (una captura, un
     nombre largo): sin él el mínimo lo fija el contenido y el panel deja de poder
     encogerse, que es el desborde horizontal clásico. */
  min-width: 0;
}
@media (min-width: 900px) {
  .pasarela__panel { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); column-gap: var(--space-6); }
}

/* La ventana de navegador con la captura. Mismo marco que ya usaba la sección
   del proyecto del Inicio: borde, radio, sombra tintada del fondo. */
.pasarela__marco {
  border: 1px solid var(--db-linea);
  border-radius: var(--db-radius-card);
  overflow: clip;
  background: var(--db-superficie);
  /* La sombra lleva desplazamiento y desenfoque, y el color es el del fondo
     bajado, no negro puro: sobre el grafito una sombra negra se lee como un
     agujero. */
  box-shadow: 0 28px 70px -24px color-mix(in srgb, #0B0C0E 72%, transparent);
}
/* La captura queda quieta, sin desplazamiento interno, en las dos pantallas.
   Se probó el recorrido dentro del marco y no funcionaba: en el celular la
   ventana mide 190px de alto y la captura 8225, o sea un borrón que pasa de
   largo. */
.pasarela__captura { width: 100%; height: auto; display: block; }

.pasarela__ficha { min-width: 0; }
.pasarela__nombre {
  /* Sin font-size propio a propósito. El mismo nombre es h2 en Proyectos —donde
     el proyecto ES el contenido de la sección— y h3 en el Inicio, donde es una
     tarjeta más del adelanto. Un solo valor para los dos lo dejaba en 48px en
     las dos, o sea nivel 2 metido adentro de una tarjeta. Heredando de h2/h3
     cada uno cae en su nivel sin una regla que lo decida dos veces. */
  letter-spacing: -0.025em;
  line-height: 1.05;
  margin: 0 0 var(--space-3);
}
.pasarela__datos {
  list-style: none;
  margin: 0 0 var(--space-3);
  padding: 0;
  display: grid;
  gap: 6px;
  font-family: var(--db-font-mono);
  font-size: var(--db-fs-small);
  color: var(--db-gris-medio);
}
/* El año en el acento: es el único dato de la ficha que dice "esto está vivo". */
.pasarela__datos li[data-campo="anio"] { color: var(--db-acento); }
.pasarela__resumen { margin: 0 0 var(--space-4); max-width: 46ch; }

/* ── El cambio de panel ──────────────────────────────────────────────────────
   La ventana y la ficha entran desde lados opuestos cuando su panel pasa a ser
   el centrado. Lo marca js/pasarela.js con .is-activo, desde el MISMO
   IntersectionObserver que actualiza el contador: un solo observador para las
   dos cosas, y ninguna escucha de scroll.
   Es transición CSS y no un tween: es un cambio de estado de dos elementos, no
   una coreografía, y así se revierte solo al salir sin que nada tenga que
   acordarse de deshacerlo. */
.pasarela__marco,
.pasarela__ficha {
  transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.45s ease;
}
.pasarela__panel:not(.is-activo) .pasarela__marco { transform: translateX(-4%); opacity: 0.5; }
.pasarela__panel:not(.is-activo) .pasarela__ficha { transform: translateX(6%); opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  /* Sin movimiento la pasarela deja de ser horizontal y pasa a ser una pila
     vertical con todos los paneles enteros y legibles. No se pierde ni un
     proyecto, que es la condición: el recorrido es cómo se ven, no qué son. */
  .pasarela__pista {
    display: grid;
    gap: var(--space-6);
    overflow-x: visible;
    scroll-snap-type: none;
    scroll-behavior: auto;
  }
  .pasarela__panel { flex: none; }
  .pasarela__cab { display: none; }
  .pasarela__marco,
  .pasarela__ficha { transition: none; transform: none; opacity: 1; }
  .pasarela__panel:not(.is-activo) .pasarela__marco,
  .pasarela__panel:not(.is-activo) .pasarela__ficha { transform: none; opacity: 1; }
}

/* ── La captura del proyecto como enlace ──────────────────────────────────────
   La imagen del sitio ES el link para visitarlo: es lo que cualquiera intenta
   tocar primero. La etiqueta va SIEMPRE visible y no en hover, porque en el
   celular no hay hover que la revele — y más de la mitad del tráfico entra por
   ahí. En desktop la etiqueta además se corre con la flecha, que es el mismo
   gesto que ya usan .card__flecha y los botones del sitio. */
.pasarela__ir {
  display: block;
  color: inherit;
  text-decoration: none;
  min-width: 0;
}
/* La etiqueta no entra en la columna del botón flotante. El botón se aparta al
   bajar (js/flotante.js), pero al subir vuelve, y volver encima de un enlace no
   es aceptable: 56px del botón + 16 de aire. Sólo en mobile — desde 1024 el
   flotante cae sobre el margen y no toca nada. */
@media (max-width: 1023px) {
  /* max-width y no padding-right: el padding agranda la caja hacia la derecha,
     o sea la mete MÁS adentro de la columna del botón. Lo que hace falta es que
     la etiqueta termine antes: 56px del botón + 16 de aire. Si no entra, corta
     de línea, que es lo correcto — el enlace se sigue leyendo entero. */
  .pasarela__ir-eti { max-width: calc(100% - 72px); }
}
.pasarela__ir-eti {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 44px;
  margin-top: var(--space-2);
  font-family: var(--db-font-mono);
  font-size: var(--db-fs-eti);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--db-acento);
}
/* ── FAMILIA 4 · el proyecto real → "Direction Aware Hover" ──────────────────
   Pieza de db-project-biblioteca, references/tarjetas.md. Es la única prueba
   concreta del sitio —un negocio de Paraná con su web funcionando— y se veía
   exactamente igual que una tarjeta de garantía. Ahora la captura responde
   según por qué borde entró el puntero, que es un gesto que ninguna otra
   familia hace: no es "más movimiento", es movimiento que sólo esta tiene.
   El desplazamiento lo escribe js/tarjetas.js; acá va el recorte, sin el cual
   la imagen desplazada deja ver el borde del marco. */
.pasarela__marco { overflow: clip; will-change: transform; }

/* Equivalente táctil: sin borde de entrada, la captura se acomoda una sola vez
   al entrar en pantalla (js/home.js, alEntrarEnPantalla) — llega en lugar de
   estar puesta. */
.pasarela__marco { transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1); }
@media (hover: none) {
  .pasarela__marco { transform: translateY(14px); }
  .pasarela__marco.es-visible { transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .pasarela__marco { transition: none; transform: none; }
}

.pasarela__ir .btn__flecha { transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1); }
.pasarela__ir:hover .btn__flecha,
.pasarela__ir:focus-visible .btn__flecha { transform: translate(3px, -3px); }
.pasarela__ir:hover .pasarela__ir-eti { text-decoration: underline; }
@media (prefers-reduced-motion: reduce) {
  .pasarela__ir .btn__flecha { transition: none; }
  .pasarela__ir:hover .btn__flecha { transform: none; }
}

/* ── Jerarquía interna del paso ───────────────────────────────────────────────
   Las dos columnas decían cosas opuestas —lo que hacemos nosotros y lo que
   hace falta de vos— con el mismo rótulo gris y el mismo cuerpo. A un vistazo
   eran dos párrafos iguales, y quien lee en el celular no se detiene a
   distinguirlos. Ahora se separan por tres señales a la vez: color del rótulo,
   material de fondo y peso del cuerpo.
   El color no es nuevo: es el mismo acento del borde izquierdo que ya
   distinguía a la columna nuestra, ahora también en su rótulo. */
.paso__col--nuestro .paso__eti { color: var(--db-acento); }
.paso__col--tuyo .paso__eti { color: var(--db-texto-sobre-oscuro); }

/* La columna tuya lleva material propio. Es la que pide algo, y pedir tiene que
   verse distinto de informar. */
.paso__col--tuyo {
  padding: var(--space-2) var(--space-3);
  background: color-mix(in srgb, var(--db-blanco) 3%, transparent);
  border-radius: 0 var(--db-radius-card) var(--db-radius-card) 0;
}
.tramo-claro .paso__col--tuyo {
  background: color-mix(in srgb, var(--db-grafito) 4%, transparent);
}
.tramo-claro .paso__col--tuyo .paso__eti { color: var(--db-texto-sobre-claro); }

/* El cuerpo del paso sube: es prosa de venta, no una nota al pie. */
.paso__col p:not(.paso__eti) { font-size: var(--db-fs-cuerpo); }


/* ═════════════════════════════════════════════════════════════════════════════
   CIFRAS — el número grande con su unidad al lado
   Compartido por el cierre del Inicio y la apertura de Proceso.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ── Los compromisos ─────────────────────────────────────────────────────────
   El número manda: grande y en mono, con la palabra chica al lado. Un número
   grande detiene la vista, un párrafo no. */
.cifras { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); }
@media (min-width: 560px) { .cifras { grid-template-columns: 1fr 1fr; } }
/* El número y su leyenda en la misma línea de base, no apilados: así el número
   se lee como cifra con unidad —"24 horas"— y no como un título con un pie. */
.cifras li { display: flex; align-items: baseline; gap: var(--space-2); }
/* El del LCP cruza las dos columnas. Es el único de tres caracteres ("1.5") y
   el único con una leyenda larga: en media columna le quedaban 110px para la
   frase y se partía en cinco renglones de dos palabras. Cruzando, el número
   sigue siendo grande y la frase entra en dos líneas. Que además sea el que
   ocupa el ancho entero es correcto: es el único de los cuatro que no pusimos
   nosotros — lo mide el navegador del visitante mientras lee. */
.cifras li:last-child { grid-column: 1 / -1; }
/* Las cuatro cifras estaban las cuatro en acento pleno, al lado de un botón
   que también es acento pleno: cinco cosas peleando por la misma mirada en el
   bloque de cierre. Ahora son blancas y ninguna lleva acento: el único de la
   sección es el canal de WhatsApp. */
.cifras__n {
  font-size: clamp(2.75rem, 5.6vw, 4.25rem);
  font-weight: 600;
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: var(--db-blanco);
  font-variant-numeric: tabular-nums;  /* sin tabular, el ancho salta al contar */
  flex-shrink: 0;
}
/* Las leyendas son unidades y etiquetas, no prosa: van en mono, como el resto
   de los datos medidos del sitio. */
.cifras__cap {
  font-family: var(--db-font-mono);
  font-size: var(--db-fs-eti);
  line-height: 1.4;
  letter-spacing: 0.04em;
  color: var(--db-gris-medio);
}

