/* ==========================================================================
   Todo el sitio (index, informatica y ciencias-del-ejercicio) — sistema visual basado en DOPE-SECURITY.md
   Hoja autocontenida.
   Sustitutos: Whyte Inktrap → Inter · Whyte Inktrap Mono → JetBrains Mono · GrandSlang → Lora Italic
   ========================================================================== */

:root {
  color-scheme: dark;

  /* Colors */
  --color-near-black: #090909;
  --color-almost-white: #f7f9fa;
  --color-soft-white: #f0f0f0;
  --color-steel: #828384;
  --color-graphite: #474747;
  --color-iron: #423738;
  --color-ash: #6b6b6b;
  --color-signal-violet: #af50ff;
  --color-lavender-mist: #e1bdff;

  /* Derivados del documento */
  --hairline: rgba(247, 249, 250, 0.2);
  --wash: rgba(237, 195, 196, 0.05);
  --nav-bg-color: rgba(51, 50, 72, 0.7);
  --text-muted: rgba(247, 249, 250, 0.78);

  /* Typography — familias */
  --font-whyte-inktrap: 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-whyte-inktrap-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  --font-grandslang: 'Lora', Georgia, 'Times New Roman', serif;

  /* Typography — escala */
  --text-caption: 10px;
  --text-body-sm: 14px;
  --text-body: 16px;
  --text-subheading: 20px;
  --text-heading-sm: 32px;
  --text-heading-lg: clamp(1.75rem, 5vw, 64px);
  --text-section-stamp: clamp(1.55rem, 9.4vw, 74px);
  --text-display-hero: clamp(4rem, 12vw, 146px);
  --text-display: clamp(3.5rem, 9vw, 88px);

  /* Spacing */
  --spacing-4: 4px;
  --spacing-8: 8px;
  --spacing-12: 12px;
  --spacing-16: 16px;
  --spacing-20: 20px;
  --spacing-24: 24px;
  --spacing-32: 32px;
  --spacing-40: 40px;
  --spacing-48: 48px;
  --spacing-64: 64px;

  /* Layout */
  --page-max-width: 1200px;
  --gutter: clamp(20px, 5vw, 40px);
  --section-pad: 64px;

  /* Border Radius */
  --radius-cards: 19.2px;
  --radius-pills: 1584px;
  --radius-buttons: 8px;
  --radius-small: 6px;

  /* Elevation — solo el hairline de la barra */
  --shadow-subtle: rgba(16, 24, 40, 0.05) 0px 1px 2px 0px;
}

@media (min-width: 768px) {
  :root { --section-pad: 120px; }
}

/* ---------- Base ---------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 120px;
}

body {
  margin: 0;
  background: var(--color-near-black);
  color: var(--color-almost-white);
  font-family: var(--font-whyte-inktrap);
  font-size: var(--text-body);
  font-weight: 300;
  line-height: 1.5;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, p, ul { margin: 0; }
ul { padding: 0; list-style: none; }
a { color: inherit; }

:focus-visible {
  outline: 1px solid var(--color-almost-white);
  outline-offset: 4px;
}

::selection { background: var(--color-signal-violet); color: var(--color-near-black); }

.wrap {
  width: min(var(--page-max-width), calc(100% - 2 * var(--gutter)));
  margin-inline: auto;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 12px;
  z-index: 100;
  padding: 8px 12px;
  background: var(--color-near-black);
  border: 1px solid var(--color-almost-white);
  border-radius: var(--radius-small);
  font-size: var(--text-body-sm);
}
.skip:focus { left: 12px; }

/* ---------- Voces tipográficas ---------- */

/* Voz sellada: Whyte Inktrap Mono */
.mono {
  font-family: var(--font-whyte-inktrap-mono);
  font-weight: 400;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.stamp {
  margin-bottom: var(--spacing-48);
  font-family: var(--font-whyte-inktrap-mono);
  font-weight: 400;
  font-size: var(--text-section-stamp);
  line-height: 0.9;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-soft-white);
  white-space: nowrap;
}

/* Voz itálica: GrandSlang (solo momentos grandes, nunca en cuerpo ni nav) */
.slang {
  font-family: var(--font-grandslang);
  font-style: italic;
  font-weight: 400;
  font-feature-settings: "liga" 1, "dlig" 1;
  letter-spacing: -0.03em;
}

/* ---------- Botones ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-8);
  font-family: inherit;
  font-size: var(--text-body);
  font-weight: 400;
  line-height: 1;
  color: var(--color-almost-white);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}

/* Acción rellena: casi del color de la página, el borde hace el trabajo */
.btn--filled {
  padding: var(--spacing-16);
  background: var(--color-near-black);
  border: 1px solid var(--color-almost-white);
  border-radius: var(--radius-buttons);
}
.btn--filled:hover { background: var(--color-almost-white); color: var(--color-near-black); }

/* Píldora fantasma para acciones secundarias dentro de tarjetas */
.btn--ghost {
  padding: var(--spacing-16) var(--spacing-24);
  background: var(--wash);
  border: 0;
  border-radius: var(--radius-pills);
}
.btn--ghost:hover { background: rgba(247, 249, 250, 0.14); }

@media (min-width: 768px) {
  .btn--ghost { padding: var(--spacing-20) var(--spacing-32); }
}

/* ---------- Barra fija con desenfoque ---------- */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  background: var(--nav-bg-color);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--color-ash);
  box-shadow: var(--shadow-subtle);
}

.nav__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--spacing-8) var(--spacing-16);
  padding-block: var(--spacing-12);
}

.nav__brand {
  flex: 1;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 500;
  text-decoration: none;
}
/* Anillo del logo de marca (versión sin texto: a este tamaño el texto sería ilegible) */
.nav__logo { flex: none; width: 32px; height: 32px; }

.nav__cta { padding: 10px var(--spacing-16); font-size: var(--text-body-sm); }

.nav__links {
  order: 3;
  display: flex;
  flex-wrap: wrap;
  width: 100%;
  gap: var(--spacing-4) var(--spacing-20);
}

.nav__links a {
  padding-block: var(--spacing-4);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--text-muted);
  transition: color 0.2s ease;
}
.nav__links a:hover { color: var(--color-almost-white); text-decoration: underline; text-underline-offset: 4px; }

@media (min-width: 900px) {
  .nav__inner { flex-wrap: nowrap; gap: var(--spacing-32); padding-block: var(--spacing-16); }
  .nav__brand { flex: 0 0 auto; }
  .nav__links { order: 0; flex: 1; width: auto; justify-content: center; gap: var(--spacing-32); }
  .nav__cta { padding: 12px var(--spacing-20); }
}

/* ---------- Héroe: cielo de crepúsculo hecho con luz, sin foto ---------- */

.hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  padding: 150px 0 var(--spacing-64);
  overflow: hidden;
  background:
    radial-gradient(70% 55% at 85% 6%, rgba(175, 80, 255, 0.36), transparent 65%),
    radial-gradient(130% 55% at 50% 120%, rgba(175, 80, 255, 0.55), rgba(225, 189, 255, 0.14) 45%, transparent 72%),
    var(--color-near-black);
}

/* El trazo de luz que cruza el cielo: único trazo de acento de la página */
.hero::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: -10%;
  right: 45%;
  top: 68%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--color-lavender-mist) 60%, transparent);
  opacity: 0.35;
  transform: rotate(-7deg);
}

.hero__grid {
  display: grid;
  gap: var(--spacing-64);
  align-items: center;
}

@media (min-width: 960px) {
  .hero__grid { grid-template-columns: 1.2fr 0.8fr; gap: var(--spacing-64); }
}

/* Logo de marca completo sobre el titular del héroe (las tres páginas). Mismo tamaño en todo el
   sitio; el margen negativo a la izquierda compensa el aire del PNG para que el anillo quede
   alineado con el borde del texto. alt="" porque el nombre ya está en la barra y el pie. */
.hero__logo {
  display: block;
  width: clamp(84px, 8.5vw, 120px);
  height: auto;
  margin: 0 0 var(--spacing-24) -0.4%;
}
.hero__title { font-weight: 400; text-wrap: balance; }
.hero__title .slang { display: block; }
.hero__title .slang--hero { font-size: var(--text-display-hero); line-height: 0.85; }
.hero__title .sans {
  display: block;
  margin-block: var(--spacing-12);
  font-size: var(--text-heading-lg);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.03em;
}
.hero__title .slang--echo {
  font-size: var(--text-heading-lg);
  line-height: 1.1;
  color: var(--color-lavender-mist);
}
/* Titular largo (informatica): la columna es un contenedor y el tamaño sale de su ancho, así la
   palabra más larga ("Infraestructura", ~6.5em) nunca la ensancha ni aprieta la tarjeta. Sin
   soporte de container queries queda el tamaño fijo de respaldo. */
.hero__copy { container-type: inline-size; }
.hero__copy .slang--hero {
  padding-bottom: 0.18em; /* el rabillo de la "f" de "fallas" no debe rozar la línea siguiente */
  font-size: clamp(2.5rem, 7vw, 104px);
}
@supports (font-size: 1cqi) {
  .hero__copy .slang--hero { font-size: min(var(--text-display-hero), 14cqi); }
}

/* Sin línea sans intermedia (index), los descendentes del titular tocarían el eco */
.hero__title .slang--hero + .slang--echo { margin-top: var(--spacing-48); }

.hero__sub {
  max-width: 44ch;
  margin-top: var(--spacing-32);
  font-size: var(--text-subheading);
  font-weight: 300;
  line-height: 1.4;
  color: var(--text-muted);
}

/* Portada: título ~13 % más chico que el display-hero compartido (146px → ~127px) y bloque
   de historia en varios párrafos, con el mismo estilo de texto que .hero__sub. */
.hero--home .hero__title .slang--hero { font-size: clamp(3.5rem, 10.4vw, 127px); }

.hero__story {
  max-width: 58ch;
  margin-top: var(--spacing-32);
  font-size: 18px;
  font-weight: 300;
  line-height: 1.55;
  color: var(--text-muted);
}
.hero__story p + p { margin-top: var(--spacing-16); }

/* Con la historia el bloque de texto es más alto que las tarjetas: se alinean arriba, junto al
   título, en vez de flotar en el centro. */
/* Sin trazo de luz sobre video: la línea fina encima de la imagen en movimiento se confunde con
   un artefacto de compresión. Se mantiene en los héroes sin video (404). */
.hero--video::before { display: none; }
/* Héroes de las tres páginas: el contenido se ancla arriba (no centrado) con el mismo padding,
   así el logo queda a la misma altura en todas y no salta al cambiar de página. Deja ~36px bajo
   la barra fija (≈95px en móvil, donde los enlaces bajan a una segunda fila; 72px desde 900px). */
.hero--video { align-items: flex-start; padding-top: 132px; }
@media (min-width: 900px) {
  .hero--video { padding-top: 108px; }
}
@media (min-width: 960px) {
  .hero--video .hero__grid { align-items: start; }
}
@media (min-width: 960px) {
  .hero--home .hero__grid { align-items: start; }
  .hero--home .choices { margin-top: var(--spacing-40); }
}

/* ---------- Héroe con video de fondo (informatica) ---------- */

.hero__media {
  position: absolute;
  inset: 0;
  z-index: -3;
  overflow: hidden;
  background: var(--color-near-black);
}

.hero__video {
  position: absolute;
  z-index: 0;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Overlay violeta oscuro semitransparente: el video es claro (fondo gris azulado), así que
   se apaga con un violeta de la paleta (signal-violet mezclado con near-black) para que el
   texto claro se lea siempre.
   z-index explícito: ::before es el primer hijo y, sin él, el video se pinta encima. */
.hero__media::before {
  content: "";
  position: absolute;
  z-index: 1;
  inset: 0;
  background: #3b1e53;
  background: color-mix(in srgb, var(--color-signal-violet) 30%, var(--color-near-black));
  opacity: 0.62;
}

/* Velo oscuro: más denso a la izquierda (donde va el texto) y hacia abajo, para fundir
   el héroe con la sección siguiente; conserva el resplandor violeta de la esquina. */
.hero__media::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(9, 9, 9, 0) 55%, var(--color-near-black) 100%),
    linear-gradient(90deg, rgba(9, 9, 9, 0.78) 0%, rgba(9, 9, 9, 0.55) 50%, rgba(9, 9, 9, 0.3) 100%),
    radial-gradient(70% 55% at 85% 6%, rgba(175, 80, 255, 0.28), transparent 65%);
}

/* Variante para el video de informatica (escena de luz azul con acentos naranjas): el modo
   "color" cambia su matiz por el violeta de la paleta y conserva la luminosidad, así la
   escena queda violeta en vez de chocar con ella. */
.hero__media--tint::before {
  background: var(--color-signal-violet);
  mix-blend-mode: color;
  opacity: 0.9;
}
.hero__media--tint::after {
  background:
    linear-gradient(180deg, rgba(9, 9, 9, 0) 55%, var(--color-near-black) 100%),
    linear-gradient(90deg, rgba(9, 9, 9, 0.92) 0%, rgba(9, 9, 9, 0.78) 50%, rgba(9, 9, 9, 0.6) 100%),
    radial-gradient(70% 55% at 85% 6%, rgba(175, 80, 255, 0.28), transparent 65%);
}

/* Las tarjetas se apoyan sobre un video en movimiento: fondo oscuro + desenfoque para leerse siempre */
.hero--video .choice {
  background: rgba(9, 9, 9, 0.5);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}
.hero--video .choice:hover { background: rgba(9, 9, 9, 0.65); }
.hero--video .choice .mono { color: rgba(247, 249, 250, 0.7); }
.hero--video .pass {
  background: rgba(9, 9, 9, 0.5);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}
/* Etiquetas de 10px: el gris steel queda justo sobre un fondo que se mueve; se aclaran aquí */
.hero--video .pass__route .mono,
.hero--video .pass__arrow { color: rgba(247, 249, 250, 0.7); }

/* Tarjeta tipo tarjeta de embarque: cristal translúcido, sin sombra */
.pass {
  padding: var(--spacing-24);
  background: var(--wash);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-cards);
}
@media (min-width: 768px) {
  .pass { padding: var(--spacing-40); }
}

.pass__label {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  margin-bottom: var(--spacing-32);
  font-size: 12px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  font-weight: 400;
}
.pass__label svg { width: 14px; height: 14px; }

.pass__route {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-16);
  padding-bottom: var(--spacing-24);
  border-bottom: 1px solid var(--hairline);
}
.pass__route > div { display: grid; gap: var(--spacing-4); }
.pass__route .mono { font-size: 10px; letter-spacing: 0.18em; color: var(--color-steel); }
.pass__route strong { font-size: var(--text-body); font-weight: 400; }
.pass__route small { font-size: var(--text-body-sm); color: var(--text-muted); }
.pass__arrow { margin-top: 22px; color: var(--color-steel); }

/* Línea de credibilidad (informatica): ocupa el lugar de la ruta ORIGEN → DESTINO,
   con la misma línea divisoria inferior */
.pass__cred {
  padding-bottom: var(--spacing-24);
  border-bottom: 1px solid var(--hairline);
  font-size: var(--text-body-sm);
  line-height: 1.55;
  color: var(--text-muted);
  text-wrap: balance;
}
/* Cada credencial es un bloque en línea: el salto de línea cae entre credenciales y no parte
   nombres ("Los / Andes"). Si una sola no cabe (pantalla muy angosta), se parte dentro. */
.pass__cred span { display: inline-block; }
/* Variante lista (ciencias-del-ejercicio): una credencial por línea, sin separador visible;
   el espacio entre ellas marca dónde empieza cada una cuando alguna se parte en dos líneas. */
.pass__cred--list span { display: block; }
.pass__cred--list span + span { margin-top: var(--spacing-4); }

.pass__title {
  margin-block: var(--spacing-24) var(--spacing-32);
  font-size: var(--text-heading-sm);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.pass__actions { display: flex; flex-wrap: wrap; gap: var(--spacing-12); }

/* Tarjetas de elección (index): mismo cristal translúcido que .pass, pero enlazables */
.choices { display: grid; gap: var(--spacing-16); }

.choice {
  display: grid;
  gap: var(--spacing-12);
  padding: var(--spacing-24);
  background: var(--wash);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-cards);
  text-decoration: none;
  transition: background 0.2s ease, border-color 0.2s ease;
}
@media (min-width: 768px) {
  .choice { padding: var(--spacing-32) var(--spacing-40); }
}
.choice:hover { background: rgba(247, 249, 250, 0.1); border-color: var(--color-almost-white); }

.choice .mono { font-size: 10px; letter-spacing: 0.18em; color: var(--color-steel); }

.choice__title {
  font-size: var(--text-heading-sm);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.choice p {
  max-width: 40ch;
  font-size: var(--text-body);
  color: var(--text-muted);
}

.choice__go {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-8);
  margin-top: var(--spacing-8);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.choice__go span { transition: transform 0.2s ease; }
.choice:hover .choice__go span { transform: translateX(4px); }

/* Entrada del héroe (assets/js/motion.js). El estado inicial solo aplica si el <head>
   marcó <html class="js">; sin JS, o si motion.js falla, el contenido se ve completo. */
.js .hero__title > span,
.js .hero__sub,
.js .pass { opacity: 0; }

/* ---------- Secciones ---------- */

.section { padding-block: var(--section-pad); }

/* Filas de servicio: la fila ES la tarjeta, el espacio y la línea fina crean el límite */
.rows { border-top: 1px solid var(--hairline); }

.row {
  display: grid;
  gap: var(--spacing-16) var(--spacing-48);
  padding-block: var(--spacing-32);
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 768px) {
  .row { grid-template-columns: 1fr 1.3fr; align-items: start; }
}

.row__k {
  font-size: var(--text-heading-sm);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.row__k .mono { display: block; margin-bottom: var(--spacing-12); font-size: 12px; color: var(--color-steel); }

.row p {
  max-width: 52ch;
  font-size: 18px;
  font-weight: 300;
  line-height: 1.5;
  color: var(--text-muted);
}

/* Filas con imagen opcional (Servicios de informatica). Desde 960px las filas comparten una
   rejilla de tres columnas, así el texto de todas queda alineado aunque solo algunas traigan
   imagen: la tercera columna es de la miniatura. Debajo de 960px la imagen va bajo el texto. */
@media (min-width: 768px) {
  .rows--media .row__media { grid-column: 2; }
}
@media (min-width: 960px) {
  .rows--media .row { grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr) 220px; }
  .rows--media .row__media { grid-column: 3; }
}

/* Miniatura: no ocupa el ancho, lleva borde fino y un velo violeta de la paleta para que
   la foto se funda con el fondo oscuro. */
.row__media {
  position: relative;
  width: 100%;
  max-width: 220px;
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-cards);
  background: var(--color-near-black);
}
.row__media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  filter: saturate(0.75) contrast(1.05) brightness(0.9);
}
.row__media::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(135deg, rgba(175, 80, 255, 0.34) 0%, rgba(9, 9, 9, 0.38) 100%);
}

/* Sobre mí */
.about__lead {
  max-width: 34ch;
  margin-bottom: var(--spacing-64);
  font-size: var(--text-heading-lg);
  line-height: 1.15;
  color: var(--color-lavender-mist);
}

.about__text {
  max-width: 56ch;
  margin-bottom: var(--spacing-64);
  display: grid;
  gap: var(--spacing-16);
  font-size: var(--text-subheading);
  font-weight: 300;
  line-height: 1.5;
  color: var(--text-muted);
}

.row--fact { padding-block: var(--spacing-24); }
.row--fact .row__k { font-size: 20px; font-weight: 400; letter-spacing: -0.01em; }
.row--fact p { font-size: var(--text-body); }

/* Sobre mí: tres columnas (Educación, Certificaciones, Experiencia) lado a lado desde 1024px;
   debajo se apilan. Dentro de cada columna la fila pasa a una sola columna: título arriba e
   institución · detalle abajo. */
.about__cols { display: grid; gap: var(--spacing-48); }
@media (min-width: 1024px) {
  .about__cols {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: start;
  }
}

.about__col-title {
  margin-bottom: var(--spacing-16);
  font-family: var(--font-whyte-inktrap-mono);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-lavender-mist);
}

.about__col .row { grid-template-columns: 1fr; gap: var(--spacing-4); }
.about__col .row p { max-width: none; font-size: var(--text-body-sm); line-height: 1.45; }

/* Columna con más ítems (Certificaciones, 6): tipografía y espaciado algo más compactos para
   que las tres columnas queden parejas en alto. Solo con las columnas lado a lado; apiladas
   no hace falta y se ven con el mismo tamaño que las demás. */
@media (min-width: 1024px) {
  .about__col--dense .row { padding-block: 10px; }
  .about__col--dense .row__k { font-size: 15px; }
  .about__col--dense .row p { font-size: 13px; }
}

/* Tarjeta de floración violeta: una por página */
.bloom {
  padding: var(--spacing-24);
  border-radius: var(--radius-cards);
  background: radial-gradient(90% 130% at 100% 0%, #c98bff 0%, var(--color-signal-violet) 55%, #9a3ff0 100%);
  color: var(--color-near-black);
}
@media (min-width: 768px) {
  .bloom { padding: var(--spacing-40); }
}

.bloom .bloom__title {
  max-width: none;
  margin-bottom: var(--spacing-24);
  font-size: var(--text-display);
  font-weight: 400;
  line-height: 0.9;
  color: #ffffff;
}
.bloom p {
  max-width: 44ch;
  margin-bottom: var(--spacing-32);
  font-size: var(--text-subheading);
  font-weight: 400;
  line-height: 1.4;
}

/* Aurora del bloque de Contacto de informatica.html (clase .bloom--aurora; el .bloom de
   ciencias-del-ejercicio.html queda como está). Dos capas (::before / ::after) con tres
   manchas radiales cada una; solo se animan transform (translate/rotate/scale), así que corre
   en el compositor sin repintar ni relayout, y sin filter/blur. Las manchas se mantienen en
   una banda de luminosidad parecida a la del degradado para no perder contraste con el texto. */

/* Base estática: el extremo oscuro del degradado (#9a3ff0) se aclara a #a64bfa para que el
   párrafo casi negro llegue a 4.5:1 (AA). Aplica también con prefers-reduced-motion. */
.bloom--aurora {
  background: radial-gradient(90% 130% at 100% 0%, #c98bff 0%, var(--color-signal-violet) 55%, #a64bfa 100%);
}

/* Con prefers-reduced-motion: reduce no se genera ninguna capa: queda solo la base estática. */
@media (prefers-reduced-motion: no-preference) {
  .bloom--aurora {
    position: relative;
    overflow: hidden;
    isolation: isolate;
  }
  .bloom--aurora > * { position: relative; z-index: 1; }

  .bloom--aurora::before,
  .bloom--aurora::after {
    content: "";
    position: absolute;
    inset: -25%;
    z-index: 0;
    pointer-events: none;
    will-change: transform;
  }

  .bloom--aurora::before {
    background:
      radial-gradient(40% 60% at 22% 30%, rgba(134, 108, 255, 0.70), transparent 100%),
      radial-gradient(34% 55% at 80% 72%, rgba(210, 72, 228, 0.65), transparent 100%),
      radial-gradient(28% 45% at 58% 88%, rgba(166, 80, 250, 0.55), transparent 100%);
    animation: aurora-a 26s ease-in-out infinite alternate;
  }
  .bloom--aurora::after {
    background:
      radial-gradient(38% 58% at 70% 22%, rgba(214, 78, 226, 0.60), transparent 100%),
      radial-gradient(34% 52% at 28% 78%, rgba(128, 104, 252, 0.65), transparent 100%),
      radial-gradient(30% 48% at 90% 48%, rgba(180, 102, 255, 0.60), transparent 100%);
    animation: aurora-b 34s ease-in-out infinite alternate;
  }
}

@keyframes aurora-a {
  from { transform: translate3d(-6%, -4%, 0) rotate(-7deg) scale(1); }
  to   { transform: translate3d(7%, 5%, 0) rotate(9deg) scale(1.16); }
}
@keyframes aurora-b {
  from { transform: translate3d(6%, 5%, 0) rotate(10deg) scale(1.14); }
  to   { transform: translate3d(-7%, -6%, 0) rotate(-8deg) scale(0.98); }
}

/* Matrix rain sutil detrás de "Hablemos." (.bloom__rain, primer hijo de .bloom--aurora).
   28 columnas estáticas (spans) a paso fijo de 42px cubriendo todo el ancho de la tarjeta;
   en pantallas angostas el overflow:hidden recorta solas las que sobran, sin media queries.
   Solo se anima transform (translateY), así que corre en el compositor, igual que la aurora.
   Vive en z-index 0 (mismo nivel que ::before/::after de la aurora), detrás del texto real
   (z-index 1 vía ".bloom--aurora > *"): como el texto es opaco (blanco/casi-negro sólidos y
   el botón con fondo sólido), donde el rain cae geométricamente debajo de una letra queda
   completamente tapado — no cambia el contraste del texto respecto a la versión solo con
   aurora. Con prefers-reduced-motion no se genera nada (display: none). */
.bloom__rain { display: none; }

@keyframes rain-fall {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, -50%, 0); }
}

@media (prefers-reduced-motion: no-preference) {
  .bloom--aurora .bloom__rain {
    display: block;
    position: absolute;
    z-index: 0;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 14%, black 78%, transparent 100%);
            mask-image: linear-gradient(to bottom, transparent 0%, black 14%, black 78%, transparent 100%);
  }

  .bloom__rain-col {
    position: absolute;
    top: 0;
    width: 16px;
    font-family: var(--font-whyte-inktrap-mono);
    font-size: 12px;
    line-height: 19px;
    white-space: pre;
    text-align: center;
    will-change: transform;
    animation-name: rain-fall;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
  }

  .bloom__rain-col:nth-child(1) { left: 0px; color: rgba(255,255,255,0.30); animation-duration: 11s; animation-delay: -0.0s; }
  .bloom__rain-col:nth-child(2) { left: 42px; color: rgba(225,196,255,0.28); animation-duration: 13s; animation-delay: -3.7s; }
  .bloom__rain-col:nth-child(3) { left: 84px; color: rgba(255,255,255,0.30); animation-duration: 14s; animation-delay: -7.4s; }
  .bloom__rain-col:nth-child(4) { left: 126px; color: rgba(225,196,255,0.28); animation-duration: 16s; animation-delay: -11.1s; }
  .bloom__rain-col:nth-child(5) { left: 168px; color: rgba(255,255,255,0.30); animation-duration: 12s; animation-delay: -2.8s; }
  .bloom__rain-col:nth-child(6) { left: 210px; color: rgba(225,196,255,0.28); animation-duration: 18s; animation-delay: -0.5s; }
  .bloom__rain-col:nth-child(7) { left: 252px; color: rgba(255,255,255,0.30); animation-duration: 15s; animation-delay: -7.2s; }
  .bloom__rain-col:nth-child(8) { left: 294px; color: rgba(225,196,255,0.28); animation-duration: 17s; animation-delay: -8.9s; }
  .bloom__rain-col:nth-child(9) { left: 336px; color: rgba(255,255,255,0.30); animation-duration: 11s; animation-delay: -7.6s; }
  .bloom__rain-col:nth-child(10) { left: 378px; color: rgba(225,196,255,0.28); animation-duration: 13s; animation-delay: -7.3s; }
  .bloom__rain-col:nth-child(11) { left: 420px; color: rgba(255,255,255,0.30); animation-duration: 14s; animation-delay: -9.0s; }
  .bloom__rain-col:nth-child(12) { left: 462px; color: rgba(225,196,255,0.28); animation-duration: 16s; animation-delay: -8.7s; }
  .bloom__rain-col:nth-child(13) { left: 504px; color: rgba(255,255,255,0.30); animation-duration: 12s; animation-delay: -8.4s; }
  .bloom__rain-col:nth-child(14) { left: 546px; color: rgba(225,196,255,0.28); animation-duration: 18s; animation-delay: -12.1s; }
  .bloom__rain-col:nth-child(15) { left: 588px; color: rgba(255,255,255,0.30); animation-duration: 15s; animation-delay: -6.8s; }
  .bloom__rain-col:nth-child(16) { left: 630px; color: rgba(225,196,255,0.28); animation-duration: 17s; animation-delay: -4.5s; }
  .bloom__rain-col:nth-child(17) { left: 672px; color: rgba(255,255,255,0.30); animation-duration: 11s; animation-delay: -4.2s; }
  .bloom__rain-col:nth-child(18) { left: 714px; color: rgba(225,196,255,0.28); animation-duration: 13s; animation-delay: -10.9s; }
  .bloom__rain-col:nth-child(19) { left: 756px; color: rgba(255,255,255,0.30); animation-duration: 14s; animation-delay: -10.6s; }
  .bloom__rain-col:nth-child(20) { left: 798px; color: rgba(225,196,255,0.28); animation-duration: 16s; animation-delay: -6.3s; }
  .bloom__rain-col:nth-child(21) { left: 840px; color: rgba(255,255,255,0.30); animation-duration: 12s; animation-delay: -2.0s; }
  .bloom__rain-col:nth-child(22) { left: 882px; color: rgba(225,196,255,0.28); animation-duration: 18s; animation-delay: -5.7s; }
  .bloom__rain-col:nth-child(23) { left: 924px; color: rgba(255,255,255,0.30); animation-duration: 15s; animation-delay: -6.4s; }
  .bloom__rain-col:nth-child(24) { left: 966px; color: rgba(225,196,255,0.28); animation-duration: 17s; animation-delay: -0.1s; }
  .bloom__rain-col:nth-child(25) { left: 1008px; color: rgba(255,255,255,0.30); animation-duration: 11s; animation-delay: -0.8s; }
  .bloom__rain-col:nth-child(26) { left: 1050px; color: rgba(225,196,255,0.28); animation-duration: 13s; animation-delay: -1.5s; }
  .bloom__rain-col:nth-child(27) { left: 1092px; color: rgba(255,255,255,0.30); animation-duration: 14s; animation-delay: -12.2s; }
  .bloom__rain-col:nth-child(28) { left: 1134px; color: rgba(225,196,255,0.28); animation-duration: 16s; animation-delay: -3.9s; }
}

/* Trayectorias de motion capture del bloque de Contacto de ciencias-del-ejercicio.html
   (clase .bloom--mocap; el .bloom compartido no se toca). Una zancada de carrera en el plano
   sagital: tronco, cadera → rodilla → tobillo → punta del pie de las dos piernas (desfase de medio
   ciclo), con las curvas que traza cada marcador dibujadas como huella fija. El SVG lo genera
   assets/js/mocap.js; sin JS el bloque queda con el fondo estático.
   Vive en z-index 0, detrás del texto (z-index 1), y una máscara lo desvanece hacia la
   izquierda para que no pase por detrás de "Hablemos.", el párrafo ni el botón. */

/* Base estática: mismo ajuste que .bloom--aurora (#9a3ff0 → #a64bfa) para que el párrafo casi
   negro llegue a 4.5:1 (AA). Aplica también con prefers-reduced-motion. */
.bloom--mocap {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: radial-gradient(90% 130% at 100% 0%, #c98bff 0%, var(--color-signal-violet) 55%, #a64bfa 100%);
}
.bloom--mocap > :not(.bloom__mocap):not(.bloom__barpath) { position: relative; z-index: 1; }

.bloom__mocap {
  position: absolute;
  z-index: 0;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(50%, 480px);
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 30%);
          mask-image: linear-gradient(to right, transparent 0%, black 30%);
}
.bloom__mocap svg { display: block; width: 100%; height: 100%; overflow: visible; }

.mocap__trace { fill: none; stroke: rgba(255, 255, 255, 0.26); stroke-width: 1; stroke-dasharray: 2 5; stroke-linecap: round; }
.mocap__trail path { fill: none; stroke: #ffffff; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.mocap__trail-0 { stroke-opacity: 0.62; }
.mocap__trail-1 { stroke-opacity: 0.40; }
.mocap__trail-2 { stroke-opacity: 0.22; }
.mocap__trail-3 { stroke-opacity: 0.10; }
.mocap__trail.mocap__leg--back path { stroke: #e1bdff; stroke-width: 1.3; }
.mocap__bone  { stroke: rgba(255, 255, 255, 0.55); stroke-width: 1.4; stroke-linecap: round; }
.mocap__dot   { fill: #ffffff; fill-opacity: 0.85; }
.mocap__ring  { fill: none; stroke: rgba(255, 255, 255, 0.45); stroke-width: 1; }
/* Pierna de atrás: lavanda más tenue, para dar profundidad sin colores nuevos */
.mocap__leg--back .mocap__bone { stroke: rgba(225, 189, 255, 0.40); }
.mocap__leg--back .mocap__dot  { fill: #e1bdff; fill-opacity: 0.55; }
.mocap__leg--back .mocap__ring { stroke: rgba(225, 189, 255, 0.30); }

/* Trayectoria de barra (bar path) de un arranque, en el centro del bloque: la franja libre entre
   el final del párrafo y la figura de la derecha. Esa franja solo existe desde ~1280px; más
   angosto el párrafo y la figura se acercan demasiado, así que no se muestra. */
.bloom__barpath { display: none; }
@media (min-width: 1280px) {
  .bloom__barpath {
    display: block;
    position: absolute;
    z-index: 0;
    top: 9%;
    bottom: 7%;
    left: calc(50% + 40px);
    width: 120px;
    pointer-events: none;
  }
  .bloom__barpath svg { display: block; width: 100%; height: 100%; overflow: visible; }
}
.barpath__line  { fill: none; stroke: #e1bdff; stroke-opacity: 0.6; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.barpath__floor { stroke: rgba(255, 255, 255, 0.22); stroke-width: 1; stroke-linecap: round; }
.barpath__key   { fill: #e1bdff; fill-opacity: 0.7; transition: opacity 0.4s ease; }

/* Por debajo de 900px el párrafo llega casi al borde derecho: la figura se achica a la
   esquina inferior derecha (a la altura del botón) y la máscara pasa a ser radial desde esa
   esquina, para que se desvanezca antes de llegar al texto por la izquierda y por arriba. */
@media (max-width: 899px) {
  .bloom__mocap {
    top: auto;
    width: 40%;
    height: 54%;
    -webkit-mask-image: radial-gradient(120% 120% at 100% 100%, black 45%, transparent 85%);
            mask-image: radial-gradient(120% 120% at 100% 100%, black 45%, transparent 85%);
  }
}

/* Electrocardiograma junto al título "Servicios" (ciencias-del-ejercicio.html). El título y la
   línea van en una fila; el h2 no se encoge (sigue en nowrap) y la línea ocupa lo que sobra, así
   que en pantallas angostas solo se acorta. Tres latidos (onda P, complejo QRS, onda T) sobre una
   línea base tenue; encima, un barrido de izquierda a derecha hecho con tres copias del trazo con
   guiones de distinto largo y opacidad que comparten la misma punta (estela que se desvanece).
   Solo se anima stroke-dashoffset de un SVG chico, sin JS. Con prefers-reduced-motion queda la
   línea estática, algo más visible. */
.stamp-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-24);
  margin-bottom: var(--spacing-48);
}
.stamp-row .stamp { flex: none; margin-bottom: 0; }

.ecg {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 360px;
  height: 0.62em;
  font-size: var(--text-section-stamp);
  -webkit-mask-image: linear-gradient(to right, black 70%, transparent 100%);
          mask-image: linear-gradient(to right, black 70%, transparent 100%);
}
.ecg svg { display: block; width: 100%; height: 100%; overflow: visible; }
/* 3 latidos desde 900px; más angosto, 2 (con 3 quedarían demasiado apretados). Mismo ritmo:
   1,2 s por latido en ambas versiones. */
.ecg__narrow { display: none !important; }
@media (max-width: 899px) {
  .ecg__wide { display: none !important; }
  .ecg__narrow { display: block !important; }
}
.ecg path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.ecg__base { stroke: rgba(225, 189, 255, 0.34); stroke-width: 1.4; }
.ecg__sweep { display: none; }

@media (prefers-reduced-motion: no-preference) {
  .ecg__base { stroke: rgba(225, 189, 255, 0.16); stroke-width: 1.2; }
  .ecg__sweep {
    display: inline;
    stroke: #e1bdff;
    animation-duration: 3.6s;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
  }
  .ecg__narrow .ecg__sweep { animation-duration: 2.4s; }
  .ecg__sweep--tail { stroke-dasharray: 34 66; animation-name: ecg-tail; stroke-opacity: 0.16; stroke-width: 1.4; }
  .ecg__sweep--mid  { stroke-dasharray: 16 84; animation-name: ecg-mid;  stroke-opacity: 0.38; stroke-width: 1.6; }
  .ecg__sweep--head { stroke-dasharray: 5 95;  animation-name: ecg-head; stroke-opacity: 0.85; stroke-width: 1.8; stroke: #ffffff; }
}
/* Cada copia tiene un guion de largo L (pathLength = 100) cuya punta queda en L − offset: el
   offset va de L a L − 100 para que las tres puntas avancen juntas de 0 a 100 (todo el trazo)
   y el loop cierre sin salto. */
@keyframes ecg-tail { from { stroke-dashoffset: 34; } to { stroke-dashoffset: -66; } }
@keyframes ecg-mid  { from { stroke-dashoffset: 16; } to { stroke-dashoffset: -84; } }
@keyframes ecg-head { from { stroke-dashoffset: 5; }  to { stroke-dashoffset: -95; } }

/* Paquetes de red junto al título "Servicios" (informatica.html), en la misma fila .stamp-row
   que el electrocardiograma de ciencias-del-ejercicio. Una ruta de nodos (extremos cuadrados:
   equipo y servidor; intermedios redondos: routers) por la que viaja un paquete de ida con
   estela; cada nodo emite un anillo al recibirlo. Medio ciclo después vuelve la respuesta, más
   tenue, y hace brillar los nodos que cruza. Solo CSS sobre un SVG chico: stroke-dashoffset
   para los paquetes y opacity/transform para los nodos. Los retrasos de cada nodo salen de su
   posición a lo largo de la ruta (van en el HTML). Con prefers-reduced-motion queda la red
   estática, sin paquetes. */
.net {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 360px;
  height: 0.62em;
  font-size: var(--text-section-stamp);
  -webkit-mask-image: linear-gradient(to right, black 75%, transparent 100%);
          mask-image: linear-gradient(to right, black 75%, transparent 100%);
}
.net svg { display: block; width: 100%; height: 100%; overflow: visible; }
/* 5 nodos desde 900px; más angosto, 3 en una ruta más corta para que no queden diminutos */
.net__narrow { display: none !important; }
@media (max-width: 899px) {
  .net__wide { display: none !important; }
  .net__narrow { display: block !important; }
}
.net path { fill: none; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.net__link { stroke: rgba(225, 189, 255, 0.36); stroke-width: 1.2; stroke-dasharray: 2 4; }
.net__node { fill: rgba(225, 189, 255, 0.60); }
.net__hit { transform-box: fill-box; transform-origin: center; }
.net__ring { fill: none; stroke: #e1bdff; stroke-width: 1; opacity: 0; transform-box: fill-box; transform-origin: center; }
.net__pkt, .net__ack { display: none; }

@media (prefers-reduced-motion: no-preference) {
  .net__link { stroke: rgba(225, 189, 255, 0.26); }
  .net__node { fill: rgba(225, 189, 255, 0.50); }
  .net__pkt, .net__ack {
    display: inline;
    animation-duration: 4.8s;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
  }
  .net__pkt--tail { stroke: #e1bdff; stroke-opacity: 0.30; stroke-width: 1.6; stroke-dasharray: 12 88; animation-name: net-tail; }
  .net__pkt--head { stroke: #ffffff; stroke-opacity: 0.90; stroke-width: 2.2; stroke-dasharray: 2.5 97.5; animation-name: net-head; }
  /* La respuesta sale medio ciclo después (delay negativo = ya va por la mitad al cargar) */
  .net__ack--tail { stroke: #e1bdff; stroke-opacity: 0.14; stroke-width: 1.4; stroke-dasharray: 8 92; animation-name: net-ack-tail; animation-delay: -2.4s; }
  .net__ack--head { stroke: #e1bdff; stroke-opacity: 0.55; stroke-width: 1.8; stroke-dasharray: 2 98; animation-name: net-ack-head; animation-delay: -2.4s; }
  .net__ring { animation: net-ring 4.8s ease-out infinite; }
  .net__hit  { animation: net-hit 4.8s ease-out infinite; }
  .net__narrow .net__pkt, .net__narrow .net__ack,
  .net__narrow .net__ring, .net__narrow .net__hit { animation-duration: 3.2s; }
  .net__narrow .net__ack { animation-delay: -1.6s; }
}
/* Punta en (L − offset): offset de L a L − 100 recorre toda la ruta; loop sin salto */
@keyframes net-tail     { from { stroke-dashoffset: 12; }  to { stroke-dashoffset: -88; } }
@keyframes net-head     { from { stroke-dashoffset: 2.5; } to { stroke-dashoffset: -97.5; } }
@keyframes net-ack-tail { from { stroke-dashoffset: 8; }   to { stroke-dashoffset: -92; } }
@keyframes net-ack-head { from { stroke-dashoffset: 2; }   to { stroke-dashoffset: -98; } }
@keyframes net-ring {
  0%   { opacity: 0.85; transform: scale(0.45); }
  14%  { opacity: 0;    transform: scale(1.5); }
  100% { opacity: 0;    transform: scale(1.5); }
}
@keyframes net-hit {
  0%   { transform: scale(1.7); }
  12%  { transform: scale(1); }
  100% { transform: scale(1); }
}

/* Lluvia de código dentro de la tarjeta "Informática" de la portada (.choice--code), con el
   mismo mecanismo que .bloom__rain del Contacto de informatica.html pero con clases propias y
   colores para fondo oscuro: 14 columnas estáticas a paso fijo de 34px, cada una con su
   secuencia repetida dos veces; solo se anima transform (translateY hasta −50%, keyframes
   rain-fall), así que corre en el compositor. Vive en z-index 0 detrás del texto de la tarjeta
   y se desvanece arriba, abajo y hacia la izquierda, donde está el texto. Al pasar el mouse se
   aviva un poco. Con prefers-reduced-motion no se genera (display: none). */
.choice__rain { display: none; }

@media (prefers-reduced-motion: no-preference) {
  .choice--code {
    position: relative;
    overflow: hidden;
    isolation: isolate;
  }
  .choice--code > :not(.choice__rain) { position: relative; z-index: 1; }

  .choice--code .choice__rain {
    display: block;
    position: absolute;
    z-index: 0;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    opacity: 0.75;
    transition: opacity 0.3s ease;
    -webkit-mask-image:
      linear-gradient(to bottom, transparent 0%, black 18%, black 78%, transparent 100%),
      linear-gradient(to right, rgba(0, 0, 0, 0.35) 0%, black 60%);
    -webkit-mask-composite: source-in;
            mask-image:
      linear-gradient(to bottom, transparent 0%, black 18%, black 78%, transparent 100%),
      linear-gradient(to right, rgba(0, 0, 0, 0.35) 0%, black 60%);
            mask-composite: intersect;
  }
  .choice--code:hover .choice__rain { opacity: 1; }

  .choice__rain-col {
    position: absolute;
    top: 0;
    width: 14px;
    font-family: var(--font-whyte-inktrap-mono);
    font-size: 12px;
    line-height: 19px;
    white-space: pre;
    text-align: center;
    will-change: transform;
    animation-name: rain-fall;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
  }
  .choice__rain-col:nth-child(1) { left: 8px; color: rgba(175, 80, 255, 0.42); animation-duration: 11s; animation-delay: -3.0s; }
  .choice__rain-col:nth-child(2) { left: 42px; color: rgba(225, 189, 255, 0.30); animation-duration: 13s; animation-delay: -10.0s; }
  .choice__rain-col:nth-child(3) { left: 76px; color: rgba(175, 80, 255, 0.42); animation-duration: 14s; animation-delay: -7.1s; }
  .choice__rain-col:nth-child(4) { left: 110px; color: rgba(225, 189, 255, 0.30); animation-duration: 16s; animation-delay: -9.0s; }
  .choice__rain-col:nth-child(5) { left: 144px; color: rgba(175, 80, 255, 0.42); animation-duration: 12s; animation-delay: -9.1s; }
  .choice__rain-col:nth-child(6) { left: 178px; color: rgba(225, 189, 255, 0.30); animation-duration: 18s; animation-delay: -16.4s; }
  .choice__rain-col:nth-child(7) { left: 212px; color: rgba(175, 80, 255, 0.42); animation-duration: 15s; animation-delay: -6.6s; }
  .choice__rain-col:nth-child(8) { left: 246px; color: rgba(225, 189, 255, 0.30); animation-duration: 17s; animation-delay: -10.4s; }
  .choice__rain-col:nth-child(9) { left: 280px; color: rgba(175, 80, 255, 0.42); animation-duration: 11s; animation-delay: -5.6s; }
  .choice__rain-col:nth-child(10) { left: 314px; color: rgba(225, 189, 255, 0.30); animation-duration: 13s; animation-delay: -6.7s; }
  .choice__rain-col:nth-child(11) { left: 348px; color: rgba(175, 80, 255, 0.42); animation-duration: 14s; animation-delay: -9.7s; }
  .choice__rain-col:nth-child(12) { left: 382px; color: rgba(225, 189, 255, 0.30); animation-duration: 16s; animation-delay: -7.2s; }
  .choice__rain-col:nth-child(13) { left: 416px; color: rgba(175, 80, 255, 0.42); animation-duration: 12s; animation-delay: -6.4s; }
  .choice__rain-col:nth-child(14) { left: 450px; color: rgba(225, 189, 255, 0.30); animation-duration: 15s; animation-delay: -7.2s; }
}

/* Trayectoria de barra (arranque, vista sagital) dentro de la tarjeta "Ciencias del ejercicio"
   de la portada (.choice--lift). El SVG lo genera assets/js/barpath.js y va en z-index 0,
   detrás del texto, en una franja angosta pegada al borde derecho de la tarjeta. El texto de
   esta tarjeta deja libre ese ancho (--lift-w), así la trayectoria nunca pasa por detrás de
   las letras en ningún ancho de pantalla. Sin JS la tarjeta queda como siempre. */
.choice--lift {
  --lift-w: 60px;
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.choice--lift > :not(.choice__lift) { position: relative; z-index: 1; max-width: calc(100% - var(--lift-w)); }
.choice--lift p { max-width: min(40ch, calc(100% - var(--lift-w))); }

.choice__lift {
  position: absolute;
  z-index: 0;
  top: 8%;
  bottom: 6%;
  right: 6px;
  width: var(--lift-w);
  pointer-events: none;
  transition: opacity 0.3s ease;
  opacity: 0.8;
}
.choice--lift:hover .choice__lift { opacity: 1; }
.choice__lift svg { display: block; width: 100%; height: 100%; overflow: visible; }

.lift__guide { stroke: rgba(225, 189, 255, 0.22); stroke-width: 1; stroke-dasharray: 2 5; vector-effect: non-scaling-stroke; }
.lift__floor { stroke: rgba(225, 189, 255, 0.28); stroke-width: 1; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.lift__path  { fill: none; stroke: #e1bdff; stroke-opacity: 0.55; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.lift__key   { fill: #e1bdff; fill-opacity: 0.7; transition: opacity 0.4s ease; }
.lift__plate-rim   { fill: rgba(175, 80, 255, 0.16); stroke: rgba(225, 189, 255, 0.60); stroke-width: 1.4; vector-effect: non-scaling-stroke; }
.lift__plate-inner { fill: none; stroke: rgba(225, 189, 255, 0.30); stroke-width: 1; vector-effect: non-scaling-stroke; }
.lift__plate-hub   { fill: #ffffff; fill-opacity: 0.8; }

/* ---------- Página legal (privacidad y términos) ----------
   Sin héroe de pantalla completa: encabezado corto que deja espacio a la barra fija y luego
   las mismas filas de Servicios (título a la izquierda, texto a la derecha). */
.legal-head { padding: 160px 0 var(--spacing-48); }
@media (max-width: 899px) { .legal-head { padding-top: 140px; } }
.legal-head .mono { color: var(--color-steel); }
.legal-head__title {
  margin-block: var(--spacing-16) var(--spacing-32);
  font-size: var(--text-display);
  line-height: 0.95;
  text-wrap: balance;
}
.legal-head__jump { display: flex; flex-wrap: wrap; gap: var(--spacing-12); }
.legal .section { padding-top: var(--spacing-48); }
.legal .about__text { margin-bottom: var(--spacing-48); }

/* ---------- Pie con sello de lugar ---------- */

.foot {
  border-top: 1px solid var(--hairline);
  padding-block: var(--spacing-32);
  font-size: var(--text-body-sm);
}
.foot__inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--spacing-16) var(--spacing-32);
}
.foot__group { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-8) var(--spacing-24); }
.foot__plus { width: 14px; height: 14px; flex: none; }
/* Logo de marca completo (anillo + "Adán Salinas"): el único lugar con tamaño para leerlo */
.foot__logo { flex: none; width: 88px; height: 88px; margin-block: -12px; }
.foot a { text-decoration: none; color: var(--text-muted); transition: color 0.2s ease; }
.foot a:hover { color: var(--color-almost-white); text-decoration: underline; text-underline-offset: 4px; }
.foot__copy { flex-basis: 100%; margin-top: var(--spacing-8); font-size: 12px; color: var(--color-steel); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition-duration: 0.01ms !important; }
}
