/* ============================================================
   TECNOLOVIDA — estilos de la página principal
   Antes vivían dentro del HTML. Separados, el navegador los
   guarda en caché una sola vez y el HTML baja mucho más liviano.
   ============================================================ */

@property --angle { syntax:'<angle>'; initial-value:0deg; inherits:false; }

:root{
  --bg:#04070a; --green:#3dffa0; --green2:#39ff6e; --fucsia:#ff2fd6; --cyan:#35e5ff;
  --text:#eafff4; --dim:#8fb6a6; --mono:'Rajdhani',sans-serif;
  --borde:rgba(61,255,160,.28);
  --nav-alto:66px;
}
*{box-sizing:border-box;margin:0;padding:0;}
/* scroll-padding evita que el nav fijo tape el título al saltar por un ancla */
html{scroll-behavior:smooth;font-size:108%;scroll-padding-top:var(--nav-alto);}
/* etiquetas técnicas: misma familia que los títulos, con peso y espaciado */
.nav .links a,.sec .eyebrow,.svc .num,.svc .ex b,.chip,.legacy figcaption,.nw .d,footer{font-weight:600;}
body{background:var(--bg);color:var(--text);font-family:'Inter',sans-serif;overflow-x:hidden;position:relative;min-height:100vh;}
h1,h2,h3,h4{font-family:'Rajdhani',sans-serif;font-weight:700;line-height:1.05;}
a{color:inherit;text-decoration:none;}
/* height:auto es imprescindible junto a los atributos width/height del HTML.
   Esos atributos valen como estilo de baja prioridad: si el CSS solo fija el
   ancho, el alto queda clavado en el número del atributo y la foto sale
   estirada. Con height:auto manda siempre la proporción real del archivo. */
img{max-width:100%;height:auto;display:block;}

/* solo para lectores de pantalla (el H1 real de la página) */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;}

/* ===== SELECCIÓN DE TEXTO =================================
   Bloqueada en toda la página: arrastrar sin querer pintaba los textos de azul
   y quedaba feo. Los campos de formulario se exceptúan a propósito — si no,
   nadie podría corregir lo que escribió. Y arrastrar una imagen deja el
   fantasma pegado al cursor, así que también se desactiva. */
body{-webkit-user-select:none;user-select:none;}
input,textarea,select,[contenteditable="true"]{-webkit-user-select:text;user-select:text;}
img{-webkit-user-drag:none;}

/* ===== INTRO DE ENTRADA ====================================
   La capa está oculta por defecto y sólo aparece si el script en línea del
   <head> puso .con-intro en el <html>. O sea: sin JavaScript no hay intro y el
   sitio entra directo. Nunca al revés.

   El bloqueo del scroll NO se hace acá sino desde intro.js, y a propósito: si
   este archivo lo bloqueara y el script no llegara a cargar, el sitio quedaría
   trabado para siempre. Así, si el script no corre, lo peor que pasa es que se
   vea una pantalla quieta que el rescate de abajo saca a los 8 segundos.

   El resplandor del contorno es un drag-shadow sobre el PNG, que sigue la
   silueta de las letras. El latido es un halo aparte que sólo cambia opacidad
   y escala, para no repintar el filtro en cada cuadro. */
/* OJO con el nombre: la clase se llama .capa-intro y NO .intro, porque el
   sitio ya usaba <p class="intro"> para las bajadas de sección (ver .sec
   .intro más arriba). Con .intro a secas, esta regla convertía cada uno de
   esos tres párrafos en una capa fija de pantalla completa con z-index 9999,
   y se veían amontonados arriba de todo tapando la portada. */
.capa-intro{display:none;}
.con-intro .capa-intro{
  display:block;position:fixed;inset:0;z-index:9999;
  animation:introRescate 0s linear 8s forwards;
}
@keyframes introRescate{to{opacity:0;visibility:hidden;pointer-events:none;}}

.intro-fondo{position:absolute;inset:0;background:#04070a;transition:opacity .45s ease;}
.intro-fondo.fue{opacity:0;}
#introLluvia{position:absolute;inset:0;width:100%;height:100%;display:block;
  transition:opacity .5s ease;}
#introLluvia.fue{opacity:0;}

.intro-centro{position:absolute;inset:0;display:grid;place-items:center;pointer-events:none;}
/* El resplandor sale del contorno de las letras y nada más. Antes había además
   un halo circular de 760px detrás, que se leía como una bola verde alrededor
   del logo en vez de un logo encendido. drop-shadow sigue la silueta del PNG,
   que es justo lo que se quiere; los radios son cortos a propósito. */
.intro-logo{
  position:relative;width:min(560px,76vw);height:auto;
  animation:introBrillo 2.4s ease-in-out infinite;
  will-change:transform,filter;
}
@keyframes introBrillo{
  0%,100%{filter:drop-shadow(0 0 4px  rgba(61,255,160,.85)) drop-shadow(0 0 11px rgba(61,255,160,.42));}
  50%    {filter:drop-shadow(0 0 7px  rgba(61,255,160,1))   drop-shadow(0 0 19px rgba(61,255,160,.68));}
}

.intro-carga{
  position:absolute;left:50%;bottom:15vh;translate:-50% 0;
  width:min(320px,72vw);text-align:center;transition:opacity .25s ease;
}
.intro-carga.fue{opacity:0;}
.intro-barra{height:2px;background:rgba(61,255,160,.16);border-radius:2px;overflow:hidden;}
.intro-barra i{
  display:block;height:100%;background:linear-gradient(90deg,rgba(61,255,160,.5),var(--green));
  transform:scaleX(0);transform-origin:left center;box-shadow:0 0 10px rgba(61,255,160,.7);
}
.intro-carga p{
  margin-top:12px;font-family:var(--mono);font-size:.8rem;letter-spacing:.22em;
  text-transform:uppercase;color:rgba(61,255,160,.8);
}
.intro-carga #introPct{color:#fff;font-variant-numeric:tabular-nums;}

.intro-saltar{
  position:absolute;right:22px;bottom:22px;
  font-family:var(--mono);font-size:.74rem;letter-spacing:.12em;text-transform:uppercase;
  color:rgba(255,255,255,.42);background:transparent;
  border:1px solid rgba(255,255,255,.16);border-radius:100px;padding:8px 16px;
  cursor:pointer;transition:color .2s,border-color .2s,opacity .25s;
}
.intro-saltar:hover{color:var(--green);border-color:rgba(61,255,160,.5);}
.intro-saltar.fue{opacity:0;pointer-events:none;}

.capa-intro.fue{opacity:0;transition:opacity .4s ease;pointer-events:none;}

@media(max-width:640px){
  .intro-carga{bottom:12vh;}
  .intro-logo{width:82vw;}
}

/* ===== LOS QUE TITILAN =====================================
   Antes latía la capa entera: dos millones y medio de píxeles subiendo y
   bajando de brillo. Estos son catorce puntos de tres píxeles — ciento
   veintiséis píxeles animados en total, veinte mil veces menos superficie.
   Y queda mejor: cada uno late a su ritmo y desfasado, como estrellas de
   verdad, en vez de todo el fondo prendiéndose y apagándose junto. */
.chispas{position:fixed;inset:0;z-index:-3;pointer-events:none;}
.chispas i{position:absolute;width:3px;height:3px;border-radius:50%;
  background:currentColor;box-shadow:0 0 7px currentColor;
  animation:chispear 4s ease-in-out infinite alternate;}
@keyframes chispear{from{opacity:.1;transform:scale(.6);}to{opacity:.95;transform:scale(1);}}

.chispas i:nth-child(1) {top:9%;  left:13%; color:var(--green);  animation-duration:3.6s; animation-delay:0s;}
.chispas i:nth-child(2) {top:23%; left:79%; color:var(--fucsia); animation-duration:5.2s; animation-delay:.7s;}
.chispas i:nth-child(3) {top:16%; left:46%; color:#fff;          animation-duration:4.4s; animation-delay:1.9s;}
.chispas i:nth-child(4) {top:39%; left:7%;  color:var(--cyan);   animation-duration:6.1s; animation-delay:.3s;}
.chispas i:nth-child(5) {top:45%; left:63%; color:var(--green);  animation-duration:3.9s; animation-delay:2.4s;}
.chispas i:nth-child(6) {top:32%; left:93%; color:var(--fucsia); animation-duration:5.7s; animation-delay:1.1s;}
.chispas i:nth-child(7) {top:59%; left:27%; color:#fff;          animation-duration:4.8s; animation-delay:3.1s;}
.chispas i:nth-child(8) {top:67%; left:72%; color:var(--green);  animation-duration:6.6s; animation-delay:.5s;}
.chispas i:nth-child(9) {top:53%; left:48%; color:var(--cyan);   animation-duration:4.1s; animation-delay:2.8s;}
.chispas i:nth-child(10){top:75%; left:16%; color:var(--fucsia); animation-duration:5.4s; animation-delay:1.6s;}
.chispas i:nth-child(11){top:82%; left:56%; color:var(--green);  animation-duration:3.4s; animation-delay:.9s;}
.chispas i:nth-child(12){top:71%; left:88%; color:#fff;          animation-duration:6.3s; animation-delay:2.1s;}
.chispas i:nth-child(13){top:91%; left:35%; color:var(--green);  animation-duration:4.6s; animation-delay:3.5s;}
.chispas i:nth-child(14){top:28%; left:34%; color:var(--cyan);   animation-duration:5.9s; animation-delay:1.4s;}

/* Los catorce chispazos quedan también en celular, por decisión del 1/8/2026.
   Se midió que salen caros —Chrome a 390x844 con el procesador frenado 20x:
   con los catorce el scroll de las tarjetas da 33 cuadros/seg y 33,3 ms por
   cuadro; dejando seis sube a 49 y baja a 16,7 ms— pero se prefiere el fondo
   completo. Si alguna vez hay que recortar, este es el lugar y el número:
   bajar a seis recupera casi todo. */
/* ===== LOS DOS RESPLANDORES ================================
   Antes eran dos manchas fijas y chicas pintadas sobre una sola capa. Ahora
   son dos elementos que se desplazan y respiran, más grandes y bien metidos en
   sus esquinas: el verde arriba a la izquierda, el violeta abajo a la derecha.

   El movimiento va SOLO por transform y opacity, que el navegador resuelve en
   la placa sin volver a dibujar nada. Esa es toda la diferencia con la capa de
   destellos que animábamos antes y que dejó el scroll en 20 fps: aquella
   repintaba doce degradados de pantalla completa en cada cuadro. Estas dos se
   dibujan una vez y después solo cambian de lugar.

   No agregar background-position, filter ni box-shadow acá: cualquiera de esos
   vuelve a meter el repintado por cuadro y se pierde lo ganado.

   Cada mancha desborda la pantalla a propósito, para que nunca se vea el borde
   del círculo. Las animaciones se apagan solas con "Pausar movimiento" y con
   prefers-reduced-motion, por las reglas globales del final del archivo.

   Sobre el tamaño: son capas que el navegador mantiene aparte para poder
   moverlas sin repintar, así que cuanto más grandes, más memoria de video. A
   72 y 80vmax dan unos 4,3 millones de píxeles de capa en una pantalla de
   1920 — del orden de lo que ocupaba el campo de destellos viejo. Si en la
   notebook se siente pesado, bajar estos dos números es lo primero que hay que
   probar; se mide con /?fps y el interruptor «Resplandores: congelarlos». */
.glow-bg{position:fixed;inset:0;z-index:-4;pointer-events:none;overflow:hidden;}
.glow-bg i{position:absolute;display:block;border-radius:50%;}
.glow-bg .verde{
  width:72vmax;height:72vmax;top:-30vmax;left:-30vmax;
  background:radial-gradient(circle closest-side,
    rgba(61,255,160,.20),rgba(61,255,160,.07) 50%,transparent 72%);
  animation:derivaVerde 38s ease-in-out infinite alternate;
}
.glow-bg .violeta{
  width:80vmax;height:80vmax;bottom:-34vmax;right:-33vmax;
  background:radial-gradient(circle closest-side,
    rgba(255,47,214,.19),rgba(255,47,214,.07) 50%,transparent 72%);
  animation:derivaVioleta 47s ease-in-out infinite alternate;
}
@keyframes derivaVerde{
  from{transform:translate3d(0,0,0);      opacity:.78;}
  to  {transform:translate3d(7vw,6vh,0);  opacity:1;}
}
@keyframes derivaVioleta{
  from{transform:translate3d(0,0,0);      opacity:1;}
  to  {transform:translate3d(-6vw,-5vh,0);opacity:.76;}
}
.scan{position:fixed;inset:0;z-index:-2;pointer-events:none;opacity:.35;background:repeating-linear-gradient(0deg,transparent 0 3px,rgba(0,0,0,.12) 3px 4px);}

/* ===== BORDES DE LUZ =====================================
   Un degradado cónico obliga al navegador a calcular un arcotangente por cada
   píxel, y al animar el ángulo lo rehace entero en cada cuadro. Con diecisiete
   tarjetas girando a la vez eran casi tres millones de píxeles por cuadro en el
   hilo principal — el mismo que mueve el scroll. De ahí que la página se
   sintiera pesada y que se destrabara al pausar el movimiento.

   Ahora el borde es un degradado fijo, que se dibuja una sola vez y no cuesta
   nada, y la lucecita recorre el borde SOLO cuando apuntás la tarjeta. Además
   de ir fluido queda mejor: el movimiento pasa a ser una respuesta a lo que
   hacés, en vez de ruido permanente. */
@keyframes spin-angle { to { --angle:360deg; } }

.lightborder{position:relative;isolation:isolate;}
.lightborder::before{content:"";position:absolute;inset:0;border-radius:inherit;padding:2px;
  background:linear-gradient(135deg,rgba(61,255,160,.5) 0%,rgba(255,255,255,.32) 28%,rgba(255,47,214,.3) 58%,rgba(61,255,160,.14) 100%);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;
  z-index:-1;}

/* la lucecita arranca al pasar el cursor o al llegar con el teclado */
.lightborder:hover::before,
.lightborder:focus-within::before,
.lightborder.luz-viva::before{
  background:conic-gradient(from var(--angle),transparent 62%,var(--green) 80%,#ffffff 88%,var(--fucsia) 94%,transparent 100%);
  animation:spin-angle 4s linear infinite;}

/* En pantallas táctiles la lucecita NO gira. Queda el filo fijo de arriba.
   -----------------------------------------------------------------------
   La regla de :hover y :focus-within está pensada para un cursor: se enciende
   mientras señalás y se apaga al correrte. Con el dedo no funciona así — un
   toque deja la tarjeta con el foco puesto y la lucecita queda girando
   indefinidamente, incluso mientras scroleás.

   Y girar sale caro. Medido en Chrome a 390x844, con una tarjeta abierta y
   tocada: 338 x 622 = 210.120 píxeles repintados por cuadro, el 64% de la
   pantalla, en el hilo principal — el mismo que mueve el scroll. Eso es lo
   que se siente como que las tarjetas se apilan con tirones.

   El borde no desaparece: se queda el degradado fijo, que se pinta una sola
   vez y no cuesta nada. */
@media (hover:none),(max-width:860px){
  .lightborder:hover::before,
  .lightborder:focus-within::before,
  .lightborder.luz-viva::before{
    background:linear-gradient(135deg,rgba(61,255,160,.5) 0%,rgba(255,255,255,.32) 28%,rgba(255,47,214,.3) 58%,rgba(61,255,160,.14) 100%);
    animation:none;
  }
}

/* El aro del óvalo del hero sí gira siempre: es la marca de la página, es uno
   solo y está arriba de todo. Cuando se va de pantalla el JS lo frena. */
.lightborder.pausa-luz::before,
.hero-oval.pausa-luz .lightring{animation-play-state:paused;}

/* ===== NAV ===== */
.nav{position:fixed;top:0;left:0;right:0;z-index:60;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 22px;backdrop-filter:blur(8px);background:rgba(4,7,10,.55);border-bottom:1px solid rgba(61,255,160,.15);}
.nav .links{display:flex;gap:6px;flex-wrap:wrap;}
.nav .links a{font-family:var(--mono);font-size:.98rem;font-weight:600;color:var(--dim);padding:6px 12px;border-radius:4px;transition:color .18s,transform .18s,text-shadow .18s;}
.nav .links a:hover{color:var(--green);transform:scale(1.12);text-shadow:0 0 10px var(--green);}
.brand-img{height:26px;width:auto;display:block;filter:drop-shadow(0 0 6px rgba(61,255,160,.6));}

/* ===== MENÚ DE CELULAR (las tres líneas) =========================
   No hay dos menús: son los MISMOS enlaces. En computadora .nav .links es una
   fila; abajo de 860 px el CSS los convierte en un panel fijo contra el borde
   derecho y los corre fuera de pantalla. Un solo lugar donde agregar o sacar
   una sección.

   Entra y sale con transform, que resuelve la placa de video sin repintar. Se
   evitó a propósito animar 'right' o 'width', que obligan a rehacer la
   maquetación en cada cuadro — el mismo error que costaba caro al desplegar
   las tarjetas.

   Y NO se bloquea el scroll de la página. Bloquearlo con overflow:hidden hace
   desaparecer la barra de desplazamiento, cambia el ancho útil y corre todo lo
   que está centrado; ya nos pasó con la intro. En su lugar el velo de atrás
   lleva touch-action:none, que frena el arrastre sin tocar la maquetación. */
.menu-btn{display:none;}
.menu-fondo{
  position:fixed;inset:0;z-index:59;background:rgba(2,6,4,.62);
  opacity:0;pointer-events:none;touch-action:none;
  transition:opacity .34s ease;
}
body.menu-abierto .menu-fondo{opacity:1;pointer-events:auto;}
/* Los dos botones flotantes se apartan: están por encima de la barra
   (z-index 120) y si no se quedaban flotando arriba del panel. */
body.menu-abierto .wa-float,
body.menu-abierto .a11y-fab{opacity:0;pointer-events:none;transition:opacity .2s ease;}

@media(max-width:860px){
  /* La barra pierde el desenfoque, y NO es por gusto. Un elemento con
     backdrop-filter se convierte en el marco de referencia de sus hijos
     position:fixed: el panel, que cuelga de la barra, quedaba encerrado
     dentro de ella. Medido: 115 px de alto en una ventana de 844, tapándole
     el botón. Sin desenfoque el panel vuelve a medirse contra la pantalla.
     De paso se deja de recalcular un desenfoque en cada cuadro del scroll,
     que era una de las palancas de rendimiento pendientes. El fondo sube de
     .55 a .94 para que el texto de atrás no se transparente. */
  .nav{
    -webkit-backdrop-filter:none;backdrop-filter:none;
    background:rgba(4,7,10,.94);
    padding:8px 16px;
  }

  .menu-btn{
    display:flex;flex-direction:column;justify-content:center;gap:5px;
    width:44px;height:44px;padding:0 8px;   /* 44 px: el mínimo cómodo para un dedo */
    background:none;border:0;cursor:pointer;position:relative;z-index:2;
    -webkit-tap-highlight-color:transparent;
  }
  .menu-btn span{
    display:block;width:100%;height:2px;border-radius:2px;
    background:var(--green);box-shadow:0 0 6px rgba(61,255,160,.75);
    transition:transform .3s cubic-bezier(.2,.8,.2,1),opacity .18s ease;
  }
  /* Las tres líneas se vuelven una cruz. Con 2 px de línea y 5 px de hueco,
     cada una está a 7 px de la del medio: por eso el translateY(7px). */
  body.menu-abierto .menu-btn span:nth-child(1){transform:translateY(7px) rotate(45deg);}
  body.menu-abierto .menu-btn span:nth-child(2){opacity:0;}
  body.menu-abierto .menu-btn span:nth-child(3){transform:translateY(-7px) rotate(-45deg);}

  .nav .links{
    position:fixed;top:0;right:0;bottom:0;width:min(272px,76vw);
    flex-direction:column;align-items:stretch;flex-wrap:nowrap;gap:4px;
    padding:calc(var(--nav-alto,66px) + 18px) 16px 28px;
    /* Opaco del todo, no casi. Se probó con rgba(...,.975) y ese 2,4% que
       pasaba alcanzaba para leer el texto de atrás: sobre un fondo tan
       oscuro, un 2% de letra blanca ya se distingue. Las tarjetas sí pueden
       ser traslúcidas —tapan poco y por poco tiempo—, un menú no. */
    background:#060c0a;
    border-left:1px solid rgba(61,255,160,.25);
    box-shadow:-18px 0 44px rgba(0,0,0,.55);
    overscroll-behavior:contain;
    z-index:1;                      /* debajo del botón, que va en 2 */
    transform:translateX(100%);
    /* visibility apagada para que los enlaces escondidos no reciban el foco
       con el tabulador ni los lea un lector de pantalla. Se apaga recién al
       terminar de salir (0s con retardo), y se enciende al instante al entrar. */
    visibility:hidden;
    transition:transform .34s cubic-bezier(.22,.8,.24,1),visibility 0s linear .34s;
  }
  body.menu-abierto .nav .links{
    transform:none;visibility:visible;
    transition:transform .34s cubic-bezier(.22,.8,.24,1),visibility 0s;
  }
  .nav .links a{
    font-size:1.06rem;padding:13px 12px;border-radius:8px;
    border-bottom:1px solid rgba(61,255,160,.1);
  }
  .nav .links a:last-child{border-bottom:0;}
  /* El agrandado del escritorio acá no va: con el dedo el :hover queda pegado
     y el enlace se quedaría grande después de tocarlo. */
  .nav .links a:hover{transform:none;}
  .nav .links a:active{background:rgba(61,255,160,.14);color:var(--green);}
}

/* ===== HERO ===== */
.hero{display:flex;flex-direction:column;align-items:center;text-align:center;max-width:940px;margin:0 auto;padding:118px 26px 8px;}
/* óvalo centrado con Matrix adentro */
.hero-oval{position:relative;width:min(700px,92vw);aspect-ratio:3.5/1;border-radius:50%;overflow:hidden;background:#03060a;box-shadow:0 0 54px rgba(61,255,160,.4),inset 0 0 44px rgba(0,0,0,.75);}
.hero-oval canvas{position:absolute;inset:0;width:100%;height:100%;z-index:0;}
.hero-oval .oval-veil{position:absolute;inset:0;z-index:1;background:radial-gradient(closest-side,rgba(3,6,10,.85),rgba(3,6,10,.4) 66%,transparent);}
.hero-oval .oval-logo-img{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:2;width:90%;max-width:660px;height:auto;filter:drop-shadow(0 0 16px rgba(61,255,160,.6));}
.hero-oval .lightring{position:absolute;inset:0;border-radius:50%;padding:2px;z-index:3;pointer-events:none;
  background:conic-gradient(from var(--angle),transparent 60%,var(--green) 80%,#ffffff 88%,var(--fucsia) 95%,transparent 100%);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;
  animation:spin-angle 4s linear infinite;}

/* banda de introducción después del óvalo */
.intro-band{max-width:900px;margin:0 auto;padding:20px 26px 10px;text-align:center;}
/* El rótulo "// SISTEMA DE IMPLEMENTACIÓN DE IA" se sacó el 1/8/2026. El
   margen de arriba del título pasó de 12 a 0 porque era el aire que lo
   separaba de ese rótulo; sin él, sobraba. */
.intro-band h2{font-size:clamp(1.6rem,4vw,2.6rem);margin:0 0 14px;text-shadow:0 0 18px rgba(61,255,160,.3);}
.intro-band p{color:var(--dim);font-size:1.08rem;max-width:640px;margin:0 auto;}

/* ===== SECCIONES ===== */
.sec{max-width:1220px;margin:0 auto;padding:80px 26px;}
/* Páginas internas (noticias, nosotros): no tienen hero, así que la primera
   sección tiene que despejar la barra fija. --nav-alto lo mide app.js de
   verdad, porque la barra crece al pasar a dos líneas en pantallas angostas. */
.subpagina{padding-top:calc(var(--nav-alto,64px) + 42px);}
.volver-inicio{display:inline-flex;align-items:center;gap:8px;font-family:var(--mono);
  font-size:.92rem;font-weight:600;color:var(--dim);padding:8px 16px 8px 13px;
  border:1px solid rgba(61,255,160,.28);border-radius:100px;background:rgba(61,255,160,.05);
  transition:color .2s,border-color .2s,background .2s,transform .2s;}
.volver-inicio:hover{color:#fff;border-color:rgba(61,255,160,.6);
  background:rgba(61,255,160,.12);transform:translateX(-3px);}
.sec .eyebrow{font-family:var(--mono);color:var(--cyan);letter-spacing:2px;font-size:.8rem;}
/* h1 además de h2: en /proyectos el título de la página es el H1 real, y tiene
   que verse igual que los títulos de sección del resto del sitio. */
.sec h1,.sec h2{font-size:clamp(1.7rem,4vw,2.8rem);margin:10px 0 12px;text-shadow:0 0 18px rgba(61,255,160,.28);}
.sec .intro{color:var(--dim);max-width:640px;margin-bottom:40px;}
/* Dos redacciones de la misma pista: se muestra la que corresponde al ancho. */
.pista{color:var(--cyan);}
.pista-toque{display:none;}

/* ===== SERVICIOS con zoom al hover + lucecita ===== */
.svcs{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;align-items:start;}
.svc{position:relative;border-radius:12px;padding:28px 24px;background:rgba(8,16,12,.72);cursor:pointer;overflow:hidden;
  transition:transform .35s cubic-bezier(.2,.8,.2,1),box-shadow .35s;}
/* Sin transform: la tarjeta se queda quieta en su lugar y lo único que pasa es
   que crece hacia abajo al desplegar el texto. Antes se levantaba 6px y se
   agrandaba un 3%, y ese movimiento competía con la apertura. Queda el
   resplandor, que alcanza para saber cuál está señalada. */
.svc:hover{box-shadow:0 16px 50px rgba(0,0,0,.6),0 0 40px rgba(61,255,160,.32);z-index:6;}
/* punto de estado que pulsa */
.svc .pulse{position:absolute;top:16px;right:16px;width:8px;height:8px;border-radius:50%;background:var(--green);box-shadow:0 0 10px var(--green);animation:svcpulse 1.8s ease-in-out infinite;}
@keyframes svcpulse{0%,100%{opacity:1;transform:scale(1);}50%{opacity:.3;transform:scale(.65);}}
/* texto extendido que se revela al pasar el cursor
   -----------------------------------------------
   Acá había tres cosas que hacían que las letras parecieran "acomodarse":

   1. Este aviso ("pasá el cursor para ver más") pasaba a height:0 y margin:0 de
      golpe, sin transición. La tarjeta se achicaba unos 25px en un solo cuadro
      y recién después empezaba a crecer: ese tironcito era el más visible.
      Ahora solo se desvanece y conserva su lugar, así nada de abajo se corre.

   2. El texto de adentro entraba con una animación de opacidad. Mientras una
      animación así está en curso el navegador suaviza las letras de una manera
      y al terminar las vuelve a dibujar de otra: se ven "asentarse". Ahora el
      texto está siempre opaco y aparece solo porque se le corre el recorte.

   3. El margen superior también se animaba. Ahora es fijo. */
.svc .hovertip{font-family:var(--mono);font-size:.68rem;color:var(--cyan);letter-spacing:1px;margin-top:12px;opacity:.7;transition:opacity .3s;}
.svc:hover .hovertip,.svc:focus-within .hovertip{opacity:0;}
.svc .more{max-height:0;overflow:hidden;margin-top:6px;transition:max-height .5s ease;}
.svc:hover .more,.svc:focus-within .more{max-height:560px;}
.svc .more p{color:var(--dim);font-size:.9rem;line-height:1.6;margin-bottom:12px;}
.svc .feats{list-style:none;display:grid;gap:8px;margin-bottom:14px;}
.svc .feats li{position:relative;padding-left:20px;color:var(--text);font-size:.88rem;line-height:1.4;}
.svc .feats li::before{content:"";position:absolute;left:0;top:5px;width:11px;height:6px;border-left:2px solid var(--green);border-bottom:2px solid var(--green);transform:rotate(-45deg);}
/* en celu (sin cursor) se muestra todo siempre */
@media(hover:none){.svc .more{max-height:none;margin-top:12px;}.svc .hovertip{display:none;}}
.svc .num{font-family:var(--mono);font-size:.72rem;color:var(--dim);margin-bottom:14px;}
.svc .ic{width:54px;height:54px;margin-bottom:16px;color:var(--green);filter:drop-shadow(0 0 10px rgba(61,255,160,.6));transition:transform .3s;}
.svc:hover .ic{transform:scale(1.12);}
/* El título ya no se agranda. Escalar texto obliga al navegador a redibujar
   cada letra en un tamaño intermedio y después a redibujarla nítida en el
   definitivo: eso es lo que se veía como si las palabras se reacomodaran.
   Se enciende igual, con el color y el resplandor, que no mueven nada. */
.svc h3{font-size:1.28rem;margin-bottom:10px;transition:text-shadow .3s,color .3s;}
.svc:hover h3{color:#fff;text-shadow:0 0 18px rgba(61,255,160,.85),0 0 34px rgba(255,47,214,.4);}
.svc .b{color:var(--text);font-size:.96rem;margin-bottom:12px;}
.svc .b strong{color:var(--green);}
.svc .ex{color:var(--dim);font-size:.88rem;border-left:2px solid var(--green);padding-left:11px;}
.svc .ex b{color:var(--green);font-family:var(--mono);font-size:.68rem;display:block;letter-spacing:1px;margin-bottom:3px;}
.svc .nota-extra{margin-top:12px;font-family:var(--mono);font-size:.72rem;font-weight:600;color:var(--cyan);letter-spacing:.5px;}

/* waveform del módulo de voz */
.wave{display:flex;align-items:center;gap:3px;height:54px;}
.wave span{width:5px;border-radius:3px;background:var(--green);box-shadow:0 0 8px var(--green);animation:wv 1.2s ease-in-out infinite;}
.wave span:nth-child(2){animation-delay:.1s;}.wave span:nth-child(3){animation-delay:.2s;}.wave span:nth-child(4){animation-delay:.3s;}.wave span:nth-child(5){animation-delay:.4s;}
@keyframes wv{0%,100%{height:10px;}50%{height:44px;}}

/* ===== ÍCONOS ANIMADOS ===== */
.ic circle,.ic path,.ic line,.ic polyline{transform-box:fill-box;transform-origin:center;}
/* Chatbot: puntitos escribiendo */
@keyframes typedot{0%,65%,100%{opacity:.2;}30%{opacity:1;}}
.ic-chat .d1{animation:typedot 1.5s infinite;}
.ic-chat .d2{animation:typedot 1.5s .22s infinite;}
.ic-chat .d3{animation:typedot 1.5s .44s infinite;}
/* Micrófono: ondas que salen a los costados */
@keyframes micwave{0%{opacity:0;transform:scale(.72);}40%{opacity:1;}100%{opacity:0;transform:scale(1.28);}}
.ic-mic .w1,.ic-mic .w2{animation:micwave 2s ease-out infinite;}
.ic-mic .w2{animation-delay:1s;}
/* Automatización: nodos que pulsan en secuencia (dato viajando) */
@keyframes nodepulse{0%,100%{opacity:.35;transform:scale(.82);}50%{opacity:1;transform:scale(1.18);}}
.ic-net .n1{animation:nodepulse 1.8s infinite;}
.ic-net .n2{animation:nodepulse 1.8s .3s infinite;}
.ic-net .n3{animation:nodepulse 1.8s .6s infinite;}
/* Plataformas: brackets que respiran + barra tipo cursor */
@keyframes brL{0%,100%{transform:translateX(0);}50%{transform:translateX(-1.8px);}}
@keyframes brR{0%,100%{transform:translateX(0);}50%{transform:translateX(1.8px);}}
@keyframes blinkc{0%,100%{opacity:1;}50%{opacity:.25;}}
.ic-code .bl{animation:brL 2.2s ease-in-out infinite;}
.ic-code .br{animation:brR 2.2s ease-in-out infinite;}
.ic-code .sl{animation:blinkc 1.3s infinite;}
/* Asesoramiento: la lámpara se enciende */
@keyframes bulbGlow{0%,100%{opacity:.45;}50%{opacity:1;}}
@keyframes rayPop{0%,100%{opacity:0;transform:scale(.7);}50%{opacity:.9;transform:scale(1.05);}}
.ic-bulb .glass{animation:bulbGlow 2.2s ease-in-out infinite;}
.ic-bulb .ray{animation:rayPop 2.2s ease-in-out infinite;}
.ic-bulb .ray2{animation:rayPop 2.2s .25s ease-in-out infinite;}
/* Capacitación: el birrete flota */
@keyframes capFloat{0%,100%{transform:translateY(0);}50%{transform:translateY(-2px);}}
.ic-cap .cap{animation:capFloat 2.6s ease-in-out infinite;}

/* En celular los íconos quedan quietos.
   ------------------------------------
   Todos estos son transform y opacity, que en una caja normal resuelve la
   placa de video sin repintar. Pero acá se aplican a partes de un SVG, y ahí
   no hay atajo: cada cuadro obliga a redibujar el dibujo entero, en el hilo
   principal, que es el mismo que mueve el scroll. Son diecinueve animaciones
   corriendo siempre, incluso con la tarjeta fuera de pantalla, y encima cada
   ícono lleva un drop-shadow que hay que rehacer en cada repintado.

   Medido con Chrome a 390x844 y el procesador frenado 20x, scrolleando la
   zona de las tarjetas, cuatro corridas:

                              cuadros/seg   mediana por cuadro   cuadros lentos
     como estaba              10 a 15       67-84 ms             210 de 210
     con los íconos quietos   25 a 32       33 ms                ~160 de 210
     además sin el puntito    32 a 45       17 ms                ~75 de 210

   El tiempo por cuadro se parte al medio con solo frenar los íconos. Se probó
   también sacarle el drop-shadow al ícono y no mueve la aguja: quietos, no
   hay repintado que rehacer.

   Los íconos NO desaparecen, quedan dibujados como cualquier ícono. Y en
   computadora se animan igual que siempre. */
@media (hover:none),(max-width:860px){
  .svcs .svc .ic,
  .svcs .svc .ic *,
  .svcs .svc .pulse{animation:none;}
}

/* ===== CASOS ===== */
.two{display:grid;grid-template-columns:1fr 1fr;gap:22px;}
.card{border-radius:12px;padding:26px;background:rgba(8,16,12,.72);}
.card h3{font-size:1.3rem;margin-bottom:10px;}
.card p{color:var(--dim);line-height:1.7;}
.card p + p{margin-top:12px;}
/* El resto del texto vive dentro de .more (en celular se pliega), así que el
   primer párrafo de adentro ya no tiene un <p> hermano antes que le dé aire. */
.card .more > p:first-child{margin-top:12px;}
.card strong{color:var(--green);}
.chip{display:inline-block;font-family:var(--mono);font-size:.7rem;color:var(--green);border:1px solid rgba(61,255,160,.35);border-radius:999px;padding:3px 12px;margin-bottom:12px;}

/* Al tocar, Android pinta de celeste el elemento tocable ENTERO. Como la
   tarjeta lleva su propio click, "el elemento tocable" son sus 620 px y se
   prende toda de rgba(51,181,229,.4). Se apaga acá y se devuelve el aviso de
   que algo pasó donde corresponde: en el botón, con su propio estado al
   apretarlo. En el resto del sitio el resaltado sigue como viene. */
.svc,.two .card,.vermas{-webkit-tap-highlight-color:transparent;}
.vermas:active{background:rgba(61,255,160,.18);border-color:rgba(61,255,160,.6);}

/* ===== TARJETA DE PROYECTOS (lleva al portfolio) ===== */
.proyectos-band{max-width:1220px;margin:0 auto;padding:0 26px 56px;}
.proyectos-card{display:grid;grid-template-columns:1.05fr .95fr;gap:34px;align-items:center;
  border-radius:16px;padding:38px 34px;overflow:hidden;
  background:linear-gradient(120deg,rgba(61,255,160,.09),rgba(255,47,214,.07));
  transition:transform .35s cubic-bezier(.2,.8,.2,1),box-shadow .35s,opacity .6s ease,translate .6s ease;}
.proyectos-card:hover{transform:translateY(-6px);box-shadow:0 20px 56px rgba(0,0,0,.6),0 0 46px rgba(61,255,160,.24);}
.proyectos-card .eyebrow{font-family:var(--mono);color:var(--cyan);letter-spacing:2px;font-size:.8rem;font-weight:600;}
.proyectos-card h2{font-size:clamp(1.5rem,3.4vw,2.3rem);margin:10px 0 12px;text-shadow:0 0 18px rgba(61,255,160,.3);}
.proyectos-card p{color:var(--dim);line-height:1.65;max-width:460px;}
.pb-cta{display:inline-flex;align-items:center;gap:10px;margin-top:22px;padding:12px 24px;border-radius:8px;
  font-family:'Rajdhani',sans-serif;font-weight:700;font-size:1.05rem;
  border:1.5px solid var(--green);color:var(--green);background:rgba(61,255,160,.06);
  transition:background .2s,box-shadow .2s;}
.proyectos-card:hover .pb-cta{background:rgba(61,255,160,.16);box-shadow:0 0 24px rgba(61,255,160,.45);}
.pb-cta .flecha{transition:transform .3s;}
.proyectos-card:hover .pb-cta .flecha{transform:translateX(5px);}
/* ===== MOSAICO DE ESTADOS =================================
   Cada casilla lleva su estado arriba a la derecha y toma el color de ese
   estado, no del rubro. Antes cada una tenía un degradado propio —azul,
   violeta, naranja, verde azulado— que no era ninguno de los colores de la
   marca y hacía que el bloque se leyera como cuatro cosas sueltas.

   El acento sale de --acento, así que agregar un estado nuevo es una línea:
   se define la terna RGB y el resto (borde, fondo, ícono, chip) se acomoda. */
.pb-tiles{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
.pb-tile{
  --acento:61,255,160;
  position:relative;border-radius:12px;padding:16px 15px 15px;min-height:104px;
  display:flex;flex-direction:column;justify-content:space-between;gap:10px;
  background:linear-gradient(160deg,rgba(var(--acento),.13),rgba(var(--acento),.02));
  border:1px solid rgba(var(--acento),.22);
  overflow:hidden;transition:border-color .3s,background .3s;
  color:rgb(var(--acento));
}
.pb-tile.e-vivo  {--acento:53,229,255;}   /* sistema real funcionando */
.pb-tile.e-probar{--acento:61,255,160;}   /* se puede usar ahora mismo */
.pb-tile.e-demo  {--acento:126,200,255;}  /* demo navegable */
.pb-tile.e-dev   {--acento:255,47,214;}   /* todavía en desarrollo */

.pb-tile svg{width:26px;height:26px;stroke:currentColor;filter:drop-shadow(0 0 7px rgba(var(--acento),.45));}
.pb-tile .que{font-family:var(--mono);font-size:.78rem;font-weight:600;letter-spacing:1px;color:#fff;text-transform:uppercase;line-height:1.3;}

/* el chip de estado: arriba a la derecha, sin robarle lugar al ícono */
.pb-tile .estado{
  position:absolute;top:9px;right:9px;
  display:inline-flex;align-items:center;gap:5px;
  font-family:var(--mono);font-size:.57rem;font-weight:700;letter-spacing:1px;
  text-transform:uppercase;color:rgb(var(--acento));
  background:rgba(var(--acento),.12);border:1px solid rgba(var(--acento),.34);
  border-radius:100px;padding:2px 7px;
}
.pb-tile .estado i{width:5px;height:5px;border-radius:50%;background:currentColor;
  box-shadow:0 0 6px currentColor;animation:latirTile 1.8s ease-in-out infinite;}
@keyframes latirTile{0%,100%{opacity:1;transform:scale(1);}50%{opacity:.35;transform:scale(.6);}}

/* Al apuntar la tarjeta las casillas se encienden, pero NO se mueven.
   Antes las impares subían 3px y las pares bajaban 3px, buscando un efecto
   escalonado; en una grilla de dos columnas eso es la columna izquierda
   subiendo y la derecha bajando, y se lee como que se desalineó. La tarjeta
   entera ya se levanta 6px en :hover, con eso alcanza. */
.proyectos-card:hover .pb-tile{
  border-color:rgba(var(--acento),.5);
  background:linear-gradient(160deg,rgba(var(--acento),.2),rgba(var(--acento),.05));
}
@media(max-width:860px){
  .proyectos-card{grid-template-columns:1fr;gap:26px;padding:30px 24px;}
  .proyectos-card p{max-width:none;}
}
/* En pantallas muy angostas, o con el texto agrandado desde el panel de
   accesibilidad, dos mosaicos por fila no entran sin cortar las palabras. */
@media(max-width:420px){
  .pb-tiles{grid-template-columns:1fr;}
  .pb-tile{min-height:0;flex-direction:row;align-items:center;gap:12px;padding:14px 16px;}
  /* En fila, el chip flotando arriba a la derecha se le monta al texto: pasa a
     ser un elemento más. Va primero en el HTML (para que un lector de pantalla
     anuncie el estado antes que el nombre), así que acá se lo manda al final
     con order, no alcanza con margin-left. */
  .pb-tile .estado{position:static;order:3;margin-left:auto;flex-shrink:0;}
  .pb-tile .que{flex:1;}
}

/* ===== NOSOTROS ===== */
/* En computadora: el texto arriba a la izquierda, la tarjeta vieja debajo, y
   la foto ocupando la columna derecha. row-gap en 0 porque el último párrafo
   ya trae sus 16 px de margen: con un hueco de grilla encima quedaba el doble
   de aire del que había antes. */
.about{display:grid;grid-template-columns:1.25fr .75fr;column-gap:34px;row-gap:0;align-items:start;
  grid-template-areas:"texto foto" "legacy foto";}
.about .texto{grid-area:texto;}
.about .photo{grid-area:foto;}
.about .legacy{grid-area:legacy;}
.about p{color:var(--dim);line-height:1.75;margin-bottom:16px;}
.about strong{color:var(--green);}
.photo{border-radius:14px;overflow:hidden;max-width:320px;justify-self:center;}
.photo img{width:100%;display:block;}
.legacy{max-width:300px;border-radius:10px;overflow:hidden;}
.legacy img{width:100%;}
.legacy figcaption{font-family:var(--mono);font-size:.72rem;color:var(--dim);padding:8px 4px 0;font-style:italic;}

/* ===== NOTICIAS ===== */
.news{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;}
.nw{border-radius:12px;padding:24px;background:rgba(8,16,12,.72);}
.nw .d{font-family:var(--mono);font-size:.72rem;color:var(--fucsia);}
.nw h3{font-size:1.12rem;margin:8px 0;}
.nw p{color:var(--dim);font-size:.9rem;}
.nw .tagn{display:inline-block;font-family:var(--mono);font-size:.66rem;color:var(--green);border:1px solid rgba(61,255,160,.3);border-radius:999px;padding:2px 10px;margin-bottom:10px;}
.nw .source{display:inline-block;margin-top:10px;font-family:var(--mono);font-size:.72rem;color:var(--cyan);text-decoration:none;border-bottom:1px solid rgba(53,229,255,.4);}
.nw .source:hover{color:#fff;}
.creditos{text-align:center;color:var(--dim);font-family:var(--mono);font-size:.66rem;margin-top:24px;}

/* video: se muestra una portada y el reproductor recién se carga al hacer clic.
   Así la página no arrastra el peso de YouTube en cada visita. */
.videobox{position:relative;width:100%;aspect-ratio:16/9;border-radius:10px;overflow:hidden;margin-bottom:14px;background:#03060a;border:1px solid rgba(61,255,160,.25);}
.videobox iframe{position:absolute;inset:0;width:100%;height:100%;border:0;}
.videoph{position:absolute;inset:0;display:grid;place-items:center;cursor:pointer;width:100%;height:100%;
  border:0;font:inherit;color:inherit;padding:0;
  background:radial-gradient(circle at 50% 45%,rgba(61,255,160,.12),transparent 60%),#04080b;}
.videoph .play{width:64px;height:64px;border-radius:50%;border:2px solid var(--green);display:grid;place-items:center;box-shadow:0 0 26px rgba(61,255,160,.5);transition:transform .2s,box-shadow .2s;}
.videoph:hover .play,.videoph:focus-visible .play{transform:scale(1.1);box-shadow:0 0 40px rgba(61,255,160,.8);}
.videoph .play::after{content:"";margin-left:4px;border-style:solid;border-width:11px 0 11px 18px;border-color:transparent transparent transparent var(--green);}
.videoph .vlabel{position:absolute;bottom:12px;left:14px;font-family:var(--mono);font-size:.7rem;font-weight:600;color:var(--green);text-shadow:0 0 8px var(--green);}

/* carrusel de imágenes en las noticias */
.carousel{position:relative;width:100%;aspect-ratio:16/9;border-radius:10px;overflow:hidden;margin-bottom:14px;border:1px solid rgba(61,255,160,.25);background:#03060a;}
.carousel .slide{position:absolute;inset:0;opacity:0;transition:opacity .8s ease;}
.carousel .slide.on{opacity:1;}
.carousel .slide img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;}
.carousel .slide::before{content:"";position:absolute;inset:0;z-index:1;background:linear-gradient(180deg,rgba(4,7,10,.1),rgba(4,7,10,.8));}
.carousel .slide .cap{position:absolute;z-index:2;left:14px;right:14px;bottom:26px;font-family:var(--mono);font-size:.82rem;color:#fff;letter-spacing:.5px;text-align:left;text-shadow:0 1px 8px rgba(0,0,0,.95);}
.carousel .dots{position:absolute;bottom:10px;left:0;right:0;display:flex;justify-content:center;gap:7px;z-index:3;}
.carousel .dots button{width:7px;height:7px;padding:0;border:0;border-radius:50%;background:rgba(255,255,255,.3);transition:background .3s,transform .3s;cursor:pointer;}
.carousel .dots button.on{background:var(--green);box-shadow:0 0 8px var(--green);transform:scale(1.2);}

/* ===== COTIZACIÓN / CONTACTO ===== */
.quote-band{max-width:1220px;margin:0 auto;padding:10px 26px 40px;}
.quote-box{position:relative;border-radius:16px;padding:44px 34px;text-align:center;overflow:hidden;
  background:linear-gradient(120deg,rgba(61,255,160,.10),rgba(255,47,214,.08));border:1px solid rgba(61,255,160,.3);}
.quote-box .qk{font-family:var(--mono);color:var(--cyan);letter-spacing:2px;font-size:.78rem;font-weight:600;}
.quote-box h2{font-size:clamp(1.6rem,3.6vw,2.5rem);margin:10px 0 10px;text-shadow:0 0 18px rgba(61,255,160,.3);}
.quote-box p{color:var(--text);max-width:560px;margin:0 auto 24px;}
.quote-box .subnote{color:var(--dim);font-size:.86rem;margin-top:16px;font-family:'Rajdhani',sans-serif;font-weight:600;letter-spacing:.5px;}
.contact{text-align:center;}
.contact .intro{margin-inline:auto;}
.wa{display:inline-flex;align-items:center;gap:10px;padding:16px 32px;border-radius:10px;background:#25d366;color:#04140b;font-family:'Rajdhani',sans-serif;font-weight:700;font-size:1.12rem;box-shadow:0 0 26px rgba(37,211,102,.45);transition:transform .18s,box-shadow .18s;}
.wa:hover{transform:translateY(-2px);box-shadow:0 0 40px rgba(37,211,102,.7);}
footer{border-top:1px solid rgba(61,255,160,.15);padding:34px 26px;text-align:center;color:var(--dim);font-family:var(--mono);font-size:.82rem;}
footer strong{color:var(--text);}

/* ===== BOTONES FLOTANTES ===== */
.wa-float{position:fixed;bottom:20px;right:20px;width:56px;height:56px;border-radius:50%;background:#25d366;display:grid;place-items:center;box-shadow:0 0 20px rgba(37,211,102,.5);z-index:120;}
.wa-float svg{width:28px;height:28px;}
/* Los estilos del botón de música se sacaron el 30/07/2026 junto con el botón
   y su crédito al pie. Si se repone, hay que reponer también la atribución:
   el tema era CC BY 3.0. */

/* ===== RESPONSIVE ===== */
@media(max-width:980px){.svcs{grid-template-columns:repeat(2,1fr);}}
@media(max-width:860px){
  .svcs,.two,.about,.news{grid-template-columns:1fr;}
  /* En celular la foto va ANTES que la tarjeta de hace diez años: primero
     quiénes somos hoy, después de dónde venimos. */
  .about{grid-template-areas:"texto" "foto" "legacy";row-gap:24px;}
  /* Acá estaba .nav .links{display:none}. Ahora los enlaces no se esconden:
     se convierten en el panel que entra desde la derecha. Ver «MENÚ DE
     CELULAR» más arriba. */
}

/* ===== APARICIÓN AL HACER SCROLL =====
   Se usa 'translate' y no 'transform' a propósito. Con transform, la regla
   .stagger.in{transform:none} tiene la misma especificidad que .svc:hover y
   .proyectos-card:hover pero va después en el archivo, así que les ganaba y
   las tarjetas ya reveladas no se levantaban al pasar el cursor. Son
   propiedades distintas, así que ahora conviven: una para entrar, otra para
   el hover. */
.reveal{opacity:0;translate:0 28px;transition:opacity .7s ease,translate .7s ease;}
.reveal.in{opacity:1;translate:0 0;}
.svc,.card,.nw{transition:transform .3s cubic-bezier(.2,.8,.2,1),box-shadow .3s,opacity .6s ease,translate .6s ease;}
.stagger{opacity:0;translate:0 22px;}
.stagger.in{opacity:1;translate:0 0;}
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  *{animation:none!important;transition:none!important;}
  .reveal,.stagger{opacity:1!important;translate:none!important;}
}

/* ===== EN CELULAR: TARJETAS RESUMIDAS Y APILADAS =========================
   Dos problemas, los dos de alto:

   1. Los siete recuadros de servicios se abrían enteros. La regla de más
      arriba para pantallas sin cursor (@media(hover:none)) ponía .more en
      max-height:none, porque sin cursor no hay forma de "pasar por encima".
      Resultado: una tirada de texto larguísima para pasar de largo.
   2. Los dos casos reales traían dos párrafos largos cada uno.

   Ahora, hasta 860 px —el mismo corte donde las grillas ya pasaban a una
   columna— cada tarjeta muestra el resumen y un botón para desplegar el
   resto, y todas se van apilando abajo de la barra, como en Pinamar Datos.

   El apilado NO se puede hacer sobre la grilla. Un elemento de grilla queda
   encerrado en su propia celda, y position:sticky solo se mueve dentro de su
   bloque contenedor: en una celda a medida no le queda recorrido y se queda
   quieto. Por eso .svcs y .two pasan a display:block acá, así el contenedor
   pasa a ser la lista entera.

   Tampoco hay clase "pegada" ni oyente de scroll. En Pinamar Datos hace
   falta porque allá el fondo es translúcido y recién al pegarse arriba se
   vuelve opaco. Acá el fondo es opaco siempre, el filo de luz ya lo dibuja
   .lightborder, y así el efecto no cuesta ni un cuadro de trabajo. */
.vermas{display:none;}

@media(max-width:860px){

  /* --- el mazo --- */
  .svcs,.two{display:block;--tope:calc(var(--nav-alto,66px) + 10px);--paso:12px;}
  .svcs>.svc,.two>.card{
    position:sticky;
    margin:0 0 14px;
    /* contain:layout le avisa al navegador que lo de adentro de cada tarjeta
       es asunto suyo y no afecta a las demás. Sin eso, al desplegar una,
       cada cuadro de la animación rehacía la maquetación de las siete y
       reubicaba las pegadas. Medido con el procesador frenado 20x, abriendo
       una tarjeta: de 83,4 ms por cuadro a 16,7 ms — de tres cuadros
       perdidos a ninguno. No se puede agregar 'size' a la lista: el alto de
       la tarjeta SÍ tiene que cambiar cuando se despliega. */
    contain:layout style;
    /* Casi opaco a propósito: tiene que tapar el texto de la tarjeta de
       abajo. Queda una pizca de los resplandores del fondo. */
    background:linear-gradient(180deg,rgba(10,20,15,.985),rgba(6,12,9,.955));
    box-shadow:0 -6px 20px rgba(0,0,0,.55);
  }
  .svcs>.svc:last-child,.two>.card:last-child{margin-bottom:0;}

  /* Cada una se pega 12 px más abajo que la anterior: al pasarlas de largo
     queda el filo encendido a la vista y se ve crecer la pila. */
  .svc:nth-child(1),.two .card:nth-child(1){top:var(--tope);z-index:1;}
  .svc:nth-child(2),.two .card:nth-child(2){top:calc(var(--tope) + var(--paso));z-index:2;}
  .svc:nth-child(3){top:calc(var(--tope) + var(--paso) * 2);z-index:3;}
  .svc:nth-child(4){top:calc(var(--tope) + var(--paso) * 3);z-index:4;}
  .svc:nth-child(5){top:calc(var(--tope) + var(--paso) * 4);z-index:5;}
  .svc:nth-child(6){top:calc(var(--tope) + var(--paso) * 5);z-index:6;}
  .svc:nth-child(7){top:calc(var(--tope) + var(--paso) * 6);z-index:7;}

  /* Desplegada deja de pegarse arriba: si siguiera pegada, la tarjeta
     siguiente le taparía el final del texto justo cuando el visitante baja
     para leerlo. app.js compensa el salto de scroll.

     Va relative y NO static: la tarjeta tiene .lightborder, cuyo filo de luz
     es un ::before con position:absolute. Si la tarjeta quedara sin posicionar,
     ese filo (y el puntito que late) se irían a buscar al antepasado
     posicionado más cercano y aparecerían en cualquier lado.

     Y va z-index ARRIBA de todas las demás, no abajo. Acá me equivoqué en la
     primera versión: le puse z-index:0 pensando que la abierta tenía que
     meterse por debajo de la pila, como pasa en el apilado normal. Pero una
     tarjeta pegada arriba no es un filo de 12 px: se dibuja entera, con sus
     240 px de alto y su fondo opaco. Así que mientras leías la desplegada y
     seguías bajando, la anterior le tapaba el texto de arriba y ese texto ya
     no se recuperaba nunca, porque la abierta no se pega y la otra no se
     mueve. Estando arriba, la desplegada pasa por encima de la pila y se lee
     completa; la pila reaparece sola cuando la abierta termina de pasar.

     Y el top:auto NO es decorativo, es el arreglo. Las reglas de arriba le
     ponen un top a cada tarjeta para escalonar el apilado. En sticky ese top
     significa "pegate a tantos píxeles del borde". En relative significa algo
     muy distinto: "corretela tantos píxeles hacia abajo SIN mover su lugar en
     el flujo". La tarjeta siguiente sigue al lugar en el flujo y no a lo que
     se ve, así que arrancaba 61 px antes de donde terminaba la abierta y le
     tapaba el final del texto. Medido en Chrome a 390x844: la de abajo caía
     27 px por encima del recuadro EJEMPLO. */
  /* 20 y no 8: deja lugar por si algún día se agregan módulos. Sigue por
     debajo de la barra de arriba, que va en 60 y tiene que taparla. */
  .svcs>.svc.abierta,.two>.card.abierta{position:relative;top:auto;z-index:20;}

  /* --- encabezado en una línea: el ícono al lado del título ---
     Se hace con un float y NO con una grilla, aunque la grilla sea lo moderno.
     La primera versión ponía cada parte en una celda con grid-template-areas,
     y en el celular el botón de abajo aparecía recortado. Con .more de celda,
     la fila tiene que ir siguiendo el alto que se anima; cuando no acompaña,
     el texto se monta sobre la fila del botón y el overflow:hidden de la
     tarjeta lo corta. En flujo normal el bloque de arriba empuja al de abajo
     y no hay nada que pueda fallar.

     Y se saca el overflow:hidden mientras se está en celular. No hace falta
     —en flujo normal no sobresale nada— y era justamente lo que convertía
     cualquier desajuste de alto en "esto está cortado" en vez de dejarlo a
     la vista. El ícono flotante lo contiene el clear de .b, no el overflow. */
  .svc{padding:20px 18px;overflow:visible;}
  .svc .num{margin-bottom:10px;}
  .svc .ic{float:left;width:34px;height:34px;margin:0 12px 0 0;}
  .svc .ic.wave{height:34px;gap:2px;}
  /* Las barras traen el alto puesto en el HTML (hasta 44 px): con max-height
     se las baja sin tener que pisar un estilo en línea. */
  .svc .ic.wave span{max-height:30px;width:4px;}
  /* El título se pone al lado del ícono, no debajo: al ser contenedor flex no
     se le mete por abajo al elemento flotante. El alto mínimo lo empareja con
     el ícono cuando el título entra en un solo renglón. */
  .svc h3{display:flex;align-items:center;min-height:34px;margin:0;font-size:1.14rem;}
  /* clear: acá se termina el ícono flotante y vuelve el ancho completo. */
  .svc .b{clear:both;margin:12px 0 0;font-size:.94rem;}
  .svc .hovertip{display:none;}

  .two>.card{padding:22px 18px;}
  .two .card h3{font-size:1.16rem;}

  /* --- el despliegue ---
     Se colapsa SOLO si el script está vivo (html.js-plegable). Si no corre no
     hay botón para abrirlo, así que en ese caso se muestra todo entero, que
     es la falla correcta. El alto lo pone app.js en línea, medido, porque de
     0 a "auto" no se puede animar.

     El aire entre el botón y el texto va como padding y NO como margin: el
     padding queda DENTRO de la caja que se recorta, así que con la tarjeta
     plegada no ocupa nada y al abrirse crece con la animación. Un margin
     estaría afuera del recorte y dejaría 14 px de vacío estando cerrada. */
  .js-plegable .svc .more,
  .js-plegable .two .card .more{
    max-height:0;overflow:hidden;margin-top:0;padding-top:14px;
    /* 260 ms y no 420: animar un alto cuesta una maquetación por cuadro, así
       que cuanto menos dure, menos veces se paga. Con los 420 originales se
       perdían cuadros aun con contain puesto. */
    transition:max-height .26s cubic-bezier(.4,0,.2,1);
  }
  /* Ese padding ya da la separación: el párrafo de adentro no necesita más. */
  .js-plegable .two .card .more > p:first-child{margin-top:0;}

  .vermas{
    display:flex;align-items:center;justify-content:center;gap:8px;
    width:100%;margin-top:14px;padding:11px 14px;
    font-family:var(--mono);font-size:.76rem;font-weight:600;letter-spacing:1px;
    color:var(--green);background:rgba(61,255,160,.07);
    border:1px solid rgba(61,255,160,.3);border-radius:8px;cursor:pointer;
  }
  .vermas .flecha{font-size:.9rem;line-height:1;transition:transform .3s ease;}
  .abierta>.vermas .flecha{transform:rotate(180deg);}

  .pista-cursor{display:none;}
  .pista-toque{display:inline;}
}

/* ===== ACCESIBILIDAD ===== */
.skip-link{position:absolute;left:-9999px;top:0;z-index:999;background:var(--green);color:#04140b;padding:10px 18px;border-radius:0 0 8px 0;font-weight:700;font-family:'Rajdhani',sans-serif;}
.skip-link:focus{left:0;}
a:focus-visible,button:focus-visible,[tabindex]:focus-visible{outline:3px solid var(--cyan);outline-offset:3px;border-radius:4px;}
html.txt1{font-size:118%;} html.txt2{font-size:130%;} html.txt3{font-size:144%;}
body.ul-links .nav .links a, body.ul-links .source, body.ul-links footer a, body.ul-links .nw a, body.ul-links .card a, body.ul-links .about a{text-decoration:underline;}
body.no-motion *{animation:none!important;transition:none!important;}
body.no-motion .hero-oval canvas,body.no-motion .chispas{display:none!important;}
body.hc{background:#000!important;}
body.hc .chispas,body.hc .glow-bg,body.hc .scan{display:none!important;}
body.hc, body.hc p, body.hc small, body.hc .intro, body.hc .card p, body.hc .nw p, body.hc .svc .b, body.hc .svc .ex, body.hc .svc .feats li, body.hc .quote-box p, body.hc .about p, body.hc .proyectos-card p{color:#fff!important;}
body.hc a, body.hc strong, body.hc .eyebrow, body.hc .qk, body.hc .nav .links a{color:#ffe64d!important;text-shadow:none!important;}
/* Los botones verdes son enlaces, así que la regla de arriba les pinta el
   texto de amarillo y quedaba amarillo sobre verde: ilegible. En alto
   contraste pasan a fondo negro con borde amarillo. */
body.hc .wa, body.hc .skip-link, body.hc .pb-cta{background:#000!important;color:#ffe64d!important;border:2px solid #ffe64d!important;box-shadow:none!important;}
body.hc .wa-float{background:#000!important;border:2px solid #ffe64d!important;}
body.hc .wa-float svg{fill:#ffe64d!important;}
body.hc .card, body.hc .svc, body.hc .nw, body.hc .quote-box, body.hc .chip, body.hc .proyectos-card{background:#0b0b0b!important;border-color:#fff!important;}
.a11y-fab{position:fixed;bottom:90px;right:20px;width:56px;height:56px;border-radius:50%;background:radial-gradient(circle at 32% 28%,#3d8bff,#0a5be0 70%);border:2px solid rgba(255,255,255,.9);display:grid;place-items:center;cursor:pointer;z-index:130;padding:0;box-shadow:0 6px 20px rgba(0,0,0,.5),0 0 0 4px rgba(10,91,224,.18);transition:transform .2s,box-shadow .2s;}
.a11y-fab svg{width:32px;height:32px;}
.a11y-fab:hover{transform:scale(1.08);box-shadow:0 8px 26px rgba(10,91,224,.6),0 0 0 6px rgba(10,91,224,.25);}
.a11y-panel{position:fixed;bottom:158px;right:20px;width:270px;background:linear-gradient(180deg,#0c1826,#08111c);border:1px solid var(--borde);border-radius:16px;padding:18px;z-index:131;display:none;box-shadow:0 16px 50px rgba(0,0,0,.7);}
.a11y-panel.open{display:block;animation:a11yin .28s ease;}
@keyframes a11yin{from{opacity:0;transform:translateY(12px) scale(.96);}to{opacity:1;transform:none;}}
.a11y-panel h4{font-family:'Rajdhani',sans-serif;color:var(--green);margin-bottom:4px;font-size:1.15rem;display:flex;align-items:center;gap:8px;}
.a11y-panel .sub{color:var(--dim);font-size:.74rem;margin-bottom:14px;font-family:'Rajdhani',sans-serif;letter-spacing:.5px;}
.a11y-panel .row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 0;font-size:.95rem;color:var(--text);border-top:1px solid rgba(255,255,255,.06);}
.a11y-panel button{background:rgba(61,255,160,.08);border:1px solid rgba(61,255,160,.3);color:var(--text);border-radius:8px;padding:7px 13px;cursor:pointer;font-family:'Rajdhani',sans-serif;font-weight:600;font-size:.88rem;transition:background .15s,transform .15s;}
.a11y-panel button:hover{background:rgba(61,255,160,.2);transform:translateY(-1px);}
.a11y-panel button.act{background:var(--green);color:#04140b;box-shadow:0 0 14px rgba(61,255,160,.5);}
.a11y-panel .txtbtns{display:flex;gap:6px;}
.a11y-panel .reset{width:100%;margin-top:12px;text-align:center;border-style:dashed;}
