
(function () {
'use strict';

var BP_MOBILE = 768;
var BP_TABLET = 1025;
var HOLD = 200;          
var SVG_NS = 'http://www.w3.org/2000/svg';

var FX_VALID = ['noise', 'ripple', 'liquid', 'shatter', 'static', 'melt',
                'focus', 'tumble', 'tunnel', 'wave', 'bars', 'cards',
                'pop', 'fly', 'rise', 'converge'];

var FX = {
    noise:   { kind: 'filter', type: 'fractalNoise', freq: 0.022, disp: 430, blur: 0,  flow: 0 },
    ripple:  { kind: 'filter', type: 'fractalNoise', freq: 0.009, disp: 320, blur: 0,  flow: 7 },
    liquid:  { kind: 'filter', type: 'fractalNoise', freq: 0.006, disp: 480, blur: 6,  flow: 11 },
    shatter: { kind: 'filter', type: 'turbulence',   freq: 0.045, disp: 540, blur: 0,  flow: 0 },
    static:  { kind: 'filter', type: 'fractalNoise', freq: 0.65,  disp: 150, blur: 0,  flow: 0 },
    melt:    { kind: 'filter', type: 'fractalNoise', freq: 0.013, disp: 360, blur: 5,  flow: 0 },
    focus:   { kind: 'filter', type: 'fractalNoise', freq: 0.02,  disp: 0,   blur: 48, flow: 0 },
    tumble:  { kind: 'xform' },
    tunnel:  { kind: 'xform' },
    wave:    { kind: 'blocks' },
    bars:    { kind: 'blocks' },
    cards:   { kind: 'blocks' },

    
    pop:      { kind: 'cells' },
    fly:      { kind: 'cells' },
    rise:     { kind: 'cells' },
    converge: { kind: 'cells' }
};

function clamp(v, a, b) { return v < a ? a : (v > b ? b : v); }
function easeOutCubic(t) { return 1 - Math.pow(1 - t, 3); }
var EASES = {
    glide:  function (t) { return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; },
    snap:   easeOutCubic,
    spring: function (t) { var c1 = 0.7, c3 = c1 + 1; return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2); }
};
function now() { return (window.performance && performance.now) ? performance.now() : Date.now(); }
function vpH() { return window.innerHeight || document.documentElement.clientHeight || 1; }

var filterSeq = 0;
function buildFilter(spec) {
    var id = 'impulse-ovfx-f' + (filterSeq++);
    var svg = document.createElementNS(SVG_NS, 'svg');
    svg.setAttribute('data-ovfx-svg', '1');
    svg.setAttribute('width', '0');
    svg.setAttribute('height', '0');
    svg.style.cssText = 'position:absolute;width:0;height:0;overflow:visible;pointer-events:none';
    var flow = spec.flow > 0
        ? '<feOffset in="turb" result="turb" dx="0" dy="0">' +
            '<animate attributeName="dx" values="0;26;0;-26;0" dur="' + spec.flow + 's" repeatCount="indefinite" calcMode="linear"/>' +
            '<animate attributeName="dy" values="-26;0;26;0;-26" dur="' + spec.flow + 's" repeatCount="indefinite" calcMode="linear"/>' +
          '</feOffset>'
        : '';
    svg.innerHTML =
        '<filter id="' + id + '" x="-50%" y="-50%" width="200%" height="200%">' +
          '<feTurbulence type="' + spec.type + '" baseFrequency="' + spec.freq + '" ' +
            'numOctaves="2" seed="6" stitchTiles="stitch" result="turb"/>' +
          flow +
          '<feGaussianBlur in="SourceGraphic" stdDeviation="0" result="src"/>' +
          '<feDisplacementMap in="src" in2="turb" scale="0" ' +
            'xChannelSelector="R" yChannelSelector="G"/>' +
        '</filter>';
    return {
        id: id,
        svg: svg,
        disp: svg.querySelector('feDisplacementMap'),
        blur: svg.querySelector('feGaussianBlur'),
        turb: svg.querySelector('feTurbulence')
    };
}

function parseColor(c) {
    c = String(c || '').trim();
    if (c.charAt(0) === '#') {
        if (c.length === 4) c = '#' + c[1] + c[1] + c[2] + c[2] + c[3] + c[3];
        return [parseInt(c.substr(1, 2), 16) || 0,
                parseInt(c.substr(3, 2), 16) || 0,
                parseInt(c.substr(5, 2), 16) || 0];
    }
    var m = c.match(/rgba?\(([^)]+)\)/);
    if (m) { var p = m[1].split(','); return [parseFloat(p[0]) || 0, parseFloat(p[1]) || 0, parseFloat(p[2]) || 0]; }
    return [128, 128, 128];
}
function mix(c1, c2, t) {
    var a = parseColor(c1), b = parseColor(c2);
    return 'rgb(' + Math.round(a[0] + (b[0] - a[0]) * t) + ',' +
                    Math.round(a[1] + (b[1] - a[1]) * t) + ',' +
                    Math.round(a[2] + (b[2] - a[2]) * t) + ')';
}
function wedgePolygon(a0, a1) {
    var pts = ['50% 50%'];
    var steps = Math.max(2, Math.ceil((a1 - a0) / 12));
    for (var i = 0; i <= steps; i++) {
        var ang = (a0 + (a1 - a0) * i / steps) * Math.PI / 180;
        pts.push((50 + Math.sin(ang) * 150).toFixed(1) + '% ' + (50 - Math.cos(ang) * 150).toFixed(1) + '%');
    }
    return 'polygon(' + pts.join(',') + ')';
}

var PIECE_RECIPES = {
    
    zipper: function (cfg, w, h) {
        var bands = clamp(Math.round(cfg.p1) || 8, 2, 24);
        var rad = clamp(cfg.p2 || 0, 0, 90) * Math.PI / 180;
        var px = -Math.sin(rad), py = Math.cos(rad);
        var ext = Math.abs(w * px) + Math.abs(h * py);
        var thick = ext / bands, len = Math.sqrt(w * w + h * h) * 1.6;
        var cx = w / 2, cy = h / 2, seam = (bands - 1) / 2, out = [];
        for (var k = 0; k < bands; k++) {
            var off = -ext / 2 + (k + 0.5) * thick, side = off >= 0 ? 1 : -1;
            out.push({
                bg: mix(cfg.c1, cfg.c2, bands > 1 ? k / (bands - 1) : 0),
                left: cx + px * off - len / 2, top: cy + py * off - thick / 2,
                width: len, height: thick + 2, br: clamp(cfg.p2 || 0, 0, 90),
                ex: px * side * ext * 1.3, ey: py * side * ext * 1.3,
                ord: seam > 0 ? (seam - Math.abs(k - seam)) / seam * (bands - 1) : 0
            });
        }
        return out;
    },
    
    blinds: function (cfg, w, h) {
        var slats = clamp(Math.round(cfg.p1) || 12, 3, 30);
        var rad = clamp(cfg.p2 || 0, 0, 90) * Math.PI / 180;
        var px = -Math.sin(rad), py = Math.cos(rad);
        var ext = Math.abs(w * px) + Math.abs(h * py);
        var thick = ext / slats, len = Math.sqrt(w * w + h * h) * 1.6;
        var cx = w / 2, cy = h / 2, out = [];
        for (var k = 0; k < slats; k++) {
            var off = -ext / 2 + (k + 0.5) * thick;
            out.push({
                bg: mix(cfg.c1, cfg.c2, slats > 1 ? k / (slats - 1) : 0),
                left: cx + px * off - len / 2, top: cy + py * off - thick / 2,
                width: len, height: thick + 2, br: clamp(cfg.p2 || 0, 0, 90),
                rx: 90, es: 0, ord: k
            });
        }
        return out;
    },
    
    crosscut: function (cfg, w, h) {
        var cols = clamp(Math.round(cfg.p1) || 6, 2, 16);
        var drift = clamp(cfg.p2 || 0, 0, 100) / 100;
        var rows = Math.max(2, Math.round(cols * h / Math.max(w, 1)));
        var cw = w / cols, ch = h / rows, maxIdx = cols + rows - 2, out = [];
        for (var r = 0; r < rows; r++) for (var c = 0; c < cols; c++) {
            var parity = (r + c) % 2;
            out.push({
                bg: mix(cfg.c1, cfg.c2, maxIdx > 0 ? (r + c) / maxIdx : 0),
                left: c * cw - 1, top: r * ch - 1, width: cw + 2, height: ch + 2,
                ey: (parity ? 1 : -1) * h * 1.4, ex: (parity ? 1 : -1) * w * drift * 0.5,
                ord: r + c
            });
        }
        return out;
    },
    
    aperture: function (cfg, w, h) {
        var blades = clamp(Math.round(cfg.p1) || 8, 4, 16);
        var twist = clamp(cfg.p2 || 0, 0, 100) / 100;
        var span = 360 / blades, out = [];
        for (var k = 0; k < blades; k++) {
            var mid = (k + 0.5) * span * Math.PI / 180;
            out.push({
                bg: mix(cfg.c1, cfg.c2, blades > 1 ? k / (blades - 1) : 0),
                clip: wedgePolygon(k * span - 2, (k + 1) * span + 2),
                ox: (50 + Math.sin(mid) * 52).toFixed(1) + '%',
                oy: (50 - Math.cos(mid) * 52).toFixed(1) + '%',
                rz: -(96 + twist * 60), es: 0, ord: k
            });
        }
        return out;
    },
    
    pinwheel: function (cfg, w, h) {
        var blades = clamp(Math.round(cfg.p1) || 8, 3, 16);
        var spin = clamp(cfg.p2 || 0, 0, 100) / 100;
        var span = 360 / blades, out = [];
        for (var k = 0; k < blades; k++) {
            out.push({
                bg: mix(cfg.c1, cfg.c2, blades > 1 ? k / (blades - 1) : 0),
                clip: wedgePolygon(k * span - 1, (k + 1) * span + 1),
                ox: '50%', oy: '50%', rz: -(120 + spin * 600), es: 0, ord: k
            });
        }
        return out;
    },
    
    diamonds: function (cfg, w, h) {
        var g = clamp(Math.round(cfg.p1) || 6, 2, 14);
        var spin = clamp(cfg.p2 || 0, 0, 100) / 100;
        var rows = Math.max(2, Math.round(g * h / Math.max(w, 1)));
        var cw = w / g, ch = h / rows, dia = (cw + ch) * 1.05;
        var total = g * rows, idx = 0, out = [];
        for (var r = 0; r < rows; r++) for (var c = 0; c < g; c++) {
            var ccx = (c + 0.5) * cw, ccy = (r + 0.5) * ch;
            out.push({
                bg: mix(cfg.c1, cfg.c2, total > 1 ? idx / (total - 1) : 0),
                clip: 'polygon(50% 0, 100% 50%, 50% 100%, 0 50%)',
                left: ccx - dia / 2, top: ccy - dia / 2, width: dia, height: dia,
                rz: (idx % 2 ? 1 : -1) * (60 + spin * 240), es: 0, ord: r + c
            });
            idx++;
        }
        return out;
    }
};

var instances = [];
var rafPending = false;
var animRunning = false;

function pickFx(cfg) {
    var fx;
    if (cfg.editor) {
        fx = cfg.fx;
    } else {
        var w = window.innerWidth;
        if (w < BP_MOBILE)      fx = (cfg.fxM != null ? cfg.fxM : cfg.fx);
        else if (w < BP_TABLET) fx = (cfg.fxT != null ? cfg.fxT : cfg.fx);
        else                    fx = cfg.fx;
    }
    return FX_VALID.indexOf(fx) !== -1 ? fx : '';
}

function collectBlocks(section) {
    var cont = section.querySelector(':scope > .impulse-container') ||
               section.querySelector('.impulse-container');
    if (!cont) return [section];
    var kids = [];
    for (var i = 0; i < cont.children.length; i++) {
        var k = cont.children[i];
        if (k.nodeType === 1) kids.push(k);
    }
    return kids.length ? kids : [cont];
}

function outermostCells(root) {

    

    var found = root.querySelectorAll('.impulse-grid-cell, .impulse-rows-cell, .impulse-layout-cell, .impulse-reviews-header, .impulse-reviews-rv, .impulse-reviews-card, .impulse-table-item, .impulse-pricing-card, .impulse-acc-reveal-item, .impulse-acc-spot-item, .impulse-unfold-card, .impulse-acc-tile, .isch-dayhdr, .isch-card, .impulse-contact-form > *:not(input[type="hidden"]):not(.impulse-form-message)');
    var cells = [];
    for (var i = 0; i < found.length; i++) {
        var c = found[i], nested = false, p = c.parentNode;
        while (p && p !== root) {
            if (p.classList && (p.classList.contains('impulse-grid-cell') ||
                                p.classList.contains('impulse-rows-cell') ||
                                p.classList.contains('impulse-layout-cell') ||
                                p.classList.contains('impulse-reviews-rv') ||
                                p.classList.contains('impulse-reviews-card') ||
                                p.classList.contains('impulse-table-item') ||
                                p.classList.contains('impulse-pricing-card') ||
                                p.classList.contains('impulse-acc-reveal-item') ||
                                p.classList.contains('impulse-acc-spot-item') ||
                                p.classList.contains('impulse-unfold-card') ||
                                p.classList.contains('impulse-acc-tile') ||
                                p.classList.contains('isch-card'))) { nested = true; break; }
            p = p.parentNode;
        }
        if (!nested) cells.push(c);
    }
    return cells;
}

function collectUnits(section) {
    var blocks = collectBlocks(section);
    var units = [];
    for (var i = 0; i < blocks.length; i++) {
        var b = blocks[i];
        var cells = outermostCells(b);
        if (cells.length) { for (var j = 0; j < cells.length; j++) units.push(cells[j]); }
        else units.push(b);
    }
    return units.length ? units : [section];
}

function contentTarget(section) {
    return section.querySelector(':scope > .impulse-container') ||
           section.querySelector('.impulse-container') || section;
}

function teardown(inst) {
    if (inst.filter && inst.filter.svg.parentNode) {
        inst.filter.svg.parentNode.removeChild(inst.filter.svg);
    }
    inst.filter = null;
    if (inst.piecesCont && inst.piecesCont.parentNode) {
        inst.piecesCont.parentNode.removeChild(inst.piecesCont);
    }
    inst.piecesCont = null;
    inst.pieceEls = null;
    if (inst.section) {
        inst.section.style.filter = '';
        inst.section.style.transform = '';
        inst.section.style.willChange = '';
        inst.section.style.opacity = '';
    }

    
    if (inst.content && inst.content !== inst.section) {
        inst.content.style.filter = '';
        inst.content.style.transform = '';
        inst.content.style.willChange = '';
        inst.content.style.opacity = '';
    }
    if (inst.blocks) {
        for (var i = 0; i < inst.blocks.length; i++) {
            var b = inst.blocks[i];
            b.style.transform = '';
            b.style.willChange = '';
            b.style.opacity = '';
            b.style.transformStyle = '';
            b.style.backfaceVisibility = '';
        }
    }
}

var CHART_ANIM_SEL = '.impulse-pie-sweep-wrap,.impulse-chart-line-path,.impulse-chart-line-area,.impulse-chart-slice';
function eachChartAnim(chart, fn) {
    var els = chart.querySelectorAll(CHART_ANIM_SEL);
    for (var j = 0; j < els.length; j++) {
        var anims = els[j].getAnimations ? els[j].getAnimations() : [];
        for (var k = 0; k < anims.length; k++) { try { fn(anims[k]); } catch (e) {} }
    }
}
function armChartAnims(sec) {
    if (!sec || !sec.querySelectorAll) return;
    var charts = sec.querySelectorAll('.impulse-chart[data-animate="1"]');
    for (var i = 0; i < charts.length; i++) {
        var chart = charts[i];
        if (chart.classList.contains('impulse-chart-anim-armed')) continue;
        chart.classList.add('impulse-chart-anim-armed');

        
        
        eachChartAnim(chart, function (a) { a.pause(); a.currentTime = 0; });
    }
}
function runChartAnims(sec) {
    if (!sec || !sec.querySelectorAll) return;
    var charts = sec.querySelectorAll('.impulse-chart.impulse-chart-anim-armed');
    for (var i = 0; i < charts.length; i++) {
        
        eachChartAnim(charts[i], function (a) { a.currentTime = 0; a.play(); });
        charts[i].classList.remove('impulse-chart-anim-armed');
    }
}

function finishReveal(inst) {

    

    
    
    teardown(inst);
}

function prepare(inst) {
    teardown(inst);
    inst.triggered = false;
    inst.done = false;
    var fx = pickFx(inst.cfg);
    inst.fx = fx;
    if (!fx) return;
    
    armChartAnims(inst.section);
    var spec = FX[fx];
    inst.spec = spec;
    inst.duration = clamp(2200 - (inst.cfg.speed || 5) * 200, 300, 2200);

    inst.content = contentTarget(inst.section);

    if (spec.kind === 'filter') {
        var p2 = clamp(inst.cfg.p2 || 0, 0, 100) / 100;
        var fspec = {
            type: spec.type,
            freq: (spec.freq * (0.45 + p2 * 1.7)).toFixed(4),
            flow: spec.flow
        };
        inst.filter = buildFilter(fspec);
        inst.content.parentNode.insertBefore(inst.filter.svg, inst.content);
        inst.content.style.filter = 'url(#' + inst.filter.id + ')';
        inst.maxDisp = (clamp(inst.cfg.p1 || 0, 0, 100) / 100) * spec.disp;
        inst.maxBlur = spec.blur * (spec.disp ? 1 : (clamp(inst.cfg.p1 || 0, 0, 100) / 100));
        inst.depth  = (clamp(inst.cfg.p3 || 0, 0, 100) / 100) * 600;
    } else if (spec.kind === 'blocks' || spec.kind === 'cells' || spec.kind === 'xform') {

        

        
        
        var units = collectUnits(inst.section);
        inst.blocks = units;
        var sr = inst.section.getBoundingClientRect();
        var scx = sr.left + sr.width / 2, scy = sr.top + sr.height / 2;
        var radial = (fx === 'converge' || fx === 'tunnel'), metric = [];
        for (var ce = 0; ce < units.length; ce++) {
            var cl = units[ce], cr = cl.getBoundingClientRect();
            var mcx = cr.left + cr.width / 2, mcy = cr.top + cr.height / 2;
            cl._ox = mcx - scx; cl._oy = mcy - scy;       
            metric.push(radial ? Math.sqrt(cl._ox * cl._ox + cl._oy * cl._oy)
                               : (mcx - sr.left) + (mcy - sr.top));
            cl.style.willChange = 'transform, opacity';
            cl.style.transformStyle = 'preserve-3d';
            cl.style.backfaceVisibility = 'hidden';
        }
        var cmn = Math.min.apply(null, metric), cmx = Math.max.apply(null, metric), crg = (cmx - cmn) || 1;
        for (var cn = 0; cn < units.length; cn++) units[cn]._stag = (metric[cn] - cmn) / crg;

        

        
        for (var ovi = 0; ovi < units.length; ovi++) {
            var _u = units[ovi], _n = _u, _ord = null, _dly = 0, _off = false;
            while (_n && _n.dataset) {
                if (_ord === null && _n.dataset.revealOrder != null && _n.dataset.revealOrder !== '') _ord = parseFloat(_n.dataset.revealOrder);
                if (!_dly && _n.dataset.revealDelay) _dly = parseFloat(_n.dataset.revealDelay) || 0;
                if (_n.dataset.revealOff === '1') _off = true;
                if (_n === inst.section) break;
                _n = _n.parentElement;
            }
            _u._revealDelayMs = _dly;
            _u._revealOff = _off;
            if (_ord !== null && !isNaN(_ord)) _u._stag = Math.max(0, Math.min(1, _ord / 10));
        }
        var _kept = units.filter(function (u) { return !u._revealOff; });
        if (_kept.length && _kept.length !== units.length) { units = _kept; inst.blocks = units; }
    } else if (spec.kind === 'pieces') {
        var pr = inst.section.getBoundingClientRect();
        var cont = document.createElement('div');
        cont.setAttribute('data-ovfx-pieces', '1');
        cont.style.cssText = 'position:absolute;inset:0;z-index:8;pointer-events:none;overflow:hidden;perspective:1200px';
        var list = (PIECE_RECIPES[fx] || PIECE_RECIPES.zipper)(inst.cfg, pr.width, pr.height);
        var omin = Infinity, omax = -Infinity, j;
        for (j = 0; j < list.length; j++) {
            var ov = (list[j].ord != null) ? list[j].ord : j;
            if (ov < omin) omin = ov;
            if (ov > omax) omax = ov;
        }
        var orange = (omax - omin) || 1;
        var els = [];
        for (j = 0; j < list.length; j++) {
            var pd = list[j];
            var d = document.createElement('div');
            d.style.position = 'absolute';
            d.style.background = pd.bg;
            d.style.backfaceVisibility = 'hidden';
            if (pd.clip) { d.style.clipPath = pd.clip; d.style.webkitClipPath = pd.clip; }
            if (pd.width != null) {
                d.style.left = pd.left + 'px'; d.style.top = pd.top + 'px';
                d.style.width = pd.width + 'px'; d.style.height = pd.height + 'px';
            } else {
                d.style.left = '0'; d.style.top = '0'; d.style.right = '0'; d.style.bottom = '0';
            }
            d.style.transformOrigin = (pd.ox || '50%') + ' ' + (pd.oy || '50%');
            d._d = pd;
            d._ord = (((pd.ord != null) ? pd.ord : j) - omin) / orange * (list.length - 1);
            cont.appendChild(d);
            els.push(d);
        }
        inst.section.appendChild(cont);
        inst.piecesCont = cont;
        inst.pieceEls = els;
        inst.n = list.length;
    }

    

    
    render(inst, 0);
}

function render(inst, lin) {
    var fx = inst.fx, c = inst.cfg;
    var ease = EASES[c.ease] || EASES.spring;
    var p1 = clamp(c.p1 || 0, 0, 100) / 100;
    var p2 = clamp(c.p2 || 0, 0, 100) / 100;
    var p3 = clamp(c.p3 || 0, 0, 100) / 100;

    if (inst.spec.kind === 'pieces') {
        var els = inst.pieceEls, np = inst.n;
        var pstag = p3 * 0.85, pspan = 1 - pstag;
        if (pspan < 0.06) pspan = 0.06;
        for (var pi = 0; pi < els.length; pi++) {
            var pel = els[pi], pd = pel._d;
            var pdelay = np > 1 ? pstag * (pel._ord / (np - 1)) : 0;
            var pp = ease(clamp((lin - pdelay) / pspan, 0, 1));
            pel.style.transform =
                'translate(' + ((pd.ex || 0) * pp).toFixed(1) + 'px,' + ((pd.ey || 0) * pp).toFixed(1) + 'px) ' +
                'rotate(' + ((pd.br || 0) + (pd.rz || 0) * pp).toFixed(2) + 'deg) ' +
                'rotateX(' + ((pd.rx || 0) * pp).toFixed(2) + 'deg) ' +
                'rotateY(' + ((pd.ry || 0) * pp).toFixed(2) + 'deg) ' +
                'scale(' + (1 + ((pd.es != null ? pd.es : 1) - 1) * pp).toFixed(3) + ')';
        }
        return;
    }

    if (inst.spec.kind === 'filter') {
        var pf = ease(lin), df = 1 - pf;
        var dDisp = clamp(df, 0, 1);      
        if (inst.maxDisp) inst.filter.disp.setAttribute('scale', (inst.maxDisp * dDisp).toFixed(1));
        if (inst.maxBlur) inst.filter.blur.setAttribute('stdDeviation', (inst.maxBlur * dDisp).toFixed(2));
        
        var dz = inst.depth * df;
        var rx = (fx === 'melt' ? 0 : 14 * p3) * df;
        var ty = (fx === 'melt' ? inst.depth * 0.35 : 0) * df;
        inst.content.style.transform =
            'perspective(1500px) translate3d(0,' + ty.toFixed(1) + 'px,' + (-dz).toFixed(1) + 'px) ' +
            'rotateX(' + rx.toFixed(2) + 'deg)';
        inst.content.style.opacity = (fx === 'static') ? clamp(0.25 + 0.75 * pf, 0, 1).toFixed(3) : '';
        return;
    }


    
    
    var units = inst.blocks, n = units.length;
    var cellFamily = (fx === 'pop' || fx === 'fly' || fx === 'rise' || fx === 'converge');
    var stag = cellFamily ? (0.12 + p3 * 0.62) : (0.2 + p3 * 0.58);
    var span = 1 - stag;
    if (span < 0.06) span = 0.06;
    for (var i = 0; i < n; i++) {
        var u = units[i];
        var ph = (u._stag != null) ? u._stag : (n > 1 ? i / (n - 1) : 0);
        var _dph = (u._revealDelayMs && inst.duration) ? (u._revealDelayMs / inst.duration) : 0;
        var bp = ease(clamp((lin - stag * ph - _dph) / span, 0, 1));
        var bd = 1 - bp, alt = (i % 2 ? 1 : -1), t;
        if (fx === 'pop') {
            var st0 = 0.25 - p1 * 0.22;        
            t = 'perspective(1100px) translateZ(' + (-(150 + p2 * 700) * bd).toFixed(1) + 'px) ' +
                'scale(' + Math.max(0, st0 + (1 - st0) * bp).toFixed(3) + ')';
        } else if (fx === 'fly') {
            t = 'perspective(1200px) translate3d(' + (alt * (250 + p1 * 900) * bd).toFixed(1) + 'px,' +
                (120 * bd).toFixed(1) + 'px,' + (-(250 + p2 * 600) * bd).toFixed(1) + 'px) ' +
                'rotateY(' + (alt * 45 * bd).toFixed(1) + 'deg)';
        } else if (fx === 'rise') {
            t = 'perspective(1200px) translate3d(0,' + ((150 + p1 * 350) * bd).toFixed(1) + 'px,' +
                (-(180 + p2 * 500) * bd).toFixed(1) + 'px) rotateX(' + (24 * bd).toFixed(1) + 'deg)';
        } else if (fx === 'converge') {

            var cspin = alt * (40 + p2 * 130);
            t = 'perspective(1200px) translate3d(' + ((u._ox || 0) * (0.6 + p1 * 1.6) * bd).toFixed(1) + 'px,' +
                ((u._oy || 0) * (0.6 + p1 * 1.6) * bd).toFixed(1) + 'px,' + (-(120 + p2 * 220) * bd).toFixed(1) + 'px) ' +
                'rotate(' + (cspin * bd).toFixed(1) + 'deg)';
        } else if (fx === 'wave') {
            var amp = 50 + p1 * 220, fr = 1 + p2 * 5;
            var off = Math.sin(ph * Math.PI * fr) * amp;
            t = 'perspective(1300px) translate3d(0,' + (off * bd).toFixed(1) + 'px,' +
                (-amp * 1.4 * bd).toFixed(1) + 'px) rotateX(' + (55 * bd).toFixed(2) + 'deg)';
        } else if (fx === 'bars') {
            var dist = 200 + p1 * 1400, sb = alt * (0.3 + p2);
            t = 'perspective(1300px) translate3d(' + (sb * 240 * bd).toFixed(1) + 'px,0,' +
                (-dist * bd).toFixed(1) + 'px) rotateY(' + (sb * 40 * bd).toFixed(2) + 'deg)';
        } else if (fx === 'cards') {
            var flip = 80 + p2 * 100;
            t = 'perspective(1200px) translateZ(' + (-120 * bd).toFixed(1) + 'px) ' +
                'rotateX(' + (flip * bd).toFixed(2) + 'deg)';
        } else if (fx === 'tumble') {
            var ang = 20 + p1 * 75, tz = 200 + p2 * 900, tsp = p3 * 60;
            t = 'perspective(1400px) rotateX(' + (ang * bd).toFixed(2) + 'deg) ' +
                'rotateZ(' + (alt * tsp * bd).toFixed(2) + 'deg) ' +
                'translateZ(' + (-tz * bd).toFixed(1) + 'px)';
        } else {  
            var depth = 600 + p1 * 2400, nsp = p3 * 220;
            t = 'perspective(1100px) translate3d(' + ((u._ox || 0) * 0.4 * bd).toFixed(1) + 'px,' +
                ((u._oy || 0) * 0.4 * bd).toFixed(1) + 'px,' + (-depth * bd).toFixed(1) + 'px) ' +
                'rotateZ(' + (alt * nsp * bd).toFixed(2) + 'deg)';
        }
        u.style.transform = t;
        u.style.opacity = clamp(0.06 + 0.94 * bp, 0, 1).toFixed(3);
    }
}

function ensureAnim() {
    if (!animRunning) { animRunning = true; requestAnimationFrame(animateFrame); }
}
function animateFrame(ts) {
    var active = false;
    for (var i = 0; i < instances.length; i++) {
        var inst = instances[i];
        if (!inst.fx || !inst.triggered || inst.done) continue;
        var lin = clamp((ts - inst.t0 - HOLD) / inst.duration, 0, 1);
        render(inst, lin);
        if (lin >= 1) {
            inst.done = true;
            finishReveal(inst);      
            runChartAnims(inst.section);  
        } else {
            active = true;
        }
    }
    if (active) requestAnimationFrame(animateFrame);
    else animRunning = false;
}

function checkTriggers() {
    rafPending = false;
    for (var i = 0; i < instances.length; i++) {
        var inst = instances[i];
        if (!inst.fx) continue;
        var r = inst.section.getBoundingClientRect();
        var vh = vpH();
        if (!inst.triggered) {
            if (r.top < vh * 0.85 && r.bottom > vh * 0.15) {
                inst.triggered = true;
                inst.done = false;
                inst.t0 = now();
                ensureAnim();
            }
        } else if (inst.done && (r.bottom < vh * 0.05 || r.top > vh * 0.95)) {
            inst.triggered = false;
            inst.done = false;
            prepare(inst);           
        }
    }
}
function onScroll() {
    if (!rafPending) { rafPending = true; requestAnimationFrame(checkTriggers); }
}

var resizeTimer;
function onResize() {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(function () {
        for (var i = 0; i < instances.length; i++) {
            var inst = instances[i];
            if (!inst.done) prepare(inst);
        }
        checkTriggers();
    }, 160);
}

function initAll() {
    for (var k = 0; k < instances.length; k++) teardown(instances[k]);
    instances = [];
    var els = document.querySelectorAll('.impulse-overlay-fx');
    for (var i = 0; i < els.length; i++) {
        var c = els[i];
        var raw = c.getAttribute('data-ovfx');
        if (!raw) continue;
        var cfg;
        try { cfg = JSON.parse(raw); } catch (e) { continue; }
        var section = c.parentNode;
        if (!section || section.nodeType !== 1) continue;
        var inst = {
            carrier: c, section: section, cfg: cfg, fx: '', spec: null,
            filter: null, blocks: null, piecesCont: null, pieceEls: null,
            triggered: false, done: false,
            t0: 0, duration: 1200, n: 0, maxDisp: 0, maxBlur: 0, depth: 0
        };
        instances.push(inst);
        prepare(inst);
    }
}

function boot() {
    initAll();
    var anyEditor = false, i;
    for (i = 0; i < instances.length; i++) {
        if (instances[i].cfg && instances[i].cfg.editor) { anyEditor = true; break; }
    }

    

    
    
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onResize);
    if (anyEditor) {

        
        document.addEventListener('scroll', onScroll, { passive: true, capture: true });
    }
    checkTriggers();
}

function play(sectionEl) {
    if (!sectionEl) { playAll(); return; }
    var inst = null, idx = -1, i;
    for (i = 0; i < instances.length; i++) {
        if (instances[i].section === sectionEl) { inst = instances[i]; idx = i; break; }
    }
    var carrier = sectionEl.querySelector(':scope > .impulse-overlay-fx');
    if (!carrier) {                       
        if (inst) { teardown(inst); instances.splice(idx, 1); }
        return;
    }
    var cfg;
    try { cfg = JSON.parse(carrier.getAttribute('data-ovfx')); } catch (e) { return; }
    if (!inst) {
        inst = { carrier: carrier, section: sectionEl, cfg: cfg, fx: '', spec: null,
                 filter: null, blocks: null, piecesCont: null, pieceEls: null,
                 triggered: false, done: false, t0: 0, duration: 1200, n: 0,
                 maxDisp: 0, maxBlur: 0, depth: 0 };
        instances.push(inst);
    } else {
        inst.cfg = cfg;                   
    }
    prepare(inst);                        
    if (inst.fx) { inst.triggered = true; inst.done = false; inst.t0 = now(); ensureAnim(); }
}

function playAll() {
    initAll();
    var any = false;
    for (var i = 0; i < instances.length; i++) {
        var inst = instances[i];
        if (inst.fx) { inst.triggered = true; inst.done = false; inst.t0 = now(); any = true; }
    }
    if (any) ensureAnim();
}

window.ImpulseOverlayFX = { init: initAll, reinit: initAll, play: play };

if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', boot);
} else {
    boot();
}

})();
