/* ============================================================
   DssLayers — prototipo de portada
   Base en escala de grises + azul para lo que se mueve y naranja para
   el haz que pasa por encima.
   Sin dependencias.

   EL MANDO DE LA VELOCIDAD: --ciclo (abajo, en :root).
   Es el tiempo que tarda la animación en dar una vuelta completa.
   - 8s   = 100 %  (demasiado rápido para leer los nombres)
   - 11.5s = 70 %  (el valor actual, elegido por el usuario)
   Para cambiarlo:  --ciclo = 8s / velocidad_deseada.
   Todo lo demás está atado a esa variable, así que el pulso, el haz
   naranja y la luz de cada fase siguen sincronizados sin tocar nada más.

   Dentro de cada ciclo (en porcentajes, por eso no cambian):
   - 0 % a 87.5 %: el pulso y el haz recorren las ocho fases.
   - 87.5 %: la fase «i» está encendida, y el haz está encima de ella.
   - 95 % a 100 %: todo apagado antes de volver a empezar.
   ============================================================ */

/* ============================================================
   LA TIPOGRAFÍA DEL TEXTO: INTER, AUTOALOJADA
   ------------------------------------------------------------
   Fichero: `fuentes/inter-latin.woff2` (47 KB). Es una fuente
   VARIABLE: un solo fichero cubre del peso 400 al 700.

   POR QUÉ SE FIJA (antes no lo estaba): el texto usaba la fuente
   del SISTEMA (`ui-sans-serif, system-ui, …`), así que cada
   visitante lo veía con la suya —Segoe UI en Windows, SF en Mac,
   la que hubiera en Linux— y la web no se veía igual en todas
   partes. Con esto se ve igual, y además NO se le pide nada a
   Google (mejor para la privacidad del visitante).

   OJO: en `file://` (doble clic) algunos navegadores bloquean las
   fuentes locales por CORS. Si algún día se abre así y el texto
   sale con otra letra, es eso y no un fallo del CSS.

   Michroma y Science Gothic YA NO se piden a Google: se autoalojan aquí abajo
   (2026-09-27, era el pendiente 9). **Con esto la web NO hace ni una sola
   petición a un servidor externo**, que es lo que permite decir «nada sale de
   casa» sin mentir: hasta hoy, cada visita mandaba la IP del visitante a
   Google (EEUU) al pedir las fuentes.
   ============================================================ */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fuentes/inter-latin.woff2") format("woff2");
}

/* LAS DOS FUENTES DE TITULARES, autoalojadas. Van en DOS ficheros cada una
   (`latin` y `latin-ext`) porque así las sirve Google, y el `unicode-range` es
   lo que hace que el navegador descargue solo el que necesita: el `latin` basta
   para español, inglés y catalán, y el `latin-ext` solo se pide si aparece un
   carácter de fuera (por eso se descarga uno y no los dos).
   OJO AL CAMBIAR EL TEXTO: si aparece un carácter que no esté en ninguno de los
   dos rangos, se verá con la fuente del sistema. Los `unicode-range` están
   copiados tal cual de Google y NO se tocan a mano. */
@font-face {
  font-family: "Michroma";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fuentes/michroma-latin-ext.woff2") format("woff2");
  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;
}

@font-face {
  font-family: "Michroma";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fuentes/michroma-latin.woff2") format("woff2");
  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: "Science Gothic";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fuentes/science-gothic-latin-ext.woff2") format("woff2");
  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;
}

@font-face {
  font-family: "Science Gothic";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fuentes/science-gothic-latin.woff2") format("woff2");
  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;
}

/* ---------- Paleta ---------- */
:root {
  /* Duración de una vuelta completa (mando único de velocidad) */
  --ciclo: 11.5s;

  /* Recorrido del cruce portada → servicios: cuánto scroll dura el momento
     en que una se apaga y la otra sube. Más alto = cruce más lento.
     Vale 100dvh porque la portada se queda FIJADA ese rato: el recorrido
     es justo el tiempo que está clavada en pantalla. */
  --recorrido: 100dvh;

  /* Recorrido de TODOS los cruces menos el primero (Misión → Services,
     Services → DSS8, Industries → Contact…).
     ── ESTABA EN 55dvh Y SE SUBIÓ A 100dvh EL 2026-09-28 ──
     Medido con 55dvh: el cruce duraba 471 px y en esa ventana **no había ni
     un solo momento en que las dos secciones estuvieran por encima del 70 %**
     (lo mejor eran 0,69 y 0,69 en un punto). La de arriba se apagaba mientras
     la de abajo subía, pero se cruzaban tan rápido que no se veían juntas: el
     usuario lo describía como «la anterior ya ha desaparecido y la siguiente
     ya es opaca desde el principio», y quedaban huecos en blanco.
     Ahora vale 100dvh, el MISMO recorrido que el primer cruce, que es el que
     el usuario ve bien: el cruce dura una pantalla entera y las dos se ven a
     la vez (medido: 40 % del recorrido con las dos por encima del 70 %,
     ≈343 px). No es scroll de más: solo cambia a qué ritmo se apagan y se
     encienden. Más alto = más lento. */
  --recorrido-cruce: 100dvh;

  --bg:          #f6f6f7;
  /* Fondo de la barra de navegación y de las tarjetas flotantes del pie
     (semitransparente, con `backdrop-filter: blur(14px)` detrás). El usuario lo
     cambió de blanco a este gris. **El tema oscuro tiene su propio valor, más
     abajo.** */
  --bg-panel:    rgb(216 216 216 / 78%);
  --placa:       #ffffff;
  --placa-borde: #dcdde1;
  --hilo:        #cfd1d6;
  --ink:         #15171b;
  --ink-soft:    #4b5058;
  --ink-faint:   #9ba0a8;

  /* Azul único y vivo. Solo para lo que se mueve. */
  --acento:      #0f62fe;
  --acento-glow: rgba(15, 98, 254, .55);
  --acento-suave: #e8f0ff;

  /* Partículas y líneas de ruido del fondo (canvas). En claro se usa un
     azul más profundo para que se vean sobre el fondo casi blanco. */
  --particula: #2a5bb5;

  /* Verde: SOLO para la última fase del diagrama de la portada (Evolution),
     que es la única que se da por terminada. Medido: el número de la placa
     (blanco) sobre este verde da 4,4:1. */
  --verde: #0e8a44;

  /* LA TRAMA DEL FONDO (los scanlines del monitor de tubo; ver `body::before`).
     En el tema claro son líneas OSCURAS muy tenues sobre el fondo casi blanco;
     en el oscuro, claras. Muy bajas a propósito: es textura, no dibujo. */
  --scan-linea: rgba(21, 23, 27, .055);
  --scan-punto: rgba(21, 23, 27, .028);

  /* Naranja: SOLO para el recuadro que vuela por encima de las fases. */
  --naranja:        #ff7a18;
  --naranja-glow:   rgba(255, 122, 24, .60);
  --naranja-suave:  rgba(255, 122, 24, .10);

  /* Rejilla de fondo de las secciones técnicas */
  --rejilla: rgba(21, 23, 27, .055);

  /* Amarillo: SOLO para el impacto del punto en su capa del diagrama.
     Es ámbar y no limón a propósito: el amarillo puro sobre blanco casi
     no tiene contraste y el borde se perdería. */
  --amarillo:       #ffb300;
  --amarillo-glow:  rgba(255, 179, 0, .55);
  --amarillo-suave: rgba(255, 179, 0, .16);
  --amarillo-fuerte: #9a6200;   /* para texto sobre fondo claro */

  /* ---------- LA LÁMPARA DE SAL ----------
     Los cuatro tonos por los que va pasando despacio el fondo de TODA la web.
     (2026-09-28: se unificó en una sola paleta calmada —antes cada sección
     tenía la suya— a petición del usuario: verde salvia dominante, azul polvo
     entrante, lavanda saliente y arena cálida como puente.)
     Medido contra el fondo claro (#f6f6f7): 3,3-3,5:1, visible sin dejar de
     ser tranquilo. */
  --tono-1: #6f8f6c;   /* verde salvia */
  --tono-2: #6f8aa8;   /* azul polvo */
  --tono-3: #8f7ab3;   /* lavanda suave */
  --tono-4: #a8896c;   /* arena cálida */

  /* La BASE de la lámpara: casi blanca. El usuario pidió que el fondo fuera
     «más tímido»: el color son ahora manchas suaves sobre esta base, no una
     superficie de color. */
  /* La base que YA NO SE USA (ver la lámpara de sal): el usuario no quiere
     una superficie de color completa en la sección. Se deja por si vuelve. */
  --tono-0: #f6f6f8;

  /* MANDO DE VELOCIDAD de la lámpara de sal: lo que tarda una vuelta. */
  --lampara: 45s;

  /* ---------- LOS COLORES DEL ESLOGAN Y SU CAJA ----------
     Elegidos por el usuario el 2026-09-27. El eslogan va dentro de una CAJA
     redondeada (`.eslogan-bloque`), así que el contraste que importa es el del
     texto contra la CAJA, no contra la página: medido, **4,77:1** (el mínimo
     recomendado es 4,5). Ajustado, pero pasa.
     En el tema oscuro hay su propia pareja (ver más abajo). */
  --eslogan-tinta: #355a9f;
  --eslogan-caja:  #d2dae1;

  /* La curva con la que entra todo en la portada (la misma de los cruces) */
  --easing-entrada: cubic-bezier(.22, 1, .36, 1);

  /* ANCLAJE DE LAS SECCIONES (lo que queda por encima del título cuando se
     pulsa un enlace del menú).
     --alto-nav: lo que mide la barra fija YA APRETADA, que es como está
                 cuando el scroll llega al destino (46 px medidos; suelta mide
                 56). Si cambia el nav, hay que cambiar esto.
     --aire-ancla: el aire que se deja entre la barra y el título. */
  --alto-nav: 46px;
  --aire-ancla: 25px;

  /* La tinta que va encima de esos tonos: el gris claro (--ink-faint) NO se
     lee sobre ellos, de ahí que sea bastante más oscura. */
  --tinta-tono: #2e2d4d;

  /* Inter primero (autoalojada). Si no cargara, cae en la del sistema. */
  --ui:   "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;

  --wordmark-font: "Michroma", var(--ui);
}

/* El modo CLARO es el que manda por defecto (decidido por el usuario),
   aunque el sistema del visitante esté en oscuro. El oscuro se activa si se
   pone data-tema="oscuro": lo hacen los botones de sol y luna de la barra (y el
   script del <head>, que aplica el tema guardado antes de pintar). */

html[data-tema="oscuro"] {
  --bg:          #0c0d0f;
  --bg-panel:    rgba(20, 22, 25, .78);
  --placa:       #15171b;
  --placa-borde: #292c31;
  --hilo:        #2c3037;
  --ink:         #f3f4f6;
  --ink-soft:    #a9aeb6;
  --ink-faint:   #5d636c;

  --acento:      #4d9bff;
  --acento-glow: rgba(77, 155, 255, .60);
  --acento-suave: #101c33;

  /* En oscuro las partículas y el ruido van en azul claro, como luces. */
  --particula: #5aa0ff;

  /* El verde de la última fase, aclarado para el fondo oscuro (9:1 contra la
     placa oscura). */
  --verde: #34d17a;

  /* La trama del fondo, en claro sobre el negro (ver el tema claro). */
  --scan-linea: rgba(243, 244, 246, .05);
  --scan-punto: rgba(243, 244, 246, .025);

  --naranja:        #ff9142;
  --naranja-glow:   rgba(255, 145, 66, .65);
  --naranja-suave:  rgba(255, 145, 66, .12);

  --rejilla: rgba(243, 244, 246, .06);

  --amarillo:       #ffd24a;
  --amarillo-glow:  rgba(255, 210, 74, .50);
  --amarillo-suave: rgba(255, 210, 74, .14);
  --amarillo-fuerte: #ffd24a;

  /* En oscuro, la lámpara trabaja al revés: la MISMA paleta calmada, pero
     luminosa (son luces sobre un fondo casi negro). Medido contra #0c0d0f:
     4,1-4,6:1. */
  --tono-1: #5d7f6a;   /* verde salvia */
  --tono-2: #5d7f9e;   /* azul polvo */
  --tono-3: #7a6b9e;   /* lavanda */
  --tono-4: #8a7358;   /* arena cálida */

  /* En oscuro la base NO puede ser la casi blanca del tema claro: se hunde */
  --tono-0: #14141a;

  --tinta-tono: #d6d5ea;

  /* El eslogan, en oscuro. El usuario no dio versión oscura de la caja: se
     hunde como el resto del tema (una caja clara brillaría sobre el negro).
     Medido: el texto sobre esta caja da 7,4:1. */
  --eslogan-tinta: #a8bde0;
  --eslogan-caja:  #232c38;
}

/* ---------- Fondo de partículas flotantes ----------
   Capa fija detrás de TODO el contenido. Tres cosas importantes:
   - `pointer-events: none`: los puntos no capturan el ratón, no estorban
     para pulsar nada.
   - `aria-hidden`: no existe para un lector de pantalla. Es decorativo.
   - z-index 0 y va la PRIMERA en el HTML: así queda por debajo de las
     secciones (que son `position: relative; z-index: 2`) y del contenido.
   Se ve donde el fondo es transparente. Donde hay un bloque con color
   propio, la tapa: eso es a propósito. */
.fondo-particulas {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* ============================================================
   LA TRAMA DEL FONDO: LOS SCANLINES DEL MONITOR DE TUBO — 2026-09-28
   ------------------------------------------------------------
   El usuario quería el efecto de los monitores de fósforo (los de las películas
   de los 80): esa TRAMA de líneas finísimas que se ve de cerca en un tubo, con
   aire difuminado. El primer intento fueron unas cuantas líneas de 1 px
   dibujadas a mano en el lienzo de partículas; el usuario las rechazó con razón:
   **se leían como rayas sueltas que aparecían, no como una textura**. Se
   quitaron del todo (ver `montarFondo` en hero.js).

   CÓMO ESTÁ HECHA AHORA, Y POR QUÉ ASÍ:
   · Son DOS TRAMAS cruzadas, no líneas sueltas: una de líneas HORIZONTALES cada
     3 px (la señal del tubo) y otra de líneas VERTICALES cada 3 px, más tenue
     todavía. Donde se cruzan se oscurecen un poco más, y eso es justo lo que
     insinúa los «puntos que forman la línea» de la máscara del tubo.
   · Va en CSS (`body::before`), no en el lienzo: así NO se repinta nada en cada
     fotograma (el lienzo ya se repinta solo, para las partículas).
   · Va DETRÁS de todo el contenido y es `body::before` a propósito: los
     pseudo-elementos van antes que los hijos en el orden de pintado, así que
     queda por debajo del lienzo de partículas, de la portada y de las secciones
     (que son `z-index: 2`) sin pelearse con ningún `z-index`. **Si se cambia a
     `::after` o se le pone `z-index: 1`, la trama pasa por encima de la portada**
     (que tiene `z-index: auto`) y ensucia el texto.
   · `pointer-events: none`, como el fondo de partículas: no captura nada.
   · LATE MUY DESPACIO (`fosforo`, 7 s, entre 0,88 y 1 de opacidad): es el
     «respirar» del fósforo. Es tan suave que no se nota, pero sin él la trama
     parece una imagen pegada.
   · CON MENOS MOVIMIENTO se queda la trama quieta (ver la media query de abajo).
   ============================================================ */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(to bottom, var(--scan-linea) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(to right,  var(--scan-punto) 0 1px, transparent 1px 3px);
  animation: fosforo 7s ease-in-out infinite alternate;
}

@keyframes fosforo {
  from { opacity: .88; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  body::before { animation: none; }
}

/* ============================================================
   LA GUÍA DE SECCIONES (los puntos de la derecha)
   ------------------------------------------------------------
   Sustituye a la barra de scroll del navegador, que se oculta más abajo.
   El punto de la sección en la que estás se enciende EN NARANJA (--naranja),
   el mismo color que se usa para remarcar en la portada.

   DOS COSAS A SABER:
   1. **La barra del navegador NO se quita con `overflow: hidden`** (eso
      convertiría el body en contenedor de scroll y **rompería el `sticky` de
      la portada**). Se oculta solo su pintado: `scrollbar-width` y
      `::-webkit-scrollbar`. El scroll sigue funcionando igual.
   2. Los puntos son **enlaces de verdad** (se pulsan y se tabulan): quien
      navegue con teclado no se queda sin la referencia de dónde está.
   ============================================================ */

/* Se oculta la barra del navegador, pero NO el desplazamiento */
html { scrollbar-width: none; }          /* Firefox */
html::-webkit-scrollbar { display: none; } /* Chrome, Edge, Safari */

.guia {
  position: fixed;
  right: clamp(10px, 1.3vw, 22px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 8;

  /* EL TIMELINE. `--paso` es la distancia entre los CENTROS de dos puntos, que
     es lo que se ve al mirarlo: 44 px. El hueco de flex es lo que sobra tras
     descontar la altura de la fila. `--fila` va FIJADA a propósito: si su alto
     dependiera del texto (la fuente tarda en cargar), el eje y los puntos se
     desalinearían a mitad de carga. */
  --paso: 44px;
  --fila: 14px;
  --punto: 8px;

  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: calc(var(--paso) - var(--fila));
}

/* EL EJE: dos líneas superpuestas en la misma columna que los puntos.
   Van del CENTRO del primer punto al del último (media fila arriba y abajo),
   no de borde a borde: si no, asomarían por los extremos como dos rabos.
   El `right` deja la raya justo en el centro del punto, que mide 8 px. */
.guia::before,
.guia::after {
  content: "";
  position: absolute;
  right: calc(var(--punto) / 2 - 0.5px);
  top: calc(var(--fila) / 2);
  bottom: calc(var(--fila) / 2);
  width: 1px;
  border-radius: 1px;
  pointer-events: none;
}

/* El eje entero, tenue: es el camino que queda por delante.
   Va en `--ink-faint`, el MISMO gris que los puntos apagados: el eje y sus
   nodos son la misma cosa, y así no parece una raya suelta. Antes estaba en
   `--placa-borde` y sobre el fondo claro de las secciones no se veía: el
   usuario pidió la línea expresamente, así que tiene que verse. */
.guia::before { background: var(--ink-faint); }

/* Y ENCIMA, el tramo ya recorrido en naranja. Lo llena `hero.js` poniendo
   `--avance` con el número de punto activo (0 en la portada, 4 en la última
   sección), así que el eje se va llenando sección a sección. */
.guia::after {
  background: var(--naranja);
  bottom: auto;
  height: calc(var(--paso) * var(--avance, 0));
  transition: height .45s cubic-bezier(.22, 1, .36, 1);
}

.guia-punto {
  position: relative;
  /* Por encima del eje: los dos pseudo-elementos de `.guia` se pintan uno antes
     y otro DESPUÉS de los hijos, así que sin esto la raya naranja cruzaría los
     puntos por encima. */
  z-index: 1;
  height: var(--fila);
  display: flex;
  /* `row-reverse`: el punto (que en el DOM va ANTES, como ::before) se coloca
     a la DERECHA del nombre. Con el orden normal, cada punto quedaba pegado a
     su nombre y, como los nombres tienen distinta longitud, **salían
     desalineados**. Así los cinco puntos quedan en la misma columna y se lee
     de un vistazo cuál está encendido. */
  flex-direction: row-reverse;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  /* El punto en sí: un círculo pequeño. Se hace con un ::before para que el
     enlace tenga un área de pulsación más grande que el propio punto. */
}

.guia-punto::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ink-faint);
  transition: background-color .35s ease, transform .35s cubic-bezier(.22, 1, .36, 1),
              box-shadow .35s ease;
}

/* El nombre: a la izquierda del punto, escondido hasta que hace falta */
.guia-nombre {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--ink-faint);
  white-space: nowrap;
  opacity: 0;
  transform: translateX(6px);
  transition: opacity .3s ease, transform .3s cubic-bezier(.22, 1, .36, 1),
              color .3s ease;
  pointer-events: none;
}

.guia-punto:hover .guia-nombre,
.guia-punto:focus-visible .guia-nombre { opacity: 1; transform: none; }

.guia-punto:hover::before { background: var(--ink-soft); transform: scale(1.3); }

/* EL PUNTO DE LA SECCIÓN EN LA QUE ESTÁS: naranja y con halo */
.guia-punto.activo::before {
  background: var(--naranja);
  transform: scale(1.45);
  box-shadow: 0 0 0 4px var(--naranja-suave), 0 0 12px var(--naranja-glow);
}

.guia-punto.activo .guia-nombre {
  opacity: 1;
  transform: none;
  color: var(--naranja);
}

.guia-punto:focus-visible { outline: 2px solid var(--acento); outline-offset: 4px; }

/* Con «sin animaciones»: el eje salta de sección en sección en vez de llenarse
   poco a poco. Sigue marcando por dónde vas, que es información, no adorno. */
@media (prefers-reduced-motion: reduce) {
  .guia::after { transition: none; }
}

/* En móvil no cabe (y ahí la barra del navegador ya da la referencia) */
@media (max-width: 900px) {
  .guia { display: none; }
}

/* ---------- Base ---------- */
* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--ui);
  /* Ojo: NO se usa overflow-x: hidden. Eso convierte el body en contenedor
     de scroll y ROMPE el position: sticky de la portada. «clip» recorta
     igual pero sin crear contenedor de scroll. */
  overflow-x: hidden;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  transition: background-color .35s ease, color .35s ease;
}

/* Los enlaces del menú bajan suave hasta su sección (solo si el
   visitante no ha pedido que no haya movimiento). */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* Las dos columnas de la portada hacen un poco de paralaje al bajar.
   will-change avisa al navegador para que lo mueva en la tarjeta gráfica. */
.hero-texto,
.hero-capas { will-change: transform, opacity; }

/* ---------- Menú de navegación ---------- */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 14px clamp(18px, 4vw, 52px);
  border-bottom: 1px solid var(--placa-borde);
  background: var(--bg-panel);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  transition: background-color .35s ease, border-color .35s ease, padding .3s ease;
}

/* Cuando bajas, el menú se aprieta un poco: la portada cede el sitio
   al contenido. Lo pone hero.js. */
.nav.compacto { padding-top: 9px; padding-bottom: 9px; }

.nav-marca {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--wordmark-font);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: -.01em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}

/* ---------- Icono de la marca ----------
   La misma pila isométrica del logo (ver más abajo), reducida. */
.nav-icono {
  width: 20px;
  height: 20px;
  flex: none;
}

/* ---------- EL LOGO: la pila isométrica de cuatro placas ----------
   HASTA EL 2026-09-28 era una PIRÁMIDE PLANA: un triángulo arriba y tres
   trapecios que se ensanchaban hacia abajo. El usuario trajo una referencia
   (una pila isométrica de placas) y pidió el cambio: ahora son CUATRO PLACAS
   DEL MISMO ANCHO apiladas, con volumen.

   Cada placa es un grupo `.placa-iso` con TRES caras:
     · `.cara-arriba` → el rombo de arriba (el más claro).
     · `.cara-izq`    → la cara lateral izquierda.
     · `.cara-der`    → la cara lateral derecha (la más oscura).
   Las tres se pintan con el degradado de su placa —las clases `.icono-1..4` de
   siempre— y el volumen lo da un FILTRO DE BRILLO en las dos laterales: así el
   oscurecido se recalcula solo en los dos temas y no hay que mantener dieciséis
   colores a mano.

   EL REPARTO DE CLASES NO CAMBIA respecto al logo anterior: `icono-1` es la
   placa de ARRIBA (la más clara) e `icono-4` la de ABAJO (la más oscura). Los
   ocho gradientes siguen declarados UNA sola vez en index.html.

   DOS COSAS A SABER SI SE TOCA:
   1. EL TEMA OSCURO USA OTRA ESCALA (`-o1..4`), y no es un capricho: la base
      de la imagen es casi negra (#22252e) y sobre el fondo oscuro da
      **1,27:1**, o sea que desaparece (el mínimo de un gráfico es 3:1). La
      escala oscura sube los cuatro pasos y da 10,4 / 7,4 / 5,0 / **3,15:1**,
      conservando la progresión de claro a oscuro.
   2. LAS PLACAS YA NO LLEVAN OPACIDAD. Antes eran azul + grises al 50 % + tinta,
      y de ahí venía el `--o` que arrastraba el keyframe `placaCae` (un keyframe
      que acabe en `opacity: 1` PISA la del elemento). Ahora son cuatro colores
      llenos y todo ese enredo se ha ido con ellos: **si se devuelve opacidad a
      alguna placa, hay que volver a poner el `--o`**. */
.logo-degradados { position: absolute; width: 0; height: 0; }

/* El trazo va del MISMO color que el relleno: no se ve, solo redondea las
   esquinas de las placas. */
.icono-1, .icono-2, .icono-3, .icono-4,
.hero-logo .placa { stroke-width: 1.1; stroke-linejoin: round; }

.icono-1, .hero-logo .p1 { fill: url(#logo-c1); stroke: url(#logo-c1); }
.icono-2, .hero-logo .p2 { fill: url(#logo-c2); stroke: url(#logo-c2); }
.icono-3, .hero-logo .p3 { fill: url(#logo-c3); stroke: url(#logo-c3); }
.icono-4, .hero-logo .p4 { fill: url(#logo-c4); stroke: url(#logo-c4); }

html[data-tema="oscuro"] .icono-1,
html[data-tema="oscuro"] .hero-logo .p1 { fill: url(#logo-o1); stroke: url(#logo-o1); }
html[data-tema="oscuro"] .icono-2,
html[data-tema="oscuro"] .hero-logo .p2 { fill: url(#logo-o2); stroke: url(#logo-o2); }
html[data-tema="oscuro"] .icono-3,
html[data-tema="oscuro"] .hero-logo .p3 { fill: url(#logo-o3); stroke: url(#logo-o3); }
html[data-tema="oscuro"] .icono-4,
html[data-tema="oscuro"] .hero-logo .p4 { fill: url(#logo-o4); stroke: url(#logo-o4); }

/* ---------- EL VOLUMEN DEL LOGO (caras laterales) ----------
   Las dos caras laterales de cada placa salen del MISMO degradado que la cara de
   arriba, oscurecido con un filtro de brillo: así el volumen se recalcula solo
   en los dos temas y no hay dieciséis colores que mantener.
   OJO CON EL TEMA OSCURO: allí el oscurecido es más SUAVE (.93 / .85 en vez de
   .87 / .72). Con el mismo valor, la placa de abajo (azul oscuro) se hundiría en
   el fondo negro y el volumen se perdería.
   LA CARA DE ARRIBA NO LLEVA FILTRO a propósito: así conserva EXACTOS los
   colores medidos (ver el comentario de arriba sobre el contraste). */
.placa-iso .cara-izq { filter: brightness(.87); }
.placa-iso .cara-der { filter: brightness(.72); }

html[data-tema="oscuro"] .placa-iso .cara-izq { filter: brightness(.93); }
html[data-tema="oscuro"] .placa-iso .cara-der { filter: brightness(.85); }

.nav-enlaces {
  display: flex;
  align-items: center;
  gap: clamp(14px, 2.2vw, 34px);
  overflow-x: auto;
  scrollbar-width: none;
}

.nav-enlaces::-webkit-scrollbar { display: none; }

.nav-enlaces a {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .01em;
  color: var(--ink-soft);
  text-decoration: none;
  white-space: nowrap;
  padding: 4px 0;
  border-bottom: 1px solid transparent;
  transition: color .25s ease, border-color .25s ease;
}

/* ---------- EL SELECTOR DE IDIOMA ----------
   Va pegado a la derecha, detrás de los enlaces del menú y separado por un
   filete. Son ENLACES, no un desplegable: cada idioma es un fichero distinto,
   así que funciona sin JavaScript, se puede abrir en otra pestaña y el buscador
   lo ve. Lo genera `origen/generar.py` (`{{selector.idiomas}}`).

   OJO CON LA BARRA: `.nav` usa `justify-content: space-between`, que con DOS
   hijos deja la marca a la izquierda y el menú a la derecha. Al entrar un
   tercero, el menú se iría al CENTRO. Por eso aquí se pasa a `flex-start` y la
   marca se lleva el `margin-right: auto`: así el menú y el selector quedan
   agrupados a la derecha, como estaban. */
.nav { justify-content: flex-start; }
.nav-marca { margin-right: auto; }

.idiomas {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: none;
  padding-left: clamp(10px, 1.4vw, 18px);
  border-left: 1px solid var(--placa-borde);
}

.idiomas a {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .08em;
  color: var(--ink-faint);
  text-decoration: none;
  padding: 4px 7px;
  border-radius: 6px;
  transition: color .25s ease, background-color .25s ease;
}

.idiomas a:hover { color: var(--ink); background: var(--acento-suave); }

/* El idioma en el que estás: marcado con `aria-current` en el HTML y aquí con
   fondo, para que se vea de un vistazo sin tener que leerlo. */
.idiomas a.activo { color: var(--ink); background: var(--acento-suave); }

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

.nav-enlaces a:hover {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

/* ---------- EL SELECTOR DE TEMA (sol / luna) — 2026-09-28 ----------
   ANTES esto era un «panel de pruebas» flotante con un botón que iba alternando
   entre claro y oscuro. El usuario lo mandó quitar: ya NO existe.
   AHORA son DOS botones en la barra, al lado de los idiomas, con el mismo
   lenguaje que ellos (el activo se marca con el fondo suave del acento), así
   que el visitante pulsa directamente el sol o la luna.

   LA ELECCIÓN SE GUARDA en `localStorage` (clave `dsslayers-tema`), no en una
   cookie: la web presume de no poner cookies y esto no hace falta que viaje al
   servidor. Se aplica en el script del `<head>` —antes de pintar nada—, así que
   quien eligió oscuro NO ve un parpadeo claro → oscuro al volver. Ver
   `hero.js` (`montarTema`) y el aviso legal de cookies. */
.temas {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: none;
  padding-left: clamp(8px, 1.1vw, 14px);
  border-left: 1px solid var(--placa-borde);
}

.tema-boton {
  display: grid;
  place-items: center;
  width: 28px;
  height: 26px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 6px;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color .25s ease, background-color .25s ease;
}

.tema-boton:hover { color: var(--ink); }

/* ---------- CUÁL ESTÁ ELEGIDO ----------
   Lo decide el ATRIBUTO del <html>, NO una clase que ponga el JavaScript. Así el
   botón marcado coincide SIEMPRE con el tema de verdad: el tema lo aplica el
   script del <head> antes de pintar, mientras que hero.js va al final del body,
   así que con una clase se vería un instante el botón equivocado al cargar (y se
   quedaría descuadrado del todo si hero.js no llegara a cargar).
   `aria-pressed` sí lo lleva el JavaScript: eso es para lectores de pantalla y
   no tiene sentido sin JavaScript. */
#tema-claro {
  color: var(--ink);
  background: var(--acento-suave);
}

html[data-tema="oscuro"] #tema-claro {
  color: var(--ink-faint);
  background: none;
}

html[data-tema="oscuro"] #tema-oscuro {
  color: var(--ink);
  background: var(--acento-suave);
}

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

.tema-ico {
  width: 17px;
  height: 17px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------- Héroe ----------
   Se queda FIJADO mientras se hace scroll: no lo empuja la página.
   El recorrido de la mezcla lo da el contenedor .transicion. */
.hero {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  /* El TEXTO va arriba (lo pidió el usuario: el nombre y el claim más altos,
     para dejar sitio al eslogan debajo). El diagrama de las fases se queda
     centrado con su propio `align-self`. */
  align-items: start;
  gap: clamp(24px, 4vw, 72px);
  max-width: 1680px;
  margin: 0 auto;
  padding: clamp(28px, 5vw, 88px);
  /* Deja sitio al menú fijo de arriba */
  padding-top: clamp(84px, 11vh, 124px);
}

/* ---------- La palabra ---------- */
.hero-texto { min-width: 0; }

/* El tamaño se multiplica por la escala de cada tipografía (--escala,
   que ajusta hero.js): las tipografías anchas necesitan menos cuerpo.
   El MÍNIMO va en rem (no se multiplica) para que en móvil nunca quede
   una palabra diminuta.

   El padding no es decorativo: el brillo está recortado al texto
   (background-clip: text) y el navegador solo lo pinta DENTRO de la caja.
   Sin ese aire de abajo, el rabo de la «y» se queda sin pintar y
   desaparece. Es la caja, no el tamaño de letra. */
/* El tamaño se multiplica por la escala de la tipografía elegida.
   Michroma es ancha, así que va a 0.6. Está aquí fijado, en el CSS,
   para que la web no dependa de JavaScript para verse bien. */
.wordmark {
  margin: 0;
  font-family: var(--wordmark-font);
  --escala: 0.6;
  font-size: clamp(2.4rem, calc(13.5vw * var(--escala, 1)), calc(15rem * var(--escala, 1)));
  font-weight: 400;
  line-height: .88;
  letter-spacing: -.04em;
  padding: .10em 0 .28em;
  color: var(--ink);
  overflow-wrap: break-word;
}

/* La palabra va en dos líneas: «Dss» y «Layers».
   Las dos van dentro del mismo h1, así que el texto que lee un buscador
   o un lector de pantalla sigue siendo «DssLayers», en una sola pieza. */
.wordmark .linea { display: block; }

/* Un brillo muy sutil que recorre la palabra. Solo si el navegador
   soporta recortar el fondo al texto; si no, se queda en color liso. */
@supports (-webkit-background-clip: text) {
  .wordmark {
    background-image: linear-gradient(100deg,
      var(--ink) 0%, var(--ink) 42%, var(--ink-faint) 50%, var(--ink) 58%, var(--ink) 100%);
    background-size: 240% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    animation: brillo 11s linear infinite;
  }
}

@keyframes brillo {
  from { background-position: 140% 0; }
  to   { background-position: -40% 0; }
}

/* La línea del héroe. En la web final, en inglés. */
.claim {
  margin: clamp(12px, 1.8vw, 24px) 0 0;
  max-width: 42ch;
  /* Más pequeño y en la tipografía de interfaz, no en la monoespaciada: es un
     subtítulo de marca, no una etiqueta técnica (lo pidió el usuario). */
  font-family: var(--ui);
  font-size: clamp(.85rem, 1.05vw, 1.05rem);
  line-height: 1.45;
  letter-spacing: .015em;
  color: var(--ink-soft);
}

/* ============================================================
   LA ENTRADA DE LA PORTADA, EN SECUENCIA
   ------------------------------------------------------------
   Al llegar a la portada se monta todo delante del visitante:
     1. Las cuatro placas del LOGO caen y encajan (de arriba abajo).
     2. Entra el NOMBRE.
     3. Entra el CLAIM.
     4. Entra el ESLOGAN, justo cuando la base del logo ha encajado.
   Lo lanza `hero.js` poniendo `.monta` en el héroe, y se la quita cuando la
   portada sale de pantalla: así **se repite cada vez que se vuelve a ella**.

   LOS ESTADOS OCULTOS VAN BAJO `.js`: sin JavaScript se ve todo. Es la
   diferencia entre un efecto y una web en blanco.
   ============================================================ */

/* El bloque del logo y la frase: uno al lado del otro, centrados entre sí,
   dentro de una CAJA redondeada (lo pidió el usuario).
   `inline-flex` y no `flex`: así la caja ABRAZA el contenido en vez de
   estirarse a todo el ancho de la columna. */
.eslogan-bloque {
  display: inline-flex;
  align-items: center;
  gap: clamp(14px, 1.6vw, 24px);
  margin: clamp(18px, 2.6vw, 34px) 0 0;
  background-color: var(--eslogan-caja);
  padding: 10px;
  border-radius: 25px;
}

.hero-logo {
  display: block;
  flex: none;                 /* que no se encoja si la frase es larga */
  /* 2026-09-28: el usuario pidió las placas «como el doble de grandes». Estaba
     en clamp(48px, 4.6vw, 72px); ahora es el DOBLE exacto. */
  width: clamp(96px, 9.2vw, 144px);
  height: auto;
}

/* Los colores de las placas de la portada NO se declaran aquí: son los MISMOS
   cuatro gradientes que el icono del menú, y viven juntos más arriba. */

.js .hero-logo .placa { opacity: 0; }
.js .hero .wordmark { opacity: 0; transform: translateY(18px); }
.js .hero .claim { opacity: 0; transform: translateY(14px); }

/* La secuencia.
   ── LOS TIEMPOS SE ACORTARON EL 2026-09-28, A PETICIÓN DEL USUARIO ──
   El aviso fue: «el texto grande DssLayers tarda demasiado en aparecer». Y era
   verdad, medido con la opacidad del nombre muestreada cada 60 ms:
   **estaba COMPLETAMENTE INVISIBLE 1,02 s y no se completaba hasta 1,74 s**,
   porque esperaba a que la 4.ª placa del logo acabara de caer (0,90 s) y encima
   sumaba 0,75 s de entrada.
   PRIMER AJUSTE: el nombre arrancaba a los 0,15 s y estaba completo a los 0,70 s.
   SEGUNDO AJUSTE (mismo día, el usuario lo pidió otra vez): «que aparezca al
   INSTANTE». Ahora el nombre arranca a los 0 s y está completo a los 0,20 s.
   La secuencia entera pasa de ~2,5 s a **~0,95 s**.
   LO QUE ESTO CAMBIA, Y ES A PROPÓSITO: **el nombre ya NO espera al logo**. Las
   placas siguen cayendo (es el adorno de la marca) pero el nombre entra mientras
   caen. El orden de lectura se mantiene —primero el nombre, después el claim y
   por último el eslogan—, que es lo que el usuario eligió; lo que se ha quitado
   es la espera.
   Si algún día se quiere volver a «el nombre cuando el logo termine», hay que
   devolver el retardo de `.wordmark` a ~0,60 s (que es cuando encaja la base).

   ── LA CAÍDA DE LAS PLACAS SE HIZO MUCHO MÁS LENTA EL 2026-09-28 ──
   El usuario la veía de golpe: caían en 0,30 s cada una y la cascada entera
   duraba 0,57 s. Ahora cada placa tarda 1,20 s y los turnos van cada 0,60 s,
   así que LA CASCADA COMPLETA DURA 3,00 s (la base, la 4.ª, termina justo ahí).
   ESO OBLIGA A MOVER EL ESLOGAN: entraba a los 0,60 s, «cuando encajaba la
   base»; ahora la base encaja a los 3,00 s, y ahí entra (ver `.hero.monta
   .eslogan`). El nombre y el claim NO cambian: siguen entrando al principio,
   porque el usuario pidió que el nombre aparezca al instante. */
.hero.monta .hero-logo .p1 { animation: placaCae 1.2s var(--easing-entrada) both; animation-delay: 0s; }
.hero.monta .hero-logo .p2 { animation: placaCae 1.2s var(--easing-entrada) both; animation-delay: .6s; }
.hero.monta .hero-logo .p3 { animation: placaCae 1.2s var(--easing-entrada) both; animation-delay: 1.2s; }
.hero.monta .hero-logo .p4 { animation: placaCae 1.2s var(--easing-entrada) both; animation-delay: 1.8s; }

@keyframes placaCae {
  /* La caída también se alargó: con el logo al doble de tamaño, los 16 px de
     antes se quedaban en nada. Ahora son 26 px (se puede subir o bajar). */
  from { opacity: 0; transform: translateY(-26px); }
  to   { opacity: 1; transform: none; }
}

/* El nombre: el `brillo` va detrás en la lista para no perderlo (el @supports
   de arriba lo pone, y aquí se vuelve a declarar junto a la entrada).
   0 s de retardo + 0,20 s de entrada = completo a los 0,20 s (al instante,
   como pidió el usuario el 2026-09-28). */
.hero.monta .wordmark {
  animation: entraNombre .20s var(--easing-entrada) 0s both, brillo 11s linear infinite;
}

@keyframes entraNombre {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

.hero.monta .claim {
  animation: entraClaim .45s var(--easing-entrada) .45s both;
}

@keyframes entraClaim {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* El eslogan entra MIENTRAS CAEN LAS PLACAS (2026-09-28, segunda vuelta).
   Antes esperaba a que la base encajara (3,00 s) y al usuario le salía
   «demasiado tarde»: era ver caer el logo con el recuadro de al lado vacío.
   Ahora arranca a los 1,50 s, con las placas 3.ª y 4.ª todavía en el aire
   (p3 va de 1,20 a 2,40 s y p4 de 1,80 a 3,00 s), y termina a los 2,20 s.
   Así el eslogan se lee mientras el logo se está armando, que es lo que pidió. */
.hero.monta .eslogan {
  animation: entraEslogan .70s var(--easing-entrada) 1.5s both;
}

@keyframes entraEslogan {
  /* Desplazamiento CORTO a propósito: ahora el logo está justo a la izquierda
     y un salto largo haría que el texto saliera de encima del logo. */
  from { opacity: 0; transform: translateX(-20px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- El eslogan de la portada ----------
   La frase que llama al que llega: «Tu empresa, preparada para la era de la IA».
   Entra **el bloque entero, desplazándose de izquierda a derecha** y aclarándose
   a la vez, y se queda quieto. Lo relanza `hero.js` cada vez que se vuelve a la
   portada.
   OJO — LO QUE NO HAY QUE HACER: antes esto se hacía con un `clip-path` que
   descubría el texto de izquierda a derecha, y el usuario lo rechazó con razón:
   **parecía una máquina de escribir**. Se mueve el bloque, no se revela letra a
   letra. (De paso: sin `clip-path` desaparece la trampa de que los adornos que
   sobresalían del texto quedaban recortados.)
   El estado oculto va bajo `.js`, como el resto de efectos. Sin JavaScript, el
   eslogan se ve: la diferencia entre un efecto y una web rota. */
.js .eslogan {
  opacity: 0;
  transform: translateX(-20px);
}
/* (Su entrada la lleva la secuencia de arriba: `.hero.monta .eslogan`) */

.eslogan {
  margin: 0;
  max-width: 30ch;
  /* Science Gothic: ancha y geométrica, elegida por el usuario. Si no carga,
     cae en la tipografía del sistema (nunca en una letra rara). */
  font-family: "Science Gothic", var(--ui);
  /* OJO con el clamp: el MÍNIMO no puede ser mayor que el MÁXIMO. El usuario
     lo había puesto al revés (clamp(1.6rem, 1.6vw, 1.5rem)), y cuando eso
     pasa el navegador se queda con el mínimo y el tamaño deja de ser fluido.
     Así da 1,6rem (25,6 px) en escritorio y baja un poco en pantallas
     pequeñas, que es lo que buscaba. */
  /* Otra vez el mismo tropiezo del clamp: `clamp(1.65rem, 1.6vw, 1.6rem)` tiene
     el MÍNIMO mayor que el MÁXIMO, y así el tamaño deja de ser fluido (el
     navegador se queda con el mínimo). Corregido: da 1,65rem (26,4 px) en
     escritorio y baja en pantallas pequeñas, que es lo que se buscaba. */
  font-size: clamp(1.4rem, 1.65vw, 1.65rem);
  /* Peso FINO (300). Science Gothic es variable y llega hasta el 100, pero hay
     que pedir el rango 300..700 en el <link>, o el 300 no se descarga. */
  font-weight: 300;
  line-height: 1.28;
  letter-spacing: -.005em;
  color: var(--eslogan-tinta);
  /* Sin el filete de la izquierda: ahora el que ata el bloque al panel es el
     LOGO, que va justo al lado. (Si se quiere recuperar, se le devuelve el
     `border-left` con `--eslogan-filete`.) */
}

/* ---------- Las fases ---------- */
/* El diagrama sigue centrado aunque el texto esté arriba */
.hero-capas { min-width: 0; align-self: center; }

.capas {
  width: 100%;
  max-width: 780px;
  height: auto;
  display: block;
  margin: 0 auto;
}

/* El marco que agrupa la fase: aparece solo mientras esa fase está
   encendida, y abarca la placa Y su texto. Va primero dentro del grupo,
   así que se dibuja por detrás.
   Lleva difuminado a propósito: no es una raya, es una luz que envuelve. */
.marco {
  fill: var(--acento-suave);
  stroke: var(--acento);
  stroke-width: 2;
  opacity: 0;
  filter: blur(1.6px) drop-shadow(0 0 18px var(--acento-glow));
  animation: marco var(--ciclo) linear infinite;
  animation-delay: calc(var(--i) * (var(--ciclo) / 8) - (var(--ciclo) * 0.875));
}

@keyframes marco {
  0%, 80%   { opacity: 0; }
  87.5%     { opacity: 1; }
  95%, 100% { opacity: 0; }
}

/* La placa. Se enciende con el mismo reloj que el marco. */
.placa {
  fill: var(--placa);
  stroke: var(--placa-borde);
  stroke-width: 1.4;
  transition: fill .3s ease, stroke .3s ease;
  animation: destello var(--ciclo) linear infinite;
  animation-delay: calc(var(--i) * (var(--ciclo) / 8) - (var(--ciclo) * 0.875));
}

@keyframes destello {
  0%, 80%   { stroke: var(--placa-borde); fill: var(--placa);        filter: none; }
  87.5%     { stroke: var(--acento);      fill: var(--acento-suave); filter: drop-shadow(0 0 9px var(--acento-glow)); }
  95%, 100% { stroke: var(--placa-borde); fill: var(--placa);        filter: none; }
}

.marca {
  fill: var(--ink-faint);
  --tinta-base: var(--ink-faint);
  animation: destelloTinta var(--ciclo) linear infinite;
  animation-delay: calc(var(--i) * (var(--ciclo) / 8) - (var(--ciclo) * 0.875));
}

.indice {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .04em;
  fill: var(--ink-faint);
  --tinta-base: var(--ink-faint);
  animation: destelloTinta var(--ciclo) linear infinite;
  animation-delay: calc(var(--i) * (var(--ciclo) / 8) - (var(--ciclo) * 0.875));
}

.etiqueta {
  font-family: var(--ui);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .005em;
  fill: var(--ink-soft);
  --tinta-base: var(--ink-soft);
  transition: fill .3s ease;
  animation: destelloTinta var(--ciclo) linear infinite;
  animation-delay: calc(var(--i) * (var(--ciclo) / 8) - (var(--ciclo) * 0.875));
}

/* La frase va debajo del nombre, en gris y sin encenderse:
   si todo se ilumina, no se ilumina nada. */
.frase {
  font-family: var(--ui);
  font-size: 12px;
  font-weight: 400;
  fill: var(--ink-faint);
  transition: fill .3s ease;
}

@keyframes destelloTinta {
  0%, 80%   { fill: var(--tinta-base); }
  87.5%     { fill: var(--acento); }
  95%, 100% { fill: var(--tinta-base); }
}

.hilo {
  stroke: var(--hilo);
  stroke-width: 1.4;
  stroke-dasharray: 4 7;
}

/* El pulso: baja por el hilo delante de las placas.
   14 px de desfase para que pase por el CENTRO de cada placa. */
.pulso {
  fill: var(--acento);
  filter: drop-shadow(0 0 8px var(--acento-glow));
  animation: pulso var(--ciclo) linear infinite;
}

@keyframes pulso {
  0%    { transform: translateY(0);     opacity: 0; }
  4%    { opacity: 1; }
  80%   { opacity: 1; }
  87.5% { transform: translateY(448px); opacity: 1; }
  93%   { opacity: 0; }
  100%  { transform: translateY(448px); opacity: 0; }
}

/* ============================================================
   EL RELLENO DE PROGRESO DE CADA FASE — añadido el 2026-09-28
   ------------------------------------------------------------
   A petición del usuario: el recuadro naranja, al ir bajando, va PINTANDO las
   placas como una barra de progreso, cada una se queda con su porcentaje
   escrito en el centro, y al final del ciclo todo se vacía y vuelve a empezar.
   Los porcentajes son 10 / 20 / 30 / 45 / 60 / 75 / 90 / 100. La penúltima
   (Adoption) lleva la BARRA LLENA de azul y su número dice 90 %; la última
   (Evolution) es la ÚNICA en verde, porque es la que se da por terminada.

   CÓMO SE SINCRONIZA CON EL RECUADRO
   El ciclo dura `--ciclo` (11,5 s) y el recuadro tarda 1,4375 s en pasar de
   una placa a la siguiente (11,5 / 8), así que cada fase se enciende 0,8625 s:
   del 87,5 % al 95 % de SU vuelta. El relleno usa EXACTAMENTE esa ventana,
   pero medida sobre el ciclo GLOBAL. Por eso cada fase necesita su propio
   `@keyframes` (`rellena1`..`rellena8`) y no sirve un keyframe único con
   retardos por fase: con el retardo desplazado, el 0 % de cada fase cae en un
   momento distinto del ciclo y la barra se vaciaría 1,4 s después de llenarse,
   justo cuando el recuadro se va a la siguiente.

   SE LLENA, AGUANTA Y SE VACÍA
   La barra se queda llena hasta el final del ciclo y ahí se apaga con un
   fundido (96 % → 100 %) COMÚN a las ocho: ese es el «se vacía y vuelve a
   empezar». El salto de vuelta al principio no se ve, porque en el 0 % cada
   barra ya está a escala 0 (ancho cero).

   EL NÚMERO DEL CENTRO
   Va en el centro de la placa (x = 237, la mitad exacta de 72..402). Las cuatro
   primeras (10, 20, 30 y 45 %) NO llegan al centro con el relleno, así que van
   en gris sobre la placa vacía. Las cuatro últimas (60, 75, 90 y 100 %) SÍ lo
   cubren y llevan el color de la PLACA: el número queda «recortado» y aparece
   justo cuando el color pasa por debajo. Ese truco vale igual para el tema
   claro y el oscuro sin escribir ni una regla más.

   SIN ANIMACIONES (prefers-reduced-motion): las barras se quedan en su
   porcentaje final y los números visibles (ver la media query del final).
   ============================================================ */

.relleno {
  fill: var(--acento);
  /* El relleno es la MISMA placa (mismo ancho, mismas esquinas), encogida en X
     desde la IZQUIERDA: `transform-box: fill-box` con el origen a la izquierda,
     igual que hace `.anillo-marcas` con su rotación. */
  transform-box: fill-box;
  transform-origin: left center;
  transform: scaleX(0);
}

/* La última fase se pinta en verde: es la única que se da por terminada. */
.capa-verde .relleno { fill: var(--verde); }

.relleno,
.porcentaje {
  animation-duration: var(--ciclo, 11.5s);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

.porcentaje {
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .06em;
  text-anchor: middle;
  fill: var(--ink-soft);
  opacity: 0;
  /* El keyframe trae también el `transform` del relleno (crecer en X). Sobre un
     TEXTO eso lo aplastaría, así que aquí se anula: una declaración
     `!important` GANA a las animaciones en el orden del cascade, así que el
     número se queda quieto en el centro y solo hereda el reloj (la opacidad).
     Si alguien quita ese `!important`, los porcentajes saldrán aplastados. */
  transform: none !important;
}

/* Las fases cuya barra LLEGA al centro (60 % o más) llevan el número del color
   de la placa: invisible sobre la placa vacía y legible sobre el relleno. */
.capa.pct-alto .porcentaje { fill: var(--placa); }

/* El reloj de cada fase, medido sobre el ciclo GLOBAL.
   Fase 1: el recuadro llega a su placa en el 0 % y el relleno ocupa el 7,5 %. */
.capa[data-fase="1"] .relleno, .capa[data-fase="1"] .porcentaje { animation-name: rellena1; }
.capa[data-fase="2"] .relleno, .capa[data-fase="2"] .porcentaje { animation-name: rellena2; }
.capa[data-fase="3"] .relleno, .capa[data-fase="3"] .porcentaje { animation-name: rellena3; }
.capa[data-fase="4"] .relleno, .capa[data-fase="4"] .porcentaje { animation-name: rellena4; }
.capa[data-fase="5"] .relleno, .capa[data-fase="5"] .porcentaje { animation-name: rellena5; }
.capa[data-fase="6"] .relleno, .capa[data-fase="6"] .porcentaje { animation-name: rellena6; }
.capa[data-fase="7"] .relleno, .capa[data-fase="7"] .porcentaje { animation-name: rellena7; }
.capa[data-fase="8"] .relleno, .capa[data-fase="8"] .porcentaje { animation-name: rellena8; }

@keyframes rellena1 {
  0%    { transform: scaleX(0); opacity: 1; }
  7.5%  { transform: scaleX(var(--pct, 0)); opacity: 1; }
  96%   { transform: scaleX(var(--pct, 0)); opacity: 1; }
  100%  { transform: scaleX(var(--pct, 0)); opacity: 0; }
}

@keyframes rellena2 {
  0%, 12.5% { transform: scaleX(0); opacity: 1; }
  20%       { transform: scaleX(var(--pct, 0)); opacity: 1; }
  96%       { transform: scaleX(var(--pct, 0)); opacity: 1; }
  100%      { transform: scaleX(var(--pct, 0)); opacity: 0; }
}

@keyframes rellena3 {
  0%, 25% { transform: scaleX(0); opacity: 1; }
  32.5%   { transform: scaleX(var(--pct, 0)); opacity: 1; }
  96%     { transform: scaleX(var(--pct, 0)); opacity: 1; }
  100%    { transform: scaleX(var(--pct, 0)); opacity: 0; }
}

@keyframes rellena4 {
  0%, 37.5% { transform: scaleX(0); opacity: 1; }
  45%       { transform: scaleX(var(--pct, 0)); opacity: 1; }
  96%       { transform: scaleX(var(--pct, 0)); opacity: 1; }
  100%      { transform: scaleX(var(--pct, 0)); opacity: 0; }
}

@keyframes rellena5 {
  0%, 50% { transform: scaleX(0); opacity: 1; }
  57.5%   { transform: scaleX(var(--pct, 0)); opacity: 1; }
  96%     { transform: scaleX(var(--pct, 0)); opacity: 1; }
  100%    { transform: scaleX(var(--pct, 0)); opacity: 0; }
}

@keyframes rellena6 {
  0%, 62.5% { transform: scaleX(0); opacity: 1; }
  70%       { transform: scaleX(var(--pct, 0)); opacity: 1; }
  96%       { transform: scaleX(var(--pct, 0)); opacity: 1; }
  100%      { transform: scaleX(var(--pct, 0)); opacity: 0; }
}

@keyframes rellena7 {
  0%, 75% { transform: scaleX(0); opacity: 1; }
  82.5%   { transform: scaleX(var(--pct, 0)); opacity: 1; }
  96%     { transform: scaleX(var(--pct, 0)); opacity: 1; }
  100%    { transform: scaleX(var(--pct, 0)); opacity: 0; }
}

@keyframes rellena8 {
  0%, 87.5% { transform: scaleX(0); opacity: 1; }
  95%       { transform: scaleX(var(--pct, 0)); opacity: 1; }
  96%       { transform: scaleX(var(--pct, 0)); opacity: 1; }
  100%      { transform: scaleX(var(--pct, 0)); opacity: 0; }
}

/* El recuadro que baja por encima de las placas: mismo tamaño que una
   placa, así que encuadra la fase justo cuando se enciende.
   Va en NARANJA y difuminado: no es un marco, es un haz de luz que pasa
   por encima. El naranja sobre el azul encendido contrasta (son
   complementarios) y hace que se vea cuál está señalando. */
.recuadro {
  fill: var(--naranja-suave);
  stroke: var(--naranja);
  stroke-width: 3;
  opacity: 0;
  filter: blur(2.6px) drop-shadow(0 0 18px var(--naranja-glow));
  animation: recorrido var(--ciclo) linear infinite;
}

@keyframes recorrido {
  0%    { transform: translateY(0);     opacity: 0; }
  4%    { opacity: .95; }
  80%   { opacity: .95; }
  87.5% { transform: translateY(434px); opacity: .95; }
  93%   { opacity: 0; }
  100%  { transform: translateY(434px); opacity: 0; }
}

/* Cada fase entra en cascada al cargar */
.capa {
  opacity: 1;
  animation: entraCapa .75s cubic-bezier(.2, .7, .2, 1) both;
  animation-delay: calc(var(--i) * .09s);
}

@keyframes entraCapa {
  from { opacity: 0; transform: translateX(-16px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* Al pasar el ratón, la fase se marca.
   Nota técnica: el color lo lleva la animación de luz, así que aquí se
   usa el grosor del borde (que la animación no toca) y la frase. */
.capa:hover .placa { stroke-width: 2.6; }
.capa:hover .frase { fill: var(--ink-soft); }

/* Partículas de fondo (las crea hero.js) */
.particulas circle {
  fill: var(--acento);
  opacity: .22;
  animation: deriva linear infinite;
}

@keyframes deriva {
  from { transform: translate(0, 0); }
  to   { transform: translate(var(--dx, 10px), var(--dy, -14px)); }
}

/* ============================================================
   SEPARADOR Y BLOQUES DE SECCIÓN
   ============================================================ */

/* ============================================================
   TRANSICIÓN (scrollytelling)
   ============================================================ */

/* El contenedor mide una pantalla (la portada fijada) MÁS el recorrido del
   cruce: ese trozo de más es el tiempo que la portada se queda clavada
   mientras la sección sube por encima. */
.transicion {
  height: calc(100vh + var(--recorrido));
  height: calc(100dvh + var(--recorrido));
}

/* El separador se dibuja al entrar en pantalla: las dos líneas salen
   hacia los lados desde el centro y la marca aparece en medio.
   Ahora vive dentro del bloque de servicios, así que no lleva márgenes
   propios: el aire se lo da la sección. */
.separador {
  display: flex;
  align-items: center;
  gap: clamp(14px, 2vw, 26px);
  margin: 0;
  padding: 0;
}

.separador-linea {
  flex: 1;
  height: 1px;
  background: var(--placa-borde);
  transform: scaleX(0);
  transition: transform 1.2s cubic-bezier(.2, .7, .2, 1);
}

.separador-linea:first-child { transform-origin: right center; }
.separador-linea:last-child  { transform-origin: left center; }

.separador-marca {
  flex: none;
  width: 26px;
  height: 26px;
  opacity: 0;
  transform: scale(.75);
  transition: opacity .7s ease .35s, transform .8s cubic-bezier(.2, .7, .2, 1) .35s;
}

.separador-marca svg { width: 100%; height: 100%; display: block; }

.separador.visible .separador-linea { transform: scaleX(1); }
.separador.visible .separador-marca  { opacity: 1; transform: scale(1); }

/* Un bloque de sección: ancho completo y mucho aire.
   Va por ENCIMA de la portada fijada (z-index 2) y lleva fondo propio,
   así que sube tapándola. Su transparencia mientras sube la pone hero.js:
   de ahí sale la mezcla. */
.bloque {
  position: relative;
  z-index: 2;
  /* Sin fondo propio: así se ve el fondo de partículas por detrás.
     Los bloques que sí llevan color lo traen de `.bloque-color::before`. */
  background: none;
  max-width: 1680px;
  margin: 0 auto;
  /* RELLENO VERTICAL REBAJADO (2026-09-27). Estaba en clamp(80px, 14vh, 180px)
     = 120 px arriba y 120 abajo, y eso dejaba **310 px de aire** entre el final
     del contenido de una sección y el principio de la siguiente: más de un
     tercio de la pantalla. Durante el cruce se veía ese hueco, que no es de
     ninguna de las dos secciones, y el efecto «una se apaga mientras la otra
     entra» se perdía. Con esto las secciones quedan más apretadas y las dos se
     ven a la vez mientras cruzan. */
  padding: clamp(44px, 6.5vh, 96px) clamp(28px, 5vw, 88px);
  display: grid;
  gap: clamp(32px, 4.5vw, 58px);
}

/* ESTA es la clave del cruce simultáneo: SOLO la sección que va justo
   después de la portada arranca pegada a ella (margen negativo) en vez de
   después de un hueco. Así, en cuanto bajas, la portada se apaga y la
   sección sube A LA VEZ. Las secciones siguientes (03, 04, 05) van
   normales: si esto se aplicara a todas, se apilarían unas sobre otras. */
.transicion + .bloque {
  margin-top: calc(var(--recorrido) * -1);
}

/* ============================================================
   BLOQUES CON COLOR (la «lámpara de sal»)
   ------------------------------------------------------------
   El color del fondo cambia despacio, en bucle, sin que se note el salto:
   de un tono al siguiente en unos 20 segundos, vuelta completa en 90.
   Es para las secciones que llevan color; las de fondo normal no la usan.

   CÓMO ESTÁ HECHO Y POR QUÉ ASÍ:
   - El color NO va en el fondo del bloque, va en un ::before que se sale
     por los lados (inset: 0 -100vmax). Así llega de borde a borde sin
     tocar la estructura y sin el truco de la sombra gigante.
   - Se anima `background-color`, que es una propiedad que el navegador
     interpola de serie. (Animar una variable de color necesitaría
     «@property» y en navegadores viejos daría SALTOS de color.)
   - Los cuatro tonos son variables (--tono-1..4): por eso el mismo
     keyframe sirve para el tema claro y el oscuro. Desde el 2026-09-28 hay
     UNA sola paleta calmada para toda la web (ver `--tono-*` en :root).
   - El bloque arranca PAUSADO y hero.js lo pone en marcha solo cuando
     asoma a la pantalla: no se repinta una superficie enorme sin que
     nadie la mire.
   ============================================================ */

/* ============================================================
   LA LÁMPARA DE SAL (v2)
   ------------------------------------------------------------
   YA NO es un color plano que va cambiando: es una BASE casi blanca con
   MANCHAS DE COLOR que crecen desde el centro, se apagan y se van
   relevando. Es lo que hace una lámpara de sal: luz que respira.

   CÓMO ESTÁ HECHO (corregido el 2026-09-27):
   - **YA NO HAY BASE DE COLOR.** Antes un `::before` pintaba una superficie
     casi blanca de borde a borde (--tono-0). El usuario dijo que NO quería
     «un color completo para la sección», así que se quitó: **el color de la
     sección son solo las manchas**. Efecto secundario buscado: al no haber
     superficie opaca, **el fondo de partículas se ve en todas las secciones**
     (antes cada bloque lo tapaba con su base).
     Si algún día se quiere volver a la superficie completa, se pone
     `background-color: var(--tono-0)` en ese `::before` (las variables
     `--tono-0` siguen definidas en los dos temas, sin usar).
   - **Las MANCHAS son dos capas que se relevan**, no una:
     · `::after` → los tonos 1 y 2.
     · `.lampara-b` → los tonos 3 y 4, **media vuelta después**
       (`animation-delay: calc(var(--lampara) / -2)`).
     El CSS ya preveía la segunda, pero **el elemento `.lampara-b` no existía
     en el HTML**: nunca se pintó, y por eso el fondo se quedaba sin color en
     la segunda mitad del ciclo. Ya está puesto en los tres sitios.
   - Se animan `transform` y `opacity`, que van en la tarjeta gráfica. Antes
     se animaba el color de una superficie enorme: esto es mucho más barato.
   - El `@keyframes florece` tiene **meseta** (0.70 en el 18 %, 0.60 en el
     45 %, 0.28 en el 80 %) y un **suelo de 0.18** (nunca baja a 0): así el
     relevo entre las dos manchas no deja NINGÚN momento sin color y el tono
     saliente se apaga sin llegar a desaparecer.
   - 2026-09-28, A PETICIÓN DEL USUARIO: el color no se veía. La causa eran
     los tonos (casi del color del fondo, 1,5-2,2:1) y el suelo de opacidad
     en 0. Se subió el suelo a 0,18, se mantuvo el pico en 0,70 y los tonos
     se rehicieron para dar 3,3-4,6:1 contra el fondo (ver `--tono-*`).
   - **Arranca PAUSADA** (el `::after` y el `.lampara-b`) y `hero.js` la pone
     en marcha cuando el bloque asoma. *(Antes la pausa estaba solo en
     `.lampara-b`, que no existía, así que la mancha real corría siempre.)*

   MANDO DE VELOCIDAD: `--lampara` (45 s por vuelta). Más alto = más lento.
   ============================================================ */

.bloque-color,
.transicion {
  position: relative;
  background: none;
  /* RECORTE DEL EJE X (no del Y): las manchas de la lámpara crecen con
     `scale` hasta 2,1 y su caja se sale más de 700 px por cada lado. Eso
     ensanchaba el documento (scrollWidth 2319 en una ventana de 1600) y podía
     dar scroll horizontal. Con `clip` se recorta la pintura SIN crear un
     contenedor de scroll, así que el `sticky` de la portada sigue funcionando
     (comprobado). Con `hidden` NO: eso lo rompería. */
  overflow-x: clip;
}

/* AQUÍ ESTABA LA BASE DE COLOR (::before con --tono-0, de borde a borde).
   Se quitó el 2026-09-27: el usuario pidió que la sección NO tuviera un color
   completo, solo las manchas que van apareciendo. Y al quitarla, el fondo de
   partículas (que va detrás de todo) deja de quedar tapado: se ve en todas
   las secciones. **No volver a ponerla sin hablarlo con el usuario.** */

/* Las manchas de color */
.bloque-color::after,
.transicion::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  background-image:
    radial-gradient(closest-side at 50% 45%, var(--tono-1) 0%, transparent 80%),
    radial-gradient(closest-side at 42% 62%, var(--tono-2) 0%, transparent 78%);
  animation: florece var(--lampara, 26s) ease-in-out infinite;
  animation-play-state: paused;
}

@keyframes florece {
  0%   { transform: scale(.20); opacity: .18; }
  18%  { transform: scale(.75); opacity: .70; }
  45%  { transform: scale(1.35); opacity: .60; }
  80%  { transform: scale(1.9); opacity: .28; }
  100% { transform: scale(2.1); opacity: .18; }
}

/* La segunda mancha, media vuelta después: así una empieza a crecer cuando
   la otra está terminando, y el relevo no se nota. */
.bloque-color .lampara-b,
.transicion .lampara-b {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  background-image:
    radial-gradient(closest-side at 55% 55%, var(--tono-3) 0%, transparent 80%),
    radial-gradient(closest-side at 45% 40%, var(--tono-4) 0%, transparent 76%);
  animation: florece var(--lampara, 26s) ease-in-out infinite;
  animation-delay: calc(var(--lampara, 26s) / -2);
  animation-play-state: paused;
}

.bloque-color.en-pantalla::after,
.bloque-color.en-pantalla .lampara-b,
.transicion.en-pantalla::after,
.transicion.en-pantalla .lampara-b {
  animation-play-state: running;
}

/* La rejilla de estos bloques se aclara: las líneas oscuras sobre color no
   se ven. (Se mantiene de la versión anterior.) */
.bloque-color { --rejilla: rgba(255, 255, 255, .30); }

/* La tinta de estos bloques */
.bloque-color .bloque-entrada,
.bloque-color .figura-pie,
.bloque-color .bloque-numero {
  color: var(--tinta-tono);
}

/* Todo lo que no es la rejilla va por encima de ella */
.bloque > *:not(.rejilla):not(.lampara-b) {
  position: relative;
  z-index: 1;
}

/* Rejilla de fondo: es la pista visual que dice «esto es un panel técnico,
   no un folleto». Va difuminada por los bordes para que no parezca una
   cuadrícula pegada encima. */
.rejilla {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right,  var(--rejilla) 1px, transparent 1px),
    linear-gradient(to bottom, var(--rejilla) 1px, transparent 1px);
  background-size: 30px 30px;
  -webkit-mask-image: radial-gradient(ellipse 72% 62% at 50% 45%, #000 18%, transparent 74%);
          mask-image: radial-gradient(ellipse 72% 62% at 50% 45%, #000 18%, transparent 74%);
}

/* Al pulsar un enlace del menú, el título queda justo debajo de la barra.
   `scroll-margin-top` es lo que hace que el ancla no lo pegue al borde.
   Se aplica a la cabecera entera (el número + el título + la entrada): así lo
   que asoma por arriba es el principio de la sección, no el separador. */
.bloque-cabecera {
  max-width: 62ch;
  scroll-margin-top: calc(var(--alto-nav) + var(--aire-ancla));
}

/* La CABECERA de sección NO se desliza al aparecer: solo se aclara.
   El motivo está medido: el navegador calcula el destino del ancla con la
   posición que el elemento tiene EN ESE MOMENTO. Mientras la cabecera no ha
   aparecido está desplazada 28 px hacia abajo (el translateY de `.aparece`),
   así que el scroll se quedaba 28 px corto y el título subía después al
   hacerse visible: acababa a 43 px del borde, medio tapado por la barra.
   Sin deslizamiento cae siempre donde toca. Las demás piezas (.figura, etc.)
   siguen deslizándose igual. */
.js .bloque-cabecera.aparece { transform: none; }

.bloque-numero {
  display: block;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .14em;
  color: var(--acento);
  margin-bottom: 14px;
}

/* Los títulos de sección van en la MISMA tipografía que la marca (Michroma),
   más pequeña que la portada pero MUY grande: es el titular del bloque.
   Michroma solo existe en 400, así que se pone 400 a propósito.
   OJO con el clamp: el mínimo tiene que ser MENOR que el máximo. */
.bloque-titulo {
  margin: 0;
  font-family: var(--wordmark-font);
  font-weight: 400;
  font-size: clamp(2.4rem, 4.2vw, 4.7rem);
  letter-spacing: -.02em;
  line-height: 1.05;
  color: var(--ink);
}

.bloque-entrada {
  margin: 16px 0 0;
  /* En la sans, NO en la monoespaciada: lo pidió el usuario («es muy consolas»).
     Son frases enteras y a este tamaño la mono cansa. La mono se queda para lo
     corto: índices, «Fig. 02», estados del diagrama. */
  font-family: var(--ui);
  font-size: clamp(.95rem, 1.15vw, 1.1rem);
  line-height: 1.6;
  color: var(--ink-faint);
}

/* ---------- Aparición al bajar ----------
   Solo se oculta si hay JavaScript (clase .js puesta en el html).
   Sin JavaScript, el texto se ve: la diferencia entre un efecto y
   una web en blanco. */
.js .aparece {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .9s ease, transform 1s cubic-bezier(.2, .7, .2, 1);
}

.js .aparece.visible {
  opacity: 1;
  transform: none;
}

.aparece-tarde { transition-delay: .18s; }

/* ---------- Diagrama técnico: la arquitectura del clúster ----------
   Lectura de instrumento: núcleo, anillos con marcas de escala, radios y
   seis capas.

   IMPORTANTE: el movimiento (el punto que viaja y el encendido del nodo)
   NO lo lleva el CSS, lo lleva hero.js. Así el impacto y el texto de la
   ficha son la MISMA cosa y no pueden desincronizarse. Por eso aquí no
   hay @keyframes para el punto ni para el nodo. */
/* TRES columnas: la ficha, el diagrama y los dibujos, en ese orden.
   El ORDEN VISUAL lo pone `order`, no el HTML. Mover el bloque de la ficha
   dentro del fichero sería un corta-pega de 120 líneas y el riesgo de perder
   algo no compensa. Consecuencia a saber: el orden del HTML (diagrama →
   dibujo → ficha) es el que recorre un lector de pantalla; el de la vista es
   ficha → diagrama → dibujo. */
.figura {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(200px, .58fr) minmax(0, 1.45fr) minmax(260px, 1fr);
  gap: clamp(20px, 3.2vw, 48px);
  align-items: center;
}

.figura-lectura { order: 1; }
.figura-plano   { order: 2; }
.figura-escena  { order: 3; }

.figura-plano { min-width: 0; }

/* El diagrama se pinta un 30 % MÁS GRANDE que su columna. Se puede hacer sin
   quitarle sitio a nadie porque el propio SVG tiene un 13,3 % de aire a cada
   lado (el anillo exterior solo llega hasta ahí): al desbordar, lo que se
   sale es AIRE, no dibujo. El gráfico pasa de ocupar el 73 % de su columna a
   ocupar el 95 %, y los rótulos de ~10 px a ~12,6 px, con la ficha y el
   dibujo intactos.

   DOS AVISOS PARA QUIEN TOQUE ESTO:
   1. El SVG lleva `pointer-events: none` a propósito: su caja se mete en las
      columnas vecinas y, sin eso, se comería los clics de los botones de la
      ficha. Solo las capas (`.nodo`) vuelven a recibir clics.
   2. Si algún día se dibuja algo pegado al borde del SVG, el desbordamiento
      dejará de caer en aire y habrá que recortarlo. */
.diagrama {
  width: 130%;
  margin-left: -15%;
  max-width: 1100px;
  height: auto;
  display: block;
  pointer-events: none;
}

/* Solo las capas reciben el ratón */
.nodo { pointer-events: auto; }

/* Anillo de marcas: los guiones son la escala. Gira muy despacio, lo justo
   para que se note que está vivo sin que maree. */
.anillo { fill: none; stroke: var(--placa-borde); stroke-width: 1; }

.anillo-marcas {
  fill: none;
  stroke: var(--placa-borde);
  stroke-width: 1.4;
  stroke-dasharray: 1.5 9;
  transform-box: fill-box;
  transform-origin: center;
  animation: girar 150s linear infinite;
}

@keyframes girar {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Los radios: del núcleo hacia cada capa */
.radio-linea {
  stroke: var(--hilo);
  stroke-width: 1.2;
  stroke-dasharray: 3 6;
}

/* El punto que viaja: hero.js le pone la posición cada fotograma.
   Sin JavaScript se queda quieto y transparente en el núcleo, que es
   justo lo que queremos: sin movimiento, sin punto. */
.radio-punto {
  fill: var(--acento);
  filter: drop-shadow(0 0 7px var(--acento-glow));
  transform: translateX(0);
  opacity: 0;
}

/* Núcleo */
.nucleo-halo    { fill: var(--acento); opacity: .07; }
.nucleo-circulo { fill: var(--placa); stroke: var(--acento); stroke-width: 1.6; }

.nucleo-nombre {
  font-family: var(--wordmark-font);
  font-size: 13px;
  fill: var(--ink);
}

.nucleo-nota {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: .1em;
  fill: var(--ink-soft);
}

/* Las capas. La que acaba de recibir el impacto lleva la clase .activo
   (la pone hero.js) y se enciende en AMARILLO con halo. */
/* Las capas del diagrama se pueden PULSAR: llevan a su ficha, igual que los
   botones. Se entiende mejor. También se llega con el tabulador. */
.nodo {
  transition: transform .25s ease;
  cursor: pointer;
}

.nodo:hover { transform: translateY(-3px); }

.nodo:focus { outline: none; }

.nodo:focus-visible .nodo-caja {
  stroke: var(--acento);
  stroke-width: 2.2;
}

.nodo-caja {
  fill: var(--placa);
  stroke: var(--placa-borde);
  stroke-width: 1.3;
  transition: stroke .35s ease, fill .35s ease, stroke-width .35s ease, filter .35s ease;
}

.nodo.activo .nodo-caja {
  stroke: var(--amarillo);
  fill: var(--amarillo-suave);
  stroke-width: 2;
  filter: drop-shadow(0 0 14px var(--amarillo-glow));
}

.nodo-indice {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  fill: var(--acento);
  transition: fill .35s ease;
}

.nodo.activo .nodo-indice { fill: var(--amarillo-fuerte); }

.nodo-nombre {
  font-family: var(--ui);
  font-size: 13px;
  font-weight: 600;
  fill: var(--ink);
}

.nodo-detalle {
  font-family: var(--mono);
  font-size: 10px;
  /* `--ink-soft` y NO `--ink-faint`: medido, `--ink-faint` da **2,63:1** sobre
     la placa blanca, por debajo del 4,5:1 de WCAG. Es el mismo color del que el
     usuario ya se quejó («casi no se ve»). */
  fill: var(--ink-soft);
}

/* Pie de figura: el detalle que hace que esto parezca documentación.
   Ocupa las dos columnas. */
.figura-pie {
  grid-column: 1 / -1;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .05em;
  color: var(--ink-faint);
  text-align: center;
}

/* ---------- La escena: el dibujo con la ficha encima ----------
   Los dibujos son JPEG de líneas sobre fondo BLANCO. Con
   `mix-blend-mode: multiply` el blanco desaparece y quedan solo las líneas:
   NO hay borde de foto, el dibujo se funde con el color del bloque y además
   adopta ese color. Es lo que hace que parezca dibujado en la web.

   En tema OSCURO eso no funciona (oscuro por oscuro = nada): allí se
   invierte la imagen y se usa `screen`, que hace lo mismo al revés. */
/* La escena: proporción casi la del propio dibujo (572×1024). Así el dibujo
   llena la columna de arriba abajo en vez de quedarse flotando en medio. */
.figura-escena {
  position: relative;
  aspect-ratio: 60 / 100;
  min-height: 420px;
  /* QUE QUEPA EN PANTALLA. Sin esto, el dibujo mide hasta **988 px de alto** en
     una tablet, más que la propia pantalla (857), así que no se veía entero ni
     centrándolo. Con el tope, la imagen se reduce y **`object-fit: contain`** se
     encarga de que no se deforme.
     OJO: NO se le pone `margin-inline: auto`. En el grid, eso desactiva el
     estirón de la columna y, como la imagen va en `position: absolute` (no
     cuenta para el tamaño), **la caja se queda en 0 y el dibujo desaparece**.
     Pasó, y por eso está escrito aquí. */
  max-height: min(76vh, 700px);
}

/* El dibujo. Cuatro cosas que lo integran:
   1. `mix-blend-mode: multiply` → el blanco desaparece y queda la línea.
   2. `brightness(1.12)` → el papel de estos dibujos NO es blanco puro (es un
      gris clarito). Subirlo es lo que elimina el RECTÁNGULO tenue; sin esto,
      el resto de la faena no se nota.
   3. `contrast(1.06)` → devuelve a las líneas su oscuridad después de
      subirles el brillo. Sin esto, el dibujo se lavaría.
   4. La máscara → desvanece los CUATRO bordes (dos degradados que se
      cruzan), que es lo que remata el canto. */
.escena-foto {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;        /* el dibujo entero, sin recortar */
  mix-blend-mode: multiply;
  filter: brightness(1.12) contrast(1.06);

  /* Desvanecido SUAVE, solo para rematar el canto. El trabajo de verdad lo
     hace el brillo de arriba: ahora que el papel es blanco, no hace falta
     difuminar media imagen. (Se probó a 11 % y 9 % y quedaba demasiado
     difuminado: no se veía el dibujo.) */
  -webkit-mask-image:
    linear-gradient(to right,  transparent 0, #000 5%, #000 95%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 4%, #000 96%, transparent 100%);
          mask-image:
    linear-gradient(to right,  transparent 0, #000 5%, #000 95%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 4%, #000 96%, transparent 100%);
  -webkit-mask-composite: source-in;   /* Safari: cruzar las dos máscaras */
          mask-composite: intersect;   /* estándar */
}

html[data-tema="oscuro"] .escena-foto {
  mix-blend-mode: screen;
  /* Invertido: el papel pasa a oscuro y las líneas a claras. El contraste
     alto es lo que manda el papel a negro de verdad. */
  filter: invert(1) contrast(1.45);
}

/* La ficha: en su propia columna (a la izquierda del diagrama), translúcida
   para que se vea el color del bloque por debajo.
   YA NO SE ARRASTRA: cuando estaba encima del dibujo tenía sentido apartarla;
   ahora tiene su sitio y no tapa nada. (El arrastre se quitó de hero.js.) */
.figura-lectura {
  display: grid;
  gap: 18px;
  align-content: center;
  padding: clamp(18px, 2vw, 26px);
  background: rgba(255, 255, 255, .72);
  border: 1px solid var(--placa-borde);
  border-radius: 14px;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

html[data-tema="oscuro"] .figura-lectura {
  background: rgba(20, 22, 25, .68);
}

.lectura-item { display: block; }

.js .lectura-item           { display: none; }
.js .lectura-item.activo    { display: block; }

.lectura-indice {
  display: block;
  margin-bottom: 6px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .14em;
  color: var(--amarillo-fuerte);
}

/* El título de la ficha, en la tipografía de la marca (Michroma), más
   pequeña que el titular de sección: misma voz, distinto volumen. */
.lectura-titulo {
  margin: 0 0 8px;
  font-family: var(--wordmark-font);
  font-weight: 400;
  font-size: clamp(1.05rem, 1.35vw, 1.35rem);
  letter-spacing: -.01em;
  line-height: 1.2;
  color: var(--ink);
}

.lectura-texto {
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* Controles: existen solo si hay JavaScript (sin JS no hacen falta,
   porque se ven las seis fichas). */
.lectura-controles { display: none; }

.js .lectura-controles {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
}

.lectura-boton {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  font: inherit;
  font-size: 14px;
  line-height: 1;
  color: var(--ink-soft);
  /* Fondo distinto al del recuadro (que es blanco): si no, el botón
     desaparecería dentro de la ficha. */
  background: var(--bg);
  border: 1px solid var(--placa-borde);
  border-radius: 8px;
  cursor: pointer;
  transition: color .2s ease, border-color .2s ease;
}

.lectura-boton:hover {
  color: var(--ink);
  border-color: var(--ink-soft);
}

.lectura-cuenta {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .08em;
  color: var(--ink-faint);
}

/* ============================================================
   BLOQUE 02 · MISSION
   ------------------------------------------------------------
   Va justo después de la portada: misión, visión y el ecosistema.
   La lámpara es la paleta calmada única (verde salvia + azul polvo +
   lavanda), la misma de toda la web desde el 2026-09-28.
   NO lleva rejilla: la cuadrícula se queda solo en Services.
   ============================================================ */




/* ---------- Misión y visión ----------
   DOS COLUMNAS, con un filete de 1 px entre las dos y otro arriba de cada una:
   se leen como dos fichas, no como dos párrafos sueltos.
   LOS RÓTULOS van en MICROMA, la tipografía de los títulos de la web (el
   usuario se quejó, con razón, de que en monoespaciada y a 12 px quedaban
   MÁS PEQUEÑOS que el texto que anuncian). El TEXTO va en la sans de
   interfaz: es una declaración larga y la mono no se lee a este tamaño. */
.mision-textos {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
}

.mision-pieza {
  padding-right: clamp(24px, 3vw, 56px);
  border-top: 1px solid var(--placa-borde);
  padding-top: clamp(18px, 2vw, 26px);
}

.mision-pieza + .mision-pieza {
  border-left: 1px solid var(--placa-borde);
  padding-left: clamp(24px, 3vw, 56px);
  padding-right: 0;
}

.mision-etiqueta {
  display: block;
  /* Michroma solo tiene el peso 400: pedirle negrita hace que el navegador la
     engorde a la fuerza. */
  font-family: var(--wordmark-font);
  font-weight: 400;
  font-size: clamp(.85rem, 1vw, 1.05rem);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--acento);
  margin-bottom: clamp(14px, 1.6vw, 20px);
}

.mision-texto {
  margin: 0;
  font-size: clamp(1.15rem, 1.6vw, 1.5rem);
  line-height: 1.5;
  color: var(--ink);
  max-width: 52ch;
}

/* Los textos de ESTA sección van JUSTIFICADOS (lo pidió el usuario). Con
   `hyphens: auto` para que no se abran ríos de espacio: el navegador parte las
   palabras donde toca (el <html> ya lleva lang="es"). */
#mision .mision-texto,
#mision .bloque-entrada {
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
}

/* ============================================================
   EL DIAGRAMA DE MISSION
   ------------------------------------------------------------
   Sustituye a la imagen generada (fotos/seccion2.jpeg), que tenía demasiado
   detalle. Cuenta lo mismo con menos piezas: lo que la empresa ya sabe entra,
   se procesa DENTRO de su servidor, sale una respuesta con la fuente delante
   y lo aprendido vuelve a la base.

   TRES COSAS A SABER SI SE TOCA:

   1. LAS CLASES VAN CON PREFIJO `md-` A PROPÓSITO. `.nodo` y `.hilo` ya
      existen en el bloque de arquitectura: sin prefijo, se pisarían.
   2. EL FLUJO USA `offset-path: var(--ruta)`, y la variable YA contiene el
      `path(...)` completo. Escribir `offset-path: path(var(--ruta))` genera un
      `path(path(...))`, que no es válido y deja los puntos parados.
   3. LAS ANIMACIONES DE BUCLE ARRANCAN PAUSADAS y las pone en marcha
      `hero.js` cuando el bloque asoma (clase `.en-pantalla`, la misma que usa
      la lámpara): repintar lo que nadie mira es tirar batería.
   ============================================================ */

/* EL DIAGRAMA DE MISSION TIENE DOS VERSIONES: la HORIZONTAL (ordenador y
   tablet, la de siempre) y la VERTICAL (móvil, apilada). Aquí se les dan los
   mismos estilos y abajo se decide cuál se ve.

   POR QUÉ DOS: en un móvil, el dibujo horizontal dejaría los rótulos a ~5 px
   (medido), así que en vez de encogerlo hasta que no se lea, se APILA. Es la
   única forma de que se vea entero Y legible a la vez.

   Las dos versiones comparten las MISMAS claves de texto (`mision.d.*`), así que
   la vertical sale traducida sin trabajo extra. */
/* La lista de problemas que comparte cada sector, en el mapa vertical. Va en
   `--ink-soft` por lo mismo que el resto de subtítulos: `--ink-faint` da 2,63:1
   y no llega al 4,5:1 de WCAG.
   TAMAÑO, MEDIDO: a 9,5 px la lista más larga medía **480 px en un lienzo de
   420** y se salía. A **8 px** se queda en 404, con 16 px de aire. **Si se
   alarga alguno de esos textos, hay que volver a medirlo.** */
.sprob {
  font-family: var(--mono);
  font-size: 8px;
  fill: var(--ink-soft);
}

/* OJO: LAS REGLAS DE "QUÉ DIBUJO SE VE" ESTÁN AL FINAL DEL FICHERO, no aquí.
   Tienen que ir DESPUÉS de las definiciones de `.dss8-diagrama` y
   `.mapa-sectores`: si van antes, su `display: block` gana y el dibujo
   horizontal se sigue pintando (y ocupando 820 px) aunque debería estar
   oculto en móvil. **Ese fallo se cometió y costó un rato encontrarlo.** */

.md-rot  { font-family: var(--mono); font-size: 13px; letter-spacing: .1em;
           text-transform: uppercase; fill: var(--ink-soft); }
.md-et   { font-family: var(--mono); font-size: 14px; fill: var(--ink); }
/* LOS SUBTÍTULOS VAN EN `--ink-soft`, NO en `--ink-faint`. Medido: `--ink-faint`
   (#9ba0a8) sobre blanco da **2,63:1**, por debajo del 4,5:1 que pide WCAG para
   texto. Es el mismo color que el usuario ya detectó a ojo como «casi no se ve»
   en este diagrama, así que aquí se corrige igual que se hizo en el del bloque
   04 (`d8-sub`). La jerarquía se mantiene por TAMAÑO, no bajando el contraste. */
.md-sub  { font-family: var(--mono); font-size: 11px; fill: var(--ink-soft); }
.md-num  { font-family: var(--mono); font-size: 12px; font-weight: 700;
           letter-spacing: .12em; fill: var(--acento); }
/* TAMAÑO DEL TEXTO DEL NÚCLEO, medido: «Local Model» a 17px mide 117px y el
   círculo tiene 108 de diámetro, así que SE SALÍA por los lados. A 14px mide
   96px y entra con aire. **Si se cambia el texto del núcleo, hay que volver a
   medirlo** (`getBBox()`), porque es lo primero que se desborda. */
.md-gran { font-family: "Science Gothic", var(--mono); font-size: 14px;
           font-weight: 500; fill: var(--ink); }

/* CONTRASTE DE LOS TRAZOS. Estaban en `--placa-borde` (#dcdde1, un gris casi
   blanco) sobre un fondo claro: los iconos del cilindro y de la persona CASI NO
   SE VEÍAN (el del documento se salvaba por las rayas de dentro). El marco sí
   se queda tenue a propósito: es un marco, no un dato.
   En el bloque de arquitectura los nodos sí pueden ir en `--placa-borde` porque
   allí el fondo es lavanda y el blanco destaca; aquí no. */
.md-marco { fill: none; stroke: var(--placa-borde); stroke-width: 1.5; }
.md-hilo  { fill: none; stroke: var(--ink-soft); stroke-width: 1.5; }
.md-nodo  { fill: var(--placa); stroke: var(--ink-soft); stroke-width: 1.5; }

.md-halo {
  fill: none; stroke: var(--acento); stroke-width: 1.5; opacity: .5;
  transform-box: fill-box; transform-origin: center;
  animation: md-respira 3.2s ease-in-out infinite;
}
@keyframes md-respira {
  0%, 100% { transform: scale(1);    opacity: .45; }
  50%      { transform: scale(1.22); opacity: .12; }
}

.md-anillo {
  fill: none; stroke: var(--acento); stroke-width: 1.5; opacity: .35;
  stroke-dasharray: 3 7;
  transform-box: fill-box; transform-origin: center;
  animation: md-gira 22s linear infinite;
}
@keyframes md-gira { to { transform: rotate(360deg); } }

/* El punto que recorre cada línea: es lo que hace que el diagrama esté vivo */
.md-flujo {
  fill: var(--acento);
  offset-path: var(--ruta);
  offset-rotate: 0deg;
  animation: md-viaja 2.6s linear infinite;
}
@keyframes md-viaja {
  from { offset-distance: 0%; }
  to   { offset-distance: 100%; }
}

/* Pausadas hasta que el bloque asoma (lo pone hero.js) */
.md-flujo,
.md-halo,
.md-anillo { animation-play-state: paused; }

.en-pantalla .md-flujo,
.en-pantalla .md-halo,
.en-pantalla .md-anillo { animation-play-state: running; }

/* Las piezas entran una detrás de otra al cargar */
.md-entra { animation: md-aparece .7s var(--easing-entrada) both; }
@keyframes md-aparece {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
.md-e1 { animation-delay: .05s; }
.md-e2 { animation-delay: .18s; }
.md-e3 { animation-delay: .31s; }
.md-e4 { animation-delay: .44s; }
.md-e5 { animation-delay: .57s; }

@media (max-width: 900px) {
  /* En móvil: una columna y el filete pasa a ser una raya horizontal */
  .mision-textos { grid-template-columns: 1fr; gap: clamp(26px, 3vw, 44px); }
  .mision-pieza { padding-right: 0; }
  .mision-pieza + .mision-pieza {
    border-left: 0;
    border-top: 1px solid var(--placa-borde);
    padding-left: 0;
    padding-top: clamp(26px, 3vw, 44px);
  }
}

/* Con «sin animaciones»: el diagrama se queda quieto y sin puntos */
@media (prefers-reduced-motion: reduce) {
  .md-flujo,
  .md-halo,
  .md-anillo,
  .md-entra { animation: none !important; }
  .md-flujo { display: none; }
  .md-halo,
  .md-anillo { opacity: .35; }
}


/* ============================================================
   BLOQUE 04 · DSS8 MICRO MODELS
   ------------------------------------------------------------
   Cómo se entrena un micro modelo a partir de la base de conocimiento.
   La lámpara es la paleta calmada única (verde salvia + azul polvo +
   lavanda), la misma de toda la web desde el 2026-09-28.
   NO lleva rejilla de fondo: la cuadrícula se queda solo en Services,
   por indicación del usuario.
   ============================================================ */

/* ---------- El diagrama: de lo que la empresa genera a sus módulos ----------
   Cinco fuentes hacen embudo hacia la base de conocimiento, que se construye
   por CAPAS (una por fuente, de abajo arriba): eso es el uso, el tiempo. Cuando
   la base está formada, los módulos por dominio se encienden.

   Sustituye a las diez estaciones del proceso de entrenamiento, que contaban el
   CÓMO (fine-tuning, LoRA, métricas). Aquí se cuenta el QUÉ.

   TRES COSAS A SABER SI SE TOCA:
   1. LAS CLASES VAN CON PREFIJO `d8-`. `.caja`, `.hilo` y `.nodo` ya existen
      en los otros diagramas: sin prefijo, se pisarían.
   2. EL FLUJO USA `offset-path: var(--ruta)`, y la variable YA contiene el
      `path(...)` completo. Escribir `offset-path: path(var(--ruta))` genera un
      `path(path(...))`, que no es válido y deja los puntos parados.
   3. LA PAUSA VA CON `.js` DELANTE: las animaciones arrancan paradas y las pone
      en marcha hero.js cuando el bloque asoma (`.en-pantalla`), igual que la
      lámpara. Repintar lo que nadie mira es tirar batería. El `.js` es lo que
      hace que SIN JavaScript el dibujo se vea entero en vez de quedarse con el
      depósito vacío (las capas arrancan invisibles). */
.dss8-diagrama {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

/* ---------- Rotulación ---------- */
.d8-rot { font-family: var(--mono); font-size: 13px; letter-spacing: .1em;
          text-transform: uppercase; fill: var(--ink-soft); }
.d8-et  { font-family: var(--mono); font-size: 14px; fill: var(--ink); }
/* LOS SUBTÍTULOS VAN EN `--ink-soft`, NO en `--ink-faint`. Medido: `--ink-faint`
   (#9ba0a8) sobre blanco da **2,63:1**, por debajo del 4,5:1 que pide WCAG para
   texto, y estos subtítulos van dentro de cajas blancas. Con `--ink-soft` sube a
   **8,12:1**. Es el mismo fallo que el usuario ya detectó a ojo en el diagrama
   de Mission («casi no se ve»): la jerarquía se mantiene por TAMAÑO y por peso,
   no bajando el contraste. */
.d8-sub { font-family: var(--mono); font-size: 11px; fill: var(--ink-soft); }
.d8-mod { font-family: "Science Gothic", var(--mono); font-size: 15px;
          font-weight: 500; fill: var(--ink); }

/* ---------- Piezas ----------
   El trazo va en `--ink-soft`, NO en `--placa-borde`: sobre el fondo de esta
   sección el gris casi blanco no se ve. Es el mismo fallo que se midió en el
   diagrama de Mission (contraste 2,31:1, por debajo del 3:1 de un gráfico). */
.d8-caja     { fill: var(--placa); stroke: var(--ink-soft); stroke-width: 1.5; }
.d8-hilo     { fill: none; stroke: var(--ink-soft); stroke-width: 1.5; }
.d8-deposito { fill: none; stroke: var(--acento); stroke-width: 2; }

/* El punto que recorre cada línea: es lo que hace que el dibujo esté vivo */
.d8-flujo {
  fill: var(--acento);
  offset-path: var(--ruta);
  offset-rotate: 0deg;
  animation: d8-viaja 2.6s linear infinite;
}
@keyframes d8-viaja {
  from { offset-distance: 0%; }
  to   { offset-distance: 100%; }
}

/* ---------- La base se construye por capas, de abajo arriba ----------
   El `both` NO es decorativo: sin él, durante el retardo la capa se queda en su
   estado natural (opaca) y al abrir la sección se ven TODAS ya apiladas antes
   de que les toque. */
.d8-capa {
  fill: var(--acento-suave);
  stroke: var(--acento);
  stroke-width: 1.2;
  transform-box: fill-box;
  transform-origin: bottom;
  animation: d8-apila 6s ease-in-out infinite both;
}
@keyframes d8-apila {
  0%, 5%   { opacity: 0; transform: translateY(14px); }
  22%, 88% { opacity: 1; transform: none; }
  100%     { opacity: 0; transform: translateY(14px); }
}
.d8-c1 { animation-delay: 0s; }   .d8-c2 { animation-delay: .3s; }
.d8-c3 { animation-delay: .6s; }  .d8-c4 { animation-delay: .9s; }
.d8-c5 { animation-delay: 1.2s; }

/* ---------- Los módulos se encienden cuando la base ya está formada ---------- */
.d8-modulo { animation: d8-enciende 6s ease-in-out infinite both; }
@keyframes d8-enciende {
  0%, 55%  { opacity: .25; }
  70%, 90% { opacity: 1; }
  100%     { opacity: .25; }
}
.d8-m1 { animation-delay: 0s; }    .d8-m2 { animation-delay: .35s; }
.d8-m3 { animation-delay: .7s; }   .d8-m4 { animation-delay: 1.05s; }

/* Paradas hasta que el bloque asoma (lo pone hero.js) */
.js .d8-flujo,
.js .d8-capa,
.js .d8-modulo { animation-play-state: paused; }

.js .en-pantalla .d8-flujo,
.js .en-pantalla .d8-capa,
.js .en-pantalla .d8-modulo { animation-play-state: running; }

/* Con «sin animaciones»: el dibujo se queda quieto, entero y sin puntos */
@media (prefers-reduced-motion: reduce) {
  .d8-flujo,
  .d8-capa,
  .d8-modulo { animation: none !important; }
  .d8-flujo { display: none; }
  .d8-capa,
  .d8-modulo { opacity: 1; }
  .d8-capa { transform: none; }
}

/* ============================================================
   BLOQUE 05 · INDUSTRIES
   ============================================================ */

/* Tiene la lámpara calmada única (verde salvia + azul polvo + lavanda), la
   misma de toda la web desde el 2026-09-28. Mismo mecanismo, misma paleta. */
#industries {
  /* Se sube un poco sobre el bloque anterior: mientras sube, lo va tapando.
     Eso da la sensación de cruce SIN fijar la pantalla, que es lo que no
     queremos aquí (fijar obliga al lector a tragarse la animación entera).
     El margen es MENOR que el aire de abajo del bloque anterior, así que
     solo se come espacio vacío. */
  margin-top: calc(clamp(80px, 14vh, 180px) * -0.55);
}

/* Los bloques con color que NO son la portada empiezan aclarados y se
   completan al subir. Con JavaScript solo: sin JS, se ven enteros. */
.js .bloque-color:not(#services) { opacity: .25; }

/* Este bloque lleva una sola columna: el mapa de sectores */
.figura-sencilla { display: block; }

.mapa-sectores {
  width: 100%;
  max-width: 900px;
  height: auto;
  display: block;
  margin: 0 auto;
}

.converge-linea {
  stroke: var(--hilo);
  stroke-width: 1.2;
  stroke-dasharray: 3 6;
}

/* El punto que va del sector al centro. Cada uno recorre SU distancia
   (--largo, puesta en el HTML), así que todos llegan a la vez al centro. */
.converge-punto {
  fill: var(--acento);
  filter: drop-shadow(0 0 7px var(--acento-glow));
  animation: converge 12s cubic-bezier(.4, 0, .2, 1) infinite;
  animation-delay: calc(var(--i) * -1.1s);
}

@keyframes converge {
  0%   { transform: translateX(0);                             opacity: 0; }
  5%   { opacity: 1; }
  26%  { transform: translateX(calc(var(--largo, 0) * 1px));   opacity: 1; }
  31%  { opacity: 0; }
  100% { transform: translateX(calc(var(--largo, 0) * 1px));   opacity: 0; }
}

/* La placa del sector se enciende cuando su punto llega al centro */
.sector-caja {
  fill: var(--placa);
  stroke: var(--placa-borde);
  stroke-width: 1.3;
  animation: sectorLlega 12s cubic-bezier(.4, 0, .2, 1) infinite;
  animation-delay: calc(var(--i) * -1.1s);
}

@keyframes sectorLlega {
  0%, 22%  { stroke: var(--placa-borde); fill: var(--placa);        stroke-width: 1.3; }
  27%      { stroke: var(--acento);      fill: var(--acento-suave); stroke-width: 2;   }
  36%,100% { stroke: var(--placa-borde); fill: var(--placa);        stroke-width: 1.3; }
}

.sector-placa-indice {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  fill: var(--acento);
}

.sector-placa-nombre {
  font-family: var(--ui);
  font-size: 13px;
  font-weight: 600;
  fill: var(--ink);
}

/* ---------- Las cinco fichas de sector ----------
   Separadas por líneas de 1 px, como el resto de la web. */
.sectores {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1px;
  background: var(--placa-borde);
  border: 1px solid var(--placa-borde);
  border-radius: 14px;
  overflow: hidden;
}

.sector {
  background: var(--placa);
  padding: 24px 26px 28px;
  display: grid;
  gap: 10px;
  align-content: start;
}

/* La cascada: cada ficha entra un poco después que la anterior */
.sectores .aparece { transition-delay: calc(var(--i, 0) * 90ms); }

.sector-indice {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .14em;
  color: var(--acento);
}

/* Los títulos de sector, en la tipografía de la marca */
.sector-titulo {
  margin: 0;
  font-family: var(--wordmark-font);
  font-weight: 400;
  font-size: clamp(1rem, 1.15vw, 1.2rem);
  letter-spacing: -.01em;
  line-height: 1.22;
  color: var(--ink);
}

/* La frase del socio: es la que vende, va destacada */
.sector-frase {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--ink);
}

.sector-texto {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* La pregunta que hoy no se puede hacer: marcada, como una cita técnica */
.sector-pregunta {
  margin: 4px 0 0;
  padding-left: 12px;
  border-left: 2px solid var(--acento);
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-soft);
}

/* ---------- BLOQUE 04 (nuevo): cajas, conexiones y ficha ----------
   OJO: las reglas antiguas de este bloque (.converge-*, .sector-placa-*,
   .sectores, .sector-frase) YA NO SE USAN: el diagrama se rehizo y quedaron
   huérfanas. Hay que borrarlas en el siguiente paso (no se tocan ahora para
   no arriesgar más cambios de golpe). */

/* Las conexiones: cada línea une un sector con un problema que le pasa.
   Apagadas de serie; al elegir un sector, se encienden las suyas. */
.hilo-s {
  fill: none;
  stroke: var(--hilo);
  stroke-width: 1.4;
  opacity: .6;
  transition: stroke .3s ease, opacity .3s ease, stroke-width .3s ease;
}

.hilo-s.activo {
  stroke: var(--acento);
  stroke-width: 2;
  opacity: 1;
}

/* Cajas de los problemas: discontinuas, para que se lean como contexto
   y no como algo que se pulsa.
   OJO con el color: este bloque tiene fondo claro (la lámpara), y el gris
   claro (--ink-faint) sobre beige NO SE LEE. De ahí que estos dos textos
   vayan oscuros. */
.prob-caja {
  fill: none;
  stroke: var(--placa-borde);
  stroke-width: 1.2;
  stroke-dasharray: 5 4;
}

.prob-titulo {
  font-family: var(--ui);
  font-size: 12.5px;
  font-weight: 600;
  fill: var(--ink);
}

.prob-sub {
  font-family: var(--mono);
  font-size: 10px;
  fill: var(--tinta-tono);
  opacity: .8;
}

/* Cajas de los sectores: se pulsan */
.scaja-g { cursor: pointer; }

.scaja {
  fill: var(--placa);
  stroke: var(--placa-borde);
  stroke-width: 1.3;
  transition: stroke .3s ease, fill .3s ease, stroke-width .3s ease;
}

.scaja-g:hover .scaja { stroke: var(--ink-soft); }

.scaja-g:focus { outline: none; }
.scaja-g:focus-visible .scaja { stroke: var(--acento); stroke-width: 2.4; }

.scaja-g.activo .scaja {
  stroke: var(--acento);
  fill: var(--acento-suave);
  stroke-width: 2;
}

.scaja-titulo {
  font-family: var(--ui);
  font-size: 13px;
  font-weight: 600;
  fill: var(--ink);
}

.scaja-sub {
  font-family: var(--mono);
  font-size: 10px;
  fill: var(--ink-faint);
}

.scaja-indice {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  fill: var(--acento);
}

/* ---------- La ficha del sector elegido ----------
   Sin JavaScript se ven las cinco seguidas; con JavaScript, solo la de la
   caja que se pulse. Con aire y con la frase del socio como titular. */
.sector-panel { position: relative; }

.js .sector-panel .sector { display: none; }
.js .sector-panel .sector.activo { display: block; }

.sector {
  background: var(--placa);
  border: 1px solid var(--placa-borde);
  border-radius: 16px;
  padding: clamp(24px, 3.4vw, 44px);
  display: grid;
  gap: 16px;
  align-content: start;
}

.sector-indice {
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--acento);
}

.sector-titulo {
  margin: 0;
  font-family: var(--wordmark-font);
  font-weight: 400;
  font-size: clamp(1.35rem, 2.1vw, 2.1rem);
  letter-spacing: -.015em;
  line-height: 1.18;
  color: var(--ink);
  max-width: 34ch;
}

.sector-texto {
  margin: 0;
  font-size: clamp(.95rem, 1.1vw, 1.1rem);
  line-height: 1.7;
  color: var(--ink-soft);
  max-width: 74ch;
}

.sector-pregunta {
  margin: 6px 0 0;
  padding: 16px 20px;
  background: var(--acento-suave);
  border-left: 3px solid var(--acento);
  border-radius: 0 10px 10px 0;
  font-family: var(--mono);
  font-size: clamp(.8rem, .95vw, .92rem);
  line-height: 1.55;
  color: var(--ink);
  max-width: 68ch;
}

/* ============================================================
   BLOQUE 06 · CONTACT
   ------------------------------------------------------------
   El cierre de la web. La lámpara es la paleta calmada única (verde salvia
   + azul polvo + lavanda), la misma de toda la web desde el 2026-09-28.
   NO lleva rejilla de fondo: la cuadrícula se queda solo en Services.
   ============================================================ */

/* ---------- El correo ----------
   Es lo único que hay que hacer en esta sección, así que se lleva todo el peso:
   grande, sin mayúsculas gritonas y con un subrayado que se dibuja al pasar el
   ratón. NADA DE BOTONES: un enlace con el correo a la vista dice más que un
   «contáctanos» al que hay que pulsar para saber a dónde va. */
.contacto {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin-top: clamp(22px, 3.2vw, 38px);
}

.contacto-etiqueta {
  margin: 0;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.contacto-correo {
  position: relative;
  display: inline-block;
  padding-bottom: 8px;
  font-family: var(--wordmark-font);
  font-size: clamp(1.25rem, 3.1vw, 2.5rem);
  letter-spacing: -.01em;
  line-height: 1.15;
  color: var(--ink);
  text-decoration: none;
  /* El correo no lleva espacios: en una pantalla estrecha hay que dejar que
     parta, o desborda la sección. */
  overflow-wrap: anywhere;
}

/* El subrayado que se dibuja: va en un pseudo-elemento para poder animar su
   ancho sin tocar la tipografía. */
.contacto-correo::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--acento);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .45s cubic-bezier(.22, 1, .36, 1);
}

.contacto-correo:hover::after,
.contacto-correo:focus-visible::after { transform: scaleX(1); }

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

.contacto-nota {
  margin: 0;
  max-width: 62ch;
  font-size: clamp(.95rem, 1.15vw, 1.1rem);
  line-height: 1.6;
  color: var(--ink-faint);
}

/* Quien pida no ver animaciones, no ve animaciones: el subrayado aparece de
   golpe al pasar el ratón, sin dibujarse. */
@media (prefers-reduced-motion: reduce) {
  .contacto-correo::after { transition: none; }
}

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .hero {
    grid-template-columns: 1fr;
    align-items: start;
    gap: clamp(28px, 7vw, 48px);
    padding: clamp(20px, 5vw, 40px);
    padding-top: 84px;
  }

  /* En móvil el factor sube a 26vw para que la palabra no quede pequeña:
     con 19vw se quedaba en 44 px por línea, que en un héroe es poca cosa. */
  .wordmark { font-size: clamp(2.8rem, calc(26vw * var(--escala, 1)), 5.5rem); }

  .capas { max-width: 560px; }

  .nav { padding: 11px 16px; gap: 14px; }
  .nav-marca { font-size: 13px; }
  .nav-enlaces { gap: 14px; }
  .nav-enlaces a { font-size: 12px; }

  /* En móvil, una sola columna y en el orden acordado: ficha, diagrama,
     dibujo. El diagrama es ancho, así que se arrastra en horizontal en vez
     de encogerlo hasta que no se lea nada. */
  .figura { grid-template-columns: 1fr; }
  .figura-plano { overflow-x: auto; }
  /* En móvil el gráfico NO se desborda: ya hay scroll horizontal para verlo */
  .diagrama { width: 100%; margin-left: 0; min-width: 640px; max-width: none; }

  .figura-escena { aspect-ratio: 82 / 100; min-height: 0; }

  /* El mapa de sectores también es ancho: se arrastra en horizontal */
  .figura-sencilla { overflow-x: auto; }
  .mapa-sectores { min-width: 620px; }

  /* Mission y el bloque 04 FALTABAN en esta lista: como `.figura-sencilla` es
     scrolleable pero su dibujo no tenía mínimo, se encogían hasta los 444 px y
     los rótulos quedaban a ~5 px, ilegibles. Van con el MISMO criterio que el
     mapa de sectores —unos 0,7 del ancho del dibujo (1180 × 0,7 ≈ 820)—, que
     deja los rótulos a ~9 px. El resto del dibujo se ve arrastrando. */
  .mision-diagrama,
  .dss8-diagrama { min-width: 820px; }

  /* En móvil se DESACTIVA el fijado de la portada: la barra del navegador
     cambia de altura al hacer scroll, y con dvh el efecto da tirones.
     Y si no hay fijado, el margen negativo sobra: taparía la portada. */
  .transicion { height: auto; }
  .hero { position: static; height: auto; }

  /* OJO CON LA ESPECIFICIDAD, que aquí se coló un fallo GRAVE: poner
     `.bloque { margin-top: 0 }` NO ANULA el margen negativo de los cruces.
     Ese margen viene de `.transicion + .bloque` —DOS clases— y de `#industries`
     —un id—, y los dos GANAN a una sola clase. Resultado medido sin esto:
     `#mision` se subía **-757 px**, una pantalla entera, y la portada quedaba
     debajo con los textos pisados. Hay que repetir los selectores EXACTOS. */
  .transicion + .bloque,
  #industries { margin-top: 0; }
}

/* ============================================================
   TABLETS (700-900 px): LOS DIBUJOS ANCHOS YA CABEN
   ------------------------------------------------------------
   En móvil los diagramas se ARRASTRAN a propósito (ver la media query de
   arriba): escalarlos hasta que quepan dejaría los rótulos a 4,9-5,9 px, que
   no se leen. **En una tablet eso ya no es verdad**: el hueco es de ~690 px y
   al escalarlos los rótulos quedan a **7,6 px**, que se leen.

   Así que en tablet se QUITA el ancho mínimo y el dibujo se ve ENTERO, sin
   arrastrar. Medido: con esto, Mission y DSS8 (los dos que se arrastraban en
   tablet) pasan de 820 px con scroll a 691 px enteros.

   POR QUÉ 700 Y NO 600: se probó con 600 y los rótulos quedaban a **5,9 px**,
   otra vez ilegibles. El corte está donde el rótulo llega a ~7 px, que es el
   mínimo que se lee sin esfuerzo. **Es un compromiso a propósito:** entre 600 y
   700 px el dibujo se arrastra, porque escalado no se leería.

   OJO CON EL ORDEN: esta media query va DESPUÉS de la de 900 px a propósito.
   Las dos tocan `min-width` con la MISMA especificidad, así que gana la última.
   ============================================================ */
@media (min-width: 700px) and (max-width: 900px) {
  .mision-diagrama,
  .dss8-diagrama,
  .mapa-sectores,
  .diagrama { min-width: 0; }
}

/* ---------- Quien pida no ver animaciones, no ve animaciones ---------- */
@media (prefers-reduced-motion: reduce) {
  .capa,
  .marco,
  .placa,
  .relleno,
  .porcentaje,
  .marca,
  .indice,
  .etiqueta,
  .pulso,
  .recuadro,
  .anillo-marcas,
  .wordmark,
  .particulas circle {
    animation: none !important;
  }

  /* Sin animación, las barras se quedan en su porcentaje FINAL y con el número
     a la vista: es más honesto que dejarlas vacías (enseñan el resultado del
     recorrido, no el principio). */
  .relleno { transform: scaleX(var(--pct, 0)); }
  .porcentaje { opacity: 1; }

  /* Sin pulso, sin recuadro ni partículas: se quedan las ocho fases
     quietas y legibles. */
  .pulso,
  .recuadro,
  .particulas { display: none; }

  /* Apariciones, separador y diagrama: sin movimiento, pero TODO visible
     y en su sitio. Nada puede quedarse oculto por pedir menos animación. */
  .js .aparece { opacity: 1; transform: none; }
  /* Toda la secuencia de la portada, quieta y visible */
  .js .hero-logo .placa,
  .js .hero .wordmark,
  .js .hero .claim,
  .js .eslogan { opacity: 1; transform: none; }
  /* Los cuatro pisos del logo son colores llenos: ya no hay grises al 50 % que
     conservar, así que aquí no hace falta repetir ninguna opacidad. */
  .hero.monta .hero-logo .placa,
  .hero.monta .wordmark,
  .hero.monta .claim,
  .hero.monta .eslogan { animation: none !important; }
  .separador-linea { transform: scaleX(1); }
  .separador-marca { opacity: 1; transform: none; }

  /* El diagrama: sin puntos, sin lectura automática y con las seis fichas
     seguidas. Los controles no hacen falta y se esconden. */
  .radio-punto { opacity: 0 !important; }
  .js .lectura-item { display: block; }
  .js .lectura-controles { display: none; }
  .figura-lectura { min-height: 0; }
  .hero-texto,
  .hero-capas { transform: none !important; opacity: 1 !important; }

  /* Sin fijado: la portada se desplaza como cualquier otra sección */
  .transicion { height: auto; }
  .hero { position: static; height: auto; opacity: 1 !important; }
  .bloque { opacity: 1 !important; }

  /* Mismo fallo de especificidad que en móvil (ver la media query de 900 px):
     sin repetir los selectores exactos, `#mision` se sube -857 px, una pantalla
     entera, encima de la portada. */
  .transicion + .bloque,
  #industries { margin-top: 0; }

  /* La lámpara de sal se queda en un color fijo: nada respira.
     OJO: como ya no hay base de color, la mancha NO se puede apagar del todo:
     se queda fija y encendida, o la sección se quedaría sin nada de color. */
  .bloque-color::after,
  .transicion::after { animation: none !important; opacity: .55; }

  /* La segunda mancha no hace falta: con una fija ya hay color */
  .bloque-color .lampara-b,
  .transicion .lampara-b { display: none; }

  /* El mapa de sectores: quieto, sin puntos y con las placas apagadas */
  .converge-punto,
  .sector-caja { animation: none !important; }
  .converge-punto { opacity: 0 !important; }

  /* Y los bloques con color, enteros (no aclarados). Sin fijado no hay
     ningún cruce, así que NINGUNO puede quedarse a medio encender: el
     «!important» es necesario porque los cruces escriben la opacidad en
     línea desde hero.js, y si el visitante cambia de opinión con la página
     ya cargada esas opacidades se quedarían puestas. */
  .js .bloque-color { opacity: 1 !important; }
}

/* ============================================================
   QUÉ DIBUJO SE VE EN CADA TAMAÑO (horizontal o vertical)
   ------------------------------------------------------------
   Este bloque va AL FINAL DEL FICHERO A PROPÓSITO. Tiene que ir DESPUÉS de las
   definiciones de `.dss8-diagrama` y `.mapa-sectores`: si va antes, su
   `display: block` gana por orden y **el dibujo horizontal se sigue pintando
   (ocupando 820 px) aunque debería estar oculto en móvil**. Ese fallo se cometió
   y costó un rato encontrarlo: el síntoma era que en móvil seguía habiendo que
   arrastrar aunque el texto ya no se salía.
   ============================================================ */

.mision-diagrama,
.mision-diagrama-v,
.services-diagrama-v,
.dss8-diagrama-v,
.mapa-sectores-v {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

/* LAS VERTICALES NO SE VEN POR DEFECTO: solo en móvil. */
.mision-diagrama-v,
.services-diagrama-v,
.dss8-diagrama-v,
.mapa-sectores-v { display: none; }

/* El corte está en 700 px, el mismo que el de la tablet: por debajo, el dibujo
   horizontal ya no se lee, así que entra el vertical. Por encima se queda el
   horizontal de siempre, y **en un ordenador no cambia absolutamente nada**. */
@media (max-width: 699px) {
  .mision-diagrama,
  .diagrama,
  .dss8-diagrama,
  .mapa-sectores { display: none; }
  .mision-diagrama-v,
  .services-diagrama-v,
  .dss8-diagrama-v,
  .mapa-sectores-v { display: block; }
}

/* ============================================================
   LA CABECERA EN MÓVIL: MENÚ DESPLEGABLE
   ------------------------------------------------------------
   MEDIDO: la marca (118 px) + el menú (416) + el selector (102) son **676 px**,
   y en un móvil hay **464**. Los seis enlaces no caben en una línea sin
   apretarlos hasta 10,5 px, y ocupando dos filas la barra se comía 68 px de
   alto. **Lo que se espera en un móvil es un menú desplegable**, así que es lo
   que hay: en la barra solo quedan la marca, el idioma y el botón.

   EL BOTÓN SOLO EXISTE EN MÓVIL **Y SOLO CON JAVASCRIPT** (ver la media query).
   Sin JS el menú se queda desplegado y se navega igual, que es la norma de esta
   web: tiene que funcionar con doble clic y sin nada más.
   ============================================================ */

/* El botón, OCULTO en cualquier tamaño. Solo la media query de móvil lo enseña,
   y solo si hay JavaScript. **Sin esta regla se ve también en un ordenador**:
   pasó, y por eso está aquí. */
.nav-abrir { display: none; }

/* OJO CON `--alto-nav`: al abrir el menú la barra crece, y esa variable la usan
   las anclas (`scroll-margin-top`) para no quedar debajo. Se ajusta a la barra
   CERRADA, que es como está el 99 % del tiempo. */
@media (max-width: 699px) {
  .nav {
    /* Dos filas: la barra arriba y, si se abre, el menú debajo */
    flex-wrap: wrap;
    gap: 0 12px;
    padding: 9px 12px;
  }

  /* ---------- EL BOTÓN DE HAMBURGUESA ----------
     Solo se ve en móvil **y solo si hay JavaScript**. Sin JS el menú se queda
     desplegado y el botón sobra: esta web tiene que funcionar con doble clic y
     sin nada más. Las tres rayas van dibujadas con CSS, no son una imagen. */
  .js .nav-abrir {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    order: 3;
    width: 34px;
    height: 32px;
    padding: 0;
    background: none;
    border: 0;
    cursor: pointer;
  }

  .nav-abrir-raya {
    display: block;
    width: 20px;
    height: 2px;
    margin: 0 auto;
    border-radius: 2px;
    background: var(--ink);
    transition: transform .3s var(--easing-entrada), opacity .2s ease;
  }

  /* Abierto, las tres rayas se vuelven una cruz */
  .nav.abierto .nav-abrir-raya:nth-child(1) { transform: translateY(6px) rotate(45deg); }
  .nav.abierto .nav-abrir-raya:nth-child(2) { opacity: 0; }
  .nav.abierto .nav-abrir-raya:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

  /* ---------- EL MENÚ DESPLEGABLE ----------
     En columna y a lo ancho, en la segunda fila. Aquí SÍ caben los enlaces a su
     tamaño normal: el problema de antes (416 px en 355) era tenerlos en una
     sola línea. */
  .js .nav-enlaces {
    display: none;
    order: 4;
    flex-basis: 100%;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    padding: 6px 0 4px;
  }
  .js .nav.abierto .nav-enlaces { display: flex; }
  .js .nav-enlaces a { font-size: 15px; padding: 9px 0; }

  /* Sin JavaScript, el menú se ve entero (una línea por enlace) */
  .nav-enlaces {
    display: flex;
    order: 4;
    flex-basis: 100%;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
  }
  .nav-enlaces a { font-size: 15px; padding: 9px 0; }

  /* El alto de la barra CERRADA, para que las anclas no queden tapadas. */
  :root { --alto-nav: 52px; }

  /* ---------- LA BARRA TIENE QUE CABER EN UNA FILA ----------
     Con el selector de tema (2026-09-28) la barra se pasaba: MEDIDO a 375 px,
     marca (118) + idiomas (102) + tema (67) + hamburguesa (34) + huecos = 357 px
     en un hueco de 351, así que el botón del menú se caía a una SEGUNDA fila por
     la izquierda y la barra subía de 52 a 77 px.
     Se aprieta lo justo: huecos de 12 a 8 px, botones de tema de 28 a 24 px (con
     el icono de 17 a 15) y los filetes más pegados. Queda en ~333 px, con 18 px
     de margen a 375. Por debajo de ~340 px la barra vuelve a partirse: es el
     mismo compromiso que ya había antes. */
  .nav { gap: 0 8px; }
  .temas { padding-left: 6px; gap: 0; }
  .tema-boton { width: 24px; height: 24px; }
  .tema-ico { width: 15px; height: 15px; }
}

/* ============================================================
   LOS ICONOS DEL MENÚ
   ------------------------------------------------------------
   Un dibujo por sección, con el lenguaje del resto de la web: trazo de 1.5, sin
   relleno, geométrico. Van en `currentColor`, así que heredan el color del
   enlace: funcionan en los dos temas y se encienden al pasar el ratón sin tocar
   nada. **No hay que traducirlos: son dibujos.**

   ESTE BLOQUE VA AL FINAL A PROPÓSITO: la media query tiene que ir DESPUÉS de la
   regla base que los esconde, o `display: none` ganaría por orden y no se verían
   nunca.
   ============================================================ */

/* En ESCRITORIO NO SE VEN. El menú de arriba mide 416 px con los seis enlaces y
   ya va justo: con iconos pasaría de 570 y en una tablet de 768 no entraría. */
.nav-ico {
  display: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (max-width: 699px) {
  /* El enlace pasa a ser icono + texto */
  .nav-enlaces a {
    display: flex;
    align-items: center;
    gap: 11px;
  }

  .nav-ico {
    display: block;
    flex: none;
    width: 19px;
    height: 19px;
    color: var(--ink-faint);
    transition: color .3s ease;
  }

  /* Al pasar el ratón se encienden el icono Y el texto (el del texto ya lo hacía
     la regla de siempre). */
  .nav-enlaces a:hover .nav-ico { color: var(--acento); }

  /* Con el foco de teclado, igual que con el ratón: si no, quien navega con
     tabulador no ve dónde está. */
  .nav-enlaces a:focus-visible .nav-ico { color: var(--acento); }
}

/* ============================================================
   PIE DE PÁGINA (footer) — añadido el 2026-09-28
   ------------------------------------------------------------
   Hasta hoy la web terminaba en la sección de contacto: no había
   footer, ni aviso de cookies ni textos legales (lo pidió el usuario
   el 2026-09-28, junto con las páginas legal/privacy/cookies y sus
   traducciones).

   QUÉ LLEVA Y POR QUÉ:
   · La marca con el mismo logo de cuatro pisos del menú: usa las
     clases `.icono-1..4`, así que tira de los degradados
     `#logo-c1..4` que están declarados en cada página.
   · Los enlaces a las secciones, con las MISMAS etiquetas del menú
     (las rellena el generador con {{nav.*}}): la web final va en
     inglés y el menú es el que manda.
   · Los tres documentos legales, cada uno apuntando al fichero de
     SU idioma ({{pie.enlace.*}}).
   · El correo y el copyright.

   NO participa en la cadena de cruces (IDS_SECCIONES en hero.js):
   es un bloque normal, sin `.bloque-color` ni lámpara. Su fondo es
   el panel translúcido del menú para cerrar la página sin cortar
   el ambiente de partículas.
   ============================================================ */
.pie {
  position: relative;
  z-index: 2;
  margin-top: clamp(40px, 6vh, 80px);
  border-top: 1px solid var(--placa-borde);
  background: var(--bg-panel);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}

.pie-grid {
  max-width: 1680px;
  margin: 0 auto;
  padding: clamp(36px, 5vh, 64px) clamp(28px, 5vw, 88px);
  display: grid;
  grid-template-columns: minmax(240px, 1.6fr) repeat(3, minmax(140px, 1fr));
  gap: clamp(28px, 4vw, 56px);
  align-items: start;
}

.pie-marca { display: grid; gap: 12px; justify-items: start; }

.pie-fila-marca {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--ink);
  text-decoration: none;
}

.pie-nombre {
  font-family: var(--wordmark-font);
  font-size: 15px;
  letter-spacing: -.01em;
  color: var(--ink);
}

.pie-lema {
  margin: 0;
  max-width: 34ch;
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-soft);
}

.pie-col { display: grid; gap: 10px; align-content: start; }

.pie-titulo {
  margin-bottom: 2px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.pie a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 13px;
  line-height: 1.5;
  transition: color .25s ease;
}

.pie a:hover { color: var(--acento); }

.pie-correo { font-family: var(--mono); font-size: 12.5px; }

.pie-copy {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--ink-faint);
}

/* En pantallas medias el pie pasa a dos columnas; en móvil, a una */
@media (max-width: 900px) {
  .pie-grid { grid-template-columns: 1fr 1fr; }
  .pie-marca { grid-column: 1 / -1; }
}

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

/* ============================================================
   AVISO DE COOKIES — añadido el 2026-09-28
   ------------------------------------------------------------
   Un aviso discreto abajo. La web NO pone cookies de seguimiento
   ni carga nada de fuera (las fuentes están autoalojadas y no hay
   ni una petición externa), así que el aviso solo informa y guarda
   la elección del visitante en `localStorage` (clave
   `dsslayers-cookies`): es lo ÚNICO que esta web guarda en el
   navegador.

   · Se ve SIEMPRE por defecto: si el JavaScript falla, el aviso
     sigue ahí (no se puede cerrar, pero tampoco se guarda nada).
   · Con JavaScript, hero.js (montarCookies) lo esconde si la
     elección ya está guardada, y la guarda al pulsar Aceptar o
     Rechazar.
   · Va por encima del menú (z-index 20) pero sin tapar toda la
     pantalla: es una tarjeta, no un muro.
   ============================================================ */
.aviso-cookies {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 20;
  width: min(680px, calc(100vw - 28px));
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  background: var(--bg-panel);
  border: 1px solid var(--placa-borde);
  border-radius: 14px;
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .18);
  animation: cookiesEntra .5s var(--easing-entrada) both;
}

@keyframes cookiesEntra {
  from { opacity: 0; transform: translate(-50%, 14px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

.aviso-cookies.cookies-cerrado { display: none; }

.cookies-texto {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-soft);
}

.cookies-texto a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.cookies-texto a:hover { color: var(--acento); }

.cookies-botones { display: flex; gap: 8px; flex: none; }

.cookies-botones button {
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}

.cookies-aceptar {
  background: var(--acento);
  border: 1px solid var(--acento);
  color: #fff;
}

.cookies-aceptar:hover { filter: brightness(1.12); }

/* Sobre el azul claro del tema oscuro, el blanco no se lee: negro. */
html[data-tema="oscuro"] .cookies-aceptar { color: #0b0d12; }

.cookies-rechazar {
  background: transparent;
  border: 1px solid var(--placa-borde);
  color: var(--ink-soft);
}

.cookies-rechazar:hover { border-color: var(--ink-soft); color: var(--ink); }

@media (max-width: 699px) {
  .aviso-cookies {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    bottom: 10px;
  }
  .cookies-botones button { flex: 1; }
}

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

/* ============================================================
   PÁGINAS LEGALES (legal, privacy, cookies) — añadido el 2026-09-28
   ------------------------------------------------------------
   Nueve ficheros sueltos (tres documentos × tres idiomas) que se
   enlazan desde el pie. Comparten `styles.css` y `hero.js`; en
   estas páginas hero.js no hace nada salvo el aviso de cookies,
   porque todas sus funciones comprueban antes si existen sus
   elementos.

   El documento es una columna estrecha y cómoda de leer (860 px),
   con la barra fija de siempre arriba y un pie reducido abajo.
   Los datos del cliente van entre CORCHETES [ASÍ] hasta que se
   rellenen: son los textos legales reales, pendientes.
   ============================================================ */

/* En las páginas legales el menú de la barra son los tres
   documentos (no las secciones). No hay botón de hamburguesa:
   los tres enlaces se quedan SIEMPRE visibles, y en móvil pasan
   a una segunda fila de la barra. */
.legal .nav-enlaces a.activo {
  color: var(--ink);
  border-bottom-color: var(--acento);
}

@media (max-width: 699px) {
  html.js body.legal .nav-enlaces {
    display: flex;
    flex-wrap: wrap;
    order: 4;
    flex-basis: 100%;
    padding: 6px 0 4px;
    gap: 8px 22px;
  }
  html.js body.legal .nav-enlaces a { font-size: 14px; padding: 6px 0; }
}

.legal-pagina {
  max-width: 860px;
  margin: 0 auto;
  padding: clamp(110px, 16vh, 150px) clamp(20px, 6vw, 48px) clamp(48px, 8vh, 90px);
}

.legal-atras { margin: 0 0 26px; }

.legal-atras a {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .06em;
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 1px solid var(--placa-borde);
  padding-bottom: 2px;
  transition: color .25s ease, border-color .25s ease;
}

.legal-atras a:hover { color: var(--acento); border-color: var(--acento); }

.legal-pagina h1 {
  margin: 0 0 10px;
  font-family: var(--wordmark-font);
  font-weight: 400;
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  letter-spacing: -.015em;
  color: var(--ink);
}

.legal-subtitulo {
  margin: 0 0 34px;
  max-width: 60ch;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* El recuadro que avisa de que faltan los datos reales del cliente */
.legal-aviso {
  margin: 0 0 34px;
  padding: 14px 18px;
  background: var(--amarillo-suave);
  border: 1px solid var(--amarillo);
  border-radius: 10px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink);
}

.legal-bloque { margin: 0 0 34px; }

.legal-pagina h2 {
  margin: 0 0 10px;
  font-family: var(--wordmark-font);
  font-weight: 400;
  font-size: 1.15rem;
  letter-spacing: -.01em;
  color: var(--ink);
}

.legal-pagina h3 {
  margin: 18px 0 8px;
  font-size: .98rem;
  font-weight: 600;
  color: var(--ink);
}

.legal-pagina p,
.legal-pagina li {
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--ink-soft);
}

.legal-pagina p { margin: 0 0 12px; }

.legal-pagina ul { margin: 0 0 12px; padding-left: 22px; }

.legal-pagina li { margin-bottom: 6px; }

.legal-pagina strong { color: var(--ink); }

/* Los huecos [ENTRE CORCHETES] se marcan para que se vean en la revisión */
.legal-dato {
  color: var(--amarillo-fuerte);
  font-weight: 600;
}

.legal-tabla {
  width: 100%;
  border-collapse: collapse;
  margin: 8px 0 16px;
}

.legal-tabla th,
.legal-tabla td {
  border: 1px solid var(--placa-borde);
  padding: 10px 12px;
  font-size: 13.5px;
  text-align: left;
  vertical-align: top;
  color: var(--ink-soft);
}

.legal-tabla th {
  background: var(--placa);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* El pie de las páginas legales: una sola fila (marca + documentos) */
.pie-legal .pie-grid {
  grid-template-columns: 1fr auto;
  align-items: center;
  padding-top: 28px;
  padding-bottom: 28px;
}

.pie-legal .pie-col { grid-template-columns: auto auto auto; gap: 24px; align-content: center; }

@media (max-width: 699px) {
  .pie-legal .pie-grid { grid-template-columns: 1fr; }
  .pie-legal .pie-col { grid-template-columns: 1fr; gap: 8px; }
}
