/* ═══════════════════════════════════════════════════════════════════════════
   home-motion.css — homepage motion layer (design port of the 2026-07-05
   motion prototype). PURELY presentational: no content, layout-copy, or SEO
   surface changes. Everything animated is gated under html.enhance (added by
   a pre-paint inline script); without JS the page renders exactly as before.
   transform+opacity only — compositor-safe, zero CLS.
   Spec + conventions: MOTION_REDESIGN_PORT.md (repo root, gitignored).
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  --m-ease-out: cubic-bezier(.22, 1, .36, 1);
  --m-ease-io: cubic-bezier(.65, 0, .35, 1);
  --m-d2: 240ms;
  --m-d3: 420ms;
  --m-d4: 640ms;
}

/* ── Hero H1 masked line-reveals ─────────────────────────────────────────────
   Markup: h1 > span.hl > span.hl-i (text nodes byte-identical to the old H1).
   Default (no JS / no .enhance): inline spans — renders exactly like the
   original single-flow H1, including the existing max-width:11ch wrapping. */
.hero-title .hl,
.hero-title .hl-i { display: inline; }

html.enhance .hero-title { max-width: none; }
html.enhance .hero-title .hl {
  display: block;
  overflow: hidden;
  /* .12em descender allowance — Cormorant J/y tails clip at less */
  padding-bottom: .12em;
  margin-bottom: -.12em;
}
html.enhance .hero-title .hl-i {
  display: block;
  transform: translateY(112%);
  animation: m-line-up .74s var(--m-ease-out) forwards;
}
html.enhance .hero-title .hl:nth-child(1) .hl-i { animation-delay: 0ms; }
html.enhance .hero-title .hl:nth-child(2) .hl-i { animation-delay: 70ms; }
html.enhance .hero-title .hl:nth-child(3) .hl-i { animation-delay: 140ms; }
html.enhance .hero-title .hl:nth-child(4) .hl-i { animation-delay: 210ms; }
@keyframes m-line-up { to { transform: translateY(0); } }

/* ── Hero rise choreography (eyebrow → price → subtitle → CTAs → pills) ────
   From-only keyframes: they end at the element's natural state, so there is
   no fill lock and hover transitions stay instant (NEVER use transitions for
   reveals — a transform transition captures hover-lifts with the delay). */
html.enhance .hero-eyebrow-row,
html.enhance .hero-price-range,
html.enhance .hero-subtitle,
html.enhance .hero-actions,
html.enhance .hero-meta {
  opacity: 1; /* explicit end-state: .fade-in is force-hidden by critical CSS */
  animation: m-rise var(--m-d4) var(--m-ease-out) backwards;
}
html.enhance .hero-eyebrow-row { animation-delay: 80ms; }
html.enhance .hero-price-range { animation-delay: 340ms; }
html.enhance .hero-subtitle    { animation-delay: 420ms; }
html.enhance .hero-actions     { animation-delay: 500ms; }
html.enhance .hero-meta        { animation-delay: 600ms; }
@keyframes m-rise { from { opacity: 0; transform: translateY(14px); } }

/* LCP guard: the subtitle is the homepage's largest contentful paint, and an
   opacity fade defers LCP to fade-end (measured 3.0s mobile vs 1.2s FCP).
   Translate-only entrance for it — full opacity from the first frame, same
   rise timing. Same pre-authorized remedy as /order's step-panel 1. */
@keyframes m-rise-slide { from { transform: translateY(14px); } }
html.enhance .hero-subtitle { animation-name: m-rise-slide; }

/* no-JS safety: the critical-CSS FOUC guard hides .fade-in; make sure it can
   never stay hidden when the enhance script did not run */
html:not(.enhance) .fade-in { opacity: 1; }

/* ── Price-band underline draw ───────────────────────────────────────────── */
html.enhance .hero-price-range .band { position: relative; white-space: nowrap; }
html.enhance .hero-price-range .band::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -3px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--pink, #db266c), var(--pink-text, #ff5a9e));
  transform: scaleX(0);
  transform-origin: left;
  animation: m-draw var(--m-d4) var(--m-ease-out) 820ms both;
}
@keyframes m-draw { to { transform: scaleX(1); } }

/* ── Hero showcase (pen) entrance + ambient float ────────────────────────────
   Layering avoids animation-shorthand collisions (one animation per element):
   .hero-showcase       → scroll-exit (below)      [parallax.js tilts it too]
   .hero-showcase-link  → entrance
   .hero-showcase-inner → infinite float loop
   .hero-showcase-glow  → glow pulse */
html.enhance .hero-showcase-link {
  display: block;
  animation: m-pen-in .9s var(--m-ease-out) 260ms backwards;
}
@keyframes m-pen-in {
  from { opacity: 0; transform: translateY(26px) scale(.97); }
}
html.enhance .hero-showcase-inner {
  animation: m-float 8.5s var(--m-ease-io) 1.3s infinite alternate;
}
@keyframes m-float {
  from { transform: translateY(-8px) rotate(-.9deg); }
  to   { transform: translateY(8px) rotate(.7deg); }
}
html.enhance .hero-showcase-glow {
  animation: m-glow-pulse 7s var(--m-ease-io) infinite alternate;
}
@keyframes m-glow-pulse {
  from { opacity: .75; transform: scale(.96); }
  to   { opacity: 1;   transform: scale(1.05); }
}

/* ── Hero scroll-exit (CSS scroll-driven; requires body overflow-x:clip —
   overflow-x:hidden would make body a scroll container and freeze these) ── */
@supports (animation-timeline: view()) {
  html.enhance .hero-content {
    animation: m-copy-exit linear both;
    animation-timeline: view();
    animation-range: exit 0% exit 92%;
  }
  html.enhance .hero-showcase {
    animation: m-stage-exit linear both;
    animation-timeline: view();
    animation-range: exit 0% exit 92%;
  }
  @keyframes m-copy-exit  { to { opacity: .15; transform: translateY(-42px); } }
  @keyframes m-stage-exit { to { opacity: .1;  transform: translateY(32px);  } }
}

/* ── Section reveal engine (classes are added at runtime by home-motion.js,
   and ONLY to elements below the first viewport — above-fold content is
   never touched, so there is no hide-then-show flash) ─────────────────── */
html.enhance .m-stagger:not(.is-in) > * { opacity: 0; }
html.enhance .m-stagger.is-in > * {
  animation: m-rev-up var(--m-d4) var(--m-ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 70ms);
}
html.enhance .m-reveal:not(.is-in) { opacity: 0; }
html.enhance .m-reveal.is-in {
  animation: m-rev-up var(--m-d4) var(--m-ease-out) backwards;
}
@keyframes m-rev-up { from { opacity: 0; transform: translateY(20px); } }

/* ── Counters (science data row) — no width jitter while counting ────────── */
.data-num { font-variant-numeric: tabular-nums; }

/* ── Magnetic CTAs (transform driven by home-motion.js) ──────────────────── */
.m-magnetic { will-change: transform; }

/* ── Mobile: halved travel — big movement reads as lag on small screens ──── */
@media (max-width: 900px) {
  @keyframes m-rise       { from { opacity: 0; transform: translateY(8px);  } }
  @keyframes m-rise-slide { from { transform: translateY(8px); } }
  @keyframes m-rev-up { from { opacity: 0; transform: translateY(12px); } }
  @keyframes m-pen-in { from { opacity: 0; transform: translateY(14px) scale(.98); } }
  /* the ::after underline can't follow a wrapped inline box — swap to a
     per-line-fragment background underline */
  html.enhance .hero-price-range .band {
    white-space: normal;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
    background: linear-gradient(90deg, var(--pink, #db266c), var(--pink-text, #ff5a9e)) 0 100% / 100% 2px no-repeat;
    padding-bottom: 3px;
  }
  html.enhance .hero-price-range .band::after { display: none; }
}

/* ── Reduced motion: everything lands instantly, ambient loops off ───────── */
@media (prefers-reduced-motion: reduce) {
  html.enhance .hero-title .hl-i,
  html.enhance .hero-eyebrow-row,
  html.enhance .hero-price-range,
  html.enhance .hero-subtitle,
  html.enhance .hero-actions,
  html.enhance .hero-meta,
  html.enhance .hero-showcase-link,
  html.enhance .hero-showcase-inner,
  html.enhance .hero-showcase-glow,
  html.enhance .hero-content,
  html.enhance .hero-showcase,
  html.enhance .m-stagger > *,
  html.enhance .m-reveal {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  html.enhance .hero-price-range .band::after {
    animation: none !important;
    transform: scaleX(1);
  }
}
