/* ==========================================================================
   GNV Engineering — Sistema de diseño
   Guillem Navarro Vargas · Ingeniería, Energía e IA
   ========================================================================== */

/* --- 0. Tipografías --------------------------------------------------------
   Servidas desde este dominio, no desde Google. Dos razones y las dos pesan:
   la petición a fonts.googleapis.com bloquea el primer pintado, y manda la IP
   de cada visitante a un tercero fuera de la UE. Con analítica sin cookies y
   política de privacidad propia, lo segundo era una incoherencia.

   Archivo e IBM Plex Sans son variables: un solo fichero cubre todos sus
   pesos, y por eso el font-weight lleva un rango en vez de un número. IBM
   Plex Mono no lo es y necesita uno por peso.

   Los subconjuntos van separados por unicode-range: el navegador solo baja
   el latin-ext si en la página aparece de verdad un carácter que lo pida.
   Ambas familias son OFL (SIL Open Font License), que permite alojarlas. */

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url("/assets/tipos/archivo.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url("/assets/tipos/archivo-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/assets/tipos/ibm-plex-sans.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/assets/tipos/ibm-plex-sans-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/tipos/ibm-plex-mono-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/tipos/ibm-plex-mono-400-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/tipos/ibm-plex-mono-500.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/tipos/ibm-plex-mono-500-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --- 1. Tokens ----------------------------------------------------------- */

:root {
  color-scheme: dark;

  /* Superficies — petróleo profundo. El neutro lleva sesgo verde-azulado:
     un gris puro al lado del acento se leería como descuido. */
  --bg:          #071412;
  --bg-elev:     #0e1f1b;
  --bg-elev-2:   #142a25;
  --line:        rgba(228, 237, 233, 0.10);
  --line-strong: rgba(228, 237, 233, 0.20);

  /* Texto */
  --fg:          #e4ede9;
  --fg-muted:    #8ba49c;
  --fg-faint:    #6d857e;

  /* Acento — verde señal, del registro de instrumentación.
     Marca lo físico: energía, carga, planta. */
  --accent:      #2fe08f;
  --accent-deep: #1fb872;
  --accent-tint: rgba(47, 224, 143, 0.12);
  --accent-glow: rgba(47, 224, 143, 0.26);

  /* Segundo acento — marca lo digital: datos, modelo, cómputo. No es
     decoración: reparte con el verde los dos mundos que cruza el trabajo.
     Se probó en naranja y competía con el verde: dos cálidos saturados
     sobre fondo oscuro vibran, y en instrumentación el ámbar es alarma. */
  --dato:      #5c9dff;
  --dato-deep: #3f7fe0;
  --dato-tint: rgba(92, 157, 255, 0.12);
  --dato-glow: rgba(92, 157, 255, 0.24);

  /* Tipografía — Archivo viene de la rotulación industrial y aguanta el
     tamaño de titular; IBM Plex se dibujó para una empresa de tecnología y
     trae esa procedencia de ingeniería al texto y a los datos. */
  --font-display: "Archivo", "Segoe UI", system-ui, sans-serif;
  --font-body:    "IBM Plex Sans", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-mono:    "IBM Plex Mono", ui-monospace, "Cascadia Code", monospace;

  /* Escala tipográfica fluida */
  --step--1: clamp(0.80rem, 0.77rem + 0.15vw, 0.88rem);
  --step-0:  clamp(0.95rem, 0.91rem + 0.20vw, 1.06rem);
  --step-1:  clamp(1.15rem, 1.06rem + 0.44vw, 1.42rem);
  --step-2:  clamp(1.40rem, 1.23rem + 0.85vw, 1.90rem);
  --step-3:  clamp(1.70rem, 1.40rem + 1.48vw, 2.55rem);
  --step-4:  clamp(2.05rem, 1.55rem + 2.50vw, 3.40rem);
  --step-5:  clamp(2.50rem, 1.60rem + 4.50vw, 4.75rem);

  /* Ritmo */
  --gutter:  clamp(1.25rem, 0.9rem + 1.8vw, 2.5rem);
  --section: clamp(4.5rem, 3rem + 7vw, 9rem);
  --maxw:    1180px;

  /* Curvas y sombras */
  --radius:    14px;
  --radius-lg: 22px;
  --ease:      cubic-bezier(0.22, 1, 0.36, 1);
  --shadow:    0 1px 2px rgba(0,0,0,.30), 0 12px 32px -12px rgba(0,0,0,.55);
}

/* El verde señal es demasiado luminoso sobre fondo claro: ahí baja a un verde
   profundo que mantiene el contraste de texto por encima de 4.5:1. */
[data-theme="light"] {
  color-scheme: light;
  --bg:          #f2f6f4;
  --bg-elev:     #fbfdfc;
  --bg-elev-2:   #ffffff;
  --line:        rgba(7, 20, 18, 0.10);
  --line-strong: rgba(7, 20, 18, 0.22);
  --fg:          #081714;
  --fg-muted:    #4e625c;
  --fg-faint:    #5f736c;
  --accent:      #067a4a;
  --accent-deep: #045c37;
  --accent-tint: rgba(6, 122, 74, 0.10);
  --accent-glow: rgba(6, 122, 74, 0.20);
  --dato:        #1d5fd0;
  --dato-deep:   #164aa6;
  --dato-tint:   rgba(29, 95, 208, 0.10);
  --dato-glow:   rgba(29, 95, 208, 0.18);
  --shadow:      0 1px 2px rgba(7,20,18,.06), 0 14px 34px -16px rgba(7,20,18,.22);
}

/* --- 2. Reset ------------------------------------------------------------ */

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

* { margin: 0; }

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

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* clip y no hidden: hidden convierte el body en contenedor de
     desplazamiento y eso rompe position:sticky en todo lo que hay dentro —la
     impresora del CV dejaba de quedarse fija y pasaba de largo. clip recorta
     igual sin crear ese contenedor. */
  overflow-x: clip;
  transition: background-color .4s var(--ease), color .4s var(--ease);
}

img, svg, video { display: block; max-width: 100%; height: auto; }

/* Red de seguridad: un SVG en línea sin atributo width hereda height:auto y
   se estira hasta llenar su caja si nadie lo dimensiona. Le damos un tamaño
   base de icono; misma especificidad que las reglas de componente, así que
   cualquiera de ellas lo sobrescribe por venir después. */
svg:not([width]) { width: 1.25em; height: 1.25em; }

a { color: inherit; text-decoration: none; }

button, input, textarea, select { font: inherit; color: inherit; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.025em;
  text-wrap: balance;
}

p { text-wrap: pretty; }

::selection { background: var(--accent); color: #071412; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* --- 3. Utilidades ------------------------------------------------------- */

.contenedor {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.seccion { padding-block: var(--section); position: relative; }

.solo-lectores {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.saltar-al-contenido {
  position: absolute; top: -100%; left: var(--gutter);
  z-index: 200; padding: .75rem 1.25rem;
  background: var(--accent); color: #071412;
  border-radius: 0 0 10px 10px; font-weight: 600;
}
.saltar-al-contenido:focus { top: 0; }

/* Etiqueta de sección */
.kicker {
  display: inline-flex; align-items: center; gap: .6rem;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 1.1rem;
}
.kicker::before {
  content: ""; width: 26px; height: 1px;
  background: currentColor; opacity: .6;
}

.seccion__titulo { font-size: var(--step-4); max-width: 20ch; }

.seccion__intro {
  color: var(--fg-muted);
  font-size: var(--step-1);
  max-width: 58ch;
  margin-top: 1.25rem;
  line-height: 1.6;
}

/* --- 3b. Transiciones entre páginas -------------------------------------
   La API de View Transitions hace que navegar entre secciones funda una
   página con la siguiente en lugar de parpadear en blanco. Donde no está
   soportada, la navegación es la de siempre: no hay nada que emular. */

@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: .32s;
  animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}

/* La cabecera se mantiene fija entre páginas en vez de fundirse consigo misma. */
.cabecera { view-transition-name: cabecera; }

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  /* Y por si el navegador ignora la regla anterior dentro de un @media,
     anulamos también la animación resultante. */
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
}

/* --- 3c. Barra de progreso de lectura ------------------------------------ */

.progreso {
  position: fixed; inset: 0 0 auto 0;
  height: 2px;
  z-index: 120;
  background: linear-gradient(90deg, var(--dato), var(--accent));
  transform: scaleX(0);
  transform-origin: 0 50%;
  will-change: transform;
  pointer-events: none;
}

/* --- 4. Fondo técnico (retícula de plano) -------------------------------- */

.reticula {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(to right,  var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: 72px 72px;
  /* La malla deriva al 12% del scroll: mas lenta que el contenido, se lee
     como un plano de fondo con profundidad. --desliza lo pone main.js y sin
     JS (o con movimiento reducido) todo queda quieto en su sitio. */
  background-position: 0 calc(var(--desliza, 0px) * -.12);
  /* Dos capas de mascara que se suman: el halo fijo de la parte alta y un
     perfil de bandas — zonas donde la reticula se ve mas y zonas donde casi
     desaparece — que barre la pagina al 30% del scroll. El perfil empieza y
     acaba en el mismo valor para repetirse sin costura. */
  mask-image:
    radial-gradient(ellipse 85% 55% at 50% 0%, #000 0%, transparent 78%),
    linear-gradient(to bottom,
      rgba(0,0,0,.55) 0%, rgba(0,0,0,.1) 14%, rgba(0,0,0,.45) 30%,
      rgba(0,0,0,0) 46%, rgba(0,0,0,.6) 62%, rgba(0,0,0,.08) 78%,
      rgba(0,0,0,.35) 90%, rgba(0,0,0,.55) 100%);
  -webkit-mask-image:
    radial-gradient(ellipse 85% 55% at 50% 0%, #000 0%, transparent 78%),
    linear-gradient(to bottom,
      rgba(0,0,0,.55) 0%, rgba(0,0,0,.1) 14%, rgba(0,0,0,.45) 30%,
      rgba(0,0,0,0) 46%, rgba(0,0,0,.6) 62%, rgba(0,0,0,.08) 78%,
      rgba(0,0,0,.35) 90%, rgba(0,0,0,.55) 100%);
  mask-size: 100% 100%, 100% 2600px;
  -webkit-mask-size: 100% 100%, 100% 2600px;
  mask-position: 0 0, 0 calc(var(--desliza, 0px) * -.3);
  -webkit-mask-position: 0 0, 0 calc(var(--desliza, 0px) * -.3);
  mask-repeat: no-repeat, repeat-y;
  -webkit-mask-repeat: no-repeat, repeat-y;
  opacity: .6;
}

/* --- 5. Botones ---------------------------------------------------------- */

.boton {
  display: inline-flex; align-items: center; justify-content: center; gap: .6rem;
  padding: .85rem 1.6rem;
  border: 1px solid transparent;
  border-radius: 100px;
  font-weight: 600;
  font-size: var(--step-0);
  letter-spacing: -0.01em;
  cursor: pointer;
  white-space: nowrap;
  transition: transform .25s var(--ease), background-color .25s var(--ease),
              border-color .25s var(--ease), box-shadow .25s var(--ease), color .25s var(--ease);
}
.boton:hover { transform: translateY(-2px); }
.boton:active { transform: translateY(0); }

.boton--principal {
  background: var(--accent);
  color: #071412;
  box-shadow: 0 8px 24px -10px var(--accent-glow);
}
.boton--principal:hover {
  background: var(--accent-deep);
  box-shadow: 0 14px 34px -10px var(--accent-glow);
}
[data-theme="light"] .boton--principal { color: #fbfdfc; }

.boton--fantasma {
  border-color: var(--line-strong);
  background: transparent;
  color: var(--fg);
}
.boton--fantasma:hover {
  border-color: var(--accent);
  background: var(--accent-tint);
  color: var(--accent);
}

.boton .flecha { transition: transform .25s var(--ease); }
.boton:hover .flecha { transform: translateX(3px); }

/* --- 6. Cabecera --------------------------------------------------------- */

.cabecera {
  position: sticky; top: 0; z-index: 100;
  border-bottom: 1px solid transparent;
  transition: background-color .3s var(--ease), border-color .3s var(--ease);
}
.cabecera.esta-fijada {
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border-bottom-color: var(--line);
}

.cabecera__interior {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  height: 4.75rem;
}

.marca {
  display: inline-flex; align-items: center; gap: .7rem;
  font-family: var(--font-display);
  font-weight: 700; font-size: 1.06rem; letter-spacing: -0.02em;
}
.marca__texto small {
  display: block; font-family: var(--font-mono); font-weight: 400;
  font-size: .6rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--fg-faint); margin-top: 1px;
}

.navegacion { display: flex; align-items: center; gap: .35rem; }

.navegacion a {
  position: relative;
  padding: .5rem .85rem;
  border-radius: 8px;
  font-size: var(--step--1);
  color: var(--fg-muted);
  transition: color .2s var(--ease), background-color .2s var(--ease);
}
.navegacion a:hover { color: var(--fg); background: var(--accent-tint); }
.navegacion a[aria-current="page"] { color: var(--fg); }
.navegacion a[aria-current="page"]::after {
  content: ""; position: absolute; left: .85rem; right: .85rem; bottom: .18rem;
  height: 1.5px; background: var(--accent); border-radius: 2px;
}

.cabecera__acciones { display: flex; align-items: center; gap: .6rem; }

.boton-icono {
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: transparent;
  cursor: pointer;
  flex-shrink: 0;
  transition: border-color .25s var(--ease), background-color .25s var(--ease), color .25s var(--ease);
}
.boton-icono:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-tint); }
.boton-icono svg { width: 17px; height: 17px; }

.icono-luna { display: none; }
[data-theme="light"] .icono-sol  { display: none; }
[data-theme="light"] .icono-luna { display: block; }

.alternar-menu { display: none; }

/* Selector de idioma */
.idiomas {
  display: flex;
  height: 38px;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  flex-shrink: 0;
}
.idiomas a {
  display: grid; place-items: center;
  padding-inline: .58rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  font-weight: 500;
  letter-spacing: .08em;
  color: var(--fg-faint);
  transition: color .2s var(--ease), background-color .2s var(--ease);
}
.idiomas a + a { border-left: 1px solid var(--line); }
.idiomas a:hover { color: var(--fg); background: var(--accent-tint); }
.idiomas a[aria-current="true"] {
  color: var(--accent);
  background: var(--accent-tint);
  cursor: default;
}

/* --- 7. Hero ------------------------------------------------------------- */

.hero {
  position: relative;
  padding-block: clamp(3.5rem, 2rem + 8vw, 7.5rem) clamp(4rem, 3rem + 5vw, 7rem);
  overflow: hidden;
}
.hero::after {
  content: ""; position: absolute; z-index: -1;
  top: -30%; left: 50%; transform: translateX(-50%);
  width: min(900px, 120%); aspect-ratio: 1;
  background: radial-gradient(circle, var(--accent-glow) 0%, transparent 62%);
  opacity: .30; filter: blur(30px); pointer-events: none;
}

.hero__disponible {
  display: inline-flex; align-items: center; gap: .6rem;
  padding: .42rem .95rem .42rem .7rem;
  border: 1px solid var(--line-strong);
  border-radius: 100px;
  background: var(--bg-elev);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--fg-muted);
  margin-bottom: 1.75rem;
}
.punto {
  position: relative; width: 7px; height: 7px;
  border-radius: 50%; background: var(--accent); flex-shrink: 0;
}
.punto::after {
  content: ""; position: absolute; inset: 0;
  border-radius: 50%; background: inherit;
  animation: latido 2.4s ease-out infinite;
}
@keyframes latido {
  0%   { transform: scale(1);   opacity: .8; }
  70%  { transform: scale(3.2); opacity: 0;  }
  100% { transform: scale(3.2); opacity: 0;  }
}

.hero__titulo {
  font-size: var(--step-5);
  letter-spacing: -0.04em;
  max-width: 16ch;
}
.hero__titulo em {
  font-style: normal;
  color: var(--accent);
}

.hero__rol {
  display: flex; flex-wrap: wrap; align-items: center; gap: .55rem .9rem;
  margin-top: 1.5rem;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.hero__rol span:not(:last-child)::after {
  content: "/"; margin-left: .9rem; color: var(--accent); opacity: .7;
}

.hero__texto {
  margin-top: 1.75rem;
  max-width: 56ch;
  font-size: var(--step-1);
  line-height: 1.6;
  color: var(--fg-muted);
}
.hero__texto strong { color: var(--fg); font-weight: 600; }

.hero__acciones {
  display: flex; flex-wrap: wrap; gap: .85rem;
  margin-top: 2.5rem;
}

/* Entrada escalonada del hero. Va en CSS puro y no en JS para que arranque
   con el primer pintado, sin esperar a que se ejecute ningún script. */
.hero__contenido > * { animation: entrar .85s var(--ease) backwards; }
.hero__contenido > *:nth-child(1) { animation-delay: .04s; }
.hero__contenido > *:nth-child(2) { animation-delay: .12s; }
.hero__contenido > *:nth-child(3) { animation-delay: .20s; }
.hero__contenido > *:nth-child(4) { animation-delay: .28s; }
.hero__contenido > *:nth-child(5) { animation-delay: .36s; }


@keyframes entrar {
  from { opacity: 0; transform: translateY(18px); }
}
@keyframes aparecer {
  from { opacity: 0; transform: scale(.94); }
}

/* Reparto hero: texto + visual 3D */
/* Sin objeto al lado, el hero deja de ser una rejilla de dos columnas y pasa
   a ser una sola cosa. El titular puede crecer todo lo que quiera, que es lo
   que hace que una primera pantalla sin imagen funcione: si no hay nada que
   mirar, tiene que haber algo que leer, y grande. */
.hero__uno { display: grid; }

.hero__uno .hero__titulo {
  font-size: clamp(2.9rem, 11vw, 8.5rem);
  line-height: .92;
  letter-spacing: -.045em;
  max-width: 14ch;
}
.hero__uno .hero__texto { max-width: 54ch; font-size: var(--step-1); }



.hero__leyenda {
  position: absolute; inset: auto 0 0 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-faint);
}

/* Cifras */
.cifras {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px;
  margin-top: clamp(3rem, 2rem + 4vw, 5rem);
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.cifra { background: var(--bg); padding: 1.5rem 1.4rem; }
.cifra__valor {
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 600; letter-spacing: -0.03em;
  color: var(--accent);
  line-height: 1;
  /* Cifras de ancho fijo: al animar el contador los dígitos no bailan. */
  font-variant-numeric: tabular-nums;
}
.cifra__etiqueta {
  margin-top: .55rem;
  font-size: var(--step--1);
  color: var(--fg-muted);
  line-height: 1.45;
}

/* --- 8. Marquesina de empresas ------------------------------------------- */

.empresas {
  border-block: 1px solid var(--line);
  padding-block: 2.25rem;
  overflow: hidden;
}
.empresas__titulo {
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: 1.75rem;
}
.marquesina {
  display: flex; gap: 3.5rem; width: max-content;
  animation: desplazar 34s linear infinite;
  mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}
.empresas:hover .marquesina { animation-play-state: paused; }
@keyframes desplazar {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.marquesina span {
  font-family: var(--font-display);
  font-size: clamp(1rem, .9rem + .5vw, 1.35rem);
  font-weight: 600; letter-spacing: .02em;
  color: var(--fg-faint);
  white-space: nowrap;
  transition: color .3s var(--ease);
}
.marquesina span:hover { color: var(--fg); }

/* --- 9. Áreas de especialización ----------------------------------------
   Lista de hoja técnica, no rejilla de tarjetas. Siete cajas redondeadas
   iguales son el patrón que hace que cualquier web parezca de plantilla;
   una lista con índice grande, filete y dominio declarado se lee como un
   documento de ingeniería, que es de donde viene el trabajo. */

.especialidades {
  margin-top: clamp(2.5rem, 2rem + 2vw, 4rem);
  border-top: 1px solid var(--line-strong);
}

.area {
  --local:      var(--accent);
  --local-tint: var(--accent-tint);
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 14rem) minmax(0, 1fr);
  gap: clamp(1rem, .5rem + 2vw, 3rem);
  align-items: start;
  padding: clamp(1.5rem, 1.1rem + 1.4vw, 2.4rem) 0;
  border-bottom: 1px solid var(--line);
}
.area[data-dominio="digital"] { --local: var(--dato);     --local-tint: var(--dato-tint); }
.area[data-dominio="proceso"] { --local: var(--fg-muted); --local-tint: var(--line); }

/* El realce sangra fuera del contenedor para que responda la fila entera,
   sin necesidad de encerrarla en una caja. */
.area::before {
  content: "";
  position: absolute;
  inset: 0 calc(var(--gutter) * -0.5);
  background: var(--local-tint);
  opacity: 0;
  transition: opacity .35s var(--ease);
}
.area:hover::before { opacity: 1; }
.area > * { position: relative; }

.area__indice {
  font-family: var(--font-mono);
  font-size: clamp(1.9rem, 1.3rem + 2.4vw, 3.2rem);
  font-weight: 500;
  line-height: .85;
  letter-spacing: -0.04em;
  color: var(--local);
  font-variant-numeric: tabular-nums;
}

.area__titulo h3 { font-size: var(--step-2); }

/* El dominio en palabras: así el código de color deja de ser un secreto. */
.area__dominio {
  display: inline-block;
  margin-top: .8rem;
  padding: .22rem .7rem;
  border: 1px solid color-mix(in srgb, var(--local) 45%, transparent);
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: .64rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--local);
}

.area__cuerpo p {
  color: var(--fg-muted);
  line-height: 1.62;
  max-width: 58ch;
}

.etiquetas {
  display: flex; flex-wrap: wrap; gap: .4rem;
  margin-top: 1.25rem;
}
.etiqueta {
  padding: .28rem .7rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .05em;
  color: var(--fg-faint);
  white-space: nowrap;
}

/* --- 9b. Método: la cadena del sistema físico a la decisión --------------
   Una sección elevada rompe la sucesión de bloques sobre el mismo fondo y
   da profundidad a la página. */

.seccion--elevada {
  background: var(--bg-elev);
  border-block: 1px solid var(--line);
}

.cadena {
  display: flex;
  align-items: stretch;
  margin-top: clamp(2.5rem, 2rem + 2vw, 3.75rem);
}

.eslabon {
  --local:      var(--accent);
  --local-tint: var(--accent-tint);
  flex: 1 1 0;
  min-width: 0;
  display: flex; flex-direction: column;
  gap: .55rem;
  padding: 1.7rem 1.4rem;
  background: var(--bg);
  border: 1px solid color-mix(in srgb, var(--local) 26%, transparent);
  border-radius: var(--radius);
  transition: border-color .35s var(--ease), transform .35s var(--ease);
}
.eslabon[data-dominio="digital"] {
  --local:      var(--dato);
  --local-tint: var(--dato-tint);
}
.eslabon:hover {
  border-color: var(--local);
  transform: translateY(-3px);
}

.eslabon__icono {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  color: var(--local);
  margin-bottom: .35rem;
}
.eslabon__icono svg { width: 18px; height: 18px; }

.eslabon__paso {
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--local);
}
.eslabon h3 { font-size: var(--step-1); }
.eslabon p {
  color: var(--fg-muted);
  font-size: var(--step--1);
  line-height: 1.55;
}

/* El conector transporta el color del tramo: verde mientras es mundo
   físico, azul en cuanto pasa a ser dato. */
.conector {
  --c: var(--accent);
  flex: 0 0 clamp(22px, 3vw, 54px);
  align-self: center;
  height: 3px;
  border-radius: 2px;
  background-image: repeating-linear-gradient(90deg, var(--c) 0 7px, transparent 7px 13px);
  background-size: 13px 3px;
  animation: fluir 1.1s linear infinite;
}
.conector[data-dominio="digital"] { --c: var(--dato); }

@keyframes fluir  { to { background-position: 13px 0; } }
@keyframes fluirV { to { background-position: 0 13px; } }

@media (max-width: 860px) {
  .cadena { flex-direction: column; }
  .conector {
    flex-basis: 32px;
    width: 3px; height: auto;
    background-image: repeating-linear-gradient(180deg, var(--c) 0 7px, transparent 7px 13px);
    background-size: 3px 13px;
    animation-name: fluirV;
  }
}

/* --- 10. Proyectos destacados (portada) ---------------------------------- */

.lista-proyectos {
  margin-top: 3.5rem;
  border-top: 1px solid var(--line);
}

.proyecto {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 1.5rem 2rem;
  padding: 2rem 1.25rem;
  border-bottom: 1px solid var(--line);
  position: relative;
  transition: background-color .35s var(--ease), padding-inline .35s var(--ease);
}
.proyecto:hover { background: var(--bg-elev); padding-inline: 1.75rem 1rem; }

.proyecto__num {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--fg-faint);
  transition: color .3s var(--ease);
}
.proyecto:hover .proyecto__num { color: var(--accent); }

.proyecto__cuerpo { min-width: 0; }
.proyecto__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .9rem;
  font-family: var(--font-mono);
  font-size: .7rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: .6rem;
}
.proyecto__meta .cliente { color: var(--accent); }
.proyecto h3 {
  font-size: var(--step-2);
  transition: color .3s var(--ease);
}
.proyecto:hover h3 { color: var(--accent); }
.proyecto p {
  margin-top: .6rem;
  color: var(--fg-muted);
  max-width: 62ch;
  font-size: var(--step-0);
}

.proyecto__flecha {
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--fg-faint);
  flex-shrink: 0;
  transition: transform .35s var(--ease), background-color .35s var(--ease),
              border-color .35s var(--ease), color .35s var(--ease);
}
.proyecto:hover .proyecto__flecha {
  border-color: var(--accent); background: var(--accent); color: var(--bg);
  transform: rotate(-45deg);
}
/* Sin tamaño explícito, este SVG hereda height:auto del reset y se estira
   hasta llenar la fila. No quitar. */
.proyecto__flecha svg { width: 17px; height: 17px; }

/* --- 10a. Filtros del portfolio ------------------------------------------ */

.filtros {
  display: flex; flex-wrap: wrap; gap: .5rem;
  margin-bottom: clamp(2.5rem, 2rem + 2vw, 4rem);
}

.filtro {
  padding: .5rem 1.05rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: transparent;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fg-muted);
  cursor: pointer;
  white-space: nowrap;
  transition: color .25s var(--ease), border-color .25s var(--ease),
              background-color .25s var(--ease);
}
.filtro:hover { color: var(--fg); border-color: var(--line-strong); background: var(--accent-tint); }
.filtro[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg);
  cursor: default;
}

.filtros__recuento {
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .08em;
  color: var(--fg-faint);
  margin-bottom: 2rem;
}

/* --- 10b. Ficha de proyecto (página Portfolio) --------------------------- */

.ficha {
  display: block;
  border-bottom: 1px solid var(--line);
  /* Compensa la cabecera fija al llegar desde un enlace con ancla. */
  scroll-margin-top: 6rem;
}
/* El filtro puede ocultar la primera o la última, así que el primer y el
   último visibles se marcan desde JS en vez de con :first/:last-of-type. */
.ficha[hidden] { display: none; }
.ficha.es-primera .ficha__resumen { padding-top: 0; }
.ficha.es-ultima  { border-bottom: 0; }
.ficha--entra { animation: entrar .5s var(--ease) backwards; }

.ficha__aside { position: sticky; top: 7rem; align-self: start; }

.ficha__num {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--step-2);
  color: var(--accent);
  letter-spacing: .04em;
  margin-bottom: 1.5rem;
}

.ficha__datos { display: grid; gap: 1.1rem; }
.ficha__datos dt {
  font-family: var(--font-mono);
  font-size: .68rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: .25rem;
}
.ficha__datos dd { margin: 0; font-size: var(--step--1); color: var(--fg); }

.ficha__cuerpo h2 { font-size: var(--step-3); }
.ficha__cuerpo h3 {
  font-family: var(--font-mono);
  font-size: .72rem; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent);
  margin-top: 2rem; margin-bottom: .9rem;
}
.ficha__cuerpo > p {
  margin-top: 1.25rem;
  color: var(--fg-muted);
  font-size: var(--step-1);
  line-height: 1.62;
  max-width: 62ch;
}
.ficha__cuerpo > p strong { color: var(--fg); font-weight: 600; }

.ficha__cuerpo ul { list-style: none; padding: 0; display: grid; gap: .7rem; }
.ficha__cuerpo li {
  position: relative;
  padding-left: 1.4rem;
  color: var(--fg-muted);
  max-width: 62ch;
}
.ficha__cuerpo li::before {
  content: ""; position: absolute;
  left: 0; top: .68em;
  width: 6px; height: 1px;
  background: var(--accent);
}
.ficha__cuerpo li strong { color: var(--fg); font-weight: 600; }

/* --- 11. Sobre mí -------------------------------------------------------- */

.sobre {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(2rem, 1rem + 5vw, 5rem);
  align-items: start;
}

.retrato {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--bg-elev);
  aspect-ratio: 4 / 5;
}
.retrato img { width: 100%; height: 100%; object-fit: cover; }
.retrato__pie {
  position: absolute; inset: auto 0 0 0;
  padding: 2.5rem 1.4rem 1.1rem;
  background: linear-gradient(to top, rgba(7,20,18,.94), transparent);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: #e4ede9;
}

.sobre__cuerpo > p {
  color: var(--fg-muted);
  font-size: var(--step-1);
  line-height: 1.68;
  margin-top: 1.25rem;
}
.sobre__cuerpo > p strong { color: var(--fg); font-weight: 600; }

.trayectoria {
  margin-top: 2.5rem;
  border-left: 1px solid var(--line);
  padding-left: 1.6rem;
  display: grid; gap: 1.6rem;
}
.hito { position: relative; }
.hito::before {
  content: ""; position: absolute;
  left: calc(-1.6rem - 4.5px); top: .55rem;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--bg); border: 1.5px solid var(--accent);
}
.hito__periodo {
  font-family: var(--font-mono);
  font-size: .7rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent);
}
.hito h4 { font-size: var(--step-1); margin-top: .3rem; }
.hito p { color: var(--fg-muted); font-size: var(--step--1); margin-top: .3rem; }

/* --- 12. Contacto -------------------------------------------------------- */

.contacto-cta {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--bg-elev);
  padding: clamp(2.5rem, 1.5rem + 5vw, 5rem);
  text-align: center;
  overflow: hidden;
}
.contacto-cta::before {
  content: ""; position: absolute; z-index: 0;
  top: -60%; left: 50%; transform: translateX(-50%);
  width: 700px; aspect-ratio: 1;
  background: radial-gradient(circle, var(--accent-glow), transparent 60%);
  opacity: .35; filter: blur(40px);
}
.contacto-cta > * { position: relative; z-index: 1; }
.contacto-cta h2 { font-size: var(--step-4); margin-inline: auto; max-width: 18ch; }
.contacto-cta p {
  margin: 1.25rem auto 0; max-width: 50ch;
  color: var(--fg-muted); font-size: var(--step-1);
}
.contacto-cta .hero__acciones { justify-content: center; }

.correo-directo {
  display: inline-flex; align-items: center; gap: .6rem;
  margin-top: 2rem;
  font-family: var(--font-mono);
  font-size: var(--step-0);
  color: var(--fg-muted);
  border-bottom: 1px solid var(--line-strong);
  padding-bottom: .2rem;
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.correo-directo:hover { color: var(--accent); border-color: var(--accent); }

/* Formulario */
.formulario {
  display: grid; gap: 1.1rem;
  max-width: 620px;
}
.campo { display: grid; gap: .5rem; }
.campo label {
  font-family: var(--font-mono);
  font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--fg-muted);
}
.campo input, .campo textarea {
  width: 100%;
  /* Nunca por debajo de 16px: si no, Safari/iOS hace zoom al abrir el teclado */
  font-size: max(16px, var(--step-0));
  padding: .85rem 1rem;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: 10px;
  transition: border-color .25s var(--ease), background-color .25s var(--ease);
}
.campo input:focus, .campo textarea:focus {
  outline: none; border-color: var(--accent); background: var(--bg-elev-2);
}
.campo textarea { min-height: 150px; resize: vertical; }
.campo input::placeholder, .campo textarea::placeholder { color: var(--fg-faint); }

.aviso-formulario {
  font-size: var(--step--1);
  color: var(--fg-faint);
  line-height: 1.5;
}
.aviso-formulario a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }

/* Rejilla de contacto */
.rejilla-contacto {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 1rem + 5vw, 4.5rem);
  align-items: start;
}
.canal {
  display: flex; gap: 1rem; align-items: flex-start;
  padding: 1.4rem 0;
  border-bottom: 1px solid var(--line);
}
.canal:first-of-type { border-top: 1px solid var(--line); }
.canal__icono {
  display: grid; place-items: center;
  width: 40px; height: 40px; flex-shrink: 0;
  border: 1px solid var(--line-strong);
  border-radius: 10px; color: var(--accent);
}
.canal__icono svg { width: 18px; height: 18px; }
.canal h3 { font-size: var(--step-0); font-family: var(--font-body); font-weight: 600; }
.canal a, .canal p { color: var(--fg-muted); font-size: var(--step--1); margin-top: .2rem; display: block; }
.canal a:hover { color: var(--accent); }

/* --- 13. Pie ------------------------------------------------------------- */

.pie {
  border-top: 1px solid var(--line);
  padding-block: 3rem 2rem;
  margin-top: var(--section);
}
.pie__interior {
  display: flex; flex-wrap: wrap; gap: 2rem;
  justify-content: space-between; align-items: flex-start;
}
.pie__enlaces { display: flex; flex-wrap: wrap; gap: 1.5rem; }
.pie__enlaces a {
  font-size: var(--step--1);
  color: var(--fg-muted);
  transition: color .2s var(--ease);
}
.pie__enlaces a:hover { color: var(--accent); }
.pie__legal {
  width: 100%;
  margin-top: 2.5rem; padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between;
  font-size: var(--step--1); color: var(--fg-faint);
}

.redes { display: flex; gap: .6rem; }
.redes a {
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--fg-muted);
  transition: transform .25s var(--ease), border-color .25s var(--ease),
              color .25s var(--ease), background-color .25s var(--ease);
}
.redes a:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-tint); transform: translateY(-2px); }
.redes svg { width: 17px; height: 17px; }

/* --- 14. Cabecera de página interior ------------------------------------- */

.pagina-cabecera {
  padding-block: clamp(3rem, 2rem + 5vw, 6rem) clamp(2rem, 1.5rem + 3vw, 4rem);
  border-bottom: 1px solid var(--line);
}
.pagina-cabecera h1 { font-size: var(--step-5); letter-spacing: -0.04em; }
.pagina-cabecera p {
  margin-top: 1.5rem; max-width: 60ch;
  font-size: var(--step-1); color: var(--fg-muted);
}

/* Texto largo */
.prosa { max-width: 70ch; }
.prosa h2 { font-size: var(--step-2); margin-top: 2.75rem; margin-bottom: .9rem; }
.prosa h3 { font-size: var(--step-1); margin-top: 1.75rem; margin-bottom: .6rem; }
.prosa p, .prosa li { color: var(--fg-muted); margin-bottom: 1rem; }
.prosa ul { padding-left: 1.25rem; }
.prosa li::marker { color: var(--accent); }
.prosa a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.prosa strong { color: var(--fg); }

/* --- 15. Animación de entrada -------------------------------------------- */

.revelar {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .8s var(--ease), transform .8s var(--ease);
}
.revelar.es-visible { opacity: 1; transform: none; }

/* --- 16. Adaptativo ------------------------------------------------------ */

@media (max-width: 980px) {
  /* El visual pasa a acompañar al texto por debajo, con menos peso vertical. */
  #lienzo-hero { aspect-ratio: 4 / 3; }
  .hero__titulo, .hero__texto { max-width: none; }
}

@media (max-width: 900px) {
  /* El cuerpo baja a su propia fila; índice y título siguen juntos arriba. */
  .area { grid-template-columns: auto minmax(0, 1fr); gap: 1rem 1.5rem; }
  .area__cuerpo { grid-column: 1 / -1; }

  .ficha__aside { position: static; }
  .ficha__num { margin-bottom: 1rem; }
  .ficha__datos {
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 1rem 1.5rem;
  }
  .sobre { grid-template-columns: 1fr; }
  .retrato { max-width: 380px; }
  .rejilla-contacto { grid-template-columns: 1fr; }
}

@media (max-width: 760px) {
  .alternar-menu { display: grid; }

  .navegacion {
    position: fixed; inset: 4.75rem 0 auto 0;
    flex-direction: column; align-items: stretch;
    gap: .25rem;
    padding: 1rem var(--gutter) 1.75rem;
    background: var(--bg);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow);
    transform: translateY(-120%);
    opacity: 0; visibility: hidden;
    transition: transform .35s var(--ease), opacity .25s var(--ease), visibility .35s;
  }
  .navegacion.esta-abierta { transform: translateY(0); opacity: 1; visibility: visible; }
  .navegacion a { padding: .8rem 1rem; font-size: var(--step-0); }
  .navegacion a[aria-current="page"]::after { display: none; }

  .proyecto { grid-template-columns: 1fr; gap: .5rem; padding-inline: 0; }
  .proyecto:hover { padding-inline: .75rem; }
  .proyecto__flecha { display: none; }

  .pie__interior { flex-direction: column; gap: 1.75rem; }
}

@media (max-width: 430px) {
  /* Con tres botones y el selector de idioma, la cabecera se queda sin sitio:
     el nombre completo de la marca cede el paso al monograma. */
  .marca__texto { display: none; }
  .idiomas a { padding-inline: .45rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .revelar { opacity: 1; transform: none; }
}


/* --- 18. El CV sale impreso al bajar --------------------------------------
   Una hoja blanca emergiendo de una impresora en mitad de un sitio oscuro:
   el contraste es el efecto. El avance se calcula en JS y llega aquí como
   --salida, de 0 a 1. */

/* Una sola medida manda sobre todo el conjunto. Antes la impresora y el papel
   se dimensionaban por separado y los dos llevaban un tope fijo, asi que en
   una pantalla grande el trasto se quedaba del tamano de un movil mientras el
   resto de la pagina crecia. Ahora el alto del folio manda, y de el cuelgan
   el ancho del folio, el ancho de la impresora, el cuerpo de letra y hasta el
   recorrido de scroll. */
.cv {
  position: relative;

  /* Tres limites a la vez, y el primero es el que faltaba: el conjunto entero
     tiene que caber en la pantalla, no solo el folio. Sin descontar el cuerpo
     de la impresora, el folio se comia el hueco y la impresora salia cortada
     por arriba.

       - 100svh menos el alto del cuerpo de la impresora y los margenes
       - el ancho disponible, que es quien manda en pantalla estrecha
       - un tope, para que en un monitor enorme no ocupe la pared entera

     --alto-impresora lo mide el JS y lo escribe aqui. El 20rem de reserva es
     solo el valor de partida por si el JS no llega a tiempo o no corre. */
  --alto-impresora: 13rem;
  --alto-hoja: clamp(220px, min(calc(100svh - var(--alto-impresora)), (94vw - 3rem) * 1.414), 1400px);
  --ancho-hoja: calc(var(--alto-hoja) / 1.414);

  /* El voladizo del chasis a los lados del papel. Una impresora de verdad es
     bastante mas ancha que el folio que traga, y aqui ademas resuelve un
     problema: un A4 vertical alto es estrecho por definicion, alto entre
     1,414, asi que por muy alto que se haga nunca llena una pantalla ancha.
     El ancho tiene que venir del chasis, no del papel. */
  --margen-bandeja: clamp(.55rem, 3.4vw, 4.6rem);

  /* El ancho del chasis, en una sola variable. Todo lo que rodea a la maquina
     (bandeja, sombra de contacto, cable) cuelga de aqui, asi que cambiarlo en
     un sitio lo mueve todo junto y nada se descuadra. */
  --ancho-chasis: calc(var(--ancho-hoja) + var(--margen-bandeja) * 2 + 2px);
}

/* Pista de scroll: el recorrido durante el cual se imprime. Crece con el
   folio, que es lo que mantiene constante la sensacion de velocidad. Con una
   pista fija, un folio mas grande se imprimiria de golpe. */
.cv__pista { height: calc(70vh + var(--alto-hoja) * 1.6); }

.cv__fijo {
  position: sticky;
  top: 0;
  /* Nada de transform para centrar: desplazaba el bloque fuera de su caja y
     se montaba sobre el titular de la sección. Con align-content el centrado
     ocurre dentro, y sticky ya garantiza que no se sale del contenedor. */
  min-height: 100vh;
  min-height: 100svh;   /* svh descuenta la barra del navegador en móvil */
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 0;
  padding-block: 1.5rem;
}

/* --- La impresora --- */

.impresora {
  width: var(--ancho-chasis);
  background: linear-gradient(180deg, var(--bg-elev-2), var(--bg-elev));
  border: 1px solid var(--line-strong);
  border-radius: 16px 16px 6px 6px;
  padding: 1rem 1.25rem .75rem;
  box-shadow: var(--shadow);
  position: relative;
  z-index: 2;
  /* Un píxel de temblor por línea. Es casi imperceptible, pero el cerebro lo
     registra: las cosas que imprimen vibran. */
  transform: translateY(calc(var(--tiembla, 0) * 1px));
}

.impresora__marca {
  display: flex; align-items: center; gap: .6rem;
  font-family: var(--font-mono);
  font-size: .64rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-faint);
}
/* Chapa de modelo. El número de serie es la ISO 50001 que implantó: un guiño
   que solo pilla quien es del gremio, que son los que interesan. */
.impresora__placa {
  margin-left: auto;
  padding: .1rem .4rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  font-size: .58rem;
  color: var(--fg-faint);
}

/* --- Pantalla de estado ---
   Va en inglés a propósito: es la salida de una máquina, no texto del sitio.
   Y los colores son literales, no fichas: es una pantalla, y una pantalla no
   cambia de color porque el visitante prefiera el tema claro. */
.lcd {
  margin-top: .7rem;
  padding: .5rem .65rem;
  background: #04140d;
  border: 1px solid rgba(47, 224, 143, .22);
  border-radius: 5px;
  font-family: var(--font-mono);
  font-size: .6rem;
  line-height: 1.6;
  letter-spacing: .1em;
  color: #2fe08f;
  text-shadow: 0 0 7px rgba(47, 224, 143, .45);
  /* Rejilla sutil de píxeles, como un LCD de verdad. */
  background-image: repeating-linear-gradient(0deg, rgba(0,0,0,.25) 0 1px, transparent 1px 3px);
}
.lcd p { white-space: nowrap; overflow: hidden; }
.lcd__tenue { opacity: .55; }

/* --- Teclas --- */
.impresora__teclas { display: flex; gap: .4rem; margin-top: .6rem; }
.tecla {
  flex: 1;
  padding: .4rem .2rem;
  font-family: var(--font-mono);
  font-size: .58rem;
  letter-spacing: .12em;
  color: var(--fg-muted);
  background: linear-gradient(180deg, var(--bg-elev-2), var(--bg-elev));
  border: 1px solid var(--line-strong);
  border-radius: 5px;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(0, 0, 0, .45);
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
.tecla:hover { color: var(--accent); border-color: var(--accent); }
/* Recorrido real al pulsar: una tecla que no se hunde no parece una tecla. */
.tecla:active { transform: translateY(2px); box-shadow: none; }

/* --- El carro ---
   Barre de un lado a otro en cada línea, alternando el sentido. Es lo que
   distingue imprimir de simplemente revelar. */
.cv__carro {
  position: absolute;
  top: calc(var(--salida, 0) * 100%);
  left: calc(var(--margen-bandeja)
             + var(--carro, 0) * (100% - 2 * var(--margen-bandeja) - 38px));
  width: 38px; height: 7px;
  margin-top: -3px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--fg-muted), var(--fg-faint));
  box-shadow: 0 0 12px var(--accent-glow);
  opacity: 0;
  pointer-events: none;
  z-index: 3;
}
.cv[data-imprimiendo="si"] .cv__carro { opacity: 1; }

/* Piloto que parpadea solo mientras se está imprimiendo. */
.impresora__piloto {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--fg-faint);
  flex-shrink: 0;
}
.cv[data-imprimiendo="si"] .impresora__piloto {
  background: var(--accent);
  animation: parpadeo .9s steps(2, end) infinite;
}
@keyframes parpadeo { 50% { opacity: .25; } }

.impresora__estado { margin-left: auto; font-variant-numeric: tabular-nums; }

/* Ranura de salida del papel. */
.impresora__ranura {
  height: 10px;
  margin-top: .85rem;
  border-radius: 3px;
  background: var(--bg);
  box-shadow: inset 0 2px 5px rgba(0,0,0,.55);
}

/* --- El papel --- */

.cv__ventana {
  height: var(--alto-hoja);
  overflow: hidden;
  display: flex;
  justify-content: center;
  position: relative;
  z-index: 1;
  /* Sin esto, mientras no hay papel se ve un agujero negro. La bandeja lo
     convierte en superficie de la impresora. */
  padding-inline: var(--margen-bandeja);
  background: linear-gradient(180deg, var(--bg-elev) 0%, transparent 85%);
  border-inline: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  border-radius: 0 0 14px 14px;
}

.hoja {
  position: relative;
  height: 100%;
  aspect-ratio: 1 / 1.414;          /* A4 */
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #f7f4ec;
  color: #1a2420;
  padding: 1.3rem 1.9rem;
  /* Proporcional al folio, no a la ventana del navegador: si el papel crece,
     la letra crece con el y el documento se lee igual de bien a cualquier
     tamano. */
  font-size: max(7px, calc(var(--alto-hoja) / 68));
  line-height: 1.45;
  box-shadow: 0 18px 40px -18px rgba(0,0,0,.7);
  /* Se revela de arriba abajo, como sale de la impresora de verdad. */
  clip-path: inset(0 0 calc((1 - var(--salida, 0)) * 100%) 0);
}

/* Arrastre de papel: los agujeros del papel continuo. */
.hoja::before,
.hoja::after {
  content: "";
  position: absolute; top: 0; bottom: 0;
  width: 13px;
  background-image: radial-gradient(circle at 50% 6px, #d7ded9 2.6px, transparent 2.7px);
  background-size: 13px 13px;
  border-inline: 1px solid #e6ebe7;
}
.hoja::before { left: 0; }
.hoja::after  { right: 0; }

/* La línea del cabezal, justo en el borde de lo ya impreso. */
.cv__cabezal {
  position: absolute;
  left: var(--margen-bandeja); right: var(--margen-bandeja);
  top: calc(var(--salida, 0) * 100%);
  height: 2px;
  background: var(--accent);
  box-shadow: 0 0 14px var(--accent-glow);
  opacity: 0;
  pointer-events: none;
}
.cv[data-imprimiendo="si"] .cv__cabezal { opacity: 1; }

/* --- Contenido de la hoja --- */

.hoja__cabecera {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 1rem;
  padding-bottom: .6rem;
  border-bottom: 1.5px solid #16211d;
}
.hoja__nombre {
  font-family: var(--font-display);
  font-size: 2.4em;
  line-height: 1;
  letter-spacing: -0.03em;
  color: #16211d;
}
.hoja__rol { font-size: 1.05em; color: #4a5a54; margin-top: .3em; }
.hoja__contacto {
  font-family: var(--font-mono);
  font-size: .92em;
  text-align: right;
  color: #4a5a54;
  white-space: nowrap;
}

.hoja__cuerpo {
  flex: 1;
  min-height: 0;          /* sin esto, un hijo desbordado estira el flex */
  overflow: hidden;
  mask-image: linear-gradient(180deg, #000 90%, transparent);
  -webkit-mask-image: linear-gradient(180deg, #000 90%, transparent);
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 1.2em;
  margin-top: .8em;
}

.hoja h3 {
  font-family: var(--font-mono);
  font-size: .88em;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #0a7a4c;
  margin-bottom: .5em;
  padding-bottom: .25em;
  border-bottom: 1px solid #d7ded9;
}
.hoja h3:not(:first-child) { margin-top: 1.3em; }

.hoja__entrada { margin-bottom: .85em; }
.hoja__entrada b { font-size: 1.1em; color: #16211d; display: block; }
.hoja__entrada time {
  font-family: var(--font-mono);
  font-size: .9em;
  color: #6b7a74;
}
.hoja__entrada p { color: #4a5a54; margin-top: .15em; }

.hoja__lista { list-style: none; padding: 0; }
.hoja__lista li {
  padding: .18em 0;
  border-bottom: 1px dotted #dfe5e1;
}
.hoja__lista li:last-child { border-bottom: 0;
  display: flex; justify-content: space-between; gap: .6em;
}
.hoja__lista span:last-child {
  font-family: var(--font-mono);
  font-size: .88em;
  color: #6b7a74;
  white-space: nowrap;
}

.hoja__pie {
  flex-shrink: 0;
  margin-top: 1em;
  display: flex; justify-content: space-between; gap: 1em;
  font-family: var(--font-mono);
  font-size: .85em;
  color: #8e9c96;
}

.cv__acciones { margin-top: 1.5rem; display: flex; justify-content: center; }

@media (prefers-reduced-motion: reduce) {
  /* Sin recorrido: la hoja aparece impresa y ya. */
  .cv__pista { height: auto; }
  .cv__fijo { position: static; min-height: 0; }
  .cv__ventana { height: auto; }
  .hoja { clip-path: none; }
}

/* En pantallas bajas la hoja no cabe en vertical: se estrecha la bandeja
   y se deja que la hoja mande sobre el ancho. */
@media (max-width: 620px) {
  /* Ya no hace falta forzar medidas: la formula de arriba las cubre. Aqui
     solo queda lo que es decision de contenido y no de tamano. */
  /* En pantalla estrecha el folio es decorativo: nadie lee 7px. Se recorta
     a una columna para que lo que se ve esté completo y legible. */
  .hoja__cuerpo { grid-template-columns: 1fr; }
  .hoja__cuerpo > div:last-child { display: none; }
}

/* --- 19. Impresión --------------------------------------------------------
   Al imprimir sale solo el CV, a página completa y en tinta negra. Una sola
   fuente de verdad: se actualiza la web y el CV queda actualizado. */

@media print {
  @page { size: A4; margin: 14mm; }

  /* Todo fuera menos la hoja. */
  .cabecera, .pie, .reticula, .progreso,
  .hero, .empresas, .seccion:not(.cv), .cv__acciones,
  .impresora, .cv__cabezal, .hoja::before, .hoja::after,
  /* La mesa y el carro se colaban en el PDF y salían como dos rayas al
     final del documento: la mesa lleva borde superior y el carro es una
     barra. Aquí va todo lo que representa la máquina — en papel solo debe
     ir el papel. */
  .cv__mesa, .cv__carro { display: none !important; }

  /* La cabecera de la sección (kicker "Currículum", el título "La trayectoria,
     en un folio." y su intro) es rótulo de pantalla, no parte del CV. En papel
     sobra: el documento debe empezar por el propio folio. */
  .cv > .contenedor { display: none !important; }

  html, body {
    background: #fff !important;
    color: #000 !important;
    font-size: 10pt;
  }

  .cv, .cv__pista, .cv__fijo, .cv__ventana {
    all: unset;
    display: block !important;
  }

  .hoja {
    position: static !important;
    display: block !important;
    width: 100% !important;
    height: auto !important;
    max-height: none !important;
    aspect-ratio: auto !important;
    overflow: visible !important;
    padding: 0 !important;
    box-shadow: none !important;
    clip-path: none !important;
    background: #fff !important;
    color: #000 !important;
    font-size: 10pt !important;
  }

  /* El cuerpo deja de ser rejilla de dos columnas: en papel, una sola
     columna se lee mejor y no obliga a cuadrar alturas. */
  .hoja__cuerpo {
    display: block !important;
    overflow: visible !important;
    min-height: 0 !important;
    /* En pantalla lo que no cabe se desvanece; en papel eso saldría como
       texto degradado hacia el gris. */
    mask-image: none !important;
    -webkit-mask-image: none !important;
  }
  /* La segunda columna se oculta en pantallas estrechas, pero en papel tiene
     que salir siempre: formación, competencias, software e idiomas. */
  .hoja__cuerpo > div:last-child { display: block !important; }
  .cv__pliegue { display: none !important; }
  /* La textura es para la pantalla. En papel, imprimir el grano de un papel
     simulado sobre papel de verdad es tinta gastada y un gris innecesario. */
  .hoja__grano { display: none !important; }
  .hoja__cuerpo p, .hoja__entrada b, .hoja__lista { text-shadow: none !important; }
  .hoja__cuerpo > div + div { margin-top: 1.5em; }

  .hoja h3 { color: #000 !important; border-bottom-color: #999 !important; }
  .hoja__entrada p, .hoja__rol, .hoja__contacto { color: #333 !important; }
  .hoja__pie { margin-top: 2em !important; }

  /* Que no se parta una entrada entre dos páginas. */
  .hoja__entrada, .hoja__lista li { break-inside: avoid; }
  .hoja h3 { break-after: avoid; }

  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .85em; color: #555; }
}

/* --- 18b. La impresora en su sitio ----------------------------------------
   Tres remates: apoyarla en algo, el rodillo que arrastra el papel, y el
   papel plegándose al salir. */

/* La impresora flotaba en el vacío. Un canto de mesa y una sombra de contacto
   la anclan: no se piensa conscientemente, pero se nota cuando falta. */
.cv__mesa {
  position: relative;
  /* Antes la mesa se dimensionaba con la altura de la pantalla, asi que en un
     monitor ancho quedaba un canto corto flotando en medio de un vacio. Una
     mesa es lo unico de esta escena que no tiene por que ser pequeno: puesta
     de lado a lado, la impresora deja de parecer un adorno centrado y pasa a
     estar apoyada en algo. */
  width: min(1400px, 96vw);
  height: 10px;
  margin-top: -1px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--bg-elev-2), var(--bg-elev) 55%, transparent);
  border-top: 1px solid var(--line-strong);
}
/* Sombra de contacto: más densa justo bajo la máquina y difusa hacia fuera. */
.cv__mesa::before {
  content: "";
  position: absolute;
  /* Anclada al ancho del chasis y no al de la mesa: la sombra la proyecta la
     maquina, no el mueble. */
  inset: 100% auto auto 50%;
  /* Sin superar la mesa: en móvil el chasis casi llena la pantalla y los
     4rem extra asomaban por el borde, ensanchando la página. */
  width: min(calc(var(--ancho-chasis) + 4rem), 100%);
  transform: translateX(-50%);
  height: 30px;
  background: radial-gradient(ellipse at 50% 0%, rgba(0,0,0,.55), transparent 72%);
  pointer-events: none;
}
/* El cable, que sale por detrás y cae. */
.cv__mesa::after {
  content: "";
  position: absolute;
  right: calc(50% - var(--ancho-chasis) / 2 + 1.5rem);
  top: -22px;
  width: 42px; height: 22px;
  border-right: 2px solid var(--line-strong);
  border-bottom: 2px solid var(--line-strong);
  border-bottom-right-radius: 14px;
  opacity: .7;
}

/* Rodillo de arrastre visible en la ranura. Gira con el papel: los dientes
   encajan con los agujeros que la hoja ya tenía dibujados. */
.impresora__ranura {
  position: relative;
  overflow: hidden;
}
.impresora__rodillo {
  position: absolute;
  inset: 1px 6px;
  border-radius: 2px;
  background-image: repeating-linear-gradient(
    90deg,
    var(--line-strong) 0 2px,
    transparent 2px 9px
  );
  /* Una vuelta de dientes por cada línea impresa. */
  background-position: calc(var(--salida, 0) * -420px) 0;
  opacity: .8;
}

/* El papel continuo se pliega al llegar abajo, como el de matriz de puntos.
   Son bandas de sombra sobre el tercio inferior de la hoja: mucho más barato
   que doblar geometría, y a este tamaño se lee igual. */
.cv__pliegue {
  /* Dentro de la hoja a propósito: así el recorte de impresión lo tapa y no
     aparecen dobleces en papel que todavía no ha salido de la máquina. */
  position: absolute;
  inset: auto 0 0 0;
  height: calc(var(--plegado, 0) * 15%);
  pointer-events: none;
  z-index: 2;
  background-image: repeating-linear-gradient(
    180deg,
    transparent 0 25px,
    rgba(255, 255, 255, .55) 25px 26px,   /* cresta del doblez */
    rgba(0, 0, 0, .085) 26px 30px          /* valle */
  );
  mask-image: linear-gradient(180deg, transparent, #000 60%);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 60%);
}

@media (max-width: 620px) {
  .cv__mesa { width: min(94vw, 380px); }
}


/* --- 18c. Textura analógica del papel -------------------------------------
   Tres capas que separan "hoja de papel" de "rectángulo blanco". Van sobre
   todo el folio y con contraste bajísimo: una banda uniforme se lee como
   textura de impresión, mientras que una banda irregular sobre parte de la
   hoja se lee como un fallo de dibujo. Esa es toda la diferencia. */

.hoja__grano {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  mix-blend-mode: multiply;
  background-image:
    /* Paso del cabezal. El paso es irregular a propósito: repetir cada tres
       píxeles exactos se lee como un rayado, no como tinta. */
    repeating-linear-gradient(180deg,
      rgba(0, 0, 0, .022) 0 1px,
      transparent 1px 4px,
      rgba(0, 0, 0, .013) 4px 5px,
      transparent 5px 11px),
    /* Sombra de los bordes: el papel no es plano, se comba hacia el canto. */
    linear-gradient(90deg,
      rgba(0, 0, 0, .06), transparent 5%, transparent 95%, rgba(0, 0, 0, .06));
}

/* La tinta de una impresora nunca cae perfectamente limpia. */
.hoja__cuerpo p,
.hoja__entrada b,
.hoja__lista { text-shadow: 0 0 .35px rgba(26, 36, 32, .45); }

/* --- 10c. Fichas plegables ------------------------------------------------
   Seis fichas abiertas de golpe son un muro de texto que nadie recorre. En
   cerrado el portfolio se lee de una ojeada y cada una se abre a demanda,
   creciendo desde su sitio con la API de View Transitions. */


.ficha__resumen {
  width: 100%;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 1rem 1.75rem;
  align-items: center;
  text-align: left;
  padding: clamp(1.3rem, 1rem + 1.1vw, 2rem) 0;
  background: none;
  border: 0;
  color: inherit;
  cursor: pointer;
  font: inherit;
  transition: padding-inline .3s var(--ease);
}
.ficha__resumen:hover { padding-inline: .5rem 0; }
.ficha__resumen:hover h2 { color: var(--accent); }

.ficha__resumen h2 {
  font-size: var(--step-2);
  transition: color .25s var(--ease);
}

.ficha__contexto {
  display: block;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: .45rem;
}
.ficha__contexto b { color: var(--accent); font-weight: 400; }

/* El signo cambia de + a − girando, no sustituyendo un icono por otro. */
.ficha__signo {
  position: relative;
  width: 34px; height: 34px;
  border: 1px solid var(--line);
  border-radius: 50%;
  flex-shrink: 0;
  transition: border-color .3s var(--ease), background-color .3s var(--ease);
}
.ficha__signo::before,
.ficha__signo::after {
  content: "";
  position: absolute;
  inset: 50% 25%;
  height: 1px;
  background: var(--fg-muted);
  transition: transform .35s var(--ease), background-color .3s var(--ease);
}
.ficha__signo::after { transform: rotate(90deg); }

.ficha__resumen:hover .ficha__signo { border-color: var(--accent); }
.ficha__resumen[aria-expanded="true"] .ficha__signo {
  border-color: var(--accent);
  background: var(--accent);
}
.ficha__resumen[aria-expanded="true"] .ficha__signo::before,
.ficha__resumen[aria-expanded="true"] .ficha__signo::after { background: var(--bg); }
/* Al abrir, la barra vertical gira hasta confundirse con la horizontal. */
.ficha__resumen[aria-expanded="true"] .ficha__signo::after { transform: rotate(0deg); }

.ficha__detalle {
  display: grid;
  grid-template-columns: minmax(0, 0.42fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 1rem + 3vw, 4rem);
  padding-bottom: clamp(2rem, 1.5rem + 2vw, 3.5rem);
}
.ficha__detalle[hidden] { display: none; }

@media (max-width: 900px) {
  .ficha__detalle { grid-template-columns: 1fr; gap: 1.5rem; }
  .ficha__resumen { gap: .75rem 1rem; }
}

@media print {
  /* En papel se imprime todo: un desplegable cerrado es contenido perdido. */
  .ficha__detalle[hidden] { display: grid !important; }
  .ficha__signo { display: none !important; }
}

/* --- 20. Contacto: arranque, preproceso y terminal ------------------------
   Un cuadro de texto en blanco es lo que más frena a quien quiere escribir:
   no sabe qué poner. Aquí el mensaje se define como se define un cálculo
   —geometría, condiciones de contorno, cargas, solver— y se redacta solo. */

/* --- Secuencia de arranque --- */

.arranque {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  line-height: 1.9;
  color: var(--accent);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-elev);
  padding: 1.25rem 1.4rem;
  margin-bottom: 2.5rem;
  min-height: 8.5rem;
}
.arranque p { opacity: 0; }
.arranque p.visible { opacity: 1; }
.arranque .ok { color: var(--fg-faint); }
.arranque .ok::after { content: " [OK]"; color: var(--accent); }
.arranque__saltar {
  margin-top: .75rem;
  padding: .3rem .7rem;
  font-family: inherit; font-size: .68rem; letter-spacing: .1em;
  color: var(--fg-faint);
  background: none;
  border: 1px solid var(--line);
  border-radius: 5px;
  cursor: pointer;
}
.arranque__saltar:hover { color: var(--accent); border-color: var(--accent); }
.arranque[hidden] { display: none; }

/* --- Preproceso: los cuatro pasos --- */

.caso { display: grid; gap: 2.25rem; }

.paso {
  border-top: 1px solid var(--line);
  padding-top: 1.5rem;
}
.paso__rotulo {
  display: flex; align-items: baseline; gap: .8rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: .3rem;
}
.paso__rotulo b { color: var(--accent); font-weight: 400; }
.paso h3 { font-size: var(--step-1); margin-bottom: 1rem; }

/* Los interruptores. Cada uno tiene su piloto, y el conjunto se lee como un
   panel de control y no como un formulario. */
.interruptores { display: flex; flex-wrap: wrap; gap: .6rem; }

.interruptor { position: relative; }
.interruptor input {
  position: absolute; opacity: 0;
  width: 100%; height: 100%; margin: 0; cursor: pointer;
}
.interruptor span {
  display: flex; align-items: center; gap: .6rem;
  padding: .7rem 1.1rem .7rem .9rem;
  border: 1px solid var(--line-strong);
  border-radius: 9px;
  background: linear-gradient(180deg, var(--bg-elev-2), var(--bg-elev));
  box-shadow: 0 2px 0 rgba(0, 0, 0, .4);
  color: var(--fg-muted);
  font-size: var(--step--1);
  transition: color .2s var(--ease), border-color .2s var(--ease),
              transform .12s var(--ease), box-shadow .12s var(--ease);
}
/* El piloto de cada interruptor. */
.interruptor span::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--line-strong);
  flex-shrink: 0;
  transition: background-color .2s var(--ease), box-shadow .2s var(--ease);
}
.interruptor input:hover + span { color: var(--fg); border-color: var(--fg-faint); }
/* Pulsado de verdad: el interruptor baja y pierde el resalte. */
.interruptor input:checked + span {
  color: var(--fg);
  border-color: var(--accent);
  transform: translateY(2px);
  box-shadow: none;
}
.interruptor input:checked + span::before {
  background: var(--accent);
  box-shadow: 0 0 9px var(--accent-glow);
}
.interruptor input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

/* --- Resumen del caso, siempre visible --- */

.caso__resumen {
  position: sticky;
  bottom: 1rem;
  margin-top: 1rem;
  padding: 1rem 1.2rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--bg-elev) 92%, transparent);
  backdrop-filter: blur(10px);
  font-family: var(--font-mono);
  font-size: .72rem;
  line-height: 1.7;
  color: var(--fg-muted);
}
.caso__resumen dt {
  display: inline;
  color: var(--fg-faint);
  letter-spacing: .1em;
  text-transform: uppercase;
  font-size: .64rem;
}
.caso__resumen dd { display: inline; margin: 0 0 0 .5rem; color: var(--fg); }
.caso__resumen div + div { margin-top: .1rem; }
.caso__resumen .pendiente { color: var(--fg-faint); }

.boton--solve { font-family: var(--font-mono); letter-spacing: .12em; }

/* --- Modo experto: la terminal --- */

.experto {
  margin-top: 2.5rem;
  border-top: 1px solid var(--line);
  padding-top: 1.5rem;
}
.experto__abrir {
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .12em;
  color: var(--fg-faint);
  background: none; border: 0; padding: 0;
  cursor: pointer;
}
.experto__abrir:hover { color: var(--accent); }
.experto__abrir::before { content: "› "; color: var(--accent); }

.terminal {
  margin-top: 1.25rem;
  background: #04140d;
  border: 1px solid rgba(47, 224, 143, .22);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  font-family: var(--font-mono);
  font-size: .74rem;
  line-height: 1.75;
  color: #2fe08f;
  max-height: 340px;
  overflow-y: auto;
}
.terminal[hidden] { display: none; }
.terminal__salida p { white-space: pre-wrap; word-break: break-word; }
.terminal__salida .tenue { color: rgba(47, 224, 143, .55); }
.terminal__salida .aviso { color: #ffd27a; }

.terminal__linea { display: flex; gap: .5rem; align-items: baseline; }
.terminal__linea::before { content: "gnv:~$"; color: rgba(47, 224, 143, .55); flex-shrink: 0; }
.terminal__entrada {
  flex: 1;
  background: none; border: 0; padding: 0;
  color: inherit; font: inherit;
  caret-color: #2fe08f;
}
.terminal__entrada:focus { outline: none; }

@media (max-width: 620px) {
  .interruptor span { padding: .6rem .85rem .6rem .75rem; }
  .caso__resumen { position: static; }
}

/* --- 20b. Selector de modo ------------------------------------------------
   La terminal escondida detrás de un enlace al final la encontraba casi
   nadie. Puesta arriba como una de dos opciones, se elige de verdad. */

.modos {
  display: flex;
  gap: .7rem;
  margin-bottom: 2rem;
}

.modo {
  flex: 1;
  display: grid;
  gap: .3rem;
  padding: .95rem 1.1rem;
  text-align: left;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--bg-elev-2), var(--bg-elev));
  box-shadow: 0 2px 0 rgba(0, 0, 0, .4);
  color: var(--fg-muted);
  cursor: pointer;
  font: inherit;
  transition: color .2s var(--ease), border-color .2s var(--ease),
              transform .12s var(--ease), box-shadow .12s var(--ease);
}
.modo:hover { color: var(--fg); border-color: var(--fg-faint); }

.modo__titulo {
  display: flex; align-items: center; gap: .55rem;
  font-family: var(--font-mono);
  font-size: .74rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: inherit;
}
/* Piloto, igual que en los interruptores del caso: el panel es uno solo. */
.modo__titulo::before {
  content: "";
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--line-strong);
  flex-shrink: 0;
  transition: background-color .2s var(--ease), box-shadow .2s var(--ease);
}
.modo small { font-size: var(--step--1); color: var(--fg-faint); line-height: 1.45; }

/* El modo activo se queda hundido: se ve cuál está puesto sin leer nada. */
.modo[aria-selected="true"] {
  color: var(--fg);
  border-color: var(--accent);
  transform: translateY(2px);
  box-shadow: none;
}
.modo[aria-selected="true"] .modo__titulo::before {
  background: var(--accent);
  box-shadow: 0 0 9px var(--accent-glow);
}
.modo[aria-selected="true"] small { color: var(--fg-muted); }

[role="tabpanel"][hidden] { display: none; }

/* En modo terminal la consola manda: más alto y sin nada que la acompañe. */
.terminal--principal { max-height: 62vh; min-height: 24rem; margin-top: 0; }

@media (max-width: 620px) {
  .modos { flex-direction: column; }
}

/* --- 20c. El hilo único y los canales al final ---------------------------- */

/* Una sola columna, y estrecha: dos columnas obligaban a decidir por dónde
   empezar a leer justo cuando el visitante ya se había decidido a escribir. */
.hilo { max-width: 780px; }

/* Los canales van al final, en fila: quien solo quiere mandar un correo no
   tiene que atravesar nada para encontrar la dirección. */
.canales {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr));
  gap: 0 2.5rem;
  margin-top: 1.5rem;
}
.canales .canal:first-of-type { border-top: 1px solid var(--line); }

@media (min-width: 760px) {
  /* En fila, el borde superior de cada uno hace de separador y el inferior
     sobra: si no, se ve una doble línea entre columnas. */
  .canales .canal { border-top: 1px solid var(--line); border-bottom: 0; }
}

/* --- 20e. Elegir modo tiene que sentirse -----------------------------------
   Tres mecanismos, y ninguno es decorativo:

   1. El indicador se DESLIZA de una pestaña a otra en vez de aparecer. El
      movimiento continuo es lo que hace que el cambio se lea como una
      decisión propia y no como un refresco de pantalla.
   2. El panel elegido entra escalonado. Ver cómo se monta lo que has pedido
      da la sensación de que algo se ha puesto en marcha por ti.
   3. La barra de avance y el botón que se arma. Es el efecto de gradiente de
      meta: lo que empuja a terminar no es el principio, es ver el final
      cerca. Por eso el botón no está encendido desde el minuto cero. */

.modos { position: relative; }

/* La barra vive en el contenedor, no en cada pestaña: así puede viajar. */
.modos::after {
  content: "";
  position: absolute;
  left: 0; bottom: -.55rem;
  height: 2px;
  width: calc((100% - (var(--modos) - 1) * .7rem) / var(--modos));
  background: linear-gradient(90deg, var(--accent), var(--dato));
  border-radius: 2px;
  transform: translateX(calc(var(--modo-i, 0) * (100% + .7rem)));
  transition: transform .42s cubic-bezier(.65, 0, .2, 1);
  box-shadow: 0 0 12px var(--accent-glow);
}

.modo[aria-selected="true"] { transition-duration: .18s; }

/* Entrada escalonada. La animación se relanza quitando y poniendo la clase,
   que es la forma de reiniciar una animación CSS sin duplicar reglas. */
.entra > * {
  animation: entraPaso .42s var(--ease) backwards;
  animation-delay: calc(var(--n, 0) * 55ms);
}
@keyframes entraPaso {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* --- Avance ---------------------------------------------------------------- */

.avance {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: .5rem 1rem;
  margin: 1.6rem 0 1rem;
}

.avance__pista {
  grid-column: 1 / -1;
  height: 3px;
  border-radius: 3px;
  background: var(--line);
  overflow: hidden;
}
.avance__barra {
  height: 100%;
  width: 100%;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--dato), var(--accent));
  transform-origin: left;
  transform: scaleX(var(--avance, 0));
  transition: transform .5s cubic-bezier(.2, .9, .25, 1);
}

.avance__texto {
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--fg-faint);
  transition: color .3s var(--ease);
}
.avance[data-completo] .avance__texto { color: var(--accent); }

.avance__cuenta {
  font-family: var(--font-mono);
  font-size: .72rem;
  color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
}

/* --- El botón se arma ------------------------------------------------------
   Apagado mientras falten respuestas, encendido cuando ya se puede enviar.
   El contraste entre los dos estados es el que hace que apetezca llegar. */

.boton--solve:not([data-listo]) {
  opacity: .55;
  filter: saturate(.35);
}
.boton--solve {
  transition: opacity .35s var(--ease), filter .35s var(--ease),
              transform .18s var(--ease), box-shadow .35s var(--ease);
}
.boton--solve[data-listo] {
  animation: armado .5s var(--ease);
}
@keyframes armado {
  0%   { transform: scale(1); box-shadow: 0 0 0 0 var(--accent-glow); }
  45%  { transform: scale(1.035); box-shadow: 0 0 0 10px transparent; }
  100% { transform: scale(1); box-shadow: 0 0 0 0 transparent; }
}
/* Latido lento en reposo: recuerda que está listo sin llegar a molestar. */
.boton--solve[data-listo] .flecha { animation: empuja 2.6s var(--ease) infinite; }
@keyframes empuja {
  0%, 62%, 100% { transform: translateX(0); }
  74%           { transform: translateX(4px); }
}

/* --- Quién contesta --------------------------------------------------------
   Lo que frena a la gente antes de enviar no es la pereza, es no saber si
   alguien lo va a leer. Decirlo cuesta una línea. */

.firma-envio {
  display: flex;
  align-items: center;
  gap: .55rem;
  margin-top: .9rem;
  font-size: var(--step--1);
  color: var(--fg-muted);
}
.firma-envio::before {
  content: "";
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
  animation: pulso 2.4s var(--ease) infinite;
}
@keyframes pulso {
  0%, 100% { box-shadow: 0 0 0 0 var(--accent-glow); opacity: 1; }
  50%      { box-shadow: 0 0 0 6px transparent; opacity: .6; }
}

@media (prefers-reduced-motion: reduce) {
  .modos::after,
  .avance__barra { transition: none; }
  .entra > *,
  .boton--solve[data-listo],
  .boton--solve[data-listo] .flecha,
  .firma-envio::before { animation: none; }
}

/* --- 21. Visor 3D de proyectos ---------------------------------------------
   Un proyecto de ingeniería en una foto se queda en una foto. Lo que lo
   explica es poder girarlo y, sobre todo, poder APAGAR capas: enseñar una
   fila de racks es un dibujo, poder quitarle el mapa térmico y ver la
   geometría debajo ya es ingeniería. */

.visor {
  display: grid;
  gap: 1rem;
  margin-top: 2rem;
}

.visor__modelos { display: flex; flex-wrap: wrap; gap: .5rem; }

.visor__modelo {
  padding: .45rem .9rem;
  border: 1px solid var(--line-strong);
  border-radius: 100px;
  background: var(--bg-elev);
  color: var(--fg-muted);
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .2s var(--ease), border-color .2s var(--ease),
              background-color .2s var(--ease);
}
.visor__modelo:hover { color: var(--fg); border-color: var(--fg-faint); }
.visor__modelo[aria-pressed="true"] {
  color: var(--bg);
  background: var(--accent);
  border-color: var(--accent);
}

.visor__escena {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background:
    radial-gradient(120% 90% at 50% 0%, var(--bg-elev-2), var(--bg-elev) 70%);
  overflow: hidden;
}
.visor__escena canvas {
  display: block;
  width: 100%;
  height: clamp(280px, 52vh, 520px);
  touch-action: pan-y;   /* el gesto vertical sigue siendo scroll de la página */
}
.visor__escena canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.visor__ayuda {
  position: absolute;
  left: .9rem; bottom: .8rem;
  margin: 0;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .06em;
  color: var(--fg-faint);
  pointer-events: none;
}

/* Solo se ve si el visor declara que no hay WebGL. */
.visor__caida { display: none; }
[data-estado="sin-webgl"] .visor__caida {
  display: block;
  margin: 0;
  padding: 2.5rem 1.5rem;
  text-align: center;
  color: var(--fg-muted);
}
[data-estado="sin-webgl"] .visor__escena canvas,
[data-estado="sin-webgl"] .visor__ayuda { display: none; }

.visor__panel {
  display: grid;
  gap: .7rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-elev);
}
.visor__rotulo {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fg-faint);
}
.visor__capas { display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; }
.visor__aviso { margin: 0; font-size: var(--step--1); color: var(--fg-faint); }

/* En pantalla ancha, controles al lado y no debajo: así se ve el efecto de
   apagar una capa sin perder de vista el modelo. */
@media (min-width: 900px) {
  .visor {
    grid-template-columns: 1fr 15rem;
    grid-template-areas: "modelos modelos" "escena panel";
  }
  .visor__modelos { grid-area: modelos; }
  .visor__escena  { grid-area: escena; }
  .visor__panel   { grid-area: panel; align-content: start; }
  .visor__capas   { display: grid; gap: .5rem; }
}

@media print { .visor { display: none; } }

/* --- 22. Portada de contacto -----------------------------------------------
   «Hablemos» y «¿tienes un proyecto?» los escribe todo el mundo: piden algo
   y no ofrecen nada. Aquí se invierte — lo primero que se lee es qué
   devuelves y cuándo, y hay dos puertas visibles desde el primer pantallazo,
   porque quien llega puede venir con un proyecto o con un puesto y no tiene
   por qué adivinar cuál de las dos es la suya. */

.portada-contacto { padding-bottom: 1rem; }

.portada-contacto__alto {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .8rem;
  margin-bottom: 1.2rem;
}

/* Piloto en verde: dice que hay alguien al otro lado sin tener que jurarlo. */
.chip-vivo {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  margin: 0;
  padding: .32rem .8rem .32rem .7rem;
  border: 1px solid var(--accent);
  border-radius: 100px;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--accent);
}
.chip-vivo::before {
  content: "";
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent);
  animation: pulso 2.4s var(--ease) infinite;
}

.portada-contacto__titulo {
  max-width: 18ch;
  font-size: clamp(2.4rem, 7vw, 4.4rem);
  line-height: 1.02;
  letter-spacing: -.03em;
  text-wrap: balance;
}
.portada-contacto__intro {
  max-width: 52ch;
  font-size: var(--step-1);
  color: var(--fg-muted);
}

/* --- Rotador de casos ------------------------------------------------------
   Nadie escribe porque le digas «hablemos»: escribe cuando ve su propio
   problema escrito por otro. Sin JS queda la lista entera, que se lee igual
   de bien; con JS se turna una sola línea. */

.rotador {
  margin: 2rem 0 2.4rem;
  padding-left: 1rem;
  border-left: 2px solid var(--accent);
}
.rotador__rotulo {
  margin: 0 0 .35rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fg-faint);
}
.rotador__lista {
  margin: 0;
  padding-left: 1.1rem;
  color: var(--fg);
  font-size: var(--step-1);
}
.rotador__lista li { margin: .15rem 0; }

/* Con JS: la lista se vuelve una ventana de una línea y las de dentro se
   turnan. La altura se fija en el propio elemento para que no salte. */
.rotador[data-activo] .rotador__lista {
  position: relative;
  list-style: none;
  padding-left: 0;
  overflow: hidden;
}
.rotador[data-activo] .rotador__lista li {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  transform: translateY(.55em);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.rotador[data-activo] .rotador__lista li[data-visible] {
  position: relative;
  opacity: 1;
  transform: none;
}
.rotador[data-activo] .rotador__lista li::before {
  content: "\201C";
  color: var(--accent);
}
.rotador[data-activo] .rotador__lista li::after {
  content: "\201D";
  color: var(--accent);
}

/* --- Las dos puertas -------------------------------------------------------
   Numeradas y del mismo tamaño: ninguna de las dos es la de servicio. */

.puertas {
  display: grid;
  gap: 1rem;
  margin-bottom: 1.6rem;
}
@media (min-width: 720px) { .puertas { grid-template-columns: 1fr 1fr; } }

.puerta {
  position: relative;
  display: grid;
  gap: .45rem;
  padding: 1.5rem 1.4rem 1.3rem;
  text-align: left;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--bg-elev-2), var(--bg-elev));
  color: var(--fg);
  cursor: pointer;
  font: inherit;
  overflow: hidden;
  transition: border-color .25s var(--ease), transform .25s var(--ease),
              box-shadow .25s var(--ease);
}
/* Barra que se llena de izquierda a derecha al pasar por encima: el gesto
   dice «esto se abre» antes de que haya que leer el botón. */
.puerta::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--dato));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .45s cubic-bezier(.65, 0, .2, 1);
}
.puerta:hover, .puerta:focus-visible {
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: 0 12px 30px -18px var(--accent-glow);
}
.puerta:hover::after, .puerta:focus-visible::after { transform: scaleX(1); }

.puerta__n {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .18em;
  color: var(--fg-faint);
}
.puerta__r {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.15;
  letter-spacing: -.02em;
}
.puerta__d { color: var(--fg-muted); font-size: var(--step--1); line-height: 1.5; }
.puerta__g {
  margin-top: .3rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .05em;
  color: var(--accent);
}
.puerta__b {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  margin-top: .7rem;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fg);
}
.puerta:hover .puerta__b .flecha { transform: translateX(4px); }
.puerta__b .flecha { transition: transform .25s var(--ease); }

/* --- Selectividad ----------------------------------------------------------
   Decir que no se coge todo es lo que hace que valga la pena entrar. Va en
   pequeño y al final, porque dicho a gritos suena a otra cosa. */

.exclusiva {
  max-width: 62ch;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
  font-size: var(--step--1);
  color: var(--fg-muted);
}

@media (prefers-reduced-motion: reduce) {
  .chip-vivo::before { animation: none; }
  .puerta, .puerta::after,
  .rotador[data-activo] .rotador__lista li { transition: none; }
}

/* --- 23. Triaje ------------------------------------------------------------
   La web estaba escrita para empresas con un proyecto. Quien viene a
   contratar aterrizaba en una propuesta comercial y tenia que deducir por su
   cuenta donde estaba lo suyo. Esto lo pregunta directamente y lleva a cada
   uno a lo que le sirve, sin partir el sitio en dos webs distintas. */

.seccion--triaje { padding-top: 3rem; padding-bottom: 3rem; }

.triaje__pregunta {
  font-size: clamp(1.7rem, 4vw, 2.6rem);
  letter-spacing: -.025em;
  margin-bottom: 1.6rem;
}

.vias {
  display: grid;
  gap: .8rem;
  margin-bottom: 1.2rem;
}
@media (min-width: 860px) { .vias { grid-template-columns: repeat(3, 1fr); } }

.via {
  position: relative;
  display: grid;
  gap: .35rem;
  align-content: start;
  padding: 1.2rem 1.2rem 1.1rem;
  text-align: left;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--bg-elev-2), var(--bg-elev));
  color: var(--fg-muted);
  cursor: pointer;
  font: inherit;
  overflow: hidden;
  transition: color .2s var(--ease), border-color .2s var(--ease),
              transform .2s var(--ease);
}
.via:hover { color: var(--fg); border-color: var(--fg-faint); transform: translateY(-2px); }

.via__n {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .18em;
  color: var(--fg-faint);
}
.via__t {
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.2;
  letter-spacing: -.015em;
  color: var(--fg);
}
.via__d { font-size: var(--step--1); line-height: 1.5; }

.via[aria-selected="true"] {
  color: var(--fg);
  border-color: var(--accent);
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 7%, var(--bg-elev-2)), var(--bg-elev));
}
.via[aria-selected="true"] .via__n { color: var(--accent); }

/* Barra que baja por el borde izquierdo hasta la respuesta: el ojo sigue el
   trazo y encuentra solo lo que se acaba de abrir. */
.via::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: linear-gradient(180deg, var(--accent), var(--dato));
  transform: scaleY(0);
  transform-origin: top;
  transition: transform .4s cubic-bezier(.65, 0, .2, 1);
}
.via[aria-selected="true"]::before { transform: scaleY(1); }

/* Mientras no se ha elegido nada, un barrido recorre las tres por turno.
   Es lo unico que se mueve en esa franja, asi que el ojo va ahi. Se apaga
   en cuanto alguien toca una: ya ha cumplido. */
.vias:not([data-tocado]) .via { animation: barrido 6s var(--ease) infinite; }
.vias:not([data-tocado]) .via:nth-child(2) { animation-delay: .5s; }
.vias:not([data-tocado]) .via:nth-child(3) { animation-delay: 1s; }
@keyframes barrido {
  0%, 22%, 100% { border-color: var(--line-strong); }
  8%            { border-color: var(--accent); }
}

/* --- Respuesta -------------------------------------------------------------- */

.respuesta {
  display: grid;
  gap: 1rem;
  padding: 1.4rem 1.4rem 1.5rem;
  border: 1px solid var(--line);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius);
  background: var(--bg-elev);
}
.respuesta__texto {
  max-width: 70ch;
  margin: 0;
  font-size: var(--step-1);
  color: var(--fg);
  text-wrap: pretty;
}
.respuesta__acciones { display: flex; flex-wrap: wrap; gap: .7rem; }

/* Al cambiar de via, el texto entra desde abajo: se nota que ha cambiado
   aunque no se haya leido todavia. */
.respuesta[data-cambiando] .respuesta__texto { animation: entraRespuesta .4s var(--ease); }
@keyframes entraRespuesta {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

.triaje__pie {
  max-width: 62ch;
  margin-top: 1.1rem;
  font-size: var(--step--1);
  color: var(--fg-muted);
}

@media (prefers-reduced-motion: reduce) {
  .vias:not([data-tocado]) .via,
  .respuesta[data-cambiando] .respuesta__texto { animation: none; }
  .via, .via::before { transition: none; }
}

@media print { .seccion--triaje { display: none; } }

/* --- 24. Que la tarjeta se ofrezca -----------------------------------------
   Un rectangulo plano se lee como decoracion. Para que se lea como pulsable
   hay que darle las senales que el ojo asocia a un objeto fisico, y son
   siempre las mismas:

   1. PROFUNDIDAD. Lo que proyecta sombra esta por encima del papel, y lo que
      esta por encima se puede empujar. Sin sombra no hay nada que empujar.
   2. INCLINACION HACIA EL CURSOR. La esquina mas cercana al puntero sale
      hacia fuera. Es lo que convierte «hay una tarjeta» en «tengo una tarjeta
      en la mano».
   3. FOCO QUE SIGUE AL PUNTERO. Una luz que persigue al cursor dice «esto me
      esta respondiendo a mi» antes de que haya que leer nada.
   4. FLECHA QUE ENTRA. Algo que aparece a medias pide cerrarse. Es el mismo
      resorte que hace terminar una lista empezada.
   5. SOBREIMPULSO AL SALIR. Un movimiento que se pasa un poco y vuelve se
      lee como vivo; uno lineal, como una animacion.
   6. HUNDIRSE AL PULSAR. Sin esto el clic no se siente, y lo que no se
      siente no se repite.
   7. RESPIRACION EN REPOSO. En tactil no hay puntero, asi que la senal tiene
      que salir de la tarjeta sola.

   El truco de todo esto es la dosis: cada mecanismo por separado es casi
   imperceptible, y juntos la tarjeta pide el clic sin llamar la atencion. */

.vias, .puertas { perspective: 1000px; }

.via, .puerta {
  transform-style: preserve-3d;
  will-change: transform;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .35);
  transition:
    transform .45s cubic-bezier(.34, 1.4, .64, 1),
    box-shadow .35s var(--ease),
    border-color .25s var(--ease),
    color .2s var(--ease);
}

/* Solo donde hay puntero de verdad. En un movil, inclinar hacia el dedo no
   significa nada y ademas se queda pegado despues de tocar. */
@media (hover: hover) and (pointer: fine) {
  .via:hover, .puerta:hover,
  .via:focus-visible, .puerta:focus-visible {
    transform:
      rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg))
      translateY(-7px) scale(1.012);
    box-shadow:
      0 26px 50px -26px rgba(0, 0, 0, .8),
      0 0 0 1px var(--accent-glow);
    border-color: var(--accent);
  }
}

/* Hundirse al pulsar, y rapido: la respuesta tactil solo funciona si llega
   antes de que el dedo se levante. */
.via:active, .puerta:active {
  transform: translateY(-1px) scale(.994);
  transition-duration: .07s;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .4);
}

/* --- El foco que sigue al puntero ------------------------------------------
   .via ya usa ::before para la barra lateral y .puerta usa ::after para la
   barra inferior, asi que cada una coge el que le queda libre. */

.via::after, .puerta::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in srgb, var(--accent) 13%, transparent), transparent 68%);
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s var(--ease);
}
.via:hover::after, .via:focus-visible::after,
.puerta:hover::before, .puerta:focus-visible::before { opacity: 1; }

/* --- La flecha que entra ---------------------------------------------------- */

.via {
  grid-template-columns: 1fr auto;
}
/* Posicion explicita para las cuatro: la flecha va en medio del marcado y
   con colocacion automatica el resultado dependeria de ese orden. */
.via__n  { grid-column: 1; grid-row: 1; }
.via__ir { grid-column: 2; grid-row: 1; }
.via__t  { grid-column: 1 / -1; grid-row: 2; }
.via__d  { grid-column: 1 / -1; grid-row: 3; }

.via__ir {
  align-self: start;
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  margin: -.35rem -.35rem 0 0;
  border-radius: 50%;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  opacity: 0;
  transform: translateX(-8px) scale(.85);
  transition: opacity .32s var(--ease),
              transform .45s cubic-bezier(.34, 1.5, .64, 1);
}
.via:hover .via__ir, .via:focus-visible .via__ir,
.via[aria-selected="true"] .via__ir {
  opacity: 1;
  transform: none;
}
.via[aria-selected="true"] .via__ir {
  color: var(--bg);
  background: var(--accent);
}

/* --- Respiracion en reposo ---------------------------------------------------
   Sustituye al barrido de borde que habia antes: aquel solo cambiaba un
   color, y un color que cambia no dice «pulsame». Un objeto que sube un poco
   y baja, si. Se apaga en cuanto alguien toca una. */

.vias:not([data-tocado]) .via { animation: respira 5.5s var(--ease) infinite; }
.vias:not([data-tocado]) .via:nth-child(2) { animation-delay: .45s; }
.vias:not([data-tocado]) .via:nth-child(3) { animation-delay: .9s; }
@keyframes respira {
  0%, 26%, 100% {
    transform: none;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .35);
    border-color: var(--line-strong);
  }
  11% {
    transform: translateY(-4px);
    box-shadow: 0 16px 30px -20px rgba(0, 0, 0, .7);
    border-color: var(--accent);
  }
}
/* El hover manda sobre la respiracion: si no, la tarjeta sigue subiendo y
   bajando con el cursor encima y parece que se ha soltado. */
@media (hover: hover) and (pointer: fine) {
  .vias:not([data-tocado]) .via:hover { animation: none; }
}

@media (prefers-reduced-motion: reduce) {
  .via, .puerta { transition: border-color .2s var(--ease), color .2s var(--ease); }
  .via:hover, .puerta:hover, .via:active, .puerta:active { transform: none; }
  .vias:not([data-tocado]) .via { animation: none; }
  .via__ir { transition: opacity .2s var(--ease); transform: none; }
}

/* --- 25. Diagnostico -------------------------------------------------------
   Nadie contrata a quien le dice que tiene un problema. Se contrata a quien
   describe el problema con tanta precision que uno se reconoce solo. Por eso
   aqui no hay ni una frase en primera persona vendiendo nada: hay cinco
   frases dichas por otros, lo que resulto ser cada vez, y lo que se hizo.

   Tres reglas de composicion, y las tres importan:

   - La cita manda visualmente. Es lo unico grande, y es lo unico que el
     lector puede reconocer como suyo. Si lo demas compite, se pierde.
   - Lo que se hizo va en el mismo bloque, sin boton ni promesa. En cuanto
     aparece una llamada a la accion, deja de ser un diagnostico y pasa a ser
     un anuncio, y ahi es donde la gente se va.
   - La vuelta entra despues que la cita. El orden es el argumento: primero
     te reconoces, y solo despues llega el giro. */

.seccion--sintomas { padding-bottom: 1rem; }

.sintomas {
  display: grid;
  gap: 0;
  margin-top: 2.4rem;
}

.sintoma {
  display: grid;
  gap: 1rem;
  padding: 2.2rem 0;
  border-top: 1px solid var(--line);
}
.sintoma:last-child { border-bottom: 1px solid var(--line); }

/* La cita: grande, en la tipografia de titulares y con la comilla colgada
   fuera del margen, como en un libro. Es lo primero que se lee y tiene que
   sonar a alguien hablando, no a un titular de seccion. */
.sintoma__frase {
  position: relative;
  max-width: 24ch;
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 3.2vw, 2.05rem);
  line-height: 1.18;
  letter-spacing: -.02em;
  color: var(--fg);
  text-wrap: balance;
}
.sintoma__frase::before {
  content: "\201C";
  position: absolute;
  right: 100%;
  margin-right: .12em;
  color: var(--accent);
}
.sintoma__frase::after { content: "\201D"; color: var(--accent); }

.sintoma__rotulo {
  margin: 0 0 .3rem;
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--fg-faint);
}
.sintoma__texto {
  margin: 0;
  color: var(--fg-muted);
  line-height: 1.6;
  text-wrap: pretty;
}

/* Lo que se hizo lleva el filo de acento. Es la unica marca de color de todo
   el bloque, y senala el hecho, no la oferta. */
.sintoma__hecho {
  padding-left: 1rem;
  border-left: 2px solid var(--accent);
}
.sintoma__hecho .sintoma__texto { color: var(--fg); }

.sintoma__ver {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin-top: .6rem;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--fg-muted);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
.sintoma__ver:hover { color: var(--accent); border-color: var(--accent); }
.sintoma__ver svg { transition: transform .25s var(--ease); }
.sintoma__ver:hover svg { transform: translateX(3px); }

/* En ancho, la cita ocupa su propia columna a la izquierda y las dos vueltas
   van al lado. Asi la cita se lee de un golpe y el giro llega a su derecha,
   que es el orden en que se lee. */
@media (min-width: 900px) {
  .sintoma {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) minmax(0, 1.15fr);
    gap: 2rem;
    align-items: start;
  }
  .sintoma__frase { max-width: none; }
}

/* El giro entra despues de la cita: primero te reconoces, luego llega la
   vuelta. Medio segundo de diferencia basta para que se lea en ese orden. */
.sintoma.es-visible .sintoma__vuelta { animation: entraGiro .5s var(--ease) .12s backwards; }
.sintoma.es-visible .sintoma__hecho  { animation: entraGiro .5s var(--ease) .26s backwards; }
@keyframes entraGiro {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

.sintomas__cierre {
  max-width: 60ch;
  margin-top: 2rem;
  font-size: var(--step-1);
  color: var(--fg);
  text-wrap: pretty;
}

@media (prefers-reduced-motion: reduce) {
  .sintoma.es-visible .sintoma__vuelta,
  .sintoma.es-visible .sintoma__hecho { animation: none; }
}

@media print { .seccion--sintomas { display: none; } }

/* El enlace nombra su caso: cinco "Ver el caso" iguales no se escanean, y un
   lector de pantalla que los lee en fila no distingue ninguno. */
.sintoma__nombre {
  color: var(--fg);
  text-transform: none;
  letter-spacing: .02em;
}
.sintoma__ver:hover .sintoma__nombre { color: var(--accent); }

/* --- 26. Herramientas ------------------------------------------------------
   Curado, no exhaustivo. Un Head of AI que declara "Microsoft Office" al lado
   de Kubernetes se lee como junior: el ojo del reclutador promedia hacia
   abajo, no hacia arriba. Y publicar una puntuacion baja solo invita a la
   pregunta que no conviene.

   Sin escala de puntos a proposito. Cada grupo va ordenado de mas a menos
   dominio, asi que el nivel se transmite por el orden, y nadie puede
   discutir un numero que no esta escrito. */

.utiles {
  display: grid;
  gap: 1.6rem;
  margin-top: 2.2rem;
}
@media (min-width: 800px) { .utiles { grid-template-columns: 1fr 1fr; } }

.util__nombre {
  margin: 0 0 .7rem;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--fg-faint);
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--line);
}

/* Sin JS queda la linea separada por puntos, que se lee igual de bien. */
.util__lista {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin: 0;
  color: var(--fg-muted);
  line-height: 1.7;
}

.chip {
  padding: .22rem .6rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: var(--bg-elev-2);
  font-size: var(--step--1);
  color: var(--fg-muted);
  white-space: nowrap;
  transition: color .18s var(--ease), border-color .18s var(--ease);
}
.chip:hover { color: var(--fg); border-color: var(--accent); }

/* La primera de cada grupo es la de mas dominio: se marca sola. */
.chip:first-child {
  color: var(--fg);
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 7%, var(--bg-elev-2));
}

/* --- 27. La credencial que sostiene el giro --------------------------------
   El posgrado de la UPC School con Schneider Electric es lo que respalda el
   movimiento hacia infraestructura critica, y en una hoja que se lee en diez
   segundos lo que no destaca no se lee.

   Las dos instituciones van en tratamiento tipografico, no con sus logos.
   Los logos de la UPC y de Schneider son marcas registradas: usarlos en una
   web personal sugiere respaldo o vinculo comercial, y Schneider ademas es
   colaboradora del programa, no la entidad que titula. Puesto asi se lee con
   la misma fuerza y no depende del permiso de nadie. */

.hoja__entrada--sello {
  padding: .55rem .75rem;
  border-left: 2px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 5%, transparent);
}

.sello {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--accent);
}

@media print {
  /* En papel el color de fondo se pierde en muchas impresoras: el filo basta. */
  .hoja__entrada--sello { background: none; border-left: 1.5pt solid #000; }
  .sello { color: #000; }
}

/* --- 28. Credenciales ------------------------------------------------------
   Hasta ahora la formacion solo existia dentro de la hoja del CV, que es un
   elemento grafico: quien no le da a imprimir no la lee nunca. Un reclutador
   de datacenters mira dos cosas, la experiencia y el sello, y el sello no
   estaba a la vista.

   Las que llevan filo de acento son las que dicen hacia donde va, no las mas
   antiguas ni las mas dificiles: el posgrado con Schneider y las dos de
   NVIDIA. Marcar tres de diez es lo que hace que se lean; marcarlas todas
   seria no marcar ninguna. */

.credenciales {
  display: grid;
  gap: 2rem;
  margin-top: 2.2rem;
}
@media (min-width: 860px) { .credenciales { grid-template-columns: 1fr 1fr; } }

.credencial__lista { margin: 0; padding: 0; list-style: none; }

.credencial {
  display: grid;
  gap: .12rem;
  padding: .85rem 0;
  border-bottom: 1px solid var(--line);
}
.credencial:last-child { border-bottom: 0; }

.credencial--sello {
  padding-left: .9rem;
  border-left: 2px solid var(--accent);
}

.credencial__t { color: var(--fg); line-height: 1.35; text-wrap: pretty; }
.credencial__c {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.credencial--sello .credencial__c { color: var(--accent); }
.credencial__p {
  font-family: var(--font-mono);
  font-size: .68rem;
  color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
}
/* Sin fecha no debe quedar un hueco: alguna esta pendiente de confirmar. */
.credencial__p:empty { display: none; }

.credenciales__carnets {
  margin-top: 2rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
  font-size: var(--step--1);
  color: var(--fg-muted);
}
.credenciales__carnets b {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-right: .5rem;
}

@media print { #credenciales { display: none; } }

/* --- 29. Ponencia ----------------------------------------------------------
   Va a lo ancho y con su propio filo, no como una linea mas de una lista.
   Una ponencia en congreso es de lo poco que distingue un CV de otro: alguien
   te puso en un escenario delante de su gremio. Eso no se cuenta en una
   linea de siete palabras. */

.ponencia {
  grid-column: 1 / -1;
  margin-top: 2rem;
  padding: 1.3rem 1.4rem;
  border: 1px solid var(--line);
  border-left: 2px solid var(--dato);
  border-radius: var(--radius);
  background: var(--bg-elev);
}
.ponencia__t {
  margin: 0 0 .25rem;
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.25;
  letter-spacing: -.015em;
  color: var(--fg);
}
.ponencia__c {
  margin: 0 0 .8rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--dato);
}
.ponencia__d {
  max-width: 78ch;
  margin: 0;
  color: var(--fg-muted);
  line-height: 1.6;
  text-wrap: pretty;
}

/* --- 30. Detalle de cada herramienta ---------------------------------------
   Una lista de nombres dice que los conoces. Poder abrir cualquiera y leer
   donde la usaste dice que has trabajado con ella, que no es lo mismo y es
   justo lo que un entrevistador quiere saber.

   Solo se abren las que tienen algo que contar. Las demas se quedan como
   etiqueta: una ficha que invita al clic y luego no dice nada defrauda mas
   que una que nunca lo invito. */

.utiles__pie {
  margin: .4rem 0 0;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .06em;
  color: var(--fg-faint);
}

.chip--abre {
  font-family: inherit;
  cursor: pointer;
  position: relative;
  padding-right: 1.5rem;
}
/* Cruz girada 45 grados: mas es cerrado, x es abierto, y la rotacion hace de
   transicion entre los dos estados sin cambiar de simbolo. */
.chip--abre::after {
  content: "+";
  position: absolute;
  right: .55rem; top: 50%;
  transform: translateY(-50%);
  color: var(--accent);
  transition: transform .3s var(--ease);
}
.chip--abre[aria-expanded="true"] {
  color: var(--bg);
  background: var(--accent);
  border-color: var(--accent);
}
.chip--abre[aria-expanded="true"]::after {
  color: var(--bg);
  transform: translateY(-50%) rotate(45deg);
}

/* El panel se mete dentro del grupo de la ficha pulsada, asi que su margen
   lo separa de la lista de arriba y no de la seccion entera. */
.util__detalle {
  margin-top: 1.1rem;
  padding: 1.2rem 1.3rem;
  border: 1px solid var(--line);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius);
  background: var(--bg-elev);
}
.util__detalle[data-entra] { animation: entraDetalle .35s var(--ease); }
@keyframes entraDetalle {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
.util__detalle-n {
  margin: 0 0 .3rem;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent);
}
.util__detalle-t {
  max-width: 72ch;
  margin: 0;
  color: var(--fg);
  line-height: 1.6;
  text-wrap: pretty;
}

@media (prefers-reduced-motion: reduce) {
  .chip--abre::after, .util__detalle[data-entra] { animation: none; transition: none; }
}

/* Dentro del grupo el panel hereda su ancho de columna, que es justo lo que
   lo ata visualmente a las fichas de las que ha salido. */
.util .util__detalle { margin-left: 0; margin-right: 0; }

/* Fuera de un grupo (estado inicial del marcado) no debe verse. */
.utiles + .util__detalle[hidden] { display: none; }

/* Una credencial puede traer su porque. Solo lo llevan las que lo necesitan:
   un grado en psicologia dentro de un CV de ingenieria parece un desvio hasta
   que se lee por que no lo es. */
.credencial__d {
  margin-top: .45rem;
  max-width: 62ch;
  color: var(--fg-muted);
  font-size: var(--step--1);
  line-height: 1.6;
  text-wrap: pretty;
}

/* El proyecto en curso usa el molde de la ponencia pero con el acento verde:
   aquella es algo que ya paso, este es algo que esta pasando. */
.ponencia--comunidad { border-left-color: var(--dato); margin-top: 2rem; }
.ponencia--comunidad .ponencia__c { color: var(--dato); }

.ponencia--curso { border-left-color: var(--accent); margin-top: 2rem; }
.ponencia--curso .ponencia__c { color: var(--accent); }

/* --- 18e. La impresora en pantalla ancha -----------------------------------
   El techo es una suma: impresora mas folio no pueden pasar de la altura de
   la ventana, o la maquina sale cortada por arriba. Con los mandos apilados,
   el cuerpo se comia 265 px de esa suma y el folio se quedaba con lo que
   sobraba.

   En pantalla ancha hay ancho de sobra y no hay altura, asi que los mandos se
   ponen en fila. El cuerpo baja a poco mas de la mitad y todo lo que suelta
   se lo lleva el papel. Es tambien lo que hace una impresora grande de
   verdad: los controles al lado, no encima. */

@media (min-width: 1100px) {
  /* En pantalla grande el aire de la seccion sobra: cada pixel de relleno
     es un pixel que le falta al folio. */
  .cv__fijo { padding-block: .6rem; }

  .cv {
    /* Con el cuerpo aplanado sobra ancho: el voladizo puede crecer mas. */
    --margen-bandeja: clamp(2rem, 5vw, 8rem);
  }

  .impresora {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 1.2rem;
    padding: .5rem 1.4rem .45rem;
  }

  /* La marca en vertical, ocupando el alto en vez del ancho. */
  .impresora__marca {
    margin: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: .25rem;
    white-space: nowrap;
  }

  .lcd { margin: 0; }

  .impresora__teclas { margin: 0; }

  /* La ranura cruza los tres, pegada al borde por donde sale el papel. */
  .impresora__ranura { grid-column: 1 / -1; margin-top: .55rem; }
}

/* Muy ancha y no muy alta: el caso de un monitor apaisado, que es donde peor
   se veia. Se aprieta aun mas para que el folio se lleve casi todo. */
@media (min-width: 1500px) and (max-height: 1100px) {
  .cv { --margen-bandeja: clamp(3rem, 6.5vw, 11rem); }
  .impresora { padding: .45rem 1.8rem .4rem; gap: 1.8rem; }
}

/* --- 18g. Chasis a la medida de la pantalla --------------------------------
   Hasta aqui el chasis salia del folio: ancho del papel mas un voladizo. Con
   un A4 vertical eso topa enseguida, porque el folio es estrecho por
   definicion y el trasto se quedaba en un tercio de un monitor ancho.

   A partir de cierto tamano se invierte la relacion: el ANCHO LO PONE LA
   PANTALLA y el papel sale por el centro de una bandeja ancha. Es lo que hace
   una impresora grande de verdad, que mide bastante mas que el folio que
   traga, y ademas es lo unico que llena el hueco sin deformar el documento.

   Sigue siendo dinamico: es un porcentaje del ancho de ventana con un tope,
   asi que crece y encoge con la ventana sin escalones. */

@media (min-width: 1100px) {
  .cv {
    /* Atado al folio y no solo a la pantalla. Una impresora de verdad mide
       entre vez y media y dos veces el ancho del papel; a dos veces y media
       el folio parece un sello en medio de una plancha, que es justo lo que
       hacia que se viera pequeno aunque midiera lo mismo. */
    --ancho-chasis: min(74vw, 1250px, calc(var(--ancho-hoja) * 1.7));
  }
  /* La bandeja acompana al chasis: si no, el papel saldria de un hueco
     estrecho en medio de una maquina ancha. */
  .cv__ventana { width: var(--ancho-chasis); }

  /* El cabezal y el carro barren el ANCHO DEL PAPEL, no el de la bandeja: lo
     que se imprime es el folio, y verlos pasearse por la chapa de al lado
     rompe el efecto entero. */
  .cv__cabezal {
    left: calc(50% - var(--ancho-hoja) / 2);
    right: calc(50% - var(--ancho-hoja) / 2);
  }
  .cv__carro {
    left: calc(50% - var(--ancho-hoja) / 2
               + var(--carro, 0) * (var(--ancho-hoja) - 38px));
  }

  /* La mesa tiene que seguir siendo mas ancha que la maquina que sostiene. */
  .cv__mesa { width: min(1700px, 97vw); }
}

@media (min-width: 1700px) {
  .cv { --ancho-chasis: min(70vw, 1420px, calc(var(--ancho-hoja) * 1.7)); }
}

/* --- 18h. El folio manda sobre el ancho, no sobre el alto -------------------
   Aqui estaba el error de fondo, y no era de pixeles sino de concepto.

   Hasta ahora la hoja entera tenia que caber en la pantalla. Con proporcion
   A4 eso significa que el ANCHO lo decide el alto disponible: alto entre
   1,414. Por eso, por mucho que se agrandara todo, el documento salia estrecho
   y con la letra minuscula. No habia forma de arreglarlo sin cambiar la regla.

   La regla nueva es la de una impresora de verdad: el ancho del papel es fijo
   y lo que no cabe todavia no ha salido. Asi que el ancho lo pone la pantalla,
   el alto sale de la proporcion A4 y la hoja es mas alta que la ventana. La
   bandeja ensena el trozo impreso, y el papel va bajando para que el frente
   de impresion siempre este a la vista.

   Resultado: el documento pasa a ser ancho y legible, que era justo lo que
   hacia falta para poder leerlo mientras sale. */

@media (min-width: 1100px) {
  .cv {
    /* El ancho manda. */
    --ancho-hoja: min(76vw, 1180px);
    --alto-hoja: calc(var(--ancho-hoja) * 1.414);

    /* Lo que se ve de la hoja: el hueco que deja la maquina. */
    --alto-ventana: max(340px, calc(100svh - var(--alto-impresora)));

    --ancho-chasis: calc(var(--ancho-hoja) + var(--margen-bandeja) * 2);
  }

  .cv__ventana {
    height: var(--alto-ventana);
    width: var(--ancho-chasis);
  }

  .hoja {
    width: var(--ancho-hoja);
    height: var(--alto-hoja);
    aspect-ratio: auto;
    /* El papel baja solo cuando el frente de impresion llega al borde de la
       bandeja. Antes de eso se queda quieto, como el papel de verdad, que no
       se mueve hasta que asoma. */
    transform: translateY(min(0px, calc(var(--alto-ventana) - var(--salida, 0) * var(--alto-hoja))));
  }

  /* El cabezal y el carro siguen al frente de impresion en coordenadas de la
     bandeja: mientras el papel no baja van con el, y cuando empieza a bajar
     se quedan clavados en el borde, que es donde de verdad esta el cabezal. */
  .cv__cabezal,
  .cv__carro {
    top: min(calc(var(--salida, 0) * var(--alto-hoja)), var(--alto-ventana));
  }

  /* Los margenes del folio en proporcion, no en rem: con la hoja a 1180 px un
     margen de 30 px se lee como si el texto se saliera del papel. */
  .hoja { padding: calc(var(--alto-hoja) * .034) calc(var(--ancho-hoja) * .068); }

  /* El recorrido de scroll es lo que decide a que velocidad "imprime". Con
     el factor anterior (.9) salian ~1,6 px de papel por pixel de scroll: el
     documento aparecia mas rapido de lo que se baja y parecia ya impreso.
     Con 2.4 salen ~0,4 px por pixel: imprimir un folio cuesta unas cuatro
     pantallas de scroll, se lee mientras sale y se nota el mecanismo. Quien
     no quiera pagar ese peaje tiene la tecla FEED. */
  .cv__pista { height: calc(100vh + var(--alto-hoja) * 2.4); }

  /* La hoja ya no cabe entera, asi que los dobleces no tienen donde caer. */
  .cv__pliegue { display: none; }
}

/* --- 30b. Pilares del proyecto en curso ------------------------------------
   Cuatro, y no es un numero decorativo: cada uno responde a una de las cuatro
   objeciones que pone una direccion antes de aprobar un sistema asi. Si
   quedaran en una lista de guiones se leerian como caracteristicas; en
   bloques con titulo se leen como respuestas. */

.pilares {
  display: grid;
  gap: 1.4rem;
  margin-top: 1.6rem;
}
@media (min-width: 820px) { .pilares { grid-template-columns: 1fr 1fr; gap: 1.6rem 2.4rem; } }

.pilar { padding-left: 1rem; border-left: 1px solid var(--line-strong); }
.pilar__t {
  margin: 0 0 .4rem;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent);
}
.pilar__x { margin: 0; color: var(--fg-muted); line-height: 1.6; text-wrap: pretty; }

.proyecto__cierre {
  max-width: 68ch;
  margin: 2rem 0 0;
  padding-left: 1rem;
  border-left: 2px solid var(--dato);
  font-size: var(--step-1);
  color: var(--fg);
  text-wrap: pretty;
}
.proyecto__aviso {
  margin: .9rem 0 0;
  font-size: var(--step--1);
  color: var(--fg-faint);
}

/* --- 31. Huella del CV descargable ---------------------------------------
   El PDF que genera cada visitante lleva estampada su propia IP y la fecha:
   discreta al pie, y en marca de agua tenue por si el pie se recorta. No se
   guarda nada en el servidor; la IP viaja de vuelta a su dueno y muere
   dentro de su copia. Aviso correspondiente en la politica de privacidad. */

.hoja__huella {
  margin-top: .4em;
  font-family: var(--font-mono);
  font-size: .72em;
  letter-spacing: .04em;
  color: #a9b6b0;
}
.hoja__huella:empty { display: none; }

.hoja__marcaagua { display: none; }

@media print {
  .hoja__marcaagua {
    display: grid;
    place-items: center;
    position: fixed;          /* fixed en imprenta: se repite en cada pagina */
    inset: 0;
    z-index: 5;
    pointer-events: none;
    transform: rotate(-32deg);
    font-family: var(--font-mono);
    font-size: 21pt;
    letter-spacing: .3em;
    white-space: nowrap;
    color: rgba(26, 36, 32, .05);
  }
  .hoja__marcaagua:empty { display: none; }
}

/* --- 32. Linea temporal ---------------------------------------------------
   Quien es y que ha hecho, en orden: formacion a la derecha (punto azul,
   --dato), trayectoria y empresas a la izquierda (punto verde, --accent).
   El peso visual sigue la importancia: grados y masteres grandes, el resto
   en su sitio. Lo que sigue activo lleva la marca que late. */

/* clip: los hitos esperan su reveal desplazados a un lado (--linea-dx)
   y en móvil ese transform asomaba por el borde y ensanchaba la página. */
.linea { margin-top: 3.5rem; overflow-x: clip; }

.linea__columnas {
  display: flex; justify-content: space-between;
  font-family: var(--font-mono);
  font-size: .68rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: 1.6rem;
}

.linea__lista { list-style: none; margin: 0; padding: 0; position: relative; }
.linea__lista::before {
  content: ''; position: absolute; top: 4px; bottom: 4px; left: 50%;
  width: 2px; margin-left: -1px;
  background: linear-gradient(to bottom, var(--line-strong), var(--line));
}

.linea__hito {
  position: relative;
  width: calc(50% - 3rem);
  padding: 1.05rem 1.25rem;
  margin: 0 0 1.25rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.linea__hito::before {
  content: ''; position: absolute; top: 1.3rem;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--bg); border: 2px solid var(--fg-faint);
}
.linea__hito--izq { margin-right: auto; text-align: right; }
.linea__hito--izq::before { right: -3rem; transform: translateX(50%); border-color: var(--accent); }
.linea__hito--der { margin-left: auto; }
.linea__hito--der::before { left: -3rem; transform: translateX(-50%); border-color: var(--dato); }

.linea__periodo {
  margin: 0 0 .3rem;
  font-family: var(--font-mono);
  font-size: .7rem; letter-spacing: .08em;
  color: var(--fg-faint);
  display: flex; align-items: center; gap: .55rem;
}
.linea__hito--izq .linea__periodo { justify-content: flex-end; }
.linea__periodo:empty { display: none; }

.linea__titulo { margin: 0; font-size: 1.02rem; font-weight: 650; letter-spacing: -.01em; }
.linea__texto { margin: .35rem 0 0; font-size: .9rem; line-height: 1.55; color: var(--fg-muted); }

.linea__hito--mayor { border-color: var(--line-strong); }
.linea__hito--mayor .linea__titulo { font-size: 1.18rem; }
.linea__hito--mayor::before { width: 13px; height: 13px; top: 1.25rem; }

.linea__hito--menor { padding: .7rem 1rem; }
.linea__hito--menor .linea__titulo { font-size: .9rem; }
.linea__hito--menor .linea__texto { font-size: .82rem; }
.linea__hito--menor::before { width: 8px; height: 8px; top: 1.05rem; }

.linea__sigue {
  display: inline-flex; align-items: center; gap: .35rem;
  font-size: .6rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-tint);
  padding: .18em .6em; border-radius: 100px;
}
.linea__sigue::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
  animation: linea-latido 2.4s var(--ease) infinite;
}
@keyframes linea-latido { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }

/* Cada lado entra desde el suyo. */
.linea__hito--izq { --linea-dx: -26px; }
.linea__hito--der { --linea-dx: 26px; }
.linea__hito.revelar { transform: translate(var(--linea-dx, 0), 14px); }
.linea__hito.revelar.es-visible { transform: none; }

@media (max-width: 819px) {
  .linea__columnas { display: none; }
  .linea__lista::before { left: 8px; }
  .linea__hito,
  .linea__hito--izq,
  .linea__hito--der { width: auto; margin: 0 0 1.05rem 2.1rem; text-align: left; --linea-dx: 18px; }
  .linea__hito--izq::before,
  .linea__hito--der::before { left: -2.1rem; right: auto; transform: translateX(-50%); }
  .linea__hito--izq .linea__periodo { justify-content: flex-start; }
}

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

/* --- 33. Logo oficial -----------------------------------------------------
   El logo real de Guillem, vectorizado 1:1 desde el PDF de Illustrator
   (trazados originales, sin redibujar) y con el nombre retirado. En la
   cabecera sigue el sello GNV, que a 34px lee mejor; el logo vive en el
   pie y en el membrete de la hoja del CV. currentColor: se adapta al tema. */

.logo-gnv { display: block; aspect-ratio: 269.8 / 148.6; }

.marca--logo { color: var(--fg); }
.marca--logo .logo-gnv { height: 44px; width: 80px; }
.marca--logo:hover { color: var(--accent); }

/* En la cabecera, el verde va solo en el simbolo: el texto no lo hereda. */
.cabecera .marca--logo { color: var(--fg); }
.cabecera .marca--logo .logo-gnv { height: 26px; width: 47px; color: var(--accent); }
.cabecera .marca--logo:hover .logo-gnv { color: var(--fg); }

/* En la hoja, medidas en em: el folio escala por tipografia. */
.hoja__marca { flex-shrink: 0; width: 7em; align-self: center; color: #1a2420; }
.hoja__marca .logo-gnv { width: 100%; height: auto; }
.hoja__identidad { flex: 1; }

/* Referencia oficial de cada herramienta: web del producto o publicacion. */
.util__detalle-refs[hidden] { display: none; }
.util__detalle-refs { display: flex; flex-wrap: wrap; gap: .35rem 1.1rem; margin-top: .65rem; }
.util__detalle-e {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .06em;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: .1em;
}
.util__detalle-e:hover { color: var(--fg); }

/* Cada punto de la linea temporal lleva a la web de su casa. */
.linea__enlace { color: inherit; text-decoration: none; }
.linea__enlace:hover { color: var(--accent); }

/* Nota de marcas al pie de las herramientas. */
.utiles__legal {
  margin-top: 2.2rem;
  font-size: .72rem;
  line-height: 1.6;
  color: var(--fg-faint);
  max-width: 70ch;
}

/* --- 34. Volver arriba ----------------------------------------------------
   Botón flotante que aparece al bajar más de una pantalla. Nace oculto y a
   ras de suelo; al mostrarse sube a su sitio. Bajo movimiento reducido
   aparece sin animación. En papel no existe. */
.subir {
  position: fixed;
  right: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  z-index: 90;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--bg-elev);
  color: var(--accent);
  cursor: pointer;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .28);
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;
  transition: opacity .25s var(--ease), transform .25s var(--ease),
              border-color .15s, background .15s;
}
.subir svg { width: 1.25rem; height: 1.25rem; }
.subir.es-visible { opacity: 1; transform: none; pointer-events: auto; }
.subir:hover { border-color: var(--accent); background: var(--bg-elev-2); }
.subir:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .subir { transition: opacity .01s; transform: none; }
}
@media print { .subir { display: none !important; } }

/* --- 35. Ganchos por perfil -----------------------------------------------
   Banda escaneable bajo el hero: cuatro señales, cada una para un tipo de
   visitante. Tarjetas con filete de acento a la izquierda; se leen de un
   vistazo y en móvil caen a una columna. */
.ganchos {
  padding: 1rem 0 3.5rem;
}
.ganchos__rejilla {
  list-style: none;
  margin: 1.1rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}
.gancho {
  padding: 1.15rem 1.25rem;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 12px;
}
.gancho__t {
  margin: 0 0 .5rem;
  font-family: var(--font-display);
  font-size: 1.02rem;
  line-height: 1.25;
  letter-spacing: -.01em;
  color: var(--fg);
  text-wrap: balance;
}
.gancho__d {
  margin: 0;
  font-size: .86rem;
  line-height: 1.55;
  color: var(--fg-muted);
}
@media (max-width: 900px) {
  .ganchos__rejilla { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .ganchos__rejilla { grid-template-columns: 1fr; }
}
@media print { .ganchos { display: none !important; } }

/* El norte: la quinta tarjeta ocupa el ancho completo y cierra la banda como
   síntesis de las cuatro anteriores. Fondo con un velo de acento y título algo
   mayor; en pantalla ancha, título y detalle conviven en dos columnas. */
.gancho--norte {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.9fr);
  gap: .55rem 1.9rem;
  align-items: center;
  background:
    linear-gradient(120deg, var(--accent-tint), transparent 70%),
    var(--bg-elev);
}
.gancho--norte .gancho__t { font-size: 1.28rem; }
.gancho--norte .gancho__d { font-size: .9rem; }
@media (max-width: 700px) {
  .gancho--norte { grid-template-columns: 1fr; }
}

/* --- 36. Aprendizajes / pilares del recorrido -----------------------------
   Lo que cada empresa del recorrido enseñó, con raíz en la psicología de la
   pericia. El primero es el rector y ocupa el ancho completo; los otros seis
   caen en dos columnas y, en móvil, en una. Namespace propio (.aprend) para
   no colisionar con los .pilar del ecosistema. */
.aprendizajes { margin-top: 3.75rem; }
.aprend__intro {
  max-width: 68ch;
  margin: 0 auto 2rem;
  text-align: center;
  font-size: 1.05rem;
  line-height: 1.7;
  color: var(--fg-muted);
  text-wrap: balance;
}
.aprend__rejilla {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.1rem;
}
.aprend {
  padding: 1.2rem 1.35rem;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 12px;
}
.aprend--rector {
  grid-column: 1 / -1;
  background:
    linear-gradient(120deg, var(--accent-tint), transparent 68%),
    var(--bg-elev);
}
.aprend__n {
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .16em;
  color: var(--accent);
}
.aprend__t {
  margin: .4rem 0 .55rem;
  font-family: var(--font-display);
  font-size: 1.08rem;
  line-height: 1.25;
  letter-spacing: -.01em;
  color: var(--fg);
  text-wrap: balance;
}
.aprend--rector .aprend__t { font-size: 1.24rem; }
.aprend__d {
  margin: 0;
  font-size: .9rem;
  line-height: 1.6;
  color: var(--fg-muted);
}
@media (max-width: 760px) {
  .aprend__rejilla { grid-template-columns: 1fr; }
}

/* Título de la sección de aprendizajes: centrado, sobre la intro. */
.aprend__titulo {
  margin: .3rem auto .9rem;
  text-align: center;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.1rem);
  line-height: 1.15;
  letter-spacing: -.02em;
  color: var(--fg);
  text-wrap: balance;
}
.aprendizajes > .kicker { text-align: center; }

/* Rótulo de fundamento de cada pilar: número + concepto psicológico. */
.aprend__meta {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  margin: 0 0 .1rem;
  flex-wrap: wrap;
}
.aprend__cat {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

/* Separador entre entradas de la tarjeta de comunidad técnica. */
.ponencia__t--sep {
  margin-top: 1.5rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--line);
}

/* --- 37. Cita destacada ---------------------------------------------------
   Bajo la banda de ganchos: una frase que puentea capacidad y carácter. */
.cita-bloque { padding: 1rem 0 3.5rem; }
.cita {
  max-width: 46ch;
  margin: 0 auto;
  padding: 0 1.2rem;
  text-align: center;
  position: relative;
}
.cita::before {
  content: "\201C";
  display: block;
  font-family: var(--font-display);
  font-size: 4rem;
  line-height: .8;
  color: var(--accent);
  opacity: .5;
  margin-bottom: .3rem;
}
.cita__texto {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 1.1rem + 1.1vw, 1.8rem);
  line-height: 1.3;
  letter-spacing: -.01em;
  color: var(--fg);
  text-wrap: balance;
}
.cita__autor {
  margin-top: 1.1rem;
  font-family: var(--font-mono);
  font-size: .74rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
@media print { .cita-bloque { display: none !important; } }

/* Visión en el hero: línea propia, con filete de acento. */
.hero__vision {
  margin: 1rem 0 0;
  padding-left: .95rem;
  border-left: 2px solid var(--accent);
  max-width: 52ch;
  color: var(--fg);
  font-size: 1.02rem;
  line-height: 1.55;
}
/* Segunda cita (humildad): separada de la primera y algo más contenida. */
.cita--sec {
  margin-top: 2.6rem;
  padding-top: 2.2rem;
  border-top: 1px solid var(--line);
}
.cita--sec .cita__texto { font-size: clamp(1.15rem, 1rem + .8vw, 1.5rem); }
.cita--sec::before { font-size: 3rem; }

/* Cita de humildad, como remate de los pilares (dentro de .aprendizajes). */
.cita--pilares {
  margin: 2.8rem auto 0;
  padding-top: 2.2rem;
  border-top: 1px solid var(--line);
}
.cita--pilares .cita__texto { font-size: clamp(1.2rem, 1rem + .9vw, 1.55rem); }
.cita--pilares::before { font-size: 3rem; }

/* Remate de la visión: destacado, en su propia línea. */
.hero__vision-cierre {
  display: block;
  margin-top: .5rem;
  color: var(--accent);
  font-weight: 600;
}

/* --- 38. Epígrafe (Sun Tzu) en los pilares --------------------------------
   Cadena antigua que refleja el método: original en chino, traducción,
   fuente y una reflexión que lo enlaza con los pilares. */
.epigrafe {
  max-width: 60ch;
  margin: 0 auto 2.4rem;
  padding: 1.5rem 1.6rem;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: 14px;
  text-align: center;
}
.epigrafe__original {
  margin: 0 0 1rem;
  font-size: 1.05rem;
  line-height: 1.9;
  letter-spacing: .08em;
  color: var(--accent);
  opacity: .8;
}
.epigrafe__texto {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.05rem, .95rem + .6vw, 1.3rem);
  line-height: 1.45;
  color: var(--fg);
  text-wrap: balance;
}
.epigrafe__autor {
  margin-top: .9rem;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.epigrafe__reflexion {
  margin: 1.4rem auto 0;
  padding-top: 1.3rem;
  border-top: 1px solid var(--line);
  max-width: 54ch;
  font-size: .95rem;
  line-height: 1.6;
  color: var(--fg-muted);
  text-wrap: balance;
}

/* Estado de una credencial (p. ej. "Pendiente de inicio"): píldora de acento. */
.credencial__estado {
  display: inline-block;
  margin-left: .55rem;
  padding: .12rem .55rem;
  border-radius: 999px;
  background: var(--accent-tint);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  vertical-align: middle;
  white-space: nowrap;
}

/* Etiqueta "pendiente de inicio" en la línea temporal (misma píldora que en
   credenciales). Desaparece sola por JS al llegar su data-desde. */
.linea__pendiente {
  display: inline-block;
  margin-left: .4rem;
  padding: .1rem .5rem;
  border-radius: 999px;
  background: var(--accent-tint);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: .62rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  vertical-align: middle;
}

/* --- 39. Candado de confidencialidad del visor ----------------------------
   El 3D queda difuminado detrás y un panel frost lo cubre: intriga sin
   mostrar nada. La clave es un gesto de acceso, no seguridad real. */
.visor { position: relative; }
.visor.esta-bloqueado .visor__escena canvas,
.visor.esta-bloqueado .visor__modelos,
.visor.esta-bloqueado .visor__panel,
.visor.esta-bloqueado .visor__ayuda {
  filter: blur(9px);
  opacity: .45;
  pointer-events: none;
  user-select: none;
}
.visor__candado {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  padding: 1.5rem;
  border-radius: inherit;
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.visor__candado-panel {
  max-width: 30rem;
  text-align: center;
  padding: 1.8rem 1.6rem;
  background: var(--bg-elev);
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .4);
}
.visor__candado-icono { width: 2rem; height: 2rem; color: var(--accent); }
.visor__candado-rotulo {
  margin: .5rem 0 0;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--accent);
}
.visor__candado-titulo {
  margin: .35rem 0 .5rem;
  font-family: var(--font-display);
  font-size: 1.3rem;
  letter-spacing: -.01em;
  color: var(--fg);
}
.visor__candado-texto {
  margin: 0 auto 1.1rem;
  max-width: 26rem;
  font-size: .9rem;
  line-height: 1.55;
  color: var(--fg-muted);
}
.visor__teasers {
  list-style: none;
  margin: 0 0 1.3rem;
  padding: 0;
  display: grid;
  gap: .5rem;
}
.visor__teasers li {
  padding: .55rem .7rem;
  border: 1px dashed var(--line-strong);
  border-radius: 9px;
  font-family: var(--font-mono);
  font-size: .8rem;
  letter-spacing: .04em;
  color: var(--fg-faint);
  /* Se intuyen pero no se leen del todo: intriga. */
  filter: blur(.4px);
}
.visor__clave {
  display: flex;
  gap: .5rem;
  max-width: 22rem;
  margin: 0 auto;
}
.visor__clave input {
  flex: 1;
  min-width: 0;
  padding: .6rem .8rem;
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: 9px;
  color: var(--fg);
  font: inherit;
}
.visor__clave input:focus { outline: none; border-color: var(--accent); }
.visor__clave button {
  padding: .6rem 1.1rem;
  border: 0;
  border-radius: 9px;
  background: var(--accent);
  color: #071412;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.visor__clave-msg {
  margin: .9rem 0 0;
  font-size: .85rem;
  color: var(--fg-muted);
}
.visor__clave-msg.es-ok { color: var(--accent); }
.visor__solicitar {
  display: inline-block;
  margin-top: .9rem;
  font-family: var(--font-mono);
  font-size: .74rem;
  letter-spacing: .06em;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
}

/* Eyebrow del hero: dominios en mono sobre el nombre (sustituye al antiguo
   distintivo de disponibilidad y equilibra el arranque). */
.hero__eyebrow {
  margin: 0 0 1.1rem;
  font-family: var(--font-mono);
  font-size: .78rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}

/* Cierre cálido de la llamada a contacto. */
.contacto-cta__cierre {
  margin: 1.4rem auto 0;
  max-width: 40ch;
  font-size: .9rem;
  line-height: 1.55;
  color: var(--fg-muted);
}

/* Cierre humilde tras los pilares: nota en primera persona, sin pretensión. */
.aprend__cierre {
  max-width: 60ch;
  margin: 2.8rem auto 0;
  padding-top: 2.2rem;
  border-top: 1px solid var(--line);
  text-align: center;
  font-size: 1.02rem;
  line-height: 1.65;
  color: var(--fg-muted);
  text-wrap: balance;
}

/* Réplica humilde bajo la cita: la voz propia frente a la cita ajena. */
.cita__replica {
  max-width: 52ch;
  margin: 1.6rem auto 0;
  padding-top: 1.4rem;
  border-top: 1px solid var(--line);
  text-align: center;
  font-size: .95rem;
  line-height: 1.65;
  color: var(--fg-muted);
  text-wrap: balance;
}
