/* motion.css - sitewide motion for callmoorhead.com. Pair with motion.js (both injected by build-motion.js).
   Ported from design-lab/transitions: 01 hero entrance, 02 scroll reveal, 05 view transitions, 06 micro-interactions.

   Safety rules baked in:
   - Every "start hidden" state is gated on html.js (set inline in <head>), so no-JS visitors and crawlers see a fully visible page.
   - prefers-reduced-motion: reduce turns every effect off (see the block at the bottom).
   - The likely LCP element on each page (hero image on the homepage, the h1 on every other page) is never opacity-hidden;
     it only moves, so Core Web Vitals are untouched.
   - The nav shrink keeps the nav's in-flow height constant (height shrinks, margin grows), so it never causes layout shift. */

:root { --m-ease: cubic-bezier(.16, 1, .3, 1); }

/* ===== 02. Scroll reveal ====================================================
   motion.js tags sections that sit below the fold on load with these attributes, reveals them once as they scroll
   into view, then strips the attributes again so no component keeps a stale transition or transform.
     data-reveal            fade + rise (default)
     data-reveal="fade"     fade only
     data-reveal="left"     slide in from the left
     data-reveal="right"    slide in from the right
     data-reveal="scale"    fade + grow from 92%
     data-reveal="clip"     wipe up out of a clipped box (headlines)
     data-reveal-stagger    direct children rise one after another */
[data-reveal] {
  --rv-y: 28px; --rv-x: 0px; --rv-s: 1;
  opacity: 0;
  transform: translate(var(--rv-x), var(--rv-y)) scale(var(--rv-s));
  transition:
    opacity   .8s var(--m-ease),
    transform .8s var(--m-ease),
    -webkit-mask-size .8s var(--m-ease),
    mask-size .8s var(--m-ease);
  transition-delay: var(--d, 0s);
}
[data-reveal="fade"]  { --rv-y: 0px; }
[data-reveal="left"]  { --rv-y: 0px; --rv-x: -40px; }
[data-reveal="right"] { --rv-y: 0px; --rv-x: 40px; }
[data-reveal="scale"] { --rv-y: 0px; --rv-s: .92; }
/* "clip" uses a mask, not clip-path: Chrome's IntersectionObserver treats a fully clipped element as zero-area
   and never fires. A mask is paint-only, so the observer still sees the full box. */
[data-reveal="clip"] { --rv-y: 14px;
  -webkit-mask-image: linear-gradient(#000, #000); mask-image: linear-gradient(#000, #000);
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: 0 100%; mask-position: 0 100%;
  -webkit-mask-size: 100% 0%; mask-size: 100% 0%; }
[data-reveal].is-in { opacity: 1; transform: none; -webkit-mask-size: 100% 100%; mask-size: 100% 100%; }

[data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .7s var(--m-ease), transform .7s var(--m-ease);
  transition-delay: var(--d, 0s);
}
[data-reveal-stagger].is-in > * { opacity: 1; transform: none; }

/* ===== 06. Nav shrink + scroll progress ===================================== */
.msc-progress { position: fixed; top: 0; left: 0; width: 100%; height: 3px; background: var(--coral, #E8604C); transform-origin: left; transform: scaleX(0); z-index: 300; pointer-events: none; }
@media (min-width: 769px) {
  .nav { transition: margin-bottom .35s var(--m-ease), box-shadow .35s; }
  .nav-inner { transition: height .35s var(--m-ease); }
  .nav-logo img { transition: height .35s var(--m-ease); }
  /* height 70 -> 56 while margin 0 -> 14: the nav's footprint in the document stays 70px, so nothing below it moves. */
  .nav.is-compact { margin-bottom: 14px; box-shadow: 0 6px 30px rgba(0,0,0,.35); }
  .nav.is-compact .nav-inner { height: 56px; }
  .nav.is-compact .nav-logo img { height: 46px; }
}

/* ===== 06. Counting stats + pulsing call button ============================= */
[data-count] { font-variant-numeric: tabular-nums; }
.btn-pulse { position: relative; }
.btn-pulse::before, .btn-pulse::after { content: ''; position: absolute; inset: -3px; border-radius: inherit; border: 2px solid var(--coral, #E8604C); animation: mPulse 2.2s cubic-bezier(.2, .7, .3, 1) infinite; pointer-events: none; }
.btn-pulse::after { animation-delay: 1.1s; }
@keyframes mPulse { 0% { transform: scale(1); opacity: .8; } 100% { transform: scale(1.35, 1.7); opacity: 0; } }

/* ===== 01. Hero entrance: homepage (.hero) ==================================
   Timing map (seconds): bg 0 -> tag .15 -> lines .30/.44/.58 -> kw .85 -> sub 1.0 -> btns 1.15/1.25 -> rule 1.3 -> trust 1.45+ */
.hero-bg-wrap { position: absolute; inset: -3%; }                    /* 3% bleed gives the mouse parallax room to move */
.hero .line { display: block; overflow: hidden; padding-bottom: .06em; margin-bottom: -.06em; }
.hero .line-in { display: block; }
.js .hero .a { opacity: 0; }
.js .hero .line-in { transform: translateY(112%); }
.js .hero-bg { transform: scale(1.12); }                              /* opacity stays as style.css sets it: the LCP image paints immediately */
.js .hero-divider { border-top-color: transparent; position: relative; }
.js .hero-divider::before { content: ''; position: absolute; top: -1px; left: 0; right: 0; height: 1px; background: rgba(255,255,255,.14); transform: scaleX(0); transform-origin: left; }

.is-loaded .hero-bg { animation: mBgIn 1.8s var(--m-ease) forwards, mBgDrift 28s 1.8s ease-in-out infinite alternate; }
.is-loaded .hero .a-tag { animation: mFadeLeft .8s var(--m-ease) .15s forwards; }
.is-loaded .hero .line-in { animation: mLineUp 1s var(--m-ease) forwards; }
.is-loaded .hero .a-l1 { animation-delay: .30s; }
.is-loaded .hero .a-l2 { animation-delay: .44s; }
.is-loaded .hero .a-l3 { animation-delay: .58s; }
.is-loaded .hero .a-kw { animation: mFadeUp .8s var(--m-ease) .85s forwards; }
.is-loaded .hero .a-sub { animation: mFadeUp .8s var(--m-ease) 1s forwards; }
.is-loaded .hero .a-b1 { animation: mFadeUp .7s var(--m-ease) 1.15s forwards; }
.is-loaded .hero .a-b2 { animation: mFadeUp .7s var(--m-ease) 1.25s forwards; }
.is-loaded .hero-divider::before { animation: mRule 1.2s var(--m-ease) 1.3s forwards; }
.is-loaded .hero .a-t1 { animation: mFadeUp .6s var(--m-ease) 1.45s forwards; }
.is-loaded .hero .a-t2 { animation: mFadeUp .6s var(--m-ease) 1.53s forwards; }
.is-loaded .hero .a-t3 { animation: mFadeUp .6s var(--m-ease) 1.61s forwards; }
.is-loaded .hero .a-t4 { animation: mFadeUp .6s var(--m-ease) 1.69s forwards; }
.is-loaded .hero .a-t5 { animation: mFadeUp .6s var(--m-ease) 1.77s forwards; }

/* ===== 01. Hero entrance: every other page (.page-hero) =====================
   Tag, sub, buttons and meta fade up in sequence. The h1 (the text LCP candidate) only rises, never fades. */
.js .page-hero-content > * { opacity: 0; transform: translateY(22px); }
.js .page-hero-content > h1 { opacity: 1; transform: translateY(30px); }
.js .page-hero-form { transform: translateY(26px); }
.is-loaded .page-hero-content > * { animation: mFadeUp .8s var(--m-ease) forwards; }
.is-loaded .page-hero-content > h1 { animation-name: mRise; animation-duration: .9s; }
.is-loaded .page-hero-content > :nth-child(1) { animation-delay: .05s; }
.is-loaded .page-hero-content > :nth-child(2) { animation-delay: .18s; }
.is-loaded .page-hero-content > :nth-child(3) { animation-delay: .30s; }
.is-loaded .page-hero-content > :nth-child(4) { animation-delay: .42s; }
.is-loaded .page-hero-content > :nth-child(5) { animation-delay: .54s; }
.is-loaded .page-hero-content > :nth-child(n+6) { animation-delay: .64s; }
.is-loaded .page-hero-form { animation: mRise .9s var(--m-ease) .35s forwards; }

@keyframes mBgIn    { from { transform: scale(1.12); } to { transform: scale(1.04); } }
@keyframes mBgDrift { from { transform: scale(1.04) translate(0, 0); } to { transform: scale(1.09) translate(-1.5%, 1%); } }
@keyframes mFadeUp  { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
@keyframes mFadeLeft{ from { opacity: 0; transform: translateX(-18px); } to { opacity: 1; transform: none; } }
@keyframes mRise    { from { transform: translateY(30px); } to { transform: none; } }
@keyframes mLineUp  { to { transform: none; } }
@keyframes mRule    { to { transform: scaleX(1); } }

/* ===== 05. Cross-document view transitions ==================================
   Old page fades out, new page rises in; the nav and the mobile call bar hold still. Browsers without the API
   (and file:// previews) just navigate normally. */
@view-transition { navigation: auto; }
.nav { view-transition-name: msc-nav; }
.msc-callbar { view-transition-name: msc-callbar; }
::view-transition-old(root) { animation: mVtOut .2s ease both; }
::view-transition-new(root) { animation: mVtIn .4s var(--m-ease) both; }
@keyframes mVtOut { to { opacity: 0; } }
@keyframes mVtIn  { from { opacity: 0; transform: translateY(16px); } }

/* ===== Reduced motion: everything visible, nothing moves ==================== */
@media (prefers-reduced-motion: reduce) {
  [data-reveal], [data-reveal-stagger] > * { opacity: 1; transform: none; -webkit-mask-image: none; mask-image: none; transition: none; }
  .nav, .nav-inner, .nav-logo img { transition: none; }
  .btn-pulse::before, .btn-pulse::after { animation: none; display: none; }
  .js .hero .a, .js .page-hero-content > * { opacity: 1; transform: none; animation: none; }
  .js .hero .line-in, .js .hero-bg, .js .page-hero-form, .js .hero-divider::before { transform: none; animation: none; }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}
