PageSourceSearch

https://multicampattern.com/static/marketing/js/homeIntro.7491b39c356d.js

js multicampattern.com collected 2026-09-26 11:22:14 UTC 27,833 bytes, 860 lines download raw bytes

1(function () {
2  'use strict';
3
4  var WORD_W = 377;
5  var WORD_H = 63;
6  var WORD_CX = 188.5;
7  var WORD_CY = 31.5;
8
9  var DEFAULT_CONFIG = {
10    slideIn: {
11      startX: 420,
12      duration: 0.87,
13      stagger: 0.055,
14      ease: 'sine.out',
15      order: ['M1', 'U', 'L', 'T', 'I', 'C', 'M2', 'A'],
16    },
17    readyTimeoutMs: 6000,
18    minHoldMs: 0,
19    scale: {
20      start: 0.13,
21      end: 0.87,
22      duration: 0.29,
23      ease: 'expo.inOut',
24      centerY: 0.5,
25    },
26    whiteFade: {
27      fromOpacity: 1,
28      toOpacity: 0,
29      duration: 0.35,
30      ease: 'power1.out',
31      offset: 0.1,
32    },
33    holdAfterScaleMs: 400,
34    zoom: {
35      duration: 0.26,
36      ease: 'expo.in',
37      endScale: 500,
38      /** Letter used as zoom pivot (matches data-letter on SVG paths). */
39      pivotLetter: 'I',
40      /** SVG-unit nudge right for I outline counter (between ~0.5 too left and ~2 toward C). */
41      cOffsetX: 1,
42      cOffsetY: 0,
43    },
44    reducedMotionFadeMs: 300,
45    debug: false,
46  };
47
48  function deepClone(o) {
49    return JSON.parse(JSON.stringify(o));
50  }
51
52  function deepMerge(base, patch) {
53    if (!patch || typeof patch !== 'object') return base;
54    Object.keys(patch).forEach(function (k) {
55      var v = patch[k];
56      if (v && typeof v === 'object' && !Array.isArray(v) && typeof v !== 'number') {
57        if (!base[k]) base[k] = {};
58        deepMerge(base[k], v);
59      } else {
60        base[k] = v;
61      }
62    });
63    return base;
64  }
65
66  function setByPath(obj, path, value) {
67    var parts = path.split('.');
68    var cur = obj;
69    for (var i = 0; i < parts.length - 1; i++) {
70      var p = parts[i];
71      if (!cur[p]) cur[p] = {};
72      cur = cur[p];
73    }
74    cur[parts[parts.length - 1]] = value;
75  }
76
77  function coerceVal(s) {
78    if (s === 'true') return true;
79    if (s === 'false') return false;
80    var n = parseFloat(s);
81    if (!isNaN(n) && String(n) === s) return n;
82    return s;
83  }
84
85  function parseIntroQueryString() {
86    try {
87      var params = new URLSearchParams(window.location.search);
88      var raw = params.get('intro');
89      if (!raw) return;
90      raw.split(',').forEach(function (pair) {
91        var eq = pair.indexOf('=');
92        if (eq === -1) return;
93        var path = pair.slice(0, eq).trim();
94        var val = coerceVal(pair.slice(eq + 1).trim());
95        if (path === 'debug') {
96          window.homeIntro.CONFIG.debug = val === true || val === 1 || val === '1';
97          return;
98        }
99        setByPath(window.homeIntro.CONFIG, path, val);
100      });
101    } catch (e) { /* ignore */ }
102  }
103
104  var easeStringCache = {};
105  var easeIdSeq = 0;
106
107  function resolveEase(str) {
108    if (!str || str === 'none') return 'none';
109    if (easeStringCache[str]) return easeStringCache[str];
110    if (typeof CustomEase === 'undefined') {
111      easeStringCache[str] = str;
112      return str;
113    }
114    if (str.indexOf('cubic(') === 0) {
115      var inner = str.slice(6, -1).replace(/\s+/g, '');
116      var nums = inner.split(',').map(parseFloat);
117      if (nums.length === 4 && nums.every(function (x) { return !isNaN(x); })) {
118        var id = 'mcHiCubic_' + (easeIdSeq++);
119        try {
120          CustomEase.create(id, 'M0,0 C' + nums[0] + ',' + nums[1] + ' ' + nums[2] + ',' + nums[3] + ' 1,1');
121          easeStringCache[str] = id;
122          return id;
123        } catch (e) { /* fall through */ }
124      }
125    }
126    if (str.charAt(0) === 'M' || str.indexOf('M0,0') === 0) {
127      var pathId = 'mcHiPath_' + (easeIdSeq++);
128      try {
129        CustomEase.create(pathId, str);
130        easeStringCache[str] = pathId;
131        return pathId;
132      } catch (e2) { /* fall through */ }
133    }
134    easeStringCache[str] = str;
135    return str;
136  }
137
138  var activeTimeline = null;
139  var overlayNode = null;
140  var introStartMs = 0;
141
142  function sliceScale(svg) {
143    var r = svg.getBoundingClientRect();
144    var vb = svg.viewBox.baseVal;
145    if (!vb || !vb.width) return Math.max(r.width / 100, r.height / 100);
146    return Math.max(r.width / vb.width, r.height / vb.height);
147  }
148
149  function wordScaleForFraction(svg, fraction) {
150    var sc = sliceScale(svg);
151    var targetPx = fraction * window.innerWidth;
152    return targetPx / (WORD_W * sc);
153  }
154
155  var LETTER_ANCHOR_X = {
156    M1: 36.5,
157    U: 113,
158    L: 138.5,
159    T: 156,
160    I: 189.35,
161    C: 228,
162    M2: 277,
163    A: 335,
164  };
165
166  /** Prefer clip-free box map from measureLetterBoxesFromVisibleClone (matches slide clips). */
167  function pivotCenterXFromLetter(boxMap, pivotKey, wrap) {
168    var b = boxMap && boxMap[pivotKey];
169    if (b && b.width > 0 && b.height > 0) {
170      return b.x + b.width / 2;
171    }
172    var el = wrap && wrap.querySelector('[data-letter="' + pivotKey + '"]');
173    if (el) {
174      try {
175        var bb = el.getBBox();
176        if (bb.width > 0 && bb.height > 0) {
177          return bb.x + bb.width / 2;
178        }
179      } catch (eBb) { /* ignore */ }
180    }
181    var ax = LETTER_ANCHOR_X[pivotKey];
182    if (typeof ax === 'number') return ax;
183    return WORD_CX;
184  }
185
186  function responsiveOverrides() {
187    var w = window.innerWidth;
188    if (w > 1024) return {};
189    if (w > 768) {
190      return {
191        scaleEnd: 1,
192        cOffsetX: 1,
193        endScaleMin: 800,
194      };
195    }
196    return {
197      scaleStart: 0.4,
198      scaleEnd: .9,
199      cOffsetX: .6,
200      endScaleMin: 1000,
201    };
202  }
203
204  /** Zoom multiplier so the wordmark grows past viewport bounds (avoids an end-of-intro opacity cheat). */
205  function zoomScaleToClearViewport(svg, S1, endScaleMin) {
206    var cfg = window.homeIntro.CONFIG;
207    var r = svg.getBoundingClientRect();
208    var sc = sliceScale(svg);
209    var halfWordPx = WORD_W * 0.52 * S1 * sc;
210    if (halfWordPx < 6) halfWordPx = 6;
211    var diag = Math.hypot(r.width, r.height);
212    var zMin = (diag * 0.62) / halfWordPx;
213    var floor = endScaleMin != null ? endScaleMin : (cfg.zoom.endScale || 30);
214    return Math.max(floor, zMin);
215  }
216
217  function buildBaseMatrix(S, centerYFrac) {
218    var cy = centerYFrac * 100;
219    return new DOMMatrix()
220      .translate(50, cy)
221      .scale(S, S)
222      .translate(-WORD_CX, -WORD_CY);
223  }
224
225  function matrixToAttr(m) {
226    return 'matrix(' + m.a + ',' + m.b + ',' + m.c + ',' + m.d + ',' + m.e + ',' + m.f + ')';
227  }
228
229  /**
230   * Geometry inside defs/mask often reports getBBox() as 0×0; clone into the visible svg subtree to measure.
231   */
232  function measureLetterBoxesFromVisibleClone(group, svg) {
233    var map = {};
234    if (!group || !svg) return map;
235    var clone = group.cloneNode(true);
236    clone.removeAttribute('id');
237    var toUnclip = clone.querySelectorAll('[clip-path]');
238    for (var u = 0; u < toUnclip.length; u++) {
239      toUnclip[u].removeAttribute('clip-path');
240    }
241    clone.setAttribute('visibility', 'hidden');
242    clone.setAttribute('pointer-events', 'none');
243    svg.appendChild(clone);
244    try {
245      var paths = clone.querySelectorAll('[data-letter]');
246      for (var i = 0; i < paths.length; i++) {
247        var p = paths[i];
248        var k = p.getAttribute('data-letter');
249        if (!k) continue;
250        map[k] = p.getBBox();
251      }
252    } finally {
253      svg.removeChild(clone);
254    }
255    return map;
256  }
257
258  /**
259   * Per-letter clip rects; glyph translates while clip stays fixed in parent coords.
260   * boxMap from measureLetterBoxesFromVisibleClone (defs/mask getBBox is unreliable in browsers).
261   */
262  function applyLetterClips(group, defs, prefix, boxMap) {
263    if (!group || !defs) return;
264    var pad = 1.25;
265    boxMap = boxMap || {};
266    var letters = group.querySelectorAll('[data-letter]');
267    for (var i = 0; i < letters.length; i++) {
268      var el = letters[i];
269      var key = el.getAttribute('data-letter');
270      if (!key) continue;
271      var bb = boxMap[key] || el.getBBox();
272      if (!(bb.width > 0 && bb.height > 0)) continue;
273      var clipId = prefix + '-clip-' + key;
274      var cp = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
275      cp.setAttribute('id', clipId);
276      cp.setAttribute('clipPathUnits', 'userSpaceOnUse');
277      var r = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
278      r.setAttribute('x', String(bb.x - pad));
279      r.setAttribute('y', String(bb.y - pad));
280      r.setAttribute('width', String(bb.width + 2 * pad));
281      r.setAttribute('height', String(bb.height + 2 * pad));
282      cp.appendChild(r);
283      defs.appendChild(cp);
284      /* Clip on parent <g>: if clip-path sits on the same node GSAP translates, the clip moves with the glyph (no reveal). */
285      var clipG = document.createElementNS('http://www.w3.org/2000/svg', 'g');
286      clipG.setAttribute('clip-path', 'url(#' + clipId + ')');
287      var par = el.parentNode;
288      if (par) {
289        par.insertBefore(clipG, el);
290        clipG.appendChild(el);
291      }
292    }
293  }
294
295  function hideMcTransitionOverlay() {
296    var ov = document.getElementById('transition-overlay');
297    if (!ov) return;
298    if (typeof gsap !== 'undefined') {
299      gsap.set(ov, { autoAlpha: 0, pointerEvents: 'none' });
300    }
301    ov.style.display = 'none';
302  }
303
304  function mountOverlayFromTemplate() {
305    var tpl = document.getElementById('home-intro-overlay-source');
306    if (!tpl || !tpl.content) return null;
307    var node = tpl.content.firstElementChild.cloneNode(true);
308    document.body.appendChild(node);
309    return node;
310  }
311
312  function removeBootLayerNextFrame() {
313    requestAnimationFrame(function () {
314      document.documentElement.classList.remove('mc-home-intro-route');
315    });
316  }
317
318  function stopLenis() {
319    var L = window.__marketingLenis;
320    if (L && typeof L.stop === 'function') {
321      try {
322        L.stop();
323      } catch (e) { /* ignore */ }
324    }
325  }
326
327  function startLenis() {
328    var L = window.__marketingLenis;
329    if (L && typeof L.start === 'function') {
330      try {
331        L.start();
332      } catch (e) { /* ignore */ }
333    }
334    if (typeof window.marketingLenisEnsureRunning === 'function') {
335      window.marketingLenisEnsureRunning();
336    }
337  }
338
339  function raceTimeout(promise, ms) {
340    if (!promise || typeof promise.then !== 'function') return Promise.resolve();
341    return Promise.race([
342      promise,
343      new Promise(function (resolve) {
344        setTimeout(resolve, ms);
345      }),
346    ]);
347  }
348
349  function sleep(ms) {
350    return new Promise(function (r) {
351      setTimeout(r, ms);
352    });
353  }
354
355  function getHeroImageUrl(explicit) {
356    if (explicit) return explicit;
357    var img = document.getElementById('hero-intro-image');
358    return img ? img.src || img.getAttribute('src') : '';
359  }
360
361  function diffConfig(current, defaults) {
362    var out = {};
363    function walk(c, d, prefix) {
364      Object.keys(c).forEach(function (k) {
365        var ck = c[k];
366        var dk = d[k];
367        var path = prefix ? prefix + '.' + k : k;
368        if (ck && typeof ck === 'object' && !Array.isArray(ck) && dk && typeof dk === 'object' && !Array.isArray(dk)) {
369          walk(ck, dk, path);
370        } else if (JSON.stringify(ck) !== JSON.stringify(dk)) {
371          setByPath(out, path, ck);
372        }
373      });
374    }
375    walk(current, defaults, '');
376    return out;
377  }
378
379  function encodeIntroParam(diff) {
380    var pairs = [];
381    function flatten(o, prefix) {
382      Object.keys(o).forEach(function (k) {
383        var v = o[k];
384        var p = prefix ? prefix + '.' + k : k;
385        if (v && typeof v === 'object' && !Array.isArray(v)) {
386          flatten(v, p);
387        } else {
388          pairs.push(p + '=' + String(v));
389        }
390      });
391    }
392    flatten(diff, '');
393    return pairs.join(',');
394  }
395
396  var EASE_OPTIONS = [
397    'none',
398    'power1.in', 'power1.out', 'power1.inOut',
399    'power2.in', 'power2.out', 'power2.inOut',
400    'power3.in', 'power3.out', 'power3.inOut',
401    'power4.in', 'power4.out', 'power4.inOut',
402    'expo.in', 'expo.out', 'expo.inOut',
403    'circ.in', 'circ.out', 'circ.inOut',
404    'sine.in', 'sine.out', 'sine.inOut',
405    'back.in', 'back.out', 'back.inOut',
406    'elastic.out(1,0.3)',
407    'bounce.out',
408  ];
409
410  function buildDebugPanel() {
411    if (document.getElementById('home-intro-debug-panel')) return;
412    var cfg = window.homeIntro.CONFIG;
413    var panel = document.createElement('div');
414    panel.id = 'home-intro-debug-panel';
415    panel.setAttribute('role', 'region');
416    panel.setAttribute('aria-label', 'Home intro tuning');
417
418    function addRange(label, path, min, max, step) {
419      var wrap = document.createElement('div');
420      var lab = document.createElement('label');
421      lab.textContent = label;
422      var input = document.createElement('input');
423      input.type = 'range';
424      input.min = min;
425      input.max = max;
426      input.step = step;
427      input.value = String(evalPath(cfg, path));
428      input.addEventListener('change', function () {
429        setByPath(cfg, path, parseFloat(input.value));
430      });
431      wrap.appendChild(lab);
432      wrap.appendChild(input);
433      panel.appendChild(wrap);
434    }
435
436    function evalPath(obj, path) {
437      return path.split('.').reduce(function (a, k) { return a[k]; }, obj);
438    }
439
440    function addEase(label, path) {
441      var wrap = document.createElement('div');
442      var lab = document.createElement('label');
443      lab.textContent = label;
444      var sel = document.createElement('select');
445      EASE_OPTIONS.forEach(function (e) {
446        var o = document.createElement('option');
447        o.value = e;
448        o.textContent = e;
449        sel.appendChild(o);
450      });
451      var optCustom = document.createElement('option');
452      optCustom.value = '__custom';
453      optCustom.textContent = 'Custom…';
454      sel.appendChild(optCustom);
455      var cur = evalPath(cfg, path);
456      if (EASE_OPTIONS.indexOf(cur) >= 0) sel.value = cur;
457      else sel.value = '__custom';
458      var ta = document.createElement('textarea');
459      ta.placeholder = 'CustomEase path or cubic(0.2,0,0,1)';
460      if (sel.value === '__custom') ta.value = cur;
461      ta.style.display = sel.value === '__custom' ? 'block' : 'none';
462      sel.addEventListener('change', function () {
463        if (sel.value === '__custom') {
464          ta.style.display = 'block';
465        } else {
466          ta.style.display = 'none';
467          setByPath(cfg, path, sel.value);
468        }
469      });
470      ta.addEventListener('change', function () {
471        setByPath(cfg, path, ta.value.trim());
472      });
473      wrap.appendChild(lab);
474      wrap.appendChild(sel);
475      wrap.appendChild(ta);
476      panel.appendChild(wrap);
477    }
478
479    var h1 = document.createElement('strong');
480    h1.textContent = 'Slide-in';
481    panel.appendChild(h1);
482    addRange('duration', 'slideIn.duration', 0.1, 2, 0.01);
483    addRange('stagger', 'slideIn.stagger', 0, 0.4, 0.005);
484    addRange('startX', 'slideIn.startX', 60, 800, 10);
485    addEase('ease', 'slideIn.ease');
486
487    var h2 = document.createElement('strong');
488    h2.textContent = 'Scale';
489    panel.appendChild(h2);
490    addRange('duration', 'scale.duration', 0.2, 3, 0.01);
491    addRange('start', 'scale.start', 0.05, 0.5, 0.01);
492    addRange('end', 'scale.end', 0.6, 1.5, 0.01);
493    addRange('centerY', 'scale.centerY', 0.2, 0.8, 0.01);
494    addEase('ease', 'scale.ease');
495
496    var h3 = document.createElement('strong');
497    h3.textContent = 'White fade';
498    panel.appendChild(h3);
499    addRange('duration', 'whiteFade.duration', 0.1, 2, 0.01);
500    addRange('offset', 'whiteFade.offset', -0.5, 1, 0.01);
501    addEase('ease', 'whiteFade.ease');
502
503    var h4 = document.createElement('strong');
504    h4.textContent = 'Hold ms';
505    panel.appendChild(h4);
506    addRange('holdAfterScaleMs', 'holdAfterScaleMs', 0, 2000, 25);
507
508    var h5 = document.createElement('strong');
509    h5.textContent = 'Zoom';
510    panel.appendChild(h5);
511    addRange('duration', 'zoom.duration', 0.2, 3, 0.01);
512    addRange('endScale', 'zoom.endScale', 5, 80, 1);
513    addRange('cOffsetX', 'zoom.cOffsetX', -50, 50, 0.5);
514    addRange('cOffsetY', 'zoom.cOffsetY', -50, 50, 0.5);
515    addEase('ease', 'zoom.ease');
516
517    var btnRow = document.createElement('div');
518    [['Replay', function () { window.homeIntro.replay(); }],
519      ['Copy URL', function () {
520        var diff = diffConfig(window.homeIntro.CONFIG, deepClone(DEFAULT_CONFIG));
521        var enc = encodeURIComponent(encodeIntroParam(diff));
522        var u = location.origin + location.pathname + '?intro=' + enc;
523        if (navigator.clipboard && navigator.clipboard.writeText) {
524          navigator.clipboard.writeText(u);
525        }
526      }],
527      ['Reset', function () {
528        window.homeIntro.resetConfig();
529      }],
530      ['Export JSON', function () {
531        var diff = diffConfig(window.homeIntro.CONFIG, deepClone(DEFAULT_CONFIG));
532        var ta2 = document.createElement('textarea');
533        ta2.value = JSON.stringify(diff, null, 2);
534        ta2.style.width = '100%';
535        ta2.style.minHeight = '80px';
536        ta2.style.marginTop = '8px';
537        panel.appendChild(ta2);
538      }],
539    ].forEach(function (pair) {
540      var b = document.createElement('button');
541      b.type = 'button';
542      b.textContent = pair[0];
543      b.addEventListener('click', pair[1]);
544      btnRow.appendChild(b);
545    });
546    panel.appendChild(btnRow);
547
548    document.body.appendChild(panel);
549
550    document.addEventListener('keydown', function escClose(ev) {
551      if (ev.key === 'Escape' && panel.parentNode) {
552        panel.parentNode.removeChild(panel);
553        document.removeEventListener('keydown', escClose);
554      }
555    });
556  }
557
558  function maybeShowDebugPanel() {
559    var cfg = window.homeIntro.CONFIG;
560    try {
561      var qs = new URLSearchParams(window.location.search);
562      if (qs.get('intro') === 'debug=0') {
563        localStorage.removeItem('homeIntroDebug');
564        return;
565      }
566      localStorage.removeItem('homeIntroDebug');
567    } catch (e) { /* ignore */ }
568    if (cfg.debug) {
569      buildDebugPanel();
570    }
571  }
572
573  function cleanupIntro(opts) {
574    opts = opts || {};
575    if (activeTimeline) {
576      try {
577        activeTimeline.kill();
578      } catch (e) { /* ignore */ }
579      activeTimeline = null;
580    }
581    var letters = document.querySelectorAll(
582      '#mc-letters-wrap [data-letter], #mc-letters-wrap-stencil [data-letter]'
583    );
584    if (typeof gsap !== 'undefined') {
585      gsap.killTweensOf(letters);
586      gsap.killTweensOf('#mc-white, #mc-bg, #mc-letters-wrap, #mc-letters-wrap-stencil');
587    }
588    if (overlayNode && overlayNode.parentNode) {
589      overlayNode.parentNode.removeChild(overlayNode);
590    }
591    overlayNode = null;
592    document.documentElement.classList.remove('home-intro-active');
593    document.documentElement.classList.remove('mc-home-intro-route');
594    if (typeof window.__marketingSetPageChromeInert === 'function') {
595      window.__marketingSetPageChromeInert(false);
596    }
597    startLenis();
598    window.dispatchEvent(new CustomEvent('home-intro-complete'));
599    window._homeIntroCleanup = null;
600  }
601
602  function runFullIntro(opts) {
603    var readyPromise = opts.readyPromise || Promise.resolve();
604
605    hideMcTransitionOverlay();
606    stopLenis();
607
608    overlayNode = mountOverlayFromTemplate();
609    if (!overlayNode) {
610      cleanupIntro();
611      startLenis();
612      return Promise.resolve();
613    }
614
615    gsap.set(overlayNode, { autoAlpha: 1 });
616
617    removeBootLayerNextFrame();
618    document.documentElement.classList.add('home-intro-active');
619    if (typeof window.__marketingSetPageChromeInert === 'function') {
620      window.__marketingSetPageChromeInert(true);
621    }
622
623    var svg = overlayNode;
624    var wrap = svg.querySelector('#mc-letters-wrap');
625    var wrapStencil = svg.querySelector('#mc-letters-wrap-stencil');
626    var mcWhite = svg.querySelector('#mc-white');
627    var mcBg = svg.querySelector('#mc-bg');
628    var cfg = window.homeIntro.CONFIG;
629
630    var lettersOrdered = cfg.slideIn.order.map(function (key) {
631      return wrap.querySelector('[data-letter="' + key + '"]');
632    }).filter(Boolean);
633
634    var lettersStencilOrdered = cfg.slideIn.order.map(function (key) {
635      return wrapStencil && wrapStencil.querySelector('[data-letter="' + key + '"]');
636    }).filter(Boolean);
637
638    var defs = svg.querySelector('defs');
639
640    lettersOrdered.concat(lettersStencilOrdered).forEach(function (el) {
641      el.removeAttribute('transform');
642    });
643
644    var boxMapMain = measureLetterBoxesFromVisibleClone(wrap, svg);
645    var boxMapStencil = wrapStencil ? measureLetterBoxesFromVisibleClone(wrapStencil, svg) : {};
646
647    if (defs) {
648      applyLetterClips(wrap, defs, 'mc-hi', boxMapMain);
649      if (wrapStencil) applyLetterClips(wrapStencil, defs, 'mc-hi-s', boxMapStencil);
650    }
651
652    lettersOrdered.concat(lettersStencilOrdered).forEach(function (el) {
653      gsap.set(el, { x: cfg.slideIn.startX });
654    });
655
656    var initOverrides = responsiveOverrides();
657    var scaleStart = initOverrides.scaleStart != null ? initOverrides.scaleStart : cfg.scale.start;
658    var S0 = wordScaleForFraction(svg, scaleStart);
659    var stencilM = matrixToAttr(buildBaseMatrix(S0, cfg.scale.centerY));
660    wrap.setAttribute('transform', stencilM);
661    if (wrapStencil) wrapStencil.setAttribute('transform', stencilM);
662    gsap.set(mcWhite, { opacity: cfg.whiteFade.fromOpacity });
663    gsap.set(mcBg, { opacity: 1 });
664
665    return new Promise(function (resolveRunFullIntro) {
666      requestAnimationFrame(function () {
667        requestAnimationFrame(function () {
668          introStartMs = performance.now();
669
670          var slideTl = gsap.timeline();
671          var slideEase = resolveEase(cfg.slideIn.ease);
672          var slideDur = cfg.slideIn.duration;
673          var slideSt = cfg.slideIn.stagger;
674          slideTl.to(lettersOrdered, {
675            x: 0,
676            duration: slideDur,
677            stagger: slideSt,
678            ease: slideEase,
679          }, 0);
680          if (lettersStencilOrdered.length) {
681            slideTl.to(lettersStencilOrdered, {
682              x: 0,
683              duration: slideDur,
684              stagger: slideSt,
685              ease: slideEase,
686            }, 0);
687          }
688
689          var slideDone = new Promise(function (resolve) {
690            slideTl.eventCallback('onComplete', resolve);
691          });
692
693          slideDone.then(function () {
694            var waits = [raceTimeout(readyPromise, cfg.readyTimeoutMs)];
695            return Promise.all(waits);
696          }).then(function () {
697            var elapsed = performance.now() - introStartMs;
698            if (elapsed < cfg.minHoldMs) return sleep(cfg.minHoldMs - elapsed);
699          }).then(function () {
700            var overrides = responsiveOverrides();
701            var scaleEnd = overrides.scaleEnd != null ? overrides.scaleEnd : cfg.scale.end;
702            var S1 = wordScaleForFraction(svg, scaleEnd);
703            var master = gsap.timeline({
704              onComplete: function () {
705                activeTimeline = null;
706              },
707            });
708            activeTimeline = master;
709
710            var scaleProxy = { S: S0 };
711            master.to(scaleProxy, {
712              S: S1,
713              duration: cfg.scale.duration,
714              ease: resolveEase(cfg.scale.ease),
715              onUpdate: function () {
716                var m = matrixToAttr(buildBaseMatrix(scaleProxy.S, cfg.scale.centerY));
717                wrap.setAttribute('transform', m);
718                if (wrapStencil) wrapStencil.setAttribute('transform', m);
719              },
720            }, 0);
721
722            master.to(mcWhite, {
723              opacity: cfg.whiteFade.toOpacity,
724              duration: cfg.whiteFade.duration,
725              ease: resolveEase(cfg.whiteFade.ease),
726            }, Math.max(0, cfg.whiteFade.offset));
727
728            master.to({}, { duration: cfg.holdAfterScaleMs / 1000 }, cfg.scale.duration);
729
730            var pivotKey = String(cfg.zoom.pivotLetter || 'I');
731            if (!/^[A-Za-z0-9]{1,5}$/.test(pivotKey)) pivotKey = 'I';
732            var cxLocal = pivotCenterXFromLetter(boxMapMain, pivotKey, wrap);
733            var cyLocal = WORD_CY;
734            var baseM = buildBaseMatrix(S1, cfg.scale.centerY);
735            var pivot = { x: cxLocal, y: cyLocal };
736            try {
737              var pt = new DOMPoint(cxLocal, cyLocal).matrixTransform(baseM);
738              pivot.x = pt.x;
739              pivot.y = pt.y;
740            } catch (ePt) {
741              pivot.x = (cxLocal - WORD_CX) * S1 + 50;
742              pivot.y = (cyLocal - WORD_CY) * S1 + cfg.scale.centerY * 100;
743            }
744            pivot.x += overrides.cOffsetX != null ? overrides.cOffsetX : cfg.zoom.cOffsetX;
745            pivot.y += cfg.zoom.cOffsetY;
746
747            var zoomProxy = { z: 1 };
748            var zoomStart = cfg.scale.duration + cfg.holdAfterScaleMs / 1000;
749            var zoomEnd = zoomScaleToClearViewport(svg, S1, overrides.endScaleMin);
750            master.to(zoomProxy, {
751              z: zoomEnd,
752              duration: cfg.zoom.duration,
753              ease: resolveEase(cfg.zoom.ease),
754              onUpdate: function () {
755                var zm = new DOMMatrix()
756                  .translate(pivot.x, pivot.y)
757                  .scale(zoomProxy.z, zoomProxy.z)
758                  .translate(-pivot.x, -pivot.y)
759                  .multiply(baseM);
760                var matStr = matrixToAttr(zm);
761                wrap.setAttribute('transform', matStr);
762                if (wrapStencil) wrapStencil.setAttribute('transform', matStr);
763              },
764            }, zoomStart);
765
766            return new Promise(function (resolve) {
767              master.eventCallback('onComplete', function () {
768                cleanupIntro();
769                resolve();
770              });
771            });
772          }).then(resolveRunFullIntro);
773        });
774      });
775    });
776  }
777
778  window.homeIntro = {
779    CONFIG: deepClone(DEFAULT_CONFIG),
780
781    applyConfig: function (partial) {
782      deepMerge(window.homeIntro.CONFIG, partial);
783    },
784
785    resetConfig: function () {
786      window.homeIntro.CONFIG = deepClone(DEFAULT_CONFIG);
787      parseIntroQueryString();
788    },
789
790    cleanup: function (opts) {
791      cleanupIntro(opts || {});
792    },
793
794    replay: function () {
795      return window.homeIntro.run({
796        replay: true,
797        readyPromise: Promise.resolve(),
798        heroImageUrl: getHeroImageUrl(),
799      });
800    },
801
802    run: function (opts) {
803      opts = opts || {};
804      if (typeof gsap === 'undefined') {
805        cleanupIntro();
806        return Promise.resolve();
807      }
808
809      window._homeIntroCleanup = function () {
810        window.homeIntro.cleanup();
811      };
812
813      var reduced = false;
814      try {
815        reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
816      } catch (e) { /* ignore */ }
817
818      if (reduced && !opts.replay) {
819        hideMcTransitionOverlay();
820        stopLenis();
821        overlayNode = mountOverlayFromTemplate();
822        removeBootLayerNextFrame();
823        document.documentElement.classList.add('home-intro-active');
824        if (typeof window.__marketingSetPageChromeInert === 'function') {
825          window.__marketingSetPageChromeInert(true);
826        }
827        var mcW = overlayNode && overlayNode.querySelector('#mc-white');
828        if (mcW && typeof gsap !== 'undefined') {
829          gsap.set(mcW, { opacity: 0 });
830        }
831        return raceTimeout(opts.readyPromise || Promise.resolve(), window.homeIntro.CONFIG.readyTimeoutMs)
832          .then(function () {
833            var ms = window.homeIntro.CONFIG.reducedMotionFadeMs || 300;
834            if (overlayNode && typeof gsap !== 'undefined') {
835              return new Promise(function (resolve) {
836                gsap.to(overlayNode, {
837                  autoAlpha: 0,
838                  duration: ms / 1000,
839                  onComplete: function () {
840                    cleanupIntro();
841                    resolve();
842                  },
843                });
844              });
845            }
846            cleanupIntro();
847          });
848      }
849
850      if (opts.replay && overlayNode) {
851        cleanupIntro();
852      }
853
854      return runFullIntro(opts);
855    },
856  };
857
858  parseIntroQueryString();
859  maybeShowDebugPanel();
860})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.