/* ============================================================================
   motion.css — Smile Denture shared motion layer (the "React Bits" flourishes)
   ----------------------------------------------------------------------------
   Lifts the home-only premium effects out of home.html so ANY page can opt in
   with one <link> + one <script src="js/motion.js">. Pairs with the base reveal
   /counter/marquee engine that already lives in brand.css + shared.js.

   Everything here is:
     • token-driven (uses brand.css vars: --brand, --clinic-green, --ease-out…)
     • opt-in via data-* / classes — adding the file changes nothing until you
       tag an element
     • fully gated behind prefers-reduced-motion (no motion for those users)

   HOW TO USE (per page, in <head> after brand.css):
     <link rel="stylesheet" href="css/motion.css">
   …and before </body>, after shared.js:
     <script src="js/motion.js"></script>

   TAGS:
     data-rb-split          → headline animates word-by-word (blur + rise)
     class="rb-shimmer"     → gradient shimmer sweep across the text
     data-countup="5.0"     → number counts up from 0 when scrolled into view
     class="rb-tick"        → SVG check mark draws itself in
     class="rb-underline"   → hand-drawn swoosh draws under a hero word (§6)
     class="rb-sheen"       → one-time light sweep across a CTA on reveal (§7)
   ========================================================================== */

/* ---- 1. Word-by-word blur reveal --------------------------------------------
   JS (motion.js) splits a [data-rb-split] element into .rb-word spans and sets
   --rb-i per word. Each word rises + un-blurs on a staggered delay. If JS is off
   or motion is reduced, the element just shows normally. */
[data-rb-split] .rb-word { display: inline-block; }

@media (prefers-reduced-motion: no-preference) {
  /* once split, the headline owns its own reveal — neutralize any parent .reveal */
  [data-rb-split].rb-split { opacity: 1; transform: none; }
  /* 2026-07-04: self-playing animation replaces the transition + JS-added
     .rb-in class. Words can never be stranded invisible — the animation
     starts the moment the split lands, no second class required. */
  [data-rb-split].rb-split .rb-word {
    animation: rb-word-in .55s ease both;
    animation-delay: calc(var(--rb-i, 0) * 85ms);
    will-change: opacity, filter, transform;
  }
  @keyframes rb-word-in {
    from { opacity: 0; filter: blur(9px); transform: translateY(0.16em); }
    to   { opacity: 1; filter: blur(0);   transform: translateY(0); }
  }
}

/* ---- 2. Gradient shimmer sweep ---------------------------------------------
   Add class="rb-shimmer" to an inline element (e.g. an <em> inside a heading).
   Reads bright/legible on both dark and light backgrounds because white is the
   base and the brand colour is the moving highlight. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .rb-shimmer {
    background: linear-gradient(100deg,
      currentColor 0%,
      var(--brand, #0768FE) 34%,
      currentColor 58%,
      var(--brand, #0768FE) 84%,
      currentColor 100%);
    background-size: 220% 100%;
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
  /* On dark surfaces, keep the highlight light instead of saturated brand. */
  .rb-shimmer--on-dark {
    background: linear-gradient(100deg,
      #ffffff 0%,
      color-mix(in oklab, var(--brand, #0768FE) 58%, #ffffff) 34%,
      #ffffff 58%,
      color-mix(in oklab, var(--brand, #0768FE) 58%, #ffffff) 84%,
      #ffffff 100%);
    background-size: 220% 100%;
  }
  @media (prefers-reduced-motion: no-preference) {
    .rb-shimmer { animation: rb-shimmer-sweep 5.5s linear infinite; }
  }
}
@keyframes rb-shimmer-sweep { to { background-position: 220% 0; } }

/* ---- 3. Animated check mark (stroke-dash draw) -----------------------------
   Markup: an <svg> tick whose <path class="rb-tick__path"> draws itself in.
   Path length ≈ 20 units → dasharray/offset = 20. Add class="rb-tick" to the
   svg and it draws once when revealed (or immediately if it starts in view). */
.rb-tick .rb-tick__path {
  stroke-dasharray: 20;
  stroke-dashoffset: 20;
}
@media (prefers-reduced-motion: no-preference) {
  .rb-tick.rb-in .rb-tick__path,
  .rb-tick.is-in .rb-tick__path {
    animation: rb-tick-draw .42s var(--ease-out, cubic-bezier(.2,.8,.2,1)) forwards;
  }
}
@keyframes rb-tick-draw {
  from { stroke-dashoffset: 20; }
  to   { stroke-dashoffset: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .rb-tick .rb-tick__path { stroke-dashoffset: 0; animation: none; }
}

/* ---- 4. Staggered group entrance -------------------------------------------
   Add data-rb-stagger to a parent; motion.js sets --rb-i on each direct child.
   Children rise in sequence once the parent enters the viewport. Reuses the
   .is-in class that shared.js already toggles via its reveal observer, so add
   class="reveal" to the parent too. */
@media (prefers-reduced-motion: no-preference) {
  [data-rb-stagger] > * {
    opacity: 0;
    transform: translateY(10px);
    transition: opacity .5s var(--ease-out, cubic-bezier(.2,.8,.2,1)),
                transform .5s var(--ease-out, cubic-bezier(.2,.8,.2,1));
    transition-delay: calc(var(--rb-i, 0) * 80ms);
  }
  [data-rb-stagger].is-in > *,
  [data-rb-stagger].rb-in > * { opacity: 1; transform: translateY(0); }
}

/* ---- 5. Scroll-linked parallax (pure CSS, modern browsers) -----------------
   Add data-rb-parallax="down" or "up" to an <img> inside an overflow:hidden
   frame. Drifts gently as the section scrolls through view. Degrades to a
   static image anywhere animation-timeline isn't supported. The image needs a
   slight scale so the drift never exposes an edge. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    [data-rb-parallax] {
      will-change: transform;
      animation-timeline: view();
      animation-range: cover;
    }
    [data-rb-parallax="down"] { animation: rb-parallax-down linear both; }
    [data-rb-parallax="up"]   { animation: rb-parallax-up   linear both; }
  }
}
@keyframes rb-parallax-down {
  from { transform: translateY(-4.4%) scale(1.14); }
  to   { transform: translateY(4.4%)  scale(1.14); }
}
@keyframes rb-parallax-up {
  from { transform: translateY(4.4%)  scale(1.14); }
  to   { transform: translateY(-4.4%) scale(1.14); }
}

/* ---- 6. Draw-on swoosh underline --------------------------------------------
   A hand-drawn stroke that sweeps under one hero word (e.g. the italic "smile")
   right after the data-rb-split word reveal finishes — echoes the logo swoosh.
   Markup, inside the word's element:
     <em class="… rb-underline">smile
       <svg class="rb-underline__svg" viewBox="0 0 120 14" preserveAspectRatio="none" aria-hidden="true">
         <path class="rb-underline__path" d="M4 10 C 32 14.5, 80 13.5, 116 5"/>
       </svg>
     </em>
   Uses --accent-leaf (Logo Green, decoration-only token). Visible statically
   when JS is off or motion is reduced — the draw is pure enhancement. */
.rb-underline { position: relative; display: inline-block; }
.rb-underline .rb-underline__svg {
  position: absolute; left: -3%; bottom: -0.14em;
  width: 106%; height: 0.3em;
  overflow: visible; pointer-events: none;
}
.rb-underline__path {
  fill: none;
  stroke: var(--accent-leaf, #00D60F);
  stroke-width: 6;
  stroke-linecap: round;
  stroke-dasharray: 130;
  stroke-dashoffset: 0;            /* visible by default → no-JS fallback */
}
@media (prefers-reduced-motion: no-preference) {
  /* draw left→right after the last word has risen — self-playing (2026-07-04) */
  .rb-split .rb-underline__path {
    stroke-dashoffset: 130;
    animation: rb-underline-draw .6s var(--ease-out, cubic-bezier(.2,.8,.2,1)) 1.05s forwards;
  }
}
@keyframes rb-underline-draw { to { stroke-dashoffset: 0; } }

/* ---- 7. One-time CTA sheen ---------------------------------------------------
   A single soft light sweep across a button the first time its section reveals
   — draws the eye to the conversion moment exactly once; never loops.
   Add class="rb-sheen" to the button. Works automatically when the button sits
   inside a .reveal section (shared.js toggles .is-in), or give the button
   .rb-in directly. Default sheen is white (for filled blue/green/dark buttons);
   add .rb-sheen--tint for a brand-blue sheen on white buttons. */
.rb-sheen { position: relative; overflow: hidden; }
.rb-sheen::after {
  content: "";
  position: absolute; top: 0; bottom: 0; left: 0;
  width: 55%;
  transform: translateX(-130%) skewX(-16deg);   /* parked off-left, invisible */
  background: linear-gradient(105deg,
    transparent 0%,
    var(--rb-sheen-color, rgba(255,255,255,.45)) 50%,
    transparent 100%);
  pointer-events: none;
}
.rb-sheen--tint { --rb-sheen-color: color-mix(in srgb, var(--brand, #0768FE) 16%, transparent); }
@media (prefers-reduced-motion: no-preference) {
  .reveal.is-in .rb-sheen::after,
  .rb-sheen.rb-in::after {
    animation: rb-sheen-once 1s ease-in-out .55s 1 both;
  }
}
@media (prefers-reduced-motion: reduce) {
  .rb-sheen::after { display: none; }
}
@keyframes rb-sheen-once {
  from { transform: translateX(-130%) skewX(-16deg); }
  to   { transform: translateX(330%)  skewX(-16deg); }
}
