  /* ---------- Reset & root variables ---------- */
  *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

  :root {
    --accent: #38bdf8;
    --text-primary: oklch(0.96 0.01 262);
    --text-body: oklch(0.8 0.02 262);
    --font-head: 'Space Grotesk', sans-serif;
    --font-body: 'Manrope', sans-serif;
  }

  html, body { height: 100%; overflow: hidden; }

  body {
    position: relative;
    background: radial-gradient(120% 90% at 50% 0%, oklch(0.22 0.04 268), oklch(0.15 0.02 262) 55%, oklch(0.12 0.015 262));
    font-family: var(--font-body);
    color: var(--text-body);
  }

  /* ---------- Nebula (drifting blurred clouds) ---------- */
  .nebula {
    position: absolute;
    inset: -10%; /* extends past the viewport so the blurred edge never shows a seam */
    background:
      radial-gradient(circle at 18% 22%, oklch(0.45 0.09 285 / 0.5), transparent 60%),
      radial-gradient(circle at 82% 68%, oklch(0.45 0.07 225 / 0.42), transparent 60%);
    filter: blur(30px);
    opacity: 0.5;
    animation: nebula-drift 34s ease-in-out infinite;
    pointer-events: none;
  }

  @keyframes nebula-drift {
    0%, 100% { transform: translate(0, 0) scale(1); }
    25%      { transform: translate(-3%, 2%) scale(1.04); }
    50%      { transform: translate(2%, -3%) scale(1.08); }
    75%      { transform: translate(-2%, -2%) scale(1.03); }
  }

  /* ---------- Star field ---------- */
  .stars {
    position: fixed;
    inset: 0;
    pointer-events: none;
  }

  .star {
    position: absolute;
    border-radius: 50%;
    animation: twinkle 4s ease-in-out infinite;
  }

  /* Twinkle reads opacity from --o (each star's own base opacity) rather than a
     fixed number, so one shared keyframe set can twinkle 180 stars of different
     brightness relative to their own base, instead of flattening them all. */
  @keyframes twinkle {
    0%, 100% { opacity: var(--o); transform: scale(1); }
    50%      { opacity: calc(var(--o) * 0.42); transform: scale(0.82); }
  }

  /* ---------- Shooting stars ---------- */
  .shooting-stars {
    position: fixed;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
  }

  .shooting-star {
    position: absolute;
    width: 0;
    height: 0;
    transform-origin: 0 0;
    animation: streak var(--dur) cubic-bezier(0.25, 0.5, 0.4, 1) forwards;
  }

  @keyframes streak {
    0%   { transform: rotate(var(--a)) translateX(0) scaleX(0.35); opacity: 0; }
    12%  { transform: rotate(var(--a)) translateX(calc(var(--d) * 0.12)) scaleX(1); opacity: 1; }
    100% { transform: rotate(var(--a)) translateX(var(--d)) scaleX(0.55); opacity: 0; }
  }

  .ss-halo, .ss-trail {
    position: absolute;
    top: 0;
    left: calc(-1 * var(--len) * 1px);
    width: calc(var(--len) * 1px);
    transform: translateY(-50%);
  }

  .ss-halo {
    height: calc(var(--thick) * 4px);
    background: linear-gradient(90deg, transparent, oklch(0.85 0.07 252 / 0.12) 55%, oklch(0.92 0.06 252 / 0.4));
    filter: blur(2.5px);
  }

  .ss-trail {
    height: calc(var(--thick) * 1px);
    border-radius: 999px;
    background: linear-gradient(90deg, transparent, oklch(0.9 0.04 252 / 0.28) 45%, oklch(0.99 0.015 252) 96%);
  }

  .ss-head {
    position: absolute;
    top: 0;
    left: 0;
    width: 3px;
    height: 3px;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    background: oklch(0.995 0.005 100);
    box-shadow:
      0 0 4px 1px oklch(0.99 0.02 252 / 0.9),
      0 0 10px 3px oklch(0.9 0.05 252 / 0.5),
      0 0 18px 6px oklch(0.85 0.07 252 / 0.25);
  }

  /* ---------- Constellations ---------- */
  .constellations {
    position: fixed;
    inset: 0;
    pointer-events: none; /* the layer itself is transparent to clicks; each box re-enables events */
  }

  .const-box {
    position: absolute;
    pointer-events: auto;
  }

  /* Lines live in an SVG whose viewBox is stretched independently on x and y to
     fit non-square boxes (e.g. Orion 170x200). A <circle> in that SVG would be
     scaled into an ellipse, so stars are plain divs instead; the SVG carries
     only the lines, and vector-effect keeps their stroke from thickening on
     one axis. */
  .const-lines {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    transition: opacity 0.4s;
  }

  .const-lines line {
    stroke: oklch(0.88 0.03 255);
    stroke-width: 1;
    stroke-opacity: 0.45;
  }

  .const-box.active .const-lines { opacity: 1; }

  .const-star {
    position: absolute;
    border-radius: 50%;
  }

  .const-name {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    font-family: var(--font-head);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.22em;
    color: oklch(0.86 0.02 258);
    white-space: nowrap;
    opacity: 0;
    transition: opacity 0.4s;
  }

  .const-name--above { bottom: calc(100% + 10px); }
  .const-name--below { top: calc(100% + 10px); }

  .const-box.active .const-name { opacity: 1; }

  .const-star-label {
    position: absolute;
    font-family: var(--font-head);
    font-size: 9px;
    letter-spacing: 0.1em;
    color: oklch(0.9 0.02 258);
    white-space: nowrap;
    opacity: 0;
    transition: opacity 0.4s;
  }

  /* Default side: right of the dot. 'left' flips across the anchor point with
     translateX(-100%) plus a negative margin, since left/top % anchor the
     element's own corner, not its centre. */
  .const-star-label--right { transform: translateY(-50%); margin-left: 8px; }
  .const-star-label--left  { transform: translate(-100%, -50%); margin-left: -8px; }

  .const-box.active .const-star-label { opacity: 1; }

  /* ---------- Centred content ---------- */
  .content {
    position: relative;
    min-height: 100vh;
    box-sizing: border-box; /* padding must be included in the 100vh, else it overflows and scrolls */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 40px 24px;
    /* This wrapper is min-height:100vh and sits on top of the constellation
       boxes near the edges. Without pointer-events:none here, it would
       swallow every mouseenter before it reaches a constellation box and the
       hover reveal would never fire. Interactive children opt back in below. */
    pointer-events: none;
  }

  .title {
    font-family: var(--font-head);
    font-weight: 700;
    font-size: clamp(2rem, 7vw, 3.4rem);
    color: var(--text-primary);
    letter-spacing: -0.01em;
    pointer-events: auto;
  }

  .subtitle-row {
    display: flex;
    align-items: center;
    gap: 16px;
    margin: 18px 0 28px;
    pointer-events: auto;
  }

  .rule {
    height: 1px;
    width: clamp(16px, 6vw, 64px);
  }

  .rule--left  { background: linear-gradient(to left, var(--accent), transparent); }
  .rule--right { background: linear-gradient(to right, var(--accent), transparent); }

  .subtitle {
    font-family: var(--font-head);
    font-weight: 500;
    font-size: clamp(0.65rem, 2.2vw, 0.85rem);
    text-transform: uppercase;
    letter-spacing: 0.25em;
    color: var(--accent);
    white-space: nowrap;
  }

  .intro {
    font-family: var(--font-body);
    font-weight: 300;
    font-size: clamp(0.82rem, 1.6vw, 1rem);
    line-height: 1.7;
    color: var(--text-body);
    max-width: 540px;
    margin-bottom: 32px;
    pointer-events: auto;
  }

  .links {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
  }

  .pill {
    font-family: var(--font-head);
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-primary);
    text-decoration: none;
    padding: 10px 22px;
    border: 1px solid var(--accent);
    border-radius: 999px;
    transition: background 0.25s, color 0.25s;
    pointer-events: auto;
  }

  .pill:hover {
    background: var(--accent);
    color: oklch(0.15 0.02 262);
  }

  /* Below this width the figures can no longer keep their labels both inside
     the viewport and clear of the centred text (measured: clean to 860px,
     colliding by 820px). Hiding them beats reflowing a real star map. */
  @media (max-width: 899px) {
    .constellations { display: none; }
  }

  /* ---------- Reduced motion ---------- */
  @media (prefers-reduced-motion: reduce) {
    .star, .nebula { animation: none; }
  }
