﻿/* ============================================================
   KIBY Space · web de presentación
   Los tokens (color, tipografía, degradado de marca) son los
   mismos que usa la app en src/index.css, para que la web y el
   producto se reconozcan como la misma cosa.
   ============================================================ */

:root {
  --bg:          #07060d;
  --bg-soft:     #0b0912;
  --surface:     #13151b;
  --surface-2:   #171a22;
  --line:        #262a36;
  --line-soft:   rgba(255, 255, 255, 0.08);

  --text:        #f4f1ff;
  --text-mute:   #a5a1bd;
  --text-dim:    #6b7185;

  --violet:      #805af2;
  --violet-soft: rgba(128, 90, 242, 0.14);
  --cyan:        #67e8f9;
  --fuchsia:     #f0abfc;
  --gold:        #fbbf24;

  --brand-grad: linear-gradient(120deg, #c4b5fd 0%, #f0abfc 45%, #67e8f9 100%);

  --wrap: 1180px;
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 22px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

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

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'Satoshi', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }

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

h1, h2, h3 {
  font-family: 'Clash Display', 'Satoshi', sans-serif;
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.015em;
  margin: 0;
}

p { margin: 0; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: 24px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  background: var(--violet);
  color: #fff;
  padding: 10px 16px;
  border-radius: 0 0 var(--r-sm) 0;
}
.skip-link:focus { left: 0; }

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

/* ============================ FONDO ============================ */
/* Estrellas y nebulosas pintadas con gradientes: cero peticiones de red
   y escala a cualquier pantalla sin pixelarse. */
.starfield {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

/* Capas de parallax. --mx/--my los pone el script: van de -1 a 1 según dónde
   esté el cursor respecto al centro de la ventana. Cuanto más "cerca" está la
   capa, más se desplaza — que es lo que da la sensación de profundidad.
   El desplazamiento máximo es pequeño a propósito: el fondo debe acompañar,
   no marear a quien está leyendo por encima. */
.layer {
  position: absolute;
  inset: 0;
  will-change: transform;
}
.layer--far {
  transform: translate3d(calc(var(--mx, 0) * -13px), calc(var(--my, 0) * -9px), 0);
}
.layer--near {
  transform: translate3d(calc(var(--mx, 0) * -32px), calc(var(--my, 0) * -22px), 0);
}

.stars {
  position: absolute;
  inset: -50%;
  background-repeat: repeat;
}

.stars--far {
  background-image:
    radial-gradient(1px 1px at 20% 30%, rgba(255,255,255,0.7) 50%, transparent 50%),
    radial-gradient(1px 1px at 70% 60%, rgba(255,255,255,0.5) 50%, transparent 50%),
    radial-gradient(1px 1px at 45% 80%, rgba(196,181,253,0.6) 50%, transparent 50%),
    radial-gradient(1px 1px at 85% 15%, rgba(255,255,255,0.45) 50%, transparent 50%);
  background-size: 320px 320px, 260px 260px, 400px 400px, 200px 200px;
  animation: drift 240s linear infinite;
}

.stars--near {
  background-image:
    radial-gradient(1.6px 1.6px at 15% 55%, rgba(255,255,255,0.85) 50%, transparent 50%),
    radial-gradient(1.6px 1.6px at 65% 25%, rgba(103,232,249,0.7) 50%, transparent 50%),
    radial-gradient(1.6px 1.6px at 90% 70%, rgba(240,171,252,0.65) 50%, transparent 50%);
  background-size: 520px 520px, 620px 620px, 480px 480px;
  animation: drift 150s linear infinite reverse;
  opacity: 0.9;
}

@keyframes drift {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-320px, -180px, 0); }
}

.nebula {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  opacity: 0.5;
  /* will-change promueve la nebulosa a su propia capa: el desenfoque de 90px
     se rasteriza UNA vez y moverla luego solo cuesta un transform. Sin esto,
     cada píxel de cursor volvería a calcular el blur. */
  will-change: transform;
}
/* Las nebulosas van al revés que las estrellas: se alejan del cursor mientras
   el polvo se acerca. Es lo que separa el fondo del primer plano. */
.nebula--violet {
  width: 720px; height: 720px;
  top: -220px; left: -160px;
  background: radial-gradient(circle, rgba(128,90,242,0.55) 0%, rgba(128,90,242,0) 70%);
  transform: translate3d(calc(var(--mx, 0) * 24px), calc(var(--my, 0) * 16px), 0);
}
.nebula--cyan {
  width: 620px; height: 620px;
  top: 120px; right: -220px;
  background: radial-gradient(circle, rgba(56,189,248,0.35) 0%, rgba(56,189,248,0) 70%);
  transform: translate3d(calc(var(--mx, 0) * 34px), calc(var(--my, 0) * 22px), 0);
}

/* Resplandor que sigue al cursor: el "espacio" se ilumina por donde pasas.
   Se posiciona con transform (compuesto en GPU) y no con left/top, que
   dispararían layout en cada movimiento. */
.cursor-glow {
  position: absolute;
  left: 0;
  top: 0;
  width: 520px;
  height: 520px;
  margin: -260px 0 0 -260px;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(128, 90, 242, 0.26) 0%,
    rgba(217, 70, 239, 0.13) 35%,
    rgba(103, 232, 249, 0.07) 55%,
    rgba(0, 0, 0, 0) 72%
  );
  filter: blur(26px);
  opacity: 0;
  transform: translate3d(50vw, 50vh, 0);
  transition: opacity 600ms ease;
  will-change: transform, opacity;
}
/* .is-live solo aparece cuando el cursor se mueve de verdad: sin ratón (móvil,
   táctil) el resplandor no llega a encenderse nunca. */
.starfield.is-live .cursor-glow { opacity: 1; }

main, .site-header, .site-footer { position: relative; z-index: 1; }

/* =========================== CABECERA =========================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  transition: background 250ms ease, border-color 250ms ease, backdrop-filter 250ms ease;
  border-bottom: 1px solid transparent;
}
.site-header.is-stuck {
  background: rgba(7, 6, 13, 0.82);
  backdrop-filter: blur(14px);
  border-bottom-color: var(--line-soft);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 28px;
  min-height: 76px;
}

.brand { display: flex; align-items: center; gap: 11px; flex-shrink: 0; }
.brand__logo { width: 40px; height: 40px; filter: drop-shadow(0 6px 20px rgba(217,70,239,0.45)); }

/* Lockup «KIBY Space»: SPACE debajo, pegado, en gris y con el tracking muy
   abierto. Nunca lleva el degradado — si lo toca deja de ser apellido. */
.brand__lockup { display: flex; flex-direction: column; }
.brand__name {
  font-family: 'Clash Display', sans-serif;
  font-size: 22px;
  font-weight: 600;
  letter-spacing: 0.3em;
  margin-right: -0.3em;
  background: var(--brand-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.brand__sub {
  margin-top: 2px;
  font-size: 8px;
  font-weight: 600;
  letter-spacing: 0.44em;
  margin-right: -0.44em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.nav {
  display: flex;
  align-items: center;
  gap: 26px;
  margin-left: auto;
  font-size: 15px;
  font-weight: 500;
  color: var(--text-mute);
}
.nav a { transition: color 160ms ease; }
.nav a:hover { color: var(--text); }

.header-cta { flex-shrink: 0; }

.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  width: 42px; height: 42px;
  align-items: center; justify-content: center;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.nav-toggle span {
  display: block; width: 18px; height: 2px;
  background: var(--text); border-radius: 2px;
  transition: transform 200ms var(--ease), opacity 200ms ease;
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* =========================== BOTONES =========================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 11px 22px;
  border-radius: 999px;
  font-family: 'Satoshi', sans-serif;
  font-size: 15px;
  font-weight: 700;
  white-space: nowrap;
  border: 1px solid transparent;
  transition: transform 180ms var(--ease), box-shadow 220ms ease, background 180ms ease, color 180ms ease;
}
.btn--lg { padding: 15px 30px; font-size: 16.5px; }

.btn--light {
  background: #f4f1ff;
  color: #0b0912;
  box-shadow: 0 10px 30px rgba(196, 181, 253, 0.18);
}
.btn--light:hover { transform: translateY(-2px); box-shadow: 0 16px 40px rgba(196, 181, 253, 0.28); }

.btn--ghost {
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  border-color: var(--line);
}
.btn--ghost:hover { background: rgba(255, 255, 255, 0.11); transform: translateY(-2px); }

/* ========================= TIPOGRAFÍA AUX ========================= */
.eyebrow {
  margin: 0 0 14px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.eyebrow--violet { color: #b9a3ff; }
.eyebrow--cyan   { color: #7dd3fc; }
.eyebrow--gold   { color: var(--gold); }
.eyebrow--center { text-align: center; }

.grad {
  background: var(--brand-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Frase rematada dentro de un titular. Lleva brillo además del degradado:
   a 44px sobre negro, el degradado solo no levanta la voz lo suficiente.
   El halo va con drop-shadow y no con text-shadow — el texto es transparente
   (background-clip: text), así que text-shadow pintaría por debajo y se
   vería el rectángulo. drop-shadow usa la silueta real de las letras. */
.hot {
  background: linear-gradient(100deg, #f0abfc 0%, #c4b5fd 42%, #67e8f9 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 28px rgba(217, 70, 239, 0.38));
}

/* En un texto ya apagado (var(--text-mute)), lo que va en negrita sube a
   blanco. Si no, "negrita gris sobre gris" no destaca nada. */
.lede strong,
.strip__text strong,
.feature p strong,
.ticks strong {
  color: var(--text);
  font-weight: 700;
}

.lede {
  font-size: 18px;
  line-height: 1.65;
  color: var(--text-mute);
  max-width: 52ch;
}

/* ============================= HERO ============================= */
.hero { padding: 72px 0 96px; }

.hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: 56px;
  align-items: center;
}

.hero__title {
  font-size: clamp(40px, 6.2vw, 74px);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 0.98;
  text-transform: uppercase;
  margin-bottom: 22px;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 32px;
}

.hero__note {
  margin-top: 18px;
  font-size: 13.5px;
  color: var(--text-dim);
}

/* --- Maqueta de la app --------------------------------------------------
   Reproduce la ventana real: barra, sidebar de 240px con el lockup y sus tres
   secciones, buscador redondo y campana. Los colores y los tamaños relativos
   salen de src/index.css, no están elegidos a ojo. */
.hero__art { perspective: 1400px; }

.mock {
  position: relative;
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, #16181f 0%, #0e1014 100%);
  border: 1px solid var(--line);
  box-shadow: 0 40px 90px rgba(0, 0, 0, 0.6), 0 0 90px rgba(128, 90, 242, 0.14);
  overflow: hidden;
  transform: rotateY(-9deg) rotateX(3deg) translateZ(0);
  transition: transform 600ms var(--ease), box-shadow 600ms ease;
}
.mock:hover { transform: rotateY(-4deg) rotateX(1deg); }
.js .mock { cursor: pointer; }

.mock__bar {
  display: flex; align-items: center; gap: 7px;
  height: 38px;                 /* fijo: .boot arranca justo debajo */
  padding: 0 14px;
  background: #0d0f14;
  border-bottom: 1px solid var(--line);
  box-sizing: border-box;
}
.dot { width: 10px; height: 10px; border-radius: 50%; }
.dot--r { background: #ff5f57; } .dot--y { background: #febc2e; } .dot--g { background: #28c840; }
.mock__winname {
  margin-left: auto; margin-right: auto;
  padding-right: 34px;          /* compensa los 3 puntos de la izquierda */
  font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.06em; color: #565c6d;
}

.mock__body { display: grid; grid-template-columns: 150px 1fr; min-height: 340px; }

.mock__side {
  padding: 18px 10px;
  background: #101219;
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column; align-items: center;
}
.mock__logo { width: 44px; height: 44px; margin-bottom: 7px; filter: drop-shadow(0 6px 18px rgba(217,70,239,0.4)); }
.mock__brand { display: flex; flex-direction: column; align-items: center; }
.mock__kiby {
  position: relative;
  font-family: 'Clash Display', sans-serif;
  font-size: 19px; font-weight: 600;
  letter-spacing: 0.32em; margin-right: -0.32em;
  background: var(--brand-grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
/* El «Alpha» del sidebar real. Absoluto, igual que en la app: dentro del
   flujo ensancharía el bloque y KIBY dejaría de centrarse sobre SPACE. */
.mock__kiby sup {
  position: absolute; left: 100%; top: 0;
  margin-left: -4px;
  font-family: 'Satoshi', sans-serif;
  font-size: 7px; font-weight: 500;
  letter-spacing: 0; color: #6b7185;
  -webkit-text-fill-color: #6b7185;
}
.mock__space {
  margin-top: 3px;
  font-size: 7px; font-weight: 600;
  letter-spacing: 0.44em; margin-right: -0.44em;
  text-transform: uppercase; color: var(--text-dim);
}
.mock__divider {
  width: 100%; height: 1px; margin: 16px 0 14px;
  background: linear-gradient(90deg, transparent, #303340 25%, rgba(128,90,242,0.4) 50%, #303340 75%, transparent);
}
.mock__nav { width: 100%; display: flex; flex-direction: column; gap: 4px; }
.mock__item {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 8px; border-radius: 9px;
  font-size: 9.5px; font-weight: 500;
  color: #8b90a2;
  transition: background 200ms ease, color 200ms ease;
}
.mock__item svg { width: 12px; height: 12px; fill: currentColor; flex-shrink: 0; }
.mock__item.is-active { background: rgba(128, 90, 242, 0.16); color: #d6ccff; }
.mock:hover .mock__item:not(.is-active) { color: #b6bbcc; }

.mock__profile {
  margin-top: auto; width: 100%;
  display: flex; align-items: center; gap: 9px;
  padding: 9px; border-radius: 11px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--line);
  box-sizing: border-box;
}
.mock__avatar {
  width: 24px; height: 24px; border-radius: 50%;
  background: linear-gradient(135deg, #6366f1, #a855f7);
  flex-shrink: 0;
}
.mock__lines { flex: 1; display: flex; flex-direction: column; gap: 4px; }
.mock__lines b { height: 6px; width: 74%; border-radius: 3px; background: #3a3f4d; }
.mock__lines i { height: 5px; width: 48%; border-radius: 3px; background: #2a2e39; }

.mock__main { padding: 14px; display: flex; flex-direction: column; gap: 11px; background: #0c0e13; }
.mock__head { display: flex; align-items: center; gap: 8px; margin-bottom: 2px; }
.mock__search {
  flex: 1;
  display: flex; align-items: center; gap: 6px;
  height: 24px; padding: 0 10px;
  border-radius: 999px;
  background: rgba(20, 22, 31, 0.7);
  border: 1px solid rgba(255, 255, 255, 0.1);
  font-size: 9.5px; color: #6d7280;
}
.mock__search svg { width: 11px; height: 11px; fill: currentColor; }
.mock__bell {
  display: grid; place-items: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.05);
  color: #8b90a2;
}
.mock__bell svg { width: 12px; height: 12px; fill: currentColor; }

/* --- Explorador de comunidades dentro de la maqueta ---
   Reproduce el panel real: un destacado grande arriba con su splash, nombre,
   descripción y etiquetas, y debajo una fila de pósters 3/4 con el contador
   de miembros y la insignia MIEMBRO. */
.mock__hero {
  position: relative;
  height: 118px;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
  flex-shrink: 0;
}
/* El "splash": arte inventado a base de gradientes. No hay imágenes que
   cargar y escala a cualquier tamaño sin pesar nada. */
.mock__heroart {
  position: absolute; inset: 0;
  background:
    radial-gradient(70% 90% at 22% 25%, rgba(240, 171, 252, 0.75), transparent 62%),
    radial-gradient(60% 80% at 72% 68%, rgba(56, 189, 248, 0.6), transparent 60%),
    radial-gradient(50% 70% at 88% 18%, rgba(251, 191, 36, 0.35), transparent 60%),
    linear-gradient(145deg, #3b1d63 0%, #16123a 55%, #0a0a18 100%);
}
/* Velo inferior: lo mismo que hace la app para que el texto se lea siempre,
   caiga encima lo que caiga. */
.mock__hero::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 35%, rgba(8, 9, 15, 0.88) 100%);
}
.mock__arrow {
  position: absolute; top: 42%;
  display: grid; place-items: center;
  width: 17px; height: 17px;
  border-radius: 50%;
  background: rgba(10, 11, 18, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.16);
  font-size: 10px; line-height: 1; color: #fff;
  z-index: 2;
}
.mock__arrow--l { left: 6px; }
.mock__arrow--r { right: 6px; }

.mock__heroinfo {
  position: absolute; left: 12px; bottom: 10px; right: 62px;
  z-index: 2;
  display: flex; flex-direction: column;
}
.mock__heroinfo b {
  font-family: 'Clash Display', sans-serif;
  font-size: 19px; font-weight: 600; line-height: 0.98;
  color: #fff;
  text-shadow: 0 3px 16px rgba(0, 0, 0, 0.6);
}
.mock__heroinfo i {
  margin-top: 3px;
  font-style: normal;
  font-size: 8px; line-height: 1.35;
  color: #d9d6f2;
}
.mock__tags { display: flex; gap: 4px; margin-top: 5px; }
.mock__tags em {
  font-style: normal;
  padding: 2px 6px;
  border-radius: 999px;
  background: rgba(147, 112, 255, 0.3);
  border: 1px solid rgba(200, 180, 255, 0.35);
  font-size: 6.5px; font-weight: 700;
  color: #e6ddff;
}
.mock__herobtn {
  position: absolute; right: 12px; bottom: 12px;
  z-index: 2;
  padding: 5px 12px;
  border-radius: 999px;
  background: linear-gradient(90deg, #8b6bff, #e15cff);
  font-size: 8px; font-weight: 800;
  color: #fff;
}

.mock__rowtitle {
  font-family: 'Clash Display', sans-serif;
  font-size: 11px; font-weight: 600;
  color: #f3f0ff;
  flex-shrink: 0;
}

.mock__row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 7px; }

.mock__poster {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: 9px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
  transition: transform 300ms var(--ease), border-color 300ms ease;
}
.mock:hover .mock__poster { border-color: rgba(128, 90, 242, 0.4); }
.mock__poster::before {
  content: "";
  position: absolute; inset: 0;
}
.mock__poster::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 40%, rgba(8, 9, 15, 0.86) 100%);
}
.mock__poster--1::before {
  background:
    radial-gradient(80% 60% at 50% 12%, rgba(217, 70, 239, 0.85), transparent 65%),
    linear-gradient(170deg, #4a1d5e 0%, #120b22 100%);
}
.mock__poster--2::before {
  background:
    radial-gradient(80% 60% at 50% 12%, rgba(56, 189, 248, 0.8), transparent 65%),
    linear-gradient(170deg, #113a55 0%, #0a1220 100%);
}
.mock__poster--3::before {
  background:
    radial-gradient(80% 60% at 50% 12%, rgba(52, 211, 153, 0.7), transparent 65%),
    linear-gradient(170deg, #10453a 0%, #08160f 100%);
}
.mock__poster--4::before {
  background:
    radial-gradient(80% 60% at 50% 12%, rgba(251, 146, 60, 0.7), transparent 65%),
    linear-gradient(170deg, #4a2a12 0%, #1a0f08 100%);
}

.mock__members {
  position: absolute; left: 5px; top: 5px; z-index: 2;
  padding: 1.5px 5px;
  border-radius: 999px;
  background: rgba(10, 11, 18, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.14);
  font-size: 6px; font-weight: 700;
  color: #dffff0;
}
.mock__joined {
  position: absolute; right: 5px; top: 5px; z-index: 2;
  padding: 1.5px 5px;
  border-radius: 999px;
  background: linear-gradient(90deg, #8b6bff, #e15cff);
  font-size: 5.5px; font-weight: 800;
  letter-spacing: 0.04em; color: #fff;
}
.mock__pname {
  position: absolute; left: 6px; right: 6px; bottom: 6px; z-index: 2;
  font-family: 'Clash Display', sans-serif;
  font-size: 10px; font-weight: 600; line-height: 1;
  color: #fff;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.75);
}

/* --- Arranque de la app -------------------------------------------------
   La misma secuencia que ves al abrir KIBY Space de verdad: el splash con
   CONNECTING TO THE SPACE, el estallido de la marca y la interfaz montándose
   detrás. Las clases (.is-reveal / .is-out / .is-live) las va poniendo
   script.js con una línea de tiempo.

   Sin JS todo esto no existe (.boot nace en display:none) y se ve la app ya
   montada: nadie se queda mirando una caja negra. */
.boot { display: none; }

.js .boot {
  display: flex;
  position: absolute;
  left: 0; right: 0; bottom: 0; top: 38px;   /* debajo de la barra */
  align-items: center; justify-content: center;
  flex-direction: column;
  background: #07060d;
  overflow: hidden;
  pointer-events: none;
  z-index: 3;
}

.boot__glow {
  position: absolute; left: 50%; top: 46%;
  width: 420px; height: 420px; margin: -210px 0 0 -210px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(168,85,247,0.6) 0%, rgba(59,130,246,0.28) 45%, rgba(0,0,0,0) 70%);
  filter: blur(18px);
  opacity: 0;
}

/* Onda expansiva: dos anillos con 140ms de diferencia. Uno solo se lee como
   un círculo que crece; dos se leen como un golpe. */
.boot__ring {
  position: absolute; left: 50%; top: 46%;
  width: 120px; height: 120px; margin: -60px 0 0 -60px;
  border-radius: 50%;
  border: 2px solid rgba(196, 181, 253, 0.9);
  opacity: 0;
}
.boot__ring--2 { border-color: rgba(103, 232, 249, 0.75); }

.boot__flash {
  position: absolute; inset: 0;
  background: radial-gradient(circle at 50% 46%, rgba(255,255,255,0.95) 0%, rgba(196,181,253,0.45) 38%, rgba(0,0,0,0) 70%);
  opacity: 0;
  mix-blend-mode: screen;
}

.boot__tagline {
  display: flex;
  font-family: 'Satoshi', sans-serif;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.34em;
  color: rgba(226, 232, 240, 0.92);
  text-shadow: 0 0 20px rgba(147, 51, 234, 0.6);
  white-space: pre;
}
.boot__tagline span {
  display: inline-block;
  opacity: 0;
  animation:
    bootLetterIn 460ms cubic-bezier(0.22, 1, 0.36, 1) calc(var(--i) * 42ms) both,
    bootLetterWave 2000ms ease-in-out calc(1000ms + var(--i) * 66ms) infinite;
}
@keyframes bootLetterIn {
  0%   { opacity: 0; transform: translateY(15px); filter: blur(6px); }
  100% { opacity: 0.92; transform: none; filter: blur(0); }
}
@keyframes bootLetterWave {
  0%, 100% { opacity: 0.5; transform: translateY(0); }
  50%      { opacity: 1;   transform: translateY(-3px); }
}

/* --- Pantalla de carga --- */
.boot__load {
  position: absolute;
  left: 50%; bottom: 26px;
  width: min(230px, 66%);
  transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 7px;
}
.boot__bar {
  height: 3px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}
/* La duración sale de --load-ms, que pone el script desde TAGLINE_MS. Así la
   barra y la línea de tiempo no pueden desincronizarse: son el mismo número. */
.boot__bar span {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, #8b6bff, #e15cff 55%, #67e8f9);
  box-shadow: 0 0 12px rgba(217, 70, 239, 0.7);
  animation: bootLoad var(--load-ms, 10000ms) cubic-bezier(0.5, 0, 0.5, 1) both;
}
/* No es lineal a propósito: avanza a tirones, como carga algo de verdad. */
@keyframes bootLoad {
  0%   { width: 0; }
  18%  { width: 24%; }
  32%  { width: 29%; }
  55%  { width: 62%; }
  68%  { width: 67%; }
  88%  { width: 93%; }
  100% { width: 100%; }
}
.boot__status {
  display: flex; align-items: center; gap: 8px;
  font-family: 'Satoshi', sans-serif;
  font-size: 7.5px; font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.boot__pct { color: #c4b5fd; font-variant-numeric: tabular-nums; }
.boot__log { color: #6b7185; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }

.boot.is-reveal .boot__load { animation: bootTaglineOut 320ms ease forwards; }

.boot__brand {
  position: absolute;
  display: flex; flex-direction: column; align-items: center;
  opacity: 0;
}
.boot__logo { width: 72px; height: 72px; margin-bottom: 10px; }
.boot__kiby {
  display: flex;
  font-family: 'Clash Display', sans-serif;
  font-size: 30px; font-weight: 600;
  letter-spacing: 0.32em; margin-right: -0.32em;
}
.boot__kiby span {
  display: inline-block;
  background: var(--brand-grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.boot__kiby span:nth-child(1) { --i: 0; }
.boot__kiby span:nth-child(2) { --i: 1; }
.boot__kiby span:nth-child(3) { --i: 2; }
.boot__kiby span:nth-child(4) { --i: 3; }
.boot__space {
  margin-top: 4px;
  font-family: 'Satoshi', sans-serif;
  font-size: 8px; font-weight: 600;
  letter-spacing: 0.44em; margin-right: -0.44em;
  text-transform: uppercase; color: #6b7185;
  opacity: 0;
}

/* ---- Fase 2: el estallido ---- */
.boot.is-reveal .boot__tagline { animation: bootTaglineOut 380ms ease forwards; }
@keyframes bootTaglineOut {
  to { opacity: 0; transform: scale(0.72); filter: blur(10px); }
}

.boot.is-reveal .boot__brand { opacity: 1; }
.boot.is-reveal .boot__logo  { animation: bootLogoIn 660ms cubic-bezier(0.16, 1.3, 0.3, 1) both; }
@keyframes bootLogoIn {
  0%   { opacity: 0; transform: scale(2.7) rotate(-14deg); filter: blur(20px) brightness(2.6); }
  55%  { opacity: 1; transform: scale(0.88) rotate(4deg);  filter: blur(0) brightness(1.6); }
  75%  { transform: scale(1.07) rotate(-1.5deg); }
  100% { opacity: 1; transform: scale(1) rotate(0deg);     filter: blur(0) brightness(1); }
}

/* Las letras caen desde arriba en cascada, como en el sidebar de la app. */
.boot.is-reveal .boot__kiby span {
  animation: bootKibyLetter 620ms cubic-bezier(0.22, 1, 0.36, 1) calc(200ms + var(--i) * 85ms) both;
}
@keyframes bootKibyLetter {
  0%   { opacity: 0; transform: translateY(-40px) scale(1.75); filter: blur(13px); }
  60%  { opacity: 1; transform: translateY(4px) scale(0.96);   filter: blur(0); }
  80%  { transform: translateY(-2px) scale(1.02); }
  100% { opacity: 1; transform: none; }
}

.boot.is-reveal .boot__space { animation: bootSpaceIn 620ms ease 560ms both; }
@keyframes bootSpaceIn {
  0%   { opacity: 0; letter-spacing: 1.1em; }
  100% { opacity: 1; letter-spacing: 0.44em; }
}

.boot.is-reveal .boot__flash { animation: bootFlash 560ms ease-out both; }
@keyframes bootFlash {
  0%   { opacity: 0; }
  10%  { opacity: 0.95; }
  100% { opacity: 0; }
}

.boot.is-reveal .boot__ring    { animation: bootRing 900ms cubic-bezier(0.2, 0.8, 0.3, 1) both; }
.boot.is-reveal .boot__ring--2 { animation-delay: 140ms; }
@keyframes bootRing {
  0%   { opacity: 0.9; transform: scale(0.15); border-width: 3px; }
  100% { opacity: 0;   transform: scale(3.6);  border-width: 0.5px; }
}

.boot.is-reveal .boot__glow { animation: bootGlow 1500ms ease-out both; }
@keyframes bootGlow {
  0%   { opacity: 0; transform: scale(0.35); }
  16%  { opacity: 1; transform: scale(1.18); }
  100% { opacity: 0.5; transform: scale(1); }
}

/* ---- Fase 3: se va y deja ver la app ---- */
.boot.is-out { animation: bootOut 620ms ease forwards; }
@keyframes bootOut {
  to { opacity: 0; transform: scale(1.07); }
}

/* La interfaz se monta pieza a pieza, no aparece de golpe: primero el
   sidebar, luego el destacado y por último los pósters uno a uno.
   Cada retardo cuelga de una CLASE, no de nth-of-type: así, al cambiar el
   contenido de la maqueta, ningún retardo se va al elemento equivocado. */
.js .mock .mock__head,
.js .mock .mock__hero,
.js .mock .mock__rowtitle,
.js .mock .mock__poster,
.js .mock .mock__item,
.js .mock .mock__profile { opacity: 0; }

.js .mock.is-live .mock__head,
.js .mock.is-live .mock__hero,
.js .mock.is-live .mock__rowtitle,
.js .mock.is-live .mock__poster,
.js .mock.is-live .mock__item,
.js .mock.is-live .mock__profile {
  animation: mockPartIn 520ms var(--ease) both;
}
@keyframes mockPartIn {
  0%   { opacity: 0; transform: translateY(10px) scale(0.97); }
  100% { opacity: 1; transform: none; }
}
.js .mock.is-live .mock__item:nth-child(1)   { animation-delay: 40ms; }
.js .mock.is-live .mock__item:nth-child(2)   { animation-delay: 100ms; }
.js .mock.is-live .mock__item:nth-child(3)   { animation-delay: 160ms; }
.js .mock.is-live .mock__profile             { animation-delay: 240ms; }
.js .mock.is-live .mock__head                { animation-delay: 60ms; }
.js .mock.is-live .mock__hero                { animation-delay: 170ms; }
.js .mock.is-live .mock__rowtitle            { animation-delay: 290ms; }
.js .mock.is-live .mock__poster:nth-child(1) { animation-delay: 350ms; }
.js .mock.is-live .mock__poster:nth-child(2) { animation-delay: 410ms; }
.js .mock.is-live .mock__poster:nth-child(3) { animation-delay: 470ms; }
.js .mock.is-live .mock__poster:nth-child(4) { animation-delay: 530ms; }

/* Pista de repetir: solo cuando ya terminó, para no competir con la intro. */
.mock__replay {
  position: absolute;
  right: 12px; bottom: 12px;
  z-index: 4;
  padding: 5px 11px;
  border-radius: 999px;
  background: rgba(11, 9, 18, 0.8);
  border: 1px solid rgba(255, 255, 255, 0.14);
  font-size: 10.5px; font-weight: 600;
  color: var(--text-mute);
  opacity: 0;
  transition: opacity 400ms ease, color 200ms ease, border-color 200ms ease;
}
.mock__replay { cursor: pointer; font-family: 'Satoshi', sans-serif; }
/* Enfocado con teclado se ve siempre, aunque la intro aún no haya terminado:
   si no, se puede tabular hasta un botón invisible. */
.mock__replay:focus-visible { opacity: 1; }
.mock.is-done .mock__replay { opacity: 0.6; }
.mock.is-done:hover .mock__replay {
  opacity: 1;
  color: var(--text);
  border-color: rgba(128, 90, 242, 0.6);
}

/* ============================================================
   HIPERESPACIO · el viaje mientras la app carga
   Esto es 3D de verdad, no un zoom disfrazado: la capa tiene `perspective` y
   cada objeto viaja por el eje Z desde el fondo hasta pasar de largo. La
   perspectiva se encarga sola de que se abran hacia fuera y crezcan, y de que
   los de los bordes vayan más rápidos que los del centro — el paralaje sale
   gratis y es el correcto, no uno inventado a mano.

   Todo compuesto en GPU (solo transform y opacity): setenta objetos volando
   sin tocar el layout ni una vez.
   ============================================================ */
.hyper {
  position: absolute;
  inset: 0;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  /* La distancia del ojo al plano. Cuanto menor, más brutal el efecto: a 800px
     un objeto que llega a Z=520 ya está casi encima y se abre de golpe. */
  perspective: 800px;
  /* Punto de fuga: hacia donde viajamos. En el centro. */
  --vx: 50%;
  --vy: 50%;
  /* El cursor lo desvía un poco: mueves el ratón y "pilotas". Poco, porque el
     efecto es muy sensible; a más de un 8% se siente como un volantazo. */
  perspective-origin: calc(var(--vx) + var(--mx, 0) * 5%) calc(var(--vy) + var(--my, 0) * 5%);
  transition: opacity 500ms ease;
}
.starfield.is-traveling .hyper { opacity: 1; }

/* Mientras se viaja, el campo de estrellas quieto estorba: baja a un fondo
   lejano para que mande el movimiento. */
.starfield.is-traveling .layer { opacity: 0.3; transition: opacity 700ms ease; }

/* --- Trazos de estrella ---
   El orden de los transforms importa y no es intercambiable:
   rotate(--a) coloca el eje X del elemento apuntando al centro; translateX
   lo aleja del punto de fuga por ese eje; translateZ lo manda al fondo. Como
   el largo del elemento va por su X, ya rotada, el trazo apunta siempre a
   donde viaja. Cambiar el orden lo convierte en confeti. */
.hs {
  position: absolute;
  /* Nacen en el punto de fuga, que está dentro del aro. */
  left: var(--vx); top: var(--vy);
  width: var(--len, 60px);
  height: var(--th, 2px);
  margin-left: calc(var(--len, 60px) / -2);
  margin-top: calc(var(--th, 2px) / -2);
  border-radius: 999px;
  /* La cabeza ya NO es blanco puro. Con 64 trazos rematados en blanco, el
     fondo era una alfombra de luces que competía con el agujero negro. Ahora
     la cabeza es solo un punto más claro que su propia estela, y el único
     foco de luz de la escena es el disco de acreción. */
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0) 0%,
    var(--col, #fff) 70%,
    rgba(255, 255, 255, 0.55) 100%);
  animation: hsFly var(--dur, 2.4s) linear var(--delay, 0s) infinite;
  opacity: 0;
}
@keyframes hsFly {
  0% {
    opacity: 0;
    transform: rotate(var(--a)) translateX(var(--r)) translateZ(-2000px) scale(0.22, 1);
  }
  9%   { opacity: var(--peak, 1); }
  78%  { opacity: var(--peak, 1); }
  100% {
    opacity: 0;
    /* Se estira a lo largo MUCHO más de lo que la perspectiva lo agranda, y a
       la vez se ADELGAZA (0.5 en Y). Ese contraste es el truco: la perspectiva
       engorda el trazo por igual en los dos ejes y lo deja como un tocho; hay
       que contrarrestarla para que quede un filamento de luz. */
    transform: rotate(var(--a)) translateX(var(--r)) translateZ(520px) scale(3.4, 0.5);
  }
}

/* --- El salto final: al llegar, todo se estira y revienta hacia fuera.
       Es el instante de "salir del hiperespacio", justo antes del estallido. */
.starfield.is-jumping .hyper {
  animation: hyperJump 700ms cubic-bezier(0.5, 0, 0.75, 0) both;
}
@keyframes hyperJump {
  0%   { opacity: 1; transform: scale(1);   filter: blur(0); }
  55%  { opacity: 1; transform: scale(2.4); filter: blur(3px) brightness(1.8); }
  100% { opacity: 0; transform: scale(5);   filter: blur(14px) brightness(2.4); }
}

/* ============================================================
   EL ESTALLIDO
   Lo que ocurre en el fondo cuando la app termina de cargar. Seis cosas a la
   vez, todas naciendo del MISMO punto: --bx/--by, que el script fija en el
   centro exacto de la maqueta. Ese detalle es lo que hace que la explosión
   parezca salir de la app y no de un sitio cualquiera de la pantalla.
   ============================================================ */
.warp {
  position: absolute;
  inset: 0;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}
.starfield.is-warp .warp { opacity: 1; }

/* 1 · Rayos. Un abanico de radios que sale disparado y gira un poco al
      hacerlo. La máscara los apaga con la distancia: sin ella se ven como una
      rueda de bicicleta que llega a los bordes, y queda plano. */
.warp__rays {
  position: absolute;
  left: var(--bx, 50%); top: var(--by, 50%);
  width: 150vmax; height: 150vmax;
  margin: -75vmax 0 0 -75vmax;
  background: repeating-conic-gradient(
    from 0deg at 50% 50%,
    rgba(255, 255, 255, 0.55) 0deg 0.5deg,
    rgba(196, 181, 253, 0.28) 0.5deg 1.2deg,
    rgba(0, 0, 0, 0) 1.2deg 6deg
  );
  -webkit-mask-image: radial-gradient(circle, #000 0%, rgba(0,0,0,0.55) 14%, transparent 46%);
  mask-image: radial-gradient(circle, #000 0%, rgba(0,0,0,0.55) 14%, transparent 46%);
  opacity: 0;
}
.starfield.is-warp .warp__rays {
  animation: warpRays 1900ms cubic-bezier(0.12, 0.85, 0.25, 1) both;
  will-change: transform, opacity;
}
@keyframes warpRays {
  0%   { opacity: 0;    transform: scale(0.04) rotate(0deg); }
  8%   { opacity: 0.95; }
  100% { opacity: 0;    transform: scale(1) rotate(26deg); }
}

/* 2 · Ondas expansivas. Tres, escalonadas: una sola se lee como un círculo
      que crece; tres se leen como un golpe que retumba. */
.warp__ring {
  position: absolute;
  left: var(--bx, 50%); top: var(--by, 50%);
  width: 40vmax; height: 40vmax;
  margin: -20vmax 0 0 -20vmax;
  border-radius: 50%;
  border: 2px solid rgba(196, 181, 253, 0.9);
  opacity: 0;
}
.warp__ring--2 { border-color: rgba(240, 171, 252, 0.75); }
.warp__ring--3 { border-color: rgba(103, 232, 249, 0.6); }
.starfield.is-warp .warp__ring {
  animation: warpRing 1700ms cubic-bezier(0.15, 0.85, 0.25, 1) both;
  will-change: transform, opacity;
}
.starfield.is-warp .warp__ring--2 { animation-delay: 130ms; }
.starfield.is-warp .warp__ring--3 { animation-delay: 260ms; }
@keyframes warpRing {
  0%   { opacity: 0.95; transform: scale(0.02); border-width: 5px; }
  70%  { opacity: 0.35; }
  100% { opacity: 0;    transform: scale(1.6);  border-width: 0.5px; }
}

/* 3 · Fogonazo de color. Cubre la pantalla entera un instante con los tres
      colores de la marca. Es lo que hace que el golpe se sienta en toda la
      página y no solo dentro de la ventanita. */
.warp__bloom {
  position: absolute; inset: -30%;
  background:
    radial-gradient(45% 45% at var(--bx, 50%) var(--by, 50%), rgba(255,255,255,0.55) 0%, transparent 55%),
    radial-gradient(75% 75% at var(--bx, 50%) var(--by, 50%), rgba(217, 70, 239, 0.42) 0%, transparent 62%),
    radial-gradient(110% 110% at var(--bx, 50%) var(--by, 50%), rgba(103, 232, 249, 0.24) 0%, transparent 68%);
  opacity: 0;
  mix-blend-mode: screen;
}
.starfield.is-warp .warp__bloom {
  animation: warpBloom 1600ms cubic-bezier(0.1, 0.8, 0.3, 1) both;
}
@keyframes warpBloom {
  0%   { opacity: 0;    transform: scale(0.55); }
  7%   { opacity: 1;    transform: scale(1.02); }
  38%  { opacity: 0.42; }
  100% { opacity: 0;    transform: scale(1.14); }
}

/* 4 · Todo el campo de estrellas da un salto de brillo y zoom. */
.starfield.is-warp {
  animation: starWarp 1800ms cubic-bezier(0.16, 0.9, 0.3, 1) both;
}
@keyframes starWarp {
  0%   { transform: scale(1);    filter: brightness(1); }
  9%   { transform: scale(1.62); filter: brightness(3.4) saturate(1.6); }
  42%  { transform: scale(1.18); filter: brightness(1.5) saturate(1.2); }
  100% { transform: scale(1);    filter: brightness(1) saturate(1); }
}

/* 5 · Las capas salen despedidas a distinta velocidad y se emborronan al
      hacerlo: es el desenfoque de movimiento lo que vende la velocidad.
      Estas animaciones PISAN el transform del parallax durante 1,8 s — es
      intencionado, y al acabar el cursor vuelve a mandar. */
.starfield.is-warp .layer--far {
  animation: layerWarpFar 1800ms cubic-bezier(0.14, 0.9, 0.28, 1) both;
}
.starfield.is-warp .layer--near {
  animation: layerWarpNear 1800ms cubic-bezier(0.12, 0.92, 0.26, 1) both;
}
@keyframes layerWarpFar {
  0%   { transform: scale(1);    filter: blur(0); }
  10%  { transform: scale(2.1);  filter: blur(1.4px); }
  100% { transform: scale(1);    filter: blur(0); }
}
@keyframes layerWarpNear {
  0%   { transform: scale(1);    filter: blur(0); }
  10%  { transform: scale(3.4);  filter: blur(3px); }
  100% { transform: scale(1);    filter: blur(0); }
}

/* 6 · Las nebulosas se encienden y se hinchan, como si el golpe las hubiera
      removido. Vuelven solas a su sitio. */
.starfield.is-warp .nebula {
  animation: nebulaFlare 1800ms ease-out both;
}
.starfield.is-warp .nebula--cyan { animation-delay: 120ms; }
@keyframes nebulaFlare {
  0%   { opacity: 0.5;  transform: scale(1); }
  12%  { opacity: 1;    transform: scale(1.45); }
  100% { opacity: 0.5;  transform: scale(1); }
}

/* La ventana de la app acusa el golpe: un respingo y un destello en el borde.
   Sin esto, la explosión parece de otra película que la maqueta. */
.mock.is-live { animation: mockJolt 900ms cubic-bezier(0.2, 1.4, 0.4, 1) both; }
@keyframes mockJolt {
  0%   { box-shadow: 0 40px 90px rgba(0,0,0,0.6), 0 0 0 rgba(196,181,253,0); }
  14%  { box-shadow: 0 40px 90px rgba(0,0,0,0.6), 0 0 90px 12px rgba(196,181,253,0.55); }
  100% { box-shadow: 0 40px 90px rgba(0,0,0,0.6), 0 0 90px rgba(128,90,242,0.14); }
}

/* ============================================================
   MUNDOS · lo que el estallido deja detrás
   El estallido dura dos segundos; esto se queda. El espacio arranca vacío
   —«EL ESPACIO ESTÁ VACÍO. LO LLENAS TÚ.»— y al terminar de cargar aparecen
   las comunidades convertidas en planetas, con los mismos nombres que salen
   en los pósters de la maqueta. La página no vuelve a ser la de antes.

   .is-warp es transitoria (2 s). .is-born es PARA SIEMPRE.
   ============================================================ */
.worlds {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.world {
  position: absolute;
  opacity: 0;
  /* Parallax con profundidad propia: --d. Los grandes están "cerca" y se
     mueven más que los pequeños del fondo. Es lo que separa unos de otros. */
  transform: translate3d(
    calc(var(--mx, 0) * var(--d, 10) * -1px),
    calc(var(--my, 0) * var(--d, 10) * -0.7px),
    0
  );
}
/* 0.62 y no 1: son fondo. A pleno color, un globo de 128px por detrás se come
   el texto que le caiga encima. Así se ven, pero no compiten. */
.starfield.is-born .world { opacity: 0.62; }

.world__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
}
.starfield.is-born .world__inner {
  animation:
    worldBorn 1100ms cubic-bezier(0.18, 1.5, 0.35, 1) var(--born, 0ms) both,
    /* La flotación arranca cuando el nacimiento termina. Sin `both` en esta
       segunda, durante su retardo no pisa a la primera: las dos animan
       transform y solo puede mandar una. */
    worldFloat var(--float, 16s) ease-in-out calc(var(--born, 0ms) + 1100ms) infinite;
}
@keyframes worldBorn {
  0%   { opacity: 0; transform: scale(0) rotate(-45deg); filter: brightness(3.5); }
  55%  { opacity: 1; transform: scale(1.14) rotate(6deg); filter: brightness(1.6); }
  100% { opacity: 1; transform: scale(1) rotate(0deg);   filter: brightness(1); }
}
@keyframes worldFloat {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-16px) rotate(2.5deg); }
}

/* El planeta. Tres capas de gradiente hacen la esfera: el brillo del sol
   arriba a la izquierda, la sombra del terminador abajo a la derecha, y el
   color base debajo. La sombra interior es la que le da el volumen. */
.world__body {
  display: block;
  width: var(--s, 80px);
  height: var(--s, 80px);
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 26%, rgba(255, 255, 255, 0.55) 0%, rgba(255, 255, 255, 0) 44%),
    radial-gradient(circle at 72% 78%, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 58%),
    var(--surface-art, linear-gradient(150deg, #8b5cf6, #4c1d95));
  box-shadow:
    inset -10px -12px 26px rgba(0, 0, 0, 0.55),
    0 0 var(--halo, 46px) var(--halo-color, rgba(139, 92, 246, 0.4));
}

.world__name {
  font-family: 'Clash Display', sans-serif;
  font-size: var(--fs, 13px);
  font-weight: 600;
  letter-spacing: 0.16em;
  margin-right: -0.16em;
  text-transform: uppercase;
  /* Más alto que el planeta porque hereda el 0.62 del padre: 0.75 × 0.62
     deja el nombre legible sin gritar. */
  color: rgba(226, 222, 250, 0.78);
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.85);
  white-space: nowrap;
}

/* Anillo de Órbita: una elipse aplastada y girada. El planeta la tapa por
   delante porque va detrás en el z, que es lo que hace que se lea como anillo
   y no como un aro pegado encima. */
.world__ring {
  position: absolute;
  top: calc(var(--s) * 0.5);
  left: 50%;
  width: calc(var(--s) * 1.85);
  height: calc(var(--s) * 0.5);
  margin-left: calc(var(--s) * -0.925);
  margin-top: calc(var(--s) * -0.25);
  border-radius: 50%;
  border: 2px solid rgba(196, 181, 253, 0.45);
  border-bottom-color: rgba(196, 181, 253, 0.12);
  transform: rotate(-17deg);
  z-index: -1;
}

/* --- Los seis mundos. Van pegados a los márgenes: el contenido manda. --- */
.world--nebula {
  left: 2%; top: 13%;
  --s: 128px; --d: 26; --fs: 14px; --born: 60ms; --float: 17s;
  --surface-art: linear-gradient(150deg, #c084fc 0%, #7c3aed 45%, #2e1065 100%);
  --halo: 60px; --halo-color: rgba(168, 85, 247, 0.45);
}
.world--vortice {
  right: 3%; top: 60%;
  --s: 94px; --d: 21; --fs: 12px; --born: 190ms; --float: 21s;
  --surface-art:
    repeating-linear-gradient(172deg,
      rgba(255,255,255,0.09) 0 6px, rgba(0,0,0,0.07) 6px 13px),
    linear-gradient(150deg, #f0abfc 0%, #c026d3 48%, #4a044e 100%);
  --halo: 52px; --halo-color: rgba(217, 70, 239, 0.4);
}
.world--orbita {
  left: 8%; top: 73%;
  --s: 62px; --d: 15; --fs: 11px; --born: 320ms; --float: 19s;
  --surface-art: linear-gradient(150deg, #7dd3fc 0%, #0284c7 48%, #082f49 100%);
  --halo: 40px; --halo-color: rgba(56, 189, 248, 0.4);
}
.world--taller {
  right: 10%; top: 15%;
  --s: 52px; --d: 12; --fs: 10px; --born: 430ms; --float: 23s;
  --surface-art: linear-gradient(150deg, #6ee7b7 0%, #059669 48%, #022c22 100%);
  --halo: 34px; --halo-color: rgba(52, 211, 153, 0.35);
}
.world--cripta {
  left: 45%; top: 88%;
  --s: 38px; --d: 8; --fs: 9px; --born: 540ms; --float: 26s;
  --surface-art: linear-gradient(150deg, #fdba74 0%, #ea580c 48%, #431407 100%);
  --halo: 28px; --halo-color: rgba(251, 146, 60, 0.32);
}
/* Abajo a la derecha: a 6% de altura caía justo detrás de la barra de
   navegación, que al hacer scroll se vuelve translúcida y lo dejaba asomando. */
.world--faro {
  right: 7%; top: 86%;
  --s: 30px; --d: 6; --fs: 8.5px; --born: 640ms; --float: 29s;
  --surface-art: linear-gradient(150deg, #fde68a 0%, #f59e0b 48%, #451a03 100%);
  --halo: 26px; --halo-color: rgba(251, 191, 36, 0.3);
}

/* El resto del fondo tampoco vuelve a ser el mismo: las nebulosas se quedan
   más encendidas y las estrellas cercanas a pleno brillo. */
.starfield.is-born .nebula { opacity: 0.72; transition: opacity 1600ms ease 400ms; }
.starfield.is-born .stars--near { opacity: 1; transition: opacity 1600ms ease 400ms; }

/* --- Estrella fugaz. Cruza cada 11 s, en diagonal, dejando estela. --- */
/* Viaja hacia ABAJO-IZQUIERDA, así que dos cosas tienen que cuadrar con eso:
   la cabeza brillante va en el extremo IZQUIERDO (el que va delante) y el
   trazo se inclina EXACTAMENTE en el ángulo del recorrido.

   Antes fallaban las dos: el degradado a 270deg dejaba el blanco en el
   extremo derecho —o sea, la cola por delante y la cabeza arrastrando— y el
   trazo iba rotado 24° mientras el movimiento bajaba 16° hacia el otro lado,
   unos 40° de desfase. Por eso se veía cruzada y al revés. */
.comet {
  position: absolute;
  top: -6%; left: 108%;
  width: 150px; height: 2px;
  border-radius: 999px;
  /* 90deg = primera parada a la IZQUIERDA. Blanco delante, estela detrás. */
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0.95) 0%,
    rgba(196, 181, 253, 0.45) 45%,
    rgba(0, 0, 0, 0) 100%);
  opacity: 0;
  transform: rotate(-18deg);
}
.starfield.is-born .comet {
  animation: cometRun 11s linear 2s infinite;
}
/* El desplazamiento va en vmax en LOS DOS ejes a propósito. Con vw en uno y
   vh en el otro, la proporción —y por tanto el ángulo— cambiaba con cada
   tamaño de ventana, así que la inclinación solo podía cuadrar en una.
   170vmax repartidos con cos(18°)=0.951 y sin(18°)=0.309. */
@keyframes cometRun {
  0%    { opacity: 0;   transform: translate3d(0, 0, 0) rotate(-18deg); }
  2%    { opacity: 0.9; }
  14%   { opacity: 0;   transform: translate3d(-161.7vmax, 52.5vmax, 0) rotate(-18deg); }
  100%  { opacity: 0;   transform: translate3d(-161.7vmax, 52.5vmax, 0) rotate(-18deg); }
}

/* ============================ STRIP ============================ */
.strip { padding: 34px 0 8px; }
.strip__inner { text-align: center; }
.strip__title {
  font-size: clamp(30px, 4.2vw, 46px);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 16px;
}
.strip__text { max-width: 62ch; margin-inline: auto; color: var(--text-mute); font-size: 17.5px; }

.pills {
  list-style: none;
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 10px; margin: 28px 0 0; padding: 0;
}
.pills li {
  padding: 7px 16px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.03);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-mute);
  transition: color 200ms ease, border-color 200ms ease, background 200ms ease;
}
.pills li:hover {
  color: var(--text);
  border-color: rgba(128, 90, 242, 0.55);
  background: rgba(128, 90, 242, 0.12);
}

/* =========================== FEATURES =========================== */
.feature { padding: 96px 0; }

.feature__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 64px;
  align-items: center;
}
.feature--flip .feature__copy { order: 2; }

.feature h2 {
  font-size: clamp(30px, 4vw, 48px);
  font-weight: 700;
  text-transform: uppercase;
  line-height: 1.02;
  letter-spacing: -0.02em;
  margin-bottom: 18px;
}
.feature p { color: var(--text-mute); font-size: 17px; max-width: 50ch; }

/* Gancho de sección: la frase que entra por el ojo antes que la explicación.
   Un punto más grande que el cuerpo y con un filete violeta al costado para
   que se lea como un aparte, no como el primer párrafo de un texto largo. */
.feature .hook {
  font-size: 19.5px;
  line-height: 1.5;
  margin-bottom: 18px;
  padding-left: 16px;
  border-left: 2px solid rgba(128, 90, 242, 0.65);
}

.ticks { list-style: none; margin: 26px 0 0; padding: 0; display: flex; flex-direction: column; gap: 13px; }
.ticks li {
  position: relative;
  padding-left: 30px;
  color: var(--text-mute);
  font-size: 15.5px;
  line-height: 1.5;
}
.ticks li::before {
  content: "";
  position: absolute;
  left: 0; top: 6px;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--violet-soft);
  border: 1px solid rgba(128, 90, 242, 0.5);
}
.ticks li::after {
  content: "";
  position: absolute;
  left: 5px; top: 10px;
  width: 6px; height: 3px;
  border-left: 1.6px solid #c4b5fd;
  border-bottom: 1.6px solid #c4b5fd;
  transform: rotate(-45deg);
}
.ticks--gold li::before { background: rgba(251, 191, 36, 0.12); border-color: rgba(251, 191, 36, 0.5); }
.ticks--gold li::after  { border-color: var(--gold); }

/* --- Capturas reales ---
   Por defecto manda el arte de CSS. El <img> solo se muestra cuando el script
   confirma que la imagen ha CARGADO (no que exista la etiqueta): mientras no
   haya capturas en shots/, la página se ve exactamente igual que ahora. */
.shot { position: relative; }
/* Escondida con opacity y NO con display:none. Con display:none el elemento
   no tiene caja, nunca "entra en pantalla", y una imagen loading="lazy" no se
   llega a pedir jamás: se quedaría oculta esperando una carga que no ocurre.
   Así conserva caja de 1px, se pide al acercarse, y al cargar se despliega. */
.shot__img {
  position: absolute;
  top: 0; left: 0;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}
.shot.has-shot .shot__img {
  position: static;
  opacity: 1;
  pointer-events: auto;
  width: 100%;
  height: auto;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.55), 0 0 70px rgba(128, 90, 242, 0.1);
}
.shot.has-shot .shot__fallback { display: none; }

/* --- Arte: pósters de comunidades --- */
.posters {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}
.poster {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #1b1f2b 0%, #101219 100%);
  overflow: hidden;
  transition: transform 400ms var(--ease), border-color 300ms ease;
}
.poster:hover { transform: translateY(-8px); border-color: rgba(128, 90, 242, 0.55); }
.poster--1 { margin-top: 26px; }
.poster--4 { margin-top: 26px; }
.poster__glow {
  position: absolute; inset: 0;
  opacity: 0.85;
}
.poster--1 .poster__glow { background: radial-gradient(110% 80% at 50% 0%, rgba(217,70,239,0.5), transparent 65%); }
.poster--2 .poster__glow { background: radial-gradient(110% 80% at 50% 0%, rgba(56,189,248,0.45), transparent 65%); }
.poster--3 .poster__glow { background: radial-gradient(110% 80% at 50% 0%, rgba(52,211,153,0.35), transparent 65%); }
.poster--4 .poster__glow { background: radial-gradient(110% 80% at 50% 0%, rgba(128,90,242,0.5), transparent 65%); }
.poster__label {
  position: absolute;
  left: 14px; right: 14px; bottom: 14px;
  height: 8px; border-radius: 4px;
  background: rgba(255, 255, 255, 0.32);
}
.poster__label::after {
  content: "";
  position: absolute; left: 0; top: 15px;
  width: 58%; height: 6px; border-radius: 3px;
  background: rgba(255, 255, 255, 0.16);
}

/* --- Arte: chat --- */
.chatart {
  padding: 26px;
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, #14171f 0%, #0d0f14 100%);
  border: 1px solid var(--line);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.5);
  display: flex; flex-direction: column; gap: 14px;
}
.chatart__row { display: flex; align-items: flex-start; gap: 10px; }
.chatart__row--me { justify-content: flex-end; }
.chatart__av {
  width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(135deg, #f472b6, #a855f7);
}
.chatart__av--2 { background: linear-gradient(135deg, #38bdf8, #6366f1); }
.chatart__b {
  height: 46px; width: 58%;
  border-radius: 14px 14px 14px 5px;
  background: #1c212b;
}
.chatart__b--wide { width: 70%; height: 60px; }
.chatart__b--me {
  border-radius: 14px 14px 5px 14px;
  background: linear-gradient(135deg, rgba(128,90,242,0.6), rgba(217,70,239,0.42));
  width: 46%;
}
.chatart__b--sm { width: 34%; height: 34px; }
.chatart__typing { display: flex; gap: 6px; padding-left: 40px; }
.chatart__typing span {
  width: 8px; height: 8px; border-radius: 50%;
  background: #4a5060;
  animation: bounce 1.3s ease-in-out infinite;
}
.chatart__typing span:nth-child(2) { animation-delay: 0.18s; }
.chatart__typing span:nth-child(3) { animation-delay: 0.36s; }
@keyframes bounce {
  0%, 60%, 100% { transform: translateY(0);   opacity: 0.55; }
  30%           { transform: translateY(-5px); opacity: 1;    }
}

/* --- Arte: overlay sobre el juego --- */
.overlayart {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.55);
}
.overlayart__game {
  position: absolute; inset: 0;
  background:
    radial-gradient(60% 80% at 30% 30%, rgba(59,130,246,0.5), transparent 60%),
    radial-gradient(70% 70% at 75% 70%, rgba(168,85,247,0.45), transparent 60%),
    linear-gradient(160deg, #1b2540 0%, #0b1020 100%);
}
.overlayart__panel {
  position: absolute;
  right: 18px; top: 18px; bottom: 18px;
  width: 44%;
  padding: 16px;
  border-radius: var(--r-md);
  background: rgba(11, 9, 18, 0.72);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
}
.overlayart__head { height: 10px; width: 60%; border-radius: 5px; background: rgba(255,255,255,0.35); margin-bottom: 16px; }
.overlayart__line { height: 30px; border-radius: 10px; background: rgba(255, 255, 255, 0.1); margin-bottom: 10px; }
.overlayart__line--2 { width: 82%; }
.overlayart__line--3 { width: 64%; background: linear-gradient(135deg, rgba(128,90,242,0.5), rgba(217,70,239,0.32)); }
.overlayart__keys { position: absolute; left: 18px; bottom: 18px; display: flex; gap: 6px; }

kbd {
  display: inline-block;
  padding: 5px 10px;
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.09);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-bottom-width: 2px;
  font-family: 'Satoshi', sans-serif;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
}

/* ============================== EOS ==============================
   La estrella del equilibrio: un núcleo de vacío con el filo carmesí y unos
   rayos oscuros girando lentos. Va DELIBERADAMENTE apagada — es lo contrario
   de un foco: absorbe. Un EOS luminoso contaría lo que no es. */
.eyebrow--eos { color: #f87171; }

.eos {
  display: flex;
  align-items: center;
  gap: 22px;
  padding: 26px;
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, #14101c 0%, #0b0810 100%);
  border: 1px solid rgba(220, 38, 38, 0.22);
}

.eos__star {
  position: relative;
  width: 96px; height: 96px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
}
/* Los rayos: rombos alargados, violeta profundo, girando muy despacio. */
.eos__ray {
  position: absolute;
  width: 6px; height: 96px;
  border-radius: 50%;
  background: linear-gradient(180deg, rgba(0,0,0,0) 0%, #4c1d95 30%, #4c1d95 70%, rgba(0,0,0,0) 100%);
  animation: eosSpin 22s linear infinite;
}
.eos__ray--b { transform: rotate(90deg); animation-duration: 30s; animation-direction: reverse; }
@keyframes eosSpin { to { transform: rotate(360deg); } }
.eos__ray--b { animation-name: eosSpinB; }
@keyframes eosSpinB { from { transform: rotate(90deg); } to { transform: rotate(450deg); } }

/* El núcleo: negro absoluto con el filo carmesí. Un solo resplandor, corto. */
.eos__core {
  position: relative;
  width: 46px; height: 46px;
  border-radius: 50%;
  background: #05040a;
  border: 1px solid rgba(220, 38, 38, 0.75);
  box-shadow: 0 0 18px rgba(124, 45, 18, 0.5), inset 0 0 14px rgba(0, 0, 0, 1);
  animation: eosPulse 3.4s ease-in-out infinite;
}
@keyframes eosPulse {
  0%, 100% { transform: scale(1);    border-color: rgba(220, 38, 38, 0.6); }
  50%      { transform: scale(1.06); border-color: rgba(220, 38, 38, 0.95); }
}

/* El cuadro de diálogo, como el de la app. */
.eos__box {
  flex: 1;
  min-width: 0;
  padding: 16px 18px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--line);
}
.eos__line { font-size: 15px; line-height: 1.5; color: #d7d3e8; }

/* El cursor de la máquina de escribir: EOS habla letra a letra. */
.eos__caret {
  display: inline-block;
  width: 7px; height: 14px;
  margin-left: 4px;
  vertical-align: -2px;
  background: #f87171;
  animation: eosCaret 1s steps(1) infinite;
}
@keyframes eosCaret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

@media (max-width: 560px) {
  .eos { flex-direction: column; align-items: flex-start; gap: 18px; padding: 20px; }
}

/* =========================== TARJETAS =========================== */
.cards { padding: 90px 0; }
.cards__title { text-align: center; font-size: clamp(26px, 3.4vw, 38px); margin-bottom: 48px; }

.cards__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 20px;
}

.card {
  padding: 28px;
  border-radius: var(--r-md);
  background: linear-gradient(180deg, rgba(255,255,255,0.045) 0%, rgba(255,255,255,0.015) 100%);
  border: 1px solid var(--line-soft);
  transition: transform 320ms var(--ease), border-color 320ms ease, background 320ms ease;
}
.card:hover {
  transform: translateY(-6px);
  border-color: rgba(128, 90, 242, 0.4);
  background: linear-gradient(180deg, rgba(128,90,242,0.09) 0%, rgba(255,255,255,0.015) 100%);
}
.card__icon {
  width: 44px; height: 44px;
  border-radius: 12px;
  display: grid; place-items: center;
  margin-bottom: 18px;
}
.card__icon--violet { background: rgba(128, 90, 242, 0.16); color: #c4b5fd; }
.card__icon--cyan   { background: rgba(56, 189, 248, 0.14); color: #7dd3fc; }
.card h3 { font-size: 20px; margin-bottom: 10px; }
.card p { color: var(--text-mute); font-size: 15px; }
.card__kbd { margin-top: 14px; display: flex; gap: 6px; }

/* La sección de seguridad se retiró a propósito: en una página que tiene que
   convencer en diez segundos, «la base de datos vigila» no gana a nadie. Eso
   sigue contado, y mejor, dentro de la app (Configuración → Acerca de). */

.tag {
  display: inline-block;
  vertical-align: middle;
  margin-left: 8px;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(251, 191, 36, 0.14);
  border: 1px solid rgba(251, 191, 36, 0.35);
  font-family: 'Satoshi', sans-serif;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold);
}

/* ============================= PRO ============================= */
.pro { padding: 90px 0; }
.pro__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 48px;
  align-items: center;
  padding: 48px;
  border-radius: var(--r-lg);
  background:
    radial-gradient(90% 130% at 100% 0%, rgba(251, 191, 36, 0.14) 0%, transparent 60%),
    linear-gradient(180deg, #16141f 0%, #0d0b13 100%);
  border: 1px solid rgba(251, 191, 36, 0.28);
}
.pro h2 { font-size: clamp(26px, 3.2vw, 36px); margin-bottom: 14px; }
.pro p { color: var(--text-mute); font-size: 16.5px; max-width: 48ch; }

.pro__art { display: grid; place-items: center; }
.crown {
  width: 130px; height: 130px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: #0b0912;
  background: linear-gradient(135deg, #fde68a 0%, #fbbf24 55%, #f59e0b 100%);
  box-shadow: 0 20px 60px rgba(251, 191, 36, 0.3);
}

/* ========================== DESCARGAR ========================== */
.download { padding: 90px 0 110px; }
.download__head { text-align: center; margin-bottom: 46px; }
.download__head h2 { font-size: clamp(28px, 3.6vw, 40px); }

.download__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 20px;
}

.dl {
  display: block;
  padding: 30px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--line);
  transition: transform 320ms var(--ease), border-color 320ms ease, box-shadow 320ms ease;
}
.dl:not(.dl--soon):hover {
  transform: translateY(-6px);
  border-color: rgba(128, 90, 242, 0.55);
  box-shadow: 0 24px 60px rgba(128, 90, 242, 0.18);
}
.dl--main {
  background:
    radial-gradient(100% 120% at 0% 0%, rgba(128, 90, 242, 0.22) 0%, transparent 60%),
    var(--surface);
  border-color: rgba(128, 90, 242, 0.42);
}
.dl__icon {
  width: 52px; height: 52px;
  border-radius: 14px;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, 0.07);
  color: var(--text);
  margin-bottom: 20px;
}
.dl--main .dl__icon { background: rgba(128, 90, 242, 0.22); color: #c4b5fd; }
.dl h3 { font-size: 22px; margin-bottom: 10px; }
.dl p { color: var(--text-mute); font-size: 15px; margin-bottom: 18px; }
.dl__hint {
  display: block;
  margin: -8px 0 16px;
  font-size: 13px;
  color: var(--text-dim);
}
.dl__hint code {
  padding: 1px 6px;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid var(--line);
  font-family: ui-monospace, 'Cascadia Code', Consolas, monospace;
  font-size: 12px;
  color: #c4b5fd;
}
.dl__cta { font-size: 15px; font-weight: 700; color: #c4b5fd; }
.dl__cta--muted { color: var(--text-dim); }
.dl--soon { opacity: 0.62; border-style: dashed; }

.download__note {
  margin-top: 34px;
  text-align: center;
  font-size: 14.5px;
  color: var(--text-dim);
}
.download__note a { color: #c4b5fd; text-decoration: underline; text-underline-offset: 3px; }

/* ============================= PIE ============================= */
.site-footer {
  padding: 48px 0 60px;
  border-top: 1px solid var(--line-soft);
  background: var(--bg-soft);
}
.footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 24px;
}
.footer__brand { display: flex; align-items: center; gap: 11px; }
.footer__nav {
  display: flex; flex-wrap: wrap; gap: 22px;
  margin-inline: auto;
  font-size: 14.5px;
  color: var(--text-mute);
}
.footer__nav a:hover { color: var(--text); }
.footer__legal { font-size: 13.5px; color: var(--text-dim); }

/* =========================== REVELADO =========================== */
/* .reveal va en el MARCADO y el ocultado cuelga de .js (la clase que pone el
   script del <head>). Sin JS no hay .js, no hay ocultado, y la página se lee
   entera: la animación es un adorno y nunca un requisito para ver el texto.

   La transición vive SOLO en el estado visible, no en .reveal. Si se declara
   en .reveal, cualquier cosa que llegue al estado oculto lo hace ANIMANDO —
   el contenido se desvanecía a la vista durante 700 ms nada más cargar.
   Aquí ocultar es instantáneo y solo se anima la entrada. */
.js .reveal {
  opacity: 0;
  transform: translateY(26px);
}
.js .reveal.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 700ms var(--ease), transform 700ms var(--ease);
}

/* ====================== PESTAÑA EN SEGUNDO PLANO ======================
   Congela todo lo que se mueve cuando el visitante se va a otra pestaña.
   Los navegadores modernos ya dejan de componer en pestañas ocultas, así que
   esto es sobre todo un seguro — pero cubre los casos en que la ventana está
   "visible" y tapada por otra, donde algunos sí siguen animando. Y es lo
   mismo que hace la app al minimizarse, que es lo que presume esta página. */
html.is-away .stars,
html.is-away .world__inner,
html.is-away .comet,
html.is-away .boot__tagline span,
html.is-away .boot__bar span,
html.is-away .chatart__typing span,
html.is-away .nebula {
  animation-play-state: paused;
}

/* =========================== RESPONSIVE =========================== */
@media (max-width: 980px) {
  .hero__inner,
  .feature__inner,
  .pro__inner {
    grid-template-columns: 1fr;
    gap: 44px;
  }
  .feature--flip .feature__copy { order: 0; }
  .hero { padding: 48px 0 64px; }
  .feature { padding: 68px 0; }
  .mock { transform: none; }
  .mock:hover { transform: none; }
  .pro__inner { padding: 34px; }
  .pro__art { display: none; }
}

@media (max-width: 820px) {
  .header-cta { display: none; }
  .nav-toggle { display: flex; margin-left: auto; }

  .nav {
    position: absolute;
    top: 100%; left: 0; right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin: 0;
    padding: 8px 24px 20px;
    background: rgba(7, 6, 13, 0.97);
    backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--line-soft);
    display: none;
  }
  .nav.is-open { display: flex; }
  .nav a {
    padding: 14px 0;
    border-bottom: 1px solid var(--line-soft);
    font-size: 16px;
  }
  .nav a:last-child { border-bottom: 0; }
}

@media (max-width: 560px) {
  .wrap { padding-inline: 18px; }
  .hero__actions .btn { width: 100%; }
  .lede { font-size: 16.5px; }
  .feature p, .strip__text { font-size: 16px; }
  .mock__body { grid-template-columns: 108px 1fr; }
  .mock__profile { display: none; }
  /* A 375px, un punto de fuga al 76% deja casi toda la pantalla con las
     estrellas cruzando hacia la izquierda y el aro fuera de cuadro. */
  .hyper { --vx: 50%; --vy: 48%; }

  /* Con el sidebar comiendo ancho, cuatro pósters caen a 44px y los nombres
     se cortan. Tres respiran y siguen contando lo mismo. */
  .mock__row { grid-template-columns: repeat(3, 1fr); }
  .mock__poster--4 { display: none; }
  .mock__pname { font-size: 8.5px; }
  /* El contador y la insignia MIEMBRO juntos no caben en un póster de 63px. */
  .mock__joined { display: none; }

  /* Seis planetas en 375px es un fondo que compite con el texto en vez de
     acompañarlo. Se quedan dos, más pequeños y pegados a los bordes. */
  .world--orbita,
  .world--taller,
  .world--cripta,
  .world--faro { display: none; }
  .world--nebula  { left: -12%; top: 10%;  --s: 92px; --fs: 11px; }
  .world--vortice { right: -10%; top: 66%; --s: 74px; --fs: 10px; }
  .comet { display: none; }
  .footer__inner { flex-direction: column; align-items: flex-start; }
  .footer__nav { margin-inline: 0; }
}

/* ====================== MOVIMIENTO REDUCIDO ====================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .js .reveal { opacity: 1; transform: none; }
  /* Nada de parallax ni resplandor: el fondo se queda quieto. El script
     tampoco los activa, esto es el cinturón por si la clase ya estuviera. */
  .layer, .nebula { transform: none !important; }
  .cursor-glow { display: none; }
  /* Los mundos se quedan (son contenido del fondo, no movimiento), pero
     quietos: ni nacimiento, ni flotación, ni estrella fugaz cruzando. */
  .world, .world__inner { animation: none !important; transform: none !important; }
  .starfield.is-born .world { opacity: 1; }
  .comet { display: none; }
}
