Next Steps

Select Phone, Zoom, or In-Person Consultations Below

Click below to lock in your preferred consultation type. Whether it’s a quick call, a face-to-face on Zoom, or in person at the studio—this is where it gets good

gold arrow pointing down
gold arrow pointing right

someone holding bottle of folicule
// File Name: custom-animations.js function setupAnimatedHeadingsOnScroll() { // --- This is the reusable part for all your animations --- // Add the unique class name for EACH of your animations here, separated by a comma. const animatedContainers = document.querySelectorAll('.color-heading-container, .princeton-animation-container, .hairline-animation-container, .no-location-animation-container'); if (animatedContainers.length === 0) return; // --- Universal Logic for splitting text into words --- // This part works for all the animations we've built. animatedContainers.forEach(container => { if (container.hasAttribute('data-animation-prepared')) return; container.setAttribute('data-animation-prepared', 'true'); const elementsToSplit = container.querySelectorAll('[data-split-words]'); elementsToSplit.forEach(element => { const text = element.textContent.trim(); const words = text.split(' '); element.innerHTML = ''; const redWords = ["Bad", "Results"]; let animationIndex = 0; for (let i = 0; i < words.length; i++) { let currentWord = words[i]; let isSpecialPhrase = false; if (words[i] === "#1" && i + 1 < words.length && words[i+1] === "Priority") { currentWord = "#1 Priority"; isSpecialPhrase = true; i++; } const wrapper = document.createElement('div'); wrapper.classList.add('word-wrapper'); wrapper.style.animationDelay = `${animationIndex * 0.15 + 0.1}s`; const wordSpan = document.createElement('span'); wordSpan.classList.add('word'); wordSpan.textContent = currentWord; if (redWords.includes(currentWord) || isSpecialPhrase) { wordSpan.classList.add('text-red'); } if (isSpecialPhrase) { wordSpan.classList.add('slide-italic-effect'); wrapper.classList.add('zoom-wrapper'); } wrapper.appendChild(wordSpan); element.appendChild(wrapper); animationIndex++; } }); }); // --- Universal Logic for triggering animation on scroll --- const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('is-in-view'); observer.unobserve(entry.target); // Animate only once } }); }, { threshold: 0.1 // Trigger when 10% of the element is visible }); // Tell the observer to watch each container animatedContainers.forEach(container => { observer.observe(container); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', setupAnimatedHeadingsOnScroll); } else { setupAnimatedHeadingsOnScroll(); }