/* ============================================================================
   DECODE · intro.css — the sticky stage, the canvas, and the hero's register.
   Loaded AFTER ground-ink.css, so it sits on the dark Ink tokens. Nothing here
   states a colour tokens-ink.css does not already own, except as an alpha over
   the bone.

   #a1 is now the pinned intro act. Its hero is the page's REAL one — there is
   no second copy of it on the page — so these rules only layer the canvas over
   that hero and fade it. The hero's own markup and layout are untouched.

   The stage follows the peak's pattern exactly: `data-sc-stage` on the
   .sheet--solo, content inside .sheet__fold. index.html already carries
   `.sheet[data-sc-stage] > .sheet__fold { position: relative; height: 100% }`
   for #a7, so the fold needs nothing new here.
   ========================================================================= */

/* THE ACT. `data-sc-act="pin"` + `data-sc-span` is the engine's own pinned
   device: scrollcraft.js sets the outer height and sticks the [data-sc-stage]
   child itself, so no height is declared here.

   AND IT PAINTS NO GROUND. This rule said `background: var(--sc-canvas)` for
   one shoot and turned the whole intro bone: the engine writes the drift as
   an INLINE `--sc-canvas` on <html>, and an inline custom property beats
   ground-ink.css's `:root[style]` reclaim, so --sc-canvas reads
   rgb(239,233,221) from the moment #a1's own ramp starts — a1's drift is
   still the cream value the bone build used. ground-ink.css deliberately
   makes `.act, .sheet, .sheet__fold` transparent so the tapestry shows
   through and `body` alone owns the ink; the intro obeys that, and the ground
   under the glyphs is the page's own. */
#a1 { position: relative; }

/* THE STAGE. The engine adds .sc-stage (position: sticky, top 0, 100svh,
   overflow: clip) to the element carrying data-sc-stage; this only adds the
   layering the intro needs. `min-height: 0` cancels `.sheet--solo`'s
   `min-height: 100%`, which on a 2.2-span act would otherwise be 220vh of
   sheet inside a 100svh sticky box. */
#a1 .sheet[data-sc-stage] { min-height: 0; height: 100svh; isolation: isolate; }

/* The fold is the grid the two layers share, so the canvas and the hero are in
   the same cell and therefore in register. */
#a1 .sheet[data-sc-stage] > .sheet__fold {
  display: grid;
  align-content: center;
  isolation: isolate;
}
#a1 .sheet__fold > .hero { grid-area: 1 / 1; z-index: 1; }
#a1 .sheet__fold > #decode { grid-area: 1 / 1; z-index: 2; }

/* THE GLYPH FIELD. One canvas carries the rain and the landing lights, so the
   whole intro is a single draw loop and a single composited layer. The cloth
   under the glyphs is tapestry.js's own canvas, behind the whole page — these
   glyphs land on its real vertices through window.__tapestry.project(). */
#decode {
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

/* THE HERO, in register under the rain. The intro fades it and lets it settle
   the last hair of a pixel, so the code resolves INTO the page instead of
   being replaced by it. `opacity` is written by intro.js off the act's
   progress; --decode-in carries the same value so the settle is pure CSS. */
#a1 .hero {
  opacity: 0;
  /* F-007: locked from the first paint, not from the first draw(); intro.js
     writes an inline `auto` once the hero is ≥ 90% resolved. */
  pointer-events: none;
  transform: scale(calc(1 + (1 - var(--decode-in, 0)) * 0.012));
  will-change: opacity, transform;
}

/* REDUCED MOTION: the final state. The canvas is drawn once at p = 1 (no rain)
   and the hero is simply there — no fade, no scale, no rAF loop. */
@media (prefers-reduced-motion: reduce) {
  #a1 .hero { opacity: 1 !important; transform: none; will-change: auto; }
}
