@charset "UTF-8";

/* ============================================================================
   04-componentes.css — sysnetia.com
   ----------------------------------------------------------------------------
   FASE 1. Los CUATRO componentes que pide la fase para poder verificar el
   esqueleto: cabecera, botón, enlace de texto y aviso.

   NO están aquí .carpeta, .escena, .barra ni .puntos: son Fase 2 en adelante.
   Si un componente aparece antes de su fase, se retira.

   REGLAS (contrato §5):
   1. Una clase por componente. Prohibido estilar por descendencia.
   2. Cero color literal. Cero medida literal. Cero font-size literal.
   3. Un modificador AÑADE, no repite la base.
   4. Cero !important.
   ========================================================================== */


/* ============================================================================
   1. CABECERA
   ----------------------------------------------------------------------------
   Fija arriba, fondo translúcido con desenfoque. El alto es una medida del
   contrato (--isotipo-alto) más el aire: no un número suelto.
   ========================================================================== */

.cabecera {
  /* Barra flotante. Nace OCULTA (`hidden` en el HTML) y se instancia con la
     rueda: en la portada no hay cabecera (§9bis).

     ORDEN DE OZ: marca a la IZQUIERDA, y a la derecha el menú pegado al botón
     de tema. De ahí el space-between: la marca se va sola al extremo izquierdo
     y el bloque de acciones al derecho, sin márgenes calculados. */
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: var(--z-cabecera);

  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-3);

  padding-block: var(--e-2);
  /* A la DERECHA se reserva el hueco del botón de tema, que es fijo e
     independiente: sin este aire, el menú se sentaría debajo del botón y los
     dos se pisarían. El hueco es el ancho del botón (--isotipo-alto) más dos
     separaciones. */
  padding-inline: max(var(--margen-borde), env(safe-area-inset-left))
                 calc(var(--isotipo-alto) + (var(--e-3) * 2));

  background-color: color-mix(in srgb, var(--fondo) 78%, transparent);
  border-block-end: var(--trazo-fino) solid var(--borde);

  /* El desenfoque solo si el navegador lo soporta; si no, el fondo es opaco
     y se lee igual. No es un adorno: sin él el texto se pisa con el scroll. */
  backdrop-filter: blur(12px) saturate(140%);
}

/* `hidden` tiene que ganar al `display: flex` de arriba. Sin esto, un elemento
   con display:flex IGNORA el atributo hidden y la cabecera se vería en la
   portada. Es una trampa clásica de CSS: hidden solo pone display:none si el
   autor no ha declarado otro display. */
.cabecera[hidden] {
  display: none;
}

.cabecera__marca {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  line-height: 1;
}

/* ============================================================================
   EL WORDMARK — contrato §3.0
   ----------------------------------------------------------------------------
   "Sysnetia" es UNA palabra, en fuente de marca, SIN ESPACIO, con Sys naranja
   y netia azul. Siempre, en toda la página.

   .marca     → contenedor (Audiowide, 400)
   .marca__b  → la parte azul ("netia")

   El factor 0.72: se midió que Audiowide a font-size igual a la caja del
   isotipo desborda por los hombros de la "S". 0.72 hace que la altura real del
   texto coincida con --isotipo-alto, así el SVG definitivo encaja sin mover nada.
   ========================================================================== */

.marca {
  font-family: var(--fuente-logo);
  font-weight: 400;              /* SIEMPRE 400. Si se ve flojo, se sube el tamaño */
  line-height: 1;
  letter-spacing: var(--track-titulo);
  white-space: nowrap;           /* "Sys" + "netia" NUNCA parten en dos líneas */
  color: var(--naranja-marca);   /* "Sys" SIEMPRE naranja, en los dos temas */
  text-shadow: none;             /* sin contorno ni sombra (§3.0bis) */
}

/* ============================================================================
   LA OTRA MITAD DE LA MARCA — contrato §3.0
   ----------------------------------------------------------------------------
   ESTA REGLA NO ES OPCIONAL Y NO ES UN DUPLICADO. Sin ella, "netia" hereda el
   naranja de .marca y la palabra entera sale de un solo color: deja de ser la
   marca.

   Ya se cometió el error (2026-10-21): se borró "por limpiar duplicados" y
   "netia" salió naranja. Los duplicados eran los DOS bloques .marca; .marca__b
   era otra cosa. Antes de borrar una regla, grep su clase en el HTML.

   El check #19 del verificador compara este color LEÍDO DEL NAVEGADOR con el
   contrato. Si no es --azul-marca, la fase no cierra.
   ========================================================================== */

.marca__b {
  color: var(--azul-marca);      /* "netia" SIEMPRE azul, en los dos temas */
}

/* ============================================================================
   LA MARCA NUNCA PIERDE CONTRA `.etq`  (§3.0, bug 2026-10-21)
   ----------------------------------------------------------------------------
   En las cejas de sección el HTML es `class="etq marca"`. `.etq` declara
   `color: var(--acento)` en `06-quienes.css`, que se carga DESPUÉS de este
   archivo, y las dos tienen la misma especificidad (0,1,0): ganaba `.etq`.
   Resultado en tema CLARO: `Sys` salía #1558C4 (azul) en vez de #FF9900.
   En tema oscuro no se notaba porque ahí `--acento` es naranja por casualidad.

   Esto es .marca junto a CUALQUIER clase que pinte color: la marca manda.
   Va con doble clase (0,2,0) para que no dependa del orden de carga.
   ========================================================================== */
.marca.marca {
  color: var(--naranja-marca);
}
.marca.marca .marca__b,
.marca.marca > .marca__b {
  color: var(--azul-marca);
}

/* El logo NO PERMUTA y NO lleva contorno: Sys naranja, netia azul, limpio, en
   los dos temas (decisión de Oz, contrato §3.0bis).

   Se probó un contorno de 8 sombras y se descartó: se veía como un borde marcado
   alrededor de las letras. Sobre fondo claro el naranja da 1.99:1 y SE ACEPTA,
   porque es un logotipo y WCAG excluye los logotipos del requisito de contraste.
   Lo que NO se hace nunca: usar el wordmark pequeño sobre fondo claro, ni meterle
   sombras "para que se lea mejor". */


/* Tamaños: por el token del isotipo, no a ojo. */
.marca--cabecera {
  font-size: calc(var(--isotipo-alto) * 0.72);

  /* Isotipo y texto EN LÍNEA, uno al lado del otro (orden de Oz).
     Sin esto el <a> es display:block y los dos hijos apilan en vertical: el
     isotipo quedaba en y=8 y el texto en y=36 — 24px de desfase, medidos.
     Va AQUÍ y no en `.cabecera__marca` porque es la clase que lleva el HTML.
     `.cabecera__marca` no la usa ningún elemento (ver 8bis, clases
     reservadas): no era el contenedor. */
  display: flex;
  align-items: center;
  gap: var(--e-2);
  line-height: 1;
}

.marca--menu {
  font-size: calc(var(--isotipo-alto-menu) * 0.72);
}

/* Wordmark de portada (§3.0c). Acoplado al isotipo por el 0.72, igual que los
   demás tamaños: símbolo y nombre crecen juntos y el logo no se ve cojo. */
.marca--portada {
  font-size: calc(var(--isotipo-alto-portada) * 0.72);
}

/* La marca cuando FIRMA (el pie): mismo wordmark, tamaño de firma.
   No se inventa otro tamaño: es el del pie, para que el nombre pese igual que
   el resto de la línea "— 2026". */
.marca--pie {
  font-size: var(--t-xs);
  vertical-align: baseline;
}

/* La marca de la cabecera es un ENLACE al inicio: se le quita el subrayado.
   NO se toca el color aquí. `a.marca` (0,1,1) gana a `.marca` (0,1,0) por
   especificidad, así que un `color: inherit` en esta regla PISA el naranja y
   "Sys" sale del color del body (blanco en oscuro). Ya pasó: medido
   rgb(245,247,250) en lugar de #FF9900. El color lo pone SOLO `.marca`. */
a.marca {
  text-decoration: none;
}

/* El isotipo pequeño de la cabecera. Su alto sale del token, igual que el
   texto: así símbolo y nombre crecen juntos (§3.0b). */
.marca__isotipo {
  display: block;
  block-size: var(--isotipo-alto);
  inline-size: var(--isotipo-alto);
  object-fit: contain;   /* el PNG ya viene cuadrado; esto solo evita deformar */
}

.marca__texto {
  display: block;
}

/* ============================================================================
   MENÚ DE ANCLAJES — copiado de ds-v2
   ----------------------------------------------------------------------------
   Los 4 botones (Servicios, Quiénes Somos, Clientes, Contacto). Vive dentro de
   la cabecera, así que NO es `position: fixed` ni se apila con z-index propio:
   lo coloca el flex de .cabecera (la marca a la izquierda, el menú detrás).
   En ds-v2 iba suelto en la página
   con z-index 30; aquí sobra, porque la cabecera YA tiene su capa (§6).
   ========================================================================== */

.anclajes {
  display: flex;
  align-items: center;
  gap: var(--e-3);
}

/* `hidden` gana al display:flex (misma trampa que la cabecera). */
.anclajes[hidden] {
  display: none;
}

.anclaje {
  font: inherit;
  font-size: var(--t-s);
  letter-spacing: 0.02em;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--mut);
  padding-block: 6px;
  padding-inline: 2px;
  position: relative;
  transition: color 0.25s ease;
}

/* Subrayado que crece desde la izquierda. Pinta --boton: naranja en oscuro,
   azul en claro, sin declarar dos colores. */
.anclaje::after {
  content: '';
  position: absolute;
  inset-inline: 2px;
  inset-block-end: 0;
  block-size: 1.5px;
  background: var(--boton);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}

.anclaje:hover {
  color: var(--fg);
}

.anclaje:hover::after {
  transform: scaleX(1);
}

/* Sección actual: subrayada de forma permanente. */
.anclaje.activo {
  color: var(--fg);
}

.anclaje.activo::after {
  transform: scaleX(1);
}

/* ============================================================================
   PIE — "Sysnetia - {año}", siempre visible
   ========================================================================== */
.pie {
  position: fixed;
  inset-block-end: 0;
  inset-inline: 0;
  z-index: var(--z-cabecera);
  padding-block: var(--e-1);

  /* CENTRADO POR FLEX, no por text-align (`text-align` solo centra el texto
     DENTRO de su caja; si la caja no ocupa el ancho, el texto se queda donde
     empieza la caja — que es lo que pasaba: el pie salía a la izquierda).
     Con flex + justify-content el hijo se centra en la barra entera. */
  display: flex;
  justify-content: center;
  align-items: center;

  /* Sin fondo ni borde: es una firma discreta sobre el fondo, no una barra.
     Si tapara contenido, es que hay algo mal colocado, no que falte opacidad. */
  pointer-events: none;
}

.pie__texto {
  font-size: var(--t-xs);
  /* SIN text-transform: poner "SYSNETIA" en mayúsculas rompe la marca (§3.0):
     el wordmark se escribe siempre igual, con su S mayúscula y el resto en
     minúsculas. El tracking tampoco se pone aquí: lo trae .marca. */

  /* NARANJA en tema oscuro, AZUL en tema claro (orden de Oz).
     Se usa --boton porque ES exactamente eso: el color de marca que ya cambia
     con el tema (naranja-500 en oscuro, azul-600 en claro). No se declaran dos
     colores ni se consulta el tema a mano: un token, dos temas.

     OJO: `--acento` valdría igual, pero `--boton` es el que el contrato define
     como "color de marca pleno" en §2.1, y es el mismo que ya usan el
     subrayado del menú y el borde del botón. Un solo criterio para todo. */
  color: var(--boton);

  margin: 0;
  text-align: center;
}

/* ============================================================================
   EL ISOTIPO — contrato §3.0b
   ----------------------------------------------------------------------------
   El símbolo va DELANTE del wordmark: [isotipo] [Sysnetia]. Se reconoce el
   símbolo antes de leer el nombre; ese es el orden correcto.

   El PNG viene con fondo TRANSPARENTE y #FF9900 exacto: no se le pone fondo,
   marco, placa ni sombra. Se muestra tal cual lo entregó Oz.

   El alto lo manda --isotipo-alto (40px en cabecera, 28px en overlays), el mismo
   token que ya reservaba el hueco. Por eso el archivo real encaja sin mover nada.
   ========================================================================== */

.cabecera__isotipo {
  block-size: var(--isotipo-alto);
  inline-size: auto;
  aspect-ratio: 1;          /* el símbolo es cuadrado, no rectangular */
  object-fit: contain;      /* nunca recorta: el símbolo tiene que verse entero */
  flex: none;               /* jamás se encoge cuando el texto crece */
  display: block;
}

/* ============================================================================
   LA PORTADA — contrato §3.0d (heredada de ds-v2)
   ----------------------------------------------------------------------------
   Orden vertical: ISOTIPO encima → nombre en PARTÍCULAS → slogan → botón.

   Todo va DENTRO de una caja relativa, porque el slogan se posiciona absoluto
   con medidas reales que publica el script (§3.0d.3). Si la caja no es
   `position: relative`, el slogan se coloca respecto a la ventana y se sale.

   La caja NO usa margin para centrarse: la norma del plan (§3.5) dice que las
   distancias las manda el contenedor. Aquí el contenedor centra por flex.
   ========================================================================== */

/* ============================================================================
   FONDO NEURONAL — contrato §3.0d.1
   ----------------------------------------------------------------------------
   Canvas WebGL copiado de ds-v2. Va POR DEBAJO de todo (z-index 0) y fijo: no
   scrollea con la página, de ahí que las secciones necesiten fondo propio
   opaco si no quieren que las partículas se vean a través.

   NUNCA se apaga (regla del original). Si el navegador no da WebGL, el propio
   script le pone display:none y queda el color sólido de --fondo: la página
   se ve bien, solo sin el efecto.
   ========================================================================== */

.fondo-neural {
  position: fixed;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  display: block;
  z-index: var(--z-fondo);   /* escalera del contrato, nunca un número suelto */
  pointer-events: none;      /* no roba clics: solo decora el fondo */
}

.portada {
  position: relative;        /* por encima del fondo neuronal */
  z-index: var(--z-contenido);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* env() para el notch y la barra de gestos: sin esto, en móvil el logo se
     pega al borde. Se SUMA al aire, no lo sustituye. */
  padding-block: calc(var(--e-6) + env(safe-area-inset-top, 0px))
                calc(var(--e-6) + env(safe-area-inset-bottom, 0px));
  padding-inline: var(--margen-borde);
}

.portada__caja {
  /* Contenedor del único contenido de la portada: el nombre en partículas.
     Centrado vertical y horizontal (orden de Oz). .portada ya es flex con
     align/justify center; aquí se refuerza el eje del contenido. */
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;

  /* El isotipo ya no ocupa sitio aquí: va absoluto y DETRÁS (§3.0d.7). Por eso
     no hay gap ni padding que reservar y el canvas es lo único que cuenta para
     el centrado — y eso no cambia nunca. De ahí sale que el nombre NO se mueva
     cuando el isotipo aparece.

     (Antes lo reservaba un margen que nacía en 16px y pasaba a −37.5px al
     llegar la medida del canvas: ese cambio en caliente era el salto de 23px
     que vio Oz.) */
  inline-size: 100%;
}



/* ISOTIPO DE FONDO (§3.0d.7). Rediseño de Oz, 2026-10-21:
   *"coloca el isotipo centrado, bájale la opacidad a 0.3 y que sea 50% de la
   altura de la pantalla"*.

   Ya NO va encima del nombre: va DETRÁS, centrado, como marca de agua. */
/* ===== ISOTIPO DE FONDO DE TODO EL SITIO =====
   Orden de Oz (2026-10-23): «dejar el logo en el fondo como en la pagina
   inicial dejarlo siempre que forme parte del background».

   Antes esta regla se llamaba `.portada__isotipo` y el <img> vivía DENTRO de
   #portada: al entrar a cualquier sección, el isotipo desaparecía con ella. En
   el HTML ahora es hermano de #neural, fuera de toda <section>.

   Mismo modelo que el canvas neural, que es el otro fondo del sitio:
     · position: fixed  → no se mueve ni al hacer scroll ni al cambiar de sección
     · --z-fondo (0)    → por debajo de todo el contenido. El canvas neural saca
                          clearColor(0,0,0,0), o sea transparente, así que el
                          orden entre ellos dos no cambia nada de lo que se ve.
     · pointer-events: none → decora; no roba clics ni toques.

   SIGUE SIENDO MARCA DE AGUA aunque ahora esté en todas partes: al 0.3 (token
   --isotipo-opacidad) se insinúa detrás del contenido sin competir con él.

   NO lleva la animación `aparece` que tenía en la portada: ese elemento no se
   vuelve a montar nunca, así que la animación solo correría al cargar y luego
   se quedaría a medias si algo la reiniciara. Opacidad fija, sin animación. */
.fondo-isotipo {
  display: block;
  position: fixed;
  inset: 0;
  margin: auto;

  /* Cuadrado que ocupa el 54% del lado más corto de la ventana: grande, sin
     desbordar en ninguna proporción (en vertical manda el ancho, en horizontal
     el alto). El mismo cálculo que tenía en la portada. */
  block-size: min(54vh, 54vw);
  inline-size: min(54vh, 54vw);
  object-fit: contain;

  z-index: var(--z-fondo);
  pointer-events: none;
  opacity: var(--isotipo-opacidad);
}

/* ===== ESGOLAN Y BOTÓN: APARECEN CON LAS PARTÍCULAS YA FORMADAS (§3.0d.8) =====
   Orden de Oz: "aparece isotipo, al terminar se instancian las partículas, al
   terminar aparece el slogan y el botón".

   Los dos cuelgan de `body.lista`, que el motor pone en el instante EXACTO del
   último fundido de partícula. No hay `setTimeout` aquí: si mañana cambia la
   velocidad de la entrada, los dos siguen entrando a la vez y en el momento
   correcto.

   Se escalona la entrada con `transition-delay`: primero el eslogan, luego el
   botón. Sin delay se encenderían los dos en el mismo frame y se leería como
   un bloque que salta, no como una secuencia. */

/* ===== EL BLOQUE DE CIERRE: ABSOLUTO, COLGANDO DEL CENTRO (§3.0d.8) =====
   Agrupa eslogan y botón. Es absoluto para NO participar del centrado (así el
   nombre se queda clavado en el centro), y dentro van en flujo con `gap` para
   que el botón caiga siempre debajo del eslogan sin calcular alturas.

   Calculándolas a mano se pisaban: −23px en PC y −132px en móvil. */
.portada__cierre {
  /* Ya NO agrupa nada: el eslogan y el botón se colocan por separado, porque
     cada uno se alinea distinto (el eslogan al ancho de "netia", el botón al
     centro del nombre). En una columna compartirían eje horizontal, y no lo
     comparten.

     El contenedor queda solo como referencia de posicionamiento: cubre la caja
     entera y no intercepta el puntero, para no robarle el hover al canvas. */
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.portada__cierre > * {
  pointer-events: auto;          /* los hijos sí se pueden pulsar */
}

/* ===== COLGAN HACIA ABAJO, SIN MOVER EL NOMBRE (§3.0d.8) =====
   Orden de Oz: "el logo debe permanecer centrado, slogan y botón se corren
   hacia abajo".

   Si el eslogan y el botón estuvieran en el flujo, el flex los contaría y el
   nombre —que es lo que se centra— se iría hacia arriba para repartir el
   espacio. Es el mismo error que hizo saltar la portada con el isotipo.

   Van ABSOLUTOS, anclados al 50% de la caja: el canvas sigue siendo lo único
   que participa del centrado, así que el nombre queda clavado en el centro de
   la pantalla pase lo que pase.

   `top: 50%` + `translate(-50%)` los clava en el centro vertical; el
   `translateY` con el hueco los baja justo por debajo del nombre. */
.portada__lema {
  font-family: var(--fuente-texto);
  /* El tamaño NO se declara aquí: lo pone más abajo
     (`var(--lema-texto-final, var(--lema-texto))`), que es el calculado por el
     script con respaldo al fluido. Tenerlo dos veces en el mismo bloque
     significaba que este se pisaba siempre: código muerto. */
  font-weight: var(--peso-ligero);
  /* El tracking lo recalcula el script en px para el tamaño final
     (--lema-tracking-final). Si se dejara en em fijo, al escalar la fuente
     crecería en proporción y el texto desbordaría el ancho de "netia". */
  letter-spacing: var(--lema-tracking-final, var(--lema-tracking));

  /* BLANCO (orden de Oz). Se usa el token del texto principal, que ya resuelve
     el color correcto en cada tema; no un #fff literal, que en tema claro
     desaparecería. */
  color: var(--fg);

  /* ===== OCUPA EXACTAMENTE EL ANCHO DE "netia" (§3.0d.8) =====
     Lo definió Oz con la captura: el eslogan empieza donde termina el naranja
     y acaba en la última "a" del nombre.

     El motor mide `azulIzq` (dónde empieza la parte azul) y `der` (borde
     derecho de la tinta). Aquí solo se colocan:

       left   = --lema-izq      (borde izquierdo del azul)
       width  = --lema-ancho    (der − azulIzq)

     Ojo: el texto NO se estira con `text-align: justify` ni se escala la
     fuente para llenarlo. Oz pidió que ocupe ese ANCHO, no que el texto se
     deforme: si la frase es más corta que el hueco, queda dentro y alineada a
     la derecha; si es más larga, encoge la fuente con `--lema-texto`, que ya
     es fluido. Deformar letras para rellenar un hueco se ve mal.

     Mientras el motor no ha medido (primer instante), el respaldo deja el
     eslogan centrado bajo el nombre: no salta, solo aparece centrado. */
  position: absolute;
  /* Se PEGA al nombre: el hueco ya lo da el tamaño del propio texto, no un
     margen. Antes había 50px de separación y Oz lo llamó "inaceptable": el
     eslogan debe quedar justo debajo de la tinta, sin aire muerto. */
  inset-block-start: calc(var(--logo-tinta-abajo, 50vh) + var(--lema-separacion));
  inset-inline-start: var(--lema-izq, 0px);
  inline-size: var(--lema-ancho, auto);

  /* ===== EL TEXTO LLENA EL ANCHO DE "netia" (§3.0d.8) =====
     Oz: *"el slogan debe aumentar la fuente para que ocupe el espacio que
     quiero"*.

     No se usa `text-align: justify` ni `letter-spacing` para estirarlo: eso
     separa letras y se ve suelto. Se escala la FUENTE.

     La cuenta la hace el script (`ajustarLema`), que mide el texto a 100px,
     saca la proporción y fija el tamaño exacto. Aquí solo se declara que el
     tamaño viene dado; el valor inicial es el respaldo por si el script aún
     no ha corrido. */
  font-size: var(--lema-texto-final, var(--lema-texto));

  text-align: end;
  white-space: nowrap;
  line-height: 1.1;

  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity var(--dur-media) ease,
    transform var(--dur-media) ease;
}



/* Con las partículas asentadas, los dos asoman: el eslogan primero, el botón
   medio segundo después. */
body.lista .portada__lema {
  opacity: 1;
  transform: translateY(0);
}

/* Se usa `translate` para centrar y `transform` para la entrada: son
   propiedades DISTINTAS y así no se pisan. Si el centrado fuera con
   `transform: translateX(-50%)`, la entrada lo borraría y el texto saltaría al
   centro. */

/* El botón lleva RETRASO, y el retraso va AQUÍ (en el estado final) y no en la
   regla base: la transición usa las propiedades del estado al que LLEGA, así
   que puesto en la base no se aplicaba al aparecer y los dos entraban a la
   vez. Con esto el eslogan sale primero y el botón medio segundo después. */
body.lista 

/* Antes de que la entrada termine el botón NO se puede pulsar. Ya existía esta
   regla para el slogan en ds-v2 y sigue teniendo sentido: un botón activo
   sobre una portada a medio montar se pulsa por error. */
body:not(.lista) .portada__boton {
  pointer-events: none;
}

/* En TÁCTIL el botón es PRIMARIO, no fantasma (§3.0d.4): un dedo no tiene
   hover, y un botón que no se ve hasta tocarlo no es un botón. */
@media (hover: none) {
  .portada__boton {
    background-color: var(--boton);
    color: var(--boton-fg);
    border-color: var(--boton);
  }
}

/* Accesibilidad: sin movimiento, aparecen y ya. */
@media (prefers-reduced-motion: reduce) {
  .portada__lema,
  .portada__boton {
    transition: none;
    transform: none;
  }
}


/* La franja de las partículas. El canvas mide 140vw en móvil y tablet porque
   el propio canvas es el TECHO del tamaño de la marca (§3.0d.2, trampa 3):
   con un canvas más estrecho que la marca, el logo no puede crecer.
   `overflow: hidden` evita que el desborde de 140vw genere scroll lateral. */
.portada__particulas {
  position: relative;
  inline-size: 140vw;
  max-inline-size: 100vw;
  display: flex;
  justify-content: center;
  overflow: hidden;
}

/* Alto del canvas: FIJO. No se ciñe a la tinta.
   El ceñido se borró entero porque cambiaba el tamaño del propio canvas que su
   ResizeObserver vigilaba, y eso era un bucle: reconstruir → fundido → ceñir
   → reconstruir (§3.0d.3sexies). */
.portada__canvas {
  display: block;
  inline-size: 140vw;
  block-size: var(--portada-canvas-alto);

  /* ===== TOUCH-ACTION: SIN ESTO EL DEDO NUNCA "SUELTA" (§3.0d.6) =====
     Con `auto`, el navegador se queda el gesto para SCROLL y hace dos cosas:
       1. cancela los `touchmove` (solo llegaba el primero).
       2. al desplazar, dispara `touchcancel` en vez de `touchend`.
     Resultado en el equipo real: las partículas se dispersaban con el dedo y
     se quedaban congeladas, porque el motor nunca sabía que el dedo se había
     ido.

     `manipulation` = se permite el scroll (no rompe la página) pero el
     navegador no reserva el gesto para zoom por doble toque, así que los
     eventos del dedo llegan completos, incluido el `touchend`.
     NO usar `none`: eso bloquearía el scroll de la página al tocar el logo. */
  touch-action: manipulation;
}


/* ============================================================================
   2. BOTONES  —  DOS piezas distintas, no una con variantes (contrato §5bis.0)
   ----------------------------------------------------------------------------
   .boton            PRIMARIO  · para DEDOS · RELLENO SÓLIDO SIEMPRE · no usa hover
   .boton--fantasma  FANTASMA  · para RATÓN · metal de ds-v2 · el hover lo llena

   La diferencia NO la marca el tema, la marca el DISPOSITIVO:
     - tema oscuro  → primario naranja #FF9900 con texto negro   (9.03:1)
     - tema claro   → primario azul    #1558C4 con texto blanco  (6.51:1)
     - en touch, el fantasma SE SUSTITUYE por el primario (nunca se oculta).

   El primario NO se puede hacer transparente ni esperar hover: un dedo no
   tiene hover, y un botón que no se ve hasta tocarlo no es un botón.
   ========================================================================== */


/* ============================================================================
   2.1 PRIMARIO — relleno sólido, funciona sin hover
   ========================================================================== */

.boton {
  position: relative;
  isolation: isolate;

  display: inline-flex;
  align-items: center;
  justify-content: center;

  padding: var(--boton-pad-y) var(--boton-pad-x);
  border-radius: var(--boton-radio);
  border: var(--boton-borde) solid var(--boton);

  font-family: var(--fuente-titular);
  font-size: var(--boton-texto);
  font-weight: var(--peso-fuerte);
  line-height: 1;
  letter-spacing: var(--boton-tracking);
  text-transform: uppercase;

  /* RELLENO SÓLIDO — está en el reposo, no en el hover */
  color: var(--boton-fg);
  background-color: var(--boton);

  cursor: pointer;
  transition:
    background-color var(--boton-dur) var(--boton-curva),
    color            var(--boton-dur) var(--boton-curva),
    border-color     var(--boton-dur) var(--boton-curva),
    transform        var(--boton-dur) var(--boton-curva);
}

/* El hover del primario es un EXTRA, no la condición para verlo. */
@media (hover: hover) and (pointer: fine) {
  .boton:hover {
    background-color: var(--boton-hover);
    border-color: var(--boton-hover);
    transform: translateY(-2px);
    box-shadow: var(--boton-glow);
  }
}

.boton:active {
  transform: translateY(0) scale(0.985);
  transition: transform var(--boton-dur-click) ease;
}

.boton:disabled,
.boton[aria-disabled="true"] {
  pointer-events: none;
  cursor: default;
  opacity: 0.45;
  filter: saturate(0.6);
}


/* ============================================================================
   ============================================================================
   GANCHO `.btn-hablemos` — NO ES UN BOTON, ES UN SELECTOR DE JS
   ----------------------------------------------------------------------------
   El aspecto lo pone `.btn` de cada seccion (.cierre .btn, etc.). Esta clase
   existe SOLO para que el listener global de rueda-accion.js encuentre los
   botones «Hablemos» de cualquier seccion sin usar un `id`.

   POR QUE NO SE USA `id`: antes habia `id="btnHablemos"` en Quienes y en
   Clientes a la vez. Dos ids iguales en el DOM; `getElementById` devuelve el
   PRIMERO, que era el de otra seccion y no tenia `data-overlay`, asi que el
   clic no llevaba a Contacto. Con una clase el duplicado es imposible.

   La regla es DELIBERADAMENTE VACIA de aspecto (solo `cursor:pointer`, que el
   boton ya tiene). Existe porque el check 19 exige que toda clase usada en el
   HTML tenga regla real en el CSS — y tiene razon: una clase sin regla es lo
   que dejo "netia" naranja.
   ============================================================================ */
.btn-hablemos {
  cursor: pointer;   /* idempotente con .btn; no cambia nada visual */
}


/* ============================================================================
   2.2 FANTASMA — el .btn-metal de ds-v2 (contrato §5bis.1)
   ----------------------------------------------------------------------------
   Transparente en reposo: borde y texto en --boton. El relleno es un degradado
   que vive SIEMPRE en el ::before y el hover SOLO cambia su opacidad.

   POR QUÉ ASÍ (y no `:hover { background: … }`): background transparent →
   gradient NO es interpolable, cambia de golpe. opacity sí interpola.
   Esto está escrito en el ds-v2 original y es lo que hace que el botón
   se sienta caro y no un botón genérico.

   En touch NO se usa: se sustituye por el primario (§2.3).
   ========================================================================== */

.boton--fantasma {
  overflow: hidden;
  background-color: transparent;
  color: var(--boton);
  border-color: var(--boton);
  box-shadow: 0 0 0 rgba(var(--boton-rgb), 0);
  will-change: transform, box-shadow;
}

/* capa del RELLENO: siempre montada, se revela con opacity (interpolable) */
.boton--fantasma::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--boton) 55%, #ffffff) 0%,
    var(--boton) 42%,
    color-mix(in srgb, var(--boton) 80%, #000000) 100%);
  opacity: 0;
  transition: opacity var(--boton-dur) var(--boton-curva);
  pointer-events: none;
}

/* banda de brillo: solo se ve cuando el botón está relleno */
.boton--fantasma::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 38%;
  left: -45%;
  opacity: 0;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.85), transparent);
  transform: skewX(-18deg);
  animation: boton-brillo var(--boton-dur-brillo) var(--boton-curva) infinite;
  z-index: 2;
  pointer-events: none;
  transition: opacity var(--boton-dur) var(--boton-curva);
}

@keyframes boton-brillo {
  0%, 62% { left: -45%; }
  100%    { left: 125%; }
}

/* Hover: se revela el relleno, el texto pasa a oscuro y sube 2px.
   Las TRES sombras importan: filo de luz, sombra interna y halo del acento. */
@media (hover: hover) and (pointer: fine) {
  .boton.boton--fantasma:hover {
    /* El texto del hover lo decide el TEMA (§5bis.2bis):
       oscuro → tinta oscura sobre naranja · claro → blanco sobre azul.

       ESPECIFICIDAD: `.boton--fantasma` define `color: var(--boton)` y esta
       regla vive en un @media. Sin subir la especificidad, empata con la base
       y gana la que aparece después en el archivo — que es esta, pero NO si
       alguien reordena. Se usa `.boton.boton--fantasma:hover` para que no
       dependa del orden: es la causa de que el texto saliera negro en claro. */
    color: var(--boton-hover-fg);
    box-shadow:
      0 1px 0 rgba(255, 255, 255, 0.5) inset,
      0 -8px 22px rgba(0, 0, 0, 0.28) inset,
      0 12px 34px rgba(var(--boton-rgb), 0.32);
    transform: translateY(-2px);
  }

  .boton--fantasma:hover::before { opacity: 1; }

  .boton--fantasma:hover::after {
    opacity: 1;
    animation-duration: var(--boton-dur-brillo-hover);
  }
}

.boton--fantasma:active {
  transform: translateY(0) scale(0.985);
  transition: transform var(--boton-dur-click) ease;
}


/* ============================================================================
   2.3 EN TOUCH, EL FANTASMA SE CONVIERTE EN PRIMARIO
   ----------------------------------------------------------------------------
   Regla de Oz: sin hover no hay metal. El fantasma se SUSTITUYE por el
   primario — no se oculta (dejaría al usuario sin la acción) ni se deja
   transparente (sería texto suelto).
   ========================================================================== */

@media (hover: none) {
  /* ESPECIFICIDAD — este bloque vive DESPUÉS del @media (hover:hover) y con
     la misma especificidad, así que le ganaba incluso cuando el hover estaba
     activo por CDP: el texto salía negro en claro. Se sube el selector para
     que cada bloque mande en su propio terreno sin depender del orden.
     Medido: sin esto, en claro + hover el texto era rgb(10,14,20). */
  .boton.boton--fantasma {
    color: var(--boton-fg);
    background-color: var(--boton);
    border-color: var(--boton);
    box-shadow: none;
  }

  /* El metal no tiene sentido sin hover: se apaga del todo. */
  .boton--fantasma::before,
  .boton--fantasma::after {
    display: none;
  }
}


/* ============================================================================
   2.4 VARIANTES
   ========================================================================== */

/* Botón de icono (el del tema). Cuadrado, sin texto: aria-label obligatorio. */
.boton--icono {
  padding: var(--e-2);
  aspect-ratio: 1;
  border-radius: var(--radio-redondo);
  text-transform: none;
  letter-spacing: var(--track-normal);
  font-weight: var(--peso-normal);
  font-size: var(--t-m);
}

/* ============================================================================
   HAMBURGUESA — solo teléfono (§3.0h)
   ----------------------------------------------------------------------------
   En escritorio y tablet el menú son 4 anclajes en horizontal. En teléfono no
   caben: se ocultan y aparece este botón, que despliega los 4 en vertical.

   `display: none` aquí; el @media (max-width:719px) lo enciende.

   Tamaño 44×44 y no el `--isotipo-alto` (28px): la recomendación de área
   táctil es 44px mínimo. El botón de tema mide 28 y aun así funciona, pero
   este va más pulsado (abre el menú), así que se lleva el mínimo.
   ========================================================================== */
.hamburguesa {
  display: none;                 /* escritorio y tablet: manda el menú */
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;

  inline-size: 44px;
  block-size: 44px;
  border-radius: var(--radio-3);   /* 16px, a juego con la rueda */
  border: var(--trazo-fino) solid var(--borde);
  background-color: var(--superficie);
  cursor: pointer;
  flex: none;

  transition: border-color var(--dur-media) ease;
}

/* Las 3 líneas. El color sale del texto, así que permuta con el tema. */
.hamb-linea {
  display: block;
  inline-size: 20px;
  block-size: 2px;
  border-radius: 2px;
  background-color: var(--fg);
  transition: transform var(--dur-media) var(--boton-curva),
              opacity var(--dur-rapida) ease,
              background-color var(--dur-media) ease;
}

/* ABIERTO: las 3 líneas forman una X */
.hamburguesa.abierto .hamb-linea:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.hamburguesa.abierto .hamb-linea:nth-child(2) {
  opacity: 0;
}
.hamburguesa.abierto .hamb-linea:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* ============================================================================
   BOTÓN DE TEMA — FIJO ARRIBA A LA DERECHA, SIEMPRE VISIBLE (§3.0g)
   ----------------------------------------------------------------------------
   Oz: "el botón claro/oscuro siempre visible" y "la posición fija del botón
   claro/oscuro es arriba a la derecha".

   VA AQUÍ, DESPUÉS de .boton y .boton--icono, Y NO ANTES. Es la misma trampa
   que ya está documentada en §3.0d.9 (trampa 8): `.boton` declara
   `position: relative`, y con la misma especificidad gana la regla que va
   MÁS ABAJO en el archivo. Puesto antes, el `position: fixed` se perdía y el
   botón acababa en x=-16, fuera de pantalla y sin recibir clics. Medido.

   Es una pieza SUELTA, no parte de la cabecera: la cabecera nace oculta y solo
   entra con la rueda, así que un botón dentro de ella desaparecería justo en
   la portada, donde más falta hace. Aquí se ve en la portada, en la rueda y en
   cualquier sección futura sin depender de nadie.

   z-index: --z-aviso (900), por encima de la cabecera (100) y de los overlays
   (500): el tema se cambia SIEMPRE. Es el único elemento con ese privilegio.
   ========================================================================== */
.boton-tema {
  position: fixed;
  inset-block-start: var(--e-2);
  inset-inline-end: max(var(--e-3), env(safe-area-inset-right));
  z-index: var(--z-aviso);
}

/* ============================================================================
   3. ENLACE DE TEXTO
   ----------------------------------------------------------------------------
   Con subrayado siempre visible: el color por sí solo no es un indicador
   accesible (WCAG 1.4.1).
   ========================================================================== */

.enlace {
  color: var(--secundario-texto);
  text-decoration: underline;
  text-decoration-thickness: var(--trazo-fino);
  text-underline-offset: var(--e-1);
  transition: color var(--dur-rapida) var(--curva);
}

@media (hover: hover) and (pointer: fine) {
  .enlace:hover {
    color: var(--acento);
  }
}


/* ============================================================================
   4. AVISO
   ----------------------------------------------------------------------------
   Caja de información. Sin color de estado todavía (verde/rojo llegan con
   el contacto, Fase 7): aquí solo superficie y borde.
   ========================================================================== */

.aviso {
  padding: var(--e-3);
  background-color: var(--superficie);
  border: var(--trazo-fino) solid var(--borde);
  border-inline-start: var(--trazo-grueso) solid var(--acento);
  border-radius: var(--radio-2);
  font-size: var(--t-s);
  color: var(--mut);
}

.aviso strong {
  color: var(--fg);
  font-weight: var(--peso-fuerte);
}


/* ============================================================================
   5. RÓTULO
   ----------------------------------------------------------------------------
   Etiqueta pequeña en mayúsculas sobre un titular. Es un contrato (§5).
   ========================================================================== */

.rotulo {
  display: block;
  font-family: var(--fuente-titular);
  font-size: var(--t-xs);
  font-weight: var(--peso-medio);
  line-height: var(--inter-rotulo);
  letter-spacing: var(--track-rotulo);
  text-transform: uppercase;
  color: var(--acento);
}


/* ============================================================================
   6. TITULAR
   ----------------------------------------------------------------------------
   Título grande de sección. El <em> ya lo resuelve 02-base (color+peso,
   nunca cursiva). Aquí solo el tamaño y el aire.
   ========================================================================== */

.titular {
  font-family: var(--fuente-titular);
  font-size: var(--t-xl);
  font-weight: var(--peso-titular);
  line-height: var(--inter-titulo);
  letter-spacing: var(--track-titulo);
  color: var(--fg);
}

.titular--portada {
  font-size: var(--t-xxl);
}

.entradilla {
  font-size: var(--t-l);
  line-height: var(--inter-texto);
  color: var(--mut);
}

.portada__boton {
  /* ===== CENTRADO (orden de Oz con la captura) =====
     Centrado respecto al NOMBRE, no a la sección. El nombre está centrado en
     la pantalla, así que `left: 50%` + `translateX(-50%)` lo clava debajo de
     su eje. Se usa `translate` (no `transform`) para centrar y dejar
     `transform` libre para la entrada: son propiedades distintas y así no se
     pisan. */
  position: absolute;
  inset-block-start: calc(var(--logo-tinta-abajo, 50vh) + var(--lema-separacion) + 68px);
  inset-inline-start: 50%;
  translate: -50% 0;

  opacity: 0;
  transform: translateY(8px);

  /* ===== AQUÍ SE COMPONEN LAS DOS TRANSICIONES =====
     `.boton` ya tiene su propia `transition` (fondo, color, borde, transform)
     para el hover. Si aquí se declara solo `opacity/transform`, **se pierde
     la del hover**, y si se declara tarde GANA y la entrada se queda sin
     animar (era lo que pasaba: el botón aparecía de golpe).

     Se declaran las dos juntas: las del hover y las de la entrada. */
  transition:
    background-color var(--boton-dur) var(--boton-curva),
    color            var(--boton-dur) var(--boton-curva),
    border-color     var(--boton-dur) var(--boton-curva),
    transform        var(--dur-media) ease,
    opacity          var(--dur-media) ease;
}

/* ===== EL BOTÓN APARECE CON EL ESLOGAN (ya formado el nombre) =====
   Este bloque se perdió al reorganizar el archivo y el botón dejó de
   aparecer: se quedaba en opacity 0 para siempre. */
body.lista .portada__boton {
  opacity: 1;
  transform: translateY(0);
}


/* ============================================================================
   CABECERA Y PIE — RESPONSIVE
   ----------------------------------------------------------------------------
   Tres bandas, las mismas del resto del proyecto:
     < 720px    teléfono
     720-1023   tablet
     >= 1024    escritorio

   QUÉ SE APRIETA EN CADA UNA, Y POR QUÉ EN ESE ORDEN
   --------------------------------------------------
   El menú es lo primero que se queda sin sitio: 4 items en una línea necesitan
   ~330px solo de texto. En teléfono NO caben junto a la marca y el botón de
   tema, así que el menú pasa a una segunda fila bajo la cabecera. No se
   convierte en hamburguesa: serían 4 destinos, esconderlos detrás de un toque
   extra para luego mostrar 4 items es más trabajo para el usuario, no menos.
   ========================================================================== */

/* --- TABLET (720-1023) --- */
@media (max-width: 1023px) {
  .cabecera {
    gap: var(--e-2);
    padding-block: var(--e-1);
  }

  .anclajes {
    gap: var(--e-2);
  }

  .anclaje {
    font-size: var(--t-xs);
  }

  /* La marca encoge con el isotipo: -20%, acoplada por el token. */
  .marca--cabecera {
    font-size: calc(var(--isotipo-alto) * 0.58);
  }

  .marca__isotipo {
    block-size: calc(var(--isotipo-alto) * 0.8);
    inline-size: calc(var(--isotipo-alto) * 0.8);
  }
}

/* --- TELÉFONO (< 720) --- */
@media (max-width: 719px) {
  .cabecera {
    flex-wrap: wrap;             /* el menú baja a la segunda fila */
    justify-content: space-between;
    row-gap: var(--e-1);
  }

  /* ORDEN DE LAS TRES PIEZAS EN MÓVIL:
       1ª fila:  [marca] .................... [tema]
       2ª fila:  [menú, repartido a lo ancho]

     TRAMPA QUE YA SE COMETIÓ: poner order:2 a un contenedor de acciones y
     order:3 al menú mandaba el botón de tema a la IZQUIERDA (x=20 medido),
     porque un hijo no puede ir después de su propio padre. El menú tiene que
     ser hijo DIRECTO de .cabecera para poder reordenarse en otra fila.

     HOY YA NO HACE FALTA ORDENAR NADA: el botón de tema salió de la cabecera
     (§3.0g, es fijo arriba a la derecha). En la cabecera quedan solo la marca
     y el menú, y el menú baja solo porque pide el 100% del ancho.

  /* EL MENÚ SE OCULTA: su sitio lo ocupa la hamburguesa.
     Ya no baja a una segunda fila (lo que hacía antes): en teléfono el menú
     horizontal desaparece y se abre como PANEL desplegable bajo el botón. */
  .anclajes {
    /* `position:absolute` lo saca del flujo de la fila. SIN esto el menú,
       aunque esté con opacidad 0, SIGUE OCUPANDO SU ANCHO en el flex de la
       cabecera y empuja la hamburguesa 28px a la izquierda, hasta solaparse
       con el botón de tema (medido: hueco = -28px). */
    position: absolute;
    inset-block-start: 100%;
    inset-inline-end: 0;
    margin-block-start: var(--e-2);
    inline-size: max-content;

    flex-direction: column;
    align-items: flex-end;
    gap: var(--e-1);
    padding: var(--e-3);
    border-radius: var(--radio-3);
    border: var(--trazo-fino) solid var(--borde);
    background-color: color-mix(in srgb, var(--fondo) 94%, transparent);
    backdrop-filter: blur(14px) saturate(1.15);
    box-shadow: var(--sombra-3);   /* permuta con el tema, como todo */

    /* Entra desde arriba. Se abre con la clase .muestra (la pone el JS). */
    opacity: 0;
    transform: translateY(calc(var(--e-2) * -1));
    pointer-events: none;
    transition: opacity var(--dur-media) ease,
                transform var(--dur-media) var(--boton-curva);
    z-index: var(--z-cabecera);
  }

  .anclajes.muestra {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }

  /* Los items, a lo ancho del panel y alineados a la derecha. */
  .anclaje {
    inline-size: 100%;
    text-align: end;
    font-size: var(--t-s);
    padding-block: var(--e-2);
    padding-inline: var(--e-2);
  }

  /* Ancho cómodo: 44px de área táctil garantizada por el propio botón. */
  .anclajes {
    min-inline-size: 12rem;
  }

  .hamburguesa {
    display: flex;               /* enciende el botón solo aquí */
    /* Queda la ÚLTIMA de la fila. El botón de tema es `fixed` (no ocupa sitio
       en el flex) y la cabecera reserva su hueco con el padding derecho, así
       que la hamburguesa aterriza a su izquierda: borde en x=318, el de tema
       en x=346 — 28px de aire, sin solaparse. */
    margin-inline-start: auto;

    /* ALINEACIÓN VERTICAL CON EL BOTÓN DE TEMA.
       La hamburguesa mide 44 y el tema 28: centrados en la fila sus centros no
       coinciden (4px de desfase, medidos). No se igualan los centros — se
       igualan los BORDES SUPERIORES, que es lo que el ojo ve como "alineado":
       los dos empiezan a la misma altura y el más alto crece hacia abajo.
       El tema está fijo a 8px del borde de la ventana; la cabecera aporta su
       padding-block, así que se compensa lo que sobra. */
    align-self: flex-start;
    margin-block-start: calc(var(--e-2) - var(--e-1));
  }

  .marca--cabecera {
    font-size: calc(var(--isotipo-alto) * 0.5);
  }

  .marca__isotipo {
    block-size: calc(var(--isotipo-alto) * 0.7);
    inline-size: calc(var(--isotipo-alto) * 0.7);
  }

  /* El pie, un punto más pequeño: en 320px "SYSENTIA - 2026" con tracking
     ancho llega justo. */
  .pie__texto {
    letter-spacing: 0.04em;
    font-size: var(--t-xxs);
  }
}
