/* ==========================================================================
   The Lead Gen Company — motion layer (v2)
   Loads AFTER leadhq-lab.css / leadhq-guide.css / leadhq-asset.css.

   Rules this layer obeys:
   1. Nothing hides unless JS is running. `.m-on` is set on <html> by an inline
      script, so with JS off or broken every element renders at its final state.
   2. Only `transform` and `opacity` animate. No layout-affecting properties.
   3. Every reveal is one-shot. Scrolling back up does not replay it.
   4. The lead form, nav, breadcrumbs, tables and legal copy are excluded by
      design — see MOTION-MAP.md.
   ========================================================================== */

:root {
  --m-fast:    180ms;   /* hover / press feedback                    */
  --m-base:    520ms;   /* section + card reveals                    */
  --m-slow:    760ms;   /* headline line masks, hero imagery         */
  --m-stagger:  70ms;   /* between headline lines                    */
  --m-stagger-sm: 60ms; /* between sibling cards                     */
  --m-out:     cubic-bezier(.22, .61, .36, 1);   /* ease-out-quad    */
  --m-expo:    cubic-bezier(.16, 1, .30, 1);     /* ease-out-expo    */
  --m-spring:  cubic-bezier(.34, 1.4, .64, 1);   /* slight overshoot */
}

/* ==========================================================================
   1. HERO — headline entrance
   Each word is wrapped in a clipping box; words sharing a line share a delay,
   so the headline reads as a line-by-line wipe rather than a word scatter.
   Padding + equal negative margin keeps descenders (g, y, p) out of the clip.
   ========================================================================== */
.m-w {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding: .08em 0 .16em;
  margin: -.08em 0 -.16em;
}
.m-w > i {
  display: inline-block;
  font-style: inherit;
  will-change: transform;
}
.m-on .m-w > i {
  transform: translateY(112%);
}
.m-on .m-in .m-w > i {
  transform: translateY(0);
  transition: transform var(--m-slow) var(--m-expo);
  transition-delay: calc(var(--m-line, 0) * var(--m-stagger));
}

/* Hero supporting elements: eyebrow, sub, CTA row, readouts, console.
   Sequenced after the headline so the eye lands on the claim first. */
.m-on [data-m-hero] {
  opacity: 0;
  transform: translateY(14px);
  will-change: transform, opacity;
}
.m-on .m-in[data-m-hero],
.m-on .m-in [data-m-hero] {
  opacity: 1;
  transform: none;
  transition: opacity var(--m-base) var(--m-out),
              transform var(--m-base) var(--m-out);
  transition-delay: calc(var(--m-seq, 0) * var(--m-stagger-sm));
}

/* ==========================================================================
   2. SCROLL REVEALS — supporting sections
   18px is deliberately short: enough to register as arrival, not enough to
   feel like the page is assembling itself.
   ========================================================================== */
.m-on [data-m-reveal] {
  opacity: 0;
  transform: translateY(18px);
  will-change: transform, opacity;
}
.m-on [data-m-reveal].m-in {
  opacity: 1;
  transform: none;
  transition: opacity var(--m-base) var(--m-out),
              transform var(--m-base) var(--m-out);
  transition-delay: calc(var(--m-seq, 0) * var(--m-stagger-sm));
}

/* Imagery: settles from a slight over-scale so the frame feels like it
   resolves rather than pops. Wrapper clips the overflow. */
.m-figure { overflow: hidden; }
.m-on [data-m-img] {
  opacity: 0;
  transform: scale(1.045);
  will-change: transform, opacity;
}
.m-on [data-m-img].m-in {
  opacity: 1;
  transform: scale(1);
  transition: opacity var(--m-slow) var(--m-out),
              transform var(--m-slow) var(--m-out);
}

/* Counters hold their final width so the count-up cannot shift layout. */
[data-m-count] { display: inline-block; text-align: left; }

/* ==========================================================================
   3. CTA — hover sheen + press
   The base .btn--go already lifts 2px and glows on hover; this adds the sheen
   and a press response without overriding what is there.
   ========================================================================== */
.btn--go, .btn--ghost { position: relative; overflow: hidden; }
.btn--go::after, .btn--ghost::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 38%,
              rgba(255, 255, 255, .38) 50%, transparent 62%);
  transform: translateX(-120%);
  pointer-events: none;
}
.btn--ghost::after { background: linear-gradient(105deg, transparent 38%,
              rgba(184, 255, 58, .22) 50%, transparent 62%); }
.btn--go:hover::after, .btn--ghost:hover::after {
  transform: translateX(120%);
  transition: transform var(--m-slow) var(--m-out);
}
.btn--go:active, .btn--ghost:active {
  transform: translateY(0) scale(.985);
  transition: transform 90ms var(--m-out);
}

/* Focus ring — motion must never replace a visible focus state. */
.btn:focus-visible {
  outline: 2px solid var(--lime);
  outline-offset: 3px;
}

/* ==========================================================================
   4. HERO VISUAL — lead haze
   A canvas of drifting lead glyphs behind each form panel. The panel itself is
   never transformed: it holds a form and stays anchored. The canvas is inert
   to input and sits below the panel in the stacking order.
   ========================================================================== */
.m-aura-wrap { position: relative; }
.m-aura-wrap > .console { position: relative; z-index: 1; }

/* The field is wider than the panel, so it reaches across into the copy
   column. Lift the text above it: motes should pass BEHIND the headline,
   never across it, or they cost legibility to buy atmosphere. */
.hero .hero__copy,
#console .console-grid > *:not(.m-aura-wrap) { position: relative; z-index: 2; }

.m-haze {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 0;
  pointer-events: none;
  line-height: 0;
}
.m-haze canvas { display: block; position: relative; z-index: 1; }
.m-haze__glow {
  position: absolute;
  inset: 8%;
  border-radius: 50%;
  background: radial-gradient(circle closest-side,
    rgba(184, 255, 58, .16) 0%, rgba(184, 255, 58, .07) 44%,
    rgba(184, 255, 58, .02) 70%, transparent 100%);
  will-change: transform, opacity;
  opacity: .34;
}

/* ==========================================================================
   5. REDUCED MOTION — everything resolves instantly, nothing is hidden.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .m-on .m-w > i,
  .m-on .m-in .m-w > i { transform: none !important; transition: none !important; }
  .m-on [data-m-hero],
  .m-on [data-m-reveal],
  .m-on [data-m-img] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .btn--go::after, .btn--ghost::after { display: none; }
  .m-haze { opacity: .5; }
}

/* ==========================================================================
   6. HEADLINE ROTATOR
   The tail of the H1 is retyped every few seconds. The caret is a plain
   element rather than a border, so it sits on the text baseline regardless of
   what the last character is.
   ========================================================================== */
/* The rotating phrase sits on its own line. Inline, every character erased or
   typed rewrapped the whole headline and moved the fixed part around - that
   reflow was the entire source of the layout shift. On its own block, the
   first half never moves and the phrase's own height is reserved. */
/* min-height in em, not px: the space is reserved from the very first paint,
   so the swap from fallback font to Space Grotesk cannot reflow the headline.
   2.2em covers the tallest variant at every breakpoint measured. */
.hero h1 [data-rotate] { display: block; min-height: 2.2em; }

/* It reveals as one block rather than word by word - see the note in
   motion.js. Delay lands it just after the final masked line. */
.m-on .hero h1 [data-rotate] { opacity: 0; transform: translateY(10px); }
.m-on .hero h1.m-in [data-rotate] {
  opacity: 1; transform: none;
  transition: opacity var(--m-base) var(--m-out), transform var(--m-base) var(--m-out);
  transition-delay: calc(3 * var(--m-stagger));
}
@media (prefers-reduced-motion: reduce) {
  .m-on .hero h1 [data-rotate] { opacity: 1 !important; transform: none !important; }
}

.h1-caret {
  display: inline-block;
  width: .055em;
  height: .78em;
  margin-left: .06em;
  vertical-align: -.04em;
  background: var(--lime);
  animation: h1blink 1.05s steps(1, end) infinite;
}
.h1-caret.is-typing { animation: none; opacity: 1; }
@keyframes h1blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  /* The rotating phrase sits on its own line. Inline, every character erased or
   typed rewrapped the whole headline and moved the fixed part around - that
   reflow was the entire source of the layout shift. On its own block, the
   first half never moves and the phrase's own height is reserved. */
/* min-height in em, not px: the space is reserved from the very first paint,
   so the swap from fallback font to Space Grotesk cannot reflow the headline.
   2.2em covers the tallest variant at every breakpoint measured. */
.hero h1 [data-rotate] { display: block; min-height: 2.2em; }

/* It reveals as one block rather than word by word - see the note in
   motion.js. Delay lands it just after the final masked line. */
.m-on .hero h1 [data-rotate] { opacity: 0; transform: translateY(10px); }
.m-on .hero h1.m-in [data-rotate] {
  opacity: 1; transform: none;
  transition: opacity var(--m-base) var(--m-out), transform var(--m-base) var(--m-out);
  transition-delay: calc(3 * var(--m-stagger));
}
@media (prefers-reduced-motion: reduce) {
  .m-on .hero h1 [data-rotate] { opacity: 1 !important; transform: none !important; }
}

.h1-caret { display: none; }
}
