/* ══════════════════════════════════════════════════════════════
   Keln — landing-portal rollout banner + bloom bridge.

   Two responsibilities:

   1. THE ROLLOUT BANNER (unchanged from pre-cinema).
      Governs the portal-preview A/B rollout UI that
      landing-portal.js mounts when data-landing-variant="portal".

   2. THE BLOOM BRIDGE.
      When the cinema completes, the portal transitions from a
      dormant state to a live one. That's what "bloom" means
      visually — no motion new to the portal, just the amplitudes
      of what it was already doing.

   ══ THIS FILE LOADS AFTER landing.css ═══════════════════════
   ...which means anything here with a heavier selector silently
   wins against the rules that own the portal's geometry. That is
   how the bloom bridge came to be flattening the disc; see the
   long note above the bridge. Before adding a rule here, check
   whether landing.css already declares the property, and if it
   does, put the rule there instead.
   ══════════════════════════════════════════════════════════════ */

/* ── Rollout banner (kept as-is) ──────────────────────────── */
.portal-rollout {
  position: relative;
  z-index: 20;
  width: min(980px, calc(100% - 32px));
  margin: var(--s-9) auto 0;
  padding: var(--s-9);
  border: 1px solid rgba(91,140,255,.35);
  border-radius: var(--r-lg);
  background: rgba(8,12,20,.88);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.portal-rollout__inner { display: grid; gap: var(--s-6); }
.portal-rollout__eyebrow {
  margin: 0;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--accent2, #22d3a6);
  font-size: var(--t-sm);
}
.portal-rollout__title { margin: 0; font-size: clamp(24px, 3.2vw, 42px); }
.portal-rollout__sub   { margin: 0; color: var(--muted, #8b9bb0); }
.portal-rollout__actions,
.portal-rollout__nodes,
.portal-rollout__cta {
  display: flex; flex-wrap: wrap; gap: var(--s-5);
}
.portal-rollout button,
.portal-rollout a {
  border: 1px solid rgba(91,140,255,.45);
  background: rgba(16,23,36,.7);
  color: var(--ink);
  border-radius: var(--r-md);
  padding: var(--s-5) var(--s-7);
  text-decoration: none;
  cursor: pointer;
}
.portal-rollout button:hover,
.portal-rollout a:hover {
  border-color: rgba(34,211,166,.8);
}

/* ── Bloom bridge ─────────────────────────────────────────
   The portal exists at reduced amplitude while the cinema is
   pending. When body[data-cinema="done"] flips, the three nodes
   light in sequence so they don't all arrive at once.

   ══ WHY THIS IS WRITTEN ON THE NODE'S CHILDREN ══════════════

   It used to be written on .portal-node itself:

     body[data-cinema="done"] .portal-node {
       opacity: 1;
       transform: none;
     }

   Both declarations were load-bearing for something else, and
   this rule is more specific than the ones in landing.css that
   own them, so it won every time:

     · TRANSFORM. .portal-node is anchored by its DOT, not by its
       box: landing.js writes the dot's position to --x/--y and
       landing.css pulls the whole column back onto that point
       with `translate(-50%, calc(-100% + 5px)) scale(var(--s))`.
       Overwriting that with `none` left every node hanging down
       and to the right of the point it was supposed to mark —
       the label's top-left corner sitting where the dot belonged,
       so all three read as scattered off the ellipse rather than
       riding it. It also dropped scale(--s), the depth cue.
     · OPACITY. landing.css sets it from --depth, which is what
       makes a node on the far side of the plane read as further
       away. Pinning it to 1 flattened the disc.

   .portal-node__text is the one part of a node that carries no
   geometry and no transition of its own, so it is the only safe
   place to put a fade — every other element in the node is either
   the anchor itself or already transitioning something (the dot
   its glow and hover scale, the leader its height and gradient),
   and a `transition` declared here would replace those lists
   rather than add to them.

   So the dot and its leader arrive with the disc, under
   landing.css's reveal of .portal-field, and the three NAMES come
   in after them, one at a time. The stagger keys off [data-node],
   which is markup that exists — the old
   .portal-node--constellation / --orbit / --calendar selectors
   matched nothing on the page, so the sequence never actually ran.

   The ring and Vega are not touched here at all. landing.css
   already reveals .portal-field, which contains both; a second
   fade on the same pixels was only ever fighting the first.
   (The old rules named .portal__ring and .portal__vega, classes
   the rebuilt markup does not have, so they too were inert.) */
body[data-cinema="pending"] .portal-node__text {
  opacity: 0;
  transition: opacity .6s cubic-bezier(.16,.86,.22,1);
}
body[data-cinema="done"] .portal-node__text {
  opacity: 1;
  transition: opacity .6s cubic-bezier(.16,.86,.22,1) var(--node-delay, 0s);
}
body[data-cinema="done"] [data-node="constellation"] { --node-delay: .1s; }
body[data-cinema="done"] [data-node="orbit"]         { --node-delay: .25s; }
body[data-cinema="done"] [data-node="calendar"]      { --node-delay: .4s; }

@media (prefers-reduced-motion: reduce) {
  body[data-cinema] .portal-node__text {
    opacity: 1;
    transition: none;
  }
}
