{"version":3,"file":"motion_controller-xS4uWz3T.js","names":[],"sources":["../../../app/javascript/entrypoints/site_controllers/motion_controller.js"],"sourcesContent":["import { Controller } from \"@hotwired/stimulus\"\n\n// Page-level motion: words of [data-words] titles rise one by one, .reveal blocks play\n// their entrance when scrolled into view, [data-count] numbers count up, and\n// [data-progress-line] fills. Content is fully visible without JS or with reduced motion.\nexport default class extends Controller {\n connect() {\n this.reduced = window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n this.splitWords()\n if (this.reduced || !(\"IntersectionObserver\" in window)) return\n\n this.observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (!entry.isIntersecting) return\n this.play(entry.target)\n this.observer.unobserve(entry.target)\n })\n }, { threshold: 0.15 })\n this.element.querySelectorAll(\".reveal, [data-count], [data-progress-line]\").forEach((el) => this.observer.observe(el))\n }\n\n disconnect() {\n this.observer?.disconnect()\n }\n\n play(el) {\n if (el.classList.contains(\"reveal\")) el.classList.add(\"in\")\n if (el.hasAttribute(\"data-progress-line\")) el.classList.add(\"in\")\n if (el.dataset.count) this.countUp(el)\n }\n\n splitWords() {\n if (this.reduced) return\n this.element.querySelectorAll(\"[data-words]\").forEach((title) => {\n if (title.dataset.split) return\n title.dataset.split = \"true\"\n let index = 0\n const walk = (node) => {\n [...node.childNodes].forEach((child) => {\n if (child.nodeType === Node.TEXT_NODE) {\n const fragment = document.createDocumentFragment()\n child.textContent.split(/(\\s+)/).forEach((part) => {\n if (!part) return\n if (/^\\s+$/.test(part)) { fragment.appendChild(document.createTextNode(part)); return }\n const word = document.createElement(\"span\")\n word.className = \"w\"\n word.style.setProperty(\"--i\", index++)\n word.textContent = part\n fragment.appendChild(word)\n })\n child.replaceWith(fragment)\n } else if (child.nodeType === Node.ELEMENT_NODE) {\n walk(child)\n }\n })\n }\n walk(title)\n title.classList.add(\"words\")\n })\n }\n\n countUp(el) {\n const target = Number(el.dataset.count)\n const suffix = el.dataset.suffix || \"\"\n const start = performance.now()\n const duration = 1200\n const step = (now) => {\n const progress = Math.min(1, (now - start) / duration)\n const eased = 1 - Math.pow(1 - progress, 3)\n el.textContent = Math.round(target * eased).toLocaleString(document.documentElement.lang) + suffix\n if (progress < 1) requestAnimationFrame(step)\n }\n requestAnimationFrame(step)\n }\n}\n"],"mappings":"4GAKA,EAAA,cAA6B,CAAW,CACtC,SAAU,CACR,KAAK,QAAU,OAAO,WAAW,mCAAmC,CAAC,QACrE,KAAK,YAAY,CACb,OAAK,SAAW,EAAE,yBAA0B,WAEhD,KAAK,SAAW,IAAI,qBAAsB,GAAY,CACpD,EAAQ,QAAS,GAAU,CACpB,EAAM,iBACX,KAAK,KAAK,EAAM,OAAO,CACvB,KAAK,SAAS,UAAU,EAAM,OAAO,GACrC,EACD,CAAE,UAAW,IAAM,CAAC,CACvB,KAAK,QAAQ,iBAAiB,8CAA8C,CAAC,QAAS,GAAO,KAAK,SAAS,QAAQ,EAAG,CAAC,EAGzH,YAAa,CACX,KAAK,UAAU,YAAY,CAG7B,KAAK,EAAI,CACH,EAAG,UAAU,SAAS,SAAS,EAAE,EAAG,UAAU,IAAI,KAAK,CACvD,EAAG,aAAa,qBAAqB,EAAE,EAAG,UAAU,IAAI,KAAK,CAC7D,EAAG,QAAQ,OAAO,KAAK,QAAQ,EAAG,CAGxC,YAAa,CACP,KAAK,SACT,KAAK,QAAQ,iBAAiB,eAAe,CAAC,QAAS,GAAU,CAC/D,GAAI,EAAM,QAAQ,MAAO,OACzB,EAAM,QAAQ,MAAQ,OACtB,IAAI,EAAQ,EACN,EAAQ,GAAS,CACrB,CAAC,GAAG,EAAK,WAAW,CAAC,QAAS,GAAU,CACtC,GAAI,EAAM,WAAa,KAAK,UAAW,CACrC,IAAM,EAAW,SAAS,wBAAwB,CAClD,EAAM,YAAY,MAAM,QAAQ,CAAC,QAAS,GAAS,CACjD,GAAI,CAAC,EAAM,OACX,GAAI,QAAQ,KAAK,EAAK,CAAE,CAAE,EAAS,YAAY,SAAS,eAAe,EAAK,CAAC,CAAE,OAC/E,IAAM,EAAO,SAAS,cAAc,OAAO,CAC3C,EAAK,UAAY,IACjB,EAAK,MAAM,YAAY,MAAO,IAAQ,CACtC,EAAK,YAAc,EACnB,EAAS,YAAY,EAAK,EAC1B,CACF,EAAM,YAAY,EAAS,MAClB,EAAM,WAAa,KAAK,cACjC,EAAK,EAAM,EAEb,EAEJ,EAAK,EAAM,CACX,EAAM,UAAU,IAAI,QAAQ,EAC5B,CAGJ,QAAQ,EAAI,CACV,IAAM,EAAS,OAAO,EAAG,QAAQ,MAAM,CACjC,EAAS,EAAG,QAAQ,QAAU,GAC9B,EAAQ,YAAY,KAAK,CAEzB,EAAQ,GAAQ,CACpB,IAAM,EAAW,KAAK,IAAI,GAAI,EAAM,GAAS,KAAS,CAChD,EAAQ,GAAa,EAAI,IAAU,EACzC,EAAG,YAAc,KAAK,MAAM,EAAS,EAAM,CAAC,eAAe,SAAS,gBAAgB,KAAK,CAAG,EACxF,EAAW,GAAG,sBAAsB,EAAK,EAE/C,sBAAsB,EAAK"}