/* ============================================================================
   MOTION — reveals, the stamp, and the curtain lift

   Everything here is gated on html[data-boot], which is set by an inline
   script in <head>. With JavaScript disabled the attribute never appears,
   so no element is ever hidden by CSS that JS was supposed to un-hide.
   ========================================================================== */

html[data-boot] [data-reveal] {
  --reveal-delay: calc(var(--reveal-i, 0) * 70ms);
  transition:
    opacity var(--dur-entrance) var(--ease-out-quart) var(--reveal-delay),
    transform var(--dur-entrance) var(--ease-out-quart) var(--reveal-delay),
    clip-path var(--dur-entrance) var(--ease-out-quart) var(--reveal-delay);
  will-change: opacity, transform;
}

/* ---- Flavours ------------------------------------------------------------ */

html[data-boot] [data-reveal="up"],
html[data-boot] [data-reveal=""] {
  opacity: 0;
  transform: translate3d(0, 20px, 0);
}

html[data-boot] [data-reveal="fade"] { opacity: 0; }

/* Headings arrive from further down and settle — the extra distance is what
   makes a masthead feel like it lands rather than appears. */
html[data-boot] [data-reveal="rise"] {
  opacity: 0;
  transform: translate3d(0, 34px, 0);
}

/* The press. Used only for the seal watermark. */
html[data-boot] [data-reveal="stamp"] {
  opacity: 0;
  transform: scale(1.16);
}

/* A printed rule: the row wipes in left-to-right, as if run through a press. */
html[data-boot] [data-reveal="rule"] {
  opacity: 0;
  clip-path: inset(0 100% 0 0);
}

/* Photographs develop upward out of the plate. */
html[data-boot] [data-reveal="mask"] {
  opacity: 0;
  clip-path: inset(14% 0 0 0);
}

html[data-boot] [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 0 0);
  will-change: auto;
}

/* ---- Failsafe -----------------------------------------------------------
   Every reveal starts at opacity 0, so if the reveal engine never runs the
   entire page is invisible — a blank site with no error to see. app.js sets
   data-reveal-live as soon as one element has actually revealed, which
   disarms this. While that marker is absent, the content shows itself. */
html[data-boot]:not([data-reveal-live]) [data-reveal] {
  animation: reveal-failsafe 400ms linear 6s forwards;
}
@keyframes reveal-failsafe {
  to { opacity: 1; transform: none; clip-path: none; }
}

/* ---- Parallax ------------------------------------------------------------ */

[data-parallax] { transform: translate3d(0, var(--py, 0px), 0); }

/* ============================================================================
   THE CURTAIN — the seal presses onto the paper
   ========================================================================== */

/* Arrives high and slightly turned, then drives down and squares up. */
@keyframes seal-press {
  0%   { opacity: 0; transform: translate3d(0, -14%, 0) scale(1.55) rotate(-9deg); }
  55%  { opacity: 1; transform: translate3d(0, 0, 0) scale(1.06) rotate(1.5deg); }
  72%  { transform: translate3d(0, 0, 0) scale(0.965) rotate(0deg); }
  100% { opacity: 1; transform: translate3d(0, 0, 0) scale(1) rotate(0deg); }
}

/* The ink halo thrown off by the impact. */
@keyframes seal-halo {
  0%   { opacity: 0; transform: scale(0.82); }
  22%  { opacity: 0.85; }
  100% { opacity: 0; transform: scale(1.85); }
}

@keyframes fade-up-in {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: none; }
}

html[data-curtain="up"] .curtain #seal-origin {
  animation: seal-press var(--dur-stamp) var(--ease-out-quart) 120ms both;
}
html[data-curtain="up"] .curtain__sealring {
  animation: seal-halo 1100ms var(--ease-out-quart) 640ms both;
}

/* The text settles after the seal has landed, never with it. */
/* The portrait fades up first, right after the seal lands (~1020ms in), so
   the person arrives on the heels of the stamp and before his name. */
html[data-curtain="up"] .curtain__avatar { animation: fade-up-in 640ms var(--ease-out-quart) 760ms both; }
html[data-curtain="up"] .curtain__estd  { animation: fade-up-in 620ms var(--ease-out-quart)  860ms both; }
html[data-curtain="up"] .curtain__name  { animation: fade-up-in 620ms var(--ease-out-quart)  900ms both; }
html[data-curtain="up"] .curtain__cred  { animation: fade-up-in 620ms var(--ease-out-quart)  980ms both; }
html[data-curtain="up"] .curtain__gate  { animation: fade-up-in 700ms var(--ease-out-quart) 1120ms both; }

/* ---- The flight: curtain seal → masthead slot ----------------------------
   seal.js measures both boxes and drives the transform directly, so this
   only has to declare how the flight feels and lift it above the curtain. */
.seal.is-flying {
  position: fixed;
  z-index: calc(var(--z-curtain) + 2);
  margin: 0;
  transform-origin: 50% 50%;
  transition: transform 900ms var(--ease-out-quint);
  pointer-events: none;
}

/* ---- The paper unrolls over the ink ground ------------------------------- */
.curtain.is-lifting {
  clip-path: inset(0 0 0 0);
  animation: curtain-lift 760ms var(--ease-in-out) forwards;
}
@keyframes curtain-lift {
  from { clip-path: inset(0 0 0 0); opacity: 1; }
  to   { clip-path: inset(0 0 100% 0); opacity: 1; }
}
.curtain.is-lifting .curtain__inner {
  animation: fade-out-down 380ms var(--ease-in-quart) forwards;
}
@keyframes fade-out-down {
  to { opacity: 0; transform: translate3d(0, 18px, 0); }
}

/* ---- Scroll cue ---------------------------------------------------------- */
@keyframes drift {
  0%, 100% { transform: translate3d(0, 0, 0); opacity: 0.55; }
  50%      { transform: translate3d(0, 6px, 0); opacity: 1; }
}
.hero__scroll { animation: drift 2.8s var(--ease-in-out) infinite; }

/* ============================================================================
   REDUCED MOTION
   Content still reveals — it simply stops travelling. The seal does not
   fly; it is placed. The curtain does not roll; it cuts.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html[data-boot] [data-reveal] {
    transition: opacity 200ms linear;
    transform: none !important;
    clip-path: none !important;
  }
  html[data-boot] [data-reveal="stamp"],
  html[data-boot] [data-reveal="rule"],
  html[data-boot] [data-reveal="mask"] { clip-path: none; transform: none; }

  html[data-curtain="up"] .curtain #seal-origin,
  html[data-curtain="up"] .curtain__sealring,
  html[data-curtain="up"] .curtain__avatar,
  html[data-curtain="up"] .curtain__estd,
  html[data-curtain="up"] .curtain__name,
  html[data-curtain="up"] .curtain__cred,
  html[data-curtain="up"] .curtain__gate { animation: none; opacity: 1; transform: none; }

  .curtain__sealring { opacity: 0; }
  .seal.is-flying { transition: none; }
  .curtain.is-lifting { animation: none; opacity: 0; }
  .hero__scroll { animation: none; opacity: 0.7; }
  [data-parallax] { transform: none; }
}
