/* ============================================================
   kivo.css — Dirección A · "Vidrio sobre petróleo"

   Superficies PLANAS (el manual no tiene degradés): petróleo dominante,
   una franja más profunda, y una sección en hueso. Lo que va detrás del
   vidrio es la trama diagonal a 135° del manual — no un radial de color.

   SIGNATURE MOVE: el anillo del isotipo, gigante, sangrando por el borde
   derecho, que se va cerrando a medida que scrolleás. Las cuatro cards de
   vidrio flotan encima y doblan la trama.

   El magenta NO se usa en texto: el manual dice que aparece solo en el
   isotipo, en un filete o en un botón. Se respeta al pie de la letra.
   ============================================================ */

/* ============================================================
   VIDRIO LÍQUIDO
   Mecánica de la liquid glass card de KokonutUI, re-teñida con los tokens
   (Parte C de componentes.md):
     - sin #000 / #fff  -> hueso y petróleo en oklch
     - sin shadow-*     -> hairline + speculares INSET (la luz propia del
                           material, no una sombra proyectada)
     - via-black/5      -> barrido magenta a <10% en un solo hue
     - ease-in-out      -> var(--ease-suave)
     - rounded-xl       -> var(--radio-vidrio)

   Cuatro capas, pero las dos de filtro son HERMANAS, no anidadas: Firefox
   y Safari no soportan url() dentro de backdrop-filter, y así la capa
   difusa sigue dando un vidrio correcto sin la refracción.
   ============================================================ */

.vidrio {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: var(--radio-vidrio);
  border: 1px solid var(--vidrio-borde);
  background: transparent;   /* el fondo va en la capa difusa, no acá */
  box-shadow:
    inset 0  1px 0 0 var(--vidrio-luz),
    inset  1px 0 0 0 var(--vidrio-canto),
    inset -1px 0 0 0 var(--vidrio-canto),
    inset 0 -1px 0 0 var(--vidrio-sombra),
    inset 0  10px 26px -14px var(--vidrio-luz),
    inset 0 -26px 44px -32px var(--vidrio-sombra);
  transition:
    transform    var(--dur-media) var(--ease-suave),
    border-color var(--dur-media) var(--ease-suave);
}

/* Capa 1 — difusa: el blur base. Sobrevive en todos los motores. */
.vidrio__difusa {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--vidrio-lavado);
  /* el blur queda solo para el modo noche y los bloques magenta, donde
     hay algo atrás que se nota desenfocado */
  backdrop-filter: saturate(var(--vidrio-satura));
  -webkit-backdrop-filter: saturate(var(--vidrio-satura));
}

/* Capa 2 — refracción: el desplazamiento líquido. Su backdrop es la página
   MÁS el resultado de la capa difusa, así que el orden queda
   turbulencia -> blur -> desplazamiento, igual que el original.
   Si el motor la ignora, no se pierde nada: es puro agregado. */
.vidrio__refr {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  backdrop-filter: url("#kivo-refraccion");
  -webkit-backdrop-filter: url("#kivo-refraccion");
  /* sobre papel no hay nada que refractar: solo vive de noche y en magenta */
  opacity: 0;
}

/* Capa 3 — brillo especular del hover */
.vidrio__brillo {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    108deg,
    transparent 0%,
    oklch(0.65 0.265 355 / 0.10) 42%,
    var(--vidrio-canto) 56%,
    transparent 100%
  );
  transition: opacity var(--dur-media) var(--ease-suave);
}

/* Capa 4 — contenido */
.vidrio__cont { position: relative; z-index: 3; }

.vidrio:hover,
.vidrio:focus-within {
  border-color: var(--linea-acento);
  transform: translateY(-4px);
}
.vidrio:hover .vidrio__brillo,
.vidrio:focus-within .vidrio__brillo { opacity: 1; }

/* En pantallas chicas la refracción cuesta caro y casi no se ve */
@media (max-width: 720px) {
  .vidrio__refr { display: none; }
  .vidrio__difusa {
    backdrop-filter: saturate(var(--vidrio-satura));
    -webkit-backdrop-filter: saturate(var(--vidrio-satura));
  }
}

@media (prefers-reduced-motion: reduce) {
  .vidrio:hover, .vidrio:focus-within { transform: none; }
}

/* El isotipo vive en tokens.css: es SVG, no el truco de borders.
   Acá van solo los tamaños de cada lugar donde aparece. */
.iso__disco { fill: var(--iso-disco); }

/* ============================================================
   MARCA DE AGUA SOBRE FOTO
   El patrón exacto del manual (sección 06 · Aplicaciones): el isotipo —o
   el wordmark— arriba a la izquierda, y el epígrafe en mono abajo, con
   padding de 22px y todo alineado a los bordes del recuadro.
   ============================================================ */
.foto { position: relative; overflow: hidden; }

.foto > img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Velos: sin esto la marca de agua desaparece sobre fotos claras */
.foto::before,
.foto::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  pointer-events: none;
  z-index: 1;
}
.foto::before {
  top: 0; height: 42%;
  background: linear-gradient(to bottom, var(--velo-alto), transparent);
}
.foto::after {
  bottom: 0; height: 48%;
  background: linear-gradient(to top, var(--velo-bajo), transparent);
}

.foto__agua {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: clamp(0.9rem, 2vw, 1.375rem);   /* 22px del manual en desktop */
  pointer-events: none;
}
.foto__agua .iso { width: clamp(30px, 3.6vw, 46px); }
.foto__agua .wordmark {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: clamp(1.15rem, 2.4vw, 2rem);
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--hueso);
}
.foto__epigrafe {
  font-family: var(--f-mono);
  font-size: clamp(0.6rem, 0.32vw + 0.52rem, 0.7rem);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: oklch(1 0 0 / 0.82);
}

/* ============================================================
   NAV
   ============================================================ */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.1rem var(--s-borde);
  border-bottom: 1px solid transparent;
  transition:
    background-color var(--dur-media) var(--ease-suave),
    border-color     var(--dur-media) var(--ease-suave),
    padding          var(--dur-media) var(--ease-suave);
}
.nav.pegado {
  background: var(--nav-fondo);
  backdrop-filter: blur(20px) saturate(130%);
  -webkit-backdrop-filter: blur(20px) saturate(130%);
  border-bottom-color: var(--linea);
  padding-block: 0.8rem;
}

.marca { display: flex; align-items: center; gap: 0.7rem; }
.marca .iso { width: 24px; }
.marca__txt {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 1.22rem;
  letter-spacing: -0.04em;
  color: var(--texto);
}

.nav__links { display: flex; align-items: center; gap: 1.7rem; }
.nav__links a {
  font-family: var(--f-mono);
  font-size: var(--t-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--nav-link);
  position: relative;
  padding-block: 0.35rem;
  transition: color var(--dur-rapida) var(--ease-suave);
}
.nav__links a::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 0; height: 1px;
  background: var(--acento);
  transition: width var(--dur-media) var(--ease-suave);
}
.nav__links a:hover { color: var(--texto); }
.nav__links a:hover::after { width: 100%; }

/* Botones */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--f-mono);
  font-size: var(--t-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 0.85rem 1.7rem;
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio);
  background: transparent;
  color: var(--texto);
  cursor: pointer;
  transition:
    background-color var(--dur-media) var(--ease-suave),
    border-color     var(--dur-media) var(--ease-suave),
    color            var(--dur-media) var(--ease-suave);
}
.btn:hover { border-color: var(--acento); color: var(--acento); }

.btn--lleno {
  background: var(--magenta);
  border-color: var(--magenta);
  /* petróleo, no papel: el blanco sobre magenta da 3.53:1 y no pasa AA */
  color: var(--negro);
  font-weight: 600;
}
.btn--lleno:hover {
  background: var(--magenta-hondo);
  border-color: var(--magenta-hondo);
  color: var(--papel);
}
.btn svg { width: 15px; height: 15px; transition: transform var(--dur-media) var(--ease-suave); }
.btn:hover svg { transform: translateX(4px); }

.hamb {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: 0;
  padding: 6px;
  cursor: pointer;
}
.hamb span {
  display: block; width: 24px; height: 1px;
  background: var(--texto);
  transition: transform var(--dur-media) var(--ease-suave), opacity var(--dur-rapida);
}
.hamb.abierto span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.hamb.abierto span:nth-child(2) { opacity: 0; }
.hamb.abierto span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.menu-movil {
  position: fixed;
  inset: 0;
  z-index: 99;
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 1.3rem;
  padding: 0 var(--s-borde);
  background: var(--menu-fondo);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  overflow-y: auto;
}
.menu-movil a {
  font-family: var(--f-display);
  font-weight: 500;
  font-size: clamp(1.45rem, 6.5vw, 2.2rem);
  letter-spacing: -0.03em;
  color: var(--texto);
  transition: color var(--dur-rapida) var(--ease-suave);
}
.menu-movil a:hover { color: var(--acento); }

/* El nav pasa a hamburguesa acá: medido, a 900px los links ya quedan a
   24px del CTA y a 800px el botón se sale de pantalla.
   La regla .abierto vive adentro del media query a propósito: si el
   teléfono gira a horizontal con el menú abierto, arriba de 900 el menú
   se apaga solo en vez de quedar tapando el sitio. */
@media (max-width: 900px) {
  .nav__links { display: none; }
  .hamb { display: flex; }
  .menu-movil.abierto { display: flex; }
}
/* Abajo de 560 el CTA no entra al lado de la hamburguesa, y no hace
   falta: el menú lo lleva en magenta. */
@media (max-width: 560px) {
  .nav > .btn { display: none; }
}

/* ============================================================
   ESCENA — hero + servicios comparten el anillo.
   Superficie plana: el fondo del tema y nada encima. Pasó por una trama de
   rayas y después por una grilla de puntos en canvas; las dos se fueron.
   ============================================================ */
.escena {
  position: relative;
  overflow: clip;
  background: var(--fondo);
}
/* Acá vivía la grilla de puntos en canvas (fondo.js). Juan la sacó: "no me
   convence el fondo ese". La escena queda con el fondo del tema y nada más
   — el peso visual lo llevan el anillo, el grano y la tipografía. */

/* El anillo: sangra por el borde derecho a propósito.
   A 1000px el isotipo no puede ir en magenta pleno (el acento tiene que
   quedar bajo el 5% de la pantalla), así que acá es presencia estructural
   y el único magenta que pesa es el punto que avanza. */
.anillo {
  position: absolute;
  top: 26vh;
  right: -20vw;
  width: min(94vw, 1040px);
  aspect-ratio: 1;
  pointer-events: none;
  z-index: 0;
}
.anillo svg { width: 100%; height: 100%; overflow: visible; }
.anillo__pista { stroke: var(--linea-fuerte); }
.anillo__arco   { stroke: var(--acento); opacity: 0.11; }
.anillo__grupo  { transform-origin: 100px 100px; }
.anillo__cabeza { stroke: var(--acento); opacity: 0.26; }
.anillo__punto  { fill: var(--acento); }

@media (max-width: 900px) {
  .anillo { top: auto; bottom: -4vh; right: -38vw; width: min(118vw, 600px); }
  .anillo__arco { opacity: 0.07; }
  .anillo__cabeza { opacity: 0.15; }
}

/* MOSAICO DEL HERO — una foto grande que se rearma por fragmentos.
   Cuarta versión de este lugar: era .anillo (SVG, sigue arriba sin usar),
   después el video de marca, después una grilla 2×2 de las cuatro fotos,
   y ahora UNA sola grande que rota entre las cuatro.

   Va EN FLUJO adentro del <aside>, no flotando con position:absolute como
   .anillo: ese anillo era transparente y podía sangrar suelto, pero
   cualquier cosa OPACA acá llega a superponerse con el texto "Cómo
   trabajamos" en ciertos anchos, porque la posición del aside depende de
   cuánto ocupe el título (cuando esto se escribió el grid alineaba por
   abajo, con align-items:end; hoy alinea por arriba, pero el riesgo es el
   mismo en cuanto algo del aside flote). En flujo eso es geométricamente
   imposible.

   ---- LAS FOTOS VAN A COLOR (decisión de Juan, 27/08) ----
   Estuvieron un rato en duotono magenta: grayscale + una capa en
   mix-blend-mode:color sobre .mosaico__marco::after. Juan lo pidió sacar
   y ahora se ven con su color original.

   Lo que ese duotono resolvía, por si alguna vez se quiere volver: las
   cuatro fotos son stock y NO comparten paleta — dos traen violeta→cian
   saturado (justo el gradiente que diseno.md prohíbe), una es cálida de
   madera y la de papelería es neutra fría. El duotono las unificaba. Sin
   él, la rotación pasa por cuatro temperaturas distintas.
   Si se reviviera: la capa va en el ::after del marco y NO en cada <img>,
   porque tiene que caer también sobre las celdas de la transición, que van
   encima — si estuviera sólo en las fotos, el mosaico entraría a todo
   color y dispararía un flash en cada pasada. Y el grayscale va ANTES del
   blend, o los violetas de fábrica pelean con el magenta. */
/* ---- El chevron del hover ----
   Port del pen "promo" que eligió Juan. Lo que se copió es la mecánica
   completa, que son cuatro cosas a la vez sobre el mismo hover:
     1. el marco pasa de rectángulo a chevron (los dos puntos al 50% del
        polygon se meten hacia adentro),
     2. el marco se corre a la derecha,
     3. la foto hace parallax INTERNO: está al 112% y arranca corrida, así
        que al enderezarse se mueve en sentido contrario al marco,
     4. entra el rótulo con su CTA.
   Y todo con el easing de rebote del original, que es lo que le da el
   carácter — un ease normal deja el chevron blando.

   Lo que NO se copió: el pen pone un color plano por tarjeta (hotpink,
   yellow, dodgerblue, darkgreen) que APARECE en el hover con
   mix-blend-mode:multiply. Acá las fotos van a color, así que un overlay
   plano encima sólo las ensuciaría — el feedback del hover lo dan de
   sobra el chevron, el desplazamiento, el parallax y el CTA.

   Los números están bajados del original a esta escala: el pen usa
   tarjetas de 60vmin sueltas en el medio de la página, acá el marco vive
   en una columna de ~310px con el borde de la página a 72px. El
   translateX del original (25%) mandaba el marco fuera de pantalla
   (1368 + 77 = 1445 > 1440), así que va 8%, y el chevron entra 18% en
   vez de 25%. Medido, no a ojo. */
.mosaico {
  /* Techo fijo, en las dos variantes de layout: a todo el ancho del aside
     sería una pared de foto que le come la escena al titular. 440 y no los
     320 que tenía — Juan la pidió más grande dos veces. */
  max-width: 440px;
  --chevron-dur: 320ms;
  /* del original, tal cual: es el rebote lo que hace el efecto */
  --chevron-rebote: cubic-bezier(0.34, 1.56, 0.64, 1);
  margin-bottom: 1.6rem;
}
.mosaico__enlace {
  position: relative;
  display: block;
  color: inherit;
  text-decoration: none;
}
.mosaico__marco {
  position: relative;
  margin: 0;
  /* 4/5 y no 1/1: el retrato le da más presencia en una columna angosta
     sin robarle ancho al titular, que es lo que manda en la portada */
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--fondo-hondo);
  /* SIN borde: el hairline de 1px que había acá se leía como un filete
     blanco alrededor de la foto (sobre papel --linea es casi blanco) y
     Juan lo pidió sacar. La foto se sostiene sola — no la necesita para
     separarse del fondo, y el chevron del hover recorta el borde en
     diagonal, así que un filete ahí queda peor todavía. */
  /* En reposo los vértices del 50% están sobre los bordes, así que el
     polygon ES un rectángulo. Tiene que estar declarado igual, o no hay
     nada desde donde interpolar al chevron. */
  clip-path: polygon(100% 0, 100% 50%, 100% 100%, 0 100%, 0 50%, 0 0);
  transition: clip-path var(--chevron-dur) var(--ease-suave),
              transform var(--chevron-dur) var(--ease-suave);
}
.mosaico__foto {
  position: absolute;
  inset: 0;
  display: block;
  /* 112% y corrida: el sobrante es lo que se recorre en el parallax.
     Al 100% no habría de dónde mover sin dejar un borde vacío.

     max-width:none NO es decorativo: tokens.css trae la regla global
     `img, video, svg { max-width: 100% }` (la de siempre, para que ninguna
     imagen desborde su caja) y max-width le gana a width — así que el 112%
     quedaba clampeado a 100%, la foto medía exactamente el marco y al
     correrse para el parallax dejaba una banda del fondo a la derecha
     (medido: 44px a 1440px de viewport). Se veía en producción. */
  width: 112%;
  max-width: none;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: translateX(-10.7%);
  transition: opacity var(--dur-media) linear,
              transform var(--chevron-dur) var(--ease-suave);
}
.mosaico__foto.es-activa { opacity: 1; }

/* ---- El rótulo ----
   El CTA sale del data-cta por ::after, como en el original.

   Dos cosas cambiadas a pedido de Juan: más chico (era 1.35rem) y
   CENTRADO respecto a la foto. Centrarlo obliga a la técnica de
   left:50% + translateX(-50%) y no a un simple left:0 — y eso a su vez
   obliga a que el desplazamiento del hover se sume DENTRO del mismo
   translate, o pisaría el -50% y el rótulo saltaría al costado.

   Por eso el corrimiento del hover va en --empuje (una variable), no en
   un transform nuevo: así el translate siempre lleva el -50% del centrado
   y el empuje se suma al lado. En el pen original esto no hacía falta
   porque el rótulo estaba alineado a la izquierda. */
.mosaico__rotulo {
  --empuje: 0px;
  position: absolute;
  left: 50%;
  bottom: 1rem;
  z-index: 4;
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
  padding: 0.35rem 0.65rem;
  background: var(--negro);
  color: var(--blanco);
  font-family: var(--f-display);
  font-weight: 500;
  font-size: 1.05rem;
  letter-spacing: -0.02em;
  line-height: 1.1;
  white-space: nowrap;
  pointer-events: none;
  transform: translateX(calc(-50% + var(--empuje)));
  transition: transform var(--chevron-dur) var(--ease-suave);
}
.mosaico__rotulo::after {
  content: attr(data-cta);
  font-family: var(--f-mono);
  font-size: 0.6rem;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--acento);
  opacity: 0;
  transform: translateX(-25%);
  transition: opacity var(--chevron-dur) var(--ease-suave),
              transform var(--chevron-dur) var(--ease-suave);
}

@media (hover: hover) and (pointer: fine) {
  /* El hover cuelga de .mosaico__enlace (el <a>) y no del marco: el rótulo
     vive AFUERA del marco —si estuviera adentro lo recortaría el chevron—
     y tiene que entrar con el mismo gesto. */
  .mosaico__enlace:hover .mosaico__marco,
  .mosaico__enlace:focus-visible .mosaico__marco {
    clip-path: polygon(82% 0, 100% 50%, 82% 100%, 0 100%, 18% 50%, 0 0);
    transform: translateX(8%);
    transition-timing-function: var(--chevron-rebote);
  }
  /* la foto vuelve a su lugar mientras el marco se va: eso es el parallax */
  .mosaico__enlace:hover .mosaico__foto,
  .mosaico__enlace:focus-visible .mosaico__foto {
    transform: translateX(0);
    transition-timing-function: var(--chevron-rebote);
  }
  /* el empuje se SUMA al -50% del centrado (ver .mosaico__rotulo) */
  .mosaico__enlace:hover .mosaico__rotulo,
  .mosaico__enlace:focus-visible .mosaico__rotulo {
    --empuje: 14px;
    transition-timing-function: var(--chevron-rebote);
  }
  .mosaico__enlace:hover .mosaico__rotulo::after,
  .mosaico__enlace:focus-visible .mosaico__rotulo::after {
    opacity: 1;
    transform: translateX(0);
    transition-timing-function: var(--chevron-rebote);
  }
}

/* En touch no hay hover, así que todo el bloque de arriba no corre nunca y
   el CTA quedaría escondido para siempre — el link se vería como una foto
   muda. Sin hover el CTA arranca visible: es el único aviso de que esto
   lleva a algún lado. El chevron sí se pierde, y está bien: es un gesto de
   puntero, no hay con qué dispararlo. */
@media not all and (hover: hover) {
  .mosaico__rotulo::after { opacity: 1; transform: none; }
}

.mosaico__enlace:focus-visible { outline: 2px solid var(--acento); outline-offset: 6px; }

/* El chevron es un recorte que deforma la foto entera: con movimiento
   reducido queda el rectángulo quieto y sólo entra el CTA. */
@media (prefers-reduced-motion: reduce) {
  .mosaico__marco,
  .mosaico__foto,
  .mosaico__rotulo { transition-duration: 0.01ms; }
  .mosaico__enlace:hover .mosaico__marco,
  .mosaico__enlace:focus-visible .mosaico__marco {
    clip-path: polygon(100% 0, 100% 50%, 100% 100%, 0 100%, 0 50%, 0 0);
    transform: none;
  }
}

/* ---- Las celdas de la transición (ver js/mosaico.js) ----
   Port de "Image Transition" de Szenia Zadvornykh (codepen QNoWmO). El
   original es Three.js + shaders WebGL sobre un <canvas>: 600 kB de
   librería y las fotos dejarían de ser <img> con alt. Acá se copió la
   MECÁNICA — la imagen se rearma por fragmentos que entran barriendo en
   diagonal — con celdas de CSS y cero dependencias.

   El truco: background-size = N × el tamaño de la celda hace que la foto
   ocupe la grilla completa, y entonces background-position en PORCENTAJE
   ubica cada celda (x/(N-1) × 100%). En px habría que remedir en cada
   resize; en porcentaje se acomoda solo.

   --n lo escribe el JS, que es el único que sabe cuántas celdas hizo. */
.mosaico__celdas {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(var(--n, 6), 1fr);
  grid-template-rows: repeat(var(--n, 6), 1fr);
  opacity: 0;
  pointer-events: none;
}
.mosaico__celdas.esta-visible { opacity: 1; }

.mosaico__celda {
  background-size: calc(var(--n, 6) * 100%) calc(var(--n, 6) * 100%);
  background-repeat: no-repeat;
  /* el estado de partida: el fragmento todavía no llegó */
  opacity: 0;
  transform: scale(0.62);
  transition: opacity 520ms var(--ease-suave), transform 520ms var(--ease-suave);
  /* transition-delay y background-position los pone el JS por celda */
}
.mosaico__celdas.esta-armando .mosaico__celda {
  opacity: 1;
  transform: none;
}

/* ---- Los mandos: flechas + una raya por foto ----
   Las rayas dejaron de ser decoración: cada una es un <button> que salta a
   su foto. Siguen siendo hairlines y no los puntitos de siempre, porque el
   sitio usa hairlines en todos lados y un dot relleno sería piel de otro
   sitio — pero ahora tienen que aceptar un dedo encima, así que el área
   clickeable se agranda con padding vertical y un ::before que la estira
   sin engordar la raya visible. */
.mosaico__mandos {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.75rem;
}
.mosaico__flecha {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--linea-fuerte);
  background: transparent;
  color: var(--texto-suave);
  cursor: pointer;
  transition: color var(--dur-rapida) var(--ease-suave),
              border-color var(--dur-rapida) var(--ease-suave);
}
.mosaico__flecha svg { width: 14px; height: 14px; }
.mosaico__flecha:hover { color: var(--acento); border-color: var(--acento); }
.mosaico__flecha:active { transform: translateY(1px); }

.mosaico__pista {
  flex: 1;
  display: flex;
  gap: 0.4rem;
}
.mosaico__barra {
  flex: 1;
  /* la raya se ve de 2px pero el botón mide 14: sin esto es un blanco de
     2px de alto, imposible de acertar con el dedo */
  height: 14px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  position: relative;
}
.mosaico__barra::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 2px;
  transform: translateY(-50%);
  background: var(--linea);
}
.mosaico__barra::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 2px;
  background: var(--acento);
  transform: translateY(-50%) scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-media) var(--ease-suave);
}
.mosaico__barra.es-activa::after { transform: translateY(-50%) scaleX(1); }
.mosaico__barra:hover::before { background: var(--linea-fuerte); }
.mosaico__barra:focus-visible { outline: 2px solid var(--acento); outline-offset: 3px; }
.mosaico__flecha:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  /* el JS ya no usa las celdas acá: sólo funde las fotos */
  .mosaico__celdas { display: none; }
}



/* ============================================================
   HERO — asimetría 7/5, alineado a la izquierda.
   ============================================================ */
.hero {
  position: relative;
  z-index: 1;
  /* el hueco al bloque siguiente medía 112px, por debajo del piso de 8rem */
  padding: clamp(9rem, 18vh, 14rem) var(--s-borde) clamp(5.5rem, 11vw, 9.5rem);
}
.hero__grid {
  max-width: var(--ancho-amplio);
  margin-inline: auto;
  display: grid;
  /* minmax(0, ·) y no `8fr 4fr` pelado. `fr` NO baja del min-content, y el
     min-content de la primera columna es "Automatizamos" en una línea: una
     sola palabra, que no hay por dónde cortar. Con el fr pelado esa columna
     se plantaba en 915px a cualquier ancho y la segunda se quedaba con lo
     que sobrara (308px a 1440, 184px a 1280) — esa, y no otra, era la razón
     por la que el hero se apilaba a 1560 y la foto terminaba DEBAJO del
     titular en cualquier pantalla de laptop.
     Con el mínimo en 0 las dos columnas se reparten de verdad 8/4 y el que
     se adapta es el cuerpo del titular (ver .hero__col y .hero h1). El 8/4
     no es un número redondo elegido a dedo: reproduce la proporción que
     tenía la portada a 1920, donde sí entraba en dos columnas (62% / 32%
     del ancho útil). */
  grid-template-columns: minmax(0, 8fr) minmax(0, 4fr);
  gap: var(--s-borde);
  /* start y no end (27/08): la columna de la derecha es más alta que la del
     texto —la foto sola ya mide 510px a 1440, y abajo lleva los mandos y el
     párrafo de "Cómo trabajamos"—, así que alineando por abajo el titular
     se hundía y quedaba un hueco muerto de ~265px arriba del filete. Ahora
     el borde de arriba de la foto y la primera línea del texto arrancan en
     la misma altura, y el sobrante cae abajo del aside, que es donde no
     molesta: ahí sigue el hueco natural hasta la tira de servicios. */
  align-items: start;
}
/* Contenedor de container-query: adentro, 1cqi es 1% del ancho de ESTA
   columna y no del viewport. Es lo que permite escribir "el titular mide lo
   que entre en su columna" sin un media query por cada ancho. */
.hero__col { container-type: inline-size; }
.hero__et { display: flex; align-items: center; gap: 0.9rem; margin-bottom: 2.2rem; }
.hero h1 {
  margin-bottom: 2rem;
  color: var(--texto);
  /* El techo de --t-display (136px) sigue mandando cuando hay lugar; abajo
     de eso manda la columna. El 14.6 salió de medir y no de tantear: a
     136px "Automatizamos" mide 915,3px, o sea 6,73px de ancho por px de
     cuerpo, así que entra justo con cuerpo = ancho / 6,73 = 14,86cqi. Se
     deja en 14,6 para guardar 1,7% de aire — si la Outfit no cargara, la
     fuente de respaldo mide un poco más y la palabra se saldría sola de la
     columna (una palabra sin espacios no se puede reacomodar).
     Apilado el techo nunca llega a morder: a 900px de ancho 14,6cqi son
     118px y --t-display a ese ancho ya viene pidiendo 94. */
  font-size: min(var(--t-display), 14.6cqi);
}
.hero__bajada {
  font-size: clamp(1.05rem, 1.5vw, 1.28rem);
  color: var(--texto-suave);
  max-width: 48ch;
  margin-bottom: 2.8rem;
}
.hero__acciones { display: flex; flex-wrap: wrap; gap: 0.9rem; }

.hero__tira {
  grid-column: 1 / -1;
  margin-top: clamp(3.5rem, 8vw, 6rem);
  padding-top: 1.4rem;
  border-top: 1px solid var(--linea);
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1.2rem;
}
.hero__tira div { display: flex; flex-direction: column; gap: 0.3rem; }
.hero__tira strong {
  font-family: var(--f-display);
  font-weight: 500;
  font-size: 1.02rem;
  letter-spacing: -0.02em;
  color: var(--texto);
}

/* El corte bajó de 1560 a 1060 (27/08). El 1560 salía de que la primera
   columna no podía achicarse abajo de los 915px del titular, así que para
   que a la derecha entraran los 440px de la foto hacían falta
   915 + gap + 440 + bordes ≈ 1560 — y abajo de eso la portada se apilaba y
   la foto caía DEBAJO del titular. Como ahora el titular se mide contra su
   columna, esa cuenta ya no existe.

   El 1060 también está medido, y el que manda ahora es el ancho de la foto,
   no el del texto: en este rango --s-borde es 5vw, así que la columna
   derecha mide 0,2833 × el ancho de la ventana, y a 1060px son exactamente
   300px de foto. Más abajo de eso la foto entra en el terreno donde ya no
   se sostiene (era más chica que las miniaturas que vino a reemplazar), y
   conviene apilar y devolverle los 440px de ancho completo.
   Va en su propio media query para no arrastrar a .hero__tira, que en ese
   rango todavía entra bien en cinco columnas. */
@media (max-width: 1060px) {
  .hero__grid { grid-template-columns: 1fr; }
}
@media (max-width: 980px) {
  .hero__tira { grid-template-columns: repeat(3, 1fr); gap: 1.6rem 1.2rem; }
}
@media (max-width: 640px) {
  /* con 5 ítems, 3 columnas aprietan: acá pasa a 2 + 2 + 1 */
  .hero__tira { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 700px) {
  .hero { padding-top: 7.5rem; }
  .hero__et { margin-bottom: 1.6rem; }
  .hero__bajada { margin-bottom: 2.2rem; }
  .hero__acciones .btn { padding: 0.8rem 1.3rem; letter-spacing: 0.13em; }
}

/* ============================================================
   SERVICIOS — 5 paneles: 2 columnas escalonadas + el quinto a lo ancho
   ============================================================ */
.servicios {
  position: relative;
  z-index: 2;
  padding: 0 var(--s-borde) var(--s-seccion);
}
.servicios__enc {
  max-width: var(--ancho-normal);
  margin: 0 auto clamp(2.5rem, 6vw, 4rem);
  display: flex;
  align-items: baseline;
  gap: 1.2rem;
}
.servicios__enc .linea-larga { flex: 1; height: 1px; background: var(--linea); }
/* ------------------------------------------------------------
   EL INDICE — cinco filas, cero cajas

   Lo que habia eran cinco cards de vidrio con radio de 20px en grilla
   escalonada, dos de ellas rellenas de magenta pleno. Rebotadas: es la
   forma que tiene todo el mundo, y las dos magenta eran media pantalla
   de color plano cada una.

   Reglas de esta version:
   · ninguna caja, ningun radio, ningun relleno de color — solo hairlines
   · el magenta entra como ACENTO (numeral + filete al pasar el mouse),
     nunca como superficie, que es lo que dice el manual de la marca
   · las dos columnas de contenido son DESIGUALES a proposito (1.15 / 0.85):
     el parrafo pesa mas que la lista y la fila queda cargada a la izquierda
   · las cinco filas son iguales — se fue el caso especial de la quinta
     card "a lo ancho" y el margin-top que habia que mantener a mano
   ------------------------------------------------------------ */
.indice {
  max-width: var(--ancho-normal);
  margin-inline: auto;
}

.indice__fila {
  position: relative;
  display: grid;
  grid-template-columns: clamp(3.2rem, 5.5vw, 5.5rem) minmax(0, 1.15fr) minmax(0, 0.85fr);
  column-gap: clamp(1.5rem, 3.5vw, 3.5rem);
  /* el hueco entre el numeral y el titular tiene que ser mas chico que el
     que hay entre el titular y el cuerpo, o las tres filas pesan igual */
  row-gap: clamp(0.9rem, 1.6vw, 1.5rem);
  padding-block: clamp(2.6rem, 5vw, 4.4rem);
  border-top: 1px solid var(--linea);
}
.indice__fila:last-child { border-bottom: 1px solid var(--linea); }

/* el filete que barre la fila: va sobre el borde de arriba, por eso el
   top:-1px — si no, queda un pelo abajo y se ven las dos lineas */
.indice__fila::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  height: 1px;
  width: 0;
  background: var(--acento);
  transition: width var(--dur-lenta) var(--ease-suave);
}
.indice__fila:hover::before,
.indice__fila:focus-within::before { width: 100%; }

/* Tres filas: la de arriba lleva el numeral y la etiqueta a los dos
   extremos, y es la que hace que esto se lea como un indice y no como una
   lista de titulos. El titular va abajo, a todo el ancho del contenido.

   La etiqueta NO va alineada al baseline del titular: el titular mide 3rem
   y la etiqueta terminaba colgada 40px mas abajo que el numeral, flotando
   sola en el medio de la fila. */
.indice__n {
  grid-column: 1;
  grid-row: 1;
  margin: 0;
  font-family: var(--f-mono);
  font-size: clamp(1.5rem, 2.6vw, 2.1rem);
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--acento-texto);
}
.indice__et {
  grid-column: 2 / -1;
  grid-row: 1;
  justify-self: end;
  align-self: center;
  color: var(--texto-tenue);
  transition: color var(--dur-media) var(--ease-suave);
}
.indice__fila:hover .indice__et { color: var(--acento-texto); }

.indice__tit {
  grid-column: 2 / -1;
  grid-row: 2;
  margin: 0;
  font-size: clamp(1.9rem, 3.6vw, 3rem);
  font-weight: 500;
  letter-spacing: -0.03em;
  color: var(--texto);
}

.indice__txt {
  grid-column: 2;
  grid-row: 3;
  margin: 0;
  max-width: 46ch;
  color: var(--texto-suave);
}

.indice__lista {
  grid-column: 3;
  grid-row: 3;
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.65rem;
  align-content: start;
}
/* En la sans, no en mono: al envolver a dos lineas la mono deja de leerse
   como etiqueta y pasa a leerse como cuerpo. */
.indice__lista li {
  display: flex;
  gap: 0.7rem;
  align-items: flex-start;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--texto-suave);
}
.indice__lista li::before {
  content: "";
  width: 5px;
  height: 5px;
  margin-top: 0.55em;
  background: var(--acento);
  flex-shrink: 0;
  opacity: 0.8;
}

/* A 900 la fila no da para tres columnas: el rail se achica y el cuerpo
   y la lista se apilan en la misma columna. */
@media (max-width: 900px) {
  .indice__fila {
    grid-template-columns: clamp(2.6rem, 8vw, 3.6rem) minmax(0, 1fr);
    row-gap: clamp(1rem, 3vw, 1.5rem);
  }
  .indice__et  { grid-column: 2; }
  .indice__tit { grid-column: 2; }
  .indice__txt { grid-column: 2; grid-row: 3; max-width: 60ch; }
  .indice__lista { grid-column: 2; grid-row: 4; }
}
@media (max-width: 620px) {
  .indice__fila { grid-template-columns: auto 1fr; }
  .indice__n   { grid-column: 1; grid-row: 1; font-size: 1.05rem; }
  .indice__et  { grid-column: 2; grid-row: 1; }
  .indice__tit { grid-column: 1 / -1; grid-row: 2; }
  .indice__txt { grid-column: 1 / -1; grid-row: 3; }
  .indice__lista { grid-column: 1 / -1; grid-row: 4; }
}

/* ============================================================
   ENCABEZADO DE SECCIÓN reutilizable
   ============================================================ */
.enc { margin-bottom: clamp(3rem, 7vw, 5rem); }
.enc__et { display: flex; align-items: center; gap: 0.9rem; margin-bottom: 1.6rem; }
.enc h2 { font-size: var(--t-h1); max-width: 30ch; }
.enc p { color: var(--texto-suave); margin-top: 1.4rem; }

.enc--corrido {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: var(--s-borde);
  align-items: end;
}
.enc--corrido p { margin: 0; align-self: end; }
@media (max-width: 900px) { .enc--corrido { grid-template-columns: 1fr; } }

/* ============================================================
   AUTOMATIZACIÓN — franja más profunda, contenedor normal adentro
   ============================================================ */
.auto {
  background: var(--fondo-hondo);
  border-block: 1px solid var(--linea);
}
/* El titular de esta sección baja de --t-h1 (hasta 4rem) a --t-h2 (hasta
   2,6rem). Es la única sección sobre magenta pleno: a 4rem, en blanco y
   sobre un fondo de luminancia media, el titular se comía la sección
   entera y peleaba con los numerales grandes de "Cosas que ya
   automatizamos", que son los que tienen que llevar el peso acá.
   Va con .auto para no tocar el resto de los encabezados del sitio. */
.auto .enc h2 { font-size: var(--t-h2); max-width: 26ch; }
/* Sin relleno y sin caja: tres columnas separadas por una linea vertical.
   El truco viejo era gap:1px con el fondo del contenedor haciendo de linea,
   pero eso OBLIGA a que cada celda tenga fondo propio — y ese fondo, sobre
   el magenta, era un rosa lavado. Mas recuadros, justo lo que se saco. */
.auto__flujo {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--linea);
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}
.auto__paso {
  padding: clamp(1.8rem, 3vw, 2.6rem) clamp(1.4rem, 2.6vw, 2.2rem);
  border-left: 1px solid var(--linea);
}
.auto__paso:first-child { border-left: 0; padding-left: 0; }
.auto__paso .et { margin-bottom: 1rem; }
.auto__paso h3 { font-size: var(--t-h3); font-weight: 500; margin-bottom: 0.7rem; }
/* :not(.et) porque etiqueta y bajada comparten el tag p: sin esto
   .auto__paso p (0,1,1) le gana a .et--acento (0,1,0) y apaga el magenta */
.auto__paso p:not(.et) { font-size: var(--t-small); color: var(--texto-suave); margin: 0; }
@media (max-width: 820px) {
  .auto__flujo { grid-template-columns: 1fr; }
  /* apilado, la linea que separa tiene que ser horizontal */
  .auto__paso { border-left: 0; border-top: 1px solid var(--linea); padding-left: 0; }
  .auto__paso:first-child { border-top: 0; }
}

/* ------------------------------------------------------------
   COSAS QUE YA AUTOMATIZAMOS — el panel que viaja

   Port del "card hover effect" de Aceternity. Ver js/hover.js para la
   mecanica; aca va la piel, que es lo unico que NO se copia del original.

   El original: rounded-3xl, bg-black, borde white/[0.2], panel
   bg-slate-800/[0.8]. Nada de eso entra:

     · a escuadra, sin radio — todo el sitio es a escuadra (es el manual) y
       los recuadros redondeados ya se habian rebotado una vez
     · en reposo NO hay caja ni borde: numeral, titulo y texto sobre el
       fondo. La caja existe solo mientras el cursor esta encima
     · el panel es blanco translucido, que sobre el magenta profundo del
       bloque se lee como una superficie levantada

   DOS columnas y no tres: el flujo ENTRA/PASA/SALE de arriba ya es una
   grilla de tres. Con tres se repetiria la forma una linea mas abajo, que
   es justo el problema que esto viene a resolver.
   ------------------------------------------------------------ */
.casos-auto {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.4rem, 1vw, 0.8rem);
}

/* El panel unico. Va detras de todo (z-index 0) y las tarjetas se apoyan
   encima; sin eso el texto quedaria tapado.

   Se anima width/height y no scale: escalando, el texto de adentro no se
   deforma porque el panel es un elemento aparte, pero los bordes se ven
   estirados en el viaje. Con width/height el borde se mantiene nitido.
   Son 5 tarjetas, no hay problema de rendimiento.

   El color va por --panel-hover (tokens.css) y no fijo: este mismo panel
   ahora tambien lo usa .proceso__grid, que vive sobre papel en vez de
   sobre el magenta profundo del bloque. Blanco al 13% se hace invisible
   sobre blanco, asi que el token se redefine por contexto — mismo criterio
   que --fondo o --texto en vez de un valor hardcodeado en esta regla. */
.hover-panel {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  width: 0;
  height: 0;
  background: var(--panel-hover);
  opacity: 0;
  pointer-events: none;
  transition:
    transform 320ms var(--ease-suave),
    width     320ms var(--ease-suave),
    height    320ms var(--ease-suave),
    opacity   150ms linear;
}
.hover-panel.esta-visible { opacity: 1; }
/* la primera aparicion no viaja: nace donde esta el cursor */
.hover-panel.sin-viaje {
  transition: opacity 150ms linear;
}

.caso-auto {
  position: relative;
  z-index: 1;
  padding: clamp(1.5rem, 2.8vw, 2.2rem) clamp(1.2rem, 2.4vw, 1.8rem);
}
/* La quinta a lo ancho: con 5 en dos columnas la ultima quedaria sola y
   descolgada. A lo ancho es una asimetria buscada, no un sobrante. */
.caso-auto:last-child { grid-column: 1 / -1; }
.caso-auto:last-child p { max-width: 70ch; }

/* Numeral grande — misma mecánica que .paso__n en Proceso ("la mecánica
   se repite, la piel no"), pero re-teñida para ESTE fondo: sobre papel
   el numeral grande apagado usa --texto al 22% porque el acento (magenta)
   ya está en todos lados y hace falta contenerlo. Acá es al revés — la
   sección entera es magenta+blanco desde .magenta (tokens.css: ahí el
   acento pasa a ser blanco, porque el magenta puro sobre magenta-fondo
   da 1,54:1) y por eso se siente chata. El negro es el tercer color de
   marca que esta sección no estaba usando: mide 3,68:1 sobre
   --magenta-fondo, de sobra para texto grande (AA pide 3:1 desde 24px;
   esto arranca en 2,6rem/41,6px). */
.caso-auto__n {
  display: block;
  font-family: var(--f-display);
  font-weight: 700;
  font-size: clamp(2.6rem, 5vw, 4rem);
  line-height: 0.85;
  letter-spacing: -0.05em;
  color: var(--negro);
  opacity: 0.85;
  margin-bottom: 1rem;
  transition: opacity var(--dur-media) var(--ease-suave);
}
.caso-auto:hover .caso-auto__n { opacity: 1; }
.caso-auto h3 {
  font-size: var(--t-h4);
  font-weight: 500;
  letter-spacing: -0.02em;
  margin-bottom: 0.6rem;
}
.caso-auto p {
  margin: 0;
  font-size: var(--t-small);
  color: var(--texto-suave);
}

@media (max-width: 760px) {
  .casos-auto { grid-template-columns: 1fr; }
  .caso-auto { padding-inline: 0; }
  .caso-auto:last-child { grid-column: 1; }
  .caso-auto__n { font-size: clamp(2.2rem, 11vw, 2.8rem); }
}
}

/* ============================================================
   DEMOS — tres automatizaciones funcionando en la página
   ============================================================ */
.demos { background: var(--fondo); }

.demo-tabs { display: flex; flex-wrap: wrap; gap: 0.7rem; margin-bottom: clamp(2rem, 4vw, 3rem); }
.demo-tab {
  display: inline-flex; align-items: center; gap: 0.7rem;
  font-family: var(--f-mono);
  font-size: var(--t-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.8rem 1.35rem;
  border: 1px solid var(--linea-fuerte);
  background: transparent;
  color: var(--texto-suave);
  cursor: pointer;
  transition:
    background-color var(--dur-rapida) var(--ease-suave),
    border-color     var(--dur-rapida) var(--ease-suave),
    color            var(--dur-rapida) var(--ease-suave);
}
.demo-tab:hover { border-color: var(--acento); color: var(--texto); }
.demo-tab[aria-selected="true"] {
  background: var(--acento);
  border-color: var(--acento);
  color: var(--papel);
  font-weight: 500;
}
.demo-tab__n { opacity: 0.65; }

.demo-panel {
  border: 1px solid var(--linea);
  background: var(--superficie);
  padding: clamp(1.3rem, 3.5vw, 3rem);
  min-height: 30rem;
}
.demo-panel[hidden] { display: none; }
.demo-dos {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.6rem, 4vw, 3.5rem);
  align-items: start;
}
@media (max-width: 860px) { .demo-dos { grid-template-columns: 1fr; } }

.demo-nota {
  font-size: var(--t-small);
  color: var(--texto-tenue);
  margin: 1.4rem 0 0;
  max-width: 52ch;
}

/* ---- Demo 1: bot de WhatsApp ----
   El mockup mantiene los colores reales de WhatsApp a propósito: es una
   captura de producto, no cromática de marca. Un WhatsApp teñido de
   petróleo se leería como falso. */
.tel {
  width: 100%;
  max-width: 320px;
  margin-inline: auto;
  border: 6px solid var(--negro-2);
  border-radius: 2rem;
  overflow: hidden;
  background: var(--negro-2);
}
.tel__cab {
  display: flex; align-items: center; gap: 0.7rem;
  padding: 0.7rem 0.9rem;
  background: #075E54;
}
.tel__av {
  width: 34px; height: 34px; border-radius: 50%;
  background: #128C7E;
  display: grid; place-items: center;
  font-size: 0.7rem; font-weight: 700; color: #fff;
  flex-shrink: 0;
}
.tel__cab strong { display: block; font-size: 0.85rem; color: #fff; font-weight: 500; line-height: 1.2; }
.tel__cab small { font-size: 0.68rem; color: #b7dfd7; }
.tel__chat {
  height: 21rem;
  overflow-y: auto;
  padding: 0.8rem;
  display: flex; flex-direction: column; gap: 0.45rem;
  background: #0b141a;
  scrollbar-width: thin;
}
.msg {
  max-width: 85%;
  padding: 0.5rem 0.65rem;
  border-radius: 0.5rem;
  font-size: 0.82rem;
  line-height: 1.45;
  white-space: pre-line;
  color: #e9edef;
  animation: entrar-msg var(--dur-media) var(--ease-suave) both;
}
.msg--bot { align-self: flex-end; background: #005c4b; border-top-right-radius: 0; }
.msg--cli { align-self: flex-start; background: #202c33; border-top-left-radius: 0; }
.msg--sys {
  align-self: center; max-width: 100%;
  background: oklch(1 0 0 / 0.1);
  font-size: 0.66rem; text-align: center; color: #cfd9d6;
  padding: 0.25rem 0.55rem;
}
.msg time { display: block; margin-top: 0.2rem; font-size: 0.62rem; text-align: right; opacity: 0.6; }
.msg--tipeando { align-self: flex-end; background: #005c4b; display: flex; gap: 0.25rem; padding: 0.7rem 0.8rem; }
.msg--tipeando i {
  width: 5px; height: 5px; border-radius: 50%;
  background: #b7dfd7;
  animation: puntear 1.2s var(--ease-suave) infinite;
}
.msg--tipeando i:nth-child(2) { animation-delay: 0.15s; }
.msg--tipeando i:nth-child(3) { animation-delay: 0.3s; }
@keyframes entrar-msg { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes puntear { 0%, 100% { opacity: 0.3; } 50% { opacity: 1; } }

/* ---- Demo 2: factura leída por IA ---- */
.mail {
  border: 1px solid var(--linea);
  background: var(--superficie);
}
.mail__cab {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--linea);
}
.mail__cuerpo { padding: 1rem; display: grid; gap: 0.45rem; font-size: var(--t-small); }
.mail__cuerpo span { color: var(--texto-tenue); }
.mail__adj {
  display: inline-flex; align-items: center; gap: 0.5rem;
  margin-top: 0.6rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--linea);
  font-family: var(--f-mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  color: var(--texto-suave);
}
.punto-vivo {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--acento);
  animation: latir 2.2s var(--ease-suave) infinite;
  flex-shrink: 0;
}
@keyframes latir { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

.pasos-ia { display: grid; gap: 0.6rem; }
.paso-ia {
  display: flex; align-items: flex-start; gap: 0.9rem;
  border: 1px solid var(--linea);
  padding: 0.85rem 1rem;
  opacity: 0.5;
  transition: opacity var(--dur-media) var(--ease-suave), border-color var(--dur-media) var(--ease-suave);
}
.paso-ia[data-estado="activo"] { opacity: 1; border-color: var(--linea-acento); }
.paso-ia[data-estado="hecho"]  { opacity: 1; }
.paso-ia__n {
  width: 26px; height: 26px; flex-shrink: 0;
  border: 1px solid var(--linea-fuerte);
  border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--f-mono); font-size: 0.68rem;
  color: var(--texto-tenue);
  transition: all var(--dur-media) var(--ease-suave);
}
.paso-ia[data-estado="activo"] .paso-ia__n { border-color: var(--acento); color: var(--acento); }
.paso-ia[data-estado="hecho"]  .paso-ia__n { border-color: var(--acento); background: var(--acento); color: var(--papel); }
.paso-ia strong { display: block; font-weight: 400; font-size: 0.95rem; }
.paso-ia small { display: block; font-size: 0.8rem; color: var(--texto-tenue); margin-top: 0.1rem; }

.campos-ia {
  margin: 0.2rem 0 0 2.4rem;
  border: 1px solid var(--linea);
  padding: 0.6rem 0.9rem;
  display: grid; gap: 0.35rem;
}
.campos-ia > div {
  display: flex; justify-content: space-between; gap: 1rem;
  font-family: var(--f-mono); font-size: 0.7rem;
  animation: entrar-msg var(--dur-rapida) var(--ease-suave) both;
}
.campos-ia dt, .campos-ia span:first-child { color: var(--texto-tenue); letter-spacing: 0.06em; }
.campos-ia span:last-child { color: var(--texto); }

/* ---- Demo 3: calculadora de ahorro ---- */
.roi { max-width: 46rem; margin-inline: auto; }
.roi__mandos { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1.4rem, 3vw, 2.5rem); margin-bottom: 2.4rem; }
@media (max-width: 700px) { .roi__mandos { grid-template-columns: 1fr; } }
.roi__mando > div { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: 0.7rem; }
.roi__mando label { font-size: var(--t-small); color: var(--texto-suave); }
.roi__valor { font-family: var(--f-mono); font-size: 1.05rem; color: var(--acento); white-space: nowrap; }
.roi__mando small { display: block; font-size: 0.78rem; color: var(--texto-tenue); margin-top: 0.55rem; }
.roi__mando input[type="range"] {
  width: 100%;
  accent-color: var(--magenta);
  height: 1.4rem;
  background: transparent;
  cursor: pointer;
}
.roi__salida { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--linea); border: 1px solid var(--linea); }
@media (max-width: 620px) { .roi__salida { grid-template-columns: 1fr; } }
.roi__caja { background: var(--superficie); padding: clamp(1.4rem, 3vw, 2.2rem); text-align: center; }
.roi__caja--gana { border-top: 2px solid var(--acento); }
.roi__caja .et { display: block; margin-bottom: 0.9rem; }
.roi__cifra {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: clamp(1.6rem, 4vw, 2.5rem);
  letter-spacing: -0.035em;
  line-height: 1;
  color: var(--texto);
}

/* ============================================================
   TIRA PARALLAX — PRUEBA: port del "Hero Parallax" de Aceternity
   ============================================================
   Decorativa (ver aria-hidden en el HTML): sin título, sin link, sin
   texto por miniatura. La prueba de que son sitios reales la sigue
   dando la lista de abajo (.pila) — esto es sólo la pared de fotos
   antes de entrar al detalle.

   Base SIN JS (o con prefers-reduced-motion): una fila común que envuelve
   si no entra, sin alto de recorrido reservado. Con JS, tira-parallax.js
   agrega .con-recorrido, fija el alto en scroll-runway y anima el
   transform a mano seguÍn el scroll — ver ese archivo para la fórmula.

   Reteñido del original (que no tenía casi piel: es sólo fotos):
   rounded-* → nada (a escuadra, como el resto del sitio); shadow-2xl al
   hover y el overlay bg-black con título → afuera enteros, porque acá no
   hay hover ni título. Lo único que queda del original es la mecánica de
   inclinar/enderezar y correr las filas para lados opuestos. */
.tira-parallax {
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
}
.tira-parallax__esc {
  overflow: hidden;
}
.tira-parallax__grupo {
  display: flex;
  flex-direction: column;
  gap: clamp(0.6rem, 1.4vw, 1rem);
}
.tira-parallax__fila {
  display: flex;
  gap: clamp(0.6rem, 1.4vw, 1rem);
  flex-wrap: wrap;
}
.tira-parallax__miniatura {
  display: block;
  flex: 1 1 220px;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border: 1px solid var(--linea);
  background: var(--fondo-hondo);
  /* es un <button>: pisar el reset del navegador */
  padding: 0;
  font: inherit;
  cursor: pointer;
  transition: border-color var(--dur-rapida) var(--ease-suave);
}
.tira-parallax__miniatura:hover,
.tira-parallax__miniatura:focus-visible { border-color: var(--linea-acento); }
.tira-parallax__miniatura:focus-visible { outline: 2px solid var(--acento); outline-offset: 3px; }
.tira-parallax__miniatura img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  transition: transform var(--dur-lenta) var(--ease-suave);
}
@media (hover: hover) and (pointer: fine) {
  .tira-parallax__miniatura:hover img { transform: scale(1.04); }
}

/* ---- con JS: recorrido de scroll + inclinación 3D ----
   Sin centrar: el grupo va arriba de todo y el alto extra (RESOLVE_PX en
   tira-parallax.js) queda íntegro DEBAJO, como distancia de scroll — si
   se centrara quedaría la mitad de ese aire ARRIBA también, y eso sí
   sería el colchón vacío que se evitó al no repartirlo en el JS. */
.tira-parallax.con-recorrido .tira-parallax__esc {
  perspective: 1000px;
}
.tira-parallax.con-recorrido .tira-parallax__grupo {
  width: 100%;
  transform-style: preserve-3d;
  will-change: transform, opacity;
}
.tira-parallax.con-recorrido .tira-parallax__fila {
  flex-wrap: nowrap;
  will-change: transform;
}
.tira-parallax.con-recorrido .tira-parallax__miniatura {
  flex: 0 0 clamp(160px, 20vw, 260px);
}

/* Igual que .pila__panel: por debajo de 900px la mecánica no traduce.
   4 miniaturas sin wrap en 390px de ancho quedan del tamaño de una uña,
   y encima la pila mobile ya muestra la foto de cada caso en su propia
   ficha — repetirlas acá, chicas, no suma nada. Afuera entera. */
@media (max-width: 900px) {
  .tira-parallax { display: none; }
}

/* ============================================================
   VISOR — la captura grande, de a una (js/visor.js)
   ============================================================
   Mismo patrón de diálogo que .chat: fixed, opacity+pointer-events en vez
   de display (así la transición de cierre se ve), aria-hidden a mano.
   El velo usa --chapa (tokens.css) — pensado para esto, no lo usaba nadie
   todavía. z-index 300: por encima del nav (100) y del chat/fab (95-96),
   que es lo más alto que hay en el resto del sitio. */
.visor {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  padding: clamp(1.2rem, 4vw, 3rem);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-media) var(--ease-suave);
}
.visor.abierto { opacity: 1; pointer-events: auto; }

.visor__velo {
  position: absolute;
  inset: 0;
  background: var(--chapa);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.visor__caja {
  position: relative;
  z-index: 1;
  width: min(92vw, 1200px);
  display: grid;
  grid-template-columns: 1fr;
  justify-items: center;
}

.visor__figura {
  margin: 0;
  width: 100%;
  max-height: 76vh;
  border: 1px solid var(--linea-acento);
  background: var(--negro);
  overflow: hidden;
  display: grid;
  place-items: center;
}
.visor__figura img {
  display: block;
  width: 100%;
  height: 100%;
  max-height: 76vh;
  object-fit: contain;
}

.visor__pie {
  display: flex;
  align-items: baseline;
  gap: 0.8rem;
  margin-top: 1rem;
  color: var(--blanco);
  text-align: center;
}
.visor__titulo { font-weight: 500; }
.visor__dom {
  font-family: var(--f-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  color: oklch(1 0 0 / 0.6);
}

.visor__cerrar {
  position: absolute;
  top: clamp(0.8rem, 2vw, 1.4rem);
  right: clamp(0.8rem, 2vw, 1.4rem);
  z-index: 2;
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border: 1px solid oklch(1 0 0 / 0.3);
  background: oklch(0 0 0 / 0.4);
  color: var(--blanco);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color var(--dur-rapida) var(--ease-suave), color var(--dur-rapida) var(--ease-suave);
}
.visor__cerrar:hover { border-color: var(--acento); color: var(--acento); }

/* Las flechas y el contador van fuera de .visor__figura (no adentro,
   como el original de Aceternity no tiene): acá conviven con la mecánica
   de .carrusel__flecha ya existente en Diseño & Merch, misma piel. */
.visor__flecha {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 1px solid oklch(1 0 0 / 0.3);
  border-radius: var(--radio);
  background: oklch(0 0 0 / 0.4);
  color: var(--blanco);
  cursor: pointer;
  transition: color var(--dur-rapida) var(--ease-suave), border-color var(--dur-rapida) var(--ease-suave), opacity var(--dur-rapida) var(--ease-suave);
}
.visor__flecha svg { width: 18px; height: 18px; }
.visor__flecha:hover:not(:disabled) { color: var(--acento); border-color: var(--acento); }
.visor__flecha:disabled { opacity: 0.25; cursor: default; }
.visor__flecha--prev { left: clamp(-0.5rem, -2vw, 0.5rem); }
.visor__flecha--next { right: clamp(-0.5rem, -2vw, 0.5rem); }

.visor__cuenta {
  position: absolute;
  bottom: clamp(-1.6rem, -3vw, -1rem);
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--f-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  color: oklch(1 0 0 / 0.5);
  font-variant-numeric: tabular-nums;
}

.visor__cerrar:focus-visible,
.visor__flecha:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }

@media (max-width: 640px) {
  .visor__flecha { width: 2.3rem; height: 2.3rem; }
  .visor__flecha--prev { left: 0; }
  .visor__flecha--next { right: 0; }
  .visor__pie { flex-direction: column; gap: 0.2rem; }
}

/* ============================================================
   TRABAJO REAL — la pila (sticky scroll reveal de Aceternity)

   Dos columnas: la de la izquierda scrollea con la página, la de la
   derecha queda pegada y cambia de foto según qué ficha esté en el centro.

   Todo lleva el prefijo pila__ y no es capricho: .paso ya era la etapa del
   proceso y .ficha ya era la ficha tecnica del merch (que ADEMAS es sticky).
   Las dos se pisaban en silencio.

   El apagado de los casos inactivos NO va en .pila__caso sino en sus hijos:
   .pila__caso lleva .reveal, y .reveal.visible {opacity:1} tiene dos clases
   de especificidad — le gana a cualquier .pila__caso{opacity:...} y
   el apagado no se vería nunca. Apagando los hijos las dos cosas conviven.
   ============================================================ */
.pila {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr);
  gap: clamp(2.5rem, 6vw, 6rem);
  align-items: start;
}
.pila__lista { display: flex; flex-direction: column; }

.pila__caso {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: clamp(1.2rem, 2.4vw, 2.2rem);
  align-content: center;
  /* alto de una ficha ~ media pantalla: diez fichas a pantalla entera son
     diez scrolls y nadie llega al final */
  min-height: 46vh;
  padding-block: clamp(2.2rem, 5vh, 3.2rem);
  border-top: 1px solid var(--linea);
}
/* el primero arranca arriba del todo: con align-content:center su texto
   caia 200px mas abajo que el panel y los dos empezaban desalineados */
.pila__caso:first-child { border-top: 0; padding-top: 0; align-content: start; }

.pila__ord {
  grid-column: 1;
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  color: var(--texto-tenue);
  line-height: 1;
  transition: color var(--dur-media) var(--ease-suave);
}
.pila__ord span { display: block; margin-top: 0.35rem; opacity: 0.6; }
/* el filete que crece: es el que marca cuál está activa, junto con el
   magenta del numeral. El gris solo no alcanzaba para notarlo. */
.pila__ord::after {
  content: "";
  display: block;
  width: 1px;
  height: 0;
  margin-top: 0.9rem;
  background: var(--acento-texto);
  transition: height var(--dur-lenta) var(--ease-suave);
}
.pila__caso.es-activo .pila__ord { color: var(--acento-texto); }
.pila__caso.es-activo .pila__ord::after { height: clamp(2rem, 5vh, 3.4rem); }

.pila__cuerpo { grid-column: 2; }
.pila__caso h3 {
  font-size: var(--t-h3);
  font-weight: 500;
  letter-spacing: -0.025em;
  margin-bottom: 0.5rem;
}
.pila__rubro { display: block; margin-bottom: 1.1rem; }
/* --texto y no --texto-suave: apagado al 58% el suave se cae por debajo
   de AA. Medido sobre papel: negro al 58% da 5,33:1; el suave no llega. */
.pila__txt {
  color: var(--texto);
  max-width: 46ch;
  margin: 0;
}
.pila__ir {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1.5rem;
  padding-bottom: 0.4rem;
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  color: var(--acento-texto);
  border-bottom: 1px solid var(--linea-acento);
  transition: color var(--dur-rapida) var(--ease-suave),
              border-color var(--dur-rapida) var(--ease-suave);
}
.pila__ir:hover, .pila__ir:focus-visible {
  color: var(--texto);
  border-bottom-color: var(--texto);
}
.pila__dom {
  margin: 1.5rem 0 0;
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  color: var(--texto-tenue);
}
.pila__nota { letter-spacing: 0.04em; opacity: 0.8; }

/* el apagado va aca, en los hijos — ver la nota de arriba */
.pila__ord, .pila__cuerpo {
  opacity: 0.58;
  transition: opacity var(--dur-media) var(--ease-suave),
              color var(--dur-media) var(--ease-suave);
}
.pila__caso.es-activo .pila__ord,
.pila__caso.es-activo .pila__cuerpo { opacity: 1; }

/* la foto dentro de la ficha existe para el movil y para el caso sin JS;
   en escritorio la muestra el panel, clonada */
.pila__foto { display: none; }

/* ------------------------------------------------------------
   EL PANEL PEGADO
   ------------------------------------------------------------ */
.pila__panel { position: sticky; top: clamp(5.5rem, 13vh, 8rem); }

.marco {
  display: block;
  border: 1px solid var(--linea);
  background: var(--fondo-hondo);
  color: inherit;
  text-decoration: none;
  transition: border-color var(--dur-media) var(--ease-suave);
}
.marco--mudo { cursor: default; }
.marco:not(.marco--mudo):hover { border-color: var(--linea-acento); }

.marco__barra {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--linea);
}
.marco__pto {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--linea-fuerte);
  flex-shrink: 0;
}
.marco__pto--vivo { background: var(--acento); }
/* min-width:0 o el dominio largo empuja el badge fuera del marco */
.marco__dom {
  min-width: 0;
  margin-left: 0.6rem;
  font-family: var(--f-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  color: var(--texto-suave);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.marco__vivo {
  margin-left: auto;
  flex-shrink: 0;
  font-family: var(--f-mono);
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--acento-texto);
}
.marco__vivo[hidden] { display: none; }

.marco__foto {
  position: relative;
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--fondo-hondo);
}
.lamina {
  position: absolute;
  inset: 0;
  display: block;
  opacity: 0;
  transform: scale(1.045);
  transition: opacity var(--dur-lenta) var(--ease-suave),
              transform 1.2s var(--ease-suave);
}
.lamina img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: top center;
}
.lamina.es-activa { opacity: 1; transform: none; }
.marco:not(.marco--mudo):hover .lamina.es-activa { transform: scale(1.03); }

.marco__abrir {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1rem;
  border-top: 1px solid var(--linea);
  font-family: var(--f-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  color: var(--texto-suave);
  transition: color var(--dur-rapida) var(--ease-suave);
}
.marco:not(.marco--mudo):hover .marco__abrir { color: var(--acento-texto); }

/* ------------------------------------------------------------
   MOVIL — sin panel: cada ficha lleva su foto y su link
   ------------------------------------------------------------ */
@media (max-width: 900px) {
  .pila { grid-template-columns: 1fr; gap: 0; }
  .pila__panel { display: none; }

  .pila__caso {
    min-height: 0;
    padding-block: clamp(2rem, 6vw, 3rem);
    align-content: start;
  }
  .pila__caso:first-child { padding-top: 0; }
  /* nada de apagar en movil: no hay panel que explique por que una ficha
     esta mas clara que la otra, asi que seria solo texto peor */
  .pila__ord, .pila__cuerpo { opacity: 1; }
  .pila__caso.es-activo .pila__ord::after { height: 0; }

  .pila__foto {
    display: block;
    grid-column: 1 / -1;
    position: relative;
    margin: 1.6rem 0 0;
    aspect-ratio: 16 / 10;
    overflow: hidden;
    border: 1px solid var(--linea);
    background: var(--fondo-hondo);
  }
  .pila__foto img {
    display: block;
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: top center;
  }
}
@media (max-width: 560px) {
  .pila__caso { grid-template-columns: 1fr; row-gap: 0.9rem; }
  .pila__ord { grid-column: 1; display: flex; align-items: center; gap: 0.5rem; }
  .pila__ord span { margin-top: 0; }
  .pila__ord::after { display: none; }
  .pila__cuerpo { grid-column: 1; }
}

/* El badge "En vivo" sobre la foto: lo usan la ficha del movil y el marco.
   Va absolute, asi que su contenedor tiene que ser relative — lo son. */
.vivo {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-family: var(--f-mono); font-size: 0.62rem;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--acento);
  position: absolute; top: 0.9rem; left: 0.9rem; z-index: 3;
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--linea-acento);
  background: oklch(0 0 0 / 0.66);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.vivo i { width: 5px; height: 5px; border-radius: 50%; background: var(--acento); animation: latir 2.2s var(--ease-suave) infinite; }

/* ============================================================
   DISEÑO Y MERCH — sección CLARA (hueso), como las cards del manual.
   La fotografía de producto se lee mejor sobre claro, y rompe la
   monotonía sin inventar un color que el manual no tenga.
   ============================================================ */
.merch { border-block: 1px solid oklch(0 0 0 / 0.14); }
.merch__enc { padding: var(--s-seccion) var(--s-borde) clamp(2.5rem, 5vw, 4rem); }
.merch__enc > * { max-width: var(--ancho-normal); margin-inline: auto; }

/* ------------------------------------------------------------
   EL CARRUSEL

   Lo que había escondía el 62% del contenido a 1440 sin ningún aviso: no
   tenía flechas, ni indicador, ni arrastre, ni teclado. Y tres bugs
   medidos: el `1fr` del minmax nunca resolvía (en un grid con
   grid-auto-flow:column y contenido que desborda el espacio libre es cero,
   así que la tarjeta quedaba clavada en 230px a TODO ancho), el gesto
   lateral disparaba el "atrás" del navegador, y la rueda del mouse
   preventDefault-eaba sin llegar a mover nada — o sea, congelaba la página.
   ------------------------------------------------------------ */
.carrusel { position: relative; }

.tira-fotos {
  display: grid;
  grid-auto-flow: column;
  /* ancho real, no un 1fr que nunca gana */
  grid-auto-columns: clamp(232px, 26vw, 330px);
  gap: 1px;
  background: var(--linea-tenue);
  border-block: 1px solid var(--linea);
  overflow-x: auto;
  scroll-snap-type: x proximity;   /* mandatory se comía los pasos cortos */
  overscroll-behavior-x: contain;  /* que el gesto no navegue hacia atrás */
  scroll-behavior: smooth;         /* no se hereda del html */
  scrollbar-width: thin;
  cursor: grab;
}
.tira-fotos:active { cursor: grabbing; }
.tira-fotos.arrastrando { scroll-behavior: auto; scroll-snap-type: none; }

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

.tira-fotos .foto {
  margin: 0;
  scroll-snap-align: start;
  aspect-ratio: 4 / 5;
  background: var(--superficie);
}
.tira-fotos .foto > img {
  filter: saturate(0.9) brightness(0.94);
  transition: filter var(--dur-media) var(--ease-suave), transform var(--dur-lenta) var(--ease-suave);
  /* si no, arrastrar la tira dispara el drag nativo de la imagen */
  -webkit-user-drag: none;
  user-select: none;
}
/* El hover va detrás de la consulta: en touch se quedaba clavado */
@media (hover: hover) and (pointer: fine) {
  .tira-fotos .foto:hover > img { filter: none; transform: scale(1.03); }
}

/* --- Mandos --- */
.carrusel__mandos {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1.1rem var(--s-borde) 0;
  max-width: var(--ancho-normal);
  margin-inline: auto;
}

.carrusel__flecha {
  display: grid;
  place-items: center;
  width: 2.75rem; height: 2.75rem;
  flex-shrink: 0;
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio);
  background: transparent;
  color: var(--texto-suave);
  cursor: pointer;
  transition:
    color        var(--dur-rapida) var(--ease-suave),
    border-color var(--dur-rapida) var(--ease-suave),
    opacity      var(--dur-rapida) var(--ease-suave);
}
.carrusel__flecha svg { width: 17px; height: 17px; }
.carrusel__flecha:hover:not(:disabled) { color: var(--acento); border-color: var(--acento); }
.carrusel__flecha:active:not(:disabled) { transform: translateY(1px); }
.carrusel__flecha:disabled { opacity: 0.3; cursor: default; }

/* La barra de progreso: reemplaza a la scrollbar del sistema como pista
   de cuánto falta. El ancho del pulgar es la proporción visible. */
.carrusel__pista {
  flex: 1;
  height: 2px;
  background: var(--linea);
  position: relative;
  overflow: hidden;
}
.carrusel__pulgar {
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 30%;
  background: var(--acento);
  transition: transform var(--dur-rapida) var(--ease-suave);
  will-change: transform;
}

.carrusel__cuenta {
  font-family: var(--f-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  color: var(--texto-tenue);
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 620px) {
  .carrusel__mandos { gap: 0.6rem; }
  .carrusel__flecha { width: 2.4rem; height: 2.4rem; }
  .carrusel__cuenta { display: none; }
}

.merch__cuerpo { padding: clamp(3rem, 6vw, 5rem) var(--s-borde) var(--s-seccion); }
.merch__cols {
  max-width: var(--ancho-normal);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
@media (max-width: 900px) { .merch__cols { grid-template-columns: 1fr; } }

.lista-lineas { display: grid; }
.lista-lineas > div {
  display: grid;
  grid-template-columns: 2.6rem 1fr;
  gap: 1.2rem;
  padding: 1.3rem 0;
  border-top: 1px solid var(--linea);
}
.lista-lineas > div:last-child { border-bottom: 1px solid var(--linea); }
.lista-lineas h3 { font-size: var(--t-h4); font-weight: 500; margin-bottom: 0.4rem; }
.lista-lineas p { margin: 0; font-size: var(--t-small); color: var(--texto-suave); }

/* Ficha técnica en mono — la estética de presupuesto del manual.
   Pegajosa: la lista de la izquierda es más larga y sin esto queda un
   hueco en L a la derecha. */
.ficha { border: 1px solid var(--linea); position: sticky; top: 6rem; background: var(--papel); }
@media (max-width: 900px) { .ficha { position: static; } }
.ficha__cab {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem 1.1rem;
  background: var(--acento);
}
.ficha__cab span {
  font-family: var(--f-mono); font-size: 0.66rem;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--papel);
}
.ficha dl { margin: 0; padding: 0.4rem 1.1rem 1.1rem; }
.ficha div {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem 0;
  border-bottom: 1px dashed var(--linea);
}
.ficha div:last-child { border-bottom: 0; }
.ficha dt { font-family: var(--f-mono); font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--texto-tenue); }
.ficha dd { margin: 0; font-family: var(--f-mono); font-size: 0.8rem; color: var(--texto); text-align: right; }

/* ============================================================
   PROCESO
   ============================================================ */
/* Hasta acá tenía el mismo criterio que el índice y que el flujo de
   automatización: columnas separadas por una línea, numeral grande
   apagado. Tres secciones seguidas con la misma receta se leen como una
   sola cosa repetida, no como un sitio coherente — y para cuando el
   visitante llega acá ya vio esa receta dos veces.

   Ahora usa el panel que viaja de COSAS QUE YA AUTOMATIZAMOS (js/hover.js
   + .hover-panel más arriba) en vez de las líneas divisorias: sin caja en
   reposo, aparece bajo el cursor y se desliza de una etapa a la otra.
   hover.js ya recorre TODAS las [data-hover-grilla] de la página sin
   distinguir cuál es cuál, así que esto es puro HTML (data-hover-grilla /
   data-hover en index.html) — no hubo que tocar el JS.

   El numeral grande sigue siendo el numeral grande: la mecánica se repite,
   la piel no. Si esto se viera igual que .caso-auto volveríamos a tener
   el mismo problema con otro nombre. */
.proceso__grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.4rem, 1vw, 0.8rem);
}
.paso {
  position: relative;
  z-index: 1;
  padding: clamp(1.8rem, 3vw, 2.6rem) clamp(1.4rem, 2.4vw, 2.2rem);
}
.paso__n {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: clamp(2.6rem, 5vw, 4rem);
  line-height: 0.85;
  letter-spacing: -0.05em;
  color: var(--texto);
  /* al 16% sobre papel el numeral casi no existia; sin la caja gris detras
     todavia menos. Sube a 0.22 y el hover lo enciende en magenta. */
  opacity: 0.22;
  margin-bottom: 1.6rem;
  transition: opacity var(--dur-media) var(--ease-suave), color var(--dur-media) var(--ease-suave);
}
.paso:hover .paso__n { opacity: 1; color: var(--acento); }
.paso h3 { font-size: var(--t-h3); font-weight: 500; margin-bottom: 0.8rem; }
/* mismo caso que .auto__paso: el numeral también es un <p> */
.paso p:not(.paso__n) { margin: 0; font-size: var(--t-small); color: var(--texto-suave); }

@media (max-width: 540px) {
  .proceso__grid { grid-template-columns: 1fr; }
}

/* ============================================================
   PRESUPUESTO — el vidrio montado sobre la franja
   ============================================================ */
.presu {
  background: var(--fondo-hondo);
  border-top: 1px solid var(--linea);
  padding-bottom: clamp(3rem, 6vw, 5rem);
  position: relative;
  overflow: clip;
}
/* La trama del manual detrás del formulario: es lo que el vidrio refracta. */
.presu__trama {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: var(--trama);
  background-size: var(--trama-tam);
}
.presu > .cont { position: relative; z-index: 1; }
.presu h2 { font-size: var(--t-h1); }
.presu__grid {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
@media (max-width: 900px) { .presu__grid { grid-template-columns: 1fr; } }

.datos { display: grid; gap: 1.7rem; margin-top: 2.6rem; }
.datos > div { display: grid; gap: 0.35rem; }
.datos a { transition: color var(--dur-rapida) var(--ease-suave); }
.datos a:hover { color: var(--acento); }
.datos strong { font-weight: 400; font-size: 1.05rem; }

/* La superposición: la card sube sobre el borde de la franja */
.form-vidrio { margin-top: clamp(-6rem, -7vw, -2rem); }
@media (max-width: 900px) { .form-vidrio { margin-top: 0; } }

.form { padding: clamp(1.6rem, 3.5vw, 2.8rem); }
.form__cab {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: 0.8rem;
  padding-bottom: 1.2rem;
  margin-bottom: 1.8rem;
  border-bottom: 1px solid var(--linea);
}
.form__cab strong { font-family: var(--f-mono); font-size: 0.78rem; letter-spacing: 0.2em; text-transform: uppercase; font-weight: 500; }

.campos { display: grid; grid-template-columns: 1fr 1fr; gap: 1.3rem; }
.campo { display: grid; gap: 0.45rem; }
.campo--ancho { grid-column: 1 / -1; }
.campo label {
  font-family: var(--f-mono);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--texto-tenue);
}
.campo input, .campo textarea {
  font-family: var(--f-texto);
  font-size: 1rem;
  font-weight: 300;
  color: var(--texto);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--linea-fuerte);
  padding: 0.6rem 0;
  border-radius: 0;
  transition: border-color var(--dur-media) var(--ease-suave);
}
.campo textarea { resize: vertical; min-height: 4.5rem; }
.campo input:focus, .campo textarea:focus {
  outline: none;
  border-bottom-color: var(--acento);
}
/* Con el mouse basta el subrayado; con teclado hace falta un indicador
   de verdad, si no el campo enfocado no se distingue. */
.campo input:focus-visible, .campo textarea:focus-visible {
  outline: 2px solid var(--acento);
  outline-offset: 4px;
  border-bottom-color: var(--acento);
}
@media (max-width: 620px) { .campos { grid-template-columns: 1fr; } }

.chips { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.chip { position: relative; }
.chip input { position: absolute; opacity: 0; pointer-events: none; }
.chip span {
  display: inline-block;
  font-family: var(--f-mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.55rem 1rem;
  border: 1px solid var(--linea-fuerte);
  color: var(--texto-suave);
  cursor: pointer;
  transition:
    background-color var(--dur-rapida) var(--ease-suave),
    border-color     var(--dur-rapida) var(--ease-suave),
    color            var(--dur-rapida) var(--ease-suave);
}
.chip input:checked + span {
  background: var(--acento);
  border-color: var(--acento);
  color: var(--papel);
}
.chip input:focus-visible + span { outline: 2px solid var(--acento); outline-offset: 3px; }

/* Sin border-top: el subrayado del textarea ya hace de regla. */
.form__pie {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem;
  margin-top: 2.6rem;
}
.form__nota { font-size: 0.85rem; color: var(--texto-tenue); margin: 0; max-width: 40ch; line-height: 1.5; }

/* ============================================================
   FOOTER
   ============================================================ */
.pie { border-top: 1px solid var(--linea); padding: clamp(3.5rem, 7vw, 5.5rem) var(--s-borde) 7rem; }
.pie__grid {
  max-width: var(--ancho-normal);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 5fr 3fr 4fr;
  gap: clamp(2rem, 5vw, 4rem);
  padding-bottom: 3rem;
}
.pie__marca { display: flex; align-items: center; gap: 0.85rem; margin-bottom: 1.4rem; }
.pie__marca .iso { width: 32px; }
.pie__marca span { font-family: var(--f-display); font-weight: 700; font-size: 1.6rem; letter-spacing: -0.04em; color: var(--texto); }
.pie p { color: var(--texto-tenue); font-size: var(--t-small); max-width: 34ch; }
.pie ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.7rem; }
.pie li a, .pie li { font-size: var(--t-small); color: var(--texto-suave); }
.pie li a:hover { color: var(--acento); }
.pie__legal {
  max-width: var(--ancho-normal);
  margin-inline: auto;
  padding-top: 1.6rem;
  border-top: 1px solid var(--linea);
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.8rem;
}
@media (max-width: 780px) { .pie__grid { grid-template-columns: 1fr; } }

/* ============================================================
   FLOTANTES — chatbot (principal) + WhatsApp (secundario)
   ============================================================ */
.flotantes {
  position: fixed;
  right: clamp(0.9rem, 3vw, 2rem);
  bottom: clamp(0.9rem, 3vw, 2rem);
  z-index: 95;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  align-items: flex-end;
}
.fab {
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--linea-acento);
  background: var(--nav-fondo);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  color: var(--acento);
  cursor: pointer;
  transition: transform var(--dur-media) var(--ease-suave), background-color var(--dur-media) var(--ease-suave), color var(--dur-media) var(--ease-suave);
}
.fab:hover { transform: translateY(-3px); background: var(--acento); color: var(--papel); }
.fab--chat { width: 56px; height: 56px; }
.fab--chat svg { width: 25px; height: 25px; }
.fab--wa { width: 44px; height: 44px; }
.fab--wa svg { width: 21px; height: 21px; }
.fab__punto {
  position: absolute;
  top: 2px; right: 2px;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--acento);
  border: 2px solid var(--fondo);
}
.fab--chat { position: relative; }
.flotantes.chat-abierto .fab--chat .fab__punto { display: none; }

/* ============================================================
   CHATBOT
   ============================================================ */
.chat {
  position: fixed;
  right: clamp(0.9rem, 3vw, 2rem);
  bottom: calc(clamp(0.9rem, 3vw, 2rem) + 7.5rem);
  z-index: 96;
  width: min(23rem, calc(100vw - 1.8rem));
  max-height: min(34rem, calc(100vh - 11rem));
  display: flex;
  flex-direction: column;
  overflow: hidden;
  opacity: 0;
  transform: translateY(12px) scale(0.98);
  pointer-events: none;
  transition:
    opacity   var(--dur-media) var(--ease-suave),
    transform var(--dur-media) var(--ease-suave);
}
.chat.abierto { opacity: 1; transform: none; pointer-events: auto; }

.chat__cab {
  display: flex; align-items: center; gap: 0.7rem;
  padding: 0.9rem 1rem;
  border-bottom: 1px solid var(--linea);
  flex-shrink: 0;
}
.chat__cab .iso { width: 30px; }
.chat__cab div { flex: 1; min-width: 0; }
.chat__cab strong {
  display: block;
  font-family: var(--f-display); font-weight: 700;
  font-size: 0.95rem; letter-spacing: -0.03em;
  color: var(--texto);
  line-height: 1.2;
}
.chat__cab small {
  font-family: var(--f-mono); font-size: 0.6rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--texto-tenue);
}
.chat__cerrar {
  background: none; border: 0; cursor: pointer;
  color: var(--texto-tenue);
  font-size: 1.35rem; line-height: 1;
  padding: 0.2rem 0.35rem;
  transition: color var(--dur-rapida) var(--ease-suave);
}
.chat__cerrar:hover { color: var(--acento); }

.chat__hilo {
  flex: 1;
  min-height: 8rem;
  overflow-y: auto;
  padding: 1rem;
  display: flex; flex-direction: column; gap: 0.7rem;
  scrollbar-width: thin;
}
.burbuja {
  max-width: 88%;
  font-size: 0.9rem;
  line-height: 1.55;
  padding: 0.65rem 0.85rem;
  border: 1px solid var(--linea);
  animation: entrar-msg var(--dur-media) var(--ease-suave) both;
}
.burbuja--kivo { align-self: flex-start; background: oklch(1 0 0 / 0.05); color: var(--texto-suave); }
.burbuja--kivo strong { color: var(--texto); font-weight: 500; }
.burbuja--yo {
  align-self: flex-end;
  background: var(--acento);
  border-color: var(--acento);
  color: var(--papel);
}
.burbuja--tipeando { display: flex; gap: 0.3rem; align-items: center; padding: 0.8rem 0.9rem; }
.burbuja--tipeando i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--acento);
  animation: puntear 1.2s var(--ease-suave) infinite;
}
.burbuja--tipeando i:nth-child(2) { animation-delay: 0.15s; }
.burbuja--tipeando i:nth-child(3) { animation-delay: 0.3s; }

.chat__ops {
  display: flex; flex-wrap: wrap; gap: 0.4rem;
  padding: 0 1rem 1rem;
  flex-shrink: 0;
}
.chat__op {
  font-family: var(--f-mono);
  font-size: 0.64rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.45rem 0.75rem;
  border: 1px solid var(--linea-fuerte);
  background: transparent;
  color: var(--texto-suave);
  cursor: pointer;
  text-align: left;
  transition:
    border-color var(--dur-rapida) var(--ease-suave),
    color        var(--dur-rapida) var(--ease-suave);
}
.chat__op:hover { border-color: var(--acento); color: var(--acento); }
.chat__op--fuerte { border-color: var(--acento); color: var(--acento); }

.chat__pie {
  border-top: 1px solid var(--linea);
  padding: 0.7rem 1rem;
  flex-shrink: 0;
}
.chat__pie p {
  margin: 0;
  font-family: var(--f-mono);
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--texto-tenue);
}

@media (max-width: 520px) {
  .chat { bottom: calc(clamp(0.9rem, 3vw, 2rem) + 7rem); max-height: calc(100vh - 10rem); }
}

/* ============================================================
   INTERRUPTOR DE DÍA Y NOCHE

   La mecánica es la de "animated-theme-toggler" (Magic UI): la View
   Transitions API saca una foto del antes y el después, y el tema nuevo
   se abre con un clip-path circular desde el botón. La estética NO: el
   botón es hairline y sale de los tokens, como el resto del sitio.
   Las reglas de ::view-transition viven en tokens.css.
   ============================================================ */
.tema-btn {
  display: grid;
  place-items: center;
  width: 2.6rem; height: 2.6rem;
  flex-shrink: 0;
  padding: 0;
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio);
  background: transparent;
  color: var(--texto-suave);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition:
    color        var(--dur-rapida) var(--ease-suave),
    border-color var(--dur-rapida) var(--ease-suave);
}
.tema-btn:hover { color: var(--acento); border-color: var(--acento); }
.tema-btn:active { transform: translateY(1px); }

/* Los dos íconos comparten celda: cero salto de layout al cambiar */
.tema-btn svg { grid-area: 1 / 1; width: 1.05rem; height: 1.05rem; }

/* Por defecto el sitio está en oscuro, así que se ofrece el sol.
   Con data-tema="claro" se ofrece la luna. */
/* De día se ofrece la luna; de noche, el sol. */
.tema-btn .ico-sol { display: none; }
:root[data-tema="oscuro"] .tema-btn .ico-sol  { display: block; }
:root[data-tema="oscuro"] .tema-btn .ico-luna { display: none; }

/* En el menú móvil el interruptor va con etiqueta, no suelto */
.menu-movil__pie {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 2.4rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--linea);
}
.menu-movil__pie .et { margin: 0; }

/* ============================================================
   EL NAV MARCA DÓNDE ESTÁS
   La página mide más de 14 pantallas y no había ni un aria-current.
   ============================================================ */
.nav__links a[aria-current="true"] { color: var(--texto); }
.nav__links a[aria-current="true"]::after { width: 100%; background: var(--acento); }

/* ============================================================
   ESTADOS QUE FALTABAN
   Había 20 reglas :hover contra 6 de :focus y CERO :active en toda la
   página: nada devolvía el gesto de apretar, y quince hovers no tenían
   equivalente de teclado.
   ============================================================ */
.btn:focus-visible,
.nav__links a:focus-visible,
.pieza:focus-visible { outline: 2px solid var(--acento); outline-offset: 3px; }

.nav__links a:focus-visible::after { width: 100%; }

.btn:active { transform: translateY(1px); }
.btn:focus-visible svg { transform: translateX(4px); }

.demo-tab:active { transform: translateY(1px); }
.chat__op:active { transform: translateY(1px); }
.fab:active { transform: translateY(-1px); }

/* El hover del zoom de las piezas, detrás de la consulta: en touch se
   quedaba clavado después de tocar. */
@media (hover: hover) and (pointer: fine) {
  a.pieza:hover .pieza__dom { color: var(--acento); }
}

/* Los chips del formulario declaraban transición pero no tenían ninguna
   regla de hover: la transición estaba muerta. */
.chip span:hover { border-color: var(--linea-fuerte); color: var(--texto); }
.chip input:focus-visible + span { outline: 2px solid var(--acento); outline-offset: 2px; }

/* ============================================================
   EL SLIDER DEL ROI
   Era el único lugar de toda la página donde se veía chrome de Windows:
   el track y el thumb eran los del sistema operativo.
   ============================================================ */
.roi__mando input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 1.6rem;
  background: transparent;
  cursor: pointer;
}

.roi__mando input[type="range"]::-webkit-slider-runnable-track {
  height: 2px;
  background: var(--linea-fuerte);
}
.roi__mando input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px; height: 14px;
  margin-top: -6px;
  border-radius: 50%;
  border: 0;
  background: var(--acento);
  transition: transform var(--dur-rapida) var(--ease-suave);
}
.roi__mando input[type="range"]:hover::-webkit-slider-thumb,
.roi__mando input[type="range"]:focus-visible::-webkit-slider-thumb { transform: scale(1.25); }

.roi__mando input[type="range"]::-moz-range-track {
  height: 2px;
  background: var(--linea-fuerte);
}
.roi__mando input[type="range"]::-moz-range-thumb {
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 0;
  background: var(--acento);
  transition: transform var(--dur-rapida) var(--ease-suave);
}
.roi__mando input[type="range"]:hover::-moz-range-thumb,
.roi__mando input[type="range"]:focus-visible::-moz-range-thumb { transform: scale(1.25); }

.roi__mando input[type="range"]:focus-visible { outline: 2px solid var(--acento); outline-offset: 6px; }

/* ============================================================
   SISTEMAS A MEDIDA — las apps reales, en un teléfono

   Adentro del teléfono manda la marca DEL CLIENTE, no la de KIVO: Revire
   va en brasa y dorado, SIGECOM en navy. Es a propósito y es lo que hace
   creíble la sección — y de paso le da a la página un respiro de color
   entre tanto magenta sobre negro. Por eso acá hay #fff y hex sueltos:
   son la UI del cliente, igual que el mock de WhatsApp de las demos.
   ============================================================ */
.sistemas { background: var(--fondo-hondo); }

.caso {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: clamp(2.5rem, 6vw, 6rem);
  align-items: center;
  padding-block: clamp(3.5rem, 8vw, 7rem);
  border-top: 1px solid var(--linea);
}
.caso:first-of-type {
  border-top: 0;
  /* el encabezado de sección ya separa: sumarle el padding entero del caso
     dejaba ~200px muertos entre el titular y el primer teléfono */
  padding-top: clamp(1rem, 2vw, 2rem);
}
.caso--invertido .caso__fono { order: 2; }

@media (max-width: 900px) {
  .caso { grid-template-columns: 1fr; gap: 2.8rem; }
  .caso--invertido .caso__fono { order: 0; }
}

.caso__fono { display: flex; justify-content: center; }

.caso__texto h3 {
  font-size: clamp(1.6rem, 3vw, 2.3rem);
  font-weight: 500;
  letter-spacing: var(--tr-titulo);
  margin: 0.9rem 0 1.2rem;
}
.caso__texto h3 em {
  font-style: italic;
  font-weight: 300;
  color: var(--acento);
}
.caso__texto > p { color: var(--texto-suave); font-size: var(--t-small); }

.caso__lista { list-style: none; padding: 0; margin: 1.8rem 0 0; display: grid; }
.caso__lista li {
  position: relative;
  padding: 0.75rem 0 0.75rem 1.7rem;
  border-top: 1px solid var(--linea);
  font-size: var(--t-small);
  color: var(--texto-suave);
}
.caso__lista li:last-child { border-bottom: 1px solid var(--linea); }
.caso__lista li::before {
  content: "";
  position: absolute;
  left: 0; top: 1.32rem;
  width: 7px; height: 7px;
  background: var(--acento);
}

.caso__nota {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin: 1.8rem 0 0;
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--linea);
  font-family: var(--f-mono);
  font-size: 0.66rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--texto-tenue);
  max-width: none;
}

/* ------------------------------------------------------------
   El teléfono
   ------------------------------------------------------------ */
.fono { position: relative; width: 282px; max-width: 100%; }
@media (max-width: 380px) { .fono { width: 246px; } }

.fono__lat {
  position: absolute;
  width: 3px;
  background: var(--linea-fuerte);
  z-index: 0;
}
.fono__lat--a { left: -3px; top: 112px; height: 34px; border-radius: 2px 0 0 2px; }
.fono__lat--b { left: -3px; top: 158px; height: 56px; border-radius: 2px 0 0 2px; }
.fono__lat--c { right: -3px; top: 140px; height: 64px; border-radius: 0 2px 2px 0; }

.fono__marco {
  position: relative;
  z-index: 1;
  border-radius: 2.6rem;
  padding: 8px;
  background: oklch(0.16 0.012 250);
  border: 1px solid var(--linea-fuerte);
}

.fono__pantalla {
  position: relative;
  overflow: hidden;
  border-radius: 2rem;
  height: 566px;
  color: #fff;
}

.fono__isla {
  position: absolute;
  left: 50%; top: 9px;
  transform: translateX(-50%);
  z-index: 30;
  width: 88px; height: 25px;
  border-radius: 999px;
  background: oklch(0.06 0 0);
}

.fono__barra {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.6rem 1.25rem 0.2rem;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
  opacity: 0.92;
  position: relative;
  z-index: 20;
}
.fono__estado { display: flex; align-items: center; gap: 5px; }
.fono__estado svg { height: 10px; width: auto; }
.fono__estado svg:nth-child(3) { height: 11px; }

.fono__vista {
  position: relative;
  height: calc(566px - 30px);
  overflow: hidden;
}

/* ------------------------------------------------------------
   Pantalla 01 · Revire — brasa y dorado
   ------------------------------------------------------------ */
.pant-revire {
  --brasa-oro: #e0a458;
  --brasa-hueso: #fbf3ea;
  background: radial-gradient(120% 70% at 50% -10%, #3a160b 0%, #1c0a00 45%, #100604 100%);
  color: var(--brasa-hueso);
}

.rv__cab {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.55rem 0.85rem;
  background: oklch(0.12 0.02 40 / 0.85);
  border-bottom: 1px solid rgb(224 164 88 / 0.18);
}
.rv__volver {
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border-radius: 0.55rem;
  font-size: 17px; line-height: 1;
  color: var(--brasa-oro);
  background: rgb(224 164 88 / 0.08);
  border: 1px solid rgb(224 164 88 / 0.22);
}
.rv__id { flex: 1; min-width: 0; line-height: 1.15; }
.rv__id strong {
  display: block;
  font-size: 12.5px; font-weight: 600;
  letter-spacing: 0.18em;
}
.rv__id small {
  font-size: 7.5px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--brasa-oro);
}
.rv__pill {
  border-radius: 999px;
  padding: 0.22rem 0.55rem;
  font-size: 9px; font-weight: 600;
  color: #ff8a3d;
  background: rgb(242 100 25 / 0.12);
  border: 1px solid rgb(242 100 25 / 0.35);
  white-space: nowrap;
}

.rv__hero { padding: 0.9rem 1rem 0.7rem; }
.rv__lugar {
  margin: 0;
  font-size: 7.5px;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: rgb(224 164 88 / 0.8);
}
.rv__tit {
  margin: 0.25rem 0 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 29px; font-weight: 600;
  line-height: 1;
  letter-spacing: 0;
  color: var(--brasa-hueso);
}
.rv__frase {
  margin: 0.3rem 0 0;
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-size: 11.5px;
  color: var(--brasa-oro);
  max-width: none;
}

.rv__platos { padding: 0 0.85rem; display: grid; gap: 0.55rem; }
.rv__plato {
  display: flex; align-items: center; gap: 0.7rem;
  border-radius: 0.7rem;
  padding: 0.55rem;
  background: rgb(251 243 234 / 0.04);
  border: 1px solid rgb(224 164 88 / 0.14);
}
.rv__miniatura {
  width: 42px; height: 42px;
  flex-shrink: 0;
  border-radius: 0.5rem;
  background: linear-gradient(135deg, #7c1d10, #b91c1c 55%, #f26419);
}
.rv__datos { min-width: 0; flex: 1; }
.rv__nombre {
  margin: 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 13.5px; font-weight: 600;
  line-height: 1.15;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rv__desc {
  margin: 0;
  font-size: 8.5px;
  line-height: 1.3;
  color: rgb(251 243 234 / 0.45);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rv__precio { margin: 0.1rem 0 0; font-size: 11px; font-weight: 700; color: var(--brasa-oro); }

.rv__add {
  flex-shrink: 0;
  border: 1px solid transparent;
  border-radius: 0.5rem;
  padding: 0.35rem 0.55rem;
  font-size: 9.5px; font-weight: 700;
  color: #fff;
  background: linear-gradient(135deg, #7c1d10, #b91c1c 55%, #f26419);
  transition:
    background-color var(--dur-media) var(--ease-suave),
    color            var(--dur-media) var(--ease-suave);
}
.rv__plato[data-en="si"] .rv__add {
  background: rgb(224 164 88 / 0.15);
  border-color: rgb(224 164 88 / 0.4);
  color: var(--brasa-oro);
}

.rv__carrito {
  position: absolute;
  inset: auto 0 0 0;
  margin: 0.75rem;
  display: flex; align-items: center; justify-content: space-between;
  border-radius: 0.7rem;
  padding: 0.7rem 0.95rem;
  background: rgb(251 243 234 / 0.06);
  opacity: 0.5;
  transition: opacity var(--dur-lenta) var(--ease-suave),
              background-color var(--dur-lenta) var(--ease-suave);
}
.rv__carrito[data-vivo="si"] {
  opacity: 1;
  background: linear-gradient(135deg, #7c1d10, #b91c1c 55%, #f26419);
}
.rv__carrito-izq {
  display: flex; align-items: center; gap: 0.5rem;
  font-size: 11.5px; font-weight: 700; color: #fff;
}
.rv__cuenta {
  display: grid; place-items: center;
  width: 19px; height: 19px;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.25);
  font-size: 9.5px;
}
.rv__total { font-size: 12.5px; font-weight: 800; color: #fff; }

/* ------------------------------------------------------------
   Pantalla 02 · SIGECOM — navy
   ------------------------------------------------------------ */
.pant-sigecom {
  background: #eef2f6;
  color: #2b3a4a;
}

.sg__cab {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.7rem 0.9rem;
  color: #fff;
  background: linear-gradient(135deg, #173a63, #4a93d9);
}
.sg__av {
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.95);
  color: #173a63;
  font-size: 13px; font-weight: 800;
}
.sg__id { flex: 1; min-width: 0; line-height: 1.25; }
.sg__id small { display: block; font-size: 9px; opacity: 0.8; }
.sg__id strong { font-size: 13px; font-weight: 700; }
.sg__salir {
  border-radius: 0.45rem;
  padding: 0.22rem 0.55rem;
  font-size: 9.5px;
  background: rgb(255 255 255 / 0.15);
}

.sg__tabs {
  display: flex;
  background: #fff;
  border-bottom: 1px solid #dbe3ec;
  font-size: 9.5px; font-weight: 600;
}
.sg__tab {
  flex: 1;
  text-align: center;
  padding: 0.6rem 0.2rem;
  color: #8497ab;
  border-bottom: 2px solid transparent;
}
.sg__tab--on { color: #173a63; border-bottom-color: #4a93d9; }

.sg__cuerpo {
  padding: 1.1rem 1rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.sg__hoy {
  margin: 0 0 1rem;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #8497ab;
}

.sg__selfie {
  display: grid; place-items: center;
  width: 108px; height: 108px;
  border-radius: 50%;
  color: #4a93d9;
  background: #fff;
  border: 2px dashed #b9cbdd;
  margin-bottom: 0.9rem;
}
.sg__selfie svg { width: 46px; height: 46px; }

.sg__gps {
  display: inline-flex; align-items: center; gap: 0.4rem;
  border-radius: 999px;
  padding: 0.3rem 0.7rem;
  font-size: 9.5px; font-weight: 600;
  color: #0f7b4f;
  background: #e2f5ec;
  border: 1px solid #b7e3ce;
}
.sg__gps i {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: #12a566;
}

.sg__accion { width: 100%; margin-top: 1.1rem; }
.sg__btn {
  width: 100%;
  border: 0;
  border-radius: 0.7rem;
  padding: 0.85rem;
  font-size: 13px; font-weight: 700;
  color: #fff;
  background: linear-gradient(135deg, #173a63, #4a93d9);
}

.sg__ok {
  width: 100%;
  margin-top: 1.1rem;
  display: none;
  align-items: center;
  gap: 0.6rem;
  text-align: left;
  border-radius: 0.7rem;
  padding: 0.7rem 0.85rem;
  background: #e2f5ec;
  border: 1px solid #b7e3ce;
  animation: entrar-msg var(--dur-media) var(--ease-suave) both;
}
.sg__cuerpo[data-fichado="si"] .sg__ok { display: flex; }
.sg__cuerpo[data-fichado="si"] .sg__accion { display: none; }
.sg__cuerpo[data-fichado="si"] .sg__selfie {
  border-style: solid;
  border-color: #12a566;
  color: #12a566;
}
.sg__ok-tilde {
  display: grid; place-items: center;
  width: 26px; height: 26px;
  flex-shrink: 0;
  border-radius: 50%;
  background: #12a566;
  color: #fff;
  font-size: 14px; font-weight: 700;
}
.sg__ok strong { display: block; font-size: 12px; color: #0f7b4f; }
.sg__ok small { font-size: 9.5px; color: #4c7d67; }

/* ============================================================
   BLOQUE MAGENTA A SANGRE

   Dos secciones enteras (Automatización y Presupuesto). Antes iban en
   magenta 100% con texto negro. Juan las rebotó — "quedó todo magenta",
   y pidió texto blanco.

   El blanco sobre magenta 100% mide 3,71:1 y AA pide 4,5, así que
   "blanco sobre magenta" obliga a elegir CUÁL magenta. El fondo bajó al
   mismo hue de marca pero más hondo, oklch(0.54 0.22 355) = #c60475, y
   ahí el blanco da 5,71:1.

   Lo que NO se pudo hacer, y conviene que quede escrito: usar el magenta
   100% como acento ARRIBA de este fondo. Medido, #fd0797 sobre #c60475
   da 1,54:1 — no se lee ni como texto ni como marca gráfica, son el
   mismo color a dos luminancias. Adentro de estos bloques la paleta es
   magenta profundo + blanco, punto. El magenta 100% vive afuera: el
   anillo, los puntos del fondo, los numerales sobre papel, los botones
   y la tira de redes.
   ============================================================ */
.magenta .btn {
  border-color: oklch(1 0 0 / 0.46);
  color: var(--blanco);
}
/* El unico lugar del bloque donde entra el magenta 100%: como TEXTO sobre
   una chapa negra. Ahi mide 5,65:1. Sobre el fondo del bloque no podria —
   son el mismo color a dos luminancias, 1,54:1. */
.magenta .btn:hover {
  border-color: var(--negro);
  background: var(--negro);
  color: var(--magenta);
}
.magenta .btn--lleno {
  background: var(--negro);
  border-color: var(--negro);
  color: var(--magenta);
}
.magenta .btn--lleno:hover {
  background: var(--papel);
  border-color: var(--papel);
  color: var(--negro);
}
/* El filete hereda --acento-texto, que adentro del bloque ya es blanco.
   Antes se forzaba a negro porque el texto era negro; ahora sobraria. */

/* ============================================================
   PANTALLA DE ENTRADA

   El esqueleto (position, z-index, el velo negro) NO esta aca: va inline en
   el <head>, porque si esperara a este archivo se veria el div sin estilo
   arriba de todo. Aca vive el video y la salida.

   object-fit: contain y no cover. El video es cuadrado (960x960) y termina
   con el lockup horizontal completo — ring + KIVO + bajada. Con cover, en
   un celular vertical el cuadrado escala hasta llenar el alto y recorta mas
   de la mitad del ancho: se comeria la bajada y parte del wordmark. Con
   contain no se recorta nada nunca, y como el fondo del video es negro puro
   igual que el velo, no se ve donde termina uno y empieza el otro.
   ============================================================ */
/* EL TAMANO NO ES ESTETICO, ES ARITMETICA. No agrandar sin rehacer la cuenta.

   Lo que se dibuja en pantalla son (ancho en css) x (devicePixelRatio)
   pixeles REALES. Si esa cuenta pasa del ancho de la fuente, el navegador
   esta inventando pixeles y el logo se ve pixelado.

   La fuente ahora mide 2160x2160 (antes 960, y por eso a 620px se veia mal:
   en retina eran 1240 reales desde 960, ampliando 1,29x). Con 2160 el
   margen es enorme y se puede mostrar mucho mas grande:

     escritorio 1440x900   -> 80vh = 720 css · DPR 2 = 1440 de 2160 = 0,67
     escritorio 2560x1440  -> tope  900 css · DPR 2 = 1800 de 2160 = 0,83
     celular    390x844    -> 80vw = 312 css · DPR 3 =  936 de 2160 = 0,43

   Todos por debajo de 1: en ningun caso se amplia. Si algun dia hace falta
   mas grande todavia, se re-renderiza con `node intro-generador/render.js 3240`
   y recien ahi se sube este tope. */
.carga__video,
.carga__fin {
  display: block;
  width: min(80vw, 80vh, 900px);
  aspect-ratio: 1;
  object-fit: contain;
  /* el video ya trae su propio negro; esto es por si tarda en decodificar */
  background: #000;
}

/* Con movimiento reducido no se reproduce: se muestra el ultimo cuadro. */
.carga__fin { display: none; }
@media (prefers-reduced-motion: reduce) {
  .carga__video { display: none; }
  .carga__fin { display: block; }
}

/* El velo se disuelve y el video se va apenas creciendo: sin ese empujon la
   salida se lee como que se apaga la luz, y con el se lee como que la
   camara entra al sitio. */
.carga__velo { transition: opacity 520ms var(--ease-suave); }
.carga__video, .carga__fin { transition: opacity 380ms linear, transform 620ms var(--ease-suave); }

.carga.esta-saliendo { pointer-events: none; }
.carga.esta-saliendo .carga__velo { opacity: 0; }
.carga.esta-saliendo .carga__video,
.carga.esta-saliendo .carga__fin { opacity: 0; transform: scale(1.06); }

/* Los .reveal de la portada se guardan para cuando la capa se levanta: si
   no, el IntersectionObserver los marca visibles DETRAS de la pantalla y
   cuando aparece la portada ya esta armada, sin el escalonado.

   La especificidad no es casual: .reveal.visible mide (0,2,0) y esta regla
   (0,2,1) — dos clases y un elemento. Con `.esta-cargando .reveal` sola no
   alcanzaba y no pasaba nada. */
html.esta-cargando:not(.esta-abriendo) .reveal {
  opacity: 0;
  transform: translateY(1.6rem);
}

/* El mosaico del hero no necesita esta retención: su reloj lo arranca un
   IntersectionObserver que sí dispara detrás de la pantalla de carga,
   pero la primera foto se ve quieta desde el arranque y la primera pasada
   recién ocurre a los 4,5s — o sea, ya con la portada a la vista. Si
   algún día ESPERA_MS de mosaico.js baja de lo que dura la carga (~3,5s),
   hay que retener el reloj igual que acá arriba se retienen los .reveal. */

@media (prefers-reduced-motion: reduce) {
  .carga__velo, .carga__video, .carga__fin { transition-duration: 200ms; }
  .carga.esta-saliendo .carga__fin { transform: none; }
}

/* ============================================================
   REDES — el boton que se abre en abanico (social button de KokonutUI)

   El ancho de la tira NO es auto: CSS no anima hacia auto. Sale de
   --n * --lado, dos variables que pone redes.js. Asi el ancho es exacto
   aunque la tira este oculta y sin layout.

   El icono va NEGRO sobre magenta y no blanco: medido, blanco sobre
   magenta 100% da 3,71:1 y no pasa AA; negro da 5,65:1.
   ============================================================ */
.redes {
  position: relative;
  margin-top: 1.8rem;
  height: 44px;
  width: max-content;
}

/* --- la pildora en reposo --- */
.redes__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  height: 44px;
  padding: 0 1.1rem;
  border: 1px solid var(--linea-fuerte);
  background: transparent;
  color: var(--texto);
  font-family: var(--f-mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: opacity var(--dur-rapida) var(--ease-suave),
              border-color var(--dur-rapida) var(--ease-suave);
}
.redes__btn svg { width: 16px; height: 16px; flex-shrink: 0; }
.redes__btn:hover { border-color: var(--acento); }

/* --- la tira que se abre --- */
.redes__tira {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  height: 44px;
  width: 0;
  overflow: hidden;
  /* la curva del original, tal cual */
  transition: width 0.34s cubic-bezier(0.23, 1, 0.32, 1);
}
.redes__ir {
  flex: 0 0 var(--lado, 44px);
  width: var(--lado, 44px);
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-right: 1px solid oklch(0 0 0 / 0.22);
  background: var(--acento);
  color: var(--negro);
  cursor: pointer;
  opacity: 0;
  transform: translateX(-18px);
  transition: opacity 0.3s cubic-bezier(0.23, 1, 0.32, 1),
              transform 0.3s cubic-bezier(0.23, 1, 0.32, 1),
              background-color var(--dur-rapida) var(--ease-suave),
              color var(--dur-rapida) var(--ease-suave);
}
.redes__ir:last-child { border-right: 0; }
.redes__ir svg { width: 19px; height: 19px; }
.redes__ir:hover, .redes__ir:focus-visible { background: var(--negro); color: var(--blanco); }
/* el flash del original al tocar */
.redes__ir.esta-tocado { transform: scale(0.86); }

/* --- abierta ---
   Nada de :focus-within: ese selector tambien matchea cuando el foco
   esta en el propio boton, y como al abrir el boton se apaga, el que
   navega con teclado perdia de vista donde estaba. La abre redes.js
   cuando el foco cae en un icono. */
.redes.esta-abierta .redes__btn {
  opacity: 0;
  pointer-events: none;
}
.redes.esta-abierta .redes__tira {
  width: calc(var(--n, 3) * var(--lado, 44px));
}
.redes.esta-abierta .redes__ir {
  opacity: 1;
  transform: none;
  transition-delay: calc(var(--i, 0) * 50ms);
}

/* El hover NO se resuelve aca. Lo abria un @media (hover:hover) .redes:hover
   y quedaban dos duenos del mismo estado: con el mouse encima la tira estaba
   abierta pero aria-expanded seguia en "false", y el boton quedaba con
   pointer-events:none, asi que el click no llegaba nunca. Ahora el mouse lo
   escucha redes.js con pointerenter y termina en la misma clase que el tap. */

@media (prefers-reduced-motion: reduce) {
  .redes__tira, .redes__ir, .redes__btn { transition-duration: 0.01ms; }
}

