@@ -24,7 +24,7 @@ export function initIndexEnhancements() {
2424 } ) ;
2525 }
2626
27- // Section reveal animations
27+ // Section reveal animations (entire sections)
2828 try {
2929 const observer = new IntersectionObserver (
3030 ( entries ) => {
@@ -44,5 +44,52 @@ export function initIndexEnhancements() {
4444 } catch {
4545 // IntersectionObserver unsupported or DOM not ready; skip enhancements
4646 }
47+
48+ // Grouped reveal animations with staggered children
49+ try {
50+ const prefersReducedMotion = window . matchMedia (
51+ "(prefers-reduced-motion: reduce)" ,
52+ ) . matches ;
53+ const groupObserver = new IntersectionObserver (
54+ ( entries ) => {
55+ for ( const entry of entries ) {
56+ if ( ! entry . isIntersecting ) continue ;
57+ const group = entry . target as HTMLElement ;
58+ group . classList . add ( "revealed" ) ;
59+ const children =
60+ group . querySelectorAll < HTMLElement > ( ".reveal-child" ) ;
61+ children . forEach ( ( el , index ) => {
62+ // Set index for CSS calc-based delay
63+ el . style . setProperty ( "--i" , String ( index ) ) ;
64+ if ( prefersReducedMotion ) {
65+ el . classList . add ( "animate-in" ) ;
66+ }
67+ } ) ;
68+ }
69+ } ,
70+ { threshold : 0.12 , rootMargin : "0px 0px -10% 0px" } ,
71+ ) ;
72+ document . querySelectorAll < HTMLElement > ( ".reveal-group" ) . forEach ( ( g ) => {
73+ groupObserver . observe ( g ) ;
74+ } ) ;
75+ } catch { }
76+
77+ // Hero intro sequence (subtle Swiss-style stagger)
78+ try {
79+ const prefersReducedMotion = window . matchMedia (
80+ "(prefers-reduced-motion: reduce)" ,
81+ ) . matches ;
82+ const items = document . querySelectorAll < HTMLElement > ( "#home .intro-item" ) ;
83+ if ( items . length ) {
84+ const baseDelay = 80 ; // ms between items
85+ items . forEach ( ( el , i ) => {
86+ if ( prefersReducedMotion ) {
87+ el . classList . add ( "animate-in" ) ;
88+ return ;
89+ }
90+ setTimeout ( ( ) => el . classList . add ( "animate-in" ) , i * baseDelay + 100 ) ;
91+ } ) ;
92+ }
93+ } catch { }
4794 } ) ;
4895}
0 commit comments