/* ============================================================
   Portfolio v5 · Santi Estevez
   Noche violeta. Sin degradés: capas y colores lisos.
   ============================================================ */

:root {
  --night: #020203;
  --night-2: #0b0b10;
  --night-3: #15151d;
  --ink: #efedf8;
  --ink-2: #bdb9d6;
  --ink-3: #8f8bad;
  --ink-soft: #dcd8ee;
  --line: rgba(236, 232, 255, 0.12);
  --line-2: rgba(236, 232, 255, 0.22);
  --violet: #8b5cf6;
  --violet-hi: #ad94ff;
  --blue: #4a6cff;
  --blue-strong: #4566fa;
  --neon: #7d74ff;

  --gutter: clamp(16px, 5.6vw, 96px);
  --nav-h: 76px;
  --r-card: 24px;

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-move: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-pres: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);

  --font: 'Satoshi', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

  /* Escala del texto de las secciones (el titular del hero tiene la suya y siempre queda un escalón arriba):
     títulos de sección, frase de debajo del título, párrafos, aire entre título y lo que sigue, y ancho de lectura */
  --fs-h2: clamp(30px, 8.2vw, 46px);
  --fs-sub: 16px;
  --fs-body: 17px;
  --lh-body: 1.62;
  --gap-head: 14px;
  --measure: 31em;

  color-scheme: dark;
}
@media (min-width: 1024px) {
  :root {
    --fs-h2: clamp(32px, 2.5vw, 44px);
    --fs-sub: clamp(16px, 1.15vw, 18px);
    --gap-head: clamp(14px, 1.1vw, 20px);
  }
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 72px;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--night);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}
body.is-locked { overflow: hidden; }

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
h1, h2, h3, p, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }

::selection { background: var(--violet); color: #fff; }

:focus-visible {
  outline: 2px solid var(--violet-hi);
  outline-offset: 3px;
  border-radius: 6px;
}

html { scrollbar-color: #26252f var(--night); scrollbar-width: thin; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--night); }
::-webkit-scrollbar-thumb { background: #26252f; border-radius: 10px; border: 2px solid var(--night); }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.i {
  width: 20px; height: 20px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip {
  position: fixed; left: 16px; top: 12px; z-index: 100;
  padding: 10px 16px; border-radius: 999px;
  background: var(--ink); color: var(--night); font-weight: 700;
  transform: translateY(-160%);
  transition: transform 0.2s var(--ease-out);
}
.skip:focus-visible { transform: none; }

/* ---------- Botones ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  height: 52px; padding: 0 26px;
  border-radius: 999px;
  font-size: 16px; font-weight: 700; letter-spacing: -0.005em;
  white-space: nowrap;
  transition: background-color 0.2s var(--ease-out), border-color 0.2s var(--ease-out), color 0.2s var(--ease-out), transform 0.16s var(--ease-out);
}
.btn .i { width: 18px; height: 18px; transition: transform 0.25s var(--ease-out); }
.btn:active { transform: scale(0.97); }
.btn-solid { background: #f3f1fb; color: #13112a; }
.btn-ghost { border: 1px solid rgba(236, 232, 255, 0.45); color: var(--ink); }
.btn-sm { height: 42px; padding: 0 18px; font-size: 14.5px; }
.btn-sm .i { width: 16px; height: 16px; }

@media (hover: hover) and (pointer: fine) {
  .btn-solid:hover { background: #fff; }
  .btn-ghost:hover { border-color: var(--ink-2); background: rgba(236, 232, 255, 0.05); }
  .btn:hover .i { transform: translateX(3px); }
}

/* ---------- Nav ---------- */

.nav {
  position: fixed; inset: 0 0 auto; z-index: 50;
  height: var(--nav-h);
  padding: 0 var(--gutter);
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  transition: transform 0.3s var(--ease-out);
}
/* Fondo de la nav compacta: se prende con opacidad, sin animar el alto ni usar blur */
.nav::before {
  content: ''; position: absolute; inset: 6px 0 0; z-index: -1;
  background: var(--night);
  border-bottom: 1px solid var(--line);
  opacity: 0; transition: opacity 0.3s var(--ease-out);
}
.nav.is-scrolled { transform: translateY(-6px); }
.nav.is-scrolled::before { opacity: 1; }

.brand {
  display: inline-flex; flex-direction: column; justify-content: center;
  min-height: 44px; line-height: 1; justify-self: start;
}
.brand-name { font-size: clamp(22px, 1.7vw, 26px); font-weight: 900; letter-spacing: 0.01em; }
.brand-last { margin-top: 2px; font-size: 11px; font-weight: 500; letter-spacing: 0.5em; color: var(--ink-2); }

.nav-links { display: none; gap: clamp(24px, 2.8vw, 44px); }
.nav-links a {
  position: relative; padding: 8px 0;
  font-size: 13.5px; font-weight: 500; color: #d9d5ea;
  transition: color 0.2s var(--ease-out);
}
.nav-links a::after {
  content: ''; position: absolute; left: 50%; bottom: -3px;
  width: 30px; height: 2px; margin-left: -15px; border-radius: 2px;
  background: #cfe0ff;
  box-shadow: 0 0 10px 1px rgba(74, 108, 255, 0.85);
  transform: scaleX(0); transition: transform 0.3s var(--ease-out);
}
.nav-links a[aria-current="true"] { color: var(--ink); }
.nav-links a[aria-current="true"]::after { transform: scaleX(1); }
@media (hover: hover) and (pointer: fine) { .nav-links a:hover { color: var(--ink); } }
/* ---- FX: pastillaDesliza (rayita del nav) ---- */
/* La rayita aparece y se apaga al instante; lo que se mueve es el viaje de un link al otro (translate),
   con un estirón a mitad de camino. Mismo idioma que la placa del ES/EN. */
.nav-links.has-ray a::after { transition: none; translate: var(--ray-x, 0px) 0; }
.nav-links.has-ray a.ray-go::after {
  transition: translate 0.46s cubic-bezier(.77, 0, .175, 1);
  animation: nav-ray-stretch 0.46s cubic-bezier(.33, 0, .25, 1);
}
@keyframes nav-ray-stretch { 45% { scale: 2.1 1; } }
@media (prefers-reduced-motion: reduce) {
  .nav-links.has-ray a.ray-go::after { transition: none; animation: none; }
}

.nav-actions { grid-column: 3; justify-self: end; display: flex; align-items: center; gap: 12px; }
.nav-cta {
  display: none;
  height: 40px; font-weight: 500;
  border: 1.5px solid rgba(236, 232, 255, 0.82);
  box-shadow: 0 0 14px rgba(236, 232, 255, 0.16);
}

/* Idioma: control segmentado. Los dos idiomas a la vista, cada uno escrito en su idioma;
   una placa de vidrio (el mismo canto de luz que las cards) se desliza debajo del elegido. */
.lang {
  --lang-h: 44px;
  position: relative; isolation: isolate; flex: none;
  display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  height: var(--lang-h); border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(236, 232, 255, 0.025);
  transition: border-color 0.2s var(--ease-out);
}
.lang-thumb {
  position: absolute; z-index: -1; top: 4px; bottom: 4px; left: 4px;
  width: calc(50% - 8px); border-radius: 999px;
  background: rgba(236, 232, 255, 0.11);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.12),
    inset 1px 1.5px 0 -0.5px rgba(255, 255, 255, 0.62),
    inset -1px -1px 0 -0.5px rgba(255, 255, 255, 0.22),
    0 0 14px -3px rgba(74, 108, 255, 0.7);
  pointer-events: none;
}
/* La misma raya de luz que marca la sección activa en el nav: lo elegido se marca igual en todo el sitio */
.lang-thumb::after {
  content: ''; position: absolute; left: 50%; bottom: 3px;
  width: 14px; height: 2px; margin-left: -7px; border-radius: 2px;
  background: #cfe0ff;
  box-shadow: 0 0 8px 1px rgba(74, 108, 255, 0.85);
}
/* translateX(100% + 8px) = medio control: la placa cae justo sobre la segunda opción */
.lang[data-current="es"] .lang-thumb { transform: translateX(calc(100% + 8px)); }
/* La transición se prende después del primer pintado: al cargar, la placa no viaja */
.lang.is-ready .lang-thumb { transition: transform 240ms var(--ease-out); }
.lang-opt {
  position: relative;
  min-width: 46px; padding: 0 14px; border-radius: 999px;
  margin-block: -1px;   /* se mete sobre el borde: en el celular cada opción toca los 44 px de alto */
  font-size: 12.5px; font-weight: 700; letter-spacing: 0.1em;
  color: var(--ink-3);
  transition: color 0.2s var(--ease-out), transform 0.16s var(--ease-out);
}
.lang-opt[aria-pressed="true"] { color: var(--ink); cursor: default; }
.lang-opt[aria-pressed="false"]:active { transform: scale(0.94); }
.lang-opt:focus-visible { outline-offset: -2px; border-radius: 999px; }
/* El cursor abraza la opción que podés elegir; la opción no se corre (la placa no la seguiría) */
.lang-opt.is-magnetic { translate: none; }
@media (hover: hover) and (pointer: fine) {
  .lang { --lang-h: 40px; }
  .lang:hover { border-color: var(--line-2); }
  .lang-opt[aria-pressed="false"]:hover { color: var(--ink-soft); }
}
/* En el menú del celular hay lugar: los nombres completos */
.lang-full { --lang-h: 48px; }
.lang-full .lang-opt { padding: 0 14px; font-size: 15px; font-weight: 600; letter-spacing: 0; }
@media (prefers-reduced-motion: reduce) {
  .lang.is-ready .lang-thumb { transition: none; }
}

.menu-btn {
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  transition: border-color 0.2s var(--ease-out), transform 0.16s var(--ease-out);
}
.menu-btn:active { transform: scale(0.95); }
.menu-btn .i { width: 22px; height: 22px; }
@media (hover: hover) and (pointer: fine) { .menu-btn:hover { border-color: var(--line-2); } }

@media (min-width: 640px) { .nav-cta { display: inline-flex; } }
@media (min-width: 1100px) {
  .nav { grid-template-columns: auto 1fr auto; }
  .nav-links { display: flex; justify-self: start; margin-left: 15vw; }
  .nav-actions .menu-btn { display: none; }
}

/* Menú de celular */
.menu {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column;
  padding: 0 var(--gutter) max(24px, env(safe-area-inset-bottom));
  background: var(--night);
  opacity: 0; transform: translateY(-12px);
  transition: opacity 0.2s var(--ease-out), transform 0.32s var(--ease-drawer);
}
.menu.is-open { opacity: 1; transform: none; }
.menu:not(.is-open) { transition-duration: 0.14s, 0.16s; }
.menu[hidden] { display: none; }
.menu-top { height: var(--nav-h); display: flex; align-items: center; justify-content: space-between; }
.menu-links { display: flex; flex-direction: column; margin-top: 4vh; }
.menu-links a {
  padding: 14px 0;
  font-size: clamp(34px, 10vw, 52px); font-weight: 700; letter-spacing: -0.03em; line-height: 1.05;
  border-bottom: 1px solid var(--line);
}
.menu-foot { margin-top: auto; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding-top: 24px; }
/* El botón ocupa lo que deja el idioma; en pantallas muy angostas baja a su propia fila, a lo ancho */
.menu-foot .btn { flex: 1 1 auto; justify-content: center; }
.menu.is-open .menu-links a { animation: rise-in 0.5s var(--ease-pres) backwards; }
.menu.is-open .menu-links a:nth-child(2) { animation-delay: 40ms; }
.menu.is-open .menu-links a:nth-child(3) { animation-delay: 80ms; }
.menu.is-open .menu-links a:nth-child(4) { animation-delay: 120ms; }
.menu.is-open .menu-links a:nth-child(5) { animation-delay: 160ms; }

/* ---------- Escenario (hero + carrusel) ---------- */

.stage { position: relative; isolation: isolate; overflow: clip; }


/* Hero */
.hero {
  position: relative; isolation: isolate;
  min-height: 100svh;
  padding: calc(var(--nav-h) + 28px) var(--gutter) 0;
  display: flex; flex-direction: column;
}
.hero-copy { position: relative; z-index: 2; max-width: 600px; }

.eyebrow {
  font-size: 12.5px; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase;
  color: #e0daf6;
}
.hero-title {
  margin-top: 18px;
  font-size: clamp(38px, 10.4vw, 66px);
  font-weight: 700; line-height: 1; letter-spacing: -0.035em;
  color: var(--ink);
  text-wrap: balance;
}
/* Máscara por línea para la entrada; el padding (devuelto con el margen negativo, no mueve nada) deja lugar a los
   descendentes abajo y a la borrosidad de la entrada a los costados */
.hero-title .ln { display: block; overflow: hidden; padding: 0 0.2em 0.12em; margin: 0 -0.2em -0.12em; }
.hero-title .ln > span { display: inline-block; }
/* La bajada va un escalón arriba de los párrafos de la página (es lo segundo que se lee) */
.lead {
  margin-top: 20px; max-width: 31em;
  font-size: clamp(16px, 4.3vw, 17.5px); line-height: 1.6;
  color: var(--ink-soft);
  text-wrap: pretty;
}
.hero-ctas { margin-top: 30px; display: flex; flex-wrap: wrap; gap: 12px; }
@media (max-width: 400px) {
  .hero-ctas { gap: 10px; }
  .hero-ctas .btn { padding: 0 16px; }
}
@media (max-width: 349px) { .hero-ctas { display: grid; } }

/* ---------- Símbolos de neón del hero ----------
   Cinco tubos de neón de vidrio, uno por cada motivo para trabajar conmigo (el dibujo viene armado en el HTML).
   Todo lo de adentro se mide en "unidades de diseño" que pasan a px con el ancho de la fila (--s, en cqw): los tubos,
   el brillo y los espacios guardan la proporción del celular a la compu. El halo borroso es la única capa con
   will-change, así crecer o atenuarse nunca vuelve a pintar el desenfoque.
   Celular y tablet: debajo del texto, donde iba la foto (en celular, a lo ancho menos 16 px por lado). */
.sigils {
  --cap-word: clamp(24px, 2.1vw, 31px);
  --cap-text: 15.5px;
  --cap-h: calc(var(--cap-word) * 1.15 + 10px + var(--cap-text) * 1.5 * 3);   /* palabra + tres renglones de frase */
  position: relative; z-index: 1;
  container-type: inline-size;
  flex: 1 1 auto;
  display: flex; flex-direction: column; justify-content: center;
  margin: 26px calc(16px - var(--gutter)) 0;
  padding: 0 0 28px;
}
.sigils-stage {
  --s: calc(100cqw / var(--rowU));
  position: relative;
  padding-bottom: calc(var(--cap-extra) * var(--s) + 10px + var(--cap-h));
}
.sigils-row { display: flex; justify-content: center; }
.sigil { --g: var(--gf); flex: none; }
@media (hover: none), (pointer: coarse) { .sigil { --g: var(--gt); } }
.sigil-btn { display: block; cursor: default; -webkit-tap-highlight-color: transparent; }
.sigil-btn:focus-visible { outline: none; }
.sigil-box {
  position: relative;
  display: grid; place-items: center;
  width: calc(var(--slot) * var(--s)); height: calc(var(--rowH) * var(--s));
}
/* Foco del teclado: un contorno tenue alrededor del símbolo (el símbolo además se enciende como con el mouse).
   0,42 es lo mínimo para 3:1 contra el negro (con 0,32 daba 2,5:1). Va en la capa que flota y mide lo que el símbolo
   ya crecido (--g), así lo rodea entero y no corta la palabra de abajo; con reduced-motion el símbolo no crece (--fg: 1). */
.sigil-btn:focus-visible .sigil-float::after {
  content: ""; position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  width: calc(var(--vw) * var(--fg, var(--g)) * var(--s) + 14px); height: calc(var(--vh) * var(--fg, var(--g)) * var(--s) + 14px);
  border-radius: 18px;
  border: 1px solid rgba(239, 237, 248, 0.42);
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) { .sigil { --fg: 1; } }
.sigil-float { display: block; position: relative; width: calc(var(--vw) * var(--s)); height: calc(var(--vh) * var(--s)); }
.sigil-scale { display: block; position: relative; width: 100%; height: 100%; }
.sigil svg { pointer-events: none; max-width: none; }
.sigil-tube { position: relative; width: 100%; height: 100%; overflow: visible; }
.sigil-halo { position: absolute; overflow: visible; opacity: 0.8; will-change: transform, opacity; }

/* La palabra de neón y la frase, debajo del símbolo encendido. La cruz alinea a su borde izquierdo, el globo al
   derecho y el resto va centrado; la altura sigue al símbolo crecido. Ocultas con opacidad (no visibility): así el
   lector de pantalla las lee siempre como el nombre del botón, "palabra — frase". */
.sigil-cap {
  position: absolute; z-index: 2;
  top: calc((var(--rowH) / 2 + var(--vh) / 2 * var(--g) + 6) * var(--s) + 10px);
  left: calc(var(--cx) * var(--s));
  translate: calc(-50% + var(--nudge, 0px)) 0;   /* --nudge: el JS la corre si en pantallas angostas se sale de la fila */
  width: max-content; max-width: 100%;
  text-align: center;
  pointer-events: none;
}
.sigil:first-child .sigil-cap { left: calc((var(--cx) - var(--hw) * var(--g)) * var(--s)); translate: var(--nudge, 0px) 0; text-align: left; }
.sigil:last-child .sigil-cap { left: auto; right: calc((var(--rowU) - var(--cx) - var(--hw) * var(--g)) * var(--s)); translate: var(--nudge, 0px) 0; text-align: right; }
.sigil-word {
  display: block;
  font-size: var(--cap-word); font-weight: 500; line-height: 1.15; letter-spacing: 0.005em;
  white-space: nowrap;
  color: var(--core);
  text-shadow: 0 0 1px var(--core), 0 0 5px var(--c), 0 0 12px var(--c), 0 0 26px var(--c), 0 0 52px var(--c-half);
  opacity: 0;
}
.sigil-text {
  display: block;
  max-width: 24ch; margin: 10px auto 0;
  font-size: var(--cap-text); line-height: 1.5; font-weight: 400;
  color: #f1f0f8;
  text-wrap: balance;
  opacity: 0;
}
.sigil:first-child .sigil-text { margin-left: 0; }
.sigil:last-child .sigil-text { margin-right: 0; }
/* Sin JS: los símbolos quedan quietos y la palabra aparece con el mouse o el foco */
.no-js .sigil-btn:is(:hover, :focus-visible) :is(.sigil-word, .sigil-text) { opacity: 1; }

/* ---------- Proyectos ---------- */

.projects {
  --card-w: clamp(180px, 54vw, 220px);
  --card-h: calc(var(--card-w) / 0.5);
  position: relative;
  padding: 48px 0 clamp(48px, 8vw, 72px);
}
.cf-wrap { position: relative; }
.projects-head { padding: 0 var(--gutter); text-align: center; }
/* el texto del título va en un bloque propio: es lo que se divide en renglones para la entrada */
.projects-title > span { display: block; }
.projects-meta { margin-top: var(--gap-head); }
.projects-sub { font-size: var(--fs-sub); line-height: 1.55; color: var(--ink-2); max-width: 30em; margin-inline: auto; text-wrap: balance; }
.cf-count {
  font-size: 13px; color: var(--ink-3); letter-spacing: 0.08em; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.cf-count b { color: var(--ink); font-weight: 500; }
/* El contador [ 01 / 05 ] va escondido (2026-10-11, pedido de Santi): el número lo muestra el índice vertical */
.cf-count--mob { display: none; position: absolute; right: var(--gutter); top: -30px; z-index: 30; }
/* ---- FX: contadorRueda ---- */
/* Mientras rueda, cada dígito es una ventanita con una tira de números. El dígito final queda invisible
   debajo (da el ancho y el texto); la ventana sobresale 3 px para no cortar los números. */
.odo { display: inline-block; white-space: nowrap; }
.odo-c { position: relative; display: inline-block; }
.odo-c:not(.is-still) .odo-s { color: transparent; }
.odo-w { position: absolute; left: 0; right: 0; top: -3px; bottom: -3px; overflow: hidden; pointer-events: none; }
.odo-strip { position: absolute; left: 0; right: 0; top: 3px; will-change: transform; }
.odo-strip i { display: block; height: var(--odo-h); line-height: var(--odo-h); text-align: center; font-style: normal; }
.odo-strip i::before { content: attr(data-d); }

/* Carrusel coverflow: una card al frente, las demás escondidas en ángulo detrás */
.cf { position: relative; margin-top: 44px; outline: none; }
.cf-track {
  position: relative;
  height: var(--card-h);
  perspective: 820px;
  perspective-origin: 50% 50%;
  touch-action: pan-y pinch-zoom;
  user-select: none; -webkit-user-select: none;
}
.cf-track.is-dragging .card { transition: none; cursor: grabbing; }
.cf-track img { -webkit-user-drag: none; }   /* si no, el mouse arrastra la imagen en vez del carrusel */

.card {
  /* Tamaño de diseño fijo (vertical): el JS la escala para que mida --card-h en pantalla */
  --cw: 236px; --ch: 472px;
  position: absolute; left: 50%;
  top: calc((var(--card-h) - var(--ch)) / 2);
  width: var(--cw); height: var(--ch);
  margin-left: calc(var(--cw) / -2);
  cursor: pointer;
  transition: transform 0.55s var(--ease-drawer), opacity 0.45s var(--ease-out), z-index 0s linear 90ms;
  will-change: transform;
  -webkit-tap-highlight-color: transparent;
}
.card[data-state="out"] { opacity: 0; pointer-events: none; }
.card-scale { position: relative; height: 100%; transition: transform 0.25s var(--ease-out); }

/* Liquid glass: la card es una placa de vidrio. Lo de atrás se ve borroso, más saturado y
   (en Chrome/Edge) curvado en los bordes; el canto agarra luz arriba a la izquierda. Todo con luz, sin degradés. */
.card-in {
  position: relative; height: 100%; overflow: hidden;
  display: flex; flex-direction: column;
  border-radius: var(--r-card);
  background: rgba(6, 5, 13, 0.93);
  -webkit-backdrop-filter: blur(18px) saturate(1.8) brightness(1.08);
  backdrop-filter: blur(18px) saturate(1.8) brightness(1.08);
  box-shadow: 0 34px 60px -30px rgba(2, 1, 10, 0.95);
}
/* El canto del vidrio: arista clara arriba a la izquierda, más tenue abajo a la derecha, brillo adentro */
.card-in::before {
  content: ''; position: absolute; inset: 0; z-index: 4;
  border-radius: inherit; pointer-events: none;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.14),
    inset 1.5px 1.5px 0 -0.5px rgba(255, 255, 255, 0.7),
    inset -1px -1.5px 0 -0.5px rgba(255, 255, 255, 0.28),
    inset 0 22px 24px -20px rgba(255, 255, 255, 0.24),
    inset 0 -18px 26px -20px rgba(175, 165, 255, 0.2),
    inset 0 0 26px rgba(255, 255, 255, 0.05);
}
/* Las de atrás: más transparentes y con el canto más encendido, como en la referencia */
.card:not([data-off="0"]) .card-in { background: rgba(8, 7, 18, 0.9); }
.card:not([data-off="0"]) .card-in::before {
  box-shadow:
    inset 0 0 0 1.5px rgba(225, 230, 255, 0.4),
    inset 2px 2px 0 -0.5px rgba(255, 255, 255, 0.75),
    inset -1px -1px 0 -0.5px rgba(255, 255, 255, 0.3),
    inset 0 24px 26px -20px rgba(255, 255, 255, 0.28),
    inset 0 0 30px rgba(190, 190, 255, 0.08);
}
/* En celular el desenfoque va solo en la del frente (las de atrás son franjas): cuida a los Android de gama media */
@media (hover: none), (pointer: coarse) {
  .card .card-in { -webkit-backdrop-filter: none; backdrop-filter: none; }
  .card:not([data-off="0"]) .card-in { background: rgba(8, 7, 18, 0.96); }
  .card[data-off="0"] .card-in { background: rgba(6, 5, 13, 0.97); }
}
/* Refracción en los bordes (Chrome/Edge, compu): el JS arma el filtro con un mapa del borde de la card */
/* Solo con el carrusel quieto: mientras se mueve va el desenfoque común (la refracción cuesta cuadros) */
.lg-refract .cf-track:not(.is-moving):not(.is-dragging) .card[data-off="0"] .card-in {
  -webkit-backdrop-filter: url(#lg-refract);
  backdrop-filter: url(#lg-refract);
}

/* Brillo que sigue al mouse sobre la card del frente */
.card-light {
  position: absolute; left: 0; top: 0; z-index: 3;
  width: 240px; height: 240px; margin: -120px 0 0 -120px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  filter: blur(46px);
  transform: translate(var(--lx, 90px), var(--ly, 80px));
  opacity: 0; transition: opacity 0.4s var(--ease-out);
  pointer-events: none;
}

/* Neón de la card del frente */
/* Neón: solo brilla el borde. El color sale de la imagen de la card (o del proyecto si no hay imagen) */
.card-glow {
  position: absolute; inset: 0; border-radius: var(--r-card);
  border: 1.5px solid var(--glow, #a99dff);
  box-shadow:
    0 0 6px -1px var(--glow, #a99dff),
    inset 0 0 6px -1px var(--glow, #a99dff);
  opacity: 0; transition: opacity 0.45s var(--ease-out);
  pointer-events: none; z-index: 2;
}
.card[data-off="0"] .card-glow { opacity: 1; }

/* La imagen va de borde a borde arriba y se funde a negro hacia abajo, donde está el texto
   (este fundido lo pidió Santi: es la única excepción al veto de degradés) */
.card-media {
  position: absolute; left: 0; right: 0; top: 0; height: 64%;
  background-color: #0b0b10;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 50%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 50%, transparent 100%);
}
/* La imagen es la portada del sitio con la marca arriba: en el celular (donde la card la recorta) se alinea arriba
   para que la marca quede justo debajo del chip */
.card-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: var(--img-pos, 50% 0%); }

.card-chip {
  position: absolute; top: 14px; left: 14px;
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 500; color: var(--ink);
  text-shadow: 0 1px 6px rgba(2, 2, 3, 0.7);
}
.card-chip-ico {
  width: 24px; height: 24px; border-radius: 7px;
  display: grid; place-items: center;
  background: var(--violet); color: #fff;
}
.card-chip-ico .i { width: 14px; height: 14px; stroke-width: 2; }
.card[data-wip] .card-chip-ico { background: #3a3566; }
/* Sobre una captura clara (Super3D, AlfaImagen) el chip va en tinta oscura para que se lea */
.card.is-light-top .card-chip { color: #13112a; text-shadow: 0 1px 6px rgba(255, 255, 255, 0.8); }

.card-body {
  position: relative; z-index: 1; margin-top: auto;
  display: flex; flex-direction: column; align-items: flex-start; gap: 9px; padding: 14px 18px 18px;
}
.card-title { font-size: 22px; font-weight: 700; line-height: 1.1; letter-spacing: -0.025em; text-shadow: 0 1px 12px rgba(0, 0, 0, 0.6); }
.card-desc {
  font-size: 13.5px; line-height: 1.5; color: var(--ink-soft);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.card-go {
  position: relative; margin-top: 3px;
  width: 54px; height: 34px; border-radius: 999px; flex: none;
  display: grid; place-items: center;
  border: 1.5px solid #5b7cff;
  background: rgba(74, 108, 255, 0.14);
  box-shadow: 0 0 8px -2px rgba(74, 108, 255, 0.6);
  color: var(--ink);
  transition: background-color 0.2s var(--ease-out), transform 0.16s var(--ease-out);
}
/* Área de toque más grande que el dibujo */
.card-go::before { content: ''; position: absolute; inset: -8px; border-radius: 999px; }
.card-go .i { width: 17px; height: 17px; }
.card-go:active { transform: scale(0.95); }

.card-thumbs {
  align-self: stretch;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 7px; margin-top: 5px;
}
.card-thumbs span {
  aspect-ratio: 16 / 10; border-radius: 7px;
  overflow: hidden;
  background-color: #0b0b10;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.16);
}
.card-thumbs img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 0; opacity: 0.9; }

/* Celular: la imagen ocupa un poco menos para que el texto quede sobre el negro */
@media (max-width: 767px) {
  .card-media { height: 56%; }
  /* La card del celular es angosta: la descripción entra en 4 líneas (el lugar lo dejó la pastilla de estado que ya no está) */
  .card-desc { -webkit-line-clamp: 4; }
}

/* Las de atrás se apagan */
.card-dim {
  position: absolute; inset: 0; z-index: 3; border-radius: inherit;
  background: #08071a;
  opacity: var(--dim, 0);
  transition: opacity 0.45s var(--ease-out);
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  .card[data-off="0"]:hover .card-scale { transform: scale(1.02); }
  .card[data-off="0"]:hover .card-go { background: var(--blue); }
  .card[data-off="0"]:hover .card-light { opacity: 1; }
  /* La de atrás sale un poco hacia afuera (y hacia adelante, por el giro) para que se note que se puede elegir */
  .card:not([data-off="0"]):not([data-state="out"]):hover .card-scale { transform: translateX(22px) scale(1.02); }
  .card[data-off^="-"]:not([data-state="out"]):hover .card-scale { transform: translateX(-22px) scale(1.02); }
  .card:not([data-off="0"]):hover .card-dim { opacity: calc(var(--dim, 0) * 0.3); }
  /* Mantiene el área del hover aunque la franja se corra bajo el mouse */
  .card:not([data-off="0"])::before { content: ''; position: absolute; inset: 0; pointer-events: auto; }
}

/* Flechas laterales (tablet y compu) */
.cf-arrow {
  position: absolute; top: 50%; z-index: 30;
  width: 44px; height: 44px; margin-top: -22px; border-radius: 50%;
  display: none; place-items: center;
  border: 1px solid var(--line-2);
  background: rgba(2, 2, 3, 0.66);
  transition: border-color 0.2s var(--ease-out), background-color 0.2s var(--ease-out), opacity 0.2s var(--ease-out), transform 0.16s var(--ease-out);
}
.cf-arrow:active { transform: scale(0.94); }
.cf-prev { left: calc(var(--gutter) * 0.5); }
.cf-next { right: calc(var(--gutter) * 0.5); }
.cf-arrow:disabled { opacity: 0.3; cursor: default; pointer-events: none; }
@media (hover: hover) and (pointer: fine) { .cf-arrow:not(:disabled):hover { border-color: var(--ink-2); background: rgba(26, 23, 54, 0.9); } }

/* Índice vertical */
.cf-index {
  position: absolute; right: 2px; top: 50%; z-index: 30;
  transform: translateY(-50%);
  display: flex; flex-direction: column;
  padding: 4px 0; border-radius: 999px;
  background: rgba(2, 2, 3, 0.72);
}
.cf-index::before {
  content: ''; position: absolute; right: 9px; top: 12px; bottom: 12px;
  width: 1px; background: var(--line-2);
}
.cf-index button {
  position: relative;
  min-width: 36px; height: 34px; padding-right: 15px;
  display: grid; place-items: center end;
  font-size: 12px; font-weight: 500; color: var(--ink-2); font-variant-numeric: tabular-nums;
  transition: color 0.2s var(--ease-out), transform 0.16s var(--ease-out);
}
.cf-index button:active { transform: scale(0.95); }
.cf-index button::after {
  content: ''; position: absolute; right: 8px; top: 50%;
  width: 3px; height: 14px; margin-top: -7px; border-radius: 2px;
  background: var(--blue);
  transform: scaleY(0); transition: transform 0.3s var(--ease-out);
}
.cf-index button[aria-current="true"] { color: var(--ink); }
.cf-index button[aria-current="true"]::after { transform: scaleY(1); }

/* Filtros: el padding deja entero el anillo de foco y el glow del activo */
.cf-filters {
  margin-top: 20px; margin-bottom: -26px;
  display: flex; gap: 6px; justify-content: safe center;
  overflow-x: auto; scrollbar-width: none;
  padding: 10px var(--gutter) 30px;
}
.cf-filters::-webkit-scrollbar { display: none; }
.cf-filters button {
  flex: none; height: 42px; padding: 0 14px; border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 14px; font-weight: 500; color: var(--ink-2);
  transition: background-color 0.25s var(--ease-out), border-color 0.25s var(--ease-out), color 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out), transform 0.16s var(--ease-out);
}
/* va después de la regla base: si no, la base lo pisa y en 390 el último filtro queda cortado */
@media (max-width: 419px) {
  .cf-filters { gap: 5px; }
  .cf-filters button { padding: 0 11px; font-size: 13.5px; }
}
.cf-filters button:active { transform: scale(0.97); }
.cf-filters button[aria-pressed="true"] {
  background: var(--blue-strong); border-color: var(--blue-strong); color: #fff;
  box-shadow: 0 8px 26px -8px rgba(74, 108, 255, 0.85);
}
@media (hover: hover) and (pointer: fine) {
  .cf-filters button:not([aria-pressed="true"]):hover { color: var(--ink); border-color: var(--line-2); }
}
/* ---- FX: pastillaDesliza (pastilla de filtros) ---- */
/* El azul y el glow del activo pasan a una pastilla aparte que viaja detrás de los botones (z-index -1
   dentro de la fila aislada). El botón elegido queda transparente y no se corre con el imán del cursor
   (la pastilla no lo seguiría), igual que la opción del ES/EN. */
.cf-filters.has-pill { position: relative; isolation: isolate; }
.cf-pill {
  position: absolute; left: 0; top: 0; z-index: -1;
  border-radius: 999px; pointer-events: none;
  background: var(--blue-strong);
  box-shadow: 0 8px 26px -8px rgba(74, 108, 255, 0.85);
  will-change: transform, width;
}
.cf-filters.has-pill button[aria-pressed="true"] {
  background: transparent; border-color: transparent; box-shadow: none;
  transition: border-color 0.25s var(--ease-out), color 0.25s var(--ease-out), transform 0.16s var(--ease-out), translate 0.3s var(--ease-out);
}
.cf-filters.has-pill button[aria-pressed="true"].is-magnetic { translate: none; }

/* Lista simple: se ve sin JS o si el JS falla */
.cf-noscript { display: grid; gap: 12px; padding: 0 var(--gutter); }
.cf-noscript li, .cf-noscript a { display: block; padding: 18px; border: 1px solid var(--line); border-radius: 16px; color: var(--ink-2); }
.cf-noscript li:has(a) { padding: 0; border: 0; }
.cf-noscript b { display: block; color: var(--ink); font-size: 20px; margin-bottom: 4px; }
.js .cf-noscript { display: none; }
.no-js .cf-track, .no-js .cf-arrow, .no-js .cf-filters, .no-js .cf-index, .no-js .cf-count,
.no-js [data-lang-switch], .no-js .menu-btn { display: none; }

/* ---------- Tablet ---------- */
@media (min-width: 768px) {
  .projects { --card-w: 280px; --card-h: calc(var(--card-w) / 0.5); padding-top: clamp(64px, 9vw, 96px); }
  .card { --cw: 300px; --ch: 600px; }
  .cf-track { perspective: 1100px; }
  .cf { margin-top: 48px; }
  .cf-arrow { display: grid; }
  .cf-filters { gap: 8px; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .cf-arrow { display: none; }
  .cf-index { right: 10px; }
}

/* Pantallas bajas (celular acostado, zoom alto) */
@media (max-height: 500px) and (max-width: 1023px) {
  .nav { position: absolute; }
  .projects { --card-w: min(54vw, 220px, calc((100svh - 60px) * 0.5)); }
  .hero { min-height: 0; padding-top: calc(var(--nav-h) + 4px); }
  .hero-title { margin-top: 12px; font-size: clamp(32px, 10.5vh, 48px); }
  .lead { margin-top: 12px; }
  .hero-ctas { margin-top: 18px; }
  .sigils { margin-top: 18px; }
}
@media (max-height: 500px) and (min-width: 768px) and (max-width: 1023px) {
  .projects { --card-w: min(280px, calc((100svh - 60px) * 0.5)); }
}

/* ---------- Compu ---------- */
@media (min-width: 1024px) {
  .hero-copy { max-width: none; }
  .eyebrow { font-size: clamp(12px, 0.72vw, 13.5px); letter-spacing: 0.06em; }
  .hero-title { margin-top: 16px; font-size: clamp(40px, min(2.95vw, 6.4vh), 60px); line-height: 0.93; }
  .hero-title .ln > span { white-space: nowrap; }
  .lead { margin-top: clamp(18px, 1.3vw, 26px); max-width: 22em; font-size: clamp(16px, 1.15vw, 19px); line-height: 1.6; color: #ece9f6; }
  .hero-ctas { margin-top: clamp(22px, 1.7vw, 34px); gap: clamp(12px, 0.8vw, 16px); }
  .hero-ctas .btn { height: clamp(44px, 2.7vw, 50px); padding: 0 clamp(22px, 1.4vw, 26px); font-size: clamp(15px, 0.92vw, 17px); }
  .card { --cw: 300px; --ch: 600px; }
  .cf-track { perspective: 1200px; }
  .cf-filters button { height: 38px; padding: 0 16px; font-size: 13.5px; }
}
@media (min-width: 1024px) and (max-width: 1159px) {
  .lead { max-width: 20em; }
  .hero-ctas { gap: 10px; }
  .hero-ctas .btn { padding: 0 18px; }
}

/* Compu: el carrusel va en su propia sección, debajo del hero (como el panel de arriba a la derecha de la imagen 1) */
@media (min-width: 1024px) {
  /* Al llegar a la sección entran el título, el carrusel y los filtros */
  .projects { --card-h: clamp(460px, calc(100svh - 350px), 640px); padding: clamp(56px, 7vh, 88px) 0 72px; }
  .cf { margin-top: 48px; }
  .cf-count--mob { top: -34px; right: calc(var(--gutter) * 0.6); }
  .cf-index { display: flex; right: calc(var(--gutter) * 0.6); background: none; }
  .cf-index button { height: 34px; font-size: 13px; }
  .cf-prev { left: max(calc(var(--gutter) * 0.5), calc(50% - var(--card-h) * 0.85 - 72px)); }
  .cf-next { right: max(calc(var(--gutter) * 2), calc(50% - var(--card-h) * 0.85 - 72px)); }
  .cf-filters { margin-top: 28px; }
}

/* ---------- Entrada ---------- */
@keyframes fade-in { from { opacity: 0; } }
@keyframes rise-in { from { opacity: 0; transform: translateY(8px); } }
@keyframes line-in { from { transform: translateY(105%); } }
/* el renglón se enfoca mientras sube: de transparente y borroso a nítido (la borrosidad sigue al tamaño de la letra) */
@keyframes line-focus { from { opacity: 0; filter: blur(0.18em); } }
/* párrafo: aparece subiendo apenas y enfocándose (misma familia que los renglones, más corto y más suave) */
@keyframes text-in { from { opacity: 0; transform: translateY(12px); filter: blur(4px); } }

/* Hero: una sola coreografía, oculto hasta que el JS pone .is-in (con keyframes de CSS: corren fuera del hilo
   principal mientras la página todavía carga, y no pisan las transiciones propias de los botones).
   Orden: la línea chica (que se decodifica) → los tres renglones del titular, cada uno sube desde abajo de su
   máscara y pasa de borroso a nítido → la bajada → los botones → los símbolos de neón se encienden mientras el
   texto se asienta. Todos los tiempos salen de --in-0 (cuándo arranca el titular) y --in-line (entre renglones). */
.hero { --in-0: 60ms; --in-line: 90ms; }
/* ---- FX: textoDecodifica ---- la línea chica se decodifica primero y el titular arranca 180 ms después
   (.fx-decode la pone el JS solo con el efecto prendido y sin reduced-motion) */
.js.fx-decode .hero { --in-0: 180ms; }
.hero-title .ln:nth-child(2) { --n: 1; }
.hero-title .ln:nth-child(3) { --n: 2; }
.js body:not(.is-in) :is(.eyebrow, .lead, .hero-ctas .btn) { opacity: 0; }
.js body:not(.is-in) .hero-title .ln > span { transform: translateY(105%); }
.js .is-in .hero-title .ln > span {
  animation: line-in 1.1s var(--ease-pres) backwards, line-focus 1s cubic-bezier(0.33, 1, 0.68, 1) backwards;
  animation-delay: calc(var(--in-0) + var(--in-line) * var(--n, 0));
}
.js .is-in .eyebrow { animation: fade-in 0.6s var(--ease-out) backwards; }
.js .is-in .lead { animation: text-in 0.9s var(--ease-out) calc(var(--in-0) + 380ms) backwards; }
.js .is-in .hero-ctas .btn { animation: rise-in 0.7s var(--ease-pres) calc(var(--in-0) + 500ms) backwards; }
.js .is-in .hero-ctas .btn + .btn { animation-delay: calc(var(--in-0) + 560ms); }
/* Al cambiar de idioma applyLang arma los renglones de nuevo: vuelven a entrar, más rápido y sin esperar a nada */
.js .is-in .hero-title.is-swap { --in-0: 0ms; --in-line: 60ms; }
.js .is-in .hero-title.is-swap .ln > span { animation-duration: 0.8s, 0.6s; }
.eyebrow.is-decoding { white-space: nowrap; }

/* Carrusel: aparece cuando se abre el abanico (en celular, al llegar a la sección). El título y la frase de arriba
   entran solos al bajar (app.js, "Títulos y párrafos") */
.js .projects:not(.is-shown) :is(.cf-filters, .cf-arrow, .cf-index, .cf-count--mob) { opacity: 0; }
.js .projects.is-shown :is(.cf-filters, .cf-arrow, .cf-index, .cf-count--mob) { animation: fade-in 0.7s var(--ease-out) 200ms backwards; }
.cf.is-intro .card { transition: none; opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  /* el hero solo aparece, sin moverse ni desenfocarse */
  .js body:not(.is-in) .hero-title .ln > span { transform: none; opacity: 0; }
  .js .is-in .hero-title .ln > span { animation: fade-in 0.6s var(--ease-out) backwards; animation-delay: calc(var(--in-0) + var(--in-line) * var(--n, 0)); }
  .js .is-in .hero-title.is-swap .ln > span { animation-duration: 0.3s; }
  .js .is-in .lead { animation-name: fade-in; }
  .js .is-in .hero-ctas .btn,
  .menu.is-open .menu-links a { animation-name: fade-in; }
  .menu { transform: none; }
  .card { transition: opacity 0.25s linear !important; }
  .cf-track.is-dragging .card { transition: none !important; }
  .card-scale, .card-go, .btn, .btn .i, .card-in { transition: none !important; }
  .card-dim, .card-glow { transition-duration: 0.15s; }
  .card .card-scale { transform: none !important; }
}

/* ---------- Caso del proyecto ---------- */
/* Celular y tablet: hoja a pantalla completa que sube desde abajo. Compu: panel flotante que crece desde la card. */

/* Con el scroll bloqueado se compensa el ancho de la barra para que nada salte */
body.is-locked { padding-right: var(--sbw, 0px); }
body.is-locked .nav { padding-right: calc(var(--gutter) + var(--sbw, 0px)); }

.case {
  position: fixed; inset: 0; z-index: 70;
  display: flex; flex-direction: column; justify-content: flex-end;
}
.case[hidden] { display: none; }
/* Mientras se cierra no agarra clics: podés volver a tocar la card enseguida */
.case:not(.is-open) { pointer-events: none; }
.case-bg {
  position: absolute; inset: 0;
  background: rgba(8, 7, 20, 0.72);
  opacity: 0; transition: opacity 0.3s var(--ease-out);
}
.case.is-open .case-bg { opacity: 1; }
.case:not(.is-open) .case-bg { transition-duration: 0.2s; }

.case-panel {
  --glow: #a99dff;
  position: relative; z-index: 1;
  display: flex; flex-direction: column;
  width: 100%; height: calc(100% - 12px);
  border-radius: var(--r-card) var(--r-card) 0 0;
  /* Opaco en celular: sin desenfoque de fondo, para los Android de gama media */
  background: #0a0917;
  border: 1.5px solid var(--glow); border-bottom: 0;
  box-shadow: 0 0 8px -1px var(--glow), inset 0 0 6px -1px var(--glow), 0 -30px 80px -30px rgba(2, 1, 10, 0.9);
  outline: none;
  transform: translateY(100%);
  transition: transform 0.52s var(--ease-drawer), border-color 0.4s var(--ease-out), box-shadow 0.4s var(--ease-out);
  will-change: transform;
}
.case.is-open .case-panel { transform: none; }
.case:not(.is-open) .case-panel { transition-duration: 0.3s; }   /* la salida es más rápida que la entrada */
.case-panel.is-dragging { transition: none; }
/* Canto del vidrio, el mismo de la card */
.case-panel::before {
  content: ''; position: absolute; inset: 0; z-index: 6;
  border-radius: inherit; pointer-events: none;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.1),
    inset 1.5px 1.5px 0 -0.5px rgba(255, 255, 255, 0.55),
    inset -1px -1.5px 0 -0.5px rgba(255, 255, 255, 0.2),
    inset 0 22px 24px -20px rgba(255, 255, 255, 0.18),
    inset 0 0 30px rgba(255, 255, 255, 0.04);
}

/* Agarradera de la hoja */
.case-grab {
  position: absolute; left: 0; right: 0; top: 0; z-index: 7;
  height: 30px; display: grid; place-items: center;
  touch-action: none;
}
.case-grab span { width: 40px; height: 4px; border-radius: 2px; background: rgba(236, 232, 255, 0.28); }

.case-x {
  position: absolute; top: 14px; right: 14px; z-index: 8;
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line-2);
  background: rgba(2, 2, 3, 0.72);
  transition: border-color 0.2s var(--ease-out), background-color 0.2s var(--ease-out), transform 0.16s var(--ease-out);
}
.case-x:active { transform: scale(0.94); }
.case-x .i { width: 20px; height: 20px; }

.case-scroll {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 62px 0 28px;
}

/* Al pasar al siguiente proyecto el contenido se funde: sale rápido, entra tranquilo */
.case-grid {
  display: grid; gap: 26px;
  transition: opacity 0.26s var(--ease-out), transform 0.26s var(--ease-out);
}
.case-grid.is-swapping { opacity: 0; transform: translateY(6px); transition-duration: 0.14s; }
@media (min-width: 1024px) and (hover: hover) {
  .case-grid { transition-property: opacity, filter, transform; transition-duration: 0.26s; }
  .case-grid.is-swapping { filter: blur(4px); }
}

/* Galería: en celular es una tira con snap; en compu, una pila con fundido */
.case-strip {
  display: flex; gap: 12px;
  overflow-x: auto; scroll-snap-type: x mandatory;
  padding: 0 20px; scroll-padding: 0 20px;
  scrollbar-width: none;
}
.case-strip::-webkit-scrollbar { display: none; }
.case-item { flex: 0 0 calc(100% - 40px); scroll-snap-align: start; margin: 0; min-width: 0; }
.case-strip.is-single .case-item { flex-basis: 100%; }

/* El marco lleva el color de la marca del proyecto: es el único lugar del sitio donde aparece */
.case-frame {
  position: relative; aspect-ratio: 16 / 10; overflow: hidden;
  padding: 8px; border-radius: 16px;
  background: var(--brand, var(--night-3));
  border: 1.5px solid var(--brand-line, var(--line-2));
}
.case-frame img {
  width: 100%; height: 100%; border-radius: 9px;
  object-fit: cover; object-position: 50% 0;
  background: #0a0917;
  opacity: 0; transition: opacity 0.35s var(--ease-out);
}
.case-frame.is-loaded img { opacity: 1; }
/* Capturas verticales (celular): enteras sobre el color de la marca, con su sombra */
.case-frame[data-fit="contain"] img {
  object-fit: contain; object-position: 50% 50%;
  background: transparent; border-radius: 0;
  filter: drop-shadow(0 14px 22px rgba(2, 1, 10, 0.45));
}
/* Una sola captura vertical (Niner): el marco acompaña el formato del teléfono */
.case-strip.is-single .case-frame[data-fit="contain"],
.case-strip.is-phones .case-frame { aspect-ratio: 4 / 5; }
.case-cap { margin: 10px 4px 0; font-size: 13px; line-height: 1.45; color: var(--ink-3); text-wrap: pretty; }

.case-thumbs { display: none; }
.case-dots { display: flex; justify-content: center; gap: 6px; margin-top: 14px; }
.case-dots span {
  width: 6px; height: 6px; border-radius: 50%;
  background: rgba(236, 232, 255, 0.22);
  transition: background-color 0.2s var(--ease-out), transform 0.2s var(--ease-out);
}
.case-dots span.is-current { background: var(--brand-line, var(--ink)); transform: scale(1.25); }
.case-strip.is-single ~ .case-dots { display: none; }

/* Texto del caso */
.case-text { padding: 0 20px; }
.case-head { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 12px; }
.case-chip { display: inline-flex; align-items: center; gap: 8px; font-size: 13.5px; font-weight: 500; color: var(--ink-2); }
.case-panel[data-wip] .card-chip-ico { background: #3a3566; }
.case-title {
  margin-top: 16px;
  font-size: clamp(30px, 8.4vw, 40px); font-weight: 700; line-height: 1.02; letter-spacing: -0.03em;
  text-wrap: balance;
}
.case-what { margin-top: 12px; font-size: 17px; line-height: 1.5; color: var(--ink-soft); text-wrap: pretty; }
.case-block { margin-top: 24px; }
.case-block[hidden] { display: none; }
.case-label { font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.case-p { margin-top: 8px; font-size: 15.5px; line-height: 1.55; color: var(--ink-2); text-wrap: pretty; }
.case-details { margin-top: 8px; display: grid; gap: 7px; }
.case-details li { position: relative; padding-left: 18px; font-size: 15.5px; line-height: 1.5; color: var(--ink-2); text-wrap: pretty; }
.case-details li::before {
  content: ''; position: absolute; left: 0; top: 0.6em;
  width: 7px; height: 7px; border-radius: 50%; background: var(--violet-hi);
}
.case-tools {
  margin-top: 10px;
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px 14px;
  font-size: 14.5px; line-height: 1.45;
}
.case-tools dt { color: var(--ink-3); }
.case-tools dd { margin: 0; color: var(--ink-2); }

/* Pie: link del sitio y siguiente proyecto */
.case-foot {
  flex: none; position: relative; z-index: 2;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 12px 16px max(12px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
}
.case-visit { font-weight: 700; }
.case-visit[hidden] { display: none; }
.case-next {
  margin-left: auto; min-width: 0;
  display: inline-flex; align-items: center; gap: 12px;
  height: 46px; padding: 0 6px 0 16px; border-radius: 999px;
  border: 1px solid var(--line-2);
  text-align: left;
  transition: border-color 0.2s var(--ease-out), background-color 0.2s var(--ease-out), transform 0.16s var(--ease-out);
}
.case-next:active { transform: scale(0.97); }
.case-next[hidden] { display: none; }
.case-next-txt { display: flex; flex-direction: column; gap: 2px; line-height: 1.1; min-width: 0; }
.case-next-txt small { font-size: 11px; font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); }
.case-next-txt b { font-size: 14.5px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.case-next-ico {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1.5px solid #5b7cff;
  background: rgba(74, 108, 255, 0.14);
  box-shadow: 0 0 8px -2px rgba(74, 108, 255, 0.6);
  transition: background-color 0.2s var(--ease-out);
}
.case-next-ico .i { width: 17px; height: 17px; transition: transform 0.25s var(--ease-out); }

@media (hover: hover) and (pointer: fine) {
  .case-x:hover { border-color: var(--ink-2); background: rgba(26, 23, 54, 0.9); }
  .case-next:hover { border-color: var(--ink-2); background: rgba(236, 232, 255, 0.05); }
  .case-next:hover .case-next-ico { background: var(--blue); }
  .case-next:hover .i { transform: translateX(3px); }
}

/* Tablet: la misma hoja, con más aire */
@media (min-width: 768px) and (max-width: 1023px) {
  .case-strip { padding: 0 32px; scroll-padding: 0 32px; }
  .case-item { flex-basis: calc(100% - 64px); }
  .case-text, .case-foot { padding-left: 32px; padding-right: 32px; }
  .case-grid { gap: 30px; }
}

/* Compu: panel flotante de vidrio sobre la página desenfocada */
@media (min-width: 1024px) {
  .case { justify-content: center; align-items: center; padding: 28px var(--gutter); }
  .case-bg {
    background: rgba(8, 7, 20, 0.6);
    -webkit-backdrop-filter: blur(14px) saturate(1.2);
    backdrop-filter: blur(14px) saturate(1.2);
  }
  .case-panel {
    width: min(1160px, 100%); height: auto; max-height: min(100%, 840px);
    border-radius: var(--r-card); border-bottom: 1.5px solid var(--glow);
    background: rgba(6, 5, 13, 0.9);
    -webkit-backdrop-filter: blur(18px) saturate(1.8) brightness(1.08);
    backdrop-filter: blur(18px) saturate(1.8) brightness(1.08);
    box-shadow: 0 0 6px -1px var(--glow), inset 0 0 6px -1px var(--glow), 0 40px 90px -30px rgba(2, 1, 10, 0.95);
    /* Crece desde la card que tocaste (--ox / --oy los pone el JS) */
    transform: scale(0.84); opacity: 0;
    transform-origin: var(--ox, 50%) var(--oy, 50%);
    transition: transform 0.46s var(--ease-pres), opacity 0.26s var(--ease-out), border-color 0.4s var(--ease-out), box-shadow 0.4s var(--ease-out);
  }
  .case.is-open .case-panel { opacity: 1; transform: none; }
  .case:not(.is-open) .case-panel { transform: scale(0.94); transition: transform 0.22s var(--ease-out), opacity 0.18s var(--ease-out); }
  .case-grab { display: none; }
  .case-x { top: 16px; right: 16px; }
  .case-scroll { padding: 0; }
  .case-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr); gap: 44px;
    align-items: start;
    padding: 34px 40px 26px;
  }
  .case-gallery { position: sticky; top: 0; }
  .case-text { padding: 2px 44px 0 0; }

  .case-strip { display: grid; gap: 0; padding: 0; overflow: visible; scroll-snap-type: none; }
  .case-item {
    grid-area: 1 / 1; flex: none;
    opacity: 0; visibility: hidden; filter: blur(5px);
    transition: opacity 0.26s var(--ease-out), filter 0.26s var(--ease-out), visibility 0s 0.26s;
  }
  .case-item.is-current { opacity: 1; visibility: visible; filter: none; transition-delay: 0s; }
  .case-frame { padding: 10px; border-radius: 18px; }
  .case-frame img { border-radius: 10px; }
  .case-strip.is-single .case-frame[data-fit="contain"],
  .case-strip.is-phones .case-frame { aspect-ratio: 5 / 4; }
  .case-dots { display: none; }
  .case-thumbs { display: flex; gap: 8px; margin-top: 12px; }
  .case-strip.is-single ~ .case-thumbs { display: none; }
  .case-thumbs button {
    width: 86px; aspect-ratio: 16 / 10; border-radius: 8px; overflow: hidden;
    border: 1.5px solid var(--line); background: #0a0917;
    opacity: 0.65;
    transition: opacity 0.2s var(--ease-out), border-color 0.2s var(--ease-out), transform 0.16s var(--ease-out);
  }
  .case-thumbs button:active { transform: scale(0.96); }
  .case-thumbs button img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 0; }
  .case-thumbs button[data-fit="contain"] img { object-fit: contain; }
  .case-thumbs button[aria-pressed="true"] { opacity: 1; border-color: var(--brand-line, var(--brand)); }
  .case-thumbs button:hover { opacity: 1; }

  .case-title { font-size: clamp(32px, 2.9vw, 42px); }
  .case-foot { padding: 14px 40px 18px; }

  /* Entrada del contenido: primero la galería, después el texto */
  .case.is-open .case-gallery { animation: rise-in 0.55s var(--ease-pres) 0.1s backwards; }
  .case.is-open .case-text { animation: rise-in 0.55s var(--ease-pres) 0.17s backwards; }
  .case.is-open .case-foot { animation: fade-in 0.4s var(--ease-out) 0.24s backwards; }
}
@media (min-width: 1024px) and (max-height: 760px) {
  .case { padding-top: 20px; padding-bottom: 20px; }
  .case-grid { gap: 36px; padding: 28px 36px 22px; }
  .case-title { font-size: 32px; }
  .case-block { margin-top: 20px; }
}

@media (prefers-reduced-motion: reduce) {
  .case-panel, .case:not(.is-open) .case-panel {
    transform: none !important;
    transition: opacity 0.2s linear, border-color 0.2s linear, box-shadow 0.2s linear !important;
    opacity: 0;
  }
  .case.is-open .case-panel { opacity: 1; }
  .case.is-open .case-gallery, .case.is-open .case-text, .case.is-open .case-foot { animation: fade-in 0.3s linear backwards; }
  .case-grid, .case-item { filter: none !important; transform: none !important; transition-duration: 0.15s !important; }
  .case-dots span, .case-next-ico .i { transition: none; }
}

/* ---------- Stack: macropad 5×5 ---------- */
/* Un macropad en 3D con una tecla por herramienta, pintada del color de su marca. Al tocarla, el panel
   "Dónde lo usé" muestra los proyectos. Celular: de frente y apenas inclinado. Compu: inclinado y girado, sigue al mouse. */

.stack {
  position: relative;
  padding: clamp(72px, 10vw, 128px) var(--gutter) clamp(64px, 8vw, 104px);
}
.stack-head { max-width: 640px; }
.stack-sub { margin-top: var(--gap-head); font-size: var(--fs-sub); line-height: 1.55; color: var(--ink-2); max-width: 32em; text-wrap: pretty; }
.stack-body { margin-top: 32px; display: grid; gap: 40px; }

/* Escena */
.pad-scene {
  --rx: 26deg; --rz: 0deg;
  perspective: 1400px; perspective-origin: 50% 18%;
  display: grid; place-items: center;
  padding: 96px 0 36px;
}
.pad {
  position: relative; width: min(100%, 460px);
  transform-style: preserve-3d;
  transform: rotateX(var(--rx)) rotateZ(var(--rz));
}
/* Sombra en el piso */
.pad-shadow {
  position: absolute; inset: 6% -3% -8% -3%; border-radius: 26%;
  background: rgba(2, 1, 10, 0.8);
  filter: blur(26px);
  transform: translateZ(-20px);
  pointer-events: none;
}
/* Placa del macropad, con su grosor en dos capas por debajo */
.pad-plate {
  position: relative; transform-style: preserve-3d;
  padding: 14px; border-radius: 22px;
  background: #1c1a38;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), inset 0 0 0 1px rgba(255, 255, 255, 0.05), inset 0 -1px 0 rgba(0, 0, 0, 0.5);
}
.pad-plate::before, .pad-plate::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  background: #110f24;
  transform: translateZ(-8px);
}
.pad-plate::after { inset: -1px; background: #0b0a1a; transform: translateZ(-16px); }

/* Cablecito USB: sale por el borde de atrás y se va hacia la compu */
.pad-cable {
  position: absolute; left: 50%; bottom: 100%;
  width: 130px; height: 110px; margin: 0 0 -8px -18px;
  transform: translateZ(-10px);
  overflow: visible; pointer-events: none;
}
.pad-cable-line { fill: none; stroke: #2b2849; stroke-width: 9; stroke-linecap: round; }
.pad-cable-core { fill: none; stroke: #403c6b; stroke-width: 2.5; stroke-linecap: round; }
.pad-cable-plug { fill: #8f93aa; stroke: #2b2849; stroke-width: 1.5; }

/* Teclas: la base oscura es el lateral que asoma; el capuchón flota encima y baja al tocar */
.pad-keys {
  display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px;
  transform-style: preserve-3d;
}
.key {
  --kz: 11px;
  position: relative; aspect-ratio: 1; border-radius: 11px;
  background: var(--kd);
  transform-style: preserve-3d;
  box-shadow: 0 10px 18px -8px rgba(2, 1, 10, 0.7);
  -webkit-tap-highlight-color: transparent;
}
.key:focus-visible { outline-offset: 5px; }
.key-cap {
  position: absolute; inset: 0; border-radius: inherit;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  padding: 4px;
  background: var(--kc); color: var(--kt);
  transform: translateZ(var(--kz));
  transition: transform 0.18s var(--ease-out), box-shadow 0.25s var(--ease-out);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    inset 0 -1.5px 0 rgba(0, 0, 0, 0.22),
    inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}
.key-ico { width: 20px; height: 20px; fill: currentColor; }
.key-name {
  font-size: 9.5px; font-weight: 700; line-height: 1.05; letter-spacing: 0.01em;
  text-align: center; text-wrap: balance;
}
.key--text .key-name { font-size: 12px; letter-spacing: 0.02em; }
.key:active { --kz: 2px; }
/* La tecla activa queda hundida y con su LED prendido */
.key[aria-pressed="true"] { --kz: 3px; }
.key[aria-pressed="true"] .key-cap {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    inset 0 -1.5px 0 rgba(0, 0, 0, 0.22),
    inset 0 0 0 1px rgba(255, 255, 255, 0.1),
    0 0 22px 2px var(--kg);
}
@media (hover: hover) and (pointer: fine) {
  .key:not([aria-pressed="true"]):hover { --kz: 6px; }
}
/* ---- FX: tecladoOla ---- un proyecto bajo el mouse hunde sus teclas en ola (la clase la pone app.js de a una).
   Solo baja el capuchón: el color y el LED de la elegida no cambian, y al sacar la clase vuelve a su altura. */
.stack .pad-keys .key.is-wave { --kz: 2px; }

/* Al llegar a la sección, los capuchones suben en diagonal (una vez) */
/* (el título y la frase de arriba entran solos al bajar: app.js, "Títulos y párrafos") */
.js .stack:not(.is-shown) .tool { opacity: 0; }
.js .stack.is-shown .tool { animation: rise-in 0.7s var(--ease-pres) 0.35s backwards; }
.js .stack:not(.is-shown) .key-cap { transform: translateZ(0); }
.js .stack.is-shown:not(.is-settled) .key-cap { transition: transform 0.6s var(--ease-pres) calc(var(--i) * 28ms); }

/* Panel "Dónde lo usé" */
.tool {
  position: relative;
  transition: opacity 0.24s var(--ease-out), transform 0.24s var(--ease-out);
}
.tool.is-swapping { opacity: 0; transform: translateY(4px); transition-duration: 0.12s; }
.tool-head { display: flex; align-items: center; gap: 16px; }
.tool-ico {
  flex: none; width: 60px; height: 60px; border-radius: 16px;
  display: grid; place-items: center;
  background: var(--kc, var(--violet)); color: var(--kt, #fff);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), inset 0 -1.5px 0 rgba(0, 0, 0, 0.2), 0 16px 30px -14px var(--kg, transparent);
}
.tool-ico-svg { width: 30px; height: 30px; fill: currentColor; }
.tool-ico-svg[hidden] { display: none; }
.tool-ico-txt { font-size: 13px; font-weight: 900; letter-spacing: 0.02em; }
.tool-ico-txt:empty { display: none; }
.tool-name { font-size: clamp(26px, 2.4vw, 34px); font-weight: 700; letter-spacing: -0.03em; line-height: 1; }
.tool-cat { margin-top: 6px; font-size: 13.5px; color: var(--ink-3); }
.tool-label { margin-top: 26px; font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.tool-uses { margin-top: 6px; display: grid; }
.tool-use {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 10px 8px; border-radius: 12px;
  text-align: left; color: var(--ink);
}
button.tool-use { transition: transform 0.16s var(--ease-out); }
button.tool-use:active { transform: scale(0.985); }
.tool-use-ico {
  flex: none; width: 30px; height: 30px; border-radius: 9px;
  display: grid; place-items: center;
  background: var(--violet); color: #fff;
}
.tool-use-ico .i { width: 16px; height: 16px; stroke-width: 2; }
div.tool-use .tool-use-ico { background: #2b2852; color: var(--ink-soft); }
.tool-use-txt { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.tool-use-txt b { font-size: 15.5px; font-weight: 700; letter-spacing: -0.01em; line-height: 1.2; }
.tool-use-txt small { font-size: 13.5px; line-height: 1.4; color: var(--ink-2); text-wrap: pretty; }
.tool-use-go {
  margin-left: auto; flex: none; width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1.5px solid #5b7cff;
  background: rgba(74, 108, 255, 0.14);
  color: var(--ink);
  transition: background-color 0.2s var(--ease-out);
}
.tool-use-go .i { width: 15px; height: 15px; transition: transform 0.25s var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  /* Pedido de Santi: al pasar el mouse la fila se pone blanca de una, sin animación (y el cursor no la abraza) */
  button.tool-use:hover { background: #f3f1fb; color: #0b0b10; }
  button.tool-use:hover .tool-use-txt small { color: #4a4760; }
  button.tool-use:hover .tool-use-go { background: #0b0b10; border-color: #0b0b10; color: #f3f1fb; transition: none; }
  button.tool-use:hover .tool-use-go .i { transition: none; }
}

/* Las herramientas dentro del caso llevan a su tecla */
.case-tool {
  display: inline; padding: 0 1px; border-radius: 4px;
  color: var(--ink-2);
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
  text-decoration-color: rgba(173, 148, 255, 0.5);
  transition: color 0.2s var(--ease-out), text-decoration-color 0.2s var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .case-tool:hover { color: var(--ink); text-decoration-color: var(--violet-hi); }
}

/* Lista simple: se ve sin JS */
.stack-noscript { display: none; gap: 10px; }
.stack-noscript li { padding: 16px 18px; border: 1px solid var(--line); border-radius: 16px; color: var(--ink-2); font-size: 15px; }
.stack-noscript b { display: block; color: var(--ink); margin-bottom: 4px; }
.no-js .stack-noscript { display: grid; }
.no-js .pad-scene, .no-js .tool { display: none; }

/* Tablet: una columna, el macropad centrado y el panel más angosto */
@media (min-width: 768px) and (max-width: 1023px) {
  .pad-scene { --rx: 34deg; --rz: -6deg; padding: 96px 0 48px; }
  .pad { width: min(100%, 520px); }
  .pad-cable { width: 220px; height: 186px; }
  .key-ico { width: 24px; height: 24px; }
  .key-name { font-size: 11px; }
  .tool { max-width: 560px; }
}

/* Compu: macropad a la izquierda, inclinado y girado; panel a la derecha */
@media (min-width: 1024px) {
  .stack-body {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    align-items: center; gap: clamp(40px, 5vw, 88px);
    margin-top: 44px;
  }
  .pad-scene {
    --rx: 54deg; --rz: -16deg;
    perspective: 1700px; perspective-origin: 50% 32%;
    padding: 16px 0 60px;
  }
  .pad { width: min(84%, 470px); }
  .pad-plate { padding: 16px; }
  .pad-keys { gap: 10px; }
  .key { --kz: 12px; border-radius: 12px; }
  .key-ico { width: 24px; height: 24px; }
  .key-name { font-size: 10.5px; }
  .key--text .key-name { font-size: 13px; }
  .pad-cable { width: 260px; height: 220px; margin-left: -30px; }
  .tool { min-height: 560px; padding-top: 24px; }
  .tool-label { margin-top: 30px; }
}

@media (prefers-reduced-motion: reduce) {
  .js .stack:not(.is-shown) .key-cap { transform: translateZ(var(--kz)); }
  .key-cap { transition: box-shadow 0.2s linear !important; }
  .js .stack.is-shown .tool { animation-name: fade-in; }
  .tool, .tool.is-swapping { transform: none; transition-duration: 0.12s; }
}

/* ---------- Cielo ---------- */
/* Fondo negro con estrellas que titilan (canvas fijo detrás de todo; lo dibuja el JS) */
.sky {
  position: fixed; left: 0; top: 0; z-index: -1;
  width: 100%; height: 100lvh;
  pointer-events: none;
}

/* ---------- Teclado 3D (Spline) ---------- */
/* El macropad en CSS queda en el DOM (es el que usan el teclado del navegador y los lectores de pantalla), pero no se
   muestra: desde el primer pintado se reserva el lugar del teclado 3D, así nunca aparece el viejo antes del nuevo.
   Solo vuelve el de CSS si el JS pone .no-3d (sin WebGL, ahorro de datos o falla) o con reduced-motion. */
.pad3d { display: none; }
.pad3d-canvas { display: block; width: 100% !important; height: 100% !important; touch-action: pan-y; }
.pad3d-wait {
  position: absolute; left: 50%; top: 50%;
  width: 28px; height: 28px; margin: -14px 0 0 -14px; border-radius: 50%;
  border: 2px solid var(--line-2); border-top-color: var(--ink-2);
  animation: spin 0.9s linear infinite;
  opacity: 0; transition: opacity 0.3s var(--ease-out) 0.6s;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: no-preference) {
  .js .stack:not(.no-3d) .pad-scene {
    position: relative; perspective: none; padding: 0; display: block;
    height: clamp(320px, 88vw, 440px);
    margin-inline: calc(-1 * var(--gutter));   /* en el celular el teclado va de borde a borde */
  }
  .js .stack:not(.no-3d) .pad {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
    transform: none !important;
  }
  .js .stack:not(.no-3d) :is(.pad-shadow, .pad-cable) { display: none; }
  .js .stack:not(.no-3d) .pad3d { display: block; position: absolute; inset: 0; border-radius: 24px; }
  .js .stack:not(.no-3d):not(.has-3d) .pad3d-wait { opacity: 1; }
  .stack.has-3d .pad3d-wait { display: none; }
  .stack.has-3d .pad3d-canvas { animation: fade-in 0.7s var(--ease-out) backwards; }
  /* Con el teclado del navegador, la tecla enfocada está escondida: el aro de foco va alrededor del teclado 3D */
  .js .stack:not(.no-3d) .pad-scene:has(.key:focus-visible) .pad3d { outline: 2px solid var(--violet-hi); outline-offset: -3px; }
  @media (min-width: 768px) {
    .js .stack:not(.no-3d) .pad-scene { margin-inline: 0; }
  }
  /* Tablet: el teclado va de frente, el lienzo no necesita tanto alto */
  @media (min-width: 768px) and (max-width: 1023px) {
    .js .stack:not(.no-3d) .pad-scene { height: 470px; }
  }
  /* 1024–1199: el teclado a lo ancho y el panel debajo (en dos columnas quedaba chico) */
  @media (min-width: 1024px) and (max-width: 1199px) {
    .js .stack:not(.no-3d) .stack-body { grid-template-columns: minmax(0, 1fr); gap: 32px; margin-top: 20px; }
    .js .stack:not(.no-3d) .pad-scene { height: 540px; }
    .js .stack:not(.no-3d) .tool { min-height: 0; max-width: 640px; padding-top: 0; }
  }
  @media (min-width: 1200px) {
    .js .stack:not(.no-3d) .stack-body { grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr); gap: clamp(32px, 4vw, 64px); margin-top: 20px; }
    .js .stack:not(.no-3d) .pad-scene { height: 560px; }
  }
}

/* ---------- Cursor ---------- */
/* Un círculo blanco que invierte lo que tiene detrás (mix-blend-mode: difference, liviano incluso sobre el 3D),
   sigue al mouse con gsap.quickTo, se estira apenas cuando vas rápido y abraza los botones. La flecha queda. */
.cursor-jelly, .cursor-dot {
  position: fixed; left: 0; top: 0; z-index: 300;
  pointer-events: none;
  mix-blend-mode: difference;
  opacity: 0;
  transition: opacity 0.25s var(--ease-out);
}
.cursor-jelly { width: 0; height: 0; }
.cursor-shape {
  position: absolute; left: 0; top: 0;
  width: 40px; height: 40px; border-radius: 20px;
  background: #fff;
  will-change: transform, width, height;
}
.cursor-dot { z-index: 301; width: 8px; height: 8px; border-radius: 50%; background: #fff; }
html.has-cursor.cursor-on .cursor-jelly, html.has-cursor.cursor-on .cursor-dot { opacity: 1; }
html.cursor-wrapping .cursor-dot { opacity: 0 !important; }
/* Sobre las filas de "Dónde lo usé" el círculo se esconde: la fila ya se pone blanca */
html.cursor-quiet .cursor-jelly { opacity: 0 !important; transition: none; }
/* Sobre los símbolos de neón el círculo y el punto se apagan suave (el símbolo crece, esa es la respuesta; invertidos
   sobre el brillo se verían de otro color) y queda la flecha */
html.cursor-hush :is(.cursor-jelly, .cursor-dot) { opacity: 0 !important; }
html:not(.has-cursor) .cursor-jelly, html:not(.has-cursor) .cursor-dot { display: none; }
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .cursor-jelly, .cursor-dot { display: none !important; }
}
/* Los botones que el cursor abraza se corren un poco hacia el puntero */
.is-magnetic { translate: var(--mx, 0px) var(--my, 0px); }

/* ---- FX: cursorPalabra ---- sobre el carrusel, la card del frente y la galería del caso, el cursor se estira a
   una cápsula con una palabra. La cápsula va aparte, SIN mix-blend-mode (si no, la palabra sale invertida):
   blanca como las filas de "Dónde lo usé", texto oscuro, sin color. El JS la pone encima del círculo. */
.cursor-label {
  position: fixed; left: 0; top: 0; z-index: 302;
  width: 40px; height: 34px; border-radius: 17px;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  background: #f3f1fb; color: #0b0b10;
  box-shadow: 0 10px 28px -12px rgba(2, 1, 10, 0.8);
  pointer-events: none;
  opacity: 0; visibility: hidden;
  will-change: transform, width;
}
.cursor-label-in {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  font-size: 13px; font-weight: 700; letter-spacing: 0.01em; line-height: 1; white-space: nowrap;
}
.cursor-label-in .i { width: 13px; height: 13px; stroke-width: 2.4; flex: none; }
@media (min-width: 1024px) and (hover: hover) and (pointer: fine) {
  html.fx-cursor-word .case-strip:not(.is-single) { cursor: pointer; }   /* en compu, clic en la captura = la siguiente */
}
/* Mientras la cápsula está a la vista, ella es el cursor: la flecha/manito del sistema no se muestra */
@media (hover: hover) and (pointer: fine) {
  html.cursor-word-on, html.cursor-word-on * { cursor: none !important; }
}
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .cursor-label { display: none !important; }
}

/* ---- FX: miniaturaFlotante ---- vista previa vertical del proyecto que sigue al mouse en las filas de
   "Dónde lo usé" y en "Siguiente proyecto". Es la imagen de su card con el mismo neón (borde + brillo corto). */
.fx-thumb {
  position: fixed; left: 0; top: 0; z-index: 250;
  width: 172px; height: 220px; border-radius: 16px;
  overflow: hidden;
  background: #0b0b10;
  border: 1.5px solid var(--glow, #a99dff);
  box-shadow: 0 0 8px -1px var(--glow, #a99dff), inset 0 0 6px -1px var(--glow, #a99dff), 0 30px 60px -24px rgba(2, 1, 10, 0.95);
  transition: border-color 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out);
  pointer-events: none;
  opacity: 0; visibility: hidden;
  will-change: transform, opacity;
}
.fx-thumb img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 32%;
  opacity: 0;
}
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .fx-thumb { display: none !important; }
}

/* ---------- Títulos de sección: misma escala en toda la página ----------
   Un solo tamaño para los cuatro (Proyectos, Stack, Sobre mí, Contacto), siempre un escalón debajo del titular del
   hero, con los renglones equilibrados. Al bajar entran renglón por renglón (app.js, "Títulos y párrafos"):
   SplitText arma .split-line dentro de una máscara .split-line-mask (overflow: clip). El padding de la máscara,
   devuelto con margen negativo, deja lugar a los descendentes y a la borrosidad de la entrada sin mover nada. */
.projects-title, .stack-title, .about-title, .contact-title {
  font-size: var(--fs-h2); font-weight: 700; line-height: 1.06; letter-spacing: -0.03em;
  text-wrap: balance;
}
.split-line { display: block; }
.split-line-mask { display: block; padding: 0 0.16em 0.12em; margin: 0 -0.16em -0.12em; }

/* ---------- Sobre mí ---------- */
.about {
  position: relative;
  padding: clamp(80px, 12vw, 152px) var(--gutter) clamp(56px, 8vw, 96px);
  display: grid; gap: 40px;
}
.about-photo { margin: 0; border-radius: var(--r-card); overflow: hidden; background: #0b0b10; aspect-ratio: 4 / 5; }
.about-photo img { width: 100%; height: 100%; object-fit: cover; }
.about-copy { max-width: 760px; }
/* Párrafos: ancho de lectura de ~65 caracteres (en em, así la frase grande ocupa su propio ancho) y un poco más de
   interlineado que lo normal, porque es texto claro sobre negro */
.about-text { margin-top: 22px; display: grid; gap: 16px; max-width: 36em; }
.about-text p { max-width: var(--measure); font-size: var(--fs-body); line-height: 1.65; color: var(--ink-soft); text-wrap: pretty; }
.about-quote {
  margin-top: 6px; padding-top: 18px; border-top: 1px solid var(--line);
  font-size: clamp(20px, 2.2vw, 24px) !important; line-height: 1.35 !important; font-weight: 500;
  color: var(--ink) !important; letter-spacing: -0.012em;
}
.about-langs { font-size: 14.5px !important; color: var(--ink-3) !important; }
/* ---- FX: fraseEnciende ---- la frase de método más grande: es el momento de la sección (las palabras las enciende app.js) */
.about-quote.fx-frase {
  margin-top: 10px; padding-top: 24px;
  font-size: clamp(24px, 2.4vw, 31px) !important; line-height: 1.24 !important; letter-spacing: -0.022em;
}
/* ---- FX: fotoSobreMi ---- 12 % de sobra (6 % arriba y abajo) para que la foto se mueva dentro del marco */
.about-photo.fx-foto { position: relative; }
.about-photo.fx-foto img { position: absolute; left: 0; top: -6%; height: 112%; will-change: transform; }
.about-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
/* Cards con relieve: una placa de vidrio más clara que la noche (las estrellas de atrás se borronean), con el canto
   de arriba encendido como en las cards del carrusel y una sombra que la despega del fondo. El ícono va hundido
   en la placa. Todo con luz y colores lisos, sin degradés. */
.about-card {
  position: relative;
  display: flex; flex-direction: column; gap: 8px;
  padding: 20px 18px 22px;
  border-radius: var(--r-card);
  background: rgba(38, 34, 70, 0.62);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  backdrop-filter: blur(14px) saturate(1.4);
  border: 1px solid rgba(236, 232, 255, 0.15);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.2),
    inset 0 -1px 0 rgba(0, 0, 0, 0.35),
    0 0 0 1px rgba(2, 2, 3, 0.6),
    0 26px 48px -26px rgba(0, 0, 0, 1),
    0 14px 36px -24px rgba(173, 148, 255, 0.22);
  transition: border-color 0.3s var(--ease-out), background-color 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out), transform 0.3s var(--ease-out);
}
.about-card-ico {
  width: 44px; height: 44px; border-radius: 14px; margin-bottom: 6px;
  display: grid; place-items: center;
  background: rgba(4, 3, 12, 0.55);
  border: 1px solid rgba(236, 232, 255, 0.16);
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.55), 0 1px 0 rgba(255, 255, 255, 0.07);
  color: var(--ink);
}
.about-card-ico .i { width: 22px; height: 22px; }
.about-card b { font-size: 16.5px; font-weight: 700; line-height: 1.2; letter-spacing: -0.01em; }
.about-card > span:last-child { font-size: 14px; line-height: 1.45; color: var(--ink-soft); text-wrap: pretty; }
@media (hover: hover) and (pointer: fine) {
  .about-card:hover {
    border-color: rgba(236, 232, 255, 0.26); background: rgba(46, 41, 84, 0.68); transform: translateY(-3px);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.28),
      inset 0 -1px 0 rgba(0, 0, 0, 0.35),
      0 0 0 1px rgba(2, 2, 3, 0.6),
      0 32px 56px -26px rgba(0, 0, 0, 1),
      0 18px 44px -24px rgba(173, 148, 255, 0.3);
  }
}
/* En pantallas táctiles, sin desenfoque (cuida a los Android de gama media): la placa va lisa, del mismo tono */
@media (hover: none), (pointer: coarse) {
  .about-card { -webkit-backdrop-filter: none; backdrop-filter: none; background: #18152b; }
}
@media (min-width: 768px) {
  .about-cards { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
}
@media (min-width: 1024px) {
  .about { grid-template-columns: minmax(0, 1fr); gap: 56px; }
  .about.has-photo { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); align-items: center; }
  .about.has-photo .about-cards { grid-column: 1 / -1; }
  .about-copy { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(32px, 5vw, 88px); max-width: none; align-items: start; }
  .about.has-photo .about-copy { grid-template-columns: 1fr; }
  .about-text { margin-top: 6px; }
}

/* ---------- Contacto ---------- */
.contact {
  position: relative;
  scroll-margin-top: 32px;
  margin: 0 var(--gutter);
  padding: clamp(36px, 6vw, 72px) clamp(20px, 5vw, 72px);
  border-radius: var(--r-card);
  border: 1px solid var(--line);
  background: rgba(4, 4, 7, 0.72);
  display: grid; gap: 40px;
}
.contact-t1, .contact-t2 { display: block; }
.contact-lead { margin-top: calc(var(--gap-head) + 4px); max-width: var(--measure); font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink-soft); text-wrap: pretty; }
.contact-mail { margin-top: 30px; }
.contact-mail-label { display: block; font-size: 13px; font-weight: 500; color: var(--ink-3); }
.contact-mail-row { margin-top: 6px; display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; }
.contact-mail-link {
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: clamp(19px, 2.4vw, 24px); font-weight: 700; letter-spacing: -0.015em;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 5px;
  text-decoration-color: var(--line-2);
  overflow-wrap: anywhere;
  transition: text-decoration-color 0.2s var(--ease-out);
}
.copy-btn {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  height: 44px; padding: 0 16px 0 13px; border-radius: 999px;
  border: 1px solid var(--line-2);
  font-size: 14px; font-weight: 500; color: var(--ink);
  transition: border-color 0.2s var(--ease-out), background-color 0.2s var(--ease-out), transform 0.16s var(--ease-out);
}
.copy-btn:active { transform: scale(0.97); }
.copy-btn .i { width: 17px; height: 17px; transition: transform 0.3s var(--ease-pres), opacity 0.2s var(--ease-out); }
.copy-ok { position: absolute; left: 13px; opacity: 0; transform: scale(0.6); color: #7ee2a8; }
.copy-btn.is-done { border-color: rgba(126, 226, 168, 0.55); }
.copy-btn.is-done .copy-ico { opacity: 0; transform: scale(0.6); }
.copy-btn.is-done .copy-ok { opacity: 1; transform: scale(1); }
.contact-gh {
  margin-top: 22px;
  display: inline-flex; align-items: center; gap: 10px; min-height: 44px;
  font-size: 15px; color: var(--ink-2);
  transition: color 0.2s var(--ease-out);
}
.contact-gh .i { width: 19px; height: 19px; }
@media (hover: hover) and (pointer: fine) {
  .contact-mail-link:hover { text-decoration-color: var(--ink-2); }
  .copy-btn:hover { border-color: var(--ink-2); background: rgba(255, 255, 255, 0.04); }
  .contact-gh:hover { color: var(--ink); }
}

/* Formulario */
.form { display: grid; gap: 18px; }
.form[hidden] { display: none; }
.field { display: grid; gap: 7px; margin: 0; padding: 0; border: 0; min-width: 0; }
.field label, .field legend { font-size: 14px; font-weight: 500; color: var(--ink-2); padding: 0; }
.field-opt { margin-left: 4px; font-size: 13px; font-weight: 400; color: var(--ink-3); }
.field input[type="text"], .field input[type="email"], .field input[type="tel"], .field textarea {
  width: 100%;
  font: inherit; font-size: 16px; color: var(--ink);
  padding: 13px 15px; border-radius: 14px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--line-2);
  outline: 2px solid transparent; outline-offset: 2px;
  transition: border-color 0.2s var(--ease-out), box-shadow 0.2s var(--ease-out), background-color 0.2s var(--ease-out);
}
.field textarea { resize: vertical; min-height: 132px; line-height: 1.5; }
.field input::placeholder, .field textarea::placeholder { color: #7d7a95; }
.field input:focus-visible, .field textarea:focus-visible {
  border-color: var(--violet-hi);
  box-shadow: 0 0 0 3px rgba(173, 148, 255, 0.22);
  background: rgba(255, 255, 255, 0.045);
}
.field :is(input, textarea)[aria-invalid="true"] { border-color: #ff8a8a; }
.field :is(input, textarea)[aria-invalid="true"]:focus-visible { border-color: #ff8a8a; box-shadow: 0 0 0 3px rgba(255, 138, 138, 0.2); }
.field-error { min-height: 0; font-size: 13.5px; line-height: 1.4; color: #ff9d9d; }
.field-error:empty { display: none; }
.type-pills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px; }
.type-pill { position: relative; cursor: pointer; }
.type-pill input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.type-pill span {
  display: inline-flex; align-items: center; height: 44px; padding: 0 16px; border-radius: 999px;
  border: 1px solid var(--line-2);
  font-size: 14.5px; font-weight: 500; color: var(--ink-2);
  transition: background-color 0.2s var(--ease-out), border-color 0.2s var(--ease-out), color 0.2s var(--ease-out), transform 0.16s var(--ease-out);
}
.type-pill:active span { transform: scale(0.97); }
.type-pill input:checked + span { background: var(--ink); border-color: var(--ink); color: #0b0b10; }
.type-pill input:focus-visible + span { outline: 2px solid var(--violet-hi); outline-offset: 3px; }
@media (hover: hover) and (pointer: fine) {
  .type-pill:hover input:not(:checked) + span { border-color: var(--ink-2); color: var(--ink); }
}
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 12px 18px; margin-top: 4px; }
.form-send { min-width: 148px; }
.form-send[disabled] { opacity: 0.75; cursor: progress; }
.form-send.is-sending .i { animation: send-nudge 0.9s var(--ease-move) infinite; }
@keyframes send-nudge { 50% { transform: translateX(4px); } }
.form-status { font-size: 14px; line-height: 1.45; color: #ff9d9d; text-wrap: pretty; max-width: 36em; }
.form-status:empty { display: none; }
.form-done {
  display: grid; justify-items: start; gap: 10px;
  padding: 28px; border-radius: var(--r-card);
  border: 1px solid rgba(126, 226, 168, 0.35);
  background: rgba(126, 226, 168, 0.05);
  outline: none;
}
.form-done[hidden] { display: none; }
.form-done-ico { width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center; background: #7ee2a8; color: #0b0b10; }
.form-done-ico .i { width: 22px; height: 22px; stroke-width: 2.4; }
.form-done-t { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; }
.form-done-p { color: var(--ink-soft); margin-bottom: 6px; }
@media (min-width: 1024px) {
  .contact { grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr); gap: clamp(40px, 6vw, 96px); align-items: start; }
}

/* ---------- Franja de cierre con firma ---------- */
/* La firma sola a la izquierda (es la despedida) y la caja centrada en su altura a la derecha */
.closing {
  padding: clamp(64px, 9vw, 112px) var(--gutter) clamp(40px, 6vw, 64px);
  display: grid; gap: 28px; align-items: center;
}
.signature {
  display: block;
  width: clamp(250px, 66vw, 500px); height: auto; max-width: 100%;
  margin: 0 0 0 -0.5%;
  user-select: none; -webkit-user-drag: none;
}
.closing-box {
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 14px 16px;
  padding: 20px 22px; border-radius: var(--r-card);
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.025);
}
.closing-box-ico { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; border: 1px solid var(--line-2); }
.closing-box-ico .i { width: 21px; height: 21px; }
.closing-box p { font-size: 16px; font-weight: 500; line-height: 1.35; text-wrap: balance; }
.closing-box .btn { grid-column: 1 / -1; justify-self: start; }
@media (min-width: 768px) {
  .closing-box { grid-template-columns: auto minmax(0, 1fr) auto; }
  .closing-box .btn { grid-column: auto; }
}
@media (min-width: 1200px) {
  .closing { grid-template-columns: minmax(0, 1fr) minmax(0, 520px); gap: 48px; }
}

/* ---------- Pie ---------- */
.footer {
  margin: 0 var(--gutter);
  padding: 22px 0 max(26px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 22px;
  font-size: 14px; color: var(--ink-3);
}
.footer a { color: var(--ink-2); text-decoration: underline; text-decoration-color: var(--line-2); text-underline-offset: 4px; transition: color 0.2s var(--ease-out), text-decoration-color 0.2s var(--ease-out); }
.footer-link { display: inline-flex; align-items: center; min-height: 44px; }
.footer-top { margin-left: auto; }
@media (hover: hover) and (pointer: fine) { .footer a:hover { color: var(--ink); text-decoration-color: var(--ink-2); } }
@media (max-width: 599px) { .footer-top { margin-left: 0; } }

/* Sin JS: todo a la vista */
.no-js .about-card, .no-js .about-title, .no-js .contact-title { opacity: 1 !important; transform: none !important; }

@media (prefers-reduced-motion: reduce) {
  .pad3d-wait { animation-duration: 2.4s; }
  .about-card, .copy-btn .i, .type-pill span { transition-duration: 0.01s !important; }
}

/* En pantallas táctiles los botones chicos también miden 44 px */
@media (hover: none), (pointer: coarse) {
  .btn-sm { height: 44px; }
  .cf-index button { min-width: 44px; height: 44px; }
}

/* En compu el texto va centrado en la altura de la pantalla, a la izquierda */
@media (min-width: 1024px) and (min-height: 600px) {
  .hero { justify-content: center; }
}

/* Si el respaldo sin JS ya mostró el hero, cuando llega el JS no se vuelve a animar */
.js .hero-late :is(.hero-title .ln > span, .eyebrow, .lead, .hero-ctas .btn) { animation: none !important; opacity: 1 !important; transform: none !important; filter: none !important; }

/* Entrada de los símbolos: aparecen y se acomodan apenas, del centro hacia afuera (con reduced-motion, solo aparecen).
   Va en .sigil-box porque la flotación y el crecer los maneja GSAP en las capas de adentro: así no se pisan.
   Es el último tiempo de la coreografía del hero: se encienden mientras la bajada entra (--in-0 está en .hero). */
@keyframes sigil-in { from { opacity: 0; transform: scale(0.9); } }
.js body:not(.is-in) .sigil-box { opacity: 0; }
.js .is-in .sigil-box { animation: sigil-in 1.2s var(--ease-pres) calc(var(--in-0) + 600ms) backwards; }
.js .is-in .sigil:nth-child(3) .sigil-box { animation-delay: calc(var(--in-0) + 420ms); }
.js .is-in .sigil:is(:nth-child(2), :nth-child(4)) .sigil-box { animation-delay: calc(var(--in-0) + 510ms); }
@media (prefers-reduced-motion: reduce) { .js .is-in .sigil-box { animation-name: fade-in; animation-duration: 0.6s; } }
.js .hero-late .sigil-box { animation: none !important; opacity: 1 !important; }

/* Tablet: la fila va centrada debajo del texto, sin llegar a los bordes */
@media (min-width: 768px) {
  .sigils { margin-inline: 0; align-self: center; width: min(100%, 700px); }
}
/* 1024–1279: el texto no entra al costado de los símbolos; van debajo, como en la tablet */
@media (min-width: 1024px) and (max-width: 1279px) {
  .hero { justify-content: flex-start; }
  .sigils { width: min(100%, 740px); margin-top: 36px; }
}
/* Compu (1280 o más): el texto a la izquierda y la fila a la derecha, centrada en altura con el texto.
   La palabra cuelga debajo de la fila (sin reservar lugar), así el centro que se alinea es el de los símbolos. */
@media (min-width: 1280px) {
  .hero {
    display: grid; grid-template-columns: auto minmax(0, 1fr);
    column-gap: clamp(32px, 4vw, 80px);
    align-items: center;
    padding-bottom: 76px;
  }
  .sigils { margin: 0; padding: 0; justify-self: center; align-self: center; width: min(100%, clamp(680px, 56vw, 1000px)); }
  .sigils-stage { padding-bottom: 0; }
}
