/* Parcival — the opening bumper.
   A port of `Parcival Bumper.dc.html` from the Claude Design project
   "Parcival Bumper", minus the GAME STUDIO subtitle and minus the fade-out
   that ended it: instead of fading, the cup flies to the header and becomes
   the site's mark (assets/js/intro.js).

   The stage is authored at 1920×1080 and scaled to fit, exactly as the
   bumper was, so every coordinate below is the design's own number. Beats
   are counted in --b, one beat, so the whole thing retimes from one value.

   Nothing here runs without JS: intro.js builds the stage. The page under
   it is complete and interactive on its own. */

/* The cover the head script paints before the body has rendered, so the
   page never flashes ahead of the bumper. It is a separate class from
   pv-intro-on because it comes off earlier: the moment the cup leaves for
   the corner, the page has to be showing through behind it. Leaving it up
   for the whole flight was the first cut, and it turned the hand-off into
   a jump — the cup travelled over black and the site appeared underneath
   it all at once at the end. A failsafe timer drops it if intro.js never
   arrives. */
/* The ambient field. It belongs to the viewport-filling layers rather than to
   the 1920x1080 stage, because the stage is letterboxed on any screen taller
   than 16:9 — which on a phone is nearly all of it. With the gradient on the
   stage, the band it occupied was visibly lighter than the flat surround and
   the bumper read as a horizontal video dropped into the page. Painted across
   the viewport there is no edge left to notice. Declared here so the cover and
   the stage paint the same thing and the hand-off between them is invisible. */
html { --pv-field: radial-gradient(120% 95% at 50% 30%, #1c1f31 0%, #0f1019 72%); }

html.pv-intro-cover::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 900;
  background: #0f1019 var(--pv-field);
}
html.pv-intro-on body { overflow: hidden; }
/* The header's cup is the thing the flight lands on. It stays invisible
   until the flier gets there, or the mark would be sitting in the corner
   watching a copy of itself arrive. */
html.pv-intro-on .brand-chalice { opacity: 0; }
/* The aureole goes with it. Left painted, it sat in the corner as a purple
   smudge with nothing in it for the whole flight. */
html.pv-intro-on .brand-grail { background: none; }

.pv-intro {
  position: fixed;
  inset: 0;
  z-index: 1000;
  overflow: hidden;
  background: #0f1019 var(--pv-field);
  --ac: var(--color-accent-500);
}
/* The veil at viewport scale. .pv-dark takes the rose down inside the stage;
   this takes everything outside it down on the same beat, so the screen dims
   as one field instead of a dark rectangle appearing over the band. Same
   colour and same timing as .pv-dark, or the seam comes back at the end. */
.pv-backdrop { position: absolute; inset: 0; background: #05060a; opacity: 0; }
/* 1920×1080 held at the centre and scaled to whichever axis runs out
   first — letterboxed against the same near-black the stage sits on. */
.pv-fit {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1920px;
  height: 1080px;
  transform-origin: center center;
}
.pv-stage {
  position: relative;
  width: 1920px;
  height: 1080px;
  overflow: hidden;
}
.pv-stage > svg { position: absolute; }
.pv-rose { inset: 0; width: 100%; height: 100%; }

/* The cup is its own element rather than a group inside the full-frame
   svg. It carries the same viewBox as the header mark, so the flight is a
   box moving to a box — the drawing inside cannot drift. */
.pv-cup {
  left: 722px;
  top: 314px;
  width: 476px;
  height: 366px;
  overflow: visible;
  transform-origin: center center;
  filter: drop-shadow(0 0 16px color-mix(in srgb, var(--ac) 55%, transparent));
}
.pv-cup g { fill: none; stroke: var(--ac); stroke-width: 4.5; stroke-linecap: round; }

/* The veil that takes the rose away before the cup settles. */
.pv-dark { position: absolute; inset: 0; background: #05060a; opacity: 0; }

.pv-orbit { position: absolute; left: 960px; top: 324px; width: 0; height: 0; transform-origin: 0 0; }
.pv-spark {
  position: absolute;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--color-neutral-100);
  box-shadow: 0 0 40px var(--ac), 0 0 14px var(--color-neutral-100);
}
.pv-orbit .pv-spark { left: -15px; top: -243px; }
.pv-drop { left: 945px; top: 81px; opacity: 0; }
.pv-bloom {
  position: absolute;
  left: 774px;
  top: 234px;
  width: 372px;
  height: 372px;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--ac) 50%, transparent) 0%, transparent 68%);
}
.pv-name {
  position: absolute;
  left: 0;
  right: 0;
  top: 790px;
  text-align: center;
  font: 500 84px/1 var(--font-heading);
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  color: var(--color-neutral-100);
}

/* The flier: the cup lifted out of the stage at its measured screen box and
   sent to the header's. Outside .pv-intro, so the stage can fade behind it
   while it is still travelling. */
.pv-flier {
  position: fixed;
  z-index: 1001;
  transform-origin: 0 0;
  pointer-events: none;
  overflow: visible;
  filter: drop-shadow(0 0 16px color-mix(in srgb, var(--color-accent-500) 55%, transparent));
}
.pv-flier g { fill: none; stroke: var(--color-accent-400); stroke-linecap: round; }

/* ── beats ────────────────────────────────────────────────────────────── */
@keyframes pv-strokeIn { from { stroke-dashoffset: var(--len); } to { stroke-dashoffset: 0; } }
@keyframes pv-fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes pv-fadeOut { to { opacity: 0; } }
/* All the way out, not to 0.07. A 7% rose is invisible against the stage's
   own gradient but not against the cup's glow — it left a ghost ring of
   arcs and nodes hanging over the cup and the wordmark for the two beats
   before the veil arrives, which reads as a stray mark rather than as a
   trace of the rose. */
@keyframes pv-dim { to { opacity: 0; } }
@keyframes pv-orbit360 { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes pv-nodeLit {
  0% { transform: scale(0.6); opacity: 0; }
  45% { transform: scale(2.1); opacity: 1; }
  100% { transform: scale(1.3); opacity: 1; }
}
@keyframes pv-plunge { from { transform: translateY(0) scale(1); } to { transform: translateY(324px) scale(0.8); } }
@keyframes pv-bloom {
  from { transform: scale(0.15); opacity: 0; }
  45% { opacity: 0.9; }
  to { transform: scale(1); opacity: 0.45; }
}
@keyframes pv-cupSettle { to { transform: scale(0.7); } }
@keyframes pv-glowSettle { to { transform: scale(0.7); opacity: 0.28; } }
@keyframes pv-nameGrow { to { transform: translateY(-84px) scale(1.34); } }
@keyframes pv-popUp {
  0% { opacity: 0; transform: translateY(48px) scale(0.94); }
  55% { opacity: 1; transform: translateY(-7px) scale(1.02); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
