/* ============================================================================
   INTHARIS — hoja de estilos compartida por las 6 paginas
   ----------------------------------------------------------------------------
   Se carga desde assets/, asi que las rutas relativas de dentro (../fonts/…)
   resuelven igual desde la raiz y desde las subpaginas.
   Orden: tapa de ruta directa · utilidades · escritorio (lienzo 1920) · movil.
   ========================================================================== */

  /* el lienzo de la home llega a z-index 80; los overlays arrancan en 200 */
  html.ruta-directa::before{ content:""; position:fixed; inset:0; z-index:150; background:var(--tapa,#f1f1f1); }
  @media (max-width:820px){ html.ruta-directa::before{ display:none; } }
.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}
  /* ====== TIPOGRAFIA: FIGTREE ======
     Sustituye a Aeonik, que no se va a usar. DOS caras y no tres porque es una
     VARIABLE: un solo archivo por subconjunto cubre el 300-700 entero, y la
     pagina usa cuatro pesos (300 en 43 reglas, 400 en 60, 500 en 6 y 700 en 9).

     SE SIRVE DESDE EL REPOSITORIO, no desde una pila del sistema, y esa es toda
     la razon de existir de este bloque: mientras la familia dependia de lo que
     hubiera instalado en cada equipo habia TRES renderizados -- Aeonik en la
     maquina de desarrollo, que la tiene instalada, Arial en Windows y Helvetica
     Neue en macOS -- y lo que se veia al disenar no era lo que salia en
     produccion.

     Los dos subconjuntos son los de Google Fonts con sus unicode-range: el
     castellano cabe entero en `latin` (U+0000-00FF cubre tildes y ene), y
     `latin-ext` va por completitud y solo se descarga si aparece un glifo suyo.
     Por eso el preload de las plantillas es unicamente el de `latin`.

     La ruta es relativa a ESTA hoja, que vive en assets/, asi que apunta a
     assets/fonts/. La de Aeonik decia '../fonts/', una carpeta en la raiz que
     nunca existio: de ahi los seis 404.

     NO llevan ?v=: solo styles.css y app.js van versionados y una fuente no
     cambia. OFL.txt va al lado porque la licencia obliga a distribuirla con los
     archivos.

     Y OJO CON EL NOMBRE: la familia se llama 'Figtree' y solo 'Figtree'. Aeonik
     ya no aparece en ninguna pila, que es lo unico que impide que un equipo con
     Aeonik instalada la siga pintando. */
  @font-face{
    font-family:'Figtree';
    src:url('fonts/figtree-latin.woff2') format('woff2');
    font-weight:300 700; font-style:normal; font-display:swap;
    unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face{
    font-family:'Figtree';
    src:url('fonts/figtree-latin-ext.woff2') format('woff2');
    font-weight:300 700; font-style:normal; font-display:swap;
    unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
  }
  :root{
    --black:#000;
    --white:#fff;
    /* El rojo de la casa. TODO el proyecto lo lee de aqui: la hoja con var(),
       app.js asignando 'var(--red-core)' en linea. Subio de var(--red-core) a #ab0000
       (+4,3 de L*) porque el anterior se apagaba sobre el gris del resalte. */
    --red-core:#ab0000;
    /* El aire de CERTIFICACIONES con lo que tenga encima, en unidades de
       lienzo y sin unidad, UNO para toda la web: lo lee fitCanvas() en la home
       (AIRE_CERTS) y es el padding-top de .nf-certs en los dos clones, que ya
       escalan su contenido de 1920 con --fs. Va del borde inferior de lo
       ultimo que se ve encima (su fondo, o la tinta de su ultimo texto) al
       titulo de la seccion: de lo VISIBLE a lo visible, fondos o tinta,
       nunca cajas. */
    --aire-certs:160;
    /* Donde empieza la TINTA del titulo «CERTIFICACIONES Y METODOLOGIAS» por
       debajo de su caja, en unidades de lienzo. CONSTANTE: depende solo de la
       fuente (Figtree 400), el cuerpo (21/1.2) y el texto, que la decide la
       tilde de la I. Medido rasterizando el texto a 10x: la linea base cae a
       19,851 de la caja y la tinta sube 18,2 sobre ella. Si cambia el titulo,
       su cuerpo o la tipografia, hay que remedirla. La restan fitCanvas() y el
       padding de .nf-certs. */
    --certs-tit-tinta:1.65;
    /* Lo mismo para el titular del cierre, «Descubre los puntos debiles»:
       su tinta empieza 21,45 por debajo de su caja (Figtree 400, 122/1.1; la
       decide la tilde de «debiles»). Medido igual, rasterizando a 10x: linea
       base a 108,848 y tinta 87,4 por encima. Con ella el top del titular deja
       --aire-certs de la tinta de los logos a la suya. */
    --cierre-tinta:21.45;
  }
  *{margin:0;padding:0;box-sizing:border-box}
  html,body{background:var(--white)}
  body{
    font-family:'Figtree',Arial,sans-serif;
    color:var(--black);
    overflow-x:hidden;
  }

  /* ====== LIENZO 1920px — fiel al frame de Figma, escalado al ancho de pantalla ====== */
  .viewport{ width:100%; overflow:hidden; position:relative; }
  .viewport{ width:100%; overflow:hidden; position:relative; z-index:65; }
  .viewport.fijado{ position:fixed; top:0; left:0; width:100%; z-index:65; }
  .canvas{
    position:relative;
    width:1920px;
    height:7370px;
    background:transparent;   /* el blanco lo pone el body: así el polvo (z-index menor) queda DETRÁS del contenido opaco y solo asoma por el blanco; los paneles del barrido lo tapan a nivel píxel */
    transform-origin:top left;
  }

  /* ====== HEADER ====== */
  .logo-simbolo{
    position:absolute; left:59px; top:40px;
    width:80px; height:45px;
  }
  .logo-simbolo svg{width:100%;height:100%;display:block}
  .tagline{
    position:absolute; left:461px; top:53px;
    font-size:20px; line-height:1.0055; width:480px;
  }
  nav.menu{
    position:absolute; left:1203px; top:57px; width:600px;
    display:flex; justify-content:space-between;
    font-size:20px;
  }
  nav.menu a{color:var(--black); text-decoration:none}

  /* ====== HERO ====== */
  .hero-claim{
    position:absolute; left:1270px; top:362px;
    width:510px;                /* sector ampliado; borde derecho en el mismo sitio */
    font-size:32px;
  }
  .hero-claim .rotador .palabra{ font-weight:700; }
  .hero-claim .linea{
    height:46px; overflow:hidden;
  }
  .hero-claim .linea-inner{
    display:flex; justify-content:space-between; align-items:center;
    height:100%;
  }
  /* Cada línea sube desde abajo hasta su sitio (la propia línea hace de máscara) */
  .hero-claim .linea-inner{
    transform:translateY(110%);
    transition:transform .8s cubic-bezier(.22,1,.36,1);
  }
  .hero-claim .linea-inner.visible{ transform:translateY(0); }
  .logo-grande{
    position:absolute; left:48px; top:690px; z-index:2;
    width:1040px; height:254px;   /* ampliado manteniendo la proporción */
    overflow:hidden;             /* las letras emergen desde el borde inferior */
  }
  .logo-grande svg{width:100%;height:100%;display:block}

  /* ====== FONDO DE LA SECCIÓN ABOUT ======
     Banda #f1f1f1 que empieza donde acaba la zona de las cortinas (y=1300),
     de modo que cuando las columnas terminan de cubrir, hero y ABOUT
     comparten el mismo color sin costura. */
  .fondo-about{
    position:absolute; left:0; top:1100px;
    width:1920px; height:4569px;   /* de reserva: el alto real lo fija fitCanvas, del símbolo hacia arriba */
    background:#f1f1f1;
  }

  /* ====== DEGRADADO ABOUT → LOS CUATRO SERVICIOS ======
     Banda elegante, siempre presente, que funde el gris de ABOUT con el
     blanco de abajo: el corte directo no existe en ningún momento. El top lo
     fija fitCanvas al FIN DEL SÍMBOLO de trazo, no al de la etiqueta SERVICES
     — antes compartían número y el gris se comía la sección de los cuatro
     servicios entera. */
  .degradado-gris{
    position:absolute; left:0; top:5669px;   /* arranca justo donde acaba el gris */
    width:1920px; height:260px;
    background:linear-gradient(to bottom, #f1f1f1 0%, rgba(241,241,241,.55) 45%, rgba(241,241,241,0) 100%);
    pointer-events:none;
  }

  /* ====== ABOUT ====== */
  .about-text{
    position:absolute; left:80px; top:1347px; width:1760px;  /* márgenes simétricos de 80px */
    font-size:58px; line-height:1.317;
    text-indent:120px;
    color:#cdcdcd;                 /* estado inicial: gris claro, legible sobre el fondo */
  }
  .about-text .ltr{
    transition:color .25s linear;  /* cada letra se pinta con suavidad */
  }
  .about-text .ltr.negra{ color:#000; }

  /* ====== SÍMBOLO DE TRAZO (sección ABOUT) ====== */
  .simbolo-trazo{
    position:absolute; left:50%; top:2490px;  /* el top real lo fija el JS, pegado al texto */
    transform:translateX(-50%);
    width:740px;                 /* centrado en el gris (el JS lo ajusta si no cabe) */
  }
  .simbolo-trazo svg{ width:100%; height:auto; display:block; overflow:visible; }

  /* ====== ENTRADA A SERVICIOS ======
     Los dos párrafos que presentan la sección de auditorías. Son lo que quedó
     del bloque de factor humano al mudarse a la pantalla de formación: se
     quedan aquí porque son la entrada a SERVICES, no argumento de phishing.
     Con el bloque se fue TODO el prefijo .pf-, que queda libre; estos tres
     estilos son ya lo único que sobrevive, con nombre propio.
     Los tops son de reserva: los fija fitCanvas() colgando del símbolo. */
  /* ====== LOS CUATRO SERVICIOS: UNA REJILLA DE CUATRO TARJETAS ======
     Ocupa el hueco que dejaron .ent-titular/.ent-texto. Los top los fija
     fitCanvas(); los de aqui son valor de reserva. Vive sobre el gris
     #f1f1f1 de .fondo-about.

     Los CUATRO llevan la misma caja: contorno de 1.5px y esquina viva sobre
     el mismo blanco del fondo -- las dos superficies son iguales y lo unico
     que define la caja es la linea. La jerarquia la da el TAMANO -- auditorias
     a todo el ancho y mas alta, las otras tres en fila --, no el que una tenga
     caja y otras no.
     Se probo al reves (auditorias sin contorno) y el efecto era el contrario
     del buscado: el servicio principal pesaba menos que los tres de apoyo.
     Ningun contorno aparece por opacidad: se DIBUJA con clip-path, como
     todas las lineas de la pagina. Calle de 30 en los dos ejes. */
  /* LA DIVISORIA QUE ABRE LA SECCION. Va alineada con la seccion (80/1760),
     NO con el titular: su 75 es compensacion optica del glifo del wordmark, y
     una linea no tiene aire lateral que compensar -- a 75 quedaria 5 unidades
     fuera de todas las demas lineas de la pagina.
     height + background y no border: el motor redondea border-width a pixel de
     dispositivo y 1.5 se queda en 0.8, mas fina que el resto.
     Se dibuja de izquierda a derecha con la curva de .sv2-hline, la divisoria
     equivalente del overlay. El top lo fija fitCanvas.

     Con CLIP-PATH y no con scaleX, aunque scaleX es lo que usan las divisorias
     animadas del overlay: aquellas viven dentro de overlays y esta es hija
     DIRECTA de .canvas, donde la animacion de carga aplica
     'transform:translateY(14px)' a todos los hijos menos al logotipo. Ese
     transform PISA el scaleX -- comprobado: la linea salia en
     matrix(1,0,0,1,0,14), entera y sin dibujar, en vez de en scaleX(0).

     Y EL RECORTE VA EN EL ::after, NUNCA en .cs-hr. Esto no es cosmetica: un
     clip-path sobre el PROPIO elemento observado anula su rectangulo de
     interseccion -- el navegador recorta antes de medir --, asi que el
     IntersectionObserver lo ve con ratio 0, nunca cruza su threshold de 0.2,
     nunca le pone .visible y nunca se quita el recorte. Circulo cerrado: la
     linea no se dibujaba porque estaba recortada y seguia recortada porque no
     se dibujaba. Con el recorte en el pseudo, el observador mide el padre
     entero (ratio 1) -- que es justo la estructura que ya tienen las tarjetas,
     con su contorno en .cs-campo::after.
     El contenedor NO declara transition: asi conserva las de la carga que le
     da la regla generica de .canvas > *. */
  .cs-hr{
    position:absolute; left:80px; top:4700px;   /* top de reserva */
    width:1760px; height:var(--linew, 1.5px);
  }
  .cs-hr::after{
    content:""; position:absolute; inset:0; background:#1d1d1c;
    clip-path:inset(0 100% 0 0);
    transition:clip-path .85s cubic-bezier(.65,0,.35,1);
  }
  .cs-hr.visible::after{ clip-path:inset(0 0 0 0); }

  /* El font-size NO es decorativo: dimTitulos() mide la palabra con esta
     tipografia viva y le da al wordmark el ancho resultante, asi que cambiarlo
     cambia el tamano del <img> -- y con el su ALTO, que es 0.739 por cada px
     de cuerpo. De ese alto cuelga el bloque principal en fitCanvas, que no
     puede medirlo (dimTitulos corre en un rAF posterior) y lo deriva del
     cuerpo. Si se toca este numero hay que tocar CS_TITULO_FONT en app.js, y
     nada lo avisa. */
  .cs-titulo{
    position:absolute; left:75px; top:4765px;
    margin:0; font-size:300px; line-height:1; font-weight:300;
    color:#1d1d1c; letter-spacing:-.02em;
  }

  /* AUDITORIAS: LA MISMA TARJETA que las tres de abajo, a todo el ancho y mas
     alta. La jerarquia la da el TAMANO, no la ausencia de caja: mientras fue
     el unico servicio sin contorno pesaba MENOS que los otros tres, que es lo
     contrario de lo que toca. El alto lo pide el contenido; lo mide fitCanvas. */
  .cs-principal{
    position:absolute; left:80px; top:5010px; width:1760px;
    box-sizing:border-box; padding:72px; background:#ffffff;
    /* 780 y no 940: el nombre solo usa 615 de ancho -- parte en dos lineas de
       537 y 615 --, asi que los 940 dejaban 325 muertas y estrangulaban la
       columna de la descripcion a 616. Con 780 la descripcion alcanza por fin
       su max-width de 760, que llevaba sin cumplirse desde que se escribio, y
       el texto baja de 7 lineas a 5. Por debajo de 780 no se gana nada: topa
       con ese max-width. El nombre aguanta en dos lineas hasta 620. */
    display:grid; grid-template-columns:780px 1fr; column-gap:60px;
    /* SUELO DE ALTURA, y no es decoracion: toda la jerarquia de la seccion es
       que esta caja sea mas alta que las tres de abajo. Ha valido 580 y 551, y
       las dos veces por la misma cuenta. Subio a 580 cuando un copy nuevo
       llevo la fila de 402 a 431 y la diferencia se quedo en 120; con 580
       volvia a 149. Al acortarse otra vez las tres descripciones la fila
       regreso a 402 y esos 580 pasaron a sobrecorregir -- la diferencia se iba
       a 178 --, asi que baja a 551. Medido: 149,6 contra los 401,5 de la fila,
       que es el mismo numero de siempre.
       551 es JUSTO LO QUE PIDE EL CONTENIDO, asi que el suelo ya no estira
       nada y cada hueco de la caja vale lo que esta escrito. Con 580 sobraban
       29 que el space-between repartia entre los dos huecos de abajo, 14,4 y
       14,5: el de la descripcion al remate se iba de 72 a 86,4 -- 72 es el
       margin-top del propio .cs-tipos -- y el del remate a "Mas informacion"
       de 28 a 42,5. La franja del fondo no la tocaba: son los 72 del padding.
       Sigue haciendo su trabajo original, que es de lo que viene el min-height
       y por eso no se quita: si con otra tipografia el nombre cupiera en una linea,
       la caja no se desplomaria. */
    min-height:551px; align-content:space-between;
  }
  /* mismo contorno y misma tecnica que .cs-campo::after, ver alli el porque
     del box-shadow. Va en absolute, asi que no entra en la rejilla.
     EN ::after, no en ::before: el ::before lo ocupa la capa de resalte, y
     ademas el ::after se pinta el ultimo, asi que la linea queda POR ENCIMA
     del resalte, que es lo que toca. */
  .cs-principal::after{
    content:""; position:absolute; inset:0;
    box-shadow:inset 0 0 0 var(--linew, 1.5px) #1d1d1c;
    clip-path:inset(0 0 100% 0);
    transition:clip-path .85s cubic-bezier(.65,0,.35,1);
    pointer-events:none;
  }
  .cs-principal.visible::after{ clip-path:inset(0 0 0 0); }
  .cs-nombre{
    grid-column:1; margin:0;
    font-size:96px; line-height:1.06; font-weight:500; letter-spacing:-.02em; color:#1d1d1c;
  }
  .cs-desc{
    grid-column:2; margin:18px 0 0; max-width:760px;
    font-size:26px; line-height:1.6; font-weight:400; color:#1d1d1c; text-wrap:pretty;
  }
  /* el remate: los tres tipos que desarrolla SERVICES justo debajo. Va
     DENTRO de la caja y con la misma pieza que la lista de las tres pequenas
     -- filete a todo el ancho interior y debajo el indice --, que es lo que
     lo saca de ser una linea huerfana entre dos bloques. */
  .cs-tipos{
    grid-column:1 / -1; position:relative; margin:72px 0 0; padding:32px 0 0;
    font-size:18px; line-height:1.0055; font-weight:400;
    letter-spacing:.05em; text-transform:uppercase; color:#1d1d1c;
  }
  .cs-tipos::before{
    content:""; position:absolute; left:0; right:0; top:0;
    height:var(--linew, 1.5px); background:#1d1d1c;
  }

  /* LOS TRES: TARJETAS de verdad. El contorno no es invento: es el mismo
     rectangulo de 1.5px y esquina viva que .fg-cta y .no-vcta, a escala. El
     fondo es el MISMO blanco que el de la seccion: cero contraste de
     superficie, a proposito. Se probaron los dos sentidos (tarjeta blanca
     sobre gris y gris sobre blanco) y los dos dan el mismo 1.129:1; aqui se
     renuncia a esa diferencia y la caja la sostiene solo el contorno. Cero
     sombra y cero radio: no existen en la pagina.
     SIN alto fijo: lo pide el contenido, y el flex las iguala a la mas alta.
     Los 400px que tuvieron dejaban una franja vacia bajo el ultimo punto --
     el mismo hueco muerto que ya costo descartar la version anterior. */
  .cs-campos{
    position:absolute; left:80px; top:5310px; width:1760px;
    display:flex; gap:30px;
  }
  .cs-campo{
    position:relative; flex:1; box-sizing:border-box;
    padding:40px; background:#ffffff;
  }
  /* el contorno va en un ::after y se DIBUJA de arriba abajo, con la tecnica
     de .no-col-title::before. La caja no se mueve: solo se revela su borde.
     En ::after porque el ::before lo ocupa la capa de resalte del hover, y
     porque asi la linea se pinta por encima de ella. */
  .cs-campo::after{
    content:""; position:absolute; inset:0;
    /* box-shadow y NO border: el motor redondea border-width a pixel de
       dispositivo (1.3333px se queda en 0.8) y la caja saldria mas fina que
       las demas lineas de la seccion. El spread del box-shadow conserva el
       decimal. Comprobado en el navegador. */
    box-shadow:inset 0 0 0 var(--linew, 1.5px) #1d1d1c;
    clip-path:inset(0 0 100% 0);
    transition:clip-path .85s cubic-bezier(.65,0,.35,1);
    pointer-events:none;
  }
  .cs-campo.visible::after{ clip-path:inset(0 0 0 0); }
  .cs-campo:nth-child(2).visible::after{ transition-delay:.12s; }
  .cs-campo:nth-child(3).visible::after{ transition-delay:.24s; }
  /* SIN position: es el ancestro del enlace, y si se posiciona, el area
     pulsable se encoge hasta el tamano del propio titulo. */
  .cs-c-nombre{
    margin:0;
    font-size:32px; line-height:1.15; font-weight:500; letter-spacing:-.02em; color:#1d1d1c;
  }
  .cs-c-desc{
    position:relative; margin:22px 0 0;
    font-size:20px; line-height:1.45; font-weight:400; color:#1d1d1c; text-wrap:pretty;
  }
  /* los tres puntos: el indice del servicio, separado por una hairline.
     Misma relacion que .svc-lista2 con su .sv2-pregunta en el overlay. */
  .cs-c-lista{
    position:relative; list-style:none; margin:34px 0 0; padding:24px 0 0;
  }
  .cs-c-lista::before{
    content:""; position:absolute; left:0; right:0; top:0;
    height:var(--linew, 1.5px); background:#1d1d1c;
  }
  .cs-c-lista li{
    font-size:18px; line-height:1.5; font-weight:400; color:#1d1d1c;
  }
  /* "MAS INFORMACION". El subrayado NO es el nativo: los tres text-decoration
     de la hoja (.legal-doc a, .co-basic a, .co-consent a) viven en texto
     corrido de los legales y del formulario, y su grosor lo elige el
     navegador, que a escala 0.75 no coincide con ninguna otra linea. Aqui es
     una linea propia del mismo grosor que las divisorias y los contornos,
     sobre un <span> para que mida lo que el texto y no la columna entera.
     Y NO con border-bottom, aunque era lo obvio: el motor redondea
     border-width a pixel de dispositivo y 1.5px se quedaba en 0.8, mas fino
     que cualquier otra linea de la seccion -- el mismo motivo por el que el
     contorno de las tarjetas va en box-shadow. Se dibuja con height +
     background, que conserva el decimal, igual que .cs-c-lista::before.
     Va FUERA del <a> a proposito: el area estirada ya hace pulsable toda la
     tarjeta, y asi el texto del enlace sigue siendo el nombre del servicio en
     vez de un "Mas informacion" que no dice nada fuera de contexto. */
  .cs-mas{
    margin:28px 0 0; font-size:18px; line-height:1.5; font-weight:400; color:#1d1d1c;
    transition:color .22s ease;   /* el mismo del nombre, para que entren juntos */
  }
  .cs-mas-in{
    position:relative; display:inline-block; padding-bottom:4px;
  }
  .cs-mas-in::after{
    content:""; position:absolute; left:0; right:0; bottom:0;
    height:var(--linew, 1.5px); background:currentColor;
  }
  /* la grande lo lleva en linea propia bajo los tipos, no a la derecha de
     ellos: cabia al lado (1099 unidades libres), pero eso la habria dejado en
     470 mientras las tres subian a ~400, estrechando de 127 a 70 la
     diferencia de alto que sostiene toda la jerarquia de la seccion. */
  .cs-principal .cs-mas{ grid-column:1 / -1; }
  /* al pasar el cursor acompana al nombre: el subrayado va en currentColor,
     asi que la linea sigue al texto sola */
  .cs-campo:hover .cs-mas,
  .cs-principal:hover .cs-mas{ color:var(--hl-tinta); }
  /* la flecha de los bloques del overlay, misma pieza */
  .cs-flecha{ display:inline-block; width:.92em; height:.92em; margin-right:.26em; vertical-align:-.1em; color:#1d1d1c; }
  .cs-flecha svg{
    width:100%; height:100%; display:block; transform:rotate(45deg);
    transition:transform .22s ease;
  }
  /* LAS CUATRO TARJETAS SON PULSABLES.
     El enlace lleva el nombre del servicio como texto real -- son cuatro
     enlaces internos de verdad desde la home, no un <a> vacio con aria-label
     -- y se estira con un ::after propio para que toda la caja responda.
     El resalte es el mecanismo YA ESCRITO para compartirse (ver .cf-item, que
     lo documenta): capa que sube desde abajo, parametrizada por dos variables.
     La capa es #f4f4f4: 11 niveles por debajo del blanco de la tarjeta, que
     es el fondo sobre el que aparece. Se aclaro desde #f1f1f1 (14 niveles).
     NO bajar mucho mas de aqui: a 9 niveles el resalte empieza a perderse con
     el brillo bajo o con luz fuerte, y de 7 para abajo el hover se queda
     marcado solo por el rojo del "Mas informacion". El ROJO no lo
     toca el nombre: se reserva para "Mas informacion", que es la llamada a la
     accion. El nombre y su flecha se quedan en tinta -- la flecha va pegada al
     nombre y con su cuerpo, asi que encenderla sola lo habria partido en dos. */
  /* --hl-tinta es el conducto que el mecanismo compartido ya usa para el
     color del texto bajo el resalte (ver .cf-item:hover .cf-q). Aqui lleva el
     el rojo de la casa, que va en --red-core -- el mismo de .co-email en
     hover, de los enlaces de los legales y de los avisos del formulario. El
     #6e0000 que tambien aparece en la hoja no cuenta: es una parada intermedia
     del degradado de .glow-box, no un color de interfaz.
     Sobre el gris del resalte, que es el caso real, da 7,96:1; sobre el blanco
     del reposo, 8,99:1. Los dos por encima de AAA. */
  /* --hl-tinta se declara POR ANFITRION, asi que este rojo es solo de las
     tarjetas: .cf-item (el acordeon de FAQ) y .tb-serv-menu a (el desplegable)
     conservan el suyo y sus propias reglas. Aqui la unica que lo consume es la
     de .cs-mas, mas abajo. */
  .cs-campo, .cs-principal{ --hl-capa:#f4f4f4; --hl-tinta:var(--red-core); }
  .cs-enlace{ display:block; color:inherit; text-decoration:none; }
  /* SIN capa estirada sobre la tarjeta. La hubo -- un .cs-enlace::after con
     inset:0 -- y hacia la caja entera pulsable, pero al estar por ENCIMA del
     texto interceptaba el raton y no se podia seleccionar ni copiar nada:
     comprobado arrastrando de verdad sobre una descripcion, la seleccion
     salia vacia. Ahora la caja entera es pulsable por el manejador delegado,
     que acepta el clic venga de donde venga dentro de ella (ver app.js), y el
     cursor lo dice el cursor:pointer de aqui. */
  .cs-campo, .cs-principal{ cursor:pointer; }
  .cs-enlace:hover .cs-flecha svg{ transform:rotate(45deg) translateX(4px); }
  /* La capa de resalte se HUNDE en vez de subir el contenido: con z-index:-1
     dentro del contexto de apilado de la tarjeta queda por delante de su
     fondo y por detras del texto, que asi puede seguir sin posicionar. El
     contexto lo crea el z-index:0 de la tarjeta. */
  .cs-campo, .cs-principal{ z-index:0; }
  .cs-campo::before, .cs-principal::before{ z-index:-1; }
  /* mascaras de revelado: las mismas que los bloques del overlay */
  .cs-principal .rv, .cs-campo .rv{ display:block; overflow:hidden; padding:.12em 0 .16em; margin:-.12em 0 -.16em; }
  .cs-principal .rv-in, .cs-campo .rv-in{ display:block; transform:translateY(130%); }
  .cs-principal.visible .rv-in, .cs-campo.visible .rv-in{
    transform:none; transition:transform 1s cubic-bezier(.16,1,.3,1);
  }
  .cs-principal.visible .cs-desc .rv-in{ transition-delay:.1s; }
  .cs-principal.visible .cs-tipos .rv-in{ transition-delay:.2s; }
  .cs-campo.visible .cs-c-desc .rv-in{ transition-delay:.1s; }
  /* LOS NOMBRES NO SUBEN: BARREN DE IZQUIERDA A DERECHA, con la ley que
     justifica la regla de abajo (1.1s / .22,1,.36,1) y sin retardo. Los
     RETARDOS del escalonado no se tocan -- contorno + nombre a la vez,
     descripcion a +.1s y .cs-tipos a +.2s --, pero el nombre dura ahora 1.1s
     contra el 1s de la descripcion: no se cruzan porque con esa salida el
     nombre se posa hacia los ~580 ms y lo que queda es cola.
     Las descripciones se quedan SUBIENDO, con su 1s y su .16,1,.3,1: ya
     entraban de abajo a arriba y con mascara, que era lo que se buscaba.

     EL RECORTE VA EN .rv-in, DOS NIVELES POR DEBAJO DE LO OBSERVADO. Lo
     observado es .cs-principal / .cs-campo, y un clip-path sobre el elemento
     observado anula su rectangulo de interseccion -- le paso a .cs-hr y esta
     documentado arriba. El .rv-in ya existia para la subida, asi que aqui el
     markup no se toca.

     Hay que NEUTRALIZAR el translateY(130%) de la regla de arriba, o se
     sumarian los dos gestos y el nombre barreria mientras sube.

     Los insets verticales son NEGATIVOS y valen lo que el relleno de .rv
     (.12em arriba, .16em abajo) a proposito. El clip-path recorta contra la
     caja de .rv-in, y con line-height 1.06 sobre 96px esa caja es MAS CORTA
     que los glifos: un inset(0) a secas guillotinaria ascendentes y
     descendentes. Asi la region de recorte coincide exactamente con la caja
     de relleno de .rv, que es donde su overflow:hidden ya corta -- ni recorta
     de mas ni deja escapar nada.

     Dos efectos que conviene saber: .rv-in es display:block, asi que el
     barrido cruza el BLOQUE entero y un nombre de dos lineas se descubre a la
     vez en las dos; y en las tarjetas pequenas la flecha va DENTRO del
     .rv-in, de modo que entra en el barrido y, por estar a la izquierda,
     asoma la primera. */
  /* width:fit-content -- EL BARRIDO TIENE QUE CRUZAR TINTA, NO HUECO. .rv-in es
     display:block, asi que sin esto el recorte cruza el ancho entero del
     bloque y no el del texto, y el reparto es malisimo: medido a 1440, la
     tinta de "Vigilancia 24/7" ocupa el 49% de sus 365 px, asi que la mitad
     del barrido pasaba por encima de nada. Encogiendo la caja al texto, el
     nombre tarda toda la duracion en revelarse, mida lo que mida.
     NO cambia el salto de linea: donde el texto ya llenaba el ancho,
     fit-content devuelve el mismo ancho, y los de dos lineas siguen en dos.
     Y NO encoge el area pulsable: el <a> conserva sus 365x34, porque el que
     se encoge es un hijo suyo. Las dos cosas, comprobadas en el navegador.
     Solo va en los BARRIDOS. Las descripciones suben y para una subida el
     ancho de la caja da igual, asi que no se tocan. */
  .cs-nombre .rv-in, .cs-c-nombre .rv-in{
    transform:none;
    width:fit-content;
    clip-path:inset(-.12em 100% -.16em 0);
  }
  /* LA CURVA NO ES LA DE LA SUBIDA NI LA DEL FILETE, y es a proposito.
     Barrer texto no es barrer un filete: en el filete el borde cruza una
     banda sin detalle y su curva no se delata, pero sobre texto cada letra
     aparece al pasar el borde, asi que lo que se ve es el RITMO al que
     llegan las letras -- o sea la velocidad del borde, no su posicion.
     Con cubic-bezier(.65,0,.35,1), que es simetrica, el pico de velocidad
     cae a 2,86x la media EN EL CENTRO EXACTO del recorrido, que es donde
     estan casi todas las letras: las letras llegan a rachas y eso es lo que
     se leia como seco.
     Con .22,1,.36,1 el pico sube a 4,55x pero se muda al ARRANQUE, donde
     todavia no hay nada que mirar, y a partir de ahi el borde solo frena. El
     texto se posa en vez de barrerse.
     Y no vale con alargar conservando la curva: eso divide la velocidad en
     proporcion pero deja el pico donde esta. De 850 a 1400 ms el pico sobre
     .cob-desc solo baja de 2118 a 1286 px/s y sigue cayendo en mitad de la
     frase. Es el mismo escalon, mas tarde -- la misma leccion que dejo SV_K
     en el overlay, donde bajarlo buscando suavidad dio pastosidad.
     1100 y no 1000 porque con una salida tan cargada el final deja de verse
     mucho antes de acabar: el borde cubre el 97% de .cob-desc a los 584 ms
     de los 1100, asi que la duracion nominal no es la percibida. */
  .cs-principal.visible .cs-nombre .rv-in,
  .cs-campo.visible .cs-c-nombre .rv-in{
    clip-path:inset(-.12em 0 -.16em 0);
    transition:clip-path 1.1s cubic-bezier(.22,1,.36,1);
  }
  /* LA TARJETA GRANDE LLEVA OTRA CURVA, y la duracion es la misma. Es el unico
     de los cuatro nombres donde el fit-content no sirvio de nada: envuelve a
     DOS lineas, asi que fit-content devuelve el ancho disponible (780) y no la
     tinta, que solo llega a 615. El 21% del barrido cruza hueco y eso aqui no
     se puede arreglar sin clavar un ancho a mano.
     Con .22,1,.36,1, que va muy cargada al arranque, ese 79% de tinta se
     cubria a los 292 ms de los 1100: lo que se ve duraba menos de un tercio
     del tiempo declarado y el resto era cola invisible. Subir la duracion no
     lo arregla, lo alarga -- a 1.5s serian 399 ms de tinta y un segundo de
     cola. Con .33,1,.68,1, que reparte mas, la tinta pasa a 447 ms SIN cola
     muerta, y de paso el pico del borde baja de 3223 a 2149 unid/s.
     Y no descasa de las tres pequenas: al compartir duracion el borde de la
     grande ya iba 3,13x mas rapido que la media de ellas, porque cruza 780
     contra 178-314. Esto lo deja en 2,09x, o sea MAS parejo que antes, no
     menos. Igualarlo del todo pediria 3,44s, que es absurdo.
     Las tres pequenas no se tocan: son una fila de tres objetos identicos,
     casan entre si y su tinta es el 100% de su caja gracias al fit-content,
     asi que usan sus 1100 ms enteros.
     Va de longhand sobre el atajo de arriba a proposito: asi lo unico que
     cambia entre la grande y las pequenas queda en una linea y a la vista. */
  .cs-principal.visible .cs-nombre .rv-in{
    transition-timing-function:cubic-bezier(.33,1,.68,1);
  }


  /* ====== COBERTURA -- banda gris a sangre, seis filas ======
     A SANGRE como el footer: left:0 y 1920 de ancho, que es la unica forma de
     sangrar en el lienzo (no hay margenes negativos que valgan, las
     coordenadas son absolutas). El contenido se queda en la columna de
     siempre, 80 -> 1840, con el padding lateral de 80: los mismos margenes
     simetricos de .about-text, .cs-hr, .cs-principal y .cs-campos.
     Los 15px que el lienzo se pasa por debajo de la barra de scroll aqui
     juegan a favor: una banda a sangre quiere sobrar, no quedarse corta.
     EL ALTO NO SE DECLARA. Es texto y refluye, asi que lo mide fitCanvas y de
     el cuelgan el cierre y el footer, igual que ya cuelgan de .cs-campos. */
  .cob{
    position:absolute; left:0; top:3806px; width:1920px;   /* top de reserva; lo fija fitCanvas */
    box-sizing:border-box; padding:120px 80px 100px;
    background:#3b3b3b;
    font-family:'Figtree',Arial,sans-serif;
    color:#ffffff;
  }
  /* SIN EYEBROW: la cabecera es solo el titular, asi que arranca en el
     padding-top de la banda y no lleva margen propio. Hubo una etiqueta de 14
     encima, y con ella se fue el margen de 43 que la separaba del titular.
     Texto vivo y no un img.tsvg: los cinco wordmarks son assets y esta seccion
     no trae ninguno. El cuerpo es el de .cs-nombre (96) y el peso el del
     display de la pagina (.cierre-headline 122/300, .cs-titulo 300/300). */
  .cob-titulo{
    margin:0;
    /* 400 y no 300: a 96px la Light de Figtree se afina mas de la cuenta. Sube
       con .cierre-headline, que tiene el mismo problema y mas acusado por su
       cuerpo de 122. Son los DOS titulares de display de texto vivo de la home,
       asi que se mueven juntos o la pagina queda con dos voces.
       NO arrastran a nadie: cada regla declara su propio peso, las 44 de la
       hoja son independientes. El overlay (.sv2-word, .fg-title) y los legales
       se quedan en 300 a proposito, que son otra pantalla.
       Y .cs-titulo NO puede acompanar: es un wordmark (img.tsvg) y su grosor
       esta en el dibujo, no en el CSS. */
    font-size:96px; line-height:1; font-weight:400; letter-spacing:-.02em; color:#ffffff;
  }
  /* DOS COLUMNAS DE TRES, y se llena POR COLUMNAS: grid-auto-flow:column con
     tres filas explicitas mete 1-2-3 en la izquierda y 4-6 en la derecha, que
     es como se pidio y ademas deja el orden del DOM igual que el de lectura
     (se baja por la izquierda y se sigue por la derecha), asi que el lector de
     pantalla y la cascada del revelado van por donde va el ojo.
     840 + 80 + 840 = 1760. La calle de 80 es el margen de la pagina: media
     banda pide un hueco de margen, no la calle de 60 de dentro de una fila. */
  .cob-filas{
    margin-top:80px;
    display:grid; grid-template-columns:840px 840px;
    grid-template-rows:repeat(3, auto); grid-auto-flow:column;
    column-gap:80px;
  }
  /* EL NOMBRE SE APILA SOBRE LA DESCRIPCION; ya no son dos columnas.
     Al partir la banda en dos, la celda pasa de 1760 a 840 y el reparto de
     antes (nombre 340 + calle 60 + descripcion 780 = 1180) no cabe. Encogerlo
     a 840 dejaria la descripcion en 440-540, o sea 38-47 caracteres por linea:
     mas estrecha que cualquier otra columna de texto de la pagina, y las seis
     descripciones se irian a 4 lineas. Apilado, la descripcion se queda con
     los 840 enteros -- unos 73 caracteres, casi la medida que ya tenia con
     780 (68) -- y el nombre no puede partirse nunca, porque le sobra el ancho.
     Asi NO hay que tocar la escala tipografica: los 32 del nombre y los 20 de
     la descripcion siguen siendo los de .cs-c-nombre y .cs-c-desc.

     Los 22 de separacion son los de .cs-c-desc, que cuelga del mismo cuerpo de
     32. El filete sigue en el ::before y ahora mide 840, el ancho de la celda:
     esa es la medida de .cs-tipos::before y .cs-c-lista::before, que tampoco
     van a sangre sino al ancho de lo que rematan. */
  .cob-fila{
    position:relative;
    padding:32px 0 40px;
  }
  /* EL FILETE VA EN EL ::before, NUNCA en .cob-fila. La fila es lo que mira el
     IntersectionObserver y un clip-path sobre el elemento observado anula su
     rectangulo de interseccion: ratio 0, nunca cruza el umbral, nunca se le
     pone .visible y nunca se quita el recorte. Le paso a .cs-hr y esta
     documentado. Fondo y no border, como .cs-tipos::before y .cs-hr::after:
     el motor redondea border-width a pixel de dispositivo. */
  .cob-fila::before{
    content:""; position:absolute; left:0; right:0; top:0;
    /* --linew-nitido y no --linew: es la UNICA regla de la pagina que usa la
       ley cuadrada, y se gana la excepcion porque aqui hay seis filetes
       identicos en una pantalla, tres encima de otros y dos en paralelo, asi
       que el ojo los compara. Con --linew el pico iba de 178 a 254 segun la
       fila; con este los tres tienen nucleo 255. En el resto de la pagina las
       lineas estan lejos unas de otras y no compensa el 60% de engorde. */
    height:var(--linew-nitido, 1.5px); background:#ffffff;
    clip-path:inset(0 100% 0 0);
    transition:clip-path .85s cubic-bezier(.65,0,.35,1);
  }
  .cob-fila.visible::before{ clip-path:inset(0 0 0 0); }
  .cob-nombre{
    margin:0;
    font-size:32px; line-height:1.15; font-weight:500; letter-spacing:-.02em; color:#ffffff;
  }
  /* EL ICONO, AL BORDE DERECHO DE LA CELDA y no pegado al nombre: los seis
     nombres miden de 44 a 211, asi que pegados quedarian a seis distancias
     distintas y la columna se leeria desordenada. Al borde, los iconos forman
     una vertical que el ojo recorre.
     Va DENTRO del .rv-in, asi que sube con el nombre como una sola pieza. Es
     lo que ya hace .cs-c-nombre con su flecha.

     El .cob de mas en el selector NO sobra: .cob .rv-in{display:block} viene
     despues en la hoja y con la misma especificidad ganaria por orden.

     align-items:baseline y no center: la linea base de un <svg> es su borde
     inferior, asi que el icono se apoya en la linea del texto. Con la tinta
     medida a la altura de mayusculas, ocupa exactamente la banda de las
     mayusculas del nombre.

     ALTURA POR TINTA Y NO POR CAJA. Los seis venian con cuatro viewBox
     distintos (24, 32, 36 y 512) y la tinta llenandolos de forma muy desigual:
     con un height:1em a 32 las alturas reales habrian salido 32, 30,6, 30, 28,
     25,5 y 23 -- un 39% de diferencia entre "el mismo tamano". Cada viewBox va
     recortado a su caja de tinta MEDIDA (rasterizada, porque getBBox no cuenta
     el trazo), asi que height los iguala de verdad.

     .705em es la altura de mayusculas MEDIDA de la tipografia, no un numero
     redondo. Se midio contra FIGTREE, que es la que se sirve, asi que
     ya es el valor bueno y no una reserva. Va en em y no en px para que al
     menos siga al cuerpo sola. */
  .cob .cob-nombre .rv-in{ display:flex; align-items:baseline; }
  .cob-n{ flex:none; }
  .cob-ico{ flex:none; margin-left:auto; height:.705em; width:auto; }
  /* #cfcfcf no es un gris inventado: es el que ya usa .footer sobre este mismo
     #3b3b3b. Los nombres van en blanco puro y las descripciones un escalon por
     debajo, que es la pareja que la pagina ya tiene hecha para este fondo. */
  .cob-desc{
    margin:22px 0 0;
    font-size:20px; line-height:1.45; font-weight:400; color:#cfcfcf; text-wrap:pretty;
  }
  /* MASCARAS DE REVELADO: LA SUBIDA DE LA CASA, la misma de .cs-principal y
     .cs-campo. Estos dos textos llegaron a barrer de izquierda a derecha y se
     han devuelto a la subida; el titular se ha quedado SIN revelado ninguno y
     por eso ya no tiene .rv en el markup.

     DE LAS DOS FORMAS DE ENTRAR DE ABAJO ARRIBA, esta y un clip-path puro que
     suba la ventana sobre el texto quieto, se pone esta -- y la razon de peso
     son las DOS LINEAS de .cob-desc. Un recorte vertical sobre un bloque de
     dos lineas descubre primero la de ABAJO, porque el borde sube: el texto
     aparecería en orden inverso al de lectura. Subiendo, el bloque entero se
     mueve de una pieza y las dos lineas llegan en su orden. Ademas es el
     gesto que ya hace el resto de la pagina y el texto se mueve, que da mas
     cuerpo que un recorte sobre texto quieto.

     SIN fit-content, que se fue con el barrido: para una subida el ancho de
     la caja da igual -- lo que tapa es .rv por arriba y por abajo -- y
     dejarlo puesto solo seria ruido. En los nombres de las tarjetas sigue,
     porque alli si se barre.

     EL FILETE NO CAMBIA: .85s / .65,0,.35,1, dibujandose de izquierda a
     derecha. Y ahora ya no hay nada que unificar con el, porque texto y
     filete vuelven a ir en EJES DISTINTOS -- el filete cruza, el texto sube
     --, que es la misma pareja cruzada que tienen .cs-campo y su contorno.
     Lo que los une sigue siendo arrancar juntos. */
  .cob .rv{ display:block; overflow:hidden; padding:.12em 0 .16em; margin:-.12em 0 -.16em; }
  .cob .rv-in{ display:block; transform:translateY(130%); }
  /* EL TITULAR NO SE REVELA: aparece ya puesto. Conserva sus .rv/.rv-in en el
     markup aunque no enmascaren nada, y esto NO es descuido. Esa caja no es
     solo mascara: el relleno de .rv (.12em + .16em = 26,88 unidades sobre un
     cuerpo de 96) entra en el alto del h2, y la seccion se midio con ella.
     Quitando los dos span, medido contra el commit anterior a 1440x820: el
     hueco de la tinta del titular a la primera fila pasaba de 64,64 a 71
     unidades, +6,36. El alto de .cob no se movia (970 las dos veces, asi que
     nada de lo de debajo se enteraba), pero el aire de dentro si. Un cambio
     de espaciado no es lo que se pidio aqui.
     Lo que si se le quita es el overflow, que sin mascara solo puede recortar
     un glifo el dia que cambie el copy o la tipografia. Y hay que
     neutralizarle el translateY o se quedaria 130% mas abajo para siempre:
     .cob-head ya no se observa, asi que nadie le va a poner .visible. */
  .cob-titulo .rv{ overflow:visible; }
  .cob-titulo .rv-in{ transform:none; }
  .cob-fila.visible .rv-in{
    transform:none; transition:transform 1s cubic-bezier(.16,1,.3,1);
  }
  .cob-fila.visible .cob-desc .rv-in{ transition-delay:.1s; }








  /* ====== TÍTULOS COMO WORDMARK (SVG) ======
     Sustituyen a los títulos de texto conservando tamaño (alto = 1em del
     título), posición y la animación de su contenedor. */
  /* height:1em es una reserva MALA y se pasa siempre: iguala la altura de la
     TINTA del wordmark con la caja em, y eso nunca es cierto -- la tinta de
     una palabra a 210px mide ~150 de alto, no 210, asi que el SVG entero se
     escala 1,4x y el ancho se va con el. Medido: los titulares nacian entre un
     33% y un 44% mas anchos de lo que dimTitulos() les pone despues.

     La reserva buena es el ANCHO EN EM de cada palabra, que es justo lo que
     mide dimTitulos(). Va por anfitrion porque la razon depende del peso y del
     tracking de cada uno, no solo de la palabra: «servicios» da 3,726 en
     .cs-titulo (peso 300, tracking -.02em) y 4,231 en .m2-pword (peso 700, sin
     tracking).

     TODAS ESTAS RAZONES ESTAN MEDIDAS CON FIGTREE, que es la que se sirve.
     Si algun dia cambia la familia hay que rehacerlas. Quien no tenga regla propia se queda
     con el height:1em de antes, que es de donde se parte. */
  .tsvg{ display:block; width:auto; height:1em; }
  .cs-titulo    .tsvg{ width:3.681em; height:auto; }   /* servicios  */
  /* El 3.486 es "Proceso" SIN transformar, y es lo correcto aunque la regla
     base .svm-big lleve text-transform:uppercase: el UNICO .svm-big con
     wordmark es el de .svm-panel--cierre, que lo anula con
     text-transform:none. Los otros cuatro .svm-big (Mapeo, Analisis,
     Intrusion, Informe) si van en versales, pero son texto plano y no tienen
     .tsvg que reservar. Comprobado en /servicios/auditorias: el anfitrion
     computa text-transform:none y el <img> mide 732,0 contra los 732,1 que da
     la reserva. */
  .svm-big      .tsvg{ width:3.486em; height:auto; }   /* Proceso    */
  .no-valores   .tsvg{ width:3.103em; height:auto; }   /* fuerzas    */
  /* Los del movil se miden EN MOVIL: sus reglas viven dentro del @media de
     820, asi que medidos desde escritorio salen con otro peso y otro tracking
     -- y con esas razones el desvio quedaba entre el 5% y el 13,5%. */
  .m2-audit     .tsvg{ width:4.113em; height:auto; }   /* auditorías */
  .m2-pfuerzas  .tsvg{ width:3.103em; height:auto; }   /* fuerzas    */
  .m2-pword     .tsvg[alt="servicios"]{ width:3.681em; height:auto; }
  .m2-pword     .tsvg[alt="about"]{ width:2.484em; height:auto; }
  .tsvg--light{ filter:brightness(0) invert(1); }
  .tsvg--dark{ filter:brightness(0); }

  /* ====== POLVO DE PUNTOS (dithering animado) ======
     Nubes de puntos cuadrados estilo tramado retro que derivan lentamente
     por toda la página. En grises y con mezcla multiplicar: se ven sobre
     blanco y gris, y desaparecen solos sobre negros y texto. */
  #polvo{
    position:fixed; inset:0;
    width:100%; height:100%;
    pointer-events:none;
    z-index:66;               /* sobre el lienzo de contenido (65): visible también en la banda gris */
    mix-blend-mode:multiply;
    opacity:0;                   /* arranca oculto: el fondo aparece como 2º paso (fundido por JS) */
    image-rendering:pixelated;
  }


  /* ====== TOP BAR FIJA (a partir de la sección 2) ======
     Aparece al dejar atrás la hero y sus animaciones. Vidrio esmerilado
     (blur) con una línea fina que la separa del resto de la página. */
  .topbar{
    /* Tamaño de las entradas del menú. Lo comparten el nav y el desplegable de
       servicios, que tiene que ir con la MISMA tipografía: family y peso los
       heredan los dos de aquí, y el tamaño sale de esta variable para que no
       puedan separarse al tocar uno de los dos. */
    --tb-nav-size:20px;
    position:fixed; top:0; left:0; right:0;
    height:56px;
    font-family:'Figtree',Arial,sans-serif;
    background:#ffffff;                        /* color sólido, sin desenfoque */
    border-bottom:1.5px solid #1d1d1c;         /* línea negra cuando la topbar es blanca */
    z-index:80;
    transform:translateY(-101%);
    transition:transform .5s cubic-bezier(.22,1,.36,1),
               background .45s ease, border-color .45s ease, color .45s ease;
  }
  .topbar.visible{ transform:translateY(0); }
  /* Cuando el bloque gris llega arriba, la topbar adopta el mismo gris */
  .topbar.met{
    background:#3b3b3b;
    border-bottom:1.5px solid #ffffff;
  }
  .topbar.met nav a{ color:#ededed; }
  .topbar.met .tb-logo{ border-right-color:#ffffff; }
  .topbar.met .tb-logo svg path{ fill:#ffffff; }
  .topbar.solido{ background:#ffffff; }
  /* La topbar adopta el gris claro de la sección ABOUT (#f1f1f1) mientras ese
     fondo ocupa la franja de la barra; vuelve a blanco cuando el fondo es blanco. */
  .topbar.claro{ background:#f1f1f1; }
  /* Logotipo "intharis" a la izquierda, centrado en su recuadro, con divisoria
     vertical que lo separa del resto. Negro sobre blanca; blanco sobre gris. */
  /* Los cuatro logotipos de topbar son <a href="/">: desde que "inicio" no
     está en el menú, son ellos el camino a la home, y como enlaces de verdad
     llegan por tabulador y se pueden abrir en otra pestaña. */
  .tb-logo, .sv-tblogo, .co-tblogo, .no-simbolo{ text-decoration:none; }
  .topbar .tb-logo{
    position:absolute; left:0; top:0; height:100%;
    width:128px; box-sizing:border-box;
    display:flex; align-items:center; justify-content:center;
    border-right:1.5px solid #1d1d1c;
    transition:border-color .45s ease;
  }
  .topbar .tb-logo svg{ height:21px; width:auto; display:block; }
  .topbar .tb-logo svg path{ fill:#1d1d1c; transition:fill .45s ease; }
  .topbar .tb-logo svg rect.glx-tmp{ fill:#1d1d1c; }
  .topbar.met .tb-logo svg rect.glx-tmp{ fill:#ffffff; }
  /* Secciones a la izquierda, tras la divisoria del logo. Minúsculas y grandes,
     cada una con un pequeño triángulo (grisáceo; blanco puro al estar activa). */
  .topbar nav{
    position:absolute; left:128px; top:0; height:100%;
    display:flex; align-items:center; gap:30px;
    padding-left:28px;
    font-size:var(--tb-nav-size);
  }
  .topbar nav a{
    color:var(--black); text-decoration:none; text-transform:lowercase;
    display:inline-flex; align-items:center; gap:9px;
    transition:color .45s ease;
  }
  .topbar nav a::before{
    content:""; width:9px; height:9px; flex:none;
    background:currentColor; opacity:.42;
    clip-path:polygon(0 0, 100% 0, 0 100%);
    transition:opacity .3s ease;
  }
  .topbar nav a.activo::before{ opacity:1; }
  .topbar.met nav a.activo{ color:#ffffff; }
  /* Hover: la palabra sube dentro de una máscara y reaparece por abajo */
  .roll{ display:inline-block; overflow:hidden; height:1.12em; line-height:1.12; vertical-align:bottom; }
  .roll__in{ display:block; transition:transform .4s cubic-bezier(.22,1,.36,1); }
  .roll__in::after{ content:attr(data-t); display:block; }
  .topbar nav a:hover .roll__in,
  .no-nav a:hover .roll__in{ transform:translateY(-50%); }

  /* ====== VARIANTES DE LA PANTALLA DE SERVICIOS ======
     La misma pantalla sirve al índice y a los cuatro servicios; cuál se ve lo
     dice data-servicio, que graba quien la abre. El envoltorio va a
     display:contents y no a block: .sv2-frase y .sv2-right se posicionan contra
     .sv2, y un envoltorio con caja propia les cambiaría el contenedor. Con
     display:contents no existe para la maquetación, y lo que se ve queda
     exactamente donde estaba. */
  .serv-overlay .sv-var{ display:none; }
  .serv-overlay[data-servicio=""] .sv-var[data-var="indice"],
  .serv-overlay:not([data-servicio]) .sv-var[data-var="indice"],
  .serv-overlay[data-servicio="auditorias"] .sv-var[data-var="auditorias"],
  .serv-overlay[data-servicio="vigilancia-24-7"] .sv-var[data-var="vigilancia-24-7"],
  .serv-overlay[data-servicio="continuidad"] .sv-var[data-var="continuidad"],
  .serv-overlay[data-servicio="formacion"] .sv-var[data-var="formacion"]{ display:contents; }

  /* ====== DESPLEGABLE DE "SERVICIOS" (escritorio) ======
     "servicios" no navega: abre este panel con los cuatro servicios y su
     índice. Cuelga de la topbar, que es position:fixed y no recorta, así que
     el panel se mide en px de PANTALLA, no en unidades del lienzo de 1920:
     la topbar vive fuera de #canvas y no la escala nadie.

     Se revela dibujándose de arriba abajo con clip-path sobre el borde, como
     las divisorias del resto de la web, y cada entrada sube desde su máscara
     con retardo escalonado, como la lista de .sv2-lista. Los colores siguen a
     la topbar: blanca, gris claro sobre about y gris oscuro sobre metodología. */
  .tb-serv-menu{
    position:absolute; top:100%;
    /* El panel arranca en la línea vertical que separa el logotipo del resto
       de la barra: el recuadro del logo mide 128px en las cuatro topbars. Aquí
       va su caja SIN restar nada; el trazo lo pinta ::before, más abajo, con la
       misma construcción que la divisoria del logotipo. Es un número del CSS,
       no del contenido: no depende de la tipografía ni hay que remedirlo al
       redimensionar. */
    left:128px;
    /* al contenido, no a un ancho fijo: así no se desalinea con nada */
    width:max-content; max-width:min(520px, calc(100vw - 160px));
    /* Los colores los pone la topbar que lo aloja, que son cuatro y cada una
       con su fondo: la principal (blanca, gris claro sobre about, gris oscuro
       sobre metodología), la de servicios (gris oscuro, blanca en la pantalla
       clara), la de "sobre nosotros" (gris oscuro) y la de contacto (gris
       claro). Con dos variables por anfitrión se evita una regla por
       combinación. */
    background:var(--tbm-fondo);
    /* Ni borde izquierdo ni inferior: los pintan ::before y la última fila,
       por lo de abajo. El superior sí, y NO duplica el de la topbar, porque
       top:100% se mide contra la caja de padding y esa ya descuenta el
       border-bottom de .topbar: el panel cae justo encima de esa línea y la
       repone con el mismo grosor y color. Que se mida contra la caja de
       padding es justo lo que lo hace exacto: el navegador cuadra el grosor
       del borde a píxeles enteros de pantalla, y la caja de padding ya lleva
       dentro ese grosor CUADRADO, no el 1.5 nominal. */
    border:1.5px solid var(--tbm-tinta);
    border-left:0; border-bottom:0;
    font-size:var(--tb-nav-size, 20px);
    visibility:hidden; pointer-events:none;
    /* La revelación solo anima el inset inferior. Los laterales llevan holgura
       porque ::before cae POR FUERA de la caja de borde, a su izquierda, y el
       clip se lo comería. Es holgura, no una medida: vale cualquier valor
       mayor que el grosor del trazo. */
    clip-path:inset(0 0 100% -8px);
    transition:clip-path .55s cubic-bezier(.16,1,.3,1), visibility 0s .55s,
               background .45s ease, border-color .45s ease;
  }
  /* ---- El trazo izquierdo, con la MISMA construcción que la del logotipo ----
     Este es el punto fino de toda la alineación. La divisoria del logotipo es
     un border-right sobre una caja cuyo borde derecho está en la x=128: se
     pinta hacia dentro, ACABANDO en 128. Un border-left del panel, en cambio,
     EMPIEZA donde lo ponga left y crece hacia la derecha. Anclados a bordes
     opuestos, los dos solo caen en los mismos píxeles si el grosor usado es
     exactamente 1.5, y no lo es casi nunca: el navegador usa
     floor(1.5 x DPR) / DPR, que da 0.8 a DPR 1.25, 1.143 a 1.75 y 1.2 a 2.5.
     De ahí el escalón de un píxel de pantalla en esos DPR, invisible a 1, 1.5
     y 2 (ahí coinciden, dos por suerte del redondeo y uno de verdad).
     Con esto el trazo del panel es la misma construcción: caja de ancho 0 cuyo
     borde derecho cae en 128 -- right:100% lo lleva al borde de padding
     izquierdo del panel, que sin border-left es su propio borde de caja, o sea
     128 -- y border-right que se pinta hacia dentro. Mismo anclaje y mismo
     grosor que el del logotipo, así que el navegador los cuadra a las mismas
     columnas sea cual sea el DPR, sin números que ajustar. */
  .tb-serv-menu::before{
    content:""; position:absolute; top:0; bottom:0; right:100%;
    width:0; border-right:1.5px solid var(--tbm-tinta);
    transition:border-color .45s ease;
  }
  /* Arriba, el mismo caso. Las otras tres topbars no llevan border-bottom: su
     línea inferior es un ::after (bottom:0; height:0; border-bottom) anclado al
     borde de abajo de la barra. Como el elemento no tiene borde, su caja de
     padding llega a los 56 enteros y top:100% deja el panel POR DEBAJO de esa
     línea; con un border-top propio se pintarían dos trazos pegados y la línea
     saldría del doble de gruesa bajo el ancho del panel.
     Aquí no hace falta reponer nada: la línea de la barra ya cruza de lado a
     lado y hace de borde superior del panel, que arranca justo debajo. En
     .topbar sí lo lleva, porque allí top:100% se mete DENTRO de su borde y hay
     que reponer el trozo tapado. */
  .sv-topbar .tb-serv-menu,
  .no-topbar .tb-serv-menu,
  .co-topbar .tb-serv-menu{ border-top:0; }
  .tb-serv-menu.abierto{
    visibility:visible; pointer-events:auto;
    clip-path:inset(0 0 0 -8px);
    transition:clip-path .55s cubic-bezier(.16,1,.3,1),
               background .45s ease, border-color .45s ease;
  }
  /* ---- Panel suelto: el desplegable de "sobre nosotros" ----
     Se alinea igual que el de servicios -- el texto de las entradas arranca
     donde arranca la tinta de su disparador en la topbar -- pero no cuelga de
     ninguna línea: la única vertical de la banda de la topbar es la divisoria
     del logotipo y esa la usa el otro, y "sobre nosotros" queda 172px a su
     derecha. De ahí el nombre: su borde izquierdo cae donde lo deje la medida,
     hoy en x≈253, y no sobre nada.
     Dos consecuencias. Una, el `left` lo escribe alinear() en app.js en vez de
     estar aquí. Otra, el trazo izquierdo es un border-left normal y no la
     construcción con ::before, que existía justamente para cuadrarlo con esa
     divisoria al píxel físico compartiendo su anclaje; sin divisoria que cuadrar
     no hay nada que compartir. */
  .tb-serv-menu.tbm-suelto{
    border-left:1.5px solid var(--tbm-tinta);
  }
  .tb-serv-menu.tbm-suelto::before{ content:none; }
  .topbar{ --tbm-fondo:#ffffff; --tbm-tinta:#1d1d1c; }
  .topbar.claro{ --tbm-fondo:#f1f1f1; }
  .topbar.met{ --tbm-fondo:#3b3b3b; --tbm-tinta:#ffffff; }
  .sv-topbar{ --tbm-fondo:#3b3b3b; --tbm-tinta:#f1f1f1; }
  .sv-topbar.claro{ --tbm-fondo:#ffffff; --tbm-tinta:#1d1d1c; }
  .no-topbar{ --tbm-fondo:#3b3b3b; --tbm-tinta:#ffffff; }
  /* .no-topbar.claro invierte la barra igual que .sv-topbar.claro (fondo
     blanco, líneas y texto en negro), así que el panel tiene que invertirse
     con ella: si no, se quedaba gris oscuro con tinta blanca colgando de una
     barra ya blanca, y su borde superior -- que es la línea de la barra --
     habría cambiado de color por su cuenta. */
  .no-topbar.claro{ --tbm-fondo:#ffffff; --tbm-tinta:#1d1d1c; }
  .co-topbar{ --tbm-fondo:#f1f1f1; --tbm-tinta:#1d1d1c; }
  /* Los dos paddings laterales son EL MISMO valor, y no es un número del CSS.
     El izquierdo es lo que separa el borde del panel (clavado en la línea del
     logotipo, x=128) del punto donde empieza la tinta de "servicios" en la
     topbar, que es donde tiene que caer el texto de las entradas: depende del
     ancho de las palabras del menú y por tanto de la tipografía, así que lo
     mide y lo escribe alinear() en app.js. El derecho no tiene por qué medirse
     -- no se alinea con nada --, pero sí tiene que valer lo mismo para que el
     texto quede centrado entre los dos bordes del panel, y por eso lee la misma
     variable en vez de llevar su propio número: con un 22 fijo, el margen que
     el JS estira a la izquierda se quedaría corto a la derecha en cuanto la
     tipografía cambiase. El 22 de aquí es solo el valor de partida, el que se ve si el
     JS no llega a correr. */
  .tb-serv-menu a{
    position:relative;
    display:block; padding:13px var(--tbm-pad-izq, 22px);
    color:var(--tbm-tinta); text-decoration:none;
    border-bottom:1.5px solid var(--tbm-tinta);
    transition:color .45s ease, border-color .45s ease, background .3s ease;
  }
  /* La última fila SÍ conserva su línea: es la que cierra el panel por abajo,
     ahora que el panel no lleva border-bottom propio. Así el trazo izquierdo
     (::before, que se extiende hasta el borde de la caja porque abajo ya no hay
     borde que le acorte la caja de padding) llega justo hasta la esquina y no
     queda una muesca de un píxel. */
  /* Hover: el resalte de fila de las FAQ de contacto (ver "RESALTE DE FILA").
     La capa y la tinta se derivan de los dos colores del anfitrión, invertidos:
     donde la barra es oscura sale el mismo efecto que en las FAQ -capa clara y
     texto oscuro- y donde es clara sale el inverso, que es la única manera de
     que resalte sobre un fondo que ya es claro. Vale igual para los cambios de
     tema en marcha (.topbar.met, .sv-topbar.claro), porque son esas mismas
     variables las que cambian. */
  .tb-serv-menu a{ --hl-capa:var(--tbm-tinta); --hl-tinta:var(--tbm-fondo); }
  .tb-serv-menu a:hover .tbs-m{ color:var(--hl-tinta); }
  /* máscara por entrada: el texto sube desde abajo, escalonado. Va por encima
     de la capa del resalte, que si no lo taparía. */
  .tb-serv-menu .tbs-m{
    display:block; overflow:hidden; padding:.16em 0 .2em; margin:-.16em 0 -.2em;
    position:relative; z-index:1; transition:color .22s ease;
  }
  .tb-serv-menu .tbs-i{ display:block; transform:translateY(130%); }
  .tb-serv-menu.abierto .tbs-i{
    transform:translateY(0);
    transition:transform .75s cubic-bezier(.16,1,.3,1);
  }
  .tb-serv-menu.abierto a:nth-child(1) .tbs-i{ transition-delay:.10s; }
  .tb-serv-menu.abierto a:nth-child(2) .tbs-i{ transition-delay:.16s; }
  .tb-serv-menu.abierto a:nth-child(3) .tbs-i{ transition-delay:.22s; }
  .tb-serv-menu.abierto a:nth-child(4) .tbs-i{ transition-delay:.28s; }
  /* el triángulo del propio "servicios" gira al desplegarse: no hace falta
     glifo nuevo, ya hay uno en cada entrada de la topbar */
  /* Se estira a lo alto de la topbar para que no quede hueco entre el
     disparador y el panel: el ratón pasa de uno a otro sin salirse. El texto
     sigue centrado porque el propio <a> es inline-flex con align-items:center. */
  /* El disparador se estira a lo alto de su topbar: zona de clic más holgada.
     Vale para las cuatro, que comparten la misma caja de nav. */
  a[data-desplegable]{ cursor:pointer; align-self:stretch; }
  a[data-desplegable]::before{ transition:opacity .3s ease, transform .45s cubic-bezier(.16,1,.3,1); }
  a[data-desplegable].abierto::before{ transform:rotate(-90deg); opacity:1; }
  .sv-nav a[data-desplegable].abierto,
  .co-nav a[data-desplegable].abierto{ opacity:1; }   /* esas dos atenúan las inactivas */


  /* ====== AURA ROJA DEL CURSOR (con estela) ======
     El cursor conserva su imagen. Un halo de degradado rojo lo acompaña
     dejando una ESTELA que se desvanece sola. Con la mezcla "lighten" solo
     se tiñe lo OSCURO: textos, logos y elementos negros se vuelven rojos al
     paso del cursor y recuperan su color al disiparse el rastro. Los fondos
     claros quedan intactos y los fondos GRISES (#3b3b3b: topbar, cierre,
     footer, overlay nosotros) se excluyen por geometría en el JS del aura. */
  #aura{
    position:fixed; inset:0;
    width:100%; height:100%;
    pointer-events:none;
    z-index:460;   /* por encima de TODAS las secciones y overlays: el rojo tiñe el texto negro en toda la página */
    mix-blend-mode:lighten;
    opacity:0;
    transition:opacity .6s ease;
  }
  #aura.activo{ opacity:1; }
  body.cargando #aura{ opacity:0; }   /* jamás durante la animación de carga */

  /* ====== TRANSICIÓN HERO → ABOUT (estilo referencia S2000) ======
     4 paneles grises, solapados para que no haya junta. Cada uno arranca y CULMINA en un
     momento distinto: los de la izquierda terminan antes y los de la derecha
     van rezagados, con alturas irregulares en todo momento. Al completarse,
     la retícula de paneles continúa en el fondo gris de ABOUT sin costura.
     Confinados a la zona de la hero: el texto de ABOUT nunca se tapa. */
  .cortinas{
    position:absolute; left:0; top:0;
    width:1920px; height:1100px;  /* SOLO la zona de la hero (acaba en ~922): ABOUT queda siempre fuera */
    overflow:hidden;
    display:flex;
    pointer-events:none;
    z-index:10;
  }
  .cortinas .col{
    flex:1;
    background:#f1f1f1;
    transform:translateY(101%);   /* empiezan escondidas por debajo */
    will-change:transform;
  }
  /* EL SOLAPE VA EN --linew, NO EN PX DE LIENZO. Cada columna es una capa
     compuesta propia (will-change) dentro de un lienzo escalado, y su borde
     cae en x fraccionarias; con -1px de lienzo el solape era 0,74 px de CSS a
     1440 -- 0,87 de dispositivo a DPR 1,17, y 0,53 a 1024 --, y por la junta
     se colaba gris la tinta del logotipo grande que hay debajo: dos trazos
     verticales sobre la "s" final, en la junta del centro. --linew vale 1 px
     de CSS a cualquier ancho, asi que esto son ~3 px de CSS siempre. */
  .cortinas .col + .col{
    margin-left:calc(-3 * var(--linew));
  }

  /* ====== ANIMACIÓN DE CARGA ====== */
  /* Mientras dura la carga no se puede scrollear: la transición de paneles
     siempre arranca sobre la home completa, nunca a medio revelar */
  body.cargando{ overflow:hidden; }
  /* Todo oculto al inicio excepto el logotipo */
  body.cargando .canvas > *:not(.logo-grande){
    opacity:0;
  }
  .canvas > *:not(.logo-grande){
    transition:opacity .7s ease, transform .7s ease;
  }
  body.cargando .canvas > *:not(.logo-grande){
    transform:translateY(14px);
  }

  body.cargando .canvas > .mostrar{
    opacity:1; transform:none;
  }

  /* Animación de carga de las letras: en vez de mover los <path> dentro de un
     mismo SVG (lo que dejaba líneas/costuras entre letras vecinas al ir
     escalonadas), se anima un CLON del SVG por letra, cada uno mostrando SOLO
     su letra y en su PROPIA capa. Así no hay región de repintado compartida
     entre letras → sin líneas. */
  /* Cada letra SUBE una a una (como al principio). Va en un elemento pequeño
     y ajustado a su glifo, con margen transparente y SU PROPIA capa de
     compositor (will-change): así su movimiento no provoca el repintado del
     lienzo escalado (que dejaba líneas/costuras, p.ej. en la "t"). */
  .logo-grande > svg{ visibility:hidden; }   /* original oculto; las letras las pintan los divs animados */
  .logo-grande .logo-letra{
    position:absolute;
    transform:translateY(310px);   /* fuera (bajo el borde) al inicio */
    transition:transform .7s cubic-bezier(.25,.8,.3,1);
    will-change:transform; backface-visibility:hidden;
  }
  .logo-grande .logo-letra.visible{ transform:translateY(0); }
  .logo-grande .logo-letra svg{ width:100%; height:100%; display:block; overflow:visible; }


  /* ====== PALABRA ROTATORIA (STARTUP / NEGOCIO / PYME / WEB / EMPRESA) ======
     Efecto rodillo: la palabra actual sube y sale por arriba mientras la
     nueva entra por abajo, dentro de una máscara que recorta el movimiento. */
  .rotador{
    position:relative; display:inline-block;
    overflow:hidden;
    text-align:right;   /* ancho fijo (lo calcula el JS): el resto de la línea no se mueve */
  }
  .rotador .palabra{
    display:inline-block;
    transition:transform .55s cubic-bezier(.22,1,.36,1);
  }
  .rotador .entrante{
    position:absolute; right:0; top:0;
    transform:translateY(115%);
  }
  .rotador .sin-transicion{ transition:none; }

  /* ====== CIERRE / CTA (fondo blanco con la animación del polvo) ====== */
  /* ================= CERTIFICACIONES =================
     Titulo pequeno y una fila de seis logos, entre COBERTURA y el cierre.
     Vive DENTRO del lienzo, asi que las medidas van en unidades de 1920 y su
     top lo escribe fitCanvas(). Fuera de .cierre: los dos clones de los
     overlays hacen cierre.cloneNode(true) con height:1080 forzado.

     EL SPRITE NO PINTA. Los seis <symbol> van en un <svg> escondido al
     principio del body; sin esto ocuparia sitio en el flujo.

     LOS ALTOS NO SON IGUALES Y ESO ES EL PUNTO. Los seis van de 19,8% de
     cobertura (OWASP) a 65,1% (OSEP y OSCP), asi que igualarlos por alto deja
     los huecos -- BTL1 y Burp -- pareciendo pequenos, e igualarlos por AREA de
     tinta infla el BTL1 a 51 contra los 30,5 del OWASP, un 67% mas alto. Lo
     que se aplica es la MEDIA GEOMETRICA de las dos leyes: altos de pantalla
     31,2 a 40,4 y tinta de 389 a 651, sin ninguna de las dos disparada.
     En unidades de lienzo son esos valores entre 0,75, que es la escala a
     1440. Los clones de los overlays escalan su contenido con la misma --fs,
     asi que alli salen del mismo tamano sin tocar nada. */
  .cert-sprite{ position:absolute; width:0; height:0; overflow:hidden; }
  .certs{
    position:absolute; left:80px; width:1760px;
    color:#1d1d1c;
  }
  .certs-tit{
    margin:0 0 48px; font-size:21px; line-height:1.2; font-weight:400;
    letter-spacing:.06em; text-transform:uppercase; color:#1d1d1c;
    text-align:center;
  }
  .certs-fila{
    display:flex; align-items:center; justify-content:center; gap:88px; flex-wrap:wrap;
  }
  /* fill:currentColor y no el negro por defecto: los <path> del sprite no llevan
     fill, asi que heredan el del <svg> que hace el <use>, y sin esta linea ese
     fill es el valor inicial de SVG, #000, aunque .certs ponga color:#1d1d1c. */
  .cert-logo{ display:block; flex:none; width:auto; fill:currentColor; }
  /* Los altos son los de la mezcla C por 2,4. El factor lo fija el ANCHO: los
     seis suman 919 de logo mas 5 calles de 88, o sea 1.359 de los 1.760, y se
     quedan en UNA fila con 401 de aire -- un 23%, que es lo que hace que el
     centrado se note. A 2,8 serian 1.553 (88% del ancho) y la fila tocaria casi
     los margenes; a 3,2, 1.746 y envuelve al primer reflujo. */
  .cert-logo--btl1 { height:130px; }
  .cert-logo--burp { height:113px; }
  .cert-logo--osep { height:103px; }
  .cert-logo--oscp { height:106px; }
  .cert-logo--ceh  { height:108px; }
  .cert-logo--owasp{ height:101px; }
  .cierre{
    position:absolute; left:0; top:0;
    width:1920px; height:1080px;
    font-family:'Figtree',Arial,sans-serif;
    color:#1d1d1c;
  }
  .cierre-headline{
    /* top: --aire-certs desde los logos hasta la TINTA del titular (el cierre
       va pegado a CERTIFICACIONES en la home y en los dos clones). Hoy 138,55;
       fue 189 con 30 de hueco por fuera. */
    position:absolute; left:80px; top:calc((var(--aire-certs) - var(--cierre-tinta)) * 1px); width:1800px;
    /* peso 400, ver .cob-titulo. Medido a 1440x820 en unidades de lienzo: la
       linea 1 pasa de 1608 a 1619,7 (+0,73%) y la 2, con «infraestructura»,
       de 1423,2 a 1439,8 (+1,17%). Siguen siendo DOS lineas -- el salto es el
       <br> del markup, no un reflow -- y el alto del bloque se queda en 268,4,
       asi que no se mueve nada debajo.
       La palabra rotatoria aguanta: su peor caso imaginable, quince «#» (el
       simbolo mas ancho del descifrado) repetidos, termina en 1783,5 de los
       1800 de la caja. Con 300 eran 1780,2: se pierden 3,3 de margen. */
    margin:0; font-size:122px; line-height:1.1; font-weight:400;
    letter-spacing:-.02em; text-indent:150px;
  }
  .cierre-headline .cierre-arrow{
    display:inline-block; margin:0 1.12em 0 -.12em;   /* huecos de tinta IGUALES a ambos lados (medidos) */
  }
  .cierre-headline .cierre-arrow img{
    display:inline-block; height:0.5em; width:auto; vertical-align:middle;
    position:relative; top:-.037em;   /* centro óptico, bajada 4px a 1920 (pedido) */
  }
  /* palabra rotatoria con efecto de descifrado (siempre activo) */
  .cierre-rot{ white-space:nowrap; }
  .cierre-rot .scr{ color:#1d1d1c; }
  .cierre-cta{
    position:absolute; left:80px; bottom:250px; width:900px;
  }
  .cierre-pregunta{
    margin:0; font-size:46px; font-weight:400; letter-spacing:-.01em;
  }
  .cierre-sub{
    margin:14px 0 0; font-size:27px; font-weight:400; color:#3b3b3b;
  }
  .cierre-btn{
    display:inline-block; margin-top:34px;
    background:#3b3b3b; color:#ededed; text-decoration:none;
    font-size:24px; line-height:1; padding:18px 30px;
    transition:background .25s ease;
  }
  .cierre-btn:hover{ background:#1d1d1c; }

  /* ====== FOOTER (fondo gris #3b3b3b) — estructura ref. atoll ====== */
  .footer{
    position:absolute; left:0; top:0;
    width:1920px; height:740px;
    background:#3b3b3b;
    font-family:'Figtree',Arial,sans-serif;
    color:#cfcfcf;
    overflow:hidden;
  }
  /* zona superior: dos columnas divididas por una vertical; la izquierda
     lleva el menú de secciones (con su divisoria bajo el encabezado) y la
     derecha los servicios */
  .footer-top{
    position:absolute; left:0; top:0; width:1920px; height:300px;
    box-sizing:border-box;
    border-top:1.5px solid #ffffff;
    border-bottom:1.5px solid #ffffff;
  }
  .footer-top::before{
    content:""; position:absolute; left:960px; top:0; height:100%;
    border-left:1.5px solid #ffffff;
  }
  .ft-head{
    position:absolute; top:32px; margin:0;
    font-size:22px; font-weight:400; letter-spacing:.01em; color:#f1f1f1;
  }
  .ft-head-izq{ left:34px; }
  .ft-head-der{ left:994px; }
  .ft-hr-izq{
    position:absolute; left:0; top:86px; width:960px;
    border-top:1.5px solid #ffffff;
  }
  .footer-menu{
    position:absolute; left:0; top:86px; width:960px; height:214px;
    display:flex; flex-direction:column;
  }
  .footer-menu a{
    position:relative; z-index:0; flex:1;
    display:flex; align-items:center;
    font-size:19px; font-weight:400; color:#cfcfcf;
    text-decoration:none; white-space:nowrap; line-height:1;
    padding:0 0 0 34px;
    transition:color .4s ease;
  }
  /* bloque BLANCO PURO que sube desde abajo al pasar el cursor (como en las
     preguntas frecuentes), cubriendo la columna entera hasta la divisoria */
  .footer-menu a::before{
    content:""; position:absolute; inset:0; z-index:-1; background:#ffffff;
    transform:scaleY(0); transform-origin:bottom; opacity:0;
    /* al recogerse, la cola lenta de la curva dejaba una línea fina abajo:
       un fundido acompasado la disuelve antes de que se note */
    transition:transform .6s cubic-bezier(.16,1,.3,1), opacity .34s ease;
  }
  .footer-menu a:hover{ color:#1d1d1c; }
  .footer-menu a:hover::before{
    transform:scaleY(1); opacity:1;
    transition:transform .6s cubic-bezier(.16,1,.3,1), opacity .1s ease;
  }
  .footer-servicios{
    position:absolute; left:994px; top:106px;
    display:flex; flex-direction:column;
  }
  .footer-servicios a{
    font-size:19px; font-weight:400; line-height:34px; color:#cfcfcf;
    text-decoration:none; white-space:nowrap;
  }
  .footer-servicios a:hover{ color:#ffffff; }
  /* fila inferior derecha: LinkedIn + marca y año */
  .footer-bottom{
    position:absolute; right:34px; bottom:24px;
    display:flex; align-items:baseline; gap:110px;
  }
  .ft-legal{
    position:absolute; left:994px; bottom:0; height:53.5px;
    display:flex; align-items:center; gap:40px;
  }
  .ft-legal a{ font-size:13px; color:#cfcfcf; letter-spacing:.03em; }
  .ft-legal a:hover{ color:#ffffff; }
  .footer-bottom a, .footer-bottom span{
    font-size:20px; font-weight:400; letter-spacing:.02em;
    color:#f1f1f1; text-decoration:none; white-space:nowrap;
  }
  .footer-bottom a:hover{ color:#ffffff; }
  /* logotipo "intharis" gigante, abajo, sangrando ligeramente por el borde izquierdo */
  .footer-logo{
    position:absolute; left:34px; bottom:24px; width:1252px;
  }
  .footer-logo svg{ width:100%; height:auto; display:block; }
  .footer-logo svg path{ fill:#ffffff; }
  .footer-reg{
    position:absolute; left:1302px; bottom:22px;
    font-size:52px; font-weight:400; line-height:1; color:#ffffff;
  }

  /* ====== OVERLAY DE SERVICIOS ======
     Página propia, se abre desde el enlace "servicios" de la topbar/menú/footer.
     Una sola pantalla (ref. atoll): "servicios" gigante a la izquierda,
     divisoria vertical y frase a la derecha. */
  .serv-overlay{
    position:fixed; inset:0; z-index:200;
    background:#ffffff;
    font-family:'Figtree',Arial,sans-serif;
    color:#1d1d1c;
    opacity:0; visibility:hidden; pointer-events:none;
    transition:opacity .5s ease, visibility .5s ease;
    overflow-y:auto; overflow-x:hidden;
    /* EL HUECO DE LA BARRA, RESERVADO SIEMPRE. Durante la intro abrir() pone
       overflow:hidden en linea y la barra desaparece; al acabar vuelve a
       auto, la barra sale y el contenido perdia de golpe 15 px de ancho
       (Windows): a 1440 bastaba para pasar dos tarjetas del recorrido de
       vigilancia de 2 a 3 lineas. stable reserva el carril tambien con
       hidden, asi que el ancho es el mismo antes y despues. Donde las barras
       son superpuestas (macOS) no reserva nada y no cambia nada. */
    scrollbar-gutter:stable;
  }
  .serv-overlay.abierto{ opacity:1; visibility:visible; pointer-events:auto; }
  .serv-scroll{ position:relative; width:100%; }

  /* topbar (idéntica al resto): en la intro va sobre gris → líneas y logo blancos */
  .sv-topbar{ position:sticky; top:0; left:0; right:0; height:56px; z-index:10; background:#3b3b3b; transition:background .35s ease; }
  .sv-topbar::after{ content:""; position:absolute; left:0; bottom:0; width:100%; height:0; border-bottom:1.5px solid #f1f1f1; }
  .sv-tblogo{ position:absolute; left:0; top:0; height:100%; width:128px; box-sizing:border-box; display:flex; align-items:center; justify-content:center; }
  .sv-tblogo::after{ content:""; position:absolute; right:0; top:0; height:100%; width:0; border-right:1.5px solid #f1f1f1; }
  .sv-tblogo svg{ width:auto; height:21px; display:block; }
  .sv-tblogo svg path{ fill:#f1f1f1; }
  .sv-nav{ position:absolute; left:128px; top:0; height:100%; display:flex; align-items:center; gap:30px; padding-left:28px; font-size:20px; }
  .sv-nav a{ color:#f1f1f1; text-decoration:none; text-transform:lowercase; display:inline-flex; align-items:center; gap:9px; opacity:.62; transition:opacity .2s ease; }
  .sv-nav a:hover, .sv-nav a.activo{ opacity:1; }
  .sv-nav a::before{ content:""; width:9px; height:9px; flex:none; background:currentColor; opacity:.42; clip-path:polygon(0 0, 100% 0, 0 100%); }
  /* cuando la topbar entra en la pantalla blanca → invierte a claro */
  .sv-topbar.claro{ background:#ffffff; }
  .sv-topbar.claro::after{ border-bottom-color:#1d1d1c; }
  .sv-topbar.claro .sv-tblogo::after{ border-right-color:#1d1d1c; }
  .sv-topbar.claro .sv-tblogo svg path{ fill:#1d1d1c; }
  .sv-topbar.claro .sv-nav a{ color:#1d1d1c; }

  /* pantalla única: "servicios" gigante + divisoria vertical + frase */
  .sv2{ position:relative; height:calc(100vh - 56px); min-height:560px; overflow:hidden; }
  /* palabra gigante a la izquierda — texto vivo, como "about".
     El JS (ajustarServicios) fija tamaño y posición para dejar EXACTAMENTE
     34px de margen de tinta con los cuatro bordes de su recuadro
     (topbar arriba, borde izquierdo, divisoria vertical y línea inferior). */
  .sv2-word{
    /* LA RESERVA ES LA MISMA LEY QUE APLICA EL CALIBRADOR, no un valor de
       relleno. ajustarServicios() busca que la TINTA de la palabra encaje
       entre el margen y la divisoria: F = 400·(0,624·W − 68)/1445, donde 1445
       es el ancho de tinta de «servicios» a 400px con Figtree. Eso es lineal en W, o sea
       calc(17.27vw − 18.82px), con el mismo tope de 460 que pone el JS.

       Antes decía min(11.4vw, 219px) = 164px a 1440, y el JS lo subía a 225 en
       un rAF POSTERIOR a que la pantalla ya fuera visible: la palabra salía un
       36% pequeña y pegaba el salto a la vista. Con la ley puesta aquí, la
       primera pintada ya es la buena y al JS no le queda nada que corregir.

       El 1445 está medido con FIGTREE, la que se sirve, así que al JS no le
       queda nada que corregir. Si cambia la familia, vuelve a sobrar un 2%.

       Va en variable porque el `top` usa el mismo cuerpo: escritos por
       separado, cambiar uno y no el otro descoloca la palabra en vertical. */
    --sv2w: min(calc(17.27vw - 18.82px), 460px);
    position:absolute; left:26px; top:calc(34px - var(--sv2w)*0.076); margin:0;
    font-size:var(--sv2w); line-height:.9; font-weight:300;
    color:#1d1d1c; letter-spacing:-.02em; white-space:nowrap;
  }
  .sv2-word .lt{ display:inline-block; overflow:hidden; padding:.14em .06em 0; margin:-.14em -.06em 0; vertical-align:top; }
  /* corrección óptica de pares: abre "r"↔"v" (quedaban más juntas que el resto) */
  .sv2-word .lt:nth-child(3){ margin-right:calc(-.06em + .025em); }
  .sv2-word .lt-in{ display:inline-block; will-change:transform; }
  /* línea divisoria horizontal bajo la palabra: UNA sola pieza que cruza
     toda la página (así jamás puede desalinearse con la lista de la derecha,
     cuyo último ítem ya no dibuja borde propio) */
  .sv2-hline{
    position:absolute; left:0; right:0; top:calc(min(11.4vw, 219px)*0.721 + 104px);
    height:0; border-top:1.5px solid #1d1d1c;
    transform:scaleX(0); transform-origin:left;
  }
  .serv-overlay.sv-line .sv2-hline{
    transform:scaleX(1);
    transition:transform .85s cubic-bezier(.65,0,.35,1) .36s;
  }
  /* divisoria vertical: nace bajo la topbar y muere en el borde inferior */
  .sv2-div{
    position:absolute; left:62.4vw; top:0; bottom:0; width:0;
    border-left:1.5px solid #1d1d1c;
    transform:scaleY(0); transform-origin:top;
  }
  .serv-overlay.sv-line .sv2-div{
    transform:scaleY(1);
    transition:transform .85s cubic-bezier(.65,0,.35,1);
  }
  /* columna derecha: lista de servicios con hairlines */
  .sv2-right{ position:absolute; left:62.4vw; top:0; right:0; bottom:0; overflow:hidden; }
  /* frase bajo la línea divisoria de "servicios" (columna izquierda; el JS
     ajusta su top al de la línea) */
  /* EN UNA LINEA, y en tamano de titular. Iba a clamp(28px, 2.35vw, 45px) y
     peso 400, partida en dos mascaras (dos lineas). Ahora 2.9vw con tope en 56
     -- 41,8 a 1440 y 55,7 a 1920 (el tope no llega a actuar hasta 1931) -- y
     peso 500, el de display del sistema. Estuvo un commit a 3.4vw/64, y se
     bajo: se veia demasiado grande. El mas largo de los cinco,
     «Cuatro servicios de ciberseguridad», deja margen a todos los anchos:
     medido, ver CLAUDE.md. Va en vw y no fijo porque el ancho disponible es
     62.4vw - 68px, y el -68 pesa mas cuanto mas estrecha es la ventana.
     nowrap garantiza la linea unica aunque cambie el copy: si un titulo nuevo
     no cabe, se ve cortado por la divisoria en vez de partirse en silencio. */
  .sv2-frase{
    position:absolute; left:34px; top:calc(min(11.4vw, 219px)*0.721 + 150px);
    width:calc(62.4vw - 68px); margin:0;
    font-size:clamp(28px, 2.9vw, 56px); line-height:1.2; font-weight:500;
    color:#1d1d1c; letter-spacing:-.01em; white-space:nowrap;
  }
  .sv2-lista{ list-style:none; margin:0; padding:0; }
  /* todas las filas miden EXACTAMENTE lo mismo: el calibrador JS reparte la
     altura hasta la hline entre las que haya (tres en los cuatro servicios,
     cuatro en el índice); este calc es solo el valor de arranque */
  /* el cuerpo es el de los titulares de las tarjetas del recorrido de
     vigilancia (.alc .auc-tit): 23,76 a 1440 y 30 a 1920. Fue
     clamp(21px, 1.7vw, 32px), 24,5 y 32. Cada entrada va a UNA linea. */
  .sv2-lista li{
    font-size:clamp(22px, 1.65vw, 30px); line-height:1.15; font-weight:400;
    box-sizing:border-box; height:calc((min(11.4vw, 219px)*0.721 + 104px)/3);
    padding:0 40px 0 34px;
    display:flex; align-items:center;
    position:relative;
  }
  /* las divisorias de la lista se DIBUJAN (izq→der), como todas las líneas
     de la página: nada de aparecer por opacidad */
  .sv2-lista li::after{
    content:""; position:absolute; left:0; right:0; bottom:0; height:0;
    border-top:1.5px solid #1d1d1c;
    transform:scaleX(0); transform-origin:left;
  }
  .serv-overlay.sv-line .sv2-lista li:nth-child(1)::after{
    transform:scaleX(1);
    transition:transform .85s cubic-bezier(.65,0,.35,1) .12s;
  }
  .serv-overlay.sv-line .sv2-lista li:nth-child(2)::after{
    transform:scaleX(1);
    transition:transform .85s cubic-bezier(.65,0,.35,1) .24s;
  }
  /* la tercera solo existe en el índice, que tiene cuatro entradas: en las
     cuatro variantes de servicio esta fila es la última y manda la regla de
     abajo, que la apaga. Sin esta regla la línea se quedaba en scaleX(0). */
  .serv-overlay.sv-line .sv2-lista li:nth-child(3)::after{
    transform:scaleX(1);
    transition:transform .85s cubic-bezier(.65,0,.35,1) .36s;
  }
  .sv2-lista li:last-child::after{ display:none; }
  /* el último ítem NO dibuja borde: su línea inferior es .sv2-hline, la
     divisoria única y recta que cruza toda la página */
  /* {SCROLL} abajo a la derecha, a la altura de la flecha. Ciclo suave:
     entra subiendo desde una máscara de recorte inferior, queda ~3s visible,
     sale por arriba de la máscara (de abajo hacia arriba) y pausa ~1s. */
  .sv2-scroll-tag{
    position:absolute; right:34px; bottom:34px; height:54px;
    display:flex; align-items:center;
    font-size:11px; letter-spacing:.06em; color:#000000;
  }
  .sv2-scroll-tag .st-mask{ display:block; overflow:hidden; padding:2px 0; }
  .sv2-scroll-tag .st-in{
    display:block;
    animation:svScrollCycle 4.4s infinite;
  }
  @keyframes svScrollCycle{
    0%   { transform:translateY(120%);  animation-timing-function:cubic-bezier(.16,1,.3,1); }
    12%  { transform:translateY(0);     animation-timing-function:linear; }
    72%  { transform:translateY(0);     animation-timing-function:cubic-bezier(.55,0,.75,.4); }
    82%  { transform:translateY(-120%); }
    100% { transform:translateY(-120%); }
  }
  /* (SCROLL) bajo el último servicio comprimido: mismo tamaño y mismo ciclo
     que el de la hero. Solo existe con el bloque final comprimido. */
  .svc-scroll2{
    position:absolute; right:0; top:calc(100% + 22px);
    font-size:11px; letter-spacing:.06em; color:#000000;
    display:none; pointer-events:none;
  }
  .svc-scroll2 .st2-mask{ display:block; overflow:hidden; padding:2px 0; }
  .svc-scroll2 .st2-in{ display:block; animation:svScrollCycle 4.4s infinite; }
  .serv-overlay.sv-scroll2 .svc-scroll2{ display:block; }
  /* flecha diagonal abajo-izquierda: LA MISMA que en "sobre nosotros" */
  .sv2-arrow{ position:absolute; left:34px; bottom:34px; width:54px; height:54px; color:#1d1d1c; }
  .sv2-arrow svg{ width:100%; height:100%; display:block; transform:rotate(135deg); }
  /* lienzo bajo la primera pantalla: arranca con la pregunta en grande */
  /* --sv2-pad es el margen lateral de esta pantalla. Se declara como variable
     porque el bloque de metodologia lo anula con margenes negativos para ir a
     sangre, y con el valor escrito dos veces cambiarlo aqui dejaria el bloque
     descuadrado sin que nada avisara.
     4.1667vw ES EL MARGEN DE LA HOME TRADUCIDO, no un numero nuevo. Alli las
     cuatro tarjetas van a left:80 sobre el lienzo de 1920, que con la escala
     son 60 px de pantalla a 1440. Aqui no hay lienzo escalado, asi que la
     traduccion es la proporcion: 80/1920 = 4,1667% del ancho de ventana. Da
     los mismos 60 a 1440 y 80 a 1920.
     Y vw es exacto AQUI y no lo seria en la home: al abrirse el overlay el
     html pasa a overflow:hidden y desaparece la barra de scroll, asi que vw
     vale el ancho visible. En la home el margen derecho VISIBLE es 45 y no 60
     por culpa de la barra; esa asimetria esta documentada en CLAUDE.md y NO se
     copia -- seria igualar a un defecto.
     Sube de 34 a 60 en las CINCO variantes a proposito: es una sola pantalla y
     las otras cuatro estan sin redactar. Metodologia no se entera, porque va a
     sangre con margenes negativos sobre esta misma variable. */
  /* Sin padding abajo, igual que .svc-lista2 y que .sv-footwrap sin margin-top:
     el aire hasta CERTIFICACIONES lo pone UNO solo, el padding-top de .nf-certs
     (var(--aire-certs)). Antes se apilaban cuatro (60 + 4.1667vw + 40 px de
     pantalla + 120) y el hueco salia de 240 a 333 unidades segun la variante y
     el ancho, contra los 120 de la home.
     Y SIN min-height: tenia 100vh, y en las variantes cortas (vigilancia y
     continuidad a 1920) estiraba la caja por debajo del contenido y metia 61
     unidades de blanco de mas antes de CERTIFICACIONES. Lo tapaban los
     rellenos que se fueron. */
  .sv2-more{ --sv2-pad:4.1667vw; position:relative; overflow:hidden; background:#ffffff; padding:96px var(--sv2-pad) 0; box-sizing:border-box; }
  /* polvo de puntos (motor de la home) recortado a esta zona */
  .sv-polvo{
    position:fixed; inset:0; width:100%; height:100%; pointer-events:none;
    image-rendering:pixelated; mix-blend-mode:multiply; z-index:2;
    opacity:0; transition:opacity .4s ease;
  }
  .serv-overlay.abierto .sv-polvo{ opacity:.26; }
  /* pie replicado (cierre + footer de la home) al final de servicios, a
     escala real 1920 → ancho de viewport; el alto en flujo lo fija el JS */
  .sv-footwrap{ position:relative; width:100%; overflow:hidden; margin-top:0; }
  .sv-footwrap .svf-in{ width:1920px; transform-origin:top left; transform:scale(var(--fs, .75)); }
  .sv-footwrap .nf-cierre{ position:relative; width:1920px; height:1080px; overflow:hidden; background:#ffffff; }
  .sv-footwrap .nf-footer{ position:relative; width:1920px; height:740px; }
  /* La seccion de certificaciones en los DOS clones. Va en flujo encima del
     cierre, dentro del mismo envoltorio de 1920 que ya escala con --fs, asi
     que sale del mismo tamano que en la home sin tocar ni un numero. El
     padding repone el left:80 que la seccion tiene en el lienzo y que deja de
     aplicarse al pasar a position:static. */
  .sv-footwrap .nf-certs,
  .no-footwrap .nf-certs{
    position:relative; width:1920px; box-sizing:border-box;
    padding:calc((var(--aire-certs) - var(--certs-tit-tinta, 0)) * 1px) 80px 0; background:#ffffff;
  }
  .sv-footwrap .nf-certs .certs,
  .no-footwrap .nf-certs .certs{ width:100%; }
  .sv2-pregunta{
    margin:0; max-width:1400px;
    font-size:clamp(64px, 5.6vw, 108px); line-height:1.08; font-weight:400;
    color:#1d1d1c; letter-spacing:-.02em;
  }
  /* frase final: fuera del flujo, anclada sobre la zona de los bloques.
     Terminada la compresión, sube CON EL SCROLL hasta la altura media del
     conjunto comprimido. Pequeña: convive con los títulos sin chocar. */
  .sv2-final{
    position:absolute; left:34px; top:0; margin:0; max-width:46vw;
    font-size:clamp(52px, 4.5vw, 86px); line-height:1.1; font-weight:400;
    color:#1d1d1c; letter-spacing:-.02em;
    visibility:hidden;             /* invisible SIEMPRE hasta que el scroll la saca */
    transform:translateY(140vh);
    /* Y fuera del todo: lo unico que la revelaba era animarFrase(), dentro de
       la compresion de auditorias, que se retiro. Con visibility:hidden seguia
       teniendo caja, y al quitarle a .sv2-more su padding inferior esa caja
       --top:0 + 140vh, 2624-2814 a 1440-- cruzaba el titulo de
       CERTIFICACIONES en el indice. No se veia (recortada por el overflow de
       .sv2-more), pero display:none quita la caja y con ella cualquier solape.
       El markup y el copy se quedan por si se recupera. */
    display:none;
  }
  .sv2-final .fin-rv{ display:block; }
  .sv2-final .fin-rv-in{ display:block; }
  /* ====== LOS 3 SERVICIOS (bajo la pregunta) ======
     Cada bloque SALE DE ABAJO A ARRIBA al entrar en pantalla: título y
     cuerpo suben desde una máscara de recorte, escalonados; su hairline
     se dibuja de izquierda a derecha. */
  .svc-lista2{ margin-top:140px; display:flex; flex-direction:column; gap:40px; padding-bottom:0; }
  /* ====== AUDITORIA COMPLETA: TRES TARJETAS (solo variante auditorias) ======
     Sustituye al bloque de los tres servicios y a su compresion secuencial.
     Nada de esto es vocabulario nuevo: la caja es la de .cs-campo, el titulo de
     una palabra es .cs-c-nombre, el cuerpo de los puntos es .svc-cuerpo y la
     banda de cierre repite la figura que la home ya tiene -- tarjeta a todo el
     ancho junto a una fila de tres --, invertida: alli va encima, aqui debajo.

     CALLE DE 30, la de .cs-campos. Cuando las columnas dejaron de ser texto y
     pasaron a ser CAJAS, el precedente correcto dejo de ser .svc-grid (60, que
     es calle entre columnas de texto) y paso a ser el de la fila de tarjetas de
     la home. Y de paso recupera medida: la caja se come 80 px por columna entre
     sus dos paddings, asi que la linea llena cae de 54 caracteres a 45 con
     calle 30 -- serian 42 con la de 60. Los 45 son el precio de poner caja, y
     se aceptan a sabiendas: la referencia baja de la web es .cs-c-desc con 53.

     align-items:start a proposito: la del medio lleva CUATRO puntos y las otras
     tres. Que sea mas alta es honesto; cuadrarlas seria mentir. */
  .auc{
    margin-top:96px;
    display:grid; grid-template-columns:repeat(3, 1fr); gap:30px;
    align-items:start;
  }
  /* LA CAJA, igual que .cs-campo: fondo blanco, padding 40, esquina viva, sin
     sombra ni radio, y el contorno en un ::after que SE DIBUJA de arriba abajo
     con clip-path. Al revelarse solo, el filete de cabecera que tenian las
     columnas sobra y se ha ido.
     box-shadow y no border, como en la home: conserva el decimal del grosor. Y
     --linew-fijo y no --linew porque el overlay vive FUERA del lienzo escalado
     -- es la misma razon por la que metodologia usa esa variable en sus dos
     border. */
  .auc-col{
    position:relative; box-sizing:border-box;
    padding:2.0833vw; background:#ffffff;
  }
  .auc-col::after{
    content:""; position:absolute; inset:0;
    box-shadow:inset 0 0 0 var(--linew-fijo, 1.5px) #1d1d1c;
    clip-path:inset(0 0 100% 0);
    transition:clip-path .85s cubic-bezier(.65,0,.35,1);
    pointer-events:none;
  }
  .auc-col.visible::after{ clip-path:inset(0 0 0 0); }
  /* Por COLUMNA y no por posicion (3n+2, 3n+3): con las tres tarjetas de
     auditorias selecciona lo mismo que nth-child(2) y (3), y en la rejilla
     de 3x2 de vigilancia la segunda fila repite la cascada de la primera. */
  .auc-col:nth-child(3n+2).visible::after{ transition-delay:.12s; }
  .auc-col:nth-child(3n+3).visible::after{ transition-delay:.24s; }
  /* El titulo de una palabra es .cs-c-nombre exacto: 32, caja baja, 500,
     -.02em. Y CAJA BAJA Y NO VERSALITAS a proposito: las versalitas con
     tracking son el idioma de las ETIQUETAS de esta web (.svm-eyebrow,
     .cs-tipos). Un titulo de tarjeta es otra cosa. A 14 en
     versalitas "Cloud" media 40,8 px y se quedaba en etiqueta perdida dentro de
     una caja de 437. */
  .auc-tit{
    margin:0 0 26px;
    font-size:32px; line-height:1.15; font-weight:500; letter-spacing:-.02em; color:#1d1d1c;
  }
  /* EL ICONO DE CADA PUNTO. Va DENTRO del .rv-in, asi que el punto entero
     -- icono y texto -- sube como una sola pieza con la mascara de revelado,
     igual que hacia .cob-ico en COBERTURA.
     .auc .auc-p .rv-in y no .auc-p .rv-in: mas abajo la mascara declara
     .auc .rv-in{display:block}, que empata en especificidad y va despues. Ya
     mordio una vez con los iconos de los titulos.

     CAJA FIJA Y NO ANCHO LIBRE. Los nueve tienen proporciones muy distintas
     -- de 0,655 la puerta a 1,183 el wifi y la camara --, asi que con el ancho
     al aire los textos arrancarian en nueve x distintas. La caja es de
     1.65em x 1.3em y el SVG encaja dentro con su preserveAspectRatio: como la
     proporcion de la caja (1,269) es mayor que la del icono mas apaisado
     (1,183), manda SIEMPRE la altura y los nueve salen con 1.3em de tinta.
     margin-top centra el icono en la primera linea: (1.55em - 1.3em) / 2. */
  .auc .auc-p .rv-in{ display:flex; align-items:flex-start; gap:.82em; }
  .auc-ico{ flex:none; width:1.65em; height:1.3em; margin-top:.125em; }
  .auc-tx{ flex:1 1 auto; min-width:0; }
  .auc-lista{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:22px; }
  .auc-p{
    margin:0; font-size:clamp(17px, 1.15vw, 21px); line-height:1.55; font-weight:400;
    color:#1d1d1c; text-wrap:pretty;
  }
  /* LA ENTRADILLA A 600, y esto AFINA el sistema de pesos en vez de romperlo.
     Medido el grosor de asta rasterizando: a 120px va 10 (400) / 12 (500) / 14
     (600) / 17 (700), o sea +20%, +40% y +70% sobre el 400. Pero a los 17px
     REALES de estos puntos ese +20% del 500 son 0,28 px de asta -- menos de un
     tercio de pixel, que el antialiasing se come casi entero: +6,4% de tinta.
     El 600 da 0,56 px, el doble de salto, y +22,5% de tinta.
     La regla, por tanto, no es "500 destaca" a secas: 500 destaca EN DISPLAY,
     donde el cuerpo es de 43 a 100 px y ese +20% si se ve. En cuerpo pequeno
     hace falta 600. El 700 sigue reservado al <strong>. */
  .auc-f{ font-weight:600; }
  /* EL TITULAR DE ESTA VARIANTE VA MAS GRANDE, y con el mismo aire arriba y
     abajo. 115,2 px a 1440 contra los 80,6 del resto. Lo situa la escala del
     propio overlay: .sv2-word (la portada) 225,6 > ESTE 115,2 > .fg-title
     100,8 > .svm-big 54 > .auc-tit 32. Segundo, a la mitad justa de la
     portada, que es lo que mantiene la jerarquia entre las dos pantallas.
     Cabe de sobra en una linea: a 1920 pide 1.170 de los 1.760 de contenido.
     Ya no necesita anular el tope de medida. Aquel max-width existia porque
     "Una imagen fiel de tu seguridad" se partia desde ~1850px de ventana;
     "¿Que ofrecemos?" no se acerca al tope de 1400.

     LOS DOS MARGENES SON DE TINTA, 96 px, NO DE CAJA. Antes eran 110 arriba y
     137 abajo. Medido en Figtree: el ascendente de la fuente es 0,9549 em y la
     tinta de este titular llega a 0,7192, asi que la caja tiene aire muerto
     arriba; por abajo, en cambio, la tinta SE SALE de la caja 0,0366 em,
     porque el interrogante de apertura y la cola de la Q bajan mas de lo que
     da el line-height de 1,08. Los dos numeros salen de medir los glifos vivos:
       -.167em  arriba  = lo que sobra de caja por encima de la tinta
        .024em  abajo   = lo que la tinta desborda la caja
     Van en em para que aguanten a cualquier ancho, porque el cuerpo es vw.
     La referencia de arriba es la divisoria .sv2-close, que cae exactamente en
     el borde de .sv2-more -- comprobado, 900 y 900 a 1440x900.
     El margen de arriba se pone con margen NEGATIVO y no tocando el
     padding-top:96 de .sv2-more, que es comun a las cinco variantes. Es el
     mismo recurso que usa .fh en la variante de formacion.

     Y EL DE ABAJO VA EN PADDING, NO EN MARGIN, que es la trampa que mordio
     aqui. El titular y .auc son hermanos, asi que un margin-bottom suyo
     COLAPSA con el margin-top:96 de .auc y se queda en el mayor de los dos en
     vez de sumarse: la correccion de la tinta desaparecia y el hueco de abajo
     salia 93,2 contra los 95,2 de arriba. El padding no colapsa. Es el mismo
     recurso que .fg-title ya usa con su padding-bottom:.06em. */
  .sv-var[data-var="auditorias"] .sv2-pregunta{
    font-size:clamp(84px, 8vw, 154px);
    margin:-.167em 0 0;
    padding-bottom:.024em;
  }
  /* VIGILANCIA 24/7: ALCANCE DEL SERVICIO. Titular grande y entradilla, y
     debajo un RECORRIDO de seis pasos (.alc) alternos a los dos lados de un
     modulo central tipo chip, con un ramal recto de cada tarjeta a un pin.
     El titular va al cuerpo del de auditorias. Su margen de arriba es de
     TINTA, como alli, y vale el mismo numero porque los astas de la l y la d
     de "Alcance" suben casi lo que la tilde de "¿Que": 95,92 a 1440 y 97,06
     a 1920, medido rasterizando. Sin padding-bottom: no baja nada.
     La entradilla es .fh-lead (cuerpo, interlineado y medida de 1080), y
     cuelga del titular con los 52 que separan .fg-title de sus columnas,
     que es el otro titular grande del overlay seguido de texto. */
  /* CONTINUIDAD lleva el mismo titular, «Alcance del servicio», con la misma
     entradilla debajo: mismo cuerpo y mismo margen de tinta. */
  .sv-var[data-var="vigilancia-24-7"] .sv2-pregunta,
  .sv-var[data-var="continuidad"] .sv2-pregunta{
    font-size:clamp(84px, 8vw, 154px);
    margin:-.167em 0 0;
  }
  .sv2-entradilla{ margin:52px 0 0; max-width:1080px; }
  /* EL RECORRIDO. Todo en unidades del lienzo de 1920 traducidas a vw, la
     misma ley que --sv2-pad: el overlay es fluido, no esta en el lienzo.
       --alc-chip   el ANCHO DEL MODULO central: 56 unidades.
       --alc-ramal  de la tarjeta al borde del modulo, PIN INCLUIDO: 140.
                    Es la variable que se toca para abrir o cerrar el
                    recorrido.
       --alc-pad    el padding de la tarjeta compacta: 24 en vez de 40.
       --alc-hueco  la calle entre filas: 48.
     LAS TARJETAS LLEGAN A LOS MARGENES y su ancho NO se escribe: son las dos
     columnas 1fr que deja una calle de modulo + dos ramales. Hoy
     (1760 - 56 - 280) / 2 = 712 unidades: 534 px a 1440, 712 a 1920. El
     modulo cae en el centro de la calle, que es el del bloque, x = 960.
     EL ESCALONADO SALE DE LA REJILLA, sin un solo top: cada paso ocupa DOS
     filas de su columna empezando en la suya (1 filas 1-2 a la izquierda,
     2 filas 2-3 a la derecha...), y el orden del DOM es el de lectura.
     FILAS IGUALES (1fr): asi los titulares, y con ellos los ramales, caen a
     un paso CONSTANTE, que es lo que deja que los pines del modulo sean
     regulares y cada ramal llegue recto a uno. El precio es que una tarjeta
     mas corta que la mas alta deja algo mas de calle hasta la siguiente de
     su lado. align-self:start: el paso mide lo que su tarjeta. */
  .alc-wrap{
    --alc-chip:calc(56 / 1920 * 100vw);
    --alc-ramal:calc(140 / 1920 * 100vw);
    --alc-pad:calc(24 / 1920 * 100vw);
    --alc-hueco:calc(48 / 1920 * 100vw);
    /* los pines libres: cuanto dura un estiron (ida y vuelta), cuanto se
       alarga (fraccion del largo del pin) y cuantos segundos espera antes de
       cada uno. Los lee app.js para sortear; la duracion la usa la hoja. */
    --alc-pin-dur:1.6s;
    --alc-pin-amp-min:.8;
    --alc-pin-amp-max:1.5;
    --alc-pin-espera-min:1;
    --alc-pin-espera-max:4;
    /* LA CARGA DE CADA TARJETA VA LIGADA AL SCROLL (app.js, "la carga de las
       tarjetas"). El tramo es la posicion del borde superior de la tarjeta en
       la pantalla, en fraccion de su alto: empieza a cargarse cuando asoma por
       el 95 % (progreso 0) y esta entera al llegar al 65 % (progreso 1).
       EL TEXTO VA CON EL DESPLIEGUE VISIBLE, el progreso YA CURVADO (el de la
       mascara), no con el lineal: con easeOutCubic la tarjeta se ve entera
       mucho antes de que el lineal llegue a 1. Aparece cuando el despliegue
       llega a --alc-texto-aparece y solo se oculta si baja de
       --alc-texto-oculta: el margen evita que parpadee en el limite. Sin
       unidad: las lee el JS con parseFloat. */
    --alc-carga-inicio:.95;
    --alc-carga-fin:.65;
    /* el tramo va en DOS FASES: primero el ramal crece hasta la tarjeta (esta
       fraccion del tramo) y, cuando conecta, la tarjeta se despliega (el
       resto). Los umbrales del texto miden el despliegue de la tarjeta, no el
       tramo entero. */
    --alc-fase-hilo:.4;
    --alc-texto-aparece:.65;
    --alc-texto-oculta:.5;
    /* el ancho del FUNDIDO del frente que avanza al desplegarse la tarjeta:
       80 unidades de 1920 */
    --alc-fundido:calc(80 / 1920 * 100vw);
    position:relative; margin-top:96px;
  }
  .alc{
    list-style:none; margin:0; padding:0;
    display:grid; grid-template-columns:1fr 1fr; grid-auto-rows:1fr;
    column-gap:calc(var(--alc-chip) + 2 * var(--alc-ramal)); row-gap:var(--alc-hueco);
  }
  .alc-paso{ position:relative; align-self:start; }
  .alc-paso:nth-child(odd){ grid-column:1; }
  .alc-paso:nth-child(even){ grid-column:2; }
  .alc-paso:nth-child(1){ grid-row:1 / span 2; }
  .alc-paso:nth-child(2){ grid-row:2 / span 2; }
  .alc-paso:nth-child(3){ grid-row:3 / span 2; }
  .alc-paso:nth-child(4){ grid-row:4 / span 2; }
  .alc-paso:nth-child(5){ grid-row:5 / span 2; }
  .alc-paso:nth-child(6){ grid-row:6 / span 2; }
  /* La tarjeta es .auc-col tal cual -- caja, contorno que se dibuja y
     revelado --, solo mas compacta: padding de 24 y 16 bajo el titular.
     EL TEXTO, MAS PEQUENO QUE EL DE LAS TARJETAS DE AUDITORIAS (17-21):
     clamp(14px, 0.92vw, 17.5px), 14 a 1440 y 17,5 a 1920. Fue antes el
     .cs-c-desc de la home traducido (15 / 20) y se bajo a peticion. */
  /* POR ENCIMA DEL POLVO, como .svm. El del overlay (.sv-polvo) es un canvas
     fijo a z-index:2 dentro de la pantalla, con mix-blend-mode:multiply, y se
     recorta con UN solo inset vertical, desde .sv2-more hasta el cierre
     clonado: no tiene forma de dejar huecos por elemento, como el de la home.
     Asi que todo lo que va en flujo dentro de .sv2-more queda DEBAJO y los
     puntos se ven encima de las tarjetas. Subirlas a 3 las pone delante sin
     tocar el motor; las calles entre tarjetas siguen enseñando el polvo,
     porque ahi no hay nada que lo tape. La barra de la pantalla va a 10. */
  .alc .auc-col{ padding:var(--alc-pad); z-index:3; }
  /* LA CARGA CON EL SCROLL. El contorno de estas tarjetas no se dibuja solo
     (el de .auc-col va de arriba abajo al entrar): esta siempre puesto, y la
     tarjeta entera -- fondo, contorno y texto -- se DESPLIEGA con una
     mask-image que escribe app.js en cada frame del scroll del overlay, desde
     el lado del ramal hacia el margen: un degradado lineal cuyo frente lleva
     un FUNDIDO de --alc-fundido en vez de un corte. Entera, la mascara es
     none: opaca del todo, sin resto de fundido en el borde. Mientras no esta
     entera, la parte sin cargar enseña el polvo y la cargada lo tapa
     (z-index:3). Solo repinta: mask-image no toca la maqueta.
     Todos los estados ocultos cuelgan de .alc-scroll, que pone el JS en
     .alc-wrap: SIN JS las tarjetas se ven enteras, con su texto. El estado
     de partida, antes del primer calculo, es la tarjeta sin cargar.
     Fue un clip-path de corte duro durante dos commits. */
  .alc .auc-col::after{ clip-path:none; transition:none; }
  .alc-scroll .alc .auc-col{
    -webkit-mask-image:linear-gradient(transparent, transparent);
            mask-image:linear-gradient(transparent, transparent);
  }
  /* el ramal crece del pin a la tarjeta con su stroke-dashoffset (pathLength
     1), con el mismo progreso que la tarjeta. A 0 va a opacidad 0: el extremo
     square dejaria un punto en el pin. */
  .alc-scroll .alc-traza .alc-ramal{ stroke-dasharray:1 1; stroke-dashoffset:1; opacity:0; }
  /* EL TITULAR, un escalon por debajo del .auc-tit de 32 y con su mismo peso
     (500). Da 23,76 a 1440 y 30 a 1920. La lista del hero de servicios
     (.sv2-lista li) usa hoy este mismo cuerpo, a 400. */
  .alc .auc-tit{ margin-bottom:16px; font-size:clamp(22px, 1.65vw, 30px); }
  .alc .auc-txt{ font-size:clamp(14px, 0.92vw, 17.5px); }
  /* EL MODULO. Esta caja no pinta nada: solo da el ANCHO (--alc-chip, que el
     JS mide de aqui). El rectangulo y los pines los dibuja app.js en el
     <svg>, y es tambien el JS el que pone top y height para que la caja
     cubra el modulo; los de aqui son de reserva. Llevaba una etiqueta,
     "SOC 24/7" en vertical, y se quito: la entradilla ya lo dice. */
  .alc-chip{
    position:absolute; left:50%; top:0; height:100%; width:var(--alc-chip);
    transform:translateX(-50%); pointer-events:none;
  }
  /* EL TRAZO. Un <svg> sobre el recorrido, del tamano del bloque, que llena
     app.js: el contorno del modulo en dos mitades, un <path> por pin y uno
     por ramal. Grosor --linew-fijo y no --linew: el overlay vive fuera del
     lienzo escalado (ver metodologia). Color de los filetes, sin relleno y
     con esquinas vivas. */
  .alc-traza{
    position:absolute; left:0; top:0; width:100%; height:100%;
    overflow:visible; pointer-events:none;
    z-index:3;   /* delante del polvo, como las tarjetas: ver .alc .auc-col */
  }
  /* el interior del modulo, opaco y del color del fondo: tapa el polvo */
  .alc-traza .alc-chip-fondo{ fill:#ffffff; stroke:none; }
  /* LOS PINES LIBRES -- los que no llevan tarjeta -- se estiran de vez en
     cuando. Solo transform: scaleX desde la BASE del pin, que es el borde del
     modulo (la derecha en los de la izquierda y al reves). transform-box
     fill-box para que el origen sea el del propio trazo. Una vuelta por
     animacion: la espera es el animation-delay que sortea app.js en cada
     vuelta (--pin-espera), y la amplitud tambien (--pin-amp). Los pines con
     tarjeta y los ramales no se mueven. */
  /* stroke-linecap:BUTT y no square, y es lo que impide que el pin se meta en
     el modulo. Su base esta en el centro del trazo del contorno, y el
     extremo square sobresale medio grosor por detras de ella; con scaleX ese
     medio grosor ESCALA con el pin: a 2,5 se metia 0,75 px por dentro del
     contorno. Con butt el pin acaba exactamente en su base, crezca lo que
     crezca. Para que en reposo midan lo mismo que los pines con tarjeta, que
     siguen en square, el JS los alarga medio grosor por fuera. */
  .alc-traza .alc-pin-libre{
    transform-box:fill-box; stroke-linecap:butt;
    animation:alc-pin var(--alc-pin-dur, 1.6s) ease-in-out var(--pin-espera, 2s) 1 both;
  }
  .alc-traza .alc-pin-libre[data-lado="izq"]{ transform-origin:right center; }
  .alc-traza .alc-pin-libre[data-lado="der"]{ transform-origin:left center; }
  .alc-wrap.alc-quieto .alc-pin-libre{ animation-play-state:paused; }
  @keyframes alc-pin{
    0%, 100%{ transform:scaleX(1); }
    50%{ transform:scaleX(calc(1 + var(--pin-amp, .5))); }
  }
  /* LA UNICA ANIMACION DE LA WEB QUE RESPETA prefers-reduced-motion, y es a
     proposito: se pidio asi para esta. El resto sigue la decision del
     proyecto de no desactivarse (ver CLAUDE.md). */
  @media (prefers-reduced-motion: reduce){
    .alc-traza .alc-pin-libre{ animation:none; }
  }
  /* ====== VIGILANCIA: PACKS DE PROTECCION ======
     Despues del recorrido de "Alcance del servicio". Nada nuevo: titular y
     entradilla son los de esa seccion (.sv2-pregunta y .sv2-entradilla, con
     la misma regla de la variante), los cuerpos son los de sus tarjetas, los
     filetes van con --linew-fijo, la capa de la columna es la de las tarjetas
     y la flecha de "Solicitar propuesta" es .cs-flecha.
     EL AIRE CON EL RECORRIDO ES --aire-certs (160 unidades): el mismo que separa
     cualquier bloque del siguiente en esta pantalla, de la tarjeta mas baja a
     la TINTA del titular. Va en el margin-top de la seccion; el titular resta
     su caja muerta con el -.167em de siempre. display:flow-root para que ese
     margen negativo del titular NO colapse con el de la seccion: si colapsara
     se juntaria con el margin-bottom negativo que app.js pone a .alc-wrap y
     solo sobreviviria el mas negativo de los dos. */
  /* LA BANDA GRIS CLARA: #f1f1f1, el fondo claro de la web (la barra clara,
     contacto, los legales, el movil), con el titular y la entradilla en
     tinta. A sangre con margenes negativos sobre --sv2-pad, como la de
     metodologia. Es una zona CLARA, asi que no lleva nada de lo que piden las
     oscuras: el aura no la veta y la barra de la pantalla sigue blanca al
     pasar (ni elemsGris ni tenirBarra la miran). El polvo, en cambio, sigue
     sin pasar por encima, que es el criterio de la banda de COBERTURA de la
     home: va a z-index:3, delante del 2 de .sv-polvo.
     Estuvo dos commits en el #3b3b3b de metodologia, con texto blanco, aura
     vetada y barra gris.
     EL ESPACIADO INTERIOR ES --aire-certs ARRIBA Y ABAJO, el mismo aire que
     separa un bloque del siguiente en esta pantalla: del borde superior de la
     banda a la tinta del titular, y del borde inferior del recuadro blanco
     de la tabla al de la banda, 160 unidades. A los lados, --sv2-pad: el contenido sigue en la
     columna de la pagina y el borde derecho de la tabla, en el margen.
     Los dos aires de FUERA salen solos: el margin-top de la seccion pone 160
     de la tarjeta mas baja del recorrido al borde superior del gris, y el
     borde inferior del gris es el de .sv2-more, de donde cuelga .nf-certs. */
  .pk{
    display:flow-root;
    margin:calc(var(--aire-certs) / 1920 * 100vw) calc(-1 * var(--sv2-pad)) 0;
    padding:calc(var(--aire-certs) / 1920 * 100vw) var(--sv2-pad);
    background:#f1f1f1; color:#1d1d1c;
    position:relative; z-index:3;
  }
  .pk .sv2-pregunta, .pk .sv2-entradilla{ color:inherit; }
  /* EL RECUADRO BLANCO, sobre la banda gris clara, con un BORDE FINO
     (--linew-fijo) en #8a8a89, el gris medio de la web para lo secundario, y
     esquinas vivas. El texto va en tinta (#1d1d1c); las lineas de dentro, en
     gris claro (ver abajo). Su espaciado es el de las tarjetas, el
     padding de .auc-col (2.0833vw, los 40 de .cs-campo traducidos): el texto
     queda a 40 unidades de cada borde. Los filetes, en cambio, van de borde a
     borde del recuadro, asi que ese padding lo ponen las celdas: el recuadro
     solo lleva arriba y abajo lo que falta hasta 40 sobre el --pk-pad de la
     celda, y la primera y la ultima columna llevan los 40 por fuera. Sin
     filete de cierre: el borde del recuadro cierra la tabla. */
  .pk-caja{
    --pk-pad:calc(24 / 1920 * 100vw);
    --pk-caja-pad:2.0833vw;
    margin-top:96px;
    padding:calc(var(--pk-caja-pad) - var(--pk-pad)) 0;
    background:#ffffff; color:#1d1d1c;
    border:var(--linew-fijo, 1px) solid #8a8a89;
  }
  /* LA TABLA. La columna de etiquetas al 40% y las tres de packs a partes
     iguales. Celdas a z-index:0 con la capa a -1, como .cs-campo.
     AL PASAR EL CURSOR POR UN PACK, SU COLUMNA SE TINE: verde lo incluido
     (.pk-incl, tambien los "Mensual" de la revision) y rojo lo que no (.pk-excl).
     Es la capa de las tarjetas (sube desde abajo, .32s), con otro color. Los
     dos tonos son casi blancos y DERIVADOS, no escritos: el 6% del rojo de la
     web (--red-core) y del verde que ya usa el formulario de contacto al
     enviarse (#1e7d3c), sobre blanco. El texto sigue en tinta y contrasta
     igual. Sin color-mix() no hay tinte, y la tabla se lee igual. */
  .pk-tabla{
    --pk-tinte-si:color-mix(in srgb, #1e7d3c 6%, #ffffff);
    --pk-tinte-no:color-mix(in srgb, var(--red-core) 6%, #ffffff);
    width:100%;
    border-collapse:separate; border-spacing:0; table-layout:fixed;
  }
  .pk-tabla th, .pk-tabla td{
    position:relative; z-index:0;
    padding:var(--pk-pad); text-align:left; vertical-align:middle;
    font-size:clamp(14px, 0.92vw, 17.5px); line-height:1.55; font-weight:400; color:inherit;
  }
  .pk-tabla tr > :first-child{ padding-left:var(--pk-caja-pad); }
  .pk-tabla tr > :last-child{ padding-right:var(--pk-caja-pad); }
  /* LAS COLUMNAS DE PACK VAN CENTRADAS (cabecera, celdas y enlace) y las
     etiquetas de fila a la izquierda. Entre columnas, un separador vertical
     fino con --linew-fijo y el gris claro de las lineas de dentro; las filas
     de grupo son una sola celda a lo ancho y no lo llevan. */
  .pk-tabla tr > :nth-child(n+2){
    text-align:center;
    border-left:var(--linew-fijo, 1px) solid #e2e2e2;
  }
  /* la ultima lleva los 40 del recuadro a la derecha: los mismos a la
     izquierda, o lo centrado se iria 8 unidades del centro de su columna */
  .pk-tabla tr > :nth-child(n+2):last-child{ padding-left:var(--pk-caja-pad); }
  /* ALTO DE FILA UNIFORME: el de cuerpo y el de grupo, el doble del padding de
     las tarjetas (80 unidades), con el texto centrado en vertical. Es un alto
     minimo de tabla, asi que una etiqueta que partiera linea creceria. */
  .pk-tabla tbody th, .pk-tabla tbody td{
    height:calc(2 * var(--pk-caja-pad)); padding-top:0; padding-bottom:0;
  }
  .pk-tabla .pk-incl{ --hl-capa:var(--pk-tinte-si); }
  .pk-tabla .pk-excl{ --hl-capa:var(--pk-tinte-no); }
  .pk-tabla .pk-incl::before, .pk-tabla .pk-excl::before{ z-index:-1; }
  /* la flecha de "Solicitar propuesta" sigue al color de la celda */
  .pk .cs-flecha{ color:inherit; }
  .pk-esquina{ width:40%; }
  .pk-tabla thead th{ vertical-align:top; }
  /* LAS LINEAS DE DENTRO (filetes entre filas y separadores) van en GRIS
     CLARO, #e2e2e2 (el de .legal-fill), y no en tinta: la jerarquia la marcan
     la cabecera y las filas de grupo, no las lineas. Es la excepcion a la
     convencion de filetes en #1d1d1c, a proposito. El ultimo filete es el
     borde del recuadro. */
  .pk-tabla tbody th, .pk-tabla tbody td,
  .pk-tabla tfoot td{ border-top:var(--linew-fijo, 1px) solid #e2e2e2; }
  /* LAS FILAS VAN AGRUPADAS: un <tbody> por grupo, abierto por una fila de
     cabecera (th scope="rowgroup" a lo ancho) con el gris claro de la capa de
     las tarjetas y la etiqueta en 600, el peso que destaca en cuerpo pequeno
     (el de .auc-f). */
  .pk-tabla .pk-grupo th{ background:#f4f4f4; font-weight:600; }
  /* CABECERA DE CADA PACK: el nombre destaca, con el titular de las tarjetas
     del recorrido (22-30, 500); debajo el beneficio, con el texto de la tabla
     y el gris de texto secundario de la web (#6b6b6a, el del indice legal):
     el cuerpo mas pequeno del sistema en el overlay es ese, asi que la
     diferencia de tamano es la del nombre al texto. */
  .pk-nombre{
    display:block;
    font-size:clamp(22px, 1.65vw, 30px); line-height:1.15; font-weight:500; letter-spacing:-.02em;
  }
  .pk-benef{ display:block; margin-top:12px; color:#6b6b6a; }
  /* LAS MARCAS, centradas en su celda.
     Incluido: una VERIFICACION de trazo fino, --linew-fijo, con esquina viva
     (miter, extremos square, como el trazo de .alc-traza). Mide el alto de
     mayusculas (.705em, la ley de .cob-ico) y 1,4 veces eso de ancho, la
     proporcion de su viewBox; el trazo no escala con el (non-scaling-stroke).
     No incluido: un GUION gris (#8a8a89, el gris de la web para lo
     secundario), del ancho del alto de mayusculas y del mismo grosor. */
  .pk-marca{
    display:block; margin:0 auto;
    width:calc(.705em * 1.4); height:.705em; overflow:visible;
    fill:none; stroke:currentColor;
  }
  .pk-marca path{
    stroke-width:var(--linew-fijo, 1px); vector-effect:non-scaling-stroke;
    stroke-linecap:square; stroke-linejoin:miter;
  }
  .pk-guion{
    display:block; margin:0 auto;
    width:.705em; height:var(--linew-fijo, 1px); background:#8a8a89;
  }
  /* SE DIBUJAN AL ENTRAR, columna a columna con el escalonado de las tarjetas
     (.12s), de izquierda a derecha con un clip-path, como los contornos que se
     dibujan en la web. Lo dispara el observador de revelado del overlay, que
     mira la tabla: el recorte va en las marcas, nunca en lo observado. */
  .pk-marca, .pk-guion{
    clip-path:inset(0 100% 0 0);
    transition:clip-path .32s cubic-bezier(.16,1,.3,1);
  }
  .pk-tabla.visible .pk-marca, .pk-tabla.visible .pk-guion{ clip-path:inset(0); }
  .pk-tabla.visible tr > :nth-child(3) :is(.pk-marca, .pk-guion){ transition-delay:.12s; }
  .pk-tabla.visible tr > :nth-child(4) :is(.pk-marca, .pk-guion){ transition-delay:.24s; }
  /* ====== VIGILANCIA: QUE CAMBIA CON NUESTRO MDR ======
     Detras de los packs y antes de CERTIFICACIONES. Fondo blanco (el de
     .sv2-more) y tres columnas con LA CELDA DE COBERTURA de la home: filete
     arriba que se dibuja de izquierda a derecha y titular y texto que suben con
     la mascara, todo al entrar (el observador de revelado del overlay mira
     .mdr-col). Sin cajas ni iconos. Las medidas de COBERTURA estan en unidades
     del lienzo de 1920; aqui van traducidas a vw, la ley de --sv2-pad: calle de
     80, 80 del titular a las columnas y 32 del filete al titular de la celda.
     EL TITULO es el de la seccion COBERTURA de la home (.cob-titulo, 96 / 400 /
     -.02em), traducido: 5vw, 72 px a 1440 y 96 a 1920. Mas pequeno que los
     titulares gigantes de la pantalla (.sv2-pregunta, 115 y 154).
     TITULARES Y TEXTOS, los de las tarjetas del recorrido: 22-30 / 500 y
     14-17,5 / 1,55.
     EL AIRE, --aire-certs, de lo visible a lo visible:
      - arriba, del borde inferior de la banda de packs a la TINTA del titulo:
        el margen resta lo que la tinta (la tilde de la é) queda bajo su caja,
        --mdr-tinta, medido rasterizando y constante en em;
      - abajo, del BORDE INFERIOR del bloque (la caja de la ultima linea de
        texto) a la tinta del titulo de CERTIFICACIONES, con el pie del overlay
        igual que en las demas variantes: sale algo por encima de 160, porque
        la caja de la linea baja de la linea base. */
  /* EL POLVO NO PASA POR ENCIMA: el bloque lleva fondo blanco a todo el ancho,
     de borde a borde como la banda de packs (margenes negativos sobre
     --sv2-pad, con el mismo padding dentro para que el contenido no se mueva),
     y va a z-index:3, delante del 2 de .sv-polvo, el mecanismo de las
     tarjetas y de la tabla. EL AIRE DE ENCIMA VA EN PADDING, no en margen,
     para que el blanco lo cubra: el bloque empieza en el borde inferior de la
     banda de packs y acaba donde empieza la franja de CERTIFICACIONES.
     POR ABAJO, EL MISMO AIRE, para que el bloque quede simetrico: 160 de la
     LINEA BASE de la ultima linea de texto al borde inferior del bloque (los
     rabos de una p o una q no lo mueven). El relleno resta lo que la caja de
     la linea baja de la linea base, --mdr-base, en cuerpos del texto. No es
     constante del todo: el navegador redondea la linea base al pixel, y se ha
     medido .45 a 1440 y .41 o .48 a 1920, segun la carga. Con .44 el aire
     queda a 160 a 1440 y a unas seis decimas por encima o por debajo a 1920.
     Debajo sigue la franja de CERTIFICACIONES con su aire de siempre. */
  /* EL BORDE DE ABAJO NO CORTA EL POLVO: los ultimos --mdr-fundido unidades
     de 1920 (100) del relleno inferior van en DEGRADADO de blanco a
     transparente, y el polvo va apareciendo poco a poco. Caben dentro del
     relleno (152 a 1920 desde el borde de la ultima linea), asi que no tocan
     el texto; el aire de CERTIFICACIONES es de la franja y no cambia. El
     transparente es blanco a alfa 0, para que el degradado no pase por gris. */
  .mdr{
    --mdr-tinta:.1302;
    --mdr-base:.44;
    --mdr-fundido:100;
    margin:0 calc(-1 * var(--sv2-pad));
    padding:calc(var(--aire-certs) / 1920 * 100vw - var(--mdr-tinta) * 5vw) var(--sv2-pad)
            calc(var(--aire-certs) / 1920 * 100vw - var(--mdr-base) * clamp(14px, 0.92vw, 17.5px));
    background:linear-gradient(to bottom, #fff calc(100% - var(--mdr-fundido) / 1920 * 100vw), rgba(255,255,255,0) 100%);
    position:relative; z-index:3;
  }
  .mdr-titulo{
    margin:0;
    font-size:5vw; line-height:1; font-weight:400; letter-spacing:-.02em; color:#1d1d1c;
  }
  .mdr-cols{
    display:grid; grid-template-columns:repeat(3, 1fr);
    column-gap:calc(80 / 1920 * 100vw);
    margin-top:calc(80 / 1920 * 100vw);
  }
  .mdr-col{ position:relative; padding-top:calc(32 / 1920 * 100vw); }
  /* el filete, en el ::before y nunca en .mdr-col, que es lo observado (un
     clip-path sobre el elemento observado le anula la interseccion). Fuera del
     lienzo, --linew-fijo y la tinta de los filetes. */
  .mdr-col::before{
    content:""; position:absolute; left:0; right:0; top:0;
    height:var(--linew-fijo, 1px); background:#1d1d1c;
    clip-path:inset(0 100% 0 0);
    transition:clip-path .85s cubic-bezier(.65,0,.35,1);
  }
  .mdr-col.visible::before{ clip-path:inset(0 0 0 0); }
  .mdr-tit{
    margin:0 0 16px;
    font-size:clamp(22px, 1.65vw, 30px); line-height:1.15; font-weight:500; letter-spacing:-.02em; color:#1d1d1c;
  }
  .mdr-txt{
    margin:0;
    font-size:clamp(14px, 0.92vw, 17.5px); line-height:1.55; font-weight:400; color:#1d1d1c; text-wrap:pretty;
  }
  .mdr .rv{ display:block; overflow:hidden; padding:.12em 0 .16em; margin:-.12em 0 -.16em; }
  .mdr .rv-in{ display:block; transform:translateY(130%); }
  .mdr-col.visible .rv-in{ transform:none; transition:transform 1s cubic-bezier(.16,1,.3,1); }
  .mdr-col.visible .mdr-txt .rv-in{ transition-delay:.1s; }
  .alc-traza path{
    fill:none; stroke:#1d1d1c; stroke-width:var(--linew-fijo, 1px);
    stroke-linecap:square; stroke-linejoin:miter;
  }
  /* LA TARJETA DE CIERRE. Misma gramatica que las tres de arriba -- contorno de
     1,5 dibujado de arriba abajo con clip-path, fondo blanco, mismo padding y
     misma mascara de revelado -- pero a todo el ancho y sin titulo. Los 30 de
     margen son la calle de la rejilla, para que las cuatro cajas se lean como
     una sola reticula.
     SIN ICONO, a proposito. Los nueve de arriba son una SERIE: tres por
     tarjeta, en columna y alineados entre si. Uno suelto aqui no tiene con que
     alinearse, y puesto a la izquierda del texto caeria en la misma posicion
     que los nueve y convertiria la tarjeta en un decimo punto, que es justo lo
     que no es. */
  .auc-cierre{
    position:relative; box-sizing:border-box; margin-top:30px;
    padding:2.0833vw; background:#ffffff;
  }
  .auc-cierre::after{
    content:""; position:absolute; inset:0;
    box-shadow:inset 0 0 0 var(--linew-fijo, 1.5px) #1d1d1c;
    clip-path:inset(0 0 100% 0);
    transition:clip-path .85s cubic-bezier(.65,0,.35,1);
    pointer-events:none;
  }
  .auc-cierre.visible::after{ clip-path:inset(0 0 0 0); }
  /* MISMO CUERPO QUE LOS PUNTOS DE ARRIBA, el clamp de .auc-p tal cual, y a
     todo el ancho de la tarjeta. Asi la tarjeta de cierre se lee como lo que
     es, la coleta del bloque, sin competir con .auc-tit (32).
     LA MEDIDA QUEDA MUY LARGA Y SE ASUME: 165 caracteres por linea a 1440, en
     2 lineas. El techo comodo de la casa son los 92-94 de .cob-desc, o sea que
     esto va al 175% de ese techo. Es el precio de llenar el ancho con cuerpo
     de parrafo, y la aritmetica no deja otra: la tarjeta tiene 1260 de
     interior y el texto 249 caracteres.
     Historial, por si se vuelve: hubo un max-width:32em (71 caracteres, 4
     lineas, con medio lado vacio) y despues un cuerpo de 33 px sin tope (85
     caracteres, 3 lineas, pero por encima de .auc-tit). Las tres opciones
     estan medidas; esta es la que prioriza no competir con los titulos. */
  .auc-cierre-t, .auc-txt{
    margin:0;
    font-size:clamp(17px, 1.15vw, 21px); line-height:1.55; font-weight:400;
    color:#1d1d1c; text-wrap:pretty;
  }
  /* mascaras de revelado: las mismas de .svc-item */
  .auc .rv, .auc-cierre .rv, .alc .rv{ display:block; overflow:hidden; padding:.12em 0 .16em; margin:-.12em 0 -.16em; }
  .auc .rv-in, .auc-cierre .rv-in{ display:block; transform:translateY(130%); }
  /* las del recorrido de vigilancia: el texto entra cuando el despliegue de
     la tarjeta llega a --alc-texto-aparece (.alc-lleno) y sale con la mascara
     a la inversa si baja de --alc-texto-oculta. La transicion va tambien en el
     estado oculto, para que la salida se anime, y dura .6 s y no el segundo
     de las demas mascaras, con la misma curva: va atada al scroll y no puede
     quedarse atras. Sin JS (sin .alc-scroll), el texto se ve. */
  .alc .rv-in{ display:block; }
  .alc-scroll .alc .rv-in{ transform:translateY(130%); transition:transform .6s cubic-bezier(.16,1,.3,1); }
  .alc-scroll .alc .auc-col.alc-lleno .rv-in{ transform:none; }
  .alc-scroll .alc .auc-col.alc-lleno .auc-txt .rv-in{ transition-delay:.06s; }
  /* ====== CONTINUIDAD: LA LINEA TEMPORAL DEL INCIDENTE ======
     Bajo «Alcance del servicio»: una LINEA horizontal fina de margen a margen
     con tres NODOS cuadrados (ANTES, DURANTE y DESPUES), la MARCA DEL
     INCIDENTE -- una vertical mas alta que cruza la linea por el nodo del
     centro, con su etiqueta encima -- y, bajo cada nodo, un RAMAL corto hasta
     su TARJETA. Todo en unidades de 1920 traducidas a vw (la ley de
     --sv2-pad), y TODO EN LA HOJA: las tres columnas son iguales, asi que los
     nodos caen en el centro de cada una y no hay nada que medir. Sin JS se ve
     completa; la carga con el scroll cuelga de .cnt-scroll (app.js).
       --cnt-calle    la calle entre tarjetas: 80, la del bloque MDR.
                      Tarjetas de (1760 - 160) / 3 = 533 unidades: 400 px a
                      1440, 533 a 1920. Nodos en x 347 · 960 · 1573.
       --cnt-ramal    del nodo a la tarjeta: 80.
       --cnt-marca    media altura de la marca del incidente: 32 (64 en total).
       --cnt-nodo     el lado del nodo: 8, el de los nodos del recorrido de
                      vigilancia en su version de zigzag, macizo en tinta.
       --cnt-etq-*    la etiqueta: la de metodologia (.svm-label) en tinta,
                      como llevaron los numeros del zigzag. Encima de la linea,
                      a 16 del nodo y 12 por encima; la del incidente,
                      centrada y 12 por encima de la marca.
     LA CARGA, ligada al scroll del overlay y reversible (ver app.js, "linea
     temporal"): un solo progreso P para todo el bloque, segun donde esta la
     linea en la pantalla (0 cuando asoma por --cnt-carga-inicio, 1 al llegar a
     --cnt-carga-fin). La linea se dibuja en los primeros --cnt-fase-linea de P;
     al llegar a un nodo sale su etiqueta, el ramal crece en --cnt-fase-ramal
     y la tarjeta se despliega de arriba abajo en --cnt-fase-tarjeta. La
     ultima acaba en P = .993 (.64 x .849 + .1 + .35): tiene que ser menos de
     1, o no llega a quitarse la mascara. Sin unidad: las lee el JS. */
  .cnt-wrap{
    --cnt-calle:calc(80 / 1920 * 100vw);
    --cnt-pad:calc(24 / 1920 * 100vw);
    --cnt-ramal:calc(80 / 1920 * 100vw);
    --cnt-marca:calc(32 / 1920 * 100vw);
    --cnt-nodo:calc(8 / 1920 * 100vw);
    --cnt-etq-fs:clamp(12px, 1.09vw, 16px);
    --cnt-etq-sep:calc(16 / 1920 * 100vw);
    --cnt-etq-aire:calc(12 / 1920 * 100vw);
    --cnt-punto:calc(16 / 1920 * 100vw);
    --cnt-fundido:calc(80 / 1920 * 100vw);
    --cnt-carga-inicio:.9;
    --cnt-carga-fin:.3;
    --cnt-fase-linea:.64;
    --cnt-fase-ramal:.1;
    --cnt-fase-tarjeta:.35;
    /* la etiqueta de la fase se va si la linea retrocede este tanto por
       detras de su nodo (en fraccion de la linea): que no parpadee en el limite */
    --cnt-etq-margen:.02;
    --cnt-texto-aparece:.65;
    --cnt-texto-oculta:.5;
    /* la altura de la linea: etiqueta del incidente + su aire + media marca */
    --cnt-linea-y:calc(var(--cnt-etq-fs) + var(--cnt-etq-aire) + var(--cnt-marca));
    position:relative; margin-top:96px; padding-top:var(--cnt-linea-y);
  }
  .cnt{
    list-style:none; margin:0; padding:0;
    display:grid; grid-template-columns:repeat(3, 1fr); column-gap:var(--cnt-calle);
    align-items:start; color:#1d1d1c;
  }
  /* cada fase arranca en la linea: el ramal ocupa su padding de arriba */
  .cnt-fase{ position:relative; padding-top:var(--cnt-ramal); }
  .cnt-eje{
    position:absolute; left:0; right:0;
    top:calc(var(--cnt-linea-y) - var(--linew-fijo, 1px) / 2);
    height:var(--linew-fijo, 1px); background:#1d1d1c;
  }
  .cnt-nodo{
    position:absolute; left:calc(50% - var(--cnt-nodo) / 2); top:calc(var(--cnt-nodo) / -2);
    width:var(--cnt-nodo); height:var(--cnt-nodo); background:#1d1d1c;
  }
  .cnt-ramal{
    position:absolute; left:calc(50% - var(--linew-fijo, 1px) / 2); top:0;
    width:var(--linew-fijo, 1px); height:var(--cnt-ramal); background:#1d1d1c;
  }
  .cnt-incidente{ position:absolute; left:0; right:0; top:0; height:0; }
  .cnt-marca{
    position:absolute; left:calc(50% - var(--linew-fijo, 1px) / 2);
    top:calc(var(--cnt-linea-y) - var(--cnt-marca));
    width:var(--linew-fijo, 1px); height:calc(2 * var(--cnt-marca)); background:#1d1d1c;
  }
  .cnt-etq{
    font-size:var(--cnt-etq-fs); line-height:1; letter-spacing:.05em; font-weight:400;
    text-transform:uppercase; color:#1d1d1c; white-space:nowrap;
  }
  /* la del incidente arriba del todo: la linea esta justo debajo de ella, su
     aire y media marca (--cnt-linea-y) */
  .cnt-incidente .cnt-etq{ position:absolute; left:50%; top:0; transform:translateX(-50%); }
  .cnt-fase > .cnt-etq{
    position:absolute; left:calc(50% + var(--cnt-etq-sep));
    bottom:calc(100% + var(--cnt-etq-aire));
  }
  /* las tarjetas: las del recorrido de vigilancia, con los tres puntos de las
     de auditorias sin icono. Tapan el polvo (z-index 3); la linea, los nodos,
     los ramales y las etiquetas, no. El contorno esta siempre puesto: se
     despliega con la tarjeta. */
  .cnt .auc-col{ padding:var(--cnt-pad); z-index:3; }
  .cnt .auc-col::after{ clip-path:none; transition:none; }
  .cnt .auc-tit{ margin-bottom:16px; font-size:clamp(22px, 1.65vw, 30px); }
  .cnt .auc-lista{ gap:var(--cnt-punto); }
  .cnt .auc-p{ font-size:clamp(14px, 0.92vw, 17.5px); }
  .cnt .rv{ display:block; overflow:hidden; padding:.12em 0 .16em; margin:-.12em 0 -.16em; }
  .cnt .rv-in{ display:block; }
  /* LOS ESTADOS OCULTOS, solo con JS (.cnt-scroll). La linea, el ramal y la
     tarjeta los escribe el JS en linea en cada frame; aqui va su estado de
     partida. El nodo del centro y la marca del incidente, siempre puestos. */
  .cnt-scroll .cnt-eje{ clip-path:inset(0 100% 0 0); }
  .cnt-scroll .cnt-ramal{ clip-path:inset(0 0 100% 0); }
  .cnt-scroll .cnt-fase:not(:nth-child(2)) .cnt-nodo{ opacity:0; }
  .cnt-scroll .cnt-fase.cnt-on .cnt-nodo{ opacity:1; }
  .cnt-scroll .cnt .auc-col{
    -webkit-mask-image:linear-gradient(transparent, transparent);
            mask-image:linear-gradient(transparent, transparent);
  }
  /* el texto con la mascara de la web, en .6 s como en vigilancia: la
     etiqueta al llegar la linea a su nodo, el de la tarjeta con su despliegue
     (--cnt-texto-aparece / --cnt-texto-oculta) */
  .cnt-scroll .cnt .rv-in{ transform:translateY(130%); transition:transform .6s cubic-bezier(.16,1,.3,1); }
  .cnt-scroll .cnt-fase.cnt-on > .cnt-etq .rv-in,
  .cnt-scroll .cnt .auc-col.cnt-lleno .rv-in{ transform:none; }
  .cnt-scroll .cnt .auc-col.cnt-lleno .auc-p:nth-child(1) .rv-in{ transition-delay:.06s; }
  .cnt-scroll .cnt .auc-col.cnt-lleno .auc-p:nth-child(2) .rv-in{ transition-delay:.12s; }
  .cnt-scroll .cnt .auc-col.cnt-lleno .auc-p:nth-child(3) .rv-in{ transition-delay:.18s; }
  .auc-col.visible .rv-in, .auc-cierre.visible .rv-in{
    transform:none; transition:transform 1s cubic-bezier(.16,1,.3,1);
  }
  .auc-col.visible .auc-p:nth-child(2) .rv-in{ transition-delay:.06s; }
  .auc-col.visible .auc-p:nth-child(3) .rv-in{ transition-delay:.12s; }
  .auc-col.visible .auc-p:nth-child(4) .rv-in{ transition-delay:.18s; }
  .auc-col.visible .auc-txt .rv-in{ transition-delay:.06s; }

  .svc-item{ position:relative; padding-top:40px; }
  /* el último servicio cierra con su propia línea por abajo */
  .svc-item:last-child{ padding-bottom:40px; }
  .svc-item:last-child::after{
    content:""; position:absolute; left:0; bottom:0; width:100%; height:0;
    border-top:1.5px solid #1d1d1c;
    transform:scaleX(0); transform-origin:left;
    transition:transform .9s cubic-bezier(.65,0,.35,1);
  }
  .svc-item:last-child.visible::after{ transform:scaleX(var(--cierre,1)); transition-delay:.15s; }
  /* durante la compresión por scroll las líneas se mueven en directo,
     sin transición (el scrub manda) */
  .svc-item.comprimiendo .svc-line{ transition:none !important; }
  .svc-item.comprimiendo::after{ transition:none !important; transform-origin:right; }
  .svc-line{
    position:absolute; left:0; top:0; width:100%; height:0;
    border-top:1.5px solid #1d1d1c;
    transform:scaleX(0); transform-origin:left;
  }
  .svc-item.visible .svc-line{
    transform:scaleX(1);
    transition:transform .9s cubic-bezier(.65,0,.35,1);
  }

  /* ====== METODOLOGÍA dentro de la pantalla de AUDITORÍAS ======
     Llega de la home, donde vivía sobre el lienzo de 1920 con tops absolutos.
     Aquí es fluida, como el resto del overlay. Los cuerpos están calibrados
     contra lo que la home PINTA a 1440 (sus px de lienzo por 0,75): etiqueta
     15,75 · icono 34,5 · título 54 · titular 57 · «Proceso» 210 · banda 420.
     Ojo: --svm-pad y el cuerpo de .svm-label no son decoración. El JS mide el
     ancho de la etiqueta para calcular el de su columna plegada, así que
     tocar ese cuerpo cambia en silencio la geometría de toda la banda. */
  .svm{
    --svm-pad: clamp(12px, 1.25vw, 18px);
    /* Espejo de .sv-topbar{height}. El bloque arranca en el BORDE de la
       pantalla, no bajo la barra, asi que esos 56 quedan dentro: se los suma
       la cabecera a su aire de arriba y se los quita la banda a su alto, para
       que el total del bloque no se mueva. Si cambia el alto de la barra hay
       que cambiarlo aqui, y nada lo avisa. */
    --svm-tb: 56px;
    /* A SANGRE: sale del padding lateral de .sv2-more con margenes negativos.
       No hace falta tocar el width -- un bloque con margenes negativos se
       ensancha solo --, y el borde derecho cae en el borde del AREA DE
       CONTENIDO del overlay, que ya excluye su barra de scroll (clientWidth
       1425 de 1440). Asi que aqui la barra no se come nada. */
    margin:clamp(90px, 9vw, 140px) calc(-1 * var(--sv2-pad, 34px)) 0;
    color:#ffffff;
    /* El fondo va en el BLOQUE, no solo en la cabecera y la banda. Mientras
       las dos sumaban el total no se notaba, pero al pasar a 100vh con la
       banda anclada abajo aparecio un hueco entre ellas -- 134 a 1440x820 --
       y ese hueco enseñaba el blanco de .sv2-more: una franja blanca cruzando
       el gris de lado a lado. */
    background:#3b3b3b;
    /* Por ENCIMA del polvo del overlay (.sv-polvo, fijo y a z-index 2). Ese
       polvo no recorta por elementos como el de la home: se recorta con un
       solo inset vertical, asi que no tiene forma de dejarle un hueco a este
       bloque. Ponerlo delante es mas barato que darle agujeros a un clip-path
       que solo admite una figura. */
    position:relative; z-index:3;
    /* DE BORDE A BORDE tambien en vertical. El overlay es fixed inset:0, asi
       que su alto ES el del viewport y 100vh no miente. El reparto va por flex
       en columna: la cabecera toma lo suyo, la banda se ancla ABAJO con
       margin-top:auto y el gris sobrante queda en medio -- que es justo lo que
       hacia la home, donde .met-band iba en absoluto con bottom:0 y dejaba 93
       aire. En ventanas bajas la banda encoge sola (flex-shrink por defecto),
       asi que no se desborda. */
    height:100vh;
    display:flex; flex-direction:column;
  }
  .svm-head{ background:#3b3b3b; padding:calc(var(--svm-tb) + clamp(16px,1.5vw,22px)) clamp(18px,1.9vw,28px) clamp(20px,1.9vw,28px); }
  .svm-eyebrow{
    display:block; font-size:14px; line-height:1.0055; font-weight:400; color:#ffffff;
  }
  .svm-head .sr-only + .svm-headline,
  /* PESO 400, y ES UNA DECISION TOMADA A SABIENDAS: empata con .svm-big, los
     titulos de los paneles que van DEBAJO, que estan en 400 y a 54 px --
     practicamente el mismo cuerpo (57) y sobre el mismo gris. O sea que el
     titular del bloque NO tiene escalon de peso sobre sus subtitulos. Se
     prefiere eso a que se vea pesado.
     Lo que si arregla es el punto de partida: estuvo en 300, o sea MAS FINO
     que sus propios subtitulos, que era jerarquia invertida.
     ASTA MEDIDA en sus condiciones -- blanco sobre #3b3b3b, rasterizando la
     'l', que es un palo puro, y dividiendo area de tinta entre alto de tinta,
     asi sale con subpixel --:
       300 -> 3,67    400 -> 5,05    425 -> 5,15
       450 -> 5,64    475 -> 5,80    500 -> 5,97
     y .svm-big, a 400 y 54 px, esta en 4,96. Con 400 la diferencia es de un
     +1,8%, que es ruido: los dos se leen al mismo peso. Se probaron 500
     (+20,4%, se veia gordo) y 450 (+13,7%), y se descartaron los dos.
     Si algun dia se quiere recuperar el escalon sin engordar el titular, la
     otra palanca es BAJAR .svm-big, no subir este.
     NO MUEVE NADA DEL CONGELADO, comprobado con los cuatro pesos: 2 lineas,
     cabecera 268,3 y at() identico. Y no puede moverlo por construccion: at()
     es el top de .svm y este titular vive DENTRO. */
  .svm-headline{
    margin:clamp(14px,1.5vw,22px) 0 0; width:100%;
    font-size:clamp(30px, 4vw, 57px); line-height:1.12; font-weight:400; color:#ffffff;
    letter-spacing:-.01em; text-indent:clamp(70px, 9.4vw, 135px);
  }
  .svm-band{
    position:relative; width:100%; margin-top:auto;
    /* 29vw y no 32: el aire entre la frase y los paneles sale de AQUI. El
       bloque mide 100vh y la cabecera ya esta recortada al hueso, asi que lo
       unico que queda para dar aire es bajar la banda. De paso su techo, 420,
       es el alto exacto que tiene en la home a esta escala. */
    height:clamp(300px, 29vw, 420px);
    overflow:hidden; background:#3b3b3b;
    /* --linew-fijo y no --linew: metodologia vive en el overlay, que es fixed
       y NO cuelga de #canvas, asi que no la encoge ningun transform. --linew
       lleva un /scale dentro para compensar el del lienzo, y aqui eso la
       engorda en vez de compensarla -- medido, 1,328 px de CSS frente a 1 en
       la home. Las dos variables apuntan a los mismos N pixeles de
       dispositivo; lo unico que cambia es si hay que deshacer la escala. */
    border-top:var(--linew-fijo, 1.5px) solid #ffffff;
  }
  .svm-panel{
    position:absolute; top:0; height:100%; overflow:hidden;
    border-left:var(--linew-fijo, 1.5px) solid #ffffff;   /* el porque, en .svm-band */
  }
  .svm-panel:first-child{ border-left:0; }
  .svm-label{
    position:absolute; left:var(--svm-pad); top:var(--svm-pad);
    font-size:clamp(12px, 1.09vw, 16px); line-height:1; letter-spacing:.05em;
    color:#ffffff; text-transform:uppercase; white-space:nowrap; font-weight:400;
  }
  .svm-icon{
    position:absolute; left:var(--svm-pad); top:calc(var(--svm-pad) + clamp(24px, 2.6vw, 38px));
    width:clamp(24px, 2.4vw, 35px); height:clamp(24px, 2.4vw, 35px); color:#ffffff;
  }
  .svm-icon svg{ width:100%; height:100%; display:block; stroke-width:2.4px; }
  .svm-big{
    margin:0; font-size:clamp(26px, 3.75vw, 54px); line-height:1; font-weight:400;
    color:#ffffff; white-space:nowrap; letter-spacing:-.02em; text-transform:uppercase;
  }
  /* ancho FIJO anclado a la izquierda: el título queda quieto y el panel lo
     tapa al estrecharse, igual que en la home. */
  .svm-bigwrap{
    position:absolute; top:0; bottom:0; left:0; width:clamp(300px, 33.3vw, 480px);
    display:flex; align-items:flex-start; justify-content:flex-end;
    padding:var(--svm-pad) clamp(14px, 1.6vw, 23px) 0 0;
  }
  .svm-foot{
    position:absolute; left:var(--svm-pad); bottom:clamp(18px, 2vw, 30px);
    width:clamp(180px, 19.8vw, 285px);
  }
  .svm-desc{ margin:0; font-size:clamp(13px, 1.25vw, 18px); line-height:1.4; color:#ffffff; text-wrap:pretty; }
  /* El margen sale de la home, no de la nada: alli .mp-big iba en absoluto con
     left:24 y el panel de cierre le baja el top a 20, los dos en unidades de
     lienzo. Por la escala 0,75 eso son 18 y 15 en pantalla, y 18 es justo
     --svm-pad. Al reescribir .svm-big en fluido se me cayo el posicionamiento
     absoluto y el titulo quedaba clavado en la esquina del recuadro. Los otros
     cuatro paneles NO lo llevan: a los suyos los coloca .svm-bigwrap. */
  .svm-panel--cierre .svm-big{
    position:absolute; left:var(--svm-pad); top:calc(var(--svm-pad) * .83);
    font-size:clamp(88px, 14.6vw, 210px); text-transform:none;
  }

  .svc-grid{ display:grid; grid-template-columns: 1.2fr 1fr; gap:60px; align-items:start; }
  .svc-titulo{ will-change:transform; }
  .svc-flecha{ display:inline-block; width:.92em; height:.92em; margin-right:.26em; vertical-align:-.1em; color:#1d1d1c; }
  .svc-flecha svg{ width:100%; height:100%; display:block; transform:rotate(45deg); }
  .svc-titulo{ margin:0; font-size:clamp(34px, 2.75vw, 54px); line-height:1.12; font-weight:400; letter-spacing:-.015em; color:#1d1d1c; }
  .svc-cuerpo{ margin:6px 0 0; font-size:clamp(17px, 1.15vw, 21px); line-height:1.55; font-weight:400; color:#1d1d1c; max-width:560px; text-wrap:pretty; }
  /* máscaras de recorte: el contenido nace abajo y sube a su sitio.
     La ventana lleva aire vertical (compensado con margen negativo) para que
     acentos y descendentes (í, y, g, p) no se corten nunca. */
  .svc-item .rv{ display:block; overflow:hidden; padding:.12em 0 .16em; margin:-.12em 0 -.16em; }
  .svc-item .rv-in{ display:block; transform:translateY(130%); }
  .svc-item.visible .rv-in{
    transform:translateY(0);
    transition:transform .95s cubic-bezier(.16,1,.3,1);
  }
  .svc-item.visible .svc-cuerpo .rv-in{ transition-delay:.14s; }
  /* ====== FACTOR HUMANO Y GARANTÍA — pantalla de FORMACIÓN ======
     Llegan de la home, donde vivían sobre el lienzo de 1920 con tops absolutos
     y un reparto (repartirFactorHumano) que estiraba sus huecos para llenar
     exactamente el tramo congelado. Aquí el overlay es FLUIDO: grid y clamp,
     como el resto de la pantalla, y de aquella maquinaria no queda nada.

     Estas clases .pf- son el vocabulario de revelado que se trajo el bloque: no
     posicionan, solo animan, y ahora solo existen dentro de este overlay. */
  .serv-overlay .pf-line{ display:block; overflow:hidden; padding-bottom:.12em; }
  .serv-overlay .pf-line .pf-in{ display:block; transform:translateY(112%); transition:transform 1s cubic-bezier(.16,1,.3,1); }
  .serv-overlay .pf-line.visible .pf-in{ transform:none; }
  .serv-overlay .pf-lr{ overflow:hidden; }
  .serv-overlay .pf-lr .pf-lr-in{ display:block; transform:translateX(-103%); transition:transform 1.1s cubic-bezier(.16,1,.3,1); }
  .serv-overlay .pf-lr.visible .pf-lr-in{ transform:none; }
  .serv-overlay .pf-rise{ opacity:0; transform:translateY(30px); transition:opacity .9s ease, transform 1s cubic-bezier(.16,1,.3,1); }
  .serv-overlay .pf-rise.visible{ opacity:1; transform:none; }
  .serv-overlay .pf-hr{ height:0; border-top:1.5px solid #1d1d1c;
    transform:scaleX(0); transform-origin:left center; transition:transform 1.15s cubic-bezier(.16,1,.3,1); }
  .serv-overlay .pf-hr.visible{ transform:scaleX(1); }

  /* ---- el bloque ---- */
  /* El -27 iguala el aire de encima del titular con el que queda entre él y el
     primer párrafo (medido de tinta a tinta: 93 arriba contra 66 abajo). Es
     margen NEGATIVO porque los 96px de arriba son el padding-top de .sv2-more,
     común a las cinco variantes: no se puede tocar ahí sin mover las otras.
     No descuadra el anclaje: at() cuelga de .sv2-close, que está por encima, y
     el min-height de la banda lo deriva ajustarBanda() del hueco MEDIDO. */
  .fh{ position:relative; margin:-27px 0 0; }
  .fh-hr{ position:relative; width:100%; }
  /* La banda del tramo congelado. En la home ocupaba exactamente el viewport
     bajo la topbar, y para eso hacía falta medir y repartir; aquí basta con
     pedirle ese alto y dejar que el contenido respire dentro. */
  /* El min-height es solo RESERVA hasta el primer at(): el valor bueno lo
     deriva el JS de dónde queda el ancla al congelarse (ver ajustarBanda). El
     150 de aquí era "línea de la topbar + hueco hasta el titular", dos medidas
     que el CSS no puede conocer y que cuadraban con 1px de margen. */
  .fh-banda{ position:relative; min-height:calc(100vh - 150px); padding-bottom:96px; }
  .fh-cab{ position:relative; overflow:hidden; }
  .fh-claim, .fh-frase{
    /* 500, y LAS DOS JUNTAS. No es un descuido que compartan regla: son las dos
       piezas que se INTERCAMBIAN en el tramo congelado -- la pregunta sale por
       la izquierda y la frase entra por la derecha ocupando su sitio --, asi
       que separarles el peso partiria a la mitad un gesto pensado para leerse
       como uno solo.
       500 y no 400 porque .fh-h2, el subtitular de este mismo bloque, ya va a
       400 y no se distinguiria; y no 700 porque ese es el peso del <strong>,
       reservado a resaltar DENTRO de un parrafo. A 94px un 700 es un titular
       de periodico.
       El peso aqui es gratis de maqueta: medido a 1440, la linea mas larga
       pasa de 921,9 a 940,7 sobre un contenedor de 1372, y el alto no se mueve
       de 172,1 en ningun peso hasta 700. */
    margin:0; font-weight:500; color:#1d1d1c;
    font-size:clamp(56px, 4.9vw, 94px); line-height:1.1; letter-spacing:-.025em;
  }
  .fh-claim{ will-change:transform; }
  /* la frase espera FUERA por la derecha; el tramo congelado la trae y a la vez
     se lleva la pregunta por la izquierda */
  .fh-frase{ position:absolute; left:0; top:0; width:100%; transform:translateX(108%); will-change:transform; }
  .fh-frase .l{ display:block; white-space:nowrap; }
  /* Los dos párrafos y el dato COMPARTEN sitio: la intro arranca pegada a la
     izquierda y el tramo congelado la desplaza a la derecha; en el hueco que
     deja sube el dato desde su máscara. La intro va en flujo (es quien da el
     alto) y la máscara, encima en absoluto. */
  .fh-cols{ position:relative; margin:58px 0 0; }
  .fh-intro{ width:48%; min-width:320px; will-change:transform; }
  .fh-body{ margin:0 0 26px; text-wrap:pretty; }
  .fh-body:last-child{ margin-bottom:0; }
  .fh-dato-mask{ position:absolute; left:0; top:0; bottom:-110vh; width:47%; min-width:300px; overflow:hidden; pointer-events:none; }
  /* min-height:100% es lo que hace que la máscara recorte de verdad: un
     translateY en % se mide contra la caja DEL PROPIO elemento, y el dato (una
     frase) es más bajo que la máscara (dos párrafos), así que un 118% suyo no
     bastaba para sacarlo y asomaba por encima de la intro. Igualando su alto al
     de la máscara, el porcentaje pasa a valer lo que mide la máscara. */
  /* 500: es un dato de callout de 37px al lado de un cuerpo de 19 a 400, y ese
     paso lo separa sin que compita con el .fh-h2, que es mas grande. La cifra
     se queda en su 600 -- un paso mas el rojo es contraste de sobra a este
     tamano, y un 700 sobre un 500 empieza a leerse como otra tipografia metida
     en la frase. Si algun dia el parrafo sube a 600, la cifra TIENE que ir a
     700 o se queda sin distincion de peso. */
  .fh-dato{ margin:0; font-size:clamp(24px,2.6vw,46px); line-height:1.18; font-weight:500; color:#1d1d1c;
    pointer-events:auto; user-select:text;
    transform:translateY(100vh); will-change:transform; }
  .fh-dato-l{ display:block; }
  /* La cifra, a 600. El color ya la separa; el peso la remata. Va SOLO en el
     span de la cifra y no en .fh-dato, que se queda en 300: el contraste entre
     el numero grueso y rojo y la frase fina pesa mas que subirlo todo.
     Tambien es gratis: el span pasa de 95,8 a 96,8 de ancho y el parrafo
     mantiene sus tres lineas y sus 128,3 de alto en cualquier peso. */
  .fh-ac{ color:var(--red-core); font-weight:600; }
  .fh-dato-fuente{ display:block; margin-top:26px; font-size:14px; line-height:1; letter-spacing:.05em; text-transform:uppercase; color:#3b3b3b; font-weight:400; }
  /* 500, EL MISMO que .fh-claim. Un solo peso de enfasis en todo el bloque y
     el TAMANO haciendo la jerarquia: el claim es 1,63 veces este h2, asi que
     manda con holgura sin necesidad de pesar mas.
     Subirlo por encima del claim no invertiria la jerarquia -- el tamano
     seguiria mandando -- pero dejaria un orden de PESOS que contradice al de
     tamanos, el elemento pequeno mas grueso que el grande, sin ganar nada.
     El 700 queda libre para lo que ya es en la web: el <strong> dentro de un
     parrafo. */
  .fh-h2{ margin:88px 0 0; font-size:clamp(34px,3vw,54px); line-height:1.14; font-weight:500; letter-spacing:-.015em; color:#1d1d1c; }
  .fh-lead{ margin:26px 0 0; max-width:1080px; }
  /* Los parrafos del bloque comparten UNA regla: el cuerpo de la intro y el del
     bloque de abajo ya median lo mismo, pero el color los hacia leer distinto. */
  .fh-body, .fh-lead, .sv2-entradilla{ font-size:clamp(17px,1.35vw,24px); line-height:1.55; font-weight:400; color:#1d1d1c; }
  /* Un solo bloque: el titular, su párrafo y qué es el phishing. Antes iban
     partidos por una divisoria (.pf-vr), que se ha quitado. */
  .fh-bloque{ margin:0; }

  /* ---- garantía ---- */
  /* AJUSTE OPTICO del hueco con el titular de abajo (.sv2-pregunta). El de
     arriba (boton .fg-cta -> titular) es este margin-bottom; el de abajo
     (titular -> primera .svc-line) es .svc-lista2{margin-top:140px}, COMUN a
     las cinco variantes y por eso intocable. Igualarlos de CAJA no basta: el
     titular es enorme y su caja lleva aire muerto entre el borde y la altura
     de mayusculas, mientras que por abajo las descendentes de «que incluye?»
     llegan casi al borde.
     123 Y NO 117. El 117 venia calibrado sobre la Aeonik local y se quedo
     escrito en CLAUDE.md como "el valor exacto a 1440"; con Figtree
     sobrecorrige. Remedido con las metricas reales de los glifos
     (actualBoundingBox del canvas, no cajas de linea), en el overlay abierto,
     en reposo revelado y con las transiciones apagadas:

       ancho    140 (antes)    123      117
       1920       +19,9        +2,9     -3,1
       1440       +16,9        -0,1     -6,1
       1024       +12,9        -4,1    -10,1

     Con 123 el residuo queda repartido alrededor de cero; con 117 se pasa de
     largo en los tres. Se remide igual si cambia la tipografia. */
  .fg{ position:relative; margin:110px 0 123px; }
  .fg-hr{ position:relative; width:100%; }
  /* 500 y 7vw, y las dos cosas van juntas. El peso entra en el sistema del
     bloque -- 400 lo que se lee, 500 lo que destaca, 600 en rojo solo la cifra
     -- donde .fh-claim, .fh-frase y .fh-h2 ya estan en 500. NO sube a 700
     porque ese peso YA se usa aqui dentro: el <strong> de .fg-text ("Te
     devolvemos el 100% del dinero"). Con el titular en 700 el strong dejaria
     de resaltar contra el.
     El cuerpo baja de 8.4vw a 7vw -- los tres valores del clamp escalados por
     el mismo 7/8.4 para que suelo y techo guarden su relacion -- porque este
     titular era el texto MAS GRANDE de toda la pantalla .sv2-more: a 1440
     medía 120,96 contra los 80,64 de .sv2-pregunta, que es el titular de
     seccion, o sea 1,50 veces. Con 7vw queda en 100,8 y la razon baja a 1,25:
     sigue siendo la pieza dominante del bloque, que es lo que toca, pero deja
     de aplastar al titular que lo ordena. Bajar hasta 5.6vw lo empataria con
     el, y dos titulares del mismo cuerpo compiten en vez de ordenarse.
     El -17% compensa lo que gana al pasar de 300 a 500: cambia grosor por
     tamaño, no encoge a secas.
     Sigue en UNA linea a 1440 y a 1024, y el tramo congelado no se entera:
     __fhComp no menciona .fg y su ancla, .sv2-close, esta por encima. */
  .fg-title{ margin:40px 0 0; font-size:clamp(40px,7vw,125px); font-weight:500; letter-spacing:-.03em; line-height:1; color:#1d1d1c; padding-bottom:.06em; }
  .fg-title .pf-lr-in{ transition-duration:1.9s; }
  .fg-cols{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(40px,6vw,110px); margin:52px 0 0; align-items:start; }
  .fg-label{ margin:0; font-size:clamp(17px,1.45vw,28px); font-weight:400; color:#1d1d1c; letter-spacing:.02em; }
  .fg-text{ margin:20px 0 0; font-size:clamp(15px,1.25vw,25px); line-height:1.5; font-weight:400; color:#1d1d1c; }
  .fg-cta{ position:relative; z-index:1; display:inline-flex; align-items:center; gap:14px; margin:52px 0 0;
    padding:17px 26px; border:1.5px solid #1d1d1c; text-decoration:none; isolation:isolate; overflow:hidden;
    font-size:clamp(15px,1.1vw,22px); font-weight:400; color:#1d1d1c; transition:color .16s ease-out, opacity .9s ease, transform 1s cubic-bezier(.16,1,.3,1); }
  .fg-cta::before{ content:""; position:absolute; inset:0; z-index:-1; background:#1d1d1c;
    transform:scaleY(0); transform-origin:bottom; transition:transform .22s ease-out; will-change:transform; }
  .fg-cta:hover{ color:#f1f1f1; }
  .fg-cta:hover::before{ transform:scaleY(1); }
  .fg-arrow{ display:inline-flex; width:.9em; height:.9em; }
  .fg-arrow svg{ width:100%; height:100%; }

  /* En pantallas estrechas la coreografía lateral no cabe: la intro y el dato
     dejan de compartir sitio y se apilan. El tramo congelado sigue existiendo
     (la pregunta y la frase se relevan igual), pero sin cruce horizontal. */
  @media (max-width:900px){
    .fh-claim, .fh-frase{ font-size:clamp(32px, 5.8vw, 58px); }
    .fh-intro{ width:100%; min-width:0; }
    .fh-dato-mask{ position:relative; width:100%; min-width:0; bottom:auto; height:auto; margin-top:40px; }
    .fh-banda{ min-height:0; }
    .fg-cols{ grid-template-columns:1fr; }
  }
  /* línea que CIERRA el bloque por abajo, de borde a borde */
  .sv2-close{
    position:absolute; left:0; right:0; bottom:0;
    height:0; border-top:1.5px solid #1d1d1c;
    transform:scaleX(0); transform-origin:left;
  }
  .serv-overlay.sv-line .sv2-close{
    transform:scaleX(1);
    transition:transform .85s cubic-bezier(.65,0,.35,1) .48s;
  }
  /* tag de scroll y flecha: aparecen tras dibujarse las divisorias */
  .sv2-scroll-tag, .sv2-arrow{ opacity:0; transform:translateY(14px); }
  .serv-overlay.sv-in .sv2-scroll-tag,
  .serv-overlay.sv-in .sv2-arrow{
    opacity:1; transform:none;
    transition:opacity .9s ease, transform .9s cubic-bezier(.16,1,.3,1);
  }
  /* cascada como "about": frase → tag → flecha */
  .serv-overlay.sv-in .sv2-scroll-tag{ transition-delay:.58s; }
  .serv-overlay.sv-in .sv2-arrow{ transition-delay:.67s; }
  /* la frase sube línea a línea desde máscaras de recorte */
  .sv2-frase .fr-rv{ display:block; overflow:hidden; padding:.12em 0 .16em; margin:-.12em 0 -.16em; }
  .sv2-frase .fr-rv-in{ display:block; transform:translateY(130%); }
  .serv-overlay.sv-in .sv2-frase .fr-rv-in{
    transform:translateY(0);
    transition:transform .9s cubic-bezier(.16,1,.3,1);
  }
  .serv-overlay.sv-in .sv2-frase .fr-rv:nth-child(1) .fr-rv-in{ transition-delay:.5s; }
  /* nombres de los servicios: suben desde una máscara de recorte, cada uno
     justo después de dibujarse su línea (orden arriba → abajo). Hay un delay
     por fila y tiene que haber tantos como entradas: el índice lleva cuatro y
     los cuatro servicios, tres. A la fila sin delay le tocaría 0s y subiría
     ANTES que las de encima, rompiendo el orden. */
  .sv2-lista .li-rv{ display:block; overflow:hidden; padding:.12em 0 .16em; margin:-.12em 0 -.16em; }
  .sv2-lista .li-rv-in{ display:block; transform:translateY(130%); }
  .serv-overlay.sv-in .sv2-lista .li-rv-in{
    transform:translateY(0);
    transition:transform .9s cubic-bezier(.16,1,.3,1);
  }
  .serv-overlay.sv-in .sv2-lista li:nth-child(1) .li-rv-in{ transition-delay:.5s; }
  .serv-overlay.sv-in .sv2-lista li:nth-child(2) .li-rv-in{ transition-delay:.6s; }
  .serv-overlay.sv-in .sv2-lista li:nth-child(3) .li-rv-in{ transition-delay:.7s; }
  .serv-overlay.sv-in .sv2-lista li:nth-child(4) .li-rv-in{ transition-delay:.8s; }
  /* topbar oculta durante la animación de entrada (como en la carga de la web):
     aparece al asentarse el logotipo, subiendo con fundido (misma cascada).
     Sus LÍNEAS (inferior y la del recuadro del logo) se DIBUJAN, no se funden. */
  .serv-overlay .sv-topbar{ opacity:0; transform:translateY(14px); pointer-events:none; }
  .serv-overlay .sv-topbar::after{ transform:scaleX(0); transform-origin:left; }
  .serv-overlay .sv-tblogo::after{ transform:scaleY(0); transform-origin:top; }
  .serv-overlay.sv-tb .sv-topbar::after{
    transform:scaleX(1);
    transition:transform .85s cubic-bezier(.65,0,.35,1) .1s;
  }
  .serv-overlay.sv-tb .sv-tblogo::after{
    transform:scaleY(1);
    transition:transform .7s cubic-bezier(.65,0,.35,1) .3s;
  }
  .serv-overlay.sv-tb .sv-topbar{
    opacity:1; transform:none; pointer-events:auto;
    transition:opacity .7s ease .35s, transform .7s ease .35s, background .35s ease;
  }

  /* ====== OVERLAY DE CONTACTO ======
     Capa fija por encima del lienzo (no toca el motor de scroll congelado).
     La abren los enlaces CONTACTO de la topbar/menú y el botón Contáctanos. */
  .contacto-overlay{
    position:fixed; inset:0; z-index:200;
    display:block;
    background:#3b3b3b;
    font-family:'Figtree',Arial,sans-serif;
    color:#1d1d1c;
    opacity:0; visibility:hidden; pointer-events:none;
    transition:opacity .5s ease, visibility .5s ease;
    overflow-y:auto;
  }
  .contacto-overlay.abierto{ opacity:1; visibility:visible; pointer-events:auto; }
  .co-scroll{ position:relative; width:100%; min-height:100%; padding:56px 0 0; background:#f1f1f1; }
  .co-scroll::before{ content:''; position:absolute; left:0; right:0; top:-100vh; height:100vh; background:#f1f1f1; }

  /* topbar idéntica al resto del sitio (logo 128px + divisoria vertical + nav
     con marcadores triangulares), en blanco con líneas negras. */
  .co-topbar{
    position:absolute; top:0; left:0; right:0; height:56px; z-index:3;
    background:#f1f1f1;
  }
  .co-topbar::after{
    content:""; position:absolute; left:0; bottom:0; width:100%; height:0;
    border-bottom:1.5px solid #1d1d1c; clip-path:inset(0 100% 0 0);
    transition:clip-path 1.1s cubic-bezier(.33,0,.2,1);
  }
  .contacto-overlay.lineas .co-topbar::after{ clip-path:inset(0 0 0 0); }
  .co-tblogo{
    position:absolute; left:0; top:0; height:100%; width:128px; box-sizing:border-box;
    display:flex; align-items:center; justify-content:center;
  }
  .co-tblogo::after{
    content:""; position:absolute; right:0; top:0; height:100%; width:0;
    border-right:1.5px solid #1d1d1c; clip-path:inset(0 0 100% 0);
    transition:clip-path 1.1s cubic-bezier(.33,0,.2,1);
  }
  .contacto-overlay.lineas .co-tblogo::after{ clip-path:inset(0 0 0 0); }
  .co-tblogo svg{ width:auto; height:21px; display:block; opacity:0; transition:opacity .95s ease; transition-delay:.4s; }
  .contacto-overlay.contenido .co-tblogo svg{ opacity:1; }
  .co-tblogo svg path{ fill:#1d1d1c; }
  .co-nav{
    position:absolute; left:128px; top:0; height:100%;
    display:flex; align-items:center; gap:30px; padding-left:28px;
    font-size:20px;
  }
  .co-nav a{
    color:rgba(29,29,28,.62); text-decoration:none; text-transform:lowercase;
    display:inline-flex; align-items:center; gap:9px;
    opacity:0; transform:translateY(6px);
    transition:opacity .9s ease, transform 1s cubic-bezier(.16,1,.3,1), color .2s ease;
  }
  .co-nav a:hover, .co-nav a.activo{ color:#1d1d1c; }
  /* entrada en cascada de izquierda a derecha (como en "sobre nosotros") */
  .contacto-overlay.contenido .co-nav a{ opacity:1; transform:none; }
  .contacto-overlay.contenido .co-nav a:nth-child(1){ transition-delay:.4s, .4s, 0s; }
  .contacto-overlay.contenido .co-nav a:nth-child(2){ transition-delay:.5s, .5s, 0s; }
  .contacto-overlay.contenido .co-nav a:nth-child(3){ transition-delay:.6s, .6s, 0s; }
  .co-nav a::before{
    content:""; width:9px; height:9px; flex:none;
    background:currentColor; opacity:.42;
    clip-path:polygon(0 0, 100% 0, 0 100%);
  }

  /* cabecera: "contacto" gigante + email a la derecha, sobre una línea negra */
  .co-head{ position:relative; padding:34px 34px 34px 20px; }
  .co-email{
    position:absolute; right:34px; top:34px; font-size:19px; color:#1d1d1c;
    text-decoration:none; opacity:0; transform:translateY(14px);
    transition:opacity .8s ease, transform .9s cubic-bezier(.16,1,.3,1), color .2s ease;
  }
  .contacto-overlay.contenido .co-email{ opacity:1; transform:none; transition-delay:.44s, .44s, 0s; }
  .co-email:hover{ color:var(--red-core); }
  .co-big{
    margin:0; padding:0; font-size:min(20vw, 270px); line-height:1;
    font-weight:400; letter-spacing:-.03em; color:#1d1d1c;
  }
  /* letras enmascaradas para la animación de carga (idénticas a "about") */
  .co-big .lt{ display:inline-block; overflow:hidden; padding-top:.16em; margin-top:-.16em; padding-bottom:.12em; margin-bottom:-.12em; vertical-align:top; }
  .co-big .lt-in{ display:inline-block; will-change:transform; }
  /* terminada la animación de entrada, la máscara ya no hace falta: se abre el
     recorte y se libera la capa para que ninguna letra pueda quedar cortada */
  .co-big.revelado .lt{ overflow:visible; }
  .co-big.revelado .lt-in{ will-change:auto; }
  .co-hr{
    height:0; border-top:1.5px solid #1d1d1c; margin:0;
    clip-path:inset(0 100% 0 0);
    transition:clip-path 1.1s cubic-bezier(.33,0,.2,1);
  }
  .contacto-overlay.lineas .co-hr{ clip-path:inset(0 0 0 0); }

  /* cuerpo: frase a la izquierda + formulario a la derecha */
  .co-body{
    display:grid; grid-template-columns:minmax(260px, 34%) 1fr; gap:120px;
    padding:34px 30px 96px;
  }
  .co-phrase{
    margin:0; font-size:clamp(18px, 1.5vw, 23px); line-height:1.25; font-weight:400;
    color:#1d1d1c; letter-spacing:-.01em; text-wrap:pretty; white-space:pre-line;
    opacity:0; transform:translateY(14px);
    transition:opacity .8s ease, transform .9s cubic-bezier(.16,1,.3,1);
  }
  .contacto-overlay.contenido .co-phrase{ opacity:1; transform:none; transition-delay:.52s; }
  .co-form{
    display:flex; flex-direction:column; gap:30px; max-width:640px;
    opacity:0; transform:translateY(14px);
    transition:opacity .8s ease, transform .9s cubic-bezier(.16,1,.3,1);
  }
  .contacto-overlay.contenido .co-form{ opacity:1; transform:none; transition-delay:.6s; }

  /* ====== PREGUNTAS FRECUENTES (banda gris, texto blanco) ====== */
  .co-faq{
    background:#3b3b3b; color:#f1f1f1;
    padding:72px 30px 88px;
  }
  .cf-title{
    margin:0 0 54px;
    font-size:clamp(56px, 4.8vw, 92px); font-weight:300; line-height:1.05;
    letter-spacing:-.02em; color:#ffffff;
  }
  .cf-list{ max-width:920px; }
  .cf-item{ position:relative; border-top:1.5px solid #f1f1f1; }
  .cf-item:last-child{ border-bottom:1.5px solid #f1f1f1; }

  /* ====== RESALTE DE FILA AL PASAR EL CURSOR ======
     Una capa que cubre EXACTO el ancho y el alto entre divisorias y entra
     subiendo desde abajo (rápida y suave), con el texto invirtiendo su color
     por encima; solo mientras hay cursor. Lo usan las preguntas de las FAQ de
     contacto y las entradas del desplegable de servicios: entre un anfitrión y
     otro lo ÚNICO que cambia son estas dos variables, así que el mecanismo se
     escribe una sola vez. La capa deja fuera el borde (queda en el margen del
     padding-box), de modo que la divisoria sigue viéndose durante el resalte.
     Ese mismo inset:0 sobre la caja de padding es lo que la deja INMUNE al
     padding-left que alinear() escribe en las entradas del desplegable: la caja
     de padding crece con él, así que la capa sigue cubriendo la fila entera,
     de borde a borde, y no solo el hueco del texto. */
  .cf-item{ --hl-capa:#f4f4f2; --hl-tinta:#1d1d1c; }
  .cf-item::before,
  .tb-serv-menu a::before,
  .cs-campo::before,
  .cs-principal::before,
  .pk-tabla .pk-incl::before,
  .pk-tabla .pk-excl::before{
    content:""; position:absolute; inset:0; background:var(--hl-capa);
    transform:scaleY(0); transform-origin:bottom;
    transition:transform .32s cubic-bezier(.16,1,.3,1);
    pointer-events:none;
  }
  .cf-item:hover::before,
  .tb-serv-menu a:hover::before,
  .cs-campo:hover::before,
  .cs-principal:hover::before{ transform:scaleY(1); }
  /* los packs de vigilancia tinen la COLUMNA entera: se pasa el cursor por
     cualquier celda de un pack (cabecera y enlace incluidos) y suben las capas
     de todas las celdas con estado de su columna */
  .pk-tabla:has(tr > :nth-child(2):hover) tr > :nth-child(2)::before,
  .pk-tabla:has(tr > :nth-child(3):hover) tr > :nth-child(3)::before,
  .pk-tabla:has(tr > :nth-child(4):hover) tr > :nth-child(4)::before{ transform:scaleY(1); }
  .cf-q{
    position:relative; z-index:1;
    display:flex; align-items:center; justify-content:space-between; gap:40px;
    width:100%; margin:0; padding:16px 12px;
    background:none; border:none; cursor:pointer; text-align:left;
    font-family:inherit; font-size:18px; font-weight:400; line-height:1.3;
    color:#ffffff;
    transition:color .22s ease;
  }
  .cf-item:hover .cf-q{ color:var(--hl-tinta); }
  .cf-plus{ position:relative; width:14px; height:14px; flex:none; transition:transform .5s cubic-bezier(.16,1,.3,1); }
  .cf-plus::before, .cf-plus::after{ content:""; position:absolute; background:currentColor; }
  .cf-plus::before{ left:0; top:6.25px; width:14px; height:1.5px; }
  .cf-plus::after{ left:6.25px; top:0; width:1.5px; height:14px; }
  .cf-item.abierta .cf-plus{ transform:rotate(45deg); }
  .cf-a{
    position:relative; z-index:1;
    max-height:0; overflow:hidden;
    transition:max-height .7s cubic-bezier(.16,1,.3,1);
  }
  .cf-a p{
    margin:0; padding:2px 12px 24px; max-width:740px;
    font-size:16px; line-height:1.6; color:#cfcfcf;
    transition:color .22s ease;
  }
  .cf-item:hover .cf-a p{ color:var(--hl-tinta); }
  .co-row{ display:grid; grid-template-columns:1fr 1fr; gap:36px; }
  .co-field{ display:flex; flex-direction:column; }
  .co-field label{ font-size:18px; color:#1d1d1c; margin-bottom:12px; }
  .co-field input, .co-field textarea{
    font-family:inherit; font-size:19px; color:#1d1d1c;
    background:none; border:1px solid #1d1d1c; border-radius:4px;
    padding:16px 17px; outline:none; resize:none;
    transition:border-color .2s ease;
  }
  .co-field textarea{ min-height:180px; }
  .co-field input:focus, .co-field textarea:focus{ border-color:var(--red-core); }
  .co-field .req{ color:var(--red-core); }
  .co-field select{
    font-family:inherit; font-size:19px; color:#1d1d1c;
    background:none; border:1px solid #1d1d1c; border-radius:4px;
    padding:16px 48px 16px 17px; outline:none; cursor:pointer;
    transition:border-color .2s ease;
    appearance:none; -webkit-appearance:none;
    background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%231d1d1c' stroke-width='1.5'/></svg>");
    background-repeat:no-repeat; background-position:right 18px center;
  }
  .co-field select:focus{ border-color:var(--red-core); }
  .co-field select:invalid{ color:#6b6b6a; }
  .co-field select option{ color:#1d1d1c; }
  .co-flabel{ font-size:18px; color:#1d1d1c; margin-bottom:14px; }
  .co-radios{ display:flex; gap:34px; }
  .co-radio{ display:inline-flex; align-items:center; gap:10px; font-size:18px; cursor:pointer; }
  .co-radio input{ position:absolute; opacity:0; pointer-events:none; }
  .co-radio .rd{
    width:18px; height:18px; border:1.5px solid #1d1d1c; border-radius:50%;
    display:inline-block; position:relative; flex:none; transition:border-color .2s ease;
  }
  .co-radio .rd::after{
    content:""; position:absolute; inset:3.5px; border-radius:50%;
    background:#1d1d1c; transform:scale(0); transition:transform .25s cubic-bezier(.16,1,.3,1);
  }
  .co-radio input:checked + .rd::after{ transform:scale(1); }
  .co-field.err .rd{ border-color:var(--red-core); }
  .co-actions{ display:flex; align-items:center; gap:24px; flex-wrap:wrap; margin-top:6px; }
  .co-submit{
    display:inline-flex; align-items:center; gap:12px;
    background:#1d1d1c; color:#ffffff; border:0; cursor:pointer; border-radius:4px;
    font-family:inherit; font-size:19px; line-height:1; padding:19px 38px;
    transition:background .25s ease;
  }
  .co-submit:hover{ background:var(--red-core); }
  .co-note{ font-size:15px; color:#3b3b3b; opacity:0; transition:opacity .4s ease; }
  .co-note.visible{ opacity:1; }

  /* ====== PÁGINAS LEGALES (privacidad / aviso legal) ====== */
  .legal-overlay{
    position:fixed; inset:0; z-index:900; background:#f1f1f1;
    font-family:'Figtree',Arial,sans-serif; color:#1d1d1c;
    opacity:0; visibility:hidden; pointer-events:none;
    transition:opacity .45s ease, visibility 0s linear .45s;
    overflow-y:auto; -webkit-overflow-scrolling:touch;
  }
  .legal-overlay.abierto{ opacity:1; visibility:visible; pointer-events:auto; transition:opacity .45s ease; }
  .legal-top{
    position:sticky; top:0; z-index:2; height:56px; background:#f1f1f1;
    border-bottom:1.5px solid #1d1d1c;
    display:flex; align-items:center; justify-content:space-between;
  }
  .legal-sim{ width:88px; height:100%; border-right:1.5px solid #1d1d1c; display:flex; align-items:center; justify-content:center; flex:none; }
  .legal-sim svg{ width:auto; height:24px; display:block; }
  .legal-close{ width:60px; height:56px; background:none; border:0; cursor:pointer; position:relative; flex:none; }
  .legal-close::before, .legal-close::after{ content:""; position:absolute; left:50%; top:50%; width:24px; height:1.5px; background:#1d1d1c; }
  .legal-close::before{ transform:translate(-50%,-50%) rotate(45deg); }
  .legal-close::after{ transform:translate(-50%,-50%) rotate(-45deg); }
  .legal-doc{ max-width:820px; margin:0 auto; padding:60px 34px 120px; text-align:left; }
  .legal-doc .legal-h1{ font-size:clamp(44px,6vw,86px); font-weight:300; letter-spacing:-.02em; line-height:.96; margin:0 0 10px; }
  .legal-upd{ font-size:14px; color:#3b3b3b; margin:0 0 44px; padding-top:26px; letter-spacing:.02em; }
  .legal-doc h2{ font-size:clamp(19px,1.7vw,24px); font-weight:700; margin:44px 0 12px; letter-spacing:0; scroll-margin-top:76px; }
  .legal-doc p, .legal-doc li{ font-size:17px; line-height:1.62; font-weight:400; color:#1d1d1c; text-wrap:pretty; }
  .legal-doc ul{ margin:0 0 14px; padding-left:22px; }
  .legal-doc li{ margin:0 0 10px; }
  .legal-doc strong{ font-weight:700; }
  .legal-doc .legal-small{ font-size:13.5px; line-height:1.55; color:#3b3b3b; margin-top:44px; }
  .legal-doc p{ margin:0 0 14px; }
  .legal-doc a{ color:var(--red-core); text-decoration:underline; }
  .legal-fill{ background:#e2e2e2; padding:1px 7px; border-radius:3px; color:#555; }
  /* índice lateral (política de privacidad): columna fija + divisoria vertical */
  .legal-cols{ display:grid; grid-template-columns:340px 1fr; align-items:stretch; }
  .legal-idx-col{ border-right:1.5px solid #1d1d1c; }
  .legal-idx{ position:sticky; top:56px; padding:52px 30px 52px 34px; display:flex; flex-direction:column; }
  .legal-nav{ position:relative; }
  .legal-idx-t{ margin:0 0 26px; font-size:11px; letter-spacing:.16em; text-transform:uppercase; color:#8a8a89; font-weight:400; }
  .legal-idx a{ position:relative; display:block; padding:8px 0; font-size:15px; line-height:1.4; font-weight:300; color:#6b6b6a; text-decoration:none; transition:color .35s ease; }
  .legal-idx a:hover{ color:var(--red-core); }
  .legal-idx a.activo{ color:#1d1d1c; font-weight:400; }
  @media (max-width:820px){
    .legal-cols{ grid-template-columns:1fr; }
    .legal-idx-col{ border-right:0; border-bottom:1.5px solid #1d1d1c; }
    .legal-idx{ position:static; padding:26px 20px 22px; }
    .legal-idx a{ padding:10px 0; font-size:16px; }
    .legal-doc{ padding:34px 20px 90px; }
    .legal-doc .legal-h1{ font-size:clamp(38px, 11.5vw, 44px); }
    .legal-upd{ padding-top:18px; margin-bottom:34px; }
    .legal-doc h2{ font-size:19px; margin:36px 0 10px; scroll-margin-top:72px; }
    .legal-doc p, .legal-doc li{ font-size:16px; overflow-wrap:anywhere; }
    .legal-sim{ width:72px; }
  }

  /* información básica + consentimiento del formulario */
  .co-basic{
    margin:4px 0 18px; padding:0; border:0;
    font-size:11.5px; line-height:1.5; color:#3b3b3b;
  }
  .co-basic strong{ color:#1d1d1c; font-weight:400; }
  .co-basic a{ color:var(--red-core); text-decoration:underline; }
  .co-consent{ display:flex; align-items:flex-start; gap:14px; margin:0 0 4px; cursor:pointer; }
  .co-consent input{
    appearance:none; -webkit-appearance:none; width:22px; height:22px; margin-top:0; flex:none; cursor:pointer;
    background:transparent; border:1.5px solid #1d1d1c; border-radius:3px; display:grid; place-content:center;
    transition:background .25s ease, border-color .25s ease;
  }
  .co-consent input::before{
    content:''; width:11px; height:11px; transform:scale(0); transition:transform .2s cubic-bezier(.16,1,.3,1);
    clip-path:polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); background:#f1f1f1;
  }
  .co-consent input:checked{ background:#1d1d1c; }
  .co-consent input:checked::before{ transform:scale(1); }
  .co-consent input:focus-visible{ outline:1.5px solid var(--red-core); outline-offset:2px; }
  .co-consent span{ font-size:15px; line-height:1.5; color:#1d1d1c; }
  .co-consent a{ color:var(--red-core); text-decoration:underline; }
  .co-consent.err input{ border-color:var(--red-core); }
  .co-consent.err span{ color:var(--red-core); }
  .co-err{ display:none; font-size:13px; color:var(--red-core); margin-top:6px; }
  .co-field.err .co-err, .co-consent-wrap.err .co-err{ display:block; }
  .co-submit.enviado{ background:#1e7d3c; }
  .co-submit.enviado:hover{ background:#1e7d3c; }

  @media (max-width:1000px){
    .co-body{ grid-template-columns:1fr; gap:40px; padding:44px 20px 72px; }
    .co-row{ grid-template-columns:1fr; }
    .co-nav, .co-tbsep{ display:none; }
    .co-faq{ padding:64px 20px 80px; }
    .co-email{ display:none; }
  }

  /* ====== OVERLAY SOBRE NOSOTROS / FILOSOFÍA ======
     Capa fija a pantalla completa, gris oscuro. La abren los enlaces
     SOBRE NOSOTROS de la topbar/menú/footer. No toca el motor de scroll. */
  .nosotros-overlay{
    position:fixed; inset:0; z-index:200;
    background:#3b3b3b;
    color:#f1f1f1;
    font-family:'Figtree',Arial,sans-serif;
    opacity:0; visibility:hidden; pointer-events:none;
    transition:visibility .01s;
    overflow:hidden;
  }
  .nosotros-overlay.abierto{ opacity:1; visibility:visible; pointer-events:auto; }

  /* topbar gris oscuro sólido (igual que el fondo del overlay): símbolo y nav
     en blanco, sin tagline ni cristal esmerilado. */
  .no-topbar{
    position:absolute; top:0; left:0; right:0; height:56px; z-index:3;
    background:#3b3b3b;
    transition:background .45s ease;
  }
  /* línea inferior de la topbar: se dibuja de izquierda a derecha */
  .no-topbar::after{
    content:""; position:absolute; left:0; bottom:0; width:100%; height:0;
    border-bottom:1.5px solid #ffffff; clip-path:inset(0 100% 0 0);
    transition:clip-path 1.1s cubic-bezier(.33,0,.2,1);
    transition-delay:0s;
  }
  .nosotros-overlay.lineas .no-topbar::after{ clip-path:inset(0 0 0 0); }
  /* topbar BLANCA: cuando el bloque blanco la alcanza al final del scroll */
  .no-topbar.claro{ background:#ffffff; }
  .no-topbar.claro::after{ border-bottom-color:#1d1d1c; transition:border-color .45s ease; }
  .no-topbar.claro .no-simbolo::after{ border-right-color:#1d1d1c; transition:border-color .45s ease; }
  .no-topbar.claro .no-simbolo svg path{ fill:#1d1d1c; }
  .no-topbar.claro .no-nav a{ color:#1d1d1c; }
  /* logo "intharis" a la izquierda, centrado, con divisoria vertical (blanco) */
  .no-simbolo{
    position:absolute; left:0; top:0; height:100%; width:128px; box-sizing:border-box;
    display:flex; align-items:center; justify-content:center;
    transform:none;
  }
  /* divisoria derecha del logo: se dibuja de arriba a abajo */
  .no-simbolo::after{
    content:""; position:absolute; right:0; top:0; height:100%; width:0;
    border-right:1.5px solid #ffffff; clip-path:inset(0 0 100% 0);
    transition:clip-path 1.1s cubic-bezier(.33,0,.2,1);
    transition-delay:0s;
  }
  .nosotros-overlay.lineas .no-simbolo::after{ clip-path:inset(0 0 0 0); }
  .no-simbolo svg{ width:auto; height:21px; display:block; opacity:0; transition:opacity .95s ease, fill .45s ease; transition-delay:.4s; }
  .nosotros-overlay.contenido .no-simbolo svg{ opacity:1; }
  .no-simbolo svg path{ fill:#ffffff; transition:fill .45s ease; }
  .no-tagline{ display:none; }
  .no-nav{
    position:absolute; left:128px; top:0; height:100%;
    display:flex; align-items:center; gap:30px; padding-left:28px;
    font-size:20px;
  }
  .no-nav a{
    color:#ededed; text-decoration:none; text-transform:lowercase;
    display:inline-flex; align-items:center; gap:9px;
    opacity:0; transform:translateY(6px);
    transition:opacity .9s ease, transform 1s cubic-bezier(.16,1,.3,1), color .45s ease;
  }
  /* las secciones salen en orden de izquierda a derecha */
  .nosotros-overlay.contenido .no-nav a{ opacity:1; transform:none; }
  .nosotros-overlay.contenido .no-nav a:nth-child(1){ transition-delay:.4s, .4s, 0s; }
  .nosotros-overlay.contenido .no-nav a:nth-child(2){ transition-delay:.5s, .5s, 0s; }
  .nosotros-overlay.contenido .no-nav a:nth-child(3){ transition-delay:.6s, .6s, 0s; }
  .no-nav a::before{
    content:""; width:9px; height:9px; flex:none;
    background:currentColor; opacity:.42;
    clip-path:polygon(0 0, 100% 0, 0 100%);
    transition:opacity .3s ease;
  }
  .no-nav a:hover{ color:#ffffff; }
  .no-nav a.activo{ color:#ffffff; }
  .no-nav a.activo::before{ opacity:1; }

  /* "about" gigante arriba-izquierda. Las letras las anima el JS al abrir. */
  .no-about{
    position:absolute; left:34px; top:38px;
    margin:0; font-size:min(26vw, 380px); line-height:.9; font-weight:300;
    color:#ffffff; letter-spacing:-.02em;
  }
  .no-about .lt{ display:inline-block; overflow:hidden; padding-top:.14em; margin-top:-.14em; vertical-align:top; }
  .no-about .lt-in{ display:inline-block; will-change:transform; }

  /* columna derecha: imagen + título + texto, divisoria a su izquierda.
     Ancho fijo ~33.5% del viewport, como la retícula de atoll. */
  .no-col{
    position:absolute; top:56px; right:0; bottom:0; width:33.5%;
    padding:24px 40px 24px 40px;
    display:flex; flex-direction:column;
    box-sizing:border-box;
  }
  /* divisoria izquierda de la columna: se dibuja de arriba a abajo */
  .no-col::before{
    content:""; position:absolute; left:var(--divX,0); top:0; height:100%; width:1.5px;
    background:#ffffff; clip-path:inset(0 0 100% 0);
    transition:clip-path 1.1s cubic-bezier(.33,0,.2,1);
    transition-delay:0s;
  }
  .nosotros-overlay.lineas .no-col::before{ clip-path:inset(0 0 0 0); }
  .no-video{
    position:relative; aspect-ratio:16/9.4; flex:none;
    width:auto; margin:0 -16px 0 -16px;
    display:grid; place-items:center;
    opacity:0; transform:none;
    transition:opacity .95s ease;
    transition-delay:.44s;
  }
  .nosotros-overlay.contenido .no-video{ opacity:1; transform:none; }
  .no-sym{ display:none; }
  .no-ssym{
    position:absolute; left:-150px; top:120px; width:96px; height:54px;
    opacity:0; pointer-events:none; z-index:2;
  }
  .no-ssym svg{ width:100%; height:100%; display:block; }
  .no-ssym svg path{ fill:#ffffff; }
  .no-sym svg{ width:100%; height:100%; display:block; }
  .no-sym svg path{ fill:#ffffff; }
  .no-vlabel{
    position:absolute; left:0; bottom:0; margin:0;
    font-size:clamp(40px,3.1vw,62px); font-weight:300; color:#ffffff;
    letter-spacing:-.005em; transform-origin:left bottom; pointer-events:none;
    clip-path:inset(0 100% 0 0);
    transition:clip-path .9s cubic-bezier(.16,1,.3,1);
    transition-delay:.45s;
  }
  /* la pregunta se revela con máscara de recorte de IZQUIERDA a DERECHA */
  .nosotros-overlay.contenido .no-vlabel{ clip-path:inset(0 0 0 0); }
  .no-col-title{
    position:relative;
    margin:24px -40px 0 -40px; padding:24px 24px 0 24px;
    font-size:clamp(38px, 2.55vw, 50px); line-height:1.08; font-weight:500; color:#ffffff;
    letter-spacing:-.015em; text-wrap:balance;
  }
  /* divisoria superior del título: se dibuja de izquierda a derecha */
  .no-col-title::before{
    content:""; position:absolute; left:var(--hbx,0); right:0; top:var(--hby,0px); height:1.5px;
    background:#ffffff; clip-path:inset(0 100% 0 0);
    transition:clip-path 1.1s cubic-bezier(.33,0,.2,1);
    transition-delay:0s;
  }
  .nosotros-overlay.lineas .no-col-title::before{ clip-path:inset(0 0 0 0); }
  .no-col-title .ct-in{
    display:block; opacity:0; transform:translateY(60px);
    transition:opacity 1.2s ease, transform 1.35s cubic-bezier(.16,1,.3,1);
    transition-delay:.52s;
  }
  .nosotros-overlay.contenido .no-col-title .ct-in{ opacity:1; transform:none; }
  .no-col-text{
    margin:auto -16px 0 -16px;
    font-size:18px; line-height:1.5; font-weight:400; color:#ffffff; text-wrap:normal;
    opacity:0; transform:translateY(72px);
    transition:opacity 1.2s ease, transform 1.35s cubic-bezier(.16,1,.3,1);
    transition-delay:.6s;
  }
  .nosotros-overlay.contenido .no-col-text{ opacity:1; transform:none; }
  /* flecha diagonal abajo-izquierda */
  .no-arrow{
    position:absolute; left:34px; bottom:34px; width:54px; height:54px; color:#ffffff;
    transform-origin:0% 100%;
    opacity:0; transform:translateY(6px);
    transition:opacity .95s ease, transform 1.05s cubic-bezier(.16,1,.3,1);
    transition-delay:.67s;
  }
  .nosotros-overlay.contenido .no-arrow{ opacity:1; transform:none; }
  .no-arrow svg{ width:100%; height:100%; display:block; transform:rotate(135deg); }
  /* flecha GRANDE a la IZQUIERDA del párrafo derecho ("Con nosotros…") */
  .no-vbody-arrow{
    position:absolute; left:calc(100vw - 34px - min(38vw, 600px) - 200px);
    top:calc(68vh + 175px + 311px + 300px + 100px + 172px + 80px);
    z-index:2;
    width:auto; height:auto; color:#1d1d1c;
    display:flex; align-items:center; justify-content:center;
  }
  .no-vbody-arrow > svg{ flex:none; width:66px; height:66px; display:block; overflow:visible; }
  /* envoltorio desplazable: tras la animación, el scroll continúa hacia el
     bloque blanco de abajo (la sección sigue hacia abajo). */
  .no-scroll{ position:absolute; inset:0; will-change:transform; }
  /* bloque blanco puro: continúa la sección por DEBAJO (no sube). */
  .no-white{
    position:absolute; top:calc(100% + 90px); left:0; width:100%; height:600%;
    background:#ffffff; z-index:1;
  }
  /* "valores" gigante, misma posición y tamaño que "about" pero en el blanco */
  .no-valores{
    position:absolute; left:34px; top:38px;
    margin:0; font-size:min(26vw, 380px); line-height:.9; font-weight:300;
    color:#1d1d1c; letter-spacing:-.02em;
  }
  /* bloque inferior: símbolo de Intharis + texto a su derecha (estilo atoll) */
  .no-vfoot-tag{
    position:absolute; left:0; top:-34px;
    font-size:13px; letter-spacing:.04em; color:#1d1d1c; pointer-events:none;
  }
  .no-vfoot{
    position:absolute; right:80px; top:68vh; bottom:auto; width:660px;
    display:flex; align-items:center; gap:26px;
  }
  .no-vfoot-sym{ flex:none; width:152px; height:152px; display:flex; align-items:center; justify-content:center; align-self:flex-start; margin-top:-16px; margin-right:-48px; }
  .no-vfoot-sym svg{ width:100%; height:100%; display:block; }
  .no-vfoot-text{
    margin:0; font-size:18px; line-height:1.5; font-weight:400; color:#1d1d1c; text-wrap:pretty;
  }
  /* tres filas con línea divisoria superior (estilo referencia): la divisoria
     deja 15px con el borde derecho y llega por la izquierda a la altura de la
     flecha (borde izq del bloque símbolo+texto). */
  .no-vlist{
    position:absolute; left:calc(100% - 740px); right:15px; top:calc(68vh + 175px);
    will-change:transform;
  }
  /* REPOSO COMPACTO: cada título entre sus divisorias a 25px. Con el scroll, la
     propia divisoria (todas 1.5px idénticas) se extiende a la izquierda y la
     fila se expande revelando el texto (solo por opacidad). */
  .no-vrow{ position:relative; }
  .no-vline{
    position:absolute; top:0; right:0; height:0; border-top:1.5px solid #1d1d1c;
    left:calc(-1 * (100vw - 750px) * var(--open, 0));
  }
  .no-vbottom{ position:absolute; top:auto; bottom:0; }
  .no-vtitle{
    padding:25px 0; margin:0;
    font-size:clamp(34px, 2.7vw, 50px); line-height:1; font-weight:400;
    color:#1d1d1c; letter-spacing:-.015em;
    text-box-trim:trim-both; text-box-edge:cap alphabetic;
  }
  .no-vdesc{
    margin:0; overflow:hidden; max-height:calc(var(--open, 0) * 210px);
    padding:0; max-width:560px;
    font-size:18px; line-height:1.5; font-weight:400; color:#1d1d1c; text-wrap:pretty;
    opacity:var(--open, 0);
  }
  .no-vdesc span{ display:block; padding:66px 0 25px; }

  /* frase grande a la izquierda, después de los bloques */
  .no-vphrase{
    position:absolute; left:37px; top:calc(68vh + 175px + 281px + 80px); width:calc(52vw - 34px);
    z-index:2;
    margin:0; font-size:clamp(48px, 4.1vw, 80px); line-height:1.1; font-weight:400;
    text-indent:2.55em;
    color:#1d1d1c; letter-spacing:-.02em; text-wrap:pretty;
  }
  /* párrafo pequeño a la derecha y un poco más abajo de la frase */
  .no-vbody{
    position:absolute; right:34px; left:auto; top:calc(68vh + 175px + 311px + 300px + 100px + 80px); width:min(38vw, 600px);
    z-index:2;
    margin:0; font-size:18px; line-height:1.6; font-weight:400;
    color:#1d1d1c; text-wrap:pretty;
  }
  /* botón Contáctanos (esquinas marcadas, bajo el párrafo derecho) */
  .no-vcta{
    display:none !important;
    position:absolute; left:calc(100vw - 34px - min(38vw, 600px) - 16px); right:auto; top:calc(68vh + 175px + 311px + 300px + 164px + 80px);
    align-items:center; gap:12px;
    padding:14px 26px; border:1.5px solid #1d1d1c; border-radius:0;
    font-size:16px; letter-spacing:.01em; color:#1d1d1c; text-decoration:none;
    background:transparent; transition:background .25s ease, color .25s ease;
  }
  .no-vcta:hover{ background:#1d1d1c; color:#ffffff; }
  .no-vphrase-tag{
    position:absolute; left:7px; top:3.1em; transform:none;
    text-indent:0; font-size:13px; letter-spacing:.04em; font-weight:400;
    color:#1d1d1c; pointer-events:none;
  }
  /* animación de la frase: cada línea sube desde una máscara de recorte.
     El reveal lo dispara UNA clase en el padre (.revelado); el escalonado va
     por --i. Se usa @keyframes (no transition) para que el play sea fiable. */
  @keyframes noLnUp { from{ transform:translateY(115%); } to{ transform:translateY(0); } }
  .no-vphrase .no-ln{ display:block; overflow:hidden; padding-bottom:.2em; margin-bottom:-.2em; }
  .no-vphrase .no-ln-in{
    display:block; transform:translateY(115%);
  }
  .no-vphrase.revelado .no-ln-in{
    animation:noLnUp .8s cubic-bezier(.16,1,.3,1) both;
    animation-delay:calc(var(--i, 0) * .07s);
  }
  /* Pie replicado (cierre + footer) al final del bloque blanco, a escala real
     1920→ancho de viewport: idéntico a la página de inicio. */
  .no-footwrap{
    position:absolute; left:0; top:calc(68vh + 1010px + 110px);
    width:1920px; transform-origin:top left; transform:scale(var(--fs, .75));
  }
  .no-footwrap .nf-cierre{ position:relative; width:1920px; height:1080px; overflow:hidden; background:#ffffff; }
  .no-footwrap .nf-footer{ position:relative; width:1920px; height:740px; }
  /* polvo de puntos IDÉNTICO al de inicio: copia el lienzo #polvo cada frame,
     fijo en pantalla y en modo multiplicar → solo se ve sobre lo BLANCO (bloque
     blanco + cierre), y desaparece sobre los grises, igual que en la home. */
  .no-polvo{
    position:fixed; inset:0; width:100%; height:100%; pointer-events:none;
    image-rendering:pixelated; mix-blend-mode:multiply; z-index:2;
    opacity:0; transition:opacity .4s ease;
  }
  .nosotros-overlay.abierto .no-polvo{ opacity:.26; }

  @media (max-width:1100px){
    .no-tagline, .no-nav{ display:none; }
    .nosotros-overlay{ overflow-y:auto; }
    .no-col{ position:static; width:100%; border-left:0; border-top:1.5px solid #ffffff; margin-top:230px; }
    .no-about{ font-size:88px; top:74px; }
    .no-arrow{ display:none; }
  }
  /* ====== BLOG (páginas reales, sin app.js) ======
     PROVISIONAL: esto es solo lo que hace falta para que las páginas no salgan
     rotas mientras se monta la maquinaria. El diseño va aparte.
     La topbar de estas páginas lleva `visible` escrita en el markup: la clase la
     pone normalmente el motor de scroll (`y > 400`), que aquí no corre, y sin
     ella la barra se queda en translateY(-101%), fuera de pantalla. Como va
     fija, el contenido tiene que empezar por debajo de sus 56px. */
  body.blog{ background:#ffffff; }
  .blog-main{
    max-width:760px; margin:0 auto;
    padding:calc(56px + 72px) 24px 120px;
    font-size:18px; line-height:1.6;
  }
  .blog-titulo, .post-titulo{ font-weight:300; font-size:56px; line-height:1.05; margin:0 0 18px; }
  .blog-entradilla, .post-entradilla{ font-size:20px; color:#3b3b3b; margin:0 0 56px; }
  .post-meta{ font-size:15px; color:#3b3b3b; margin:0 0 18px; }
  .post-meta a{ color:#3b3b3b; }
  .post-cuerpo h2{ font-weight:400; font-size:28px; margin:48px 0 14px; }
  .post-cuerpo p, .post-cuerpo ul{ margin:0 0 20px; }
  .post-cuerpo ul{ padding-left:22px; }
  .post-cuerpo li{ margin-bottom:10px; }
  .post-volver{ margin-top:72px; border-top:1.5px solid #1d1d1c; padding-top:24px; }
  .blog-lista{ list-style:none; margin:0; padding:0; }
  .blog-item{ border-top:1.5px solid #1d1d1c; }
  .blog-item:last-child{ border-bottom:1.5px solid #1d1d1c; }
  .blog-item a{ display:block; padding:28px 0; color:inherit; text-decoration:none; }
  .blog-item time{ font-size:15px; color:#3b3b3b; }
  .blog-item h2{ font-weight:400; font-size:30px; line-height:1.15; margin:8px 0 10px; }
  .blog-item p{ margin:0; color:#3b3b3b; }
  /* ---- La topbar del blog en móvil ----
     No se puede reutilizar tal cual: el recuadro de 128px del logotipo y la nav
     de 20px con sus triangulitos suman 555px de contenido, más del ancho entero
     de un teléfono. Se recompone en una fila flex, con las medidas de
     .m2-topbar, que es la barra móvil de la casa: 54px de alto y el logotipo a
     16px. Lo que no se copia es su menú a pantalla completa, que aquí no hace
     falta para tres enlaces. */
  @media (max-width:820px){
    body.blog .topbar{
      display:flex; align-items:center; gap:16px;
      height:54px; padding:0 20px;
    }
    body.blog .topbar .tb-logo{
      position:static; width:auto; height:auto; flex:none; border-right:0;
    }
    body.blog .topbar .tb-logo svg{ height:16px; }
    body.blog .topbar nav{
      position:static; height:auto; padding-left:0;
      margin-left:auto; gap:16px; font-size:14px;
    }
    /* El triangulito de cada entrada son 18px (9 de glifo y 9 de separación),
       54 entre las tres: justo lo que falta para que quepan a 375. */
    body.blog .topbar nav a::before{ display:none; }
    body.blog .topbar nav a{ gap:0; }

    /* El hueco de arriba sigue a la barra: 54 de barra y 42 de aire, la misma
       proporción que los 56 + 72 del escritorio. */
    .blog-main{ padding:calc(54px + 42px) 20px 80px; font-size:17px; }
    .blog-titulo, .post-titulo{ font-size:38px; }
    .blog-entradilla, .post-entradilla{ font-size:18px; }
  }
  /* A 375 y 390 sobran 20px, pero a 320 la nav queda pegada al logotipo, sin más
     separación que el gap: ahí ya no hay holgura que perder. Y estas medidas se
     han tomado con Figtree, que es la que se sirve, así
     que el margen real es este. Un punto menos de cuerpo en las
     pantallas más estrechas devuelve el aire y quita el riesgo. */
  @media (max-width:359px){
    body.blog .topbar{ gap:12px; padding:0 16px; }
    body.blog .topbar nav{ gap:12px; font-size:13px; }
  }

  /* ====== VERSIÓN MÓVIL v2 (≤820px) ======
     Columna única y eficiente: mismas líneas de 1.5px, Figtree 300 en palabras
     grandes, revelados con máscara de recorte y curva cubic-bezier(.16,1,.3,1).
     Sin lienzos ni motores de scroll: IntersectionObserver + transiciones. */
  .movil{ display:none; }
  @media (min-width:820.1px){ .movil{ display:none !important; } }

  @media (max-width:820px){
    /* La topbar se esconde porque en la SPA la sustituye .m2-topbar, con su
       menú a pantalla completa. Las páginas del blog NO tienen columna móvil:
       son el mismo documento a cualquier ancho, así que ahí se queda o se
       quedarían sin logotipo y sin navegación. Recompuesta, más abajo. */
    body:not(.blog) .topbar, .viewport, #polvo, #aura{ display:none !important; }
    .legal-close{ display:none !important; }
    html{ scroll-behavior:smooth; }
    body{ background:transparent; cursor:auto; }
    .movil{ display:block; color:#1d1d1c; background:#f1f1f1; }

    /* ---- revelados (máscara de recorte) ---- */
    .r, .rh{ overflow:hidden; }
    .r > .r-in, .rh > .r-in{ display:block; transform:translateY(112%); transition:transform .9s cubic-bezier(.16,1,.3,1); }
    .r.vis > .r-in, .movil.in .rh > .r-in{ transform:none; }
    .m2-hr{ height:1.5px; background:#1d1d1c; transform:scaleX(0); transform-origin:left; transition:transform 1.05s cubic-bezier(.33,0,.2,1); }
    .m2-hr.vis, .movil.in .m2-hr.rh2{ transform:none; }
    .m2-hr.rh2{ transition-delay:.55s; }

    /* ---- topbar ---- */
    .m2-topbar{
      position:sticky; top:0; z-index:60; height:54px;
      background:#f1f1f1; border-bottom:1.5px solid #1d1d1c;
      display:flex; align-items:center; padding:0 20px;
    }
    .m2-marca{ line-height:0; }
    .m2-marca svg{ height:16px; width:auto; display:block; }

    /* ---- botón "=" (fijo; color opuesto al fondo por mezcla) ---- */
    .m2-igual{
      position:fixed; top:4px; right:10px; z-index:930;
      width:46px; height:46px; background:none; border:none; padding:0; cursor:pointer;
      display:flex; flex-direction:column; align-items:center; justify-content:center; gap:7px;
      mix-blend-mode:difference;
    }
    .m2-igual span{ display:block; width:28px; height:2px; background:#ffffff; transition:transform .45s cubic-bezier(.16,1,.3,1); }
    .m2-igual.abierto span:nth-child(1){ transform:translateY(4.5px) rotate(45deg); }
    .m2-igual.abierto span:nth-child(2){ transform:translateY(-4.5px) rotate(-45deg); }

    /* ---- menú a pantalla completa ---- */
    .m2-menu{
      position:fixed; inset:0; z-index:920; background:#3b3b3b; color:#f1f1f1;
      display:flex; flex-direction:column; padding:26px 20px 30px;
      opacity:0; visibility:hidden; pointer-events:none;
      transition:opacity .4s ease, visibility 0s .4s;
    }
    .m2-menu.abierto{ opacity:1; visibility:visible; pointer-events:auto; transition:opacity .4s ease; }
    .m2-menu-marca{ line-height:0; margin:8px 0 40px; }
    .m2-menu-marca svg{ height:24px; width:auto; display:block; }
    .m2-menu-marca svg path{ fill:#f1f1f1; }
    .m2-menu nav{ border-top:1.5px solid #f1f1f1; }
    /* Solo las entradas de primer nivel: el desplegable de servicios mete un
       bloque entre medias y sus enlaces llevan su propio tamaño. Por eso el
       escalonado va por nth-of-type y no por nth-child: así no se descuadra
       al intercalar ese bloque, que no es un <a>. */
    /* Tipografía y caja de las entradas de primer nivel. "servicios" va dentro
       de una .m2-fila porque comparte renglón con el botón del desplegable. */
    .m2-menu nav > a,
    .m2-menu nav .m2-fila > a{
      display:block; padding:19px 0;
      color:#f1f1f1; text-decoration:none;
      font-size:clamp(34px, 9.6vw, 44px); font-weight:300; letter-spacing:-.01em;
    }
    /* La línea y la aparición van en el RENGLÓN, no en el enlace: en servicios
       el renglón lleva además el botón, y una línea puesta en el enlace se
       quedaría corta. */
    .m2-menu nav > a,
    .m2-menu nav .m2-fila{
      border-bottom:1.5px solid #f1f1f1;
      opacity:0; transform:translateY(16px);
      transition:opacity .45s ease, transform .55s cubic-bezier(.16,1,.3,1);
    }
    .m2-menu nav .m2-fila{ display:flex; align-items:center; justify-content:space-between; }
    .m2-menu.abierto nav > a,
    .m2-menu.abierto nav .m2-fila{ opacity:1; transform:none; }
    /* El escalonado salta la .m2-fila, que no es un <a>: por eso lleva el suyo. */
    .m2-menu.abierto nav > a:nth-of-type(1){ transition-delay:.06s; }
    .m2-menu.abierto nav .m2-fila{ transition-delay:.12s; }
    .m2-menu.abierto nav > a:nth-of-type(2){ transition-delay:.18s; }
    .m2-menu.abierto nav > a:nth-of-type(3){ transition-delay:.24s; }
    /* ---- desplegable de servicios (móvil): acordeón, no hay hover ----
       Pulsar "servicios" no cierra el menú ni abre la página: despliega estas
       cinco entradas debajo. El alto lo mide el JS (scrollHeight) en vez de
       fijar un max-height a ojo, que se queda corto si cambia el copy. */
    .m2-menu nav .m2-serv-sub{
      overflow:hidden; max-height:0;
      transition:max-height .55s cubic-bezier(.16,1,.3,1);
    }
    .m2-menu nav .m2-serv-sub a{
      display:block; padding:14px 0 14px 20px;
      border-bottom:1.5px solid #f1f1f1;
      color:#f1f1f1; text-decoration:none;
      font-size:clamp(16px, 4.4vw, 19px); font-weight:400; letter-spacing:.01em;
      opacity:0; transform:translateY(10px);
      transition:opacity .4s ease, transform .5s cubic-bezier(.16,1,.3,1);
    }
    .m2-menu nav .m2-serv-sub.abierto a{ opacity:1; transform:none; }
    .m2-menu nav .m2-serv-sub.abierto a:nth-child(1){ transition-delay:.05s; }
    .m2-menu nav .m2-serv-sub.abierto a:nth-child(2){ transition-delay:.10s; }
    .m2-menu nav .m2-serv-sub.abierto a:nth-child(3){ transition-delay:.15s; }
    .m2-menu nav .m2-serv-sub.abierto a:nth-child(4){ transition-delay:.20s; }
    /* Botón "+" que se vuelve "−" al abrir: dos barras de 1.5px, como el "="
       del botón de menú. Nunca un background de 1.5px (borroso a DPR
       fraccionario). Es un <button> de verdad, no un trozo del enlace: así se
       tabula hasta él y un lector de pantalla lo anuncia como lo que es. Mide
       44px para que la zona de toque no se coma la de la palabra. */
    .m2-serv-mas{
      appearance:none; -webkit-appearance:none; background:none; border:0; padding:0;
      position:relative; width:44px; height:44px; flex:none; cursor:pointer;
    }
    .m2-serv-mas span{
      position:absolute; left:11px; top:50%; width:22px; height:0;
      border-top:1.5px solid #f1f1f1;
      transition:transform .45s cubic-bezier(.16,1,.3,1);
    }
    .m2-serv-mas span:nth-child(2){ transform:rotate(90deg); }
    .m2-serv-mas.abierto span:nth-child(2){ transform:rotate(0deg); }
    .m2-menu-pie{ margin-top:auto; display:flex; flex-wrap:wrap; gap:12px 24px; }
    .m2-menu-pie a{ color:#f1f1f1; text-decoration:none; font-size:13px; letter-spacing:.06em; }

    /* ---- intro de carga ---- */
    .m2-intro{ position:fixed; inset:0; z-index:950; background:#f1f1f1; transition:opacity .45s ease; }
    .m2-intro.fuera{ opacity:0; pointer-events:none; }
    .m2-intro-mask{ position:absolute; left:20px; bottom:30px; width:min(60vw, 300px); overflow:hidden; }
    .m2-intro-mask svg{ width:100%; height:auto; display:block; transform:translateY(112%); transition:transform 1s cubic-bezier(.16,1,.3,1); }
    .m2-intro.sube .m2-intro-mask svg{ transform:none; }


    /* ---- hero ---- */
    .m2-hero{
      min-height:calc(100vh - 54px); min-height:calc(100svh - 54px);
      box-sizing:border-box; display:flex; flex-direction:column;
      padding:22px 20px 18px; scroll-margin-top:54px;
    }
    .m2-logoWrap{ margin:auto 0; }
    .m2-logo{ display:block; }
    .m2-logo svg{ width:100%; height:auto; display:block; }
    .m2-claim{ margin:0 0 44px; font-size:clamp(23px, 6.4vw, 30px); line-height:1.34; font-weight:400; letter-spacing:.01em; }
    .m2-rotmask{ display:inline-block; overflow:hidden; vertical-align:bottom; }
    .m2-rot{ display:inline-block; font-weight:700; }
    .m2-tagline{ margin:0 0 14px; font-size:12.5px; letter-spacing:.08em; }

    /* ---- about (gris) ---- */
    .m2-about{ background:#3b3b3b; color:#f1f1f1; padding:64px 20px 58px; scroll-margin-top:54px; }
    .m2-abouttext{ margin:0; font-size:clamp(21px, 5.9vw, 26px); line-height:1.42; font-weight:400; text-wrap:pretty; }
    .m2-trazo{ margin:52px 0 0; }
    .m2-trazo svg{ width:100%; height:auto; display:block; }
    .m2-trazo svg path{ stroke:#82827f; stroke-width:3; }

    /* ---- factor humano ---- */
    .m2-fh{ padding:60px 20px 6px; scroll-margin-top:54px; }
    .m2-fhclaim{ margin:26px 0 0; font-size:clamp(27px,8vw,40px); line-height:1.16; font-weight:500; letter-spacing:-.02em; text-wrap:balance; }
    .m2-fhtext{ margin:34px 0 0; font-size:clamp(16px,4.4vw,18px); line-height:1.5; font-weight:400; text-wrap:pretty; }
    .m2-fhh{ border-top:1.5px solid #1d1d1c; margin:48px 0 6px; padding-top:26px; font-size:clamp(20px,5.8vw,25px); line-height:1.28; font-weight:400; letter-spacing:-.01em; }
    .m2-fhdato{ margin:40px 0 0; font-size:clamp(23px,6.8vw,30px); line-height:1.22; font-weight:300; letter-spacing:-.02em; }
    .m2-fhdato .pf-ac{ color:var(--red-core); }
    .m2-fhdatofuente{ display:block; margin-top:12px; font-size:12px; letter-spacing:.05em; text-transform:uppercase; color:#3b3b3b; font-weight:400; }
    /* Bloque único (Phishing): asume el margen superior que daba el rótulo. */
    .m2-fh .m2-svc{ margin-top:44px; }
    .m2-fh .m2-svc:last-of-type{ padding-bottom:8px; }
    .m2-fhgt{ border-top:1.5px solid #1d1d1c; margin:36px 0 0; padding-top:30px; font-size:clamp(27px,8vw,36px); line-height:1.05; font-weight:500; letter-spacing:-.02em; }
    .m2-fhglabel{ margin:30px 0 0; font-size:13px; font-weight:400; color:#1d1d1c; letter-spacing:.06em; }
    .m2-fhcta{ display:inline-flex; align-items:center; gap:.5em; margin:32px 0 0; padding:11px 18px; border:1.5px solid #1d1d1c; font-size:clamp(15px,4.2vw,16.5px); font-weight:400; color:#1d1d1c; text-decoration:none; }
    .m2-fhcta svg{ width:.9em; height:.9em; }
    .m2-fhclose{ margin:8px 0 0; font-size:clamp(16px,4.4vw,18px); line-height:1.5; font-weight:400; text-wrap:pretty; }
    .m2-fhbridge{ border-top:1.5px solid #1d1d1c; margin:48px 0 0; padding-top:28px; font-size:clamp(19px,5.6vw,24px); line-height:1.4; font-weight:400; letter-spacing:-.01em; color:#1d1d1c; text-wrap:balance; }
    .m2-fhbridge .pf-ac{ color:inherit; }

    /* ---- servicios ---- */
    .m2-serv{ padding:60px 20px 10px; scroll-margin-top:54px; }
    .m2-audit{ margin:0 0 34px; font-size:clamp(54px, 16vw, 84px); line-height:.98; font-weight:300; letter-spacing:-.02em; }
    .m2-svc{ border-top:1.5px solid #1d1d1c; padding:22px 0 30px; }
    .m2-svc .m2-sname{ margin:0 0 3px; font-size:26px; font-weight:400; letter-spacing:-.01em; }
    .m2-ssub{ margin:0 0 13px; font-size:12.5px; letter-spacing:.06em; text-transform:uppercase; color:#3b3b3b; }
    .m2-sdesc{ margin:0 0 20px; font-size:16.5px; line-height:1.55; font-weight:400; text-wrap:pretty; }
    .m2-svc img{ width:100%; aspect-ratio:16/10; object-fit:cover; display:block; }

    /* ---- metodología (gris) ---- */
    .m2-met{ background:#3b3b3b; color:#f1f1f1; padding:64px 20px 56px; }
    .m2-methead{ margin:0 0 40px; font-size:clamp(24px, 6.8vw, 31px); line-height:1.3; font-weight:400; text-wrap:pretty; }
    .m2-mp{ border-top:1.5px solid #f1f1f1; padding:20px 0 28px; }
    .m2-mp-top{ display:flex; justify-content:space-between; align-items:center; margin-bottom:12px; }
    .m2-mp-label{ margin:0; font-size:12.5px; letter-spacing:.06em; }
    .m2-mp-icon{ width:34px; height:34px; display:block; }
    .m2-mp-icon svg, .m2-mp-icon img{ width:100%; height:100%; display:block; }
    .m2-mp-big{ margin:0 0 8px; font-size:clamp(30px, 8.4vw, 38px); font-weight:300; letter-spacing:-.01em; }
    .m2-mp-desc{ margin:0; font-size:16px; line-height:1.5; font-weight:400; }

    /* ---- valores ---- */
    .m2-val{ padding:60px 20px 58px; }
    .m2-vintro{ display:flex; gap:16px; margin:0 0 44px; }
    .m2-vintro-sym{ display:block; width:42px; height:42px; flex:none; margin-top:2px; }
    .m2-vintro-sym svg{ width:100%; height:100%; display:block; }
    .m2-vintro p{ margin:0; font-size:17px; line-height:1.6; font-weight:400; text-wrap:pretty; }
    .m2-aaa{ margin:0 0 12px; font-size:12.5px; letter-spacing:.08em; color:#3b3b3b; }
    .m2-vrow{ border-top:1.5px solid #1d1d1c; padding:20px 0 26px; }
    .m2-vrow h3{ margin:0 0 8px; font-size:22px; font-weight:400; letter-spacing:-.01em; }
    .m2-vrow p{ margin:0; font-size:16px; line-height:1.55; font-weight:400; }
    .m2-why{ margin:46px 0 18px; font-size:clamp(22px, 6vw, 27px); line-height:1.34; font-weight:400; text-wrap:pretty; }
    .m2-why-tag{ display:block; font-size:12.5px; letter-spacing:.08em; margin-bottom:12px; }
    .m2-vbody{ margin:0; font-size:16px; line-height:1.6; font-weight:400; text-wrap:pretty; }

    /* ---- cierre ---- */
    /* CERTIFICACIONES en movil: columna fluida, en flujo, encima del cierre.
       Los altos van en px de pantalla directos -- aqui no hay lienzo que
       escale -- o sea los de la mezcla C tal cual, no los de unidades de
       lienzo. Que la fila envuelva es lo normal: con seis logos en un movil
       estrecho caen en dos o tres filas.
       OJO con la divisoria de abajo: .m2-cierre-inner lleva un border-top que
       se apagaba con ".m2-met + .m2-cierre". Al meter esto en medio ese
       selector deja de casar y la linea vuelve, que es lo que se quiere --
       .m2-certs no dibuja ninguna. */
    .m2-certs{ padding:0 20px; margin:64px 0 72px; color:#1d1d1c; }
    .m2-certs-tit{
      margin:0 0 28px; font-size:12px; line-height:1.2; font-weight:400;
      letter-spacing:.08em; text-transform:uppercase; color:#1d1d1c;
      text-align:center;
    }
    .m2-certs-fila{
      display:flex; align-items:center; justify-content:center; gap:30px; flex-wrap:wrap;
    }
    .m2-certs .cert-logo{ display:block; flex:none; width:auto; }
    /* Aqui el factor es 1,6 y no el 2,4 del escritorio: con 335 de ancho util,
       2,4 dejaria el OWASP en 251 y la seccion en cuatro filas. Con 1,6 son
       tres y el logo mas ancho se queda en 167, la mitad del hueco. */
    .m2-certs .cert-logo--btl1 { height:64px; }
    .m2-certs .cert-logo--burp { height:56px; }
    .m2-certs .cert-logo--osep { height:53px; }
    .m2-certs .cert-logo--oscp { height:53px; }
    .m2-certs .cert-logo--ceh  { height:54px; }
    .m2-certs .cert-logo--owasp{ height:50px; }
    .m2-cierre{ padding:0 20px 72px; }
    .m2-cierre-inner{ border-top:1.5px solid #1d1d1c; padding-top:56px; }
    .m2-met + .m2-cierre .m2-cierre-inner{ border-top:0; }
    .m2-cierre .m2-chead{ margin:0 0 40px; font-size:clamp(29px, 8.4vw, 40px); line-height:1.22; font-weight:400; letter-spacing:-.01em; }
    .m2-cierre .m2-rotmask{ display:block; min-height:1.3em; }
    .m2-flecha{ display:inline-block; }
    .m2-flecha img{ height:.72em; width:auto; display:inline-block; vertical-align:baseline; }
    .m2-cq{ margin:0; font-size:18px; font-weight:400; }
    .m2-cs{ margin:2px 0 30px; font-size:18px; font-weight:400; color:#3b3b3b; }
    .m2-btn{ display:inline-block; background:#1d1d1c; color:#f1f1f1; text-decoration:none; font-size:16px; padding:15px 36px; }

    /* rebote de overscroll: fondo oscuro sólido por debajo, tapa clara pintada sobre el inicio */
    html{ background:#3b3b3b; }
    .m2-hero::before{ content:''; position:absolute; left:0; right:0; top:-100vh; height:100vh; background:#f1f1f1; }
    .m2-wrap{ background:#f1f1f1; min-height:100%; position:relative; }
    .m2-page-gris > .m2-wrap{ background:#3b3b3b; }
    .m2-wrap::before{ content:''; position:absolute; left:0; right:0; top:-100vh; height:100vh; background:inherit; z-index:1; }
    .m2-wrap::after{ content:''; display:block; position:relative; z-index:1; height:0; box-shadow:0 100vh 0 100vh #3b3b3b; }
    /* ---- footer (gris) ---- */
    .m2-footer{ background:#3b3b3b; color:#f1f1f1; padding:56px 20px 26px; }
    .m2-fhead{ margin:0 0 4px; font-size:12.5px; letter-spacing:.08em; color:#bdbdbc; font-weight:400; }
    .m2-fnav{ margin-bottom:38px; }
    .m2-fnav a{ display:block; padding:15px 0; border-bottom:1.5px solid #f1f1f1; color:#f1f1f1; text-decoration:none; font-size:21px; font-weight:400; }
    .m2-fsvc{ margin-bottom:6px; }
    .m2-fsvc a{ display:block; padding:12px 0; border-bottom:1.5px solid rgba(241,241,241,.35); color:#f1f1f1; text-decoration:none; font-size:15px; font-weight:400; }
    .m2-fmeta{ display:flex; flex-wrap:wrap; gap:10px 24px; margin:38px 0 0; }
    .m2-fmeta a{ color:#f1f1f1; font-size:11px; letter-spacing:.05em; text-decoration:none; }
    .m2-fmeta a[data-legal]{ font-size:9.5px; }
    .m2-fcopy{ margin:26px 0 18px; font-size:12px; color:#bdbdbc; }
    .m2-flogo{ line-height:0; }
    .m2-flogo svg{ width:100%; height:auto; display:block; }
    .m2-flogo svg path{ fill:#f1f1f1; }

    /* ---- páginas de sección (overlays a pantalla completa) ---- */
    .m2-page{
      position:fixed; inset:0; z-index:50; background:#3b3b3b; color:#1d1d1c;
      overflow-y:auto; -webkit-overflow-scrolling:touch;
      opacity:0; visibility:hidden; pointer-events:none;
      transition:opacity .35s ease, visibility 0s .35s;
    }
    .m2-page.abierta{ opacity:1; visibility:visible; pointer-events:auto; transition:opacity .35s ease; }
    .m2-page-gris{ background:#3b3b3b; color:#f1f1f1; }
    .m2-ph{ padding:76px 20px 0; }
    .m2-pword{ margin:0 0 24px; font-size:clamp(56px, 17vw, 92px); line-height:1; font-weight:300; letter-spacing:-.02em; overflow:hidden; }
    .m2-pword > span{ display:block; transform:translateY(112%); transition:transform 1s cubic-bezier(.16,1,.3,1) .15s; }
    .m2-page.in .m2-pword > span{ transform:none; }
    .m2-hr.ph-hr{ transition-delay:.7s; }
    .m2-page.in .m2-hr.ph-hr{ transform:none; }
    .m2-hr.clara{ background:#f1f1f1; }
    .m2-psub, .m2-ptexto, .m2-plista{
      opacity:0; transform:translateY(14px);
      transition:opacity .5s ease .95s, transform .6s cubic-bezier(.16,1,.3,1) .95s;
    }
    .m2-page.in .m2-psub, .m2-page.in .m2-ptexto, .m2-page.in .m2-plista{ opacity:1; transform:none; }
    .m2-psub{ margin:24px 0 0; font-size:18px; line-height:1.4; font-weight:400; }
    .m2-ptexto{ margin:16px 0 0; font-size:16.5px; line-height:1.6; font-weight:400; text-wrap:pretty; transition-delay:1.08s, 1.08s; }
    .m2-plista{ list-style:none; margin:28px 0 0; padding:0; transition-delay:1.08s, 1.08s; }
    .m2-plista li{ border-top:1.5px solid #1d1d1c; padding:14px 0; font-size:16px; font-weight:400; }
    .m2-pbody{ padding:52px 20px 64px; }
    .m2-pregunta{ margin:0 0 40px; font-size:clamp(27px, 7.6vw, 34px); line-height:1.24; font-weight:400; letter-spacing:-.01em; }
    .m2-psvc{ border-top:1.5px solid #1d1d1c; padding:22px 0 30px; }
    .m2-psvc h4{ margin:0 0 12px; font-size:21px; line-height:1.25; font-weight:400; letter-spacing:-.01em; }
    .m2-psvcflecha{ display:inline-block; width:.9em; height:.9em; margin-right:.28em; vertical-align:-.08em; color:#1d1d1c; }
    .m2-psvcflecha svg{ width:100%; height:100%; display:block; }
    .m2-psvc p{ margin:0; font-size:16px; line-height:1.6; font-weight:400; text-wrap:pretty; }
    .m2-pfinal{ margin:56px 0 8px; font-size:clamp(30px, 8.8vw, 40px); line-height:1.1; font-weight:400; letter-spacing:-.015em; }
    .m2-pblanco{ background:#f1f1f1; color:#1d1d1c; margin-top:56px; padding:56px 20px 64px; }
    [data-m2-pie]{ background:#f1f1f1; color:#1d1d1c; display:block; }
    #m2PagNosotros .m2-ph{ padding-top:94px; }
    #m2PagNosotros .m2-pword{ font-size:clamp(64px, 20vw, 112px); color:#ffffff; margin-bottom:26px; }
    #m2PagNosotros .m2-pword img{ max-width:100%; height:auto; }
    .m2-pfuerzas{ margin:0 0 30px; font-size:clamp(56px, 17vw, 92px); line-height:.98; font-weight:300; letter-spacing:-.02em; }
    .m2-pblanco .m2-btn{ margin-top:38px; }
    .m2-acc{ border-top:1.5px solid #1d1d1c; }
    .m2-acc:last-of-type{ border-bottom:1.5px solid #1d1d1c; }
    .m2-acc-q{
      width:100%; background:none; border:0; padding:19px 0;
      display:flex; align-items:center; gap:14px;
      font-family:inherit; color:inherit; text-align:left; cursor:pointer;
    }
    .m2-acc-idx{ flex:none; font-size:12.5px; letter-spacing:.06em; color:#3b3b3b; }
    .m2-acc-t{ flex:1; font-size:21px; font-weight:400; letter-spacing:-.01em; }
    .m2-acc-plus{ position:relative; width:16px; height:16px; flex:none; }
    .m2-acc-plus::before, .m2-acc-plus::after{
      content:""; position:absolute; left:50%; top:50%; background:#1d1d1c;
      transition:transform .45s cubic-bezier(.16,1,.3,1);
    }
    .m2-acc-plus::before{ width:16px; height:1.5px; transform:translate(-50%,-50%); }
    .m2-acc-plus::after{ width:1.5px; height:16px; transform:translate(-50%,-50%); }
    .m2-acc.abierta .m2-acc-plus::after{ transform:translate(-50%,-50%) rotate(90deg); }
    .m2-acc-a{ overflow:hidden; max-height:0; transition:max-height .55s cubic-bezier(.16,1,.3,1); }
    .m2-acc.abierta .m2-acc-a{ max-height:300px; }
    .m2-acc-a p{ margin:0 0 24px; font-size:16px; line-height:1.55; font-weight:400; text-wrap:pretty; }
    .m2-banda{ margin:52px -20px 0; }
    .m2-banda > .r-in{ background:#3b3b3b; color:#f1f1f1; padding:46px 20px 50px; }
    .m2-banda .m2-why{ margin:0 0 18px; }
    .m2-banda .m2-vbody{ margin:0; }
    .m2-banda .m2-aaa, .m2-banda .m2-why-tag{ color:#bdbdbc; }

    /* ---- polvo de puntos (zonas claras, como en PC) ---- */
    .m2-dust{ pointer-events:none; position:absolute; inset:0; z-index:0; mix-blend-mode:multiply; image-rendering:pixelated; opacity:.26; }
    .m2-dust-pag{ position:sticky; top:0; display:block; z-index:0; }
    .m2-dust-menu{ mix-blend-mode:screen; opacity:.08; }
    .m2-menu > *:not(.m2-dust){ position:relative; z-index:1; }
    .m2-hero, .m2-fh, .m2-serv, .m2-cierre, .m2-pblanco{ position:relative; }
    .m2-hero > *:not(.m2-dust), .m2-fh > *:not(.m2-dust), .m2-serv > *:not(.m2-dust), .m2-cierre > *:not(.m2-dust), .m2-pblanco > *:not(.m2-dust){ position:relative; z-index:1; }
    .m2-ph, .m2-pbody, [data-m2-pie]{ position:relative; z-index:1; }

    /* ---- página de contacto en móvil (retoques) ---- */
    .contacto-overlay .co-topbar{ display:none; }
    .contacto-overlay .co-head{ padding:64px 20px 24px; }
    .co-faq{ padding:56px 20px 72px; }
    .cf-title{ font-size:clamp(34px, 10vw, 46px); margin-bottom:36px; }
  }
