@hortonstudio/main 1.2.35 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +1,27 @@
1
- const API_NAME = 'hsmain';
1
+ const API_NAME = "hsmain";
2
2
 
3
3
  // Check for reduced motion preference
4
4
  const prefersReducedMotion = () => {
5
- return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
5
+ return (
6
+ window.matchMedia &&
7
+ window.matchMedia("(prefers-reduced-motion: reduce)").matches
8
+ );
6
9
  };
7
10
 
8
11
  // Animation timing (in seconds)
9
12
  const timing = {
10
- announce: 0,
11
- nav: 0.1,
12
- navLogo: 0.3,
13
- navList: 0.35,
14
- navMenu: 0.35,
15
- navButton: 0.5,
16
- tag: 0.1,
17
- heading: 0.15,
18
- subheading: 0.25,
19
- button: 0.35,
20
- image: 0.5,
21
- appear: 0.6
13
+ announce: 0,
14
+ nav: 0.1,
15
+ navLogo: 0.3,
16
+ navList: 0.35,
17
+ navMenu: 0.35,
18
+ navButton: 0.5,
19
+ tag: 0.1,
20
+ heading: 0.15,
21
+ subheading: 0.25,
22
+ button: 0.35,
23
+ image: 0.5,
24
+ appear: 0.6,
22
25
  };
23
26
 
24
27
  // Hero Animations Module
@@ -28,637 +31,764 @@ let subheadingSplits = [];
28
31
  let heroTimeout = null; // Track the setTimeout
29
32
 
30
33
  const config = {
31
- global: {
32
- animationDelay: 0.2
33
- },
34
- headingSplit: {
35
- duration: 1.5,
36
- stagger: 0.1,
37
- yPercent: 110,
38
- ease: "power4.out"
39
- },
40
- subheadingSplit: {
41
- duration: 1.5,
42
- stagger: 0.1,
43
- yPercent: 110,
44
- ease: "power4.out"
45
- },
46
- appear: {
47
- y: 50,
48
- duration: 1,
49
- ease: "power3.out"
50
- },
51
- navStagger: {
52
- duration: 1,
53
- stagger: 0.1,
54
- ease: "power3.out"
55
- },
56
- nav: {
57
- duration: 1,
58
- ease: "power3.out"
59
- }
34
+ global: {
35
+ animationDelay: 0.2,
36
+ },
37
+ headingSplit: {
38
+ duration: 1.5,
39
+ stagger: 0.1,
40
+ yPercent: 110,
41
+ ease: "power4.out",
42
+ },
43
+ subheadingSplit: {
44
+ duration: 1.5,
45
+ stagger: 0.1,
46
+ yPercent: 110,
47
+ ease: "power4.out",
48
+ },
49
+ appear: {
50
+ y: 50,
51
+ duration: 1,
52
+ ease: "power3.out",
53
+ },
54
+ navStagger: {
55
+ duration: 1,
56
+ stagger: 0.1,
57
+ ease: "power3.out",
58
+ },
59
+ nav: {
60
+ duration: 1,
61
+ ease: "power3.out",
62
+ },
60
63
  };
61
64
 
62
65
  function updateConfig(newConfig) {
63
- function deepMerge(target, source) {
64
- for (const key in source) {
65
- if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
66
- target[key] = target[key] || {};
67
- deepMerge(target[key], source[key]);
68
- } else {
69
- target[key] = source[key];
70
- }
71
- }
72
- return target;
66
+ function deepMerge(target, source) {
67
+ for (const key in source) {
68
+ if (
69
+ source[key] &&
70
+ typeof source[key] === "object" &&
71
+ !Array.isArray(source[key])
72
+ ) {
73
+ target[key] = target[key] || {};
74
+ deepMerge(target[key], source[key]);
75
+ } else {
76
+ target[key] = source[key];
77
+ }
73
78
  }
74
-
75
- deepMerge(config, newConfig);
79
+ return target;
80
+ }
81
+
82
+ deepMerge(config, newConfig);
76
83
  }
77
84
 
78
85
  function killHeroAnimations() {
79
- if (heroTimeout) {
80
- clearTimeout(heroTimeout);
81
- heroTimeout = null;
86
+ if (heroTimeout) {
87
+ clearTimeout(heroTimeout);
88
+ heroTimeout = null;
89
+ }
90
+
91
+ if (heroTimeline) {
92
+ heroTimeline.kill();
93
+ heroTimeline = null;
94
+ }
95
+
96
+ headingSplits.forEach((split) => {
97
+ if (split && split.revert) {
98
+ split.revert();
82
99
  }
83
-
84
- if (heroTimeline) {
85
- heroTimeline.kill();
86
- heroTimeline = null;
100
+ });
101
+ headingSplits = [];
102
+
103
+ subheadingSplits.forEach((split) => {
104
+ if (split && split.revert) {
105
+ split.revert();
87
106
  }
88
-
89
- headingSplits.forEach(split => {
90
- if (split && split.revert) {
91
- split.revert();
92
- }
93
- });
94
- headingSplits = [];
95
-
96
- subheadingSplits.forEach(split => {
97
- if (split && split.revert) {
98
- split.revert();
99
- }
100
- });
101
- subheadingSplits = [];
102
-
103
- // Restore page-wide tabbing if animation is killed
104
- const allFocusableElements = document.querySelectorAll('[data-original-tabindex]');
105
- allFocusableElements.forEach(el => {
106
- el.style.pointerEvents = '';
107
- const originalTabindex = el.getAttribute('data-original-tabindex');
108
- if (originalTabindex === '0') {
109
- el.removeAttribute('tabindex');
110
- } else {
111
- el.setAttribute('tabindex', originalTabindex);
112
- }
113
- el.removeAttribute('data-original-tabindex');
114
- });
115
- // Restore nav pointer events if animation is killed
116
- const navElement = document.querySelector('[data-hs-hero="nav"]');
117
- if (navElement) {
118
- navElement.style.pointerEvents = '';
107
+ });
108
+ subheadingSplits = [];
109
+
110
+ // Restore page-wide tabbing if animation is killed
111
+ const allFocusableElements = document.querySelectorAll(
112
+ "[data-original-tabindex]",
113
+ );
114
+ allFocusableElements.forEach((el) => {
115
+ el.style.pointerEvents = "";
116
+ const originalTabindex = el.getAttribute("data-original-tabindex");
117
+ if (originalTabindex === "0") {
118
+ el.removeAttribute("tabindex");
119
+ } else {
120
+ el.setAttribute("tabindex", originalTabindex);
119
121
  }
122
+ el.removeAttribute("data-original-tabindex");
123
+ });
124
+ // Restore nav pointer events if animation is killed
125
+ const navElement = document.querySelector('[data-hs-hero="nav"]');
126
+ if (navElement) {
127
+ navElement.style.pointerEvents = "";
128
+ }
120
129
  }
121
130
 
122
131
  function startHeroAnimations() {
123
- killHeroAnimations();
124
- init();
132
+ killHeroAnimations();
133
+ init();
125
134
  }
126
135
 
127
136
  function showHeroElementsWithoutAnimation() {
128
- // Simply show all hero elements without any animation or split text
129
- const allHeroElements = [
130
- ...document.querySelectorAll('[data-hs-hero="announce"]'),
131
- ...document.querySelectorAll('[data-hs-hero="nav"]'),
132
- ...document.querySelectorAll('[data-hs-hero="nav-menu"]'),
133
- ...document.querySelectorAll('[data-hs-hero="nav-logo"]'),
134
- ...document.querySelectorAll('[data-hs-hero="nav-button"] > *:first-child'),
135
- ...document.querySelectorAll('[data-hs-hero="nav-list"] > * > *:first-child'),
136
- ...document.querySelectorAll('[data-hs-hero="heading"] > *:first-child'),
137
- ...document.querySelectorAll('[data-hs-hero="subheading"] > *:first-child'),
138
- ...document.querySelectorAll('[data-hs-hero="tag"] > *:first-child'),
139
- ...document.querySelectorAll('[data-hs-hero="button"] > *'),
140
- ...document.querySelectorAll('[data-hs-hero="image"]'),
141
- ...document.querySelectorAll('[data-hs-hero="appear"]')
142
- ];
143
-
144
- allHeroElements.forEach(element => {
145
- if (element) {
146
- gsap.set(element, {
147
- autoAlpha: 1,
148
- opacity: 1,
149
- y: 0,
150
- yPercent: 0
151
- });
152
- // Remove any pointer-events restrictions
153
- element.style.pointerEvents = '';
154
- }
155
- });
137
+ // Simply show all hero elements without any animation or split text
138
+ const allHeroElements = [
139
+ ...document.querySelectorAll('[data-hs-hero="announce"]'),
140
+ ...document.querySelectorAll('[data-hs-hero="nav"]'),
141
+ ...document.querySelectorAll('[data-hs-hero="nav-menu"]'),
142
+ ...document.querySelectorAll('[data-hs-hero="nav-logo"]'),
143
+ ...document.querySelectorAll('[data-hs-hero="nav-button"] > *:first-child'),
144
+ ...document.querySelectorAll(
145
+ '[data-hs-hero="nav-list"] > * > *:first-child',
146
+ ),
147
+ ...document.querySelectorAll('[data-hs-hero="heading"] > *:first-child'),
148
+ ...document.querySelectorAll('[data-hs-hero="subheading"] > *:first-child'),
149
+ ...document.querySelectorAll('[data-hs-hero="tag"] > *:first-child'),
150
+ ...document.querySelectorAll('[data-hs-hero="button"] > *'),
151
+ ...document.querySelectorAll('[data-hs-hero="image"]'),
152
+ ...document.querySelectorAll('[data-hs-hero="appear"]'),
153
+ ...document.querySelectorAll('[data-hs-hero="main"]'),
154
+ ];
156
155
 
157
- // Restore page-wide tabbing
158
- const allFocusableElements = document.querySelectorAll('[data-original-tabindex]');
159
- allFocusableElements.forEach(el => {
160
- el.style.pointerEvents = '';
161
- const originalTabindex = el.getAttribute('data-original-tabindex');
162
- if (originalTabindex === '0') {
163
- el.removeAttribute('tabindex');
164
- } else {
165
- el.setAttribute('tabindex', originalTabindex);
166
- }
167
- el.removeAttribute('data-original-tabindex');
168
- });
156
+ allHeroElements.forEach((element) => {
157
+ if (element) {
158
+ gsap.set(element, {
159
+ autoAlpha: 1,
160
+ opacity: 1,
161
+ y: 0,
162
+ yPercent: 0,
163
+ });
164
+ // Remove any pointer-events restrictions
165
+ element.style.pointerEvents = "";
166
+ }
167
+ });
168
+
169
+ // Restore page-wide tabbing
170
+ const allFocusableElements = document.querySelectorAll(
171
+ "[data-original-tabindex]",
172
+ );
173
+ allFocusableElements.forEach((el) => {
174
+ el.style.pointerEvents = "";
175
+ const originalTabindex = el.getAttribute("data-original-tabindex");
176
+ if (originalTabindex === "0") {
177
+ el.removeAttribute("tabindex");
178
+ } else {
179
+ el.setAttribute("tabindex", originalTabindex);
180
+ }
181
+ el.removeAttribute("data-original-tabindex");
182
+ });
169
183
  }
170
184
 
171
185
  export async function init() {
172
- if (typeof window.gsap === "undefined") {
173
- console.error('GSAP not found - hero animations disabled');
174
- return;
175
- }
176
-
177
- if (prefersReducedMotion()) {
178
- // For reduced motion, just show elements without animation
179
- showHeroElementsWithoutAnimation();
180
-
181
- // Still expose the API for consistency
182
- window[API_NAME] = window[API_NAME] || {};
183
- window[API_NAME].heroAnimations = {
184
- config: config,
185
- updateConfig: updateConfig,
186
- start: startHeroAnimations,
187
- kill: killHeroAnimations,
188
- restart: () => {
189
- killHeroAnimations();
190
- startHeroAnimations();
191
- }
192
- };
193
-
194
- return { result: 'anim-hero initialized (reduced motion)' };
186
+ if (typeof window.gsap === "undefined") {
187
+ console.error("GSAP not found - hero animations disabled");
188
+ return;
189
+ }
190
+
191
+ if (prefersReducedMotion()) {
192
+ // For reduced motion, just show elements without animation
193
+ showHeroElementsWithoutAnimation();
194
+
195
+ // Still expose the API for consistency
196
+ window[API_NAME] = window[API_NAME] || {};
197
+ window[API_NAME].heroAnimations = {
198
+ config: config,
199
+ updateConfig: updateConfig,
200
+ start: startHeroAnimations,
201
+ kill: killHeroAnimations,
202
+ restart: () => {
203
+ killHeroAnimations();
204
+ startHeroAnimations();
205
+ },
206
+ };
207
+
208
+ return { result: "anim-hero initialized (reduced motion)" };
209
+ }
210
+
211
+ gsap.registerPlugin(ScrollTrigger, SplitText);
212
+
213
+ // Element selection
214
+ const announceElements = document.querySelectorAll(
215
+ '[data-hs-hero="announce"]',
216
+ );
217
+ const navElement = document.querySelector('[data-hs-hero="nav"]');
218
+ const navMenuElements = document.querySelectorAll(
219
+ '[data-hs-hero="nav-menu"]',
220
+ );
221
+ const navLogoElements = document.querySelectorAll(
222
+ '[data-hs-hero="nav-logo"]',
223
+ );
224
+ const imageElements = document.querySelectorAll('[data-hs-hero="image"]');
225
+ const imageFirstElements = document.querySelectorAll('[data-hs-hero="image"][data-hs-timing="first"]');
226
+ const imageRegularElements = document.querySelectorAll('[data-hs-hero="image"]:not([data-hs-timing="first"])');
227
+ const appearElements = document.querySelectorAll('[data-hs-hero="appear"]');
228
+ const mainElements = document.querySelectorAll('[data-hs-hero="main"]');
229
+
230
+ // Check if nav has advanced config
231
+ const hasAdvancedNav =
232
+ navElement &&
233
+ navElement.hasAttribute("data-hs-config") &&
234
+ navElement.getAttribute("data-hs-config") === "advanced";
235
+
236
+ // First child elements - only select if advanced nav is enabled
237
+ const navButton = [];
238
+ if (hasAdvancedNav) {
239
+ const navButtonParents = document.querySelectorAll(
240
+ '[data-hs-hero="nav-button"]',
241
+ );
242
+ navButtonParents.forEach((el) => {
243
+ if (el.firstElementChild) navButton.push(el.firstElementChild);
244
+ });
245
+ }
246
+
247
+ const subheading = [];
248
+ const subheadingAppearElements = [];
249
+ const subheadingElements = document.querySelectorAll(
250
+ '[data-hs-hero="subheading"]',
251
+ );
252
+ const subheadingSplitElements = [];
253
+
254
+ subheadingElements.forEach((el) => {
255
+ if (el.firstElementChild) {
256
+ // Get the heroconfig attribute to determine animation type (default to appear)
257
+ const heroConfig = el.getAttribute("data-hs-config") || "appear";
258
+
259
+ if (heroConfig === "appear") {
260
+ subheadingAppearElements.push(el.firstElementChild);
261
+ } else {
262
+ subheading.push(el.firstElementChild);
263
+ subheadingSplitElements.push(el);
264
+ }
195
265
  }
196
-
197
- gsap.registerPlugin(ScrollTrigger, SplitText);
198
-
199
- // Element selection
200
- const announceElements = document.querySelectorAll('[data-hs-hero="announce"]');
201
- const navElement = document.querySelector('[data-hs-hero="nav"]');
202
- const navMenuElements = document.querySelectorAll('[data-hs-hero="nav-menu"]');
203
- const navLogoElements = document.querySelectorAll('[data-hs-hero="nav-logo"]');
204
- const imageElements = document.querySelectorAll('[data-hs-hero="image"]');
205
- const appearElements = document.querySelectorAll('[data-hs-hero="appear"]');
206
-
207
- // Check if nav has advanced config
208
- const hasAdvancedNav = navElement && navElement.hasAttribute('data-hs-config') && navElement.getAttribute('data-hs-config') === 'advanced';
209
-
210
- // First child elements - only select if advanced nav is enabled
211
- const navButton = [];
212
- if (hasAdvancedNav) {
213
- const navButtonParents = document.querySelectorAll('[data-hs-hero="nav-button"]');
214
- navButtonParents.forEach(el => {
215
- if (el.firstElementChild) navButton.push(el.firstElementChild);
216
- });
266
+ });
267
+
268
+ const heading = [];
269
+ const headingAppearElements = [];
270
+ const headingElements = document.querySelectorAll('[data-hs-hero="heading"]');
271
+ const headingSplitElements = [];
272
+
273
+ headingElements.forEach((el) => {
274
+ if (el.firstElementChild) {
275
+ // Get the heroconfig attribute to determine animation type
276
+ const heroConfig = el.getAttribute("data-hs-config") || "line"; // default to line if not specified
277
+
278
+ if (heroConfig === "appear") {
279
+ headingAppearElements.push(el.firstElementChild);
280
+ } else {
281
+ heading.push(el.firstElementChild);
282
+ headingSplitElements.push(el);
283
+ }
217
284
  }
218
-
219
- const subheading = [];
220
- const subheadingAppearElements = [];
221
- const subheadingElements = document.querySelectorAll('[data-hs-hero="subheading"]');
222
- const subheadingSplitElements = [];
223
-
224
- subheadingElements.forEach(el => {
225
- if (el.firstElementChild) {
226
- // Get the heroconfig attribute to determine animation type (default to appear)
227
- const heroConfig = el.getAttribute('data-hs-config') || 'appear';
228
-
229
- if (heroConfig === 'appear') {
230
- subheadingAppearElements.push(el.firstElementChild);
231
- } else {
232
- subheading.push(el.firstElementChild);
233
- subheadingSplitElements.push(el);
234
- }
285
+ });
286
+
287
+ const tag = [];
288
+ const tagParents = document.querySelectorAll('[data-hs-hero="tag"]');
289
+ tagParents.forEach((el) => {
290
+ if (el.firstElementChild) tag.push(el.firstElementChild);
291
+ });
292
+
293
+ // All children elements
294
+ const buttonAllChildren = [];
295
+ const buttonParents = document.querySelectorAll('[data-hs-hero="button"]');
296
+ buttonParents.forEach((el) => {
297
+ const children = Array.from(el.children);
298
+ buttonAllChildren.push(...children);
299
+ });
300
+
301
+ const navListAllChildren = [];
302
+ if (hasAdvancedNav) {
303
+ const navListParents = document.querySelectorAll(
304
+ '[data-hs-hero="nav-list"]',
305
+ );
306
+ navListParents.forEach((el) => {
307
+ const children = Array.from(el.children);
308
+
309
+ // Add overflow clip class to each child and collect their first child for animation
310
+ children.forEach((child) => {
311
+ child.classList.add("u-overflow-clip");
312
+ if (child.firstElementChild) {
313
+ navListAllChildren.push(child.firstElementChild);
235
314
  }
315
+ });
236
316
  });
237
-
238
- const heading = [];
239
- const headingAppearElements = [];
240
- const headingElements = document.querySelectorAll('[data-hs-hero="heading"]');
241
- const headingSplitElements = [];
242
-
243
- headingElements.forEach(el => {
244
- if (el.firstElementChild) {
245
- // Get the heroconfig attribute to determine animation type
246
- const heroConfig = el.getAttribute('data-hs-config') || 'line'; // default to line if not specified
247
-
248
- if (heroConfig === 'appear') {
249
- headingAppearElements.push(el.firstElementChild);
250
- } else {
251
- heading.push(el.firstElementChild);
252
- headingSplitElements.push(el);
253
- }
317
+ }
318
+
319
+ // Initial states
320
+ if (announceElements.length > 0)
321
+ gsap.set(announceElements, { opacity: 0, y: -50 });
322
+ if (navElement) {
323
+ gsap.set(navElement, { opacity: 0, y: -50 });
324
+ // Disable nav pointer events until animation completes
325
+ navElement.style.pointerEvents = "none";
326
+ }
327
+ if (hasAdvancedNav && navListAllChildren.length > 0)
328
+ gsap.set(navListAllChildren, { opacity: 0, yPercent: 110 });
329
+ if (hasAdvancedNav && navMenuElements.length > 0)
330
+ gsap.set(navMenuElements, { opacity: 0 });
331
+ if (hasAdvancedNav && navButton.length > 0)
332
+ gsap.set(navButton, { opacity: 0 });
333
+ if (hasAdvancedNav && navLogoElements.length > 0)
334
+ gsap.set(navLogoElements, { opacity: 0 });
335
+ if (subheadingAppearElements.length > 0)
336
+ gsap.set(subheadingAppearElements, { y: config.appear.y, opacity: 0 });
337
+ if (tag.length > 0) gsap.set(tag, { y: config.appear.y, opacity: 0 });
338
+ if (buttonAllChildren.length > 0)
339
+ gsap.set(buttonAllChildren, { y: config.appear.y, opacity: 0 });
340
+ if (imageElements.length > 0) gsap.set(imageElements, { opacity: 0 });
341
+ if (mainElements.length > 0) gsap.set(mainElements, { opacity: 0 });
342
+ if (appearElements.length > 0)
343
+ gsap.set(appearElements, { y: config.appear.y, opacity: 0 });
344
+ if (headingAppearElements.length > 0)
345
+ gsap.set(headingAppearElements, { y: config.appear.y, opacity: 0 });
346
+
347
+ // Disable page-wide tabbing and interactions until animation completes
348
+ const allFocusableElements = document.querySelectorAll(
349
+ 'a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])',
350
+ );
351
+ allFocusableElements.forEach((el) => {
352
+ el.style.pointerEvents = "none";
353
+ el.setAttribute(
354
+ "data-original-tabindex",
355
+ el.getAttribute("tabindex") || "0",
356
+ );
357
+ el.setAttribute("tabindex", "-1");
358
+ });
359
+
360
+ // Animation timeline
361
+ document.fonts.ready.then(() => {
362
+ // Split text setup (after fonts are loaded)
363
+ headingSplits = [];
364
+
365
+ if (heading.length > 0) {
366
+ headingSplitElements.forEach((parent, index) => {
367
+ const textElement = heading[index];
368
+ const splitType = parent.getAttribute("data-hs-config") || "line";
369
+
370
+ let splitConfig = {};
371
+ let elementsClass = "";
372
+
373
+ if (splitType === "char") {
374
+ splitConfig = {
375
+ type: "words,chars",
376
+ mask: "chars",
377
+ charsClass: "char",
378
+ };
379
+ elementsClass = "chars";
380
+ } else if (splitType === "line") {
381
+ splitConfig = {
382
+ type: "lines",
383
+ mask: "lines",
384
+ linesClass: "line",
385
+ };
386
+ elementsClass = "lines";
387
+ } else {
388
+ splitConfig = {
389
+ type: "words",
390
+ mask: "words",
391
+ wordsClass: "word",
392
+ };
393
+ elementsClass = "words";
254
394
  }
255
- });
256
-
257
- const tag = [];
258
- const tagParents = document.querySelectorAll('[data-hs-hero="tag"]');
259
- tagParents.forEach(el => {
260
- if (el.firstElementChild) tag.push(el.firstElementChild);
261
- });
262
-
263
- // All children elements
264
- const buttonAllChildren = [];
265
- const buttonParents = document.querySelectorAll('[data-hs-hero="button"]');
266
- buttonParents.forEach(el => {
267
- const children = Array.from(el.children);
268
- buttonAllChildren.push(...children);
269
- });
270
-
271
- const navListAllChildren = [];
272
- if (hasAdvancedNav) {
273
- const navListParents = document.querySelectorAll('[data-hs-hero="nav-list"]');
274
- navListParents.forEach(el => {
275
- const children = Array.from(el.children);
276
-
277
- // Add overflow clip class to each child and collect their first child for animation
278
- children.forEach(child => {
279
- child.classList.add('u-overflow-clip');
280
- if (child.firstElementChild) {
281
- navListAllChildren.push(child.firstElementChild);
282
- }
283
- });
395
+
396
+ const split = new SplitText(textElement, splitConfig);
397
+ split.elementsClass = elementsClass;
398
+ headingSplits.push(split);
399
+
400
+ gsap.set(split[elementsClass], {
401
+ yPercent: config.headingSplit.yPercent,
284
402
  });
403
+ gsap.set(textElement, { autoAlpha: 1 });
404
+ });
285
405
  }
286
-
287
- // Initial states
288
- if (announceElements.length > 0) gsap.set(announceElements, { opacity: 0, y: -50 });
289
- if (navElement) {
290
- gsap.set(navElement, { opacity: 0, y: -50 });
291
- // Disable nav pointer events until animation completes
292
- navElement.style.pointerEvents = 'none';
406
+
407
+ // Split text setup for subheadings
408
+ if (subheading.length > 0) {
409
+ subheadingSplitElements.forEach((parent, index) => {
410
+ const textElement = subheading[index];
411
+ const splitType = parent.getAttribute("data-hs-config") || "word";
412
+
413
+ let splitConfig = {};
414
+ let elementsClass = "";
415
+
416
+ if (splitType === "char") {
417
+ splitConfig = {
418
+ type: "words,chars",
419
+ mask: "chars",
420
+ charsClass: "char",
421
+ };
422
+ elementsClass = "chars";
423
+ } else if (splitType === "line") {
424
+ splitConfig = {
425
+ type: "lines",
426
+ mask: "lines",
427
+ linesClass: "line",
428
+ };
429
+ elementsClass = "lines";
430
+ } else {
431
+ splitConfig = {
432
+ type: "words",
433
+ mask: "words",
434
+ wordsClass: "word",
435
+ };
436
+ elementsClass = "words";
293
437
  }
294
- if (hasAdvancedNav && navListAllChildren.length > 0) gsap.set(navListAllChildren, { opacity: 0, yPercent: 110 });
295
- if (hasAdvancedNav && navMenuElements.length > 0) gsap.set(navMenuElements, { opacity: 0 });
296
- if (hasAdvancedNav && navButton.length > 0) gsap.set(navButton, { opacity: 0 });
297
- if (hasAdvancedNav && navLogoElements.length > 0) gsap.set(navLogoElements, { opacity: 0 });
298
- if (subheadingAppearElements.length > 0) gsap.set(subheadingAppearElements, { y: config.appear.y, opacity: 0 });
299
- if (tag.length > 0) gsap.set(tag, { y: config.appear.y, opacity: 0 });
300
- if (buttonAllChildren.length > 0) gsap.set(buttonAllChildren, { y: config.appear.y, opacity: 0 });
301
- if (imageElements.length > 0) gsap.set(imageElements, { opacity: 0 });
302
- if (appearElements.length > 0) gsap.set(appearElements, { y: config.appear.y, opacity: 0 });
303
- if (headingAppearElements.length > 0) gsap.set(headingAppearElements, { y: config.appear.y, opacity: 0 });
304
-
305
- // Disable page-wide tabbing and interactions until animation completes
306
- const allFocusableElements = document.querySelectorAll('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])');
307
- allFocusableElements.forEach(el => {
308
- el.style.pointerEvents = 'none';
309
- el.setAttribute('data-original-tabindex', el.getAttribute('tabindex') || '0');
310
- el.setAttribute('tabindex', '-1');
438
+
439
+ const split = new SplitText(textElement, splitConfig);
440
+ split.elementsClass = elementsClass;
441
+ subheadingSplits.push(split);
442
+
443
+ gsap.set(split[elementsClass], {
444
+ yPercent: config.subheadingSplit.yPercent,
311
445
  });
312
-
313
- // Animation timeline
314
- document.fonts.ready.then(() => {
315
-
316
- // Split text setup (after fonts are loaded)
317
- headingSplits = [];
318
-
319
- if (heading.length > 0) {
320
- headingSplitElements.forEach((parent, index) => {
321
- const textElement = heading[index];
322
- const splitType = parent.getAttribute('data-hs-config') || 'line';
323
-
324
- let splitConfig = {};
325
- let elementsClass = '';
326
-
327
- if (splitType === 'char') {
328
- splitConfig = {
329
- type: "words,chars",
330
- mask: "chars",
331
- charsClass: "char"
332
- };
333
- elementsClass = 'chars';
334
- } else if (splitType === 'line') {
335
- splitConfig = {
336
- type: "lines",
337
- mask: "lines",
338
- linesClass: "line"
339
- };
340
- elementsClass = 'lines';
341
- } else {
342
- splitConfig = {
343
- type: "words",
344
- mask: "words",
345
- wordsClass: "word"
346
- };
347
- elementsClass = 'words';
348
- }
349
-
350
- const split = new SplitText(textElement, splitConfig);
351
- split.elementsClass = elementsClass;
352
- headingSplits.push(split);
353
-
354
- gsap.set(split[elementsClass], { yPercent: config.headingSplit.yPercent });
355
- gsap.set(textElement, { autoAlpha: 1 });
356
- });
357
- }
358
-
359
- // Split text setup for subheadings
360
- if (subheading.length > 0) {
361
- subheadingSplitElements.forEach((parent, index) => {
362
- const textElement = subheading[index];
363
- const splitType = parent.getAttribute('data-hs-config') || 'word';
364
-
365
- let splitConfig = {};
366
- let elementsClass = '';
367
-
368
- if (splitType === 'char') {
369
- splitConfig = {
370
- type: "words,chars",
371
- mask: "chars",
372
- charsClass: "char"
373
- };
374
- elementsClass = 'chars';
375
- } else if (splitType === 'line') {
376
- splitConfig = {
377
- type: "lines",
378
- mask: "lines",
379
- linesClass: "line"
380
- };
381
- elementsClass = 'lines';
382
- } else {
383
- splitConfig = {
384
- type: "words",
385
- mask: "words",
386
- wordsClass: "word"
387
- };
388
- elementsClass = 'words';
389
- }
390
-
391
- const split = new SplitText(textElement, splitConfig);
392
- split.elementsClass = elementsClass;
393
- subheadingSplits.push(split);
394
-
395
- gsap.set(split[elementsClass], { yPercent: config.subheadingSplit.yPercent });
396
- gsap.set(textElement, { autoAlpha: 1 });
397
- });
398
- }
399
-
400
- heroTimeout = setTimeout(() => {
401
- heroTimeline = gsap.timeline();
402
-
403
- if (announceElements.length > 0) {
404
- heroTimeline.to(announceElements,
405
- { opacity: 1, y: 0, duration: config.nav.duration, ease: config.nav.ease },
406
- timing.announce
407
- );
408
- }
409
-
410
- if (navElement) {
411
- heroTimeline.to(navElement,
412
- {
413
- opacity: 1,
414
- y: 0,
415
- duration: config.nav.duration,
416
- ease: config.nav.ease,
417
- onComplete: () => {
418
- // If no advanced nav, restore interactions here
419
- if (!hasAdvancedNav) {
420
- const allFocusableElements = document.querySelectorAll('[data-original-tabindex]');
421
- allFocusableElements.forEach(el => {
422
- el.style.pointerEvents = '';
423
- const originalTabindex = el.getAttribute('data-original-tabindex');
424
- if (originalTabindex === '0') {
425
- el.removeAttribute('tabindex');
426
- } else {
427
- el.setAttribute('tabindex', originalTabindex);
428
- }
429
- el.removeAttribute('data-original-tabindex');
430
- });
431
- // Restore nav pointer events
432
- navElement.style.pointerEvents = '';
433
- }
434
- }
435
- },
436
- timing.nav
437
- );
438
- }
439
-
440
- if (hasAdvancedNav && navLogoElements.length > 0) {
441
- heroTimeline.to(navLogoElements,
442
- { opacity: 1, duration: .5, ease: config.nav.ease },
443
- timing.navLogo
444
- );
445
- }
446
-
447
- if (hasAdvancedNav && navListAllChildren.length > 0) {
448
- heroTimeline.to(navListAllChildren,
449
- {
450
- opacity: 1,
451
- yPercent: 0,
452
- duration: config.nav.duration,
453
- stagger: 0.05,
454
- ease: config.nav.ease,
455
- onComplete: () => {
456
- // Remove u-overflow-clip class from list children
457
- const navListParents = document.querySelectorAll('[data-hs-hero="nav-list"]');
458
- navListParents.forEach(parent => {
459
- const children = parent.children;
460
- Array.from(children).forEach(child => {
461
- child.classList.remove('u-overflow-clip');
462
- });
463
- });
464
- }
465
- },
466
- timing.navList
467
- );
468
- }
469
-
470
- if (hasAdvancedNav && navMenuElements.length > 0) {
471
- heroTimeline.to(navMenuElements,
472
- { opacity: 1, duration: config.nav.duration, ease: config.nav.ease },
473
- timing.navMenu
474
- );
475
- }
476
-
477
- if (hasAdvancedNav && navButton.length > 0) {
478
- heroTimeline.to(navButton,
479
- {
480
- opacity: 1,
481
- duration: config.nav.duration,
482
- ease: config.nav.ease,
483
- onComplete: () => {
484
- // Restore page-wide tabbing and interactions after navbar animations complete
485
- const allFocusableElements = document.querySelectorAll('[data-original-tabindex]');
486
- allFocusableElements.forEach(el => {
487
- el.style.pointerEvents = '';
488
- const originalTabindex = el.getAttribute('data-original-tabindex');
489
- if (originalTabindex === '0') {
490
- el.removeAttribute('tabindex');
491
- } else {
492
- el.setAttribute('tabindex', originalTabindex);
493
- }
494
- el.removeAttribute('data-original-tabindex');
495
- });
496
- // Restore nav pointer events
497
- if (navElement) {
498
- navElement.style.pointerEvents = '';
499
- }
500
- }
501
- },
502
- timing.navButton
446
+ gsap.set(textElement, { autoAlpha: 1 });
447
+ });
448
+ }
449
+
450
+ heroTimeout = setTimeout(() => {
451
+ heroTimeline = gsap.timeline();
452
+
453
+ if (announceElements.length > 0) {
454
+ heroTimeline.to(
455
+ announceElements,
456
+ {
457
+ opacity: 1,
458
+ y: 0,
459
+ duration: config.nav.duration,
460
+ ease: config.nav.ease,
461
+ },
462
+ timing.announce,
463
+ );
464
+ }
465
+
466
+ if (navElement) {
467
+ heroTimeline.to(
468
+ navElement,
469
+ {
470
+ opacity: 1,
471
+ y: 0,
472
+ duration: config.nav.duration,
473
+ ease: config.nav.ease,
474
+ onComplete: () => {
475
+ // If no advanced nav, restore interactions here
476
+ if (!hasAdvancedNav) {
477
+ const allFocusableElements = document.querySelectorAll(
478
+ "[data-original-tabindex]",
503
479
  );
504
- }
505
-
506
- if (headingSplits.length > 0) {
507
- headingSplits.forEach(split => {
508
- heroTimeline.to(split[split.elementsClass],
509
- {
510
- yPercent: 0,
511
- duration: config.headingSplit.duration,
512
- stagger: config.headingSplit.stagger,
513
- ease: config.headingSplit.ease,
514
- onComplete: () => {
515
- if (split && split.revert) {
516
- split.revert();
517
- }
518
- }
519
- },
520
- timing.heading
521
- );
480
+ allFocusableElements.forEach((el) => {
481
+ el.style.pointerEvents = "";
482
+ const originalTabindex = el.getAttribute(
483
+ "data-original-tabindex",
484
+ );
485
+ if (originalTabindex === "0") {
486
+ el.removeAttribute("tabindex");
487
+ } else {
488
+ el.setAttribute("tabindex", originalTabindex);
489
+ }
490
+ el.removeAttribute("data-original-tabindex");
522
491
  });
523
- }
524
-
525
- if (subheadingSplits.length > 0) {
526
- subheadingSplits.forEach(split => {
527
- heroTimeline.to(split[split.elementsClass],
528
- {
529
- yPercent: 0,
530
- duration: config.subheadingSplit.duration,
531
- stagger: config.subheadingSplit.stagger,
532
- ease: config.subheadingSplit.ease,
533
- onComplete: () => {
534
- if (split && split.revert) {
535
- split.revert();
536
- }
537
- }
538
- },
539
- timing.subheading
540
- );
492
+ // Restore nav pointer events
493
+ navElement.style.pointerEvents = "";
494
+ }
495
+ },
496
+ },
497
+ timing.nav,
498
+ );
499
+ }
500
+
501
+ if (hasAdvancedNav && navLogoElements.length > 0) {
502
+ heroTimeline.to(
503
+ navLogoElements,
504
+ { opacity: 1, duration: 0.5, ease: config.nav.ease },
505
+ timing.navLogo,
506
+ );
507
+ }
508
+
509
+ if (hasAdvancedNav && navListAllChildren.length > 0) {
510
+ heroTimeline.to(
511
+ navListAllChildren,
512
+ {
513
+ opacity: 1,
514
+ yPercent: 0,
515
+ duration: config.nav.duration,
516
+ stagger: 0.05,
517
+ ease: config.nav.ease,
518
+ onComplete: () => {
519
+ // Remove u-overflow-clip class from list children
520
+ const navListParents = document.querySelectorAll(
521
+ '[data-hs-hero="nav-list"]',
522
+ );
523
+ navListParents.forEach((parent) => {
524
+ const children = parent.children;
525
+ Array.from(children).forEach((child) => {
526
+ child.classList.remove("u-overflow-clip");
541
527
  });
542
- }
543
-
544
- if (subheadingAppearElements.length > 0) {
545
- heroTimeline.to(subheadingAppearElements,
546
- { y: 0, opacity: 1, duration: config.appear.duration, ease: config.appear.ease },
547
- timing.subheading
548
- );
549
- }
550
-
551
- if (tag.length > 0) {
552
- heroTimeline.to(tag,
553
- { y: 0, opacity: 1, duration: config.appear.duration, ease: config.appear.ease },
554
- timing.tag
555
- );
556
- }
557
-
558
- if (buttonAllChildren.length > 0) {
559
- heroTimeline.to(buttonAllChildren,
560
- { y: 0, opacity: 1, duration: config.navStagger.duration, stagger: config.navStagger.stagger, ease: config.navStagger.ease },
561
- timing.button
562
- );
563
- }
564
-
565
- if (imageElements.length > 0) {
566
- heroTimeline.to(imageElements,
567
- { opacity: 1, duration: config.appear.duration, ease: config.appear.ease },
568
- timing.image
528
+ });
529
+ },
530
+ },
531
+ timing.navList,
532
+ );
533
+ }
534
+
535
+ if (hasAdvancedNav && navMenuElements.length > 0) {
536
+ heroTimeline.to(
537
+ navMenuElements,
538
+ { opacity: 1, duration: config.nav.duration, ease: config.nav.ease },
539
+ timing.navMenu,
540
+ );
541
+ }
542
+
543
+ if (hasAdvancedNav && navButton.length > 0) {
544
+ heroTimeline.to(
545
+ navButton,
546
+ {
547
+ opacity: 1,
548
+ duration: config.nav.duration,
549
+ ease: config.nav.ease,
550
+ onComplete: () => {
551
+ // Restore page-wide tabbing and interactions after navbar animations complete
552
+ const allFocusableElements = document.querySelectorAll(
553
+ "[data-original-tabindex]",
554
+ );
555
+ allFocusableElements.forEach((el) => {
556
+ el.style.pointerEvents = "";
557
+ const originalTabindex = el.getAttribute(
558
+ "data-original-tabindex",
569
559
  );
570
- }
571
-
572
- // Combine appear elements and heading appear elements
573
- const allAppearElements = [...appearElements, ...headingAppearElements];
574
-
575
- if (allAppearElements.length > 0) {
576
- heroTimeline.to(allAppearElements,
577
- {
578
- y: 0,
579
- opacity: 1,
580
- duration: config.appear.duration,
581
- ease: config.appear.ease,
582
- onComplete: () => {
583
- // Check if interactions haven't been restored yet
584
- const stillDisabled = document.querySelector('[data-original-tabindex]');
585
- if (stillDisabled) {
586
- const allFocusableElements = document.querySelectorAll('[data-original-tabindex]');
587
- allFocusableElements.forEach(el => {
588
- el.style.pointerEvents = '';
589
- const originalTabindex = el.getAttribute('data-original-tabindex');
590
- if (originalTabindex === '0') {
591
- el.removeAttribute('tabindex');
592
- } else {
593
- el.setAttribute('tabindex', originalTabindex);
594
- }
595
- el.removeAttribute('data-original-tabindex');
596
- });
597
- // Restore nav pointer events
598
- if (navElement) {
599
- navElement.style.pointerEvents = '';
600
- }
601
- }
602
- }
603
- },
604
- timing.appear
560
+ if (originalTabindex === "0") {
561
+ el.removeAttribute("tabindex");
562
+ } else {
563
+ el.setAttribute("tabindex", originalTabindex);
564
+ }
565
+ el.removeAttribute("data-original-tabindex");
566
+ });
567
+ // Restore nav pointer events
568
+ if (navElement) {
569
+ navElement.style.pointerEvents = "";
570
+ }
571
+ },
572
+ },
573
+ timing.navButton,
574
+ );
575
+ }
576
+
577
+ if (headingSplits.length > 0) {
578
+ headingSplits.forEach((split) => {
579
+ heroTimeline.to(
580
+ split[split.elementsClass],
581
+ {
582
+ yPercent: 0,
583
+ duration: config.headingSplit.duration,
584
+ stagger: config.headingSplit.stagger,
585
+ ease: config.headingSplit.ease,
586
+ onComplete: () => {
587
+ if (split && split.revert) {
588
+ split.revert();
589
+ }
590
+ },
591
+ },
592
+ timing.heading,
593
+ );
594
+ });
595
+ }
596
+
597
+ if (subheadingSplits.length > 0) {
598
+ subheadingSplits.forEach((split) => {
599
+ heroTimeline.to(
600
+ split[split.elementsClass],
601
+ {
602
+ yPercent: 0,
603
+ duration: config.subheadingSplit.duration,
604
+ stagger: config.subheadingSplit.stagger,
605
+ ease: config.subheadingSplit.ease,
606
+ onComplete: () => {
607
+ if (split && split.revert) {
608
+ split.revert();
609
+ }
610
+ },
611
+ },
612
+ timing.subheading,
613
+ );
614
+ });
615
+ }
616
+
617
+ if (subheadingAppearElements.length > 0) {
618
+ heroTimeline.to(
619
+ subheadingAppearElements,
620
+ {
621
+ y: 0,
622
+ opacity: 1,
623
+ duration: config.appear.duration,
624
+ ease: config.appear.ease,
625
+ },
626
+ timing.subheading,
627
+ );
628
+ }
629
+
630
+ if (tag.length > 0) {
631
+ heroTimeline.to(
632
+ tag,
633
+ {
634
+ y: 0,
635
+ opacity: 1,
636
+ duration: config.appear.duration,
637
+ ease: config.appear.ease,
638
+ },
639
+ timing.tag,
640
+ );
641
+ }
642
+
643
+ if (buttonAllChildren.length > 0) {
644
+ heroTimeline.to(
645
+ buttonAllChildren,
646
+ {
647
+ y: 0,
648
+ opacity: 1,
649
+ duration: config.navStagger.duration,
650
+ stagger: config.navStagger.stagger,
651
+ ease: config.navStagger.ease,
652
+ },
653
+ timing.button,
654
+ );
655
+ }
656
+
657
+ if (imageFirstElements.length > 0) {
658
+ heroTimeline.to(
659
+ imageFirstElements,
660
+ {
661
+ opacity: 1,
662
+ duration: config.appear.duration,
663
+ ease: config.appear.ease,
664
+ },
665
+ 0,
666
+ );
667
+ }
668
+
669
+ if (imageRegularElements.length > 0) {
670
+ heroTimeline.to(
671
+ imageRegularElements,
672
+ {
673
+ opacity: 1,
674
+ duration: config.appear.duration,
675
+ ease: config.appear.ease,
676
+ },
677
+ timing.image,
678
+ );
679
+ }
680
+
681
+ // Combine appear elements and heading appear elements
682
+ const allAppearElements = [...appearElements, ...headingAppearElements];
683
+
684
+ if (allAppearElements.length > 0) {
685
+ heroTimeline.to(
686
+ allAppearElements,
687
+ {
688
+ y: 0,
689
+ opacity: 1,
690
+ duration: config.appear.duration,
691
+ ease: config.appear.ease,
692
+ onComplete: () => {
693
+ // Check if interactions haven't been restored yet
694
+ const stillDisabled = document.querySelector(
695
+ "[data-original-tabindex]",
696
+ );
697
+ if (stillDisabled) {
698
+ const allFocusableElements = document.querySelectorAll(
699
+ "[data-original-tabindex]",
605
700
  );
606
- } else {
607
- // If no appear elements, check if interactions need restoring when timeline completes
608
- heroTimeline.call(() => {
609
- const stillDisabled = document.querySelector('[data-original-tabindex]');
610
- if (stillDisabled) {
611
- const allFocusableElements = document.querySelectorAll('[data-original-tabindex]');
612
- allFocusableElements.forEach(el => {
613
- el.style.pointerEvents = '';
614
- const originalTabindex = el.getAttribute('data-original-tabindex');
615
- if (originalTabindex === '0') {
616
- el.removeAttribute('tabindex');
617
- } else {
618
- el.setAttribute('tabindex', originalTabindex);
619
- }
620
- el.removeAttribute('data-original-tabindex');
621
- });
622
- // Restore nav pointer events
623
- if (navElement) {
624
- navElement.style.pointerEvents = '';
625
- }
626
- }
701
+ allFocusableElements.forEach((el) => {
702
+ el.style.pointerEvents = "";
703
+ const originalTabindex = el.getAttribute(
704
+ "data-original-tabindex",
705
+ );
706
+ if (originalTabindex === "0") {
707
+ el.removeAttribute("tabindex");
708
+ } else {
709
+ el.setAttribute("tabindex", originalTabindex);
710
+ }
711
+ el.removeAttribute("data-original-tabindex");
627
712
  });
713
+ // Restore nav pointer events
714
+ if (navElement) {
715
+ navElement.style.pointerEvents = "";
716
+ }
717
+ }
718
+ },
719
+ },
720
+ timing.appear,
721
+ );
722
+ } else {
723
+ // If no appear elements, check if interactions need restoring when timeline completes
724
+ heroTimeline.call(() => {
725
+ const stillDisabled = document.querySelector(
726
+ "[data-original-tabindex]",
727
+ );
728
+ if (stillDisabled) {
729
+ const allFocusableElements = document.querySelectorAll(
730
+ "[data-original-tabindex]",
731
+ );
732
+ allFocusableElements.forEach((el) => {
733
+ el.style.pointerEvents = "";
734
+ const originalTabindex = el.getAttribute(
735
+ "data-original-tabindex",
736
+ );
737
+ if (originalTabindex === "0") {
738
+ el.removeAttribute("tabindex");
739
+ } else {
740
+ el.setAttribute("tabindex", originalTabindex);
741
+ }
742
+ el.removeAttribute("data-original-tabindex");
743
+ });
744
+ // Restore nav pointer events
745
+ if (navElement) {
746
+ navElement.style.pointerEvents = "";
628
747
  }
629
-
630
- heroTimeout = null;
631
-
632
- }, config.global.animationDelay * 1000);
633
-
748
+ }
634
749
  });
635
-
636
- // API exposure
637
- window[API_NAME] = window[API_NAME] || {};
638
- window[API_NAME].heroAnimations = {
639
- config: config,
640
- updateConfig: updateConfig,
641
- start: startHeroAnimations,
642
- kill: killHeroAnimations,
643
- restart: () => {
644
- killHeroAnimations();
645
- startHeroAnimations();
646
- }
647
- };
648
-
649
- // Add resize listener for responsive line splits
650
- let heroResizeTimeout;
651
- let lastWidth = window.innerWidth;
652
- window.addEventListener('resize', () => {
653
- const currentWidth = window.innerWidth;
654
- if (currentWidth !== lastWidth) {
655
- lastWidth = currentWidth;
656
- clearTimeout(heroResizeTimeout);
657
- heroResizeTimeout = setTimeout(() => {
658
- ScrollTrigger.refresh();
659
- }, 300);
660
- }
661
- });
662
-
663
- return { result: 'anim-hero initialized' };
664
- }
750
+ }
751
+
752
+ // Handle main elements with CSS transitions (no GSAP)
753
+ if (mainElements.length > 0) {
754
+ heroTimeline.call(() => {
755
+ mainElements.forEach((el) => {
756
+ el.style.transition = "opacity 1s ease";
757
+ el.style.opacity = "1";
758
+ });
759
+ }, null, timing.appear + 0.1);
760
+ }
761
+
762
+ heroTimeout = null;
763
+ }, config.global.animationDelay * 1000);
764
+ });
765
+
766
+ // API exposure
767
+ window[API_NAME] = window[API_NAME] || {};
768
+ window[API_NAME].heroAnimations = {
769
+ config: config,
770
+ updateConfig: updateConfig,
771
+ start: startHeroAnimations,
772
+ kill: killHeroAnimations,
773
+ restart: () => {
774
+ killHeroAnimations();
775
+ startHeroAnimations();
776
+ },
777
+ };
778
+
779
+ // Add resize listener for responsive line splits
780
+ let heroResizeTimeout;
781
+ let lastWidth = window.innerWidth;
782
+ window.addEventListener("resize", () => {
783
+ const currentWidth = window.innerWidth;
784
+ if (currentWidth !== lastWidth) {
785
+ lastWidth = currentWidth;
786
+ clearTimeout(heroResizeTimeout);
787
+ heroResizeTimeout = setTimeout(() => {
788
+ ScrollTrigger.refresh();
789
+ }, 300);
790
+ }
791
+ });
792
+
793
+ return { result: "anim-hero initialized" };
794
+ }