/** * Feature Section Card Animator * Staggered scroll-reveal entrance + icon pop-in for .feature-section cards. * Coordinates with the main.js scroll-hidden/visible system: * 1. Sets --scroll-delay CSS custom property on each card so main.js's * scroll-visible transition fires at staggered intervals. * 2. Uses MutationObserver to detect when scroll-visible is applied, then * triggers the icon-pop animation on the card's .feature-icon. * 3. Resets the delay to 0s after the entrance so hover interactions stay snappy. */ (function () { 'use strict'; var STAGGER = 0.08; // seconds between each card's entrance document.addEventListener('DOMContentLoaded', function () { if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; // 1. Assign incrementing --scroll-delay to every card within a feature-section. // The block renders .grid-2/.grid-3/.grid-4 wrappers (no .feature-section class). // main.js's .scroll-visible rule reads this via var(--scroll-delay, 0s). document.querySelectorAll('.grid-2, .grid-3, .grid-4').forEach(function (grid) { grid.querySelectorAll('.oribi-card').forEach(function (card, i) { card.style.setProperty('--scroll-delay', (i * STAGGER).toFixed(2) + 's'); }); }); // 2. Watch for scroll-visible being added to each card. var cards = document.querySelectorAll('.grid-2 .oribi-card, .grid-3 .oribi-card, .grid-4 .oribi-card'); if (!cards.length) return; var mo = new MutationObserver(function (mutations) { mutations.forEach(function (m) { var card = m.target; if (!card.classList.contains('scroll-visible')) return; mo.unobserve(card); // Trigger icon pop ~150ms after the card itself starts fading in. var icon = card.querySelector('.feature-icon'); if (icon) { var cardDelay = parseFloat(card.style.getPropertyValue('--scroll-delay')) || 0; icon.style.animationDelay = (cardDelay + 0.15).toFixed(2) + 's'; icon.classList.add('icon-pop'); icon.addEventListener('animationend', function () { icon.classList.remove('icon-pop'); icon.style.animationDelay = ''; // Start ambient float+ring animation once the pop-in finishes. card.classList.add('is-animated'); }, { once: true }); } // Reset stagger delay after entrance transition so hover isn't delayed. card.addEventListener('transitionend', function (e) { if (e.propertyName === 'opacity') { card.style.setProperty('--scroll-delay', '0s'); } }, { once: true }); }); }); cards.forEach(function (card) { mo.observe(card, { attributes: true, attributeFilter: ['class'] }); }); }); }());