
(function () {
  'use strict';

  var SPRING_IN  = 'linear(0, 0.23 8%, 0.74 17%, 1 28%, 1.17 40%, 1.04 50%, 0.95 61%, 1.012 72%, 0.997 84%, 1)';
  var SPRING_OUT = 'cubic-bezier(0.32, 0, 0.6, -0.45)';

  var MOTIONS = {
    
    'zoom-in': {
      initial: function (ix) { return 'transform:scale(0);opacity:0'; },
      kf: function (ix) {
        var ov = 1 + 0.06 * ix; 
        return [
          { transform: 'scale(0)',                 opacity: 0 },
          { transform: 'scale(' + ov.toFixed(2) + ')', opacity: 1, offset: 0.7 },
          { transform: 'scale(1)',                 opacity: 1 }
        ];
      },
      duration: 700,
      easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
    },
    'rise': {
      initial: function (ix) {
        var p = Math.round(125 * ix);
        return 'transform:translateY(' + p + '%);opacity:0';
      },
      kf: function (ix) {
        var p = Math.round(125 * ix);
        return [
          { transform: 'translateY(' + p + '%)', opacity: 0 },
          { transform: 'translateY(0)',          opacity: 1 }
        ];
      },
      duration: 650,
      easing: SPRING_IN
    },
    'drop': {
      initial: function (ix) {
        var p = Math.round(125 * ix);
        return 'transform:translateY(-' + p + '%);opacity:0';
      },
      kf: function (ix) {
        var p = Math.round(125 * ix);
        return [
          { transform: 'translateY(-' + p + '%)', opacity: 0 },
          { transform: 'translateY(0)',           opacity: 1 }
        ];
      },
      duration: 650,
      easing: SPRING_IN
    },
    'glide-from-l': {
      initial: function (ix) {
        var p = Math.round(125 * ix);
        return 'transform:translateX(-' + p + '%);opacity:0';
      },
      kf: function (ix) {
        var p = Math.round(125 * ix);
        return [
          { transform: 'translateX(-' + p + '%)', opacity: 0 },
          { transform: 'translateX(0)',           opacity: 1 }
        ];
      },
      duration: 650,
      easing: SPRING_IN
    },
    'glide-from-r': {
      initial: function (ix) {
        var p = Math.round(125 * ix);
        return 'transform:translateX(' + p + '%);opacity:0';
      },
      kf: function (ix) {
        var p = Math.round(125 * ix);
        return [
          { transform: 'translateX(' + p + '%)', opacity: 0 },
          { transform: 'translateX(0)',          opacity: 1 }
        ];
      },
      duration: 650,
      easing: SPRING_IN
    },
    'fade-in': {
      initial: 'opacity:0',
      kf: [ { opacity: 0 }, { opacity: 1 } ],
      duration: 500,
      easing: 'ease-in-out'
    },
    'blur-in': {
      initial: function (ix) {
        var b = Math.round(20 * ix);
        return 'opacity:0;filter:blur(' + b + 'px)';
      },
      kf: function (ix) {
        var b = Math.round(20 * ix);
        return [
          { opacity: 0, filter: 'blur(' + b + 'px)' },
          { opacity: 1, filter: 'blur(0)' }
        ];
      },
      duration: 700,
      easing: 'ease-out'
    },
    'spacing-in': {
      initial: function (ix) {
        var em = (0.5 * ix).toFixed(2);
        return 'opacity:0;letter-spacing:' + em + 'em';
      },
      kf: function (ix) {
        var em = (0.5 * ix).toFixed(2);
        return [
          { opacity: 0, letterSpacing: em + 'em' },
          { opacity: 1, letterSpacing: '-0.04em', offset: 0.7 },
          { opacity: 1, letterSpacing: '0em'    }
        ];
      },
      duration: 700,
      easing: SPRING_IN
    },

    'bounce-slide-split': {
      initial: function (ix, i, n) {
        var fromLeft = i < Math.ceil(n / 2);
        var p = Math.round(100 * ix);
        var x = fromLeft ? -p : p;
        return 'transform:translateX(' + x + '%);opacity:0';
      },
      kf: function (ix, i, n) {
        var fromLeft = i < Math.ceil(n / 2);
        var p = Math.round(100 * ix);
        var x = fromLeft ? -p : p;
        return [
          { transform: 'translateX(' + x + '%)', opacity: 0 },
          { transform: 'translateX(0)',           opacity: 1 }
        ];
      },
      duration: 700,
      easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
    },
    'bounce-slide-l': {
      initial: function (ix) {
        var p = Math.round(100 * ix);
        return 'transform:translateX(-' + p + '%);opacity:0';
      },
      kf: function (ix) {
        var p = Math.round(100 * ix);
        return [
          { transform: 'translateX(-' + p + '%)', opacity: 0 },
          { transform: 'translateX(0)',           opacity: 1 }
        ];
      },
      duration: 700,
      easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
    },
    'bounce-rise': {
      initial: function (ix) {
        var p = Math.round(100 * ix);
        return 'transform:translateY(' + p + '%);opacity:0';
      },
      kf: function (ix) {
        var p = Math.round(100 * ix);
        return [
          { transform: 'translateY(' + p + '%)', opacity: 0 },
          { transform: 'translateY(0)',          opacity: 1 }
        ];
      },
      duration: 750,
      easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
    },

    'letter-kick-in': {
      initial: 'opacity:0;letter-spacing:0.35em',
      kf: function (ix) {
        var em = (0.35 * ix).toFixed(2);
        return [
          { opacity: 0, letterSpacing: em + 'em',  transform: 'translateY(20%)' },
          { opacity: 1, letterSpacing: '-0.05em', transform: 'translateY(0)', offset: 0.55 },
          { opacity: 1, letterSpacing: '0.02em',                              offset: 0.78 },
          { opacity: 1, letterSpacing: '0em' }
        ];
      },
      duration: 700,
      easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
    },

    'scatter-in': {
      
      initial: function (ix, i, n) {
        var r1 = _rand(i * 7 + 1), r2 = _rand(i * 11 + 3), r3 = _rand(i * 13 + 5);
        var angle = r1 * Math.PI * 2;
        var dist  = (60 + r2 * 140) * ix;
        var dx = Math.cos(angle) * dist;
        var dy = Math.sin(angle) * dist;
        var rot = (r3 * 80 - 40) * ix;
        return 'transform:translate(' + dx.toFixed(0) + 'px,' + dy.toFixed(0) + 'px) rotate(' + rot.toFixed(1) + 'deg) scale(0.35);opacity:0';
      },
      kf: function (ix, i, n) {
        var r1 = _rand(i * 7 + 1), r2 = _rand(i * 11 + 3), r3 = _rand(i * 13 + 5);
        var angle = r1 * Math.PI * 2;
        var dist  = (60 + r2 * 140) * ix;
        var dx = Math.cos(angle) * dist;
        var dy = Math.sin(angle) * dist;
        var rot = (r3 * 80 - 40) * ix;
        return [
          { transform: 'translate(' + dx.toFixed(0) + 'px,' + dy.toFixed(0) + 'px) rotate(' + rot.toFixed(1) + 'deg) scale(0.35)', opacity: 0 },
          { transform: 'translate(0,0) rotate(0deg) scale(1)', opacity: 1 }
        ];
      },
      duration: 900,
      easing: SPRING_IN
    },
    'shake-in': {
      
      initial: 'opacity:0',
      kf: function (ix) {
        var a = 9 * ix;
        return [
          { transform: 'translate(0,0)',                                                                    opacity: 0 },
          { transform: 'translate(' + a.toFixed(0) + 'px,-' + (a*0.7).toFixed(0) + 'px)',                   opacity: 0.5, offset: 0.18 },
          { transform: 'translate(-' + (a*0.8).toFixed(0) + 'px,' + (a*0.5).toFixed(0) + 'px)',             opacity: 0.8, offset: 0.42 },
          { transform: 'translate(' + (a*0.5).toFixed(0) + 'px,' + (a*0.3).toFixed(0) + 'px)',              opacity: 1,   offset: 0.65 },
          { transform: 'translate(-' + (a*0.2).toFixed(0) + 'px,-' + (a*0.15).toFixed(0) + 'px)',           opacity: 1,   offset: 0.85 },
          { transform: 'translate(0,0)',                                                                    opacity: 1 }
        ];
      },
      duration: 700,
      easing: 'cubic-bezier(0.34, 1.2, 0.64, 1)'
    },
    'noise-flicker': {
      
      initial: 'opacity:0',
      kf: function (ix) {
        var lo = 0.05;
        var hi = Math.min(1, 0.55 * ix);
        return [
          { opacity: 0 },
          { opacity: hi,         offset: 0.08 },
          { opacity: lo,         offset: 0.16 },
          { opacity: hi * 1.4,   offset: 0.24 },
          { opacity: lo * 2,     offset: 0.36 },
          { opacity: 0.75,       offset: 0.48 },
          { opacity: 0.15,       offset: 0.58 },
          { opacity: 0.92,       offset: 0.72 },
          { opacity: 0.35,       offset: 0.82 },
          { opacity: 1 }
        ];
      },
      duration: 850,
      easing: 'steps(18, end)'
    },

    'flip-up-in': {
      initial: 'opacity:0;transform-origin:50% 100%;transform:rotateX(-90deg)',
      kf: [ { transform: 'rotateX(-90deg)', opacity: 0 }, { transform: 'rotateX(0deg)', opacity: 1 } ],
      duration: 1100, easing: SPRING_IN
    },
    'flip-down-in': {
      initial: 'opacity:0;transform-origin:50% 0%;transform:rotateX(90deg)',
      kf: [ { transform: 'rotateX(90deg)', opacity: 0 }, { transform: 'rotateX(0deg)', opacity: 1 } ],
      duration: 1100, easing: SPRING_IN
    },
    'spin-in': {
      initial: 'opacity:0;transform-origin:50% 50%;transform:rotateY(-105deg)',
      kf: [ { transform: 'rotateY(-105deg)', opacity: 0 }, { transform: 'rotateY(0deg)', opacity: 1 } ],
      duration: 1300, easing: SPRING_IN
    },
    'swing-in': {
      initial: 'opacity:0;transform-origin:0% 50%;transform:rotateY(78deg)',
      kf: [ { transform: 'rotateY(78deg)', opacity: 0 },
            { transform: 'rotateY(-14deg)', opacity: 1, offset: 0.62 },
            { transform: 'rotateY(0deg)', opacity: 1 } ],
      duration: 1500, easing: 'cubic-bezier(0.33, 1, 0.68, 1)'
    },
    'unfold-in': {
      initial: 'opacity:0;transform-origin:50% 0%;transform:rotateX(88deg) translateY(-6%)',
      kf: [ { transform: 'rotateX(88deg) translateY(-6%)', opacity: 0 },
            { transform: 'rotateX(0deg) translateY(0)', opacity: 1 } ],
      duration: 1200, easing: SPRING_IN
    },
    'curtain-in': {
      initial: 'opacity:0;transform-origin:0% 50%;transform:scaleX(0.02)',
      kf: [ { transform: 'scaleX(0.02)', opacity: 0.35 }, { transform: 'scaleX(1)', opacity: 1 } ],
      duration: 1000, easing: SPRING_IN
    },
    'depth-in': {
      initial: function (ix) { var z = Math.round(700 * ix); return 'opacity:0;transform:translateZ(-' + z + 'px)'; },
      kf: function (ix) { var z = Math.round(700 * ix); return [ { transform: 'translateZ(-' + z + 'px)', opacity: 0 }, { transform: 'translateZ(0)', opacity: 1 } ]; },
      duration: 1200, easing: SPRING_IN
    },
    'depth-fly-in': {
      
      initial: 'opacity:0;transform:translateZ(-5000px);filter:blur(12px)',
      kf: [
        { transform: 'translateZ(-5000px)', opacity: 0, filter: 'blur(12px)' },
        { transform: 'translateZ(-1400px)', opacity: 1, filter: 'blur(3px)', offset: 0.55 },
        { transform: 'translateZ(0px)',      opacity: 1, filter: 'blur(0px)' }
      ],
      duration: 1300, easing: SPRING_IN
    },
    'tumble-in': {
      initial: function (ix) { var d = Math.round(55 * ix); return 'opacity:0;transform:translateY(-' + d + '%) rotateX(-70deg) rotateZ(-16deg)'; },
      kf: function (ix) { var d = Math.round(55 * ix); return [ { transform: 'translateY(-' + d + '%) rotateX(-70deg) rotateZ(-16deg)', opacity: 0 }, { transform: 'translateY(0) rotateX(0deg) rotateZ(0deg)', opacity: 1 } ]; },
      duration: 1300, easing: SPRING_IN
    },
    
    'flip-up-out': {
      initial: 'transform-origin:50% 0%',
      kf: [ { transform: 'rotateX(0deg)', opacity: 1 }, { transform: 'rotateX(90deg)', opacity: 0 } ],
      duration: 520, easing: SPRING_OUT
    },
    'fold-out': {
      initial: 'transform-origin:50% 100%',
      kf: [ { transform: 'rotateX(0deg)', opacity: 1 }, { transform: 'rotateX(-90deg)', opacity: 0 } ],
      duration: 520, easing: SPRING_OUT
    },
    'spin-out': {
      initial: 'transform-origin:50% 50%',
      kf: [ { transform: 'rotateY(0deg)', opacity: 1 }, { transform: 'rotateY(105deg)', opacity: 0 } ],
      duration: 560, easing: SPRING_OUT
    },
    'curtain-out': {
      initial: 'transform-origin:100% 50%',
      kf: [ { transform: 'scaleX(1)', opacity: 1 }, { transform: 'scaleX(0.02)', opacity: 0 } ],
      duration: 520, easing: SPRING_OUT
    },
    'depth-out': {
      initial: '',
      kf: function (ix) { var z = Math.round(500 * ix); return [ { transform: 'translateZ(0)', opacity: 1 }, { transform: 'translateZ(' + z + 'px)', opacity: 0 } ]; },
      duration: 560, easing: SPRING_OUT
    },
    'depth-fly-out': {
      
      initial: '',
      kf: [
        { transform: 'translateZ(0px)',     opacity: 1, filter: 'blur(0px)' },
        { transform: 'translateZ(-3000px)', opacity: 0, filter: 'blur(10px)' }
      ],
      duration: 660, easing: SPRING_OUT
    },

    'zoom-out': {
      initial: '',
      kf: [
        { transform: 'scale(1)', opacity: 1 },
        { transform: 'scale(0)', opacity: 0 }
      ],
      duration: 500,
      easing: SPRING_OUT
    },
    'rise-out': {
      initial: '',
      kf: function (ix) {
        var p = Math.round(125 * ix);
        return [
          { transform: 'translateY(0)',           opacity: 1 },
          { transform: 'translateY(-' + p + '%)', opacity: 0 }
        ];
      },
      duration: 550,
      easing: SPRING_OUT
    },
    'drop-out': {
      initial: '',
      kf: function (ix) {
        var p = Math.round(125 * ix);
        return [
          { transform: 'translateY(0)',          opacity: 1 },
          { transform: 'translateY(' + p + '%)', opacity: 0 }
        ];
      },
      duration: 550,
      easing: SPRING_OUT
    },
    'glide-to-l': {
      initial: '',
      kf: function (ix) {
        var p = Math.round(125 * ix);
        return [
          { transform: 'translateX(0)',           opacity: 1 },
          { transform: 'translateX(-' + p + '%)', opacity: 0 }
        ];
      },
      duration: 550,
      easing: SPRING_OUT
    },
    'glide-to-r': {
      initial: '',
      kf: function (ix) {
        var p = Math.round(125 * ix);
        return [
          { transform: 'translateX(0)',          opacity: 1 },
          { transform: 'translateX(' + p + '%)', opacity: 0 }
        ];
      },
      duration: 550,
      easing: SPRING_OUT
    },
    'fade-out': {
      initial: '',
      kf: [ { opacity: 1 }, { opacity: 0 } ],
      duration: 500,
      easing: 'ease-in-out'
    },
    'blur-out': {
      initial: '',
      kf: function (ix) {
        var b = Math.round(20 * ix);
        return [
          { opacity: 1, filter: 'blur(0)' },
          { opacity: 0, filter: 'blur(' + b + 'px)' }
        ];
      },
      duration: 550,
      easing: 'ease-in'
    },
    'spacing-out': {
      initial: '',
      kf: function (ix) {
        var em = (0.6 * ix).toFixed(2);
        return [
          { opacity: 1, letterSpacing: '0em'   },
          { opacity: 0, letterSpacing: em + 'em' }
        ];
      },
      duration: 550,
      easing: SPRING_OUT
    },
    'scatter-out': {
      initial: '',
      kf: function (ix, i, n) {
        var r1 = _rand(i * 17 + 2), r2 = _rand(i * 19 + 4), r3 = _rand(i * 23 + 6);
        var angle = r1 * Math.PI * 2;
        var dist  = (80 + r2 * 160) * ix;
        var dx = Math.cos(angle) * dist;
        var dy = Math.sin(angle) * dist;
        var rot = (r3 * 100 - 50) * ix;
        return [
          { transform: 'translate(0,0) rotate(0deg) scale(1)', opacity: 1 },
          { transform: 'translate(' + dx.toFixed(0) + 'px,' + dy.toFixed(0) + 'px) rotate(' + rot.toFixed(1) + 'deg) scale(0.4)', opacity: 0 }
        ];
      },
      duration: 600,
      easing: SPRING_OUT
    },

    'circle-reveal': {
      initial: 'opacity:0;clip-path:circle(0% at 50% 50%);-webkit-clip-path:circle(0% at 50% 50%)',
      kf: function (ix) {
        var to = Math.round(75 * ix); 
        return [
          { opacity: 0, clipPath: 'circle(0% at 50% 50%)',  webkitClipPath: 'circle(0% at 50% 50%)'  },
          { opacity: 1, clipPath: 'circle(' + to + '% at 50% 50%)', webkitClipPath: 'circle(' + to + '% at 50% 50%)' }
        ];
      },
      duration: 700,
      easing: SPRING_IN
    },
    'circle-close': {
      initial: '',
      kf: [
        { opacity: 1, clipPath: 'circle(75% at 50% 50%)', webkitClipPath: 'circle(75% at 50% 50%)' },
        { opacity: 0, clipPath: 'circle(0% at 50% 50%)',  webkitClipPath: 'circle(0% at 50% 50%)'  }
      ],
      duration: 500,
      easing: SPRING_OUT
    },
    'wipe-right': {
      initial: 'opacity:0;clip-path:inset(0 100% 0 0);-webkit-clip-path:inset(0 100% 0 0)',
      kf: [
        { opacity: 0, clipPath: 'inset(0 100% 0 0)', webkitClipPath: 'inset(0 100% 0 0)' },
        { opacity: 1, clipPath: 'inset(0 0% 0 0)',   webkitClipPath: 'inset(0 0% 0 0)' }
      ],
      duration: 700,
      easing: SPRING_IN
    },
    'wipe-left': {
      initial: 'opacity:0;clip-path:inset(0 0 0 100%);-webkit-clip-path:inset(0 0 0 100%)',
      kf: [
        { opacity: 0, clipPath: 'inset(0 0 0 100%)', webkitClipPath: 'inset(0 0 0 100%)' },
        { opacity: 1, clipPath: 'inset(0 0 0 0%)',   webkitClipPath: 'inset(0 0 0 0%)' }
      ],
      duration: 700,
      easing: SPRING_IN
    },
    'wipe-right-out': {
      initial: '',
      kf: [
        { opacity: 1, clipPath: 'inset(0 0 0 0%)',   webkitClipPath: 'inset(0 0 0 0%)' },
        { opacity: 0, clipPath: 'inset(0 0 0 100%)', webkitClipPath: 'inset(0 0 0 100%)' }
      ],
      duration: 550,
      easing: SPRING_OUT
    },
    'slit-open': {
      
      initial: 'opacity:0;clip-path:inset(50% 0 50% 0);-webkit-clip-path:inset(50% 0 50% 0)',
      kf: [
        { opacity: 0, clipPath: 'inset(50% 0 50% 0)', webkitClipPath: 'inset(50% 0 50% 0)' },
        { opacity: 1, clipPath: 'inset(0 0 0 0)',     webkitClipPath: 'inset(0 0 0 0)' }
      ],
      duration: 800,
      easing: SPRING_IN
    },
    'slit-close': {
      initial: '',
      kf: [
        { opacity: 1, clipPath: 'inset(0 0 0 0)',     webkitClipPath: 'inset(0 0 0 0)' },
        { opacity: 0, clipPath: 'inset(50% 0 50% 0)', webkitClipPath: 'inset(50% 0 50% 0)' }
      ],
      duration: 550,
      easing: SPRING_OUT
    },

    'weight-morph-in': {
      initial: 'opacity:0;font-variation-settings:"wght" 120;font-weight:200',
      kf: [
        { opacity: 0, fontVariationSettings: '"wght" 120', fontWeight: '200' },
        { opacity: 1, fontVariationSettings: '"wght" 800', fontWeight: '800' }
      ],
      duration: 820,
      easing: SPRING_IN
    },
    'weight-morph-out': {
      initial: '',
      kf: [
        { opacity: 1, fontVariationSettings: '"wght" 800', fontWeight: '800' },
        { opacity: 0, fontVariationSettings: '"wght" 120', fontWeight: '200' }
      ],
      duration: 520,
      easing: SPRING_OUT
    },

    'box-in': {
      initial: 'opacity:0;clip-path:inset(50% 50% 50% 50%);-webkit-clip-path:inset(50% 50% 50% 50%)',
      kf: [
        { opacity: 0, clipPath: 'inset(50% 50% 50% 50%)', webkitClipPath: 'inset(50% 50% 50% 50%)' },
        { opacity: 1, clipPath: 'inset(0 0 0 0)',          webkitClipPath: 'inset(0 0 0 0)' }
      ],
      duration: 720,
      easing: SPRING_IN
    },
    'box-out': {
      initial: '',
      kf: [
        { opacity: 1, clipPath: 'inset(0 0 0 0)',          webkitClipPath: 'inset(0 0 0 0)' },
        { opacity: 0, clipPath: 'inset(50% 50% 50% 50%)', webkitClipPath: 'inset(50% 50% 50% 50%)' }
      ],
      duration: 520,
      easing: SPRING_OUT
    },
    'wipe-up': {
      initial: 'opacity:0;clip-path:inset(100% 0 0 0);-webkit-clip-path:inset(100% 0 0 0)',
      kf: [
        { opacity: 0, clipPath: 'inset(100% 0 0 0)', webkitClipPath: 'inset(100% 0 0 0)' },
        { opacity: 1, clipPath: 'inset(0 0 0 0)',    webkitClipPath: 'inset(0 0 0 0)' }
      ],
      duration: 700,
      easing: SPRING_IN
    },
    'wipe-down': {
      initial: 'opacity:0;clip-path:inset(0 0 100% 0);-webkit-clip-path:inset(0 0 100% 0)',
      kf: [
        { opacity: 0, clipPath: 'inset(0 0 100% 0)', webkitClipPath: 'inset(0 0 100% 0)' },
        { opacity: 1, clipPath: 'inset(0 0 0 0)',    webkitClipPath: 'inset(0 0 0 0)' }
      ],
      duration: 700,
      easing: SPRING_IN
    },

    'skew-in': {
      initial: function (ix) { var s = Math.round(26 * ix), x = Math.round(10 * ix); return 'opacity:0;transform:skewX(' + s + 'deg) translateX(-' + x + '%)'; },
      kf: function (ix) { var s = Math.round(26 * ix), x = Math.round(10 * ix); return [
        { opacity: 0, transform: 'skewX(' + s + 'deg) translateX(-' + x + '%)' },
        { opacity: 1, transform: 'skewX(0deg) translateX(0)' }
      ]; },
      duration: 680,
      easing: SPRING_IN
    },
    'skew-out': {
      initial: '',
      kf: function (ix) { var s = Math.round(22 * ix), x = Math.round(10 * ix); return [
        { opacity: 1, transform: 'skewX(0deg) translateX(0)' },
        { opacity: 0, transform: 'skewX(-' + s + 'deg) translateX(' + x + '%)' }
      ]; },
      duration: 520,
      easing: SPRING_OUT
    },

    'glitch-in': {
      initial: 'opacity:0',
      kf: function (ix) {
        var ox = Math.round(5 * ix);
        var jx = Math.round(8 * ix);
        return [
          { opacity: 0, transform: 'translate(' + jx + 'px,0)', textShadow: '-' + ox + 'px 0 0 #f0f,' + ox + 'px 0 0 #0ff' },
          { opacity: 0.6, transform: 'translate(-' + Math.round(jx*0.8) + 'px,2px)', textShadow: '-' + Math.round(ox*0.7) + 'px 0 0 #f0f,' + Math.round(ox*0.7) + 'px 0 0 #0ff', offset: 0.20 },
          { opacity: 0.4, transform: 'translate(' + Math.round(jx*0.5) + 'px,-1px)', textShadow: '-' + Math.round(ox*1.2) + 'px 0 0 #f0f,' + Math.round(ox*1.2) + 'px 0 0 #0ff', offset: 0.40 },
          { opacity: 0.85, transform: 'translate(-' + Math.round(jx*0.3) + 'px,1px)', textShadow: '-' + Math.round(ox*0.4) + 'px 0 0 #f0f,' + Math.round(ox*0.4) + 'px 0 0 #0ff', offset: 0.70 },
          { opacity: 1,   transform: 'translate(0,0)',                                 textShadow: 'none' }
        ];
      },
      duration: 650,
      easing: 'steps(24, end)'
    },
    'glitch-out': {
      initial: '',
      kf: function (ix) {
        var ox = Math.round(5 * ix);
        var jx = Math.round(10 * ix);
        return [
          { opacity: 1, transform: 'translate(0,0)', textShadow: 'none' },
          { opacity: 0.6, transform: 'translate(' + Math.round(jx*0.5) + 'px,1px)', textShadow: '-' + Math.round(ox*0.7) + 'px 0 0 #f0f,' + Math.round(ox*0.7) + 'px 0 0 #0ff', offset: 0.40 },
          { opacity: 0.3, transform: 'translate(-' + jx + 'px,-2px)', textShadow: '-' + Math.round(ox*1.5) + 'px 0 0 #f0f,' + Math.round(ox*1.5) + 'px 0 0 #0ff', offset: 0.70 },
          { opacity: 0, transform: 'translate(' + jx + 'px,0)', textShadow: '-' + ox + 'px 0 0 #f0f,' + ox + 'px 0 0 #0ff' }
        ];
      },
      duration: 500,
      easing: 'steps(16, end)'
    },
    'distort-in': {
      
      initial: function (ix) {
        var b = Math.round(12 * ix);
        return 'opacity:0;filter:blur(' + b + 'px) contrast(0.3)';
      },
      kf: function (ix) {
        var b = 12 * ix;
        return [
          { opacity: 0,   filter: 'blur(' + b.toFixed(0) + 'px) contrast(0.3)' },
          { opacity: 0.5, filter: 'blur(' + (b*0.5).toFixed(0) + 'px) contrast(2)',   offset: 0.30 },
          { opacity: 0.3, filter: 'blur(' + (b*0.8).toFixed(0) + 'px) contrast(0.4)', offset: 0.50 },
          { opacity: 0.9, filter: 'blur(2px) contrast(1.5)',                            offset: 0.78 },
          { opacity: 1,   filter: 'blur(0) contrast(1)' }
        ];
      },
      duration: 800,
      easing: 'steps(20, end)'
    },
    'distort-out': {
      initial: '',
      kf: function (ix) {
        var b = 14 * ix;
        return [
          { opacity: 1, filter: 'blur(0) contrast(1)' },
          { opacity: 0.7, filter: 'blur(3px) contrast(1.6)',                            offset: 0.35 },
          { opacity: 0.4, filter: 'blur(' + (b*0.6).toFixed(0) + 'px) contrast(0.4)', offset: 0.60 },
          { opacity: 0,   filter: 'blur(' + b.toFixed(0) + 'px) contrast(0.2)' }
        ];
      },
      duration: 600,
      easing: 'steps(16, end)'
    }
  };

  function _resolve(field, intensity, i, n) {
    return (typeof field === 'function') ? field(intensity, i, n) : field;
  }

  var AUTO_EXIT_PAIRS = {
    'rise':                'rise-out',
    'drop':                'drop-out',
    'glide-from-l':        'glide-to-l',
    'glide-from-r':        'glide-to-r',
    'bounce-slide-l':      'glide-to-l',
    'bounce-slide-split':  'glide-to-r',
    'bounce-rise':         'drop-out',
    'zoom-in':             'zoom-out',
    'fade-in':             'fade-out',
    'blur-in':             'blur-out',
    'spacing-in':          'spacing-out',
    'letter-kick-in':      'spacing-out',
    'scatter-in':          'scatter-out',
    'shake-in':            'fade-out',
    'noise-flicker':       'fade-out',
    'glitch-in':           'glitch-out',
    'distort-in':          'distort-out',
    'circle-reveal':       'circle-close',
    'slit-open':           'slit-close',
    'wipe-right':          'wipe-right-out',
    'wipe-left':           'fade-out',
    
    'flip-up-in':          'flip-up-out',
    'flip-down-in':        'fold-out',
    'spin-in':             'spin-out',
    'swing-in':            'spin-out',
    'unfold-in':           'fold-out',
    'curtain-in':          'curtain-out',
    'depth-in':            'depth-out',
    'depth-fly-in':        'depth-fly-out',
    'tumble-in':           'fade-out',
    
    'weight-morph-in':     'weight-morph-out',
    'box-in':              'box-out',
    'wipe-up':             'fade-out',
    'wipe-down':           'fade-out',
    'skew-in':             'skew-out'
  };

  var AUTO_TARGET = {
    'rise':                'letter',
    'drop':                'letter',
    'glide-from-l':        'word',
    'glide-from-r':        'word',
    'bounce-slide-l':      'word',
    'bounce-slide-split':  'word',
    'bounce-rise':         'letter',
    'zoom-in':             'word',
    'fade-in':             'letter',
    'blur-in':             'whole',
    'spacing-in':          'whole',
    'letter-kick-in':      'letter',
    'scatter-in':          'letter',
    'shake-in':            'letter',
    'noise-flicker':       'letter',
    'glitch-in':           'letter',
    'distort-in':          'word',
    'circle-reveal':       'letter',
    'slit-open':           'letter',
    'wipe-right':          'word',
    'wipe-left':           'word',
    
    'flip-up-in':          'whole',
    'flip-down-in':        'whole',
    'spin-in':             'whole',
    'swing-in':            'whole',
    'unfold-in':           'whole',
    'curtain-in':          'whole',
    'depth-in':            'whole',
    'depth-fly-in':        'whole',
    'tumble-in':           'whole',
    'weight-morph-in':     'letter',
    'box-in':              'word',
    'wipe-up':             'word',
    'wipe-down':           'word',
    'skew-in':             'word'
  };

  var DECOR_SHAPES = {
    'underline-line': {
      inner: '<line x1="2" y1="5" x2="98" y2="5" stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 10',
      widthMult: 1.05, heightPx: 14,
      placement: 'below', offset: 6,
      drawn: true
    },
    'underline-wavy': {
      inner: '<path d="M3,7 Q12,1 22,7 T42,7 T62,7 T82,7 T97,7" stroke="currentColor" stroke-width="5" fill="none" stroke-linecap="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 14',
      widthMult: 1.05, heightPx: 22,
      placement: 'below', offset: 6,
      drawn: true
    },
    'strike': {
      inner: '<line x1="2" y1="5" x2="98" y2="5" stroke="currentColor" stroke-width="7" stroke-linecap="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 10',
      widthMult: 1.08, heightPx: 12,
      placement: 'overlay-mid', offset: 0,
      drawn: true
    },
    'circle': {
      inner: '<ellipse cx="50" cy="50" rx="46" ry="42" stroke="currentColor" stroke-width="5" fill="none" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 100',
      widthMult: 1.25, heightMult: 1.5,
      placement: 'overlay', offset: 0,
      drawn: true
    },
    'brackets': {
      
      inner: '<path d="M22,5 L8,5 L8,95 L22,95 M78,5 L92,5 L92,95 L78,95" stroke="currentColor" stroke-width="5" fill="none" stroke-linecap="round" stroke-linejoin="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 100',
      widthMult: 1.18, heightMult: 1.25,
      placement: 'overlay', offset: 0,
      drawn: true
    },
    'bracket-left': {
      
      inner: '<path d="M85,8 L20,8 L20,92 L85,92" stroke="currentColor" stroke-width="7" fill="none" stroke-linecap="round" stroke-linejoin="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 100',
      widthMult: 0.22, heightMult: 1.2,
      placement: 'left-of', offset: 16,
      drawn: true
    },
    'bracket-right': {
      
      inner: '<path d="M15,8 L80,8 L80,92 L15,92" stroke="currentColor" stroke-width="7" fill="none" stroke-linecap="round" stroke-linejoin="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 100',
      widthMult: 0.22, heightMult: 1.2,
      placement: 'right-of', offset: 16,
      drawn: true
    },
    'splash': {
      
      inner: '<path d="M50,3 Q72,5 75,22 Q92,30 82,52 Q90,72 65,73 Q52,90 38,75 Q15,78 18,55 Q3,40 18,25 Q24,4 50,3 Z" fill="currentColor" />',
      viewBox: '0 0 100 80',
      widthMult: 1.35, heightMult: 1.6,
      placement: 'overlay', offset: 0,
      opacity: 0.18,
      drawn: false,
      behind: true
    },
    'ticks': {
      
      inner: '<line x1="5" y1="15" x2="5" y2="85" stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="95" y1="15" x2="95" y2="85" stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 100',
      widthMult: 1.22, heightMult: 1.1,
      placement: 'overlay', offset: 0,
      drawn: true
    },
    'streaks': {
      
      inner: '<line x1="0" y1="5" x2="20" y2="5" stroke="currentColor" stroke-width="5" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="80" y1="5" x2="100" y2="5" stroke="currentColor" stroke-width="5" stroke-linecap="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 10',
      widthMult: 1.35, heightPx: 12,
      placement: 'overlay-mid', offset: 0,
      drawn: true
    },
    'lines-from-center': {
      
      inner: '<line x1="50" y1="5" x2="2" y2="5" stroke="currentColor" stroke-width="7" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="50" y1="5" x2="98" y2="5" stroke="currentColor" stroke-width="7" stroke-linecap="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 10',
      widthMult: 1.4, heightPx: 14,
      placement: 'overlay-mid', offset: 0,
      drawn: true
    },
    'brush-stroke': {
      
      inner: '<path d="M2,40 Q10,26 22,33 Q35,22 48,36 Q60,26 72,36 Q85,28 98,38 Q92,54 78,48 Q60,58 45,52 Q28,58 12,52 Q5,50 2,40 Z" fill="currentColor" />',
      viewBox: '0 0 100 80',
      widthMult: 1.25, heightMult: 1.35,
      placement: 'overlay', offset: 0,
      opacity: 0.22,
      drawn: false,
      behind: true
    },
    'arrow-down': {
      inner: '<path d="M50,5 L50,75 M30,55 L50,77 L70,55" stroke="currentColor" stroke-width="7" fill="none" stroke-linecap="round" stroke-linejoin="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 100',
      widthMult: 0.25, heightMult: 0.85,
      placement: 'above', offset: 14,
      drawn: true
    },
    'arrow-right': {
      inner: '<path d="M5,50 L85,50 M65,30 L88,50 L65,70" stroke="currentColor" stroke-width="7" fill="none" stroke-linecap="round" stroke-linejoin="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 100',
      widthMult: 0.5, heightMult: 0.55,
      placement: 'left-of', offset: 24,
      drawn: true
    },
    'asterisk-burst': {
      
      inner: '<g>' +
             '<line x1="50" y1="50" x2="50" y2="3"  stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="50" y1="50" x2="50" y2="97" stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="50" y1="50" x2="3"  y2="50" stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="50" y1="50" x2="97" y2="50" stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="50" y1="50" x2="14" y2="14" stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="50" y1="50" x2="86" y2="14" stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="50" y1="50" x2="14" y2="86" stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="50" y1="50" x2="86" y2="86" stroke="currentColor" stroke-width="6" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '</g>',
      viewBox: '0 0 100 100',
      widthMult: 1.5, heightMult: 1.9,
      placement: 'overlay', offset: 0,
      opacity: 0.85,
      drawn: true
    },
    'frame-rect': {
      
      inner: '<rect x="3" y="3" width="94" height="94" stroke="currentColor" stroke-width="4" fill="none" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 100',
      widthMult: 1.15, heightMult: 1.25,
      placement: 'overlay', offset: 0,
      drawn: true
    },
    'viewfinder': {
      
      inner: '<path d="M5,20 L5,5 L20,5 M80,5 L95,5 L95,20 M95,80 L95,95 L80,95 M20,95 L5,95 L5,80" stroke="currentColor" stroke-width="5" fill="none" stroke-linecap="round" stroke-linejoin="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 100',
      
      widthMult: 1.14, heightMult: 1.16,
      placement: 'overlay', offset: 0,
      drawn: true
    },
    'scribble': {
      
      inner: '<path d="M5,10 Q12,2 18,12 Q24,18 30,8 Q36,1 42,11 Q49,17 55,7 Q61,2 67,13 Q73,17 79,9 Q86,3 95,12" stroke="currentColor" stroke-width="5" fill="none" stroke-linecap="round" vector-effect="non-scaling-stroke" />',
      viewBox: '0 0 100 20',
      widthMult: 1.08, heightPx: 22,
      placement: 'below', offset: 6,
      drawn: true
    },
    'drip': {
      
      inner: '<line x1="20" y1="0" x2="20" y2="80" stroke="currentColor" stroke-width="4" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="50" y1="0" x2="50" y2="65" stroke="currentColor" stroke-width="4" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<line x1="80" y1="0" x2="80" y2="75" stroke="currentColor" stroke-width="4" stroke-linecap="round" vector-effect="non-scaling-stroke" />' +
             '<circle cx="20" cy="83" r="5" fill="currentColor" />' +
             '<circle cx="50" cy="68" r="5" fill="currentColor" />' +
             '<circle cx="80" cy="78" r="5" fill="currentColor" />',
      viewBox: '0 0 100 100',
      widthMult: 0.6, heightMult: 0.9,
      placement: 'above', offset: 4,
      drawn: true
    }
  };

  var DECOR_MOTIONS = {
    'draw-on':  { drawOn: true, duration: 800, easing: 'cubic-bezier(0.65, 0, 0.35, 1)' },
    'draw-off': { drawOff: true, duration: 500, easing: 'cubic-bezier(0.45, 0, 0.55, 1)' },
    'scale-pop': {
      initial: 'transform:scale(0);opacity:0;transform-origin:50% 50%',
      kf: [
        { transform: 'scale(0)',    opacity: 0 },
        { transform: 'scale(1.12)', opacity: 1, offset: 0.7 },
        { transform: 'scale(1)',    opacity: 1 }
      ],
      duration: 600,
      easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
    },
    'fade-in': {
      initial: 'opacity:0',
      kf: [ { opacity: 0 }, { opacity: 1 } ],
      duration: 500,
      easing: 'ease-out'
    },
    'fade-out': {
      initial: '',
      kf: [ { opacity: 1 }, { opacity: 0 } ],
      duration: 500,
      easing: 'ease-in'
    },
    'scale-out': {
      initial: '',
      kf: [
        { transform: 'scale(1)',    opacity: 1 },
        { transform: 'scale(1.15)', opacity: 0 }
      ],
      duration: 500,
      easing: SPRING_OUT
    },
    'rotate-in': {
      initial: 'transform:rotate(-180deg) scale(0);opacity:0;transform-origin:50% 50%',
      kf: [
        { transform: 'rotate(-180deg) scale(0)', opacity: 0 },
        { transform: 'rotate(0deg) scale(1.1)',  opacity: 1, offset: 0.75 },
        { transform: 'rotate(0deg) scale(1)',    opacity: 1 }
      ],
      duration: 700,
      easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
    },
    'rotate-out': {
      initial: '',
      kf: [
        { transform: 'rotate(0deg) scale(1)',     opacity: 1 },
        { transform: 'rotate(180deg) scale(0.4)', opacity: 0 }
      ],
      duration: 550,
      easing: SPRING_OUT
    },
    
    'bracket-emerge-l': {
      initial: 'transform:translateX(500%);opacity:0',
      kf: [
        { transform: 'translateX(500%)', opacity: 0 },
        { transform: 'translateX(500%)', opacity: 1, offset: 0.18 },
        { transform: 'translateX(0)',    opacity: 1 }
      ],
      duration: 800,
      easing: SPRING_IN
    },
    'bracket-emerge-r': {
      initial: 'transform:translateX(-500%);opacity:0',
      kf: [
        { transform: 'translateX(-500%)', opacity: 0 },
        { transform: 'translateX(-500%)', opacity: 1, offset: 0.18 },
        { transform: 'translateX(0)',     opacity: 1 }
      ],
      duration: 800,
      easing: SPRING_IN
    },
    'bracket-collapse-l': {
      
      initial: '',
      kf: [
        { transform: 'translateX(0)',    opacity: 1 },
        { transform: 'translateX(500%)', opacity: 1, offset: 0.75 },
        { transform: 'translateX(500%)', opacity: 0 }
      ],
      duration: 800,
      easing: SPRING_OUT
    },
    'bracket-collapse-r': {
      initial: '',
      kf: [
        { transform: 'translateX(0)',     opacity: 1 },
        { transform: 'translateX(-500%)', opacity: 1, offset: 0.75 },
        { transform: 'translateX(-500%)', opacity: 0 }
      ],
      duration: 800,
      easing: SPRING_OUT
    }
  };

  var STAGGERS = {
    'simultaneous': function (i, n, dur) { return 0; },
    'sequential':   function (i, n, dur) {
      return n <= 1 ? 0 : (i / (n - 1)) * dur * 0.55;
    },
    'reverse':      function (i, n, dur) {
      return n <= 1 ? 0 : ((n - 1 - i) / (n - 1)) * dur * 0.55;
    },
    'wave':         function (i, n, dur) {
      
      return n <= 1 ? 0 : Math.sin((i / (n - 1)) * Math.PI) * dur * 0.6;
    },
    'random':       function (i, n, dur) {
      
      var v = (i * 0.6180339887 + 0.5) % 1;
      return v * dur * 0.55;
    },
    'center-out':   function (i, n, dur) {
      if (n <= 1) return 0;
      var mid = (n - 1) / 2;
      return (Math.abs(i - mid) / Math.max(0.5, mid)) * dur * 0.5;
    },
    'edges-in':     function (i, n, dur) {
      if (n <= 1) return 0;
      var mid = (n - 1) / 2;
      return (1 - Math.abs(i - mid) / Math.max(0.5, mid)) * dur * 0.5;
    }
  };

  var COMPOSITIONS = {

    'cylinder': {
      name: 'Cylinder',
      description: 'Lines wrap a horizontal drum that rolls around the X axis.',
      continuous: true,
      duration: 8000,
      minLines: 1, maxLines: 4,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 600 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 7400, dur: 600 } }
      ]
    },

    
    
    'wiper': {
      name: 'Wiper', description: 'A blade sweeps across and repaints the line behind it.',
      continuous: true, duration: 4200, lines: [{ text: '', motion: 'rise' }]
    },

    'sweep': {
      name: 'Bar Sweep',
      description: 'A skewed bar sweeps across and reveals the text in its wake, then wipes it out.',
      continuous: true,
      duration: 5000,
      minLines: 1, maxLines: 4,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 600 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 4400, dur: 600 } }
      ]
    },

    'brutal': {
      name: 'Extruded',
      description: 'Bold extruded letters slide in horizontally with a hard depth shadow.',
      continuous: true,
      duration: 5000,
      minLines: 1, maxLines: 4,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 600 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 4400, dur: 600 } }
      ]
    },

    'cube': {
      name: 'Puzzle Cube',
      description: 'Text rides a tumbling puzzle cube; layer twists slice it apart and reassemble it.',
      continuous: true,
      duration: 12000,
      minLines: 1, maxLines: 6,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 600 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 11400, dur: 600 } }
      ]
    },

    'glitchloop': {
      name: 'Glitch Loop',
      description: 'Bold line, calm between short slice-and-split glitch bursts.',
      continuous: true,
      duration: 4130,
      minLines: 1, maxLines: 2,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 400 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 3800, dur: 400 } }
      ]
    },

    'echo': {
      name: 'Echo Zoom',
      description: 'A word breathes with fading depth echoes; lines take turns.',
      continuous: true,
      duration: 9000,
      minLines: 1, maxLines: 4,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 600 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 8400, dur: 600 } }
      ]
    },

    'helix': {
      name: 'Helix',
      description: 'The text winds a slowly rotating spiral ribbon.',
      continuous: true,
      duration: 24000,
      minLines: 1, maxLines: 2,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 600 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 23400, dur: 600 } }
      ]
    },

    'curtain': {
      name: 'Curtain',
      description: 'Tall stretched letters ripple like hanging fabric.',
      continuous: true,
      duration: 8000,
      minLines: 1, maxLines: 2,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 700 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 7300, dur: 700 } }
      ]
    },

    'typepulse': {
      name: 'Type Pulse',
      description: 'A packed text block where letters swell and the words repack.',
      continuous: true,
      duration: 7000,
      minLines: 1, maxLines: 6,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 600 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 6400, dur: 600 } }
      ]
    },

    'tide': {
      name: 'Tide',
      description: 'A wavy divider sweeps across and inverts the text it passes.',
      continuous: true,
      duration: 9000,
      minLines: 1, maxLines: 4,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 600 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 8400, dur: 600 } }
      ]
    },

    'discs': {
      name: 'Discs',
      description: 'Words ride overlapping circles that drift in slow orbits.',
      continuous: true,
      duration: 12000,
      minLines: 1, maxLines: 4,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 700 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 11300, dur: 700 } }
      ]
    },

    'arc': {
      name: 'Camera Arc',
      description: 'Letters blast in from the camera, assemble, then blast back out.',
      continuous: true,
      duration: 5000,
      minLines: 1, maxLines: 4,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in', target: 'whole', stagger: 'simultaneous', at: 0, dur: 600 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 4400, dur: 600 } }
      ]
    },

    'slide': {
      name: 'Slide Assemble',
      description: 'Letters slide in horizontally in reading order under a fixed // accent, hold, then slide out the same way.',
      continuous: true,
      duration: 5200,
      minLines: 1, maxLines: 4,
      lines: [
        { role: 'hero', scale: 1.0,
          enter: { motion: 'glide-from-l', target: 'letter', stagger: 'forward', at: 0, dur: 700 },
          exit:  { motion: 'fade-out', target: 'whole', stagger: 'simultaneous', at: 4500, dur: 600 } }
      ]
    },

    'block-slam': {
      name: 'Block Slam',
      description: 'Hero rises through a tight mask, subtitle bounce-slides from alternating sides. Both fade out.',
      duration: 5800,
      minLines: 1, maxLines: 2,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'rise',     target: 'letter', stagger: 'sequential',   at: 0,    dur: 700 },
          exit:  { motion: 'rise-out', target: 'letter', stagger: 'reverse',      at: 4700, dur: 600 }
        },
        {
          role: 'sub', scale: 0.42,
          enter: { motion: 'bounce-slide-split', target: 'word', stagger: 'sequential', at: 900,  dur: 700 },
          exit:  { motion: 'glide-to-r',          target: 'word', stagger: 'sequential', at: 4700, dur: 500 }
        }
      ]
    },

    'triple-cascade': {
      name: 'Triple Cascade',
      description: 'Hero zooms with bounce, sub bounce-slides from sides, label rises. Distinct exits.',
      duration: 7500,
      minLines: 1, maxLines: 3,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'zoom-in',  target: 'word', stagger: 'sequential', at: 0,    dur: 700 },
          exit:  { motion: 'zoom-out', target: 'word', stagger: 'sequential', at: 4500, dur: 600 }
        },
        {
          role: 'sub', scale: 0.55,
          enter: { motion: 'bounce-slide-split', target: 'word', stagger: 'sequential', at: 900,  dur: 750 },
          exit:  { motion: 'glide-to-r',          target: 'word', stagger: 'reverse',    at: 6000, dur: 700 }
        },
        {
          role: 'label', scale: 0.32,
          enter: { motion: 'rise',     target: 'letter', stagger: 'sequential', at: 1800, dur: 600 },
          exit:  { motion: 'rise-out', target: 'word',   stagger: 'sequential', at: 5400, dur: 500 }
        }
      ]
    },

    'wave-build': {
      name: 'Wave Build',
      description: 'Each line waves in via a different motion: rise → drop → zoom → blur, all sine-staggered.',
      duration: 6500,
      minLines: 1, maxLines: 4,
      lines: [
        {
          role: 'hero', scale: 0.95,
          enter: { motion: 'rise',     target: 'letter', stagger: 'wave', staggerScale: 1.5, intensity: 0.9, at: 0,    dur: 900 },
          exit:  { motion: 'fade-out', target: 'whole',  stagger: 'simultaneous', at: 5400, dur: 600 }
        },
        {
          role: 'sub', scale: 0.5,
          enter: { motion: 'drop',     target: 'letter', stagger: 'wave', staggerScale: 1.5, intensity: 0.9, at: 1000, dur: 800 },
          exit:  { motion: 'fade-out', target: 'whole',  stagger: 'simultaneous', at: 5300, dur: 600 }
        },
        {
          role: 'label', scale: 0.32,
          enter: { motion: 'zoom-in',  target: 'letter', stagger: 'wave', staggerScale: 1.5, intensity: 0.8, at: 1900, dur: 700 },
          exit:  { motion: 'fade-out', target: 'whole',  stagger: 'simultaneous', at: 5200, dur: 500 }
        },
        {
          role: 'label', scale: 0.26,
          enter: { motion: 'blur-in',  target: 'letter', stagger: 'wave', staggerScale: 1.5, intensity: 0.7, at: 2700, dur: 600 },
          exit:  { motion: 'fade-out', target: 'whole',  stagger: 'simultaneous', at: 5100, dur: 500 }
        }
      ]
    },

    'spotlight': {
      name: 'Spotlight',
      description: 'Hero blurs in dramatically. Subtitle letter-spaces in below. Both fade out.',
      duration: 6500,
      minLines: 1, maxLines: 2,
      lines: [
        {
          role: 'hero', scale: 1.2,
          enter: { motion: 'blur-in',  target: 'whole', stagger: 'simultaneous', at: 0,    dur: 1200 },
          exit:  { motion: 'blur-out', target: 'whole', stagger: 'simultaneous', at: 5000, dur: 800 }
        },
        {
          role: 'sub', scale: 0.4,
          enter: { motion: 'spacing-in',  target: 'word', stagger: 'sequential', at: 1500, dur: 800 },
          exit:  { motion: 'spacing-out', target: 'word', stagger: 'reverse',    at: 4800, dur: 700 }
        }
      ]
    },

    'reverse-cascade': {
      name: 'Up Cascade',
      description: 'Bottom label glides in, sub bounce-slides, hero rises. Hero exits first via drop.',
      duration: 7200,
      minLines: 1, maxLines: 3,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'rise',           target: 'word', stagger: 'sequential', at: 1600, dur: 700 },
          exit:  { motion: 'drop-out',       target: 'word', stagger: 'sequential', at: 4800, dur: 600 }
        },
        {
          role: 'sub', scale: 0.55,
          enter: { motion: 'bounce-slide-split', target: 'word', stagger: 'sequential', at: 800, dur: 650 },
          exit:  { motion: 'glide-to-r',          target: 'word', stagger: 'sequential', at: 5300, dur: 600 }
        },
        {
          role: 'label', scale: 0.35,
          enter: { motion: 'glide-from-l',   target: 'word', stagger: 'sequential', at: 0,    dur: 600 },
          exit:  { motion: 'glide-to-l',     target: 'word', stagger: 'sequential', at: 5800, dur: 500 }
        }
      ]
    },

    'slide-stack': {
      name: 'Slide Stack',
      description: 'Lines build from alternating sides with bounce and per-letter kick, staggered into a layered stack.',
      duration: 7200,
      minLines: 1, maxLines: 4,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'bounce-slide-split', target: 'word',   stagger: 'sequential', at: 0,    dur: 760 },
          exit:  { motion: 'glide-to-l',         target: 'word',   stagger: 'sequential', at: 5400, dur: 600 }
        },
        {
          role: 'sub', scale: 0.5,
          enter: { motion: 'glide-from-r',       target: 'letter', stagger: 'sequential', at: 650,  dur: 720 },
          exit:  { motion: 'spacing-out',        target: 'whole',  stagger: 'simultaneous', at: 5600, dur: 560 }
        },
        {
          role: 'label', scale: 0.35,
          enter: { motion: 'letter-kick-in',     target: 'letter', stagger: 'sequential', at: 1300, dur: 640 },
          exit:  { motion: 'drop-out',           target: 'letter', stagger: 'sequential', at: 5800, dur: 560 }
        },
        {
          role: 'label', scale: 0.28,
          enter: { motion: 'bounce-slide-l',     target: 'word',   stagger: 'sequential', at: 1950, dur: 640 },
          exit:  { motion: 'glide-to-r',         target: 'word',   stagger: 'sequential', at: 6000, dur: 560 }
        }
      ]
    },

    'pulse-zoom': {
      name: 'Pulse Zoom',
      description: 'Hero zooms with bounce. Sub letter-spaces with kick. Label spring-rises. Each line a different motion.',
      duration: 6000,
      minLines: 1, maxLines: 3,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'zoom-in',         target: 'whole',  stagger: 'simultaneous', at: 0,    dur: 800 },
          exit:  { motion: 'zoom-out',        target: 'whole',  stagger: 'simultaneous', at: 4700, dur: 500 }
        },
        {
          role: 'sub', scale: 0.5,
          enter: { motion: 'letter-kick-in',  target: 'letter', stagger: 'sequential',   at: 1000, dur: 700 },
          exit:  { motion: 'spacing-out',     target: 'whole',  stagger: 'simultaneous', at: 4500, dur: 500 }
        },
        {
          role: 'label', scale: 0.32,
          enter: { motion: 'bounce-rise',     target: 'word',   stagger: 'sequential',   at: 1800, dur: 600 },
          exit:  { motion: 'drop-out',        target: 'word',   stagger: 'sequential',   at: 4300, dur: 500 }
        }
      ]
    },

    'typewriter': {
      name: 'Typewriter',
      description: 'Hero strikes in letter-by-letter. Sub drops in. Label glides in. Then the whole thing un-types, erasing backward letter by letter.',
      duration: 8200,
      minLines: 1, maxLines: 3,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'rise',     target: 'letter', stagger: 'sequential', staggerScale: 2.5, at: 0,    dur: 220 },
          exit:  { motion: 'drop-out', target: 'letter', stagger: 'reverse',    staggerScale: 1.6, at: 6300, dur: 200 }
        },
        {
          role: 'sub', scale: 0.5,
          enter: { motion: 'drop',         target: 'letter', stagger: 'sequential', staggerScale: 2.0, at: 2200, dur: 200 },
          exit:  { motion: 'spacing-out',  target: 'letter', stagger: 'reverse',    staggerScale: 1.4, at: 6650, dur: 200 }
        },
        {
          role: 'label', scale: 0.32,
          enter: { motion: 'glide-from-l', target: 'letter', stagger: 'sequential', staggerScale: 2.2, at: 4200, dur: 180 },
          exit:  { motion: 'glide-to-r',   target: 'letter', stagger: 'reverse',    staggerScale: 1.4, at: 6950, dur: 190 }
        }
      ]
    },

    'edge-burst': {
      name: 'Edge Burst',
      description: 'Letters converge from the edges to the centre. Hold, then fly out the same way.',
      duration: 6200,
      minLines: 1, maxLines: 2,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'zoom-in',  target: 'letter', stagger: 'edges-in',   staggerScale: 1.4, at: 0,    dur: 600 },
          exit:  { motion: 'zoom-out', target: 'letter', stagger: 'center-out', staggerScale: 1.4, at: 4800, dur: 500 }
        },
        {
          role: 'sub', scale: 0.5,
          enter: { motion: 'fade-in',  target: 'word', stagger: 'sequential', at: 1400, dur: 600 },
          exit:  { motion: 'fade-out', target: 'word', stagger: 'sequential', at: 4900, dur: 500 }
        }
      ]
    },

    'center-burst': {
      name: 'Center Burst',
      description: 'Letters explode outward from the centre. Pull back to centre on exit.',
      duration: 5800,
      minLines: 1, maxLines: 2,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'fade-in',  target: 'letter', stagger: 'center-out', staggerScale: 1.4, at: 0,    dur: 600 },
          exit:  { motion: 'fade-out', target: 'letter', stagger: 'edges-in',   staggerScale: 1.4, at: 4500, dur: 500 }
        },
        {
          role: 'sub', scale: 0.4,
          enter: { motion: 'spacing-in',  target: 'whole', stagger: 'simultaneous', at: 1400, dur: 800 },
          exit:  { motion: 'spacing-out', target: 'whole', stagger: 'simultaneous', at: 4500, dur: 600 }
        }
      ]
    },

    'random-rain': {
      name: 'Random Rain',
      description: 'Hero letters drop randomly. Sub letters rise randomly from below. Label blurs in randomly. Chaotic build.',
      duration: 6800,
      minLines: 1, maxLines: 3,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'drop',     target: 'letter', stagger: 'random', staggerScale: 1.5, at: 0,    dur: 600 },
          exit:  { motion: 'fade-out', target: 'letter', stagger: 'random', staggerScale: 1.5, at: 5000, dur: 500 }
        },
        {
          role: 'sub', scale: 0.5,
          enter: { motion: 'rise',     target: 'letter', stagger: 'random', staggerScale: 1.5, at: 1100, dur: 550 },
          exit:  { motion: 'fade-out', target: 'letter', stagger: 'random', staggerScale: 1.5, at: 5100, dur: 500 }
        },
        {
          role: 'label', scale: 0.32,
          enter: { motion: 'blur-in',  target: 'letter', stagger: 'random', staggerScale: 1.5, at: 2100, dur: 500 },
          exit:  { motion: 'fade-out', target: 'letter', stagger: 'random', staggerScale: 1.5, at: 5200, dur: 500 }
        }
      ]
    },

    'quick-flash': {
      name: 'Quick Flash',
      description: 'Snappy zoom in, sub kicks in with letter-spacing pulse. Snappy zoom out.',
      duration: 3500,
      minLines: 1, maxLines: 2,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'zoom-in',  target: 'whole', stagger: 'simultaneous', at: 0,    dur: 380 },
          exit:  { motion: 'zoom-out', target: 'whole', stagger: 'simultaneous', at: 2700, dur: 280 }
        },
        {
          role: 'sub', scale: 0.4,
          enter: { motion: 'letter-kick-in', target: 'letter', stagger: 'sequential',   at: 400, dur: 400 },
          exit:  { motion: 'spacing-out',    target: 'whole',  stagger: 'simultaneous', at: 2600, dur: 300 }
        }
      ]
    },

    'side-step': {
      name: 'Side Step',
      description: 'Lines glide in from alternating sides. Exit out the OPPOSITE side they came from.',
      duration: 6500,
      minLines: 1, maxLines: 4,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'glide-from-l', target: 'whole', stagger: 'simultaneous', at: 0,    dur: 650 },
          exit:  { motion: 'glide-to-r',   target: 'whole', stagger: 'simultaneous', at: 5200, dur: 550 }
        },
        {
          role: 'sub', scale: 0.55,
          enter: { motion: 'glide-from-r', target: 'whole', stagger: 'simultaneous', at: 800, dur: 650 },
          exit:  { motion: 'glide-to-l',   target: 'whole', stagger: 'simultaneous', at: 5000, dur: 550 }
        },
        {
          role: 'label', scale: 0.35,
          enter: { motion: 'glide-from-l', target: 'whole', stagger: 'simultaneous', at: 1600, dur: 600 },
          exit:  { motion: 'glide-to-r',   target: 'whole', stagger: 'simultaneous', at: 4800, dur: 500 }
        },
        {
          role: 'label', scale: 0.28,
          enter: { motion: 'glide-from-r', target: 'whole', stagger: 'simultaneous', at: 2400, dur: 600 },
          exit:  { motion: 'glide-to-l',   target: 'whole', stagger: 'simultaneous', at: 4600, dur: 500 }
        }
      ]
    },

    'letter-blur': {
      name: 'Letter Blur',
      description: 'Hero letters blur in, sub letter-spaces in, label letters distort in. Different distortion per line.',
      duration: 6500,
      minLines: 1, maxLines: 3,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'blur-in',     target: 'letter', stagger: 'sequential', at: 0,    dur: 600 },
          exit:  { motion: 'blur-out',    target: 'letter', stagger: 'sequential', at: 5000, dur: 500 }
        },
        {
          role: 'sub', scale: 0.5,
          enter: { motion: 'spacing-in',  target: 'whole',  stagger: 'simultaneous', at: 900, dur: 700 },
          exit:  { motion: 'spacing-out', target: 'whole',  stagger: 'simultaneous', at: 5100, dur: 500 }
        },
        {
          role: 'label', scale: 0.32,
          enter: { motion: 'distort-in',  target: 'letter', stagger: 'sequential', intensity: 0.8, at: 1800, dur: 500 },
          exit:  { motion: 'distort-out', target: 'letter', stagger: 'sequential', intensity: 0.8, at: 5200, dur: 500 }
        }
      ]
    },

    'rise-fall': {
      name: 'Rise Fall',
      description: 'Hero rises in dramatically, falls out via drop. Sub bounce-slides from sides. Letter-kick label optional.',
      duration: 6500,
      minLines: 1, maxLines: 2,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'rise',               target: 'whole', stagger: 'simultaneous', at: 0,    dur: 900 },
          exit:  { motion: 'drop-out',           target: 'whole', stagger: 'simultaneous', at: 5000, dur: 700 }
        },
        {
          role: 'sub', scale: 0.4,
          enter: { motion: 'bounce-slide-split', target: 'word',  stagger: 'sequential',   at: 1200, dur: 650 },
          exit:  { motion: 'glide-to-r',         target: 'word',  stagger: 'sequential',   at: 4800, dur: 500 }
        }
      ]
    },

    'mixed-cascade': {
      name: 'Mixed Cascade',
      description: 'Hero scatter-bursts. Sub bounce-slides from sides. Label blurs in with kick. All blur out.',
      duration: 7200,
      minLines: 1, maxLines: 3,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'scatter-in', target: 'letter', stagger: 'center-out', staggerScale: 1.2, intensity: 1.3, at: 0, dur: 800 },
          exit:  { motion: 'blur-out',   target: 'whole',  stagger: 'simultaneous', at: 5500, dur: 700 }
        },
        {
          role: 'sub', scale: 0.55,
          enter: { motion: 'bounce-slide-split', target: 'word',   stagger: 'sequential', at: 900,  dur: 700 },
          exit:  { motion: 'blur-out',           target: 'whole',  stagger: 'simultaneous', at: 5500, dur: 700 }
        },
        {
          role: 'label', scale: 0.32,
          enter: { motion: 'letter-kick-in', target: 'letter', stagger: 'sequential', at: 2000, dur: 600 },
          exit:  { motion: 'blur-out',       target: 'whole',  stagger: 'simultaneous', at: 5500, dur: 700 }
        }
      ]
    },

    'explosion': {
      name: 'Explosion',
      description: 'Letters scatter into place from random angles at full intensity. Sub bounces. Hero blasts out via scatter.',
      duration: 6200,
      minLines: 1, maxLines: 2,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'scatter-in',  target: 'letter', stagger: 'random', staggerScale: 1.8, intensity: 2.0, at: 0,    dur: 800 },
          exit:  { motion: 'scatter-out', target: 'letter', stagger: 'random', staggerScale: 1.8, intensity: 2.0, at: 4700, dur: 700 }
        },
        {
          role: 'sub', scale: 0.45,
          enter: { motion: 'bounce-slide-split', target: 'word',  stagger: 'sequential',   at: 1100, dur: 650 },
          exit:  { motion: 'glide-to-r',          target: 'word',  stagger: 'sequential',   at: 4800, dur: 500 }
        }
      ]
    },

    'tremor': {
      name: 'Tremor',
      description: 'Hero shakes into place. Sub bounce-slides from sides. Label glitches in. Distinct per line.',
      duration: 5800,
      minLines: 1, maxLines: 3,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'shake-in',           target: 'letter', stagger: 'random',     staggerScale: 0.8, intensity: 1.3, at: 0,    dur: 700 },
          exit:  { motion: 'glitch-out',         target: 'whole',  stagger: 'simultaneous',                   intensity: 0.8, at: 4500, dur: 500 }
        },
        {
          role: 'sub', scale: 0.5,
          enter: { motion: 'bounce-slide-split', target: 'word',   stagger: 'sequential', at: 900, dur: 650 },
          exit:  { motion: 'glide-to-r',         target: 'word',   stagger: 'sequential', at: 4600, dur: 500 }
        },
        {
          role: 'label', scale: 0.32,
          enter: { motion: 'glitch-in',          target: 'whole',  stagger: 'simultaneous', intensity: 0.7, at: 1700, dur: 550 },
          exit:  { motion: 'fade-out',           target: 'whole',  stagger: 'simultaneous', at: 4700, dur: 500 }
        }
      ]
    },

    'static': {
      name: 'Static',
      description: 'Hero noise-flickers in like a broken neon sign. Sub glitches in with chromatic aberration. Holds, fades.',
      duration: 5500,
      minLines: 1, maxLines: 2,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'noise-flicker', target: 'letter', stagger: 'random', staggerScale: 0.6, intensity: 1.2, at: 0,    dur: 850 },
          exit:  { motion: 'glitch-out',    target: 'whole',  stagger: 'simultaneous',                intensity: 1.0, at: 4300, dur: 700 }
        },
        {
          role: 'sub', scale: 0.4,
          enter: { motion: 'glitch-in',     target: 'word',   stagger: 'random', staggerScale: 0.8, intensity: 1.0, at: 1100, dur: 600 },
          exit:  { motion: 'fade-out',      target: 'whole',  stagger: 'simultaneous',                                 at: 4400, dur: 500 }
        }
      ]
    },

    

    

    

    

    

    

    'glitch': {
      name: 'Glitch',
      description: 'Hero glitches in with chromatic aberration. Sub distorts in through blur-contrast noise. Both fade with glitch-out.',
      duration: 5800,
      minLines: 1, maxLines: 2,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'glitch-in',  target: 'letter', stagger: 'random', staggerScale: 1.2, intensity: 1.5, at: 0,    dur: 650 },
          exit:  { motion: 'glitch-out', target: 'whole',  stagger: 'simultaneous',                intensity: 1.5, at: 4500, dur: 600 }
        },
        {
          role: 'sub', scale: 0.45,
          enter: { motion: 'distort-in',  target: 'word',  stagger: 'sequential',   intensity: 1.0, at: 1100, dur: 700 },
          exit:  { motion: 'distort-out', target: 'word',  stagger: 'sequential',   intensity: 0.8, at: 4600, dur: 500 }
        }
      ]
    },

    'distortion': {
      name: 'Distortion',
      description: 'Hero resolves out of heavy blur and contrast noise — analog video tuning in. Sub kicks in. Both fade through blur.',
      duration: 6500,
      minLines: 1, maxLines: 2,
      lines: [
        {
          role: 'hero', scale: 1.0,
          enter: { motion: 'distort-in',  target: 'word',  stagger: 'simultaneous', intensity: 1.4, at: 0,    dur: 900 },
          exit:  { motion: 'distort-out', target: 'whole', stagger: 'simultaneous', intensity: 1.4, at: 5000, dur: 700 }
        },
        {
          role: 'sub', scale: 0.45,
          enter: { motion: 'letter-kick-in', target: 'letter', stagger: 'sequential', at: 1400, dur: 600 },
          exit:  { motion: 'spacing-out',    target: 'whole',  stagger: 'simultaneous', at: 5100, dur: 600 }
        }
      ]
    }

  };

  function _isEditor() {
    try { return window.parent !== window; } catch (e) { return false; }
  }
  function _isScreenMode() {
    return document.body.getAttribute('data-screen-mode') === '1'
        || !!document.querySelector('.impulse-screen-wrapper');
  }
  function _ms(base, speed) {
    return Math.max(0, Math.round(base / (speed || 1)));
  }
  
  function _rand(seed) {
    var x = Math.sin(seed * 12.9898 + 78.233) * 43758.5453;
    return x - Math.floor(x);
  }
  
  var _kBrRe = /<br\s*\/?>/gi;
  
  var _kWordRe = /[^\s\u00A0]+(?:\u00A0[^\s\u00A0]+)*/g;
  
  function _bindConnectors(line) {
    return String(line || '').replace(/(^|[\s\u00A0])([&+\u2014\u2013])[\s]+(?=\S)/g, '$1$2\u00A0');
  }
  
  function _parseText(raw) {
    raw = (raw || '').replace(/\r/g, '');
    return raw.split('\n')
      .map(function (s) { return s.trim(); })
      .filter(Boolean)
      .map(function (line) { line = _bindConnectors(line); return { text: line, words: (line.match(_kWordRe) || []) }; });
  }

  var _kDecodeEl = null;
  function _kDecodeEntities(str) {
    if (str == null) return '';
    str = String(str);
    if (str.indexOf('&') === -1) return str;
    if (!_kDecodeEl) _kDecodeEl = document.createElement('textarea');
    _kDecodeEl.innerHTML = str;
    return _kDecodeEl.value;
  }

  var _kMeasCanvas = null, _kMeasCtx = null;
  function _kDescentEm(lineText, family, weight) {
    if (!lineText) return 0.03;
    try {
      if (!_kMeasCtx) { _kMeasCanvas = document.createElement('canvas'); _kMeasCtx = _kMeasCanvas.getContext('2d'); }
      _kMeasCtx.font = (weight || '800') + ' 100px ' + (family || 'sans-serif');
      var m = _kMeasCtx.measureText(lineText);
      if (m && typeof m.actualBoundingBoxDescent === 'number') return m.actualBoundingBoxDescent / 100;
    } catch (e) {}
    return 0.22; 
  }

  function _tierScale(tier, li) {
    if (tier === 'equal') return 1;
    if (tier === 'label') {
      if (li === 0) return 0.34;
      if (li === 1) return 1;
      return 0.42;
    }
    return li === 0 ? 1 : 0.42; 
  }

  var KFONTS = {
    system:    '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
    serif:     'Georgia, "Times New Roman", serif',
    geometric: '"Century Gothic", "Avant Garde", "URW Gothic L", "Twentieth Century", "Futura", "Trebuchet MS", sans-serif',
    mono:      'ui-monospace, "SF Mono", "Cascadia Code", "Consolas", "Courier New", monospace'
  };

  var _KDBG = false;
  try { _KDBG = /[?&]kdebug=1/.test(location.search); } catch (eD) {}
  function _klog(el, ev) {
    if (!_KDBG) return;
    try { (el._kLog = el._kLog || []).push(Math.round(performance.now()) + ' ' + ev); } catch (eL) {}
  }

  function KineticBlock(el) {
    _klog(el, 'construct');
    this.el = el;
    this._destroyed = false;
    this._running   = false;
    this._timers    = [];
    this._anims     = [];
    this._io        = null;

    this.composition = el.getAttribute('data-composition') || 'block-slam';
    
    if (this.composition === 'slow-burn') this.composition = 'spotlight';
    
    if (this.composition === 'wiper') {
      this.composition = 'block-slam';
      this._migratedWiper = true;
    }
    
    if (['weightshift', 'ribbon', 'flipgrid'].indexOf(this.composition) !== -1) this.composition = 'block-slam';
    
    if (['glitchloop', 'echo', 'helix', 'cube', 'cylinder', 'curtain', 'typepulse', 'tide', 'discs', 'wiper']
          .indexOf(this.composition) !== -1 && el.offsetHeight < 40) {
      
      var _authorMinH = 0;
      try { _authorMinH = parseFloat(getComputedStyle(el).minHeight) || 0; } catch (e) {}
      if (_authorMinH < 40) el.style.minHeight = '480px';
    }
    this.tier        = el.getAttribute('data-tier') || 'hero'; 
    
    this.discClip    = el.getAttribute('data-disc-clip') !== '0';
    this.lineGap     = parseFloat(el.getAttribute('data-line-gap') || '0'); 
    if (!isFinite(this.lineGap)) this.lineGap = 0;
    this._lineGapBase = this.lineGap;   

    this.maxWidthD = parseFloat(el.getAttribute('data-max-width') || '0');
    if (!isFinite(this.maxWidthD) || this.maxWidthD < 0) this.maxWidthD = 0;
    var _mwT = el.getAttribute('data-max-width-tablet');
    this.maxWidthT = (_mwT != null && _mwT !== '') ? parseFloat(_mwT) : null;
    var _mwM = el.getAttribute('data-max-width-mobile');
    this.maxWidthM = (_mwM != null && _mwM !== '') ? parseFloat(_mwM) : null;
    this.maxWidth  = this._pickMaxWidth();
    
    this._devNum = function (attr, base) {
        var w = window.innerWidth || 9999;
        var v = null;
        if (w < 768)       v = el.getAttribute('data-' + attr + '-mobile');
        if (v == null || v === '') { if (w < 1024) v = el.getAttribute('data-' + attr + '-tablet'); }
        if (v == null || v === '') return base;
        var n = parseFloat(v);
        return isFinite(n) ? n : base;
    };
    this.cylDiameter = this._devNum('cyl-diameter', parseFloat(el.getAttribute('data-cyl-diameter') || '70')); 
    this.cubeStyle   = (el.getAttribute('data-cube-style') || 'faces').toLowerCase(); 
    this.cubeMono    = el.getAttribute('data-cube-mono') === '1';                     
    this.echoCount   = Math.max(2, Math.min(16, parseInt(el.getAttribute('data-echo-count') || '5', 10) || 5)); 
    
    this.discColors  = (function (raw) {
      try { var a = JSON.parse(decodeURIComponent(raw || '')); return Array.isArray(a) ? a : []; }
      catch (e) { return []; }
    })(el.getAttribute('data-disc-colors'));

    
    this.asBackground = el.classList.contains('impulse-kinetic-bg');
    this.discButtons = el.getAttribute('data-disc-buttons') !== '0';
    this.discGlow    = el.getAttribute('data-disc-glow') === '1';
    
    this.discInk     = (el.getAttribute('data-disc-ink') || '').trim();

    
    this.compFont    = Math.max(0, this._devNum('comp-font', parseFloat(el.getAttribute('data-comp-font') || '0')) || 0);
    this.discFont    = Math.max(0, this._devNum('disc-font', parseFloat(el.getAttribute('data-disc-font') || '0')) || 0);
    
    if (!(this.discFont > 0)) this.discFont = 30;
    
    this.kWeight     = (el.getAttribute('data-kinetic-weight') || '').trim();
    this.tideBubbles = el.getAttribute('data-tide-bubbles') === '1';
    
    this.discSubs    = (function (raw) {
      try { var a = JSON.parse(decodeURIComponent(raw || '')); return Array.isArray(a) ? a : []; }
      catch (e) { return []; }
    })(el.getAttribute('data-disc-subs'));
    this.discLinks   = (function (raw) {
      try { var a = JSON.parse(decodeURIComponent(raw || '')); return Array.isArray(a) ? a : []; }
      catch (e) { return []; }
    })(el.getAttribute('data-disc-links'));
    this.cubeSize    = this._devNum('cube-size', parseFloat(el.getAttribute('data-cube-size') || '55')); 
    if (!isFinite(this.cylDiameter) || this.cylDiameter <= 0) this.cylDiameter = 70;
    this.accent      = el.getAttribute('data-accent') || 'none'; 
    var _accTxt      = el.getAttribute('data-accent-text') || '';
    try { _accTxt = decodeURIComponent(_accTxt); } catch (e) {}
    this.accentText  = _accTxt;
    this.color       = el.getAttribute('data-color') || '#ffffff';
    
    this.fill        = (el.getAttribute('data-fill') || 'solid').toLowerCase();
    this.gradMode    = (el.getAttribute('data-grad-mode') || 'travel').toLowerCase();
    if (this._migratedWiper) { this.gradMode = 'wipe'; this.fill = 'gradient'; }
    this.gradScope   = (el.getAttribute('data-grad-scope') || 'line').toLowerCase(); 
    this.gradC1      = el.getAttribute('data-grad-c1') || '#ff2d55';
    this.gradC2      = el.getAttribute('data-grad-c2') || '#5e5cff';
    this.gradSpeed   = this._devNum('grad-speed', parseFloat(el.getAttribute('data-grad-speed') || '1'));
    if (!isFinite(this.gradSpeed) || this.gradSpeed <= 0) this.gradSpeed = 1;
    if (this.fill === 'gradient') _kInjectGradCss();
    this.speed       = this._devNum('speed', parseFloat(el.getAttribute('data-speed') || '1'));
    this.intensity   = this._devNum('intensity', parseFloat(el.getAttribute('data-intensity') || '1'));
    this.lineGap     = this._devNum('line-gap', this._lineGapBase);
    if (!isFinite(this.intensity) || this.intensity <= 0) this.intensity = 1;
    this.loop        = el.getAttribute('data-loop') !== '0';
    
    this.cycle       = el.getAttribute('data-cycle') === '1';
    
    var _alignRaw    = (el.getAttribute('data-align') || 'center').toLowerCase();
    this.align       = (_alignRaw === 'left' || _alignRaw === 'right') ? _alignRaw : 'center';
    
    this.scrollExit  = (el.getAttribute('data-scroll-exit') || 'off').toLowerCase();

    
    
    this.leadScreen  = el.getAttribute('data-lead-screen') !== '0'
                       && !(typeof window !== 'undefined' && window._impulseEditorPreview);
    
    this.heightAuto  = el.getAttribute('data-height-auto') === '1';

    this.compScale = (function (self_el, devNum) {
      var sz = devNum('comp-size', parseFloat(self_el.getAttribute('data-comp-size')));
      if (isFinite(sz) && sz > 0) return sz / 5;
      return devNum('comp-scale', parseFloat(self_el.getAttribute('data-comp-scale')));
    })(el, this._devNum.bind(this));
    if (!isFinite(this.compScale) || this.compScale <= 0) this.compScale = 1;
    
    this.fontStack = KFONTS[el.getAttribute('data-font')] || KFONTS.system;
    
    this.curMagnetic  = el.getAttribute('data-cursor-magnetic')  === '1';
    this.curSpotlight = el.getAttribute('data-cursor-spotlight') === '1';
    this.curGradient  = el.getAttribute('data-cursor-gradient')  === '1';
    this.curTilt      = el.getAttribute('data-cursor-tilt')      === '1';
    
    if (this.composition === 'discs') this.curTilt = false;
    
    this._settleMs   = 1500;

    this.customMode = el.getAttribute('data-custom-mode') === '1';
    var customRaw   = el.getAttribute('data-custom-lines') || '[]';
    try { customRaw = decodeURIComponent(customRaw); } catch (e) {}
    try { this.customLines = JSON.parse(customRaw); }
    catch (e) { this.customLines = []; }
    if (Array.isArray(this.customLines)) {
      
      this.customLines.forEach(function (cl) {
        if (cl && typeof cl.text === 'string') cl.text = _kDecodeEntities(cl.text.replace(_kBrRe, '\n'));
      });
      
      var _kExpanded = [];
      this.customLines.forEach(function (cl) {
        if (!cl || typeof cl.text !== 'string' || cl.text.indexOf('\n') === -1) { _kExpanded.push(cl); return; }
        cl.text.split('\n').forEach(function (part) {
          if (part.trim() === '') return; 
          var copy = {}; for (var _ck in cl) copy[_ck] = cl[_ck];
          copy.text = part;
          _kExpanded.push(copy);
        });
      });
      this.customLines = _kExpanded;
    }

    var raw = el.getAttribute('data-text') || '';
    try { raw = decodeURIComponent(raw); } catch (e) {}
    raw = raw.replace(_kBrRe, '\n'); 
    raw = _kDecodeEntities(raw);
    this.lines = _parseText(raw);

    this._setup();
    this._startObserver();
    this._startResizeObserver();
  }

  KineticBlock.prototype._pickMaxWidth = function () {
    var w = window.innerWidth || 9999;
    var v;
    if (w < 768 && this.maxWidthM != null && isFinite(this.maxWidthM)) v = this.maxWidthM;
    else if (w < 1024 && this.maxWidthT != null && isFinite(this.maxWidthT)) v = this.maxWidthT;
    else v = this.maxWidthD;
    return (isFinite(v) && v > 0) ? v : 0;
  };

  KineticBlock.prototype._startResizeObserver = function () {
    var self = this;
    if (!window.ResizeObserver) return;
    var debounce = null;
    try {
      self._ro = new ResizeObserver(function () {
        
        if (self._destroyed || (!self._running && !self._shown)) return;
        
        var w = self.el.offsetWidth, h = self.el.offsetHeight;
        if (Math.abs(w - (self._lastW || 0)) < 3 && Math.abs(h - (self._lastH || 0)) < 3) return;
        if (debounce) clearTimeout(debounce);
        debounce = setTimeout(function () {
          if (self._destroyed || (!self._running && !self._shown)) return;
          var w2 = self.el.offsetWidth, h2 = self.el.offsetHeight;
          if (Math.abs(w2 - (self._lastW || 0)) < 3 && Math.abs(h2 - (self._lastH || 0)) < 3) return;
          var wasShown = self._shown;
          
          self._instantRefit = (wasShown && !self.loop && !self.cycle);
          self._clearAll();   
          self._playOnce();
          self._instantRefit = false;
          
          if (wasShown) self._shown = true;
        }, 150); 
      });
      self._ro.observe(self.el);
    } catch (e) {}
  };

  KineticBlock.prototype._cacheCursorLetters = function () {
    var self = this;
    if (!(self.curMagnetic || self.curSpotlight)) { self._curUnits = null; return; }
    var rect = self.el.getBoundingClientRect();
    if (rect.width < 2) { self._curUnits = null; return; }
    var masks = [].slice.call(self._stage.querySelectorAll('.kp-char-mask'));
    
    var map = new Map();
    masks.forEach(function (m) {
      var line = m.closest('[data-cur-gran]');
      var gran = line ? line.getAttribute('data-cur-gran') : 'letter';
      var keyEl = gran === 'line' ? (line || m) : (gran === 'word' ? (m.closest('.kp-word-mask') || m) : m);
      m.style.transition = 'transform 0.3s cubic-bezier(0.2,0.7,0.3,1), opacity 0.3s ease-in-out';
      m.style.willChange = 'transform, opacity';
      var u = map.get(keyEl);
      if (!u) { u = { els: [], rests: [], minL: Infinity, minT: Infinity, maxR: -Infinity, maxB: -Infinity }; map.set(keyEl, u); }
      var r = m.getBoundingClientRect();
      u.els.push(m); u.rests.push(m.style.transform || '');
      u.minL = Math.min(u.minL, r.left); u.minT = Math.min(u.minT, r.top);
      u.maxR = Math.max(u.maxR, r.right); u.maxB = Math.max(u.maxB, r.bottom);
    });
    self._curUnits = [];
    map.forEach(function (u) {
      self._curUnits.push({ els: u.els, rests: u.rests, cx: (u.minL + u.maxR) / 2 - rect.left, cy: (u.minT + u.maxB) / 2 - rect.top });
    });
    
    var wms = self._stage.querySelectorAll('.kp-word-mask');
    for (var wi = 0; wi < wms.length; wi++) wms[wi].style.overflow = self.curMagnetic ? 'visible' : '';
    self._lastW = self.el.offsetWidth;
    self._lastH = self.el.offsetHeight;
  };

  KineticBlock.prototype._startCursorFX = function () {
    var self = this;
    if (!(self.curMagnetic || self.curSpotlight || self.curGradient || self.curTilt)) return;
    if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    
    if (self.curGradient && self.fill === 'gradient' && self._stage) self._stage.style.animation = 'none';
    if (self._cursorInit) return;
    self._cursorInit = true;
    var hoverable = !(window.matchMedia && window.matchMedia('(hover: none)').matches);
    var raf = null, mx = 0, my = 0, active = false;

    if (self.curTilt) self._stage.style.transition = ((self._stage.style.transition ? self._stage.style.transition + ', ' : '') + 'transform 0.35s cubic-bezier(0.2,0.7,0.3,1)');

    function apply() {
      raf = null;
      if (self._destroyed) return;
      var rect = self.el.getBoundingClientRect();
      if (rect.width < 2) return;
      var cx = mx - rect.left, cy = my - rect.top, on = active ? 1 : 0;
      if (self.curTilt) {
        var nx = cx / rect.width - 0.5, ny = cy / rect.height - 0.5;
        self._stage.style.transform = 'perspective(900px) rotateY(' + (nx * 13 * on).toFixed(2) + 'deg) rotateX(' + (-ny * 13 * on).toFixed(2) + 'deg)';
      }
      if (self.curGradient && self.fill === 'gradient') {
        var ang = Math.atan2(cy - rect.height / 2, cx - rect.width / 2) * 180 / Math.PI + 90;
        self._stage.style.setProperty('--kg-angle', ang.toFixed(1) + 'deg');
        self._stage.style.setProperty('--kg', Math.max(0, Math.min(1, cx / rect.width)).toFixed(3));
      }
      if ((self.curMagnetic || self.curSpotlight) && self._curUnits) {
        var R = Math.max(rect.width, rect.height) * 0.32;
        for (var i = 0; i < self._curUnits.length; i++) {
          var U = self._curUnits[i];
          var dx = U.cx - cx, dy = U.cy - cy, d = Math.sqrt(dx * dx + dy * dy) || 1;
          var f = on * Math.max(0, 1 - d / R), p = f * f * 26;
          var tx = self.curMagnetic ? (' translate(' + (dx / d * p).toFixed(1) + 'px,' + (dy / d * p).toFixed(1) + 'px)') : '';
          var op = self.curSpotlight ? (0.28 + 0.72 * f).toFixed(3) : null;
          for (var j = 0; j < U.els.length; j++) {
            if (self.curMagnetic) U.els[j].style.transform = U.rests[j] + tx;
            if (op !== null) U.els[j].style.opacity = op;
          }
        }
      }
    }
    function schedule() { if (!raf) raf = requestAnimationFrame(apply); }

    if (hoverable) {
      self._curMove = function (e) { active = true; mx = e.clientX; my = e.clientY; schedule(); };
      self._curLeave = function () { active = false; schedule(); };
      
      window.addEventListener('pointermove', self._curMove, { passive: true });
      document.addEventListener('mouseleave', self._curLeave, { passive: true });
    } else if (self.curTilt) {
      self._curOrient = function (e) {
        var rc = self.el.getBoundingClientRect();
        active = true;
        mx = rc.left + rc.width  * (0.5 + Math.max(-1, Math.min(1, (e.gamma || 0) / 28)) * 0.5);
        my = rc.top  + rc.height * (0.5 + Math.max(-1, Math.min(1, ((e.beta || 0) - 45) / 28)) * 0.5);
        schedule();
      };
      window.addEventListener('deviceorientation', self._curOrient, { passive: true });
    }
  };

  KineticBlock.prototype._stopCursorFX = function () {
    if (this._curMove) window.removeEventListener('mousemove', this._curMove);
    if (this._curLeave) document.removeEventListener('mouseleave', this._curLeave);
    if (this._curOrient) window.removeEventListener('deviceorientation', this._curOrient);
    this._curMove = this._curLeave = this._curOrient = null;
    this._cursorInit = false;
  };

  KineticBlock.prototype.updateCursorFX = function () {
    this.curMagnetic  = this.el.getAttribute('data-cursor-magnetic')  === '1';
    this.curSpotlight = this.el.getAttribute('data-cursor-spotlight') === '1';
    this.curGradient  = this.el.getAttribute('data-cursor-gradient')  === '1';
    this.curTilt      = this.el.getAttribute('data-cursor-tilt')      === '1';
    if (this.composition === 'discs') this.curTilt = false;
    if (this._stopCursorFX) this._stopCursorFX();
    this._resetCursorFX();
    this._cacheCursorLetters();
    this._startCursorFX();
  };

  KineticBlock.prototype._resetCursorFX = function () {
    var st = this._stage;
    if (!st) return;
    st.style.transform = '';
    var masks = st.querySelectorAll('.kp-char-mask');
    for (var i = 0; i < masks.length; i++) { masks[i].style.transform = ''; masks[i].style.opacity = ''; }
    
    if (this.fill === 'gradient' && !this.curGradient && this._lineEls && this._lineEls.length) {
      try { this._applyGradientScope(this._lineEls); } catch (e) {}
    }
  };

  KineticBlock.prototype._fillContainer = function () {
    if (this.el.style.height !== '100%') return; 
    
    var node = this.el;
    for (var i = 0; i < 4 && node && node.parentElement; i++) {
      var parent = node.parentElement;
      var pd;
      try { pd = (node.ownerDocument.defaultView || window).getComputedStyle(parent); }
      catch (e) { break; }
      node.style.flex = '1 1 0';
      node.style.minHeight = '0';
      node.style.alignSelf = 'stretch';
      if (pd.display.indexOf('flex') > -1 && pd.flexDirection === 'column') {
        break; 
      }
      node = parent;
    }
  };

  KineticBlock.prototype._setup = function () {
    this._fillContainer();
    
    this._stage = document.createElement('div');
    this._stage.className = 'impulse-kinetic-stage';
    
    this._stage.setAttribute('aria-hidden', 'true');
    var _alignItems = this.align === 'left' ? 'flex-start' : (this.align === 'right' ? 'flex-end' : 'center');

    var _stageInFlow = this.heightAuto && !this.asBackground
      && SCENE_COMPS.indexOf(this.composition) === -1;
    this._stage.style.cssText = _stageInFlow
      ? ('position:relative;width:100%;' +
         'display:flex;flex-direction:column;' +
         'align-items:' + _alignItems + ';justify-content:center;' +
         'padding:0;box-sizing:border-box;' +
         
         'flex:1 1 auto;' +
         'direction:ltr;text-align:' + this.align + ';' +
         'pointer-events:none;overflow:visible;' +
         'color:' + this.color + ';' +
         'font-family:' + this.fontStack + ';' +
         'font-weight:' + (this.kWeight || '800') + ';line-height:1;')
      : ('position:absolute;inset:0;' +
         'display:flex;flex-direction:column;' +
         'align-items:' + _alignItems + ';justify-content:center;' +
         'padding:0;box-sizing:border-box;' +
         'direction:ltr;text-align:' + this.align + ';' +
         'pointer-events:none;overflow:hidden;' +
         'color:' + this.color + ';' +
         'font-family:' + this.fontStack + ';' +
         'font-weight:' + (this.kWeight || '800') + ';line-height:1;');
    this.el.appendChild(this._stage);
  };

  function _kInjectGradCss() {
    if (typeof document === 'undefined') return;
    if (document.getElementById('impulse-kinetic-grad-css')) return;
    var st = document.createElement('style');
    st.id = 'impulse-kinetic-grad-css';
    
    st.textContent =
      '@property --kg-angle{syntax:"<angle>";inherits:true;initial-value:0deg;}' +
      '@property --kg{syntax:"<number>";inherits:true;initial-value:0;}' +
      '@keyframes kg-spin{to{--kg-angle:360deg;}}' +
      '@keyframes kg-roll{to{--kg:1;}}';
    (document.head || document.documentElement).appendChild(st);
  }

  function _kScreenEl(el) {
    if (!el || !el.closest) return null;
    var scr = el.closest('.impulse-screen');
    if (scr) return scr;
    var sec = el.closest('.impulse-el[data-type="section"]');
    while (sec) {
      var up = sec.parentElement && sec.parentElement.closest('.impulse-el[data-type="section"]');
      if (!up) break;
      sec = up;
    }
    return sec || null;
  }

  KineticBlock.prototype._classicSafetyNet = function (delay) {
    var self = this;
    _klog(self.el, 'safetyNet armed=' + !!self._safetyArmed);
    if (self._safetyArmed) return;          
    self._safetyArmed = true;

    var tryRun = function () {
      _klog(self.el, 'tryRun d=' + !!self._destroyed + ' s=' + !!self._shown + ' e=' + !!self._exiting + ' r=' + !!self._running);
      if (self._destroyed || self._shown || self._exiting || self._running) return false;
      var el = self.el;

      

      

      var vis = (typeof el.checkVisibility === 'function')
        ? el.checkVisibility({ visibilityProperty: true })
        : (el.offsetParent !== null);
      if (!vis) { _klog(self.el, 'tryRun !vis'); return false; }
      var r = el.getBoundingClientRect();
      var vh = window.innerHeight || 0, vw = window.innerWidth || 0;
      
      if (!(r.bottom > 1 && r.top < vh && r.right > 1 && r.left < vw && r.width > 1)) { _klog(self.el, 'tryRun !box t=' + Math.round(r.top) + ' b=' + Math.round(r.bottom)); return false; }
      if (el.offsetWidth > 0 && (r.width / el.offsetWidth) < 0.85) { _klog(self.el, 'tryRun !scale'); return false; }
      _klog(self.el, 'tryRun RUN');
      self._run();
      return true;
    };

    var stop = function () {
      if (self._safetyPoll) { clearTimeout(self._safetyPoll); self._safetyPoll = null; }
      if (self._safetyIO) { try { self._safetyIO.disconnect(); } catch (e) {} self._safetyIO = null; }
    };
    self._safetyStop = stop;

    var attempts = 0, maxAttempts = 16; 
    var poll = function () {
      self._safetyPoll = null;
      if (tryRun()) { stop(); return; }
      if (self._destroyed || self._shown) { stop(); return; }
      if (++attempts < maxAttempts) self._safetyPoll = setTimeout(poll, 500);
    };

    if (window.IntersectionObserver) {
      
      self._safetyIO = new IntersectionObserver(function (entries) {
        if (self._shown || self._destroyed) { stop(); return; }
        _klog(self.el, 'IO fire int=' + (entries[0] && entries[0].isIntersecting));
        if (!entries[0] || !entries[0].isIntersecting) return;
        if (tryRun()) { stop(); return; }
        
        attempts = 0;
        if (!self._safetyPoll) self._safetyPoll = setTimeout(poll, 400);
        
        var armedAnc = self.el.closest ? self.el.closest('.impulse-ovfx-armed') : null;
        if (armedAnc && !self._settleHook) {
          self._settleHook = true;
          armedAnc.addEventListener('impulse:ovfx-settled', function () {
            self._settleHook = false;
            _klog(self.el, 'settled hook');
            if (!self._shown && !self._destroyed && tryRun()) stop();
          }, { once: true });
        }
      }, { threshold: [0, 0.15] });
      self._safetyIO.observe(self.el);
    }

    self._safetyPoll = setTimeout(poll, delay || 700);
  };

  KineticBlock.prototype._startObserver = function () {
    var self = this;
    if (_isScreenMode()) {
      var sc = _kScreenEl(self.el);
      self._screenEl = sc || null;
      
      var _runtimeScreens = !!document.querySelector('.impulse-screen-wrapper');
      if (_runtimeScreens && sc) {
        if (sc.classList.contains('impulse-screen-active')) self._run();
        else self._classicSafetyNet(700); 
        return;
      }
      
      if (sc && window.MutationObserver) {
        
        var _entering = function () { return sc.classList.contains('impulse-screen-entering'); };
        var _active   = function () { return sc.classList.contains('impulse-screen-active'); };
        if (_entering() || _active()) { if (_active()) self._wasActive = true; self._run(); }
        self._screenMO = new MutationObserver(function () {
          if (_active()) self._wasActive = true;
          if (_entering() || _active()) {
            if (!self._shown && !self._exiting) self._run();
          } else if (self._wasActive && self._shown && !self._exiting) {
            
            self._pause();
            self._wasActive = false;
          }
        });
        self._screenMO.observe(sc, { attributes: true, attributeFilter: ['class'] });
        self._classicSafetyNet(600); 
        return;
      }
      
    }
    if (!window.IntersectionObserver) { self._run(); return; }
    self._io = new IntersectionObserver(function (entries) {
      var e = entries[0];
      if (e.isIntersecting && !self._shown && !self._exiting) self._run();
      else if (!e.isIntersecting && self._shown && !self._exiting) {
        if (self.scrollExit === 'spring' || self.scrollExit === 'fade') self._scrollExitAnim(self.scrollExit);
        else self._pause();
      }
    }, { threshold: [0, 0.15] });   
    self._io.observe(self.el);
  };

  KineticBlock.prototype._scrollExitAnim = function (style) {
    var self = this;
    if (self._exiting || !self._stage) { self._pause(); return; }
    self._exiting = true;
    var dur = _ms(style === 'spring' ? 520 : 620, self.speed);
    var kf  = (style === 'spring')
      ? [{ transform: 'translateY(0) scale(1)', opacity: 1 }, { transform: 'translateY(-14%) scale(0.9)', opacity: 0 }]
      : [{ transform: 'translateY(0)', opacity: 1 },          { transform: 'translateY(-8%)', opacity: 0 }];
    var ease = (style === 'spring') ? SPRING_OUT : 'ease-in-out';
    try { self._anims.push(self._stage.animate(kf, { duration: dur, easing: ease, fill: 'forwards' })); } catch (e) {}
    var t = setTimeout(function () {
      self._exiting = false;
      self._pause(); 
      
      if (self._screenEl && self._screenEl.classList.contains('impulse-screen-active')) self._run();
    }, dur + 40);
    self._timers.push(t);
  };

  function _ensureLeadCss() {
    if (_ensureLeadCss._done) return;
    var doc = document;
    if (doc.getElementById('impulse-kinetic-lead-css')) { _ensureLeadCss._done = true; return; }
    var st = doc.createElement('style');
    st.id = 'impulse-kinetic-lead-css';
    st.textContent =
      
      '.impulse-kinetic-lead .impulse-el:not(:has(.impulse-kinetic-block)):not(:has(section.impulse-frosted)){opacity:0 !important;transition:none;}' +
      
      '.impulse-kinetic-lead.impulse-kinetic-revealed .impulse-el:not(:has(.impulse-kinetic-block)):not(:has(section.impulse-frosted)){opacity:1 !important;transition:opacity 480ms ease-in-out;}';
    (doc.head || doc.documentElement).appendChild(st);
    _ensureLeadCss._done = true;
  }

  KineticBlock.prototype._leadGate = function () {
    var sc = this._screenEl;
    if (!sc || !this.leadScreen) return;
    _ensureLeadCss();
    if (this._leadTimer) { clearTimeout(this._leadTimer); this._leadTimer = null; }
    
    sc.classList.remove('impulse-kinetic-revealed');
    sc.classList.add('impulse-kinetic-lead');
  };
  
  KineticBlock.prototype._leadScheduleRelease = function () {
    if (!this._screenEl || !this.leadScreen) return;
    var self = this;
    if (this._leadTimer) clearTimeout(this._leadTimer);
    this._leadTimer = setTimeout(function () { self._leadRelease(); },
                                 Math.max(300, this._settleMs || 1500));
    this._timers.push(this._leadTimer);
  };
  KineticBlock.prototype._leadRelease = function () {
    var sc = this._screenEl;
    if (!sc) return;
    
    sc.classList.add('impulse-kinetic-revealed');
    var self = this;
    var t = setTimeout(function () {
      sc.classList.remove('impulse-kinetic-lead');
      sc.classList.remove('impulse-kinetic-revealed');
    }, 540);
    this._timers.push(t);
  };

  KineticBlock.prototype._run = function () {
    if (this._destroyed) return;
    
    _klog(this.el, '_run enter');
    if (this._holdQueued) { _klog(this.el, '_run: already queued'); return; }
    var selfH = this, armedSec = null;
    try {
      
      var secH = this.el.closest ? this.el.closest('.impulse-ovfx-armed') : null;
      if (secH) {
        var probe = this.el, hidden = false;
        for (var d = 0; probe && probe !== secH && d < 4; d++, probe = probe.parentElement) {
          if (parseFloat(getComputedStyle(probe).opacity) < 0.5) { hidden = true; break; }
        }
        if (hidden) armedSec = secH;
      }
    } catch (eC) {}
    if (window.__impHoldKinetic || armedSec) {
      this._holdQueued = true;
      _klog(this.el, '_run queue hold=' + !!window.__impHoldKinetic);
      var release = function () {
        if (!selfH._holdQueued) return;
        selfH._holdQueued = false;
        clearTimeout(selfH._holdTimer);
        selfH._run();
      };
      if (window.__impHoldKinetic) window.addEventListener('impulse:revealed', release, { once: true });
      if (armedSec) armedSec.addEventListener('impulse:ovfx-settled', release, { once: true });
      this._holdTimer = setTimeout(release, 2600);
      return;
    }
    
    if (this._running || this._shown) { _klog(this.el, '_run bail r=' + !!this._running + ' s=' + !!this._shown); return; }
    _klog(this.el, '_run PLAY');
    this._running = true;
    if (this.leadScreen) this._leadGate();   
    this._playOnce();      
    this._shown   = true;  
    if (this.leadScreen) this._leadScheduleRelease();
  };
  KineticBlock.prototype._pause = function () {
    _klog(this.el, '_pause');
    this._running = false;
    this._exiting = false;
    this._clearAll();
    
    if (this.leadScreen) this._leadGate();
  };
  KineticBlock.prototype._clearAll = function () {
    if (this._discOff) { try { this._discOff(); } catch (e) {} this._discOff = null; }
    this._shown = false;
    
    this._holdQueued = false;
    clearTimeout(this._holdTimer);
    this._anims.forEach(function (a) { try { a.cancel(); } catch (e) {} });
    this._anims = [];
    this._timers.forEach(clearTimeout);
    this._timers = [];
    if (this._stage) {
      this._stage.innerHTML = '';
      
      this._stage.style.perspective = '';
      this._stage.style.perspectiveOrigin = '';
      this._stage.style.clipPath = '';
      this._stage.style.webkitClipPath = '';
      
      this._stage.style.webkitMaskImage = '';
      this._stage.style.maskImage = '';
      
      this._stage.style.transform = '';
      this._stage.style.opacity = '';
      
      this._stage.style.overflow = '';
      this.el.style.overflow = '';
      this._stage.style.minHeight = '';
    }
  };

  KineticBlock.prototype._playOnce = function () {
    var self = this;
    self._clearAll();
    self.maxWidth = self._pickMaxWidth(); 
    
    var _el = self.el;
    self.speed       = self._devNum('speed', parseFloat(_el.getAttribute('data-speed') || '1'));
    self.intensity   = self._devNum('intensity', parseFloat(_el.getAttribute('data-intensity') || '1'));
    self.lineGap     = self._devNum('line-gap', parseFloat(_el.getAttribute('data-line-gap') || '0'));
    self.compScale   = (function () {
      var sz = self._devNum('comp-size', parseFloat(_el.getAttribute('data-comp-size')));
      if (isFinite(sz) && sz > 0) return sz / 5;
      return self._devNum('comp-scale', parseFloat(_el.getAttribute('data-comp-scale') || '1'));
    })();
    self.cylDiameter = self._devNum('cyl-diameter', parseFloat(_el.getAttribute('data-cyl-diameter') || '70'));
    self.cubeSize    = self._devNum('cube-size', parseFloat(_el.getAttribute('data-cube-size') || '55'));
    self.cubeStyle   = (_el.getAttribute('data-cube-style') || 'faces').toLowerCase();
    self.cubeMono    = _el.getAttribute('data-cube-mono') === '1';
    self.compFont    = Math.max(0, self._devNum('comp-font', parseFloat(_el.getAttribute('data-comp-font') || '0')) || 0);
    
    self.discInk     = (_el.getAttribute('data-disc-ink') || '').trim();
    self.discFont    = Math.max(0, self._devNum('disc-font', parseFloat(_el.getAttribute('data-disc-font') || '0')) || 0);
    if (!(self.discFont > 0)) self.discFont = 30;
    self.kWeight     = (_el.getAttribute('data-kinetic-weight') || '').trim();
    self.echoCount   = Math.max(2, Math.min(16, parseInt(_el.getAttribute('data-echo-count') || '5', 10) || 5));
    self.gradSpeed   = self._devNum('grad-speed', parseFloat(_el.getAttribute('data-grad-speed') || '1'));
    if (!isFinite(self.speed) || self.speed <= 0) self.speed = 1;
    if (!isFinite(self.intensity) || self.intensity <= 0) self.intensity = 1;
    if (!isFinite(self.lineGap)) self.lineGap = 0;
    if (!isFinite(self.compScale) || self.compScale <= 0) self.compScale = 1;
    if (!isFinite(self.cylDiameter) || self.cylDiameter <= 0) self.cylDiameter = 70;
    if (!isFinite(self.cubeSize) || self.cubeSize <= 0) self.cubeSize = 55;
    if (!isFinite(self.gradSpeed) || self.gradSpeed <= 0) self.gradSpeed = 1;
    
    self._lastW = self.el.offsetWidth;
    self._lastH = self.el.offsetHeight;

    if (['glitchloop', 'echo', 'typepulse', 'tide', 'discs', 'curtain', 'helix', 'cube', 'cylinder', 'wiper']
          .indexOf(self.composition) !== -1 && self._stage) {

      var _isBgBlock = false;
      try { _isBgBlock = getComputedStyle(self.el).position === 'absolute'; } catch (e) {}
      if (!_isBgBlock && (self.el.clientHeight || 0) < 40) {
        var _fMinH = 0;
        try { _fMinH = parseFloat(getComputedStyle(self.el).minHeight) || 0; } catch (e) {}
        if (_fMinH < 40) self.el.style.minHeight = '480px';
      }
      if ((self._stage.offsetHeight || 0) < 40 && (self.el.clientHeight || 0) < 40) {
        self._stage.style.minHeight = '480px';
      }
    }

    var comp = COMPOSITIONS[self.composition] || COMPOSITIONS['block-slam'];

    var useCustom = !!(self.customMode && self.customLines && self.customLines.length &&
                       self.customLines.some(function(cl){ return cl && (cl.text || '').trim(); }));

    if (!useCustom && comp && comp.continuous && self.composition === 'cylinder' &&
        typeof self._playCylinder === 'function') {
      self._playCylinder();
      return;
    }
    
    if (!useCustom && SCENE_COMPS.indexOf(self.composition) !== -1) self._sceneRemeasure();

    if (!useCustom && self.composition === 'arc' && typeof self._playArc === 'function') {
      self._playArc();
      return;
    }
    if (!useCustom && self.composition === 'slide' && typeof self._playSlide === 'function') {
      self._playSlide();
      return;
    }
    if (!useCustom && self.composition === 'brutal' && typeof self._playBrutal === 'function') {
      self._playBrutal();
      return;
    }
    if (!useCustom && self.composition === 'sweep' && typeof self._playSweep === 'function') {
      self._playSweep();
      return;
    }
    if (!useCustom && self.composition === 'cube' && typeof self._playCube === 'function') {
      self._playCube();
      return;
    }
    if (!useCustom && self.composition === 'glitchloop' && typeof self._playGlitch === 'function') {
      self._playGlitch();
      return;
    }
    if (!useCustom && self.composition === 'echo' && typeof self._playEcho === 'function') {
      self._playEcho();
      return;
    }
    if (!useCustom && self.composition === 'curtain' && typeof self._playCurtain === 'function') {
      self._playCurtain();
      return;
    }
    if (!useCustom && self.composition === 'typepulse' && typeof self._playTypePulse === 'function') {
      self._playTypePulse();
      return;
    }
    if (!useCustom && self.composition === 'wiper' && typeof self._playWiper === 'function') {
      self._playWiper();
      return;
    }
    if (!useCustom && self.composition === 'tide' && typeof self._playTide === 'function') {
      self._playTide();
      return;
    }
    if (!useCustom && self.composition === 'discs' && typeof self._playDiscs === 'function') {
      self._playDiscs();
      return;
    }
    if (!useCustom && self.composition === 'helix' && typeof self._playHelix === 'function') {
      self._playHelix();
      return;
    }
    
    var hasCustomText = self.customMode &&
                        Array.isArray(self.customLines) &&
                        self.customLines.some(function(cl){ return cl && (cl.text || '').trim(); });
    if (!hasCustomText && (!self.lines.length || !comp.lines.length)) {
      self._stage.innerHTML =
        '<span style="font-size:64px;opacity:0.18;letter-spacing:0.02em">Kinetic</span>';
      self._running = false;
      return;
    }

    var AUTO_EXTEND_POOL = [
      { enter: 'bounce-slide-split', exit: 'glide-to-r',   target: 'word',   stagger: 'sequential' },
      { enter: 'letter-kick-in',     exit: 'spacing-out',  target: 'letter', stagger: 'sequential' },
      { enter: 'rise',               exit: 'rise-out',     target: 'letter', stagger: 'sequential' },
      { enter: 'drop',               exit: 'drop-out',     target: 'letter', stagger: 'sequential' },
      { enter: 'glide-from-l',       exit: 'glide-to-l',   target: 'word',   stagger: 'sequential' },
      { enter: 'glide-from-r',       exit: 'glide-to-r',   target: 'word',   stagger: 'sequential' },
      { enter: 'zoom-in',            exit: 'zoom-out',     target: 'whole',  stagger: 'simultaneous' },
      { enter: 'blur-in',            exit: 'blur-out',     target: 'whole',  stagger: 'simultaneous' },
      { enter: 'spacing-in',         exit: 'spacing-out',  target: 'whole',  stagger: 'simultaneous' },
      { enter: 'wipe-right',         exit: 'wipe-right-out',target:'word',   stagger: 'sequential' }
    ];

    var maxN, slots, texts, compSlots, compSlotCount;

    self._useCustom = useCustom;
    if (useCustom) {
      var customN = Math.min(4, self.customLines.length);
      maxN = customN;
      slots = [];
      texts = [];
      var compDuration = 5500;
      var entryStaggerMs = 700;
      var exitStaggerMs  = 100;
      var exitAtBase     = compDuration - 800;
      for (var ci = 0; ci < customN; ci++) {
        var cl = self.customLines[ci] || {};
        var motion = cl.motion || 'rise';
        var exitMotion = cl.exit_motion || AUTO_EXIT_PAIRS[motion] || 'fade-out';
        var tgt    = cl.target  || AUTO_TARGET[motion] || 'letter';
        
        var _enterDur = (MOTIONS[motion] && MOTIONS[motion].duration) || 650;
        var _exitDur  = (MOTIONS[exitMotion] && MOTIONS[exitMotion].duration) || 500;
        var slScale = parseFloat(cl.scale);
        if (!isFinite(slScale) || slScale <= 0) slScale = 1.0;
        var slPx = parseFloat(cl.px);
        if (!isFinite(slPx) || slPx <= 0) slPx = 0; 
        slots.push({
          role:  'custom',
          scale: slScale,
          px:    slPx,
          font:  cl.font   || '',
          weight: cl.weight || '',
          color: cl.color  || '',
          enter: {
            motion:  motion,
            target:  tgt,
            stagger: cl.stagger || 'sequential',
            at:      (cl.at  != null) ? cl.at  : ci * entryStaggerMs,
            dur:     cl.dur != null ? cl.dur : _enterDur
          },
          exit: {
            motion:  exitMotion,
            target:  tgt,
            stagger: cl.stagger || 'sequential',
            at:      (cl.exit_at != null) ? cl.exit_at : exitAtBase + ci * exitStaggerMs,
            dur:     cl.exit_dur != null ? cl.exit_dur : _exitDur
          }
        });
        var txt = (cl.text || '').trim();
        txt = _bindConnectors(txt);   
        texts.push({ text: txt, words: txt.match(_kWordRe) || [] });
      }
      compSlots     = [];
      compSlotCount = 0;
    } else {
      maxN          = Math.min(4, self.lines.length);
      compSlots     = comp.lines || [];
      compSlotCount = compSlots.length;
      slots         = [];
    }

    if (!useCustom) {
      var usedMotionsForPool = {};
      for (var cii = 0; cii < Math.min(compSlotCount, maxN); cii++) {
        if (compSlots[cii].enter && compSlots[cii].enter.motion) {
          usedMotionsForPool[compSlots[cii].enter.motion] = true;
        }
      }

      for (var si = 0; si < maxN; si++) {
        if (si < compSlotCount) {
          slots.push(compSlots[si]);
        } else {
          var lastDefined = compSlots[compSlotCount - 1] || { enter: { at: 0 }, exit: { at: 4500 } };
          var stepsBeyond = si - compSlotCount + 1;
          var available = AUTO_EXTEND_POOL.filter(function (m) {
            return !usedMotionsForPool[m.enter];
          });
          if (!available.length) available = AUTO_EXTEND_POOL;
          var pick = available[0];

          var baseEnterAt = (lastDefined.enter && lastDefined.enter.at) || 0;
          var baseExitAt  = (lastDefined.exit  && lastDefined.exit.at)  || 4500;
          slots.push({
            role:  'label',
            scale: 1.0,
            enter: {
              motion:  pick.enter,
              target:  pick.target,
              stagger: pick.stagger,
              at:      baseEnterAt + stepsBeyond * 800,
              dur:     600
            },
            exit: {
              motion:  pick.exit,
              target:  pick.target,
              stagger: pick.stagger,
              at:      Math.max(0, baseExitAt - stepsBeyond * 100),
              dur:     500
            }
          });
          usedMotionsForPool[pick.enter] = true;
        }
      }
      texts = self.lines.slice(0, maxN);
    }

    var stageH    = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW    = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    
    self._stage.style.perspective = Math.round(stageW * 1.4) + 'px';
    self._stage.style.perspectiveOrigin = '50% 50%';
    var divisor, heroFont;
    if (self.heightAuto) {
      
      divisor  = 1;
      
      heroFont = Math.min(64, stageW * 0.16) * self.compScale;
      if (self.compFont > 0) heroFont = self.compFont;   
    } else if (useCustom) {
      
      var sumScales = 0, _pxBudgetH = 0;
      for (var ss = 0; ss < slots.length; ss++) {
        var _sp = parseFloat(slots[ss].px);
        if (isFinite(_sp) && _sp > 0) { _pxBudgetH += _sp * 1.15; continue; }
        var s_scale = parseFloat(slots[ss].scale);
        if (!isFinite(s_scale) || s_scale <= 0) s_scale = 1;
        sumScales += s_scale;
      }
      divisor  = sumScales > 0 ? sumScales : 1;
      var _relBudgetH = Math.max(40, stageH * 0.9 - _pxBudgetH);
      heroFont = Math.min(_relBudgetH / (divisor * 1.15), stageW * 0.16);
      if (self.compFont > 0) heroFont = self.compFont;   
    } else {
      divisor  = slots.length || 1; 
      
      heroFont = Math.min(stageH * 0.9 / (divisor * 1.15), stageW * 0.16 * self.compScale);
      if (self.compFont > 0) heroFont = self.compFont;   
    }

    var lineEls = [];
    slots.forEach(function (slot, idx) {
      var tx = texts[idx];
      if (!tx) return;
      var le = self._buildLine(tx, slot, heroFont, idx);
      self._stage.appendChild(le);
      lineEls.push({ el: le, slot: slot });
    });

    var _gapPx = Math.round((self.lineGap / 100) * heroFont * 0.6);
    if (_gapPx) {
      for (var _gi = 1; _gi < lineEls.length; _gi++) {
        lineEls[_gi].el.style.marginTop = _gapPx + 'px';
      }
    }

    if (lineEls.length) {
      void self._stage.offsetWidth; 
      var _pxH = 0, _relH = 0, _relWidest = 0, _relEls = [];
      
      var _gbScale = (function () {
        var sr = self._stage.getBoundingClientRect();
        var ow = self._stage.offsetWidth || 0;
        var s = (ow > 0) ? (sr.width / ow) : 1;
        return (s > 0) ? s : 1;
      })();
      lineEls.forEach(function (le) {
        var h = le.el.offsetHeight;
        if (le.slot && parseFloat(le.slot.px) > 0) { _pxH += h; return; }
        _relH += h;
        _relEls.push(le);
        
        var kids = le.el.children;
        if (kids.length) {
          var w = (kids[kids.length - 1].getBoundingClientRect().right - kids[0].getBoundingClientRect().left) / _gbScale;
          if (w > _relWidest) _relWidest = w;
        }
      });
      if (_relEls.length) {
        var _gaps   = _gapPx * Math.max(0, lineEls.length - 1);
        var budgetH = stageH * 0.90;
        var budgetW = stageW * 0.92;
        var _relRoom = Math.max(20, budgetH - _pxH - _gaps); 
        
        var fitH = self.heightAuto ? 1 : ((_relH > _relRoom && _relH > 0) ? _relRoom / _relH : 1);

        var fitW = (self.maxWidth > 0) ? 1 : ((_relWidest > budgetW && _relWidest > 0) ? budgetW / _relWidest : 1);
        var fit  = Math.min(fitH, fitW);
        if (fit < 1) {
          _relEls.forEach(function (le) {
            var cur = parseFloat(le.el.style.fontSize) || 0;
            if (cur > 0) le.el.style.fontSize = Math.max(8, Math.round(cur * fit)) + 'px';
          });
        }
      }

      var _safeW = stageW * 0.92;
      void self._stage.offsetWidth; 

      if (!self.maxWidth) lineEls.forEach(function (le) {
        if (le.slot && parseFloat(le.slot.px) > 0) {
          
          var _cw = le.el.clientWidth, _sw = le.el.scrollWidth;
          if (_sw > _cw + 1 && _cw > 0) {
            var _cp = parseFloat(le.el.style.fontSize) || 0;
            if (_cp > 0) le.el.style.fontSize = Math.max(8, Math.floor(_cp * (_cw / _sw))) + 'px';
          }
          return;
        }
        var kids = le.el.children;
        if (!kids.length) return;
        var w = (kids[kids.length - 1].getBoundingClientRect().right -
                kids[0].getBoundingClientRect().left) / _gbScale;
        if (w > _safeW && w > 0) {
          var cur = parseFloat(le.el.style.fontSize) || 0;
          if (cur > 0) le.el.style.fontSize = Math.max(8, Math.floor(cur * (_safeW / w))) + 'px';
        }
      });
      
      if (self.el._kHoldMinH) { self.el.style.minHeight = self.el._kOrigMinH || ''; self.el._kHoldMinH = false; }
      
      if (self.heightAuto) {
        self._lastW = self.el.offsetWidth;
        self._lastH = self.el.offsetHeight;
      }
    }

    if (self.fill === 'gradient' && lineEls.length) self._applyGradientScope(lineEls);

    self._lineEls = lineEls;
    self._cacheCursorLetters();
    self._startCursorFX();

    var maxEnd = 0;
    var maxEnterEnd = 0;   
    var _kCycle = (useCustom && self.cycle && lineEls.length > 1);
    if (_kCycle) {
      
      self._stage.style.display    = 'grid';
      
      self._stage.style.alignItems   = 'center';
      var _hAlign = self.align === 'left' ? 'start'
                  : (self.align === 'right' ? 'end' : 'center');
      self._stage.style.justifyItems = _hAlign;
      
      self._stage.style.justifyContent = _hAlign;
      var _holdBase = 2200;   
      var _tBase = 0;
      lineEls.forEach(function (le, i) {
        le.el.style.gridArea = '1 / 1';
        var _en = le.slot.enter || {}, _ex = le.slot.exit || {};
        var _enterDurBase = _en.dur || ((MOTIONS[_en.motion] || {}).duration) || 650;
        var _exitDurBase  = _ex.dur || ((MOTIONS[_ex.motion] || {}).duration) || 500;
        self._schedule(le.el, { motion: _en.motion, target: _en.target, stagger: _en.stagger, dur: _en.dur, at: _tBase });
        if (i === 0) maxEnterEnd = _ms(_tBase + _enterDurBase, self.speed); 
        var _exitAt = _tBase + _enterDurBase + _holdBase;
        self._schedule(le.el, { motion: _ex.motion, target: _ex.target, stagger: _ex.stagger, dur: _ex.dur, at: _exitAt });
        _tBase = _exitAt + _exitDurBase + 300; 
      });
      maxEnd = _ms(_tBase, self.speed);
    } else {
      lineEls.forEach(function (le) {
        var endEnter = self._schedule(le.el, le.slot.enter);
        if (endEnter > maxEnd) maxEnd = endEnter;
        if (endEnter > maxEnterEnd) maxEnterEnd = endEnter;
        
        if (self.loop) {
          var endExit = self._schedule(le.el, le.slot.exit);
          if (endExit > maxEnd) maxEnd = endExit;
        }
      });
    }

    if (comp.decor && comp.decor.length) {
      
      void self._stage.offsetWidth;
      var stageRect = self._stage.getBoundingClientRect();
      comp.decor.forEach(function (dc) {
        if (!dc || !dc.shape) return;
        var shape = DECOR_SHAPES[dc.shape];
        if (!shape) return;
        
        var attachRect;
        if (dc.attach === 'stage' || dc.attach === 'all') {
          attachRect = stageRect;
        } else {
          var lineIdx = (dc.attach != null) ? dc.attach : 0;
          var lineEntry = lineEls[lineIdx];
          if (!lineEntry) return;
          attachRect = lineEntry.el.getBoundingClientRect();
        }
        var decorEl  = self._buildDecor(shape, attachRect, stageRect, dc);
        if (!decorEl) return;
        
        self._applyDecorInitial(decorEl, shape, dc.enter);
        self._stage.appendChild(decorEl);
        var dEnd  = self._scheduleDecor(decorEl, shape, dc.enter);
        if (dEnd  > maxEnd) maxEnd = dEnd;
        if (dEnd  > maxEnterEnd) maxEnterEnd = dEnd;
        
        if (self.loop) {
          var dExit = self._scheduleDecor(decorEl, shape, dc.exit);
          if (dExit > maxEnd) maxEnd = dExit;
        }
      });
    }

    var totalDur = Math.max(_ms(comp.duration, self.speed), maxEnd);

    self._settleMs = Math.max(300, maxEnterEnd + 120);

    var tDone = setTimeout(function () {
      if (self._destroyed) return;
      if (self.loop || _kCycle) self._playOnce();
      else self._running = false;
    }, totalDur + 200);
    self._timers.push(tDone);
  };

  KineticBlock.prototype._playCylinder = function () {
    var self = this;

    var srcLines = (self.lines || []).map(function (l) { return (l && l.text || '').trim(); }).filter(Boolean);   
    if (self.customMode && Array.isArray(self.customLines) && self.customLines.length) {
      var cl = self.customLines
        .map(function (c) { return (c && c.text || '').trim(); })
        .filter(Boolean);
      if (cl.length) srcLines = cl;
    }
    srcLines = srcLines.slice(0, 4); 
    if (!srcLines.length) {
      self._stage.innerHTML =
        '<span style="font-size:64px;opacity:0.18;letter-spacing:0.02em">Kinetic</span>';
      self._running = false;
      return;
    }

    var numLines = srcLines.length;
    var repeats  = Math.ceil(6 / numLines);
    var N        = numLines * repeats; 

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var ix     = self.intensity || 1;

    var refDim   = Math.min(stageW, stageH);
    var diaPct   = (this.cylDiameter > 0 ? this.cylDiameter : 70) / 100;
    var R        = refDim * (diaPct / 2) * (0.96 + ix * 0.04);    
    var h        = Math.max(16, Math.round(2 * R * Math.sin(Math.PI / N))); 
    var apothem  = Math.round(R * Math.cos(Math.PI / N));         
    
    var fontSize = Math.max(12, Math.round(h * 0.82));
    var _budgetW = stageW * 0.86;
    var _meas = document.createElement('span');
    _meas.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:nowrap;' +
      'visibility:hidden;font-weight:800;line-height:1;font-size:' + fontSize + 'px;';
    self._stage.appendChild(_meas);
    var _widest = 0;
    for (var _li = 0; _li < srcLines.length; _li++) {
      _meas.textContent = srcLines[_li];
      if (_meas.offsetWidth > _widest) _widest = _meas.offsetWidth;
    }
    if (_meas.parentNode) _meas.parentNode.removeChild(_meas);
    if (_widest > _budgetW && _widest > 0) {
      fontSize = Math.max(12, Math.floor(fontSize * (_budgetW / _widest)));
    }

    self._stage.style.perspective = Math.round(stageW * 1.2) + 'px';
    self._stage.style.perspectiveOrigin = '50% 24%';

    var _cylFade = 'linear-gradient(to bottom,'
                 + 'rgba(0,0,0,0) 5%,'
                 + 'rgba(0,0,0,0.30) 20%,'
                 + 'rgba(0,0,0,0.60) 33%,'
                 + 'rgba(0,0,0,1) 43%,'
                 + 'rgba(0,0,0,1) 57%,'
                 + 'rgba(0,0,0,0.60) 67%,'
                 + 'rgba(0,0,0,0.30) 80%,'
                 + 'rgba(0,0,0,0) 95%)';
    self._stage.style.webkitMaskImage = _cylFade;
    self._stage.style.maskImage = _cylFade;

    var scaleWrap = document.createElement('div');
    scaleWrap.style.cssText =
      'position:absolute;inset:0;transform-style:preserve-3d;will-change:transform,opacity;';
    var ring = document.createElement('div');
    ring.style.cssText =
      'position:absolute;inset:0;transform-style:preserve-3d;will-change:transform;';

    for (var i = 0; i < N; i++) {
      var face = document.createElement('div');
      
      var angle = -(360 / N) * i;
      face.textContent = srcLines[i % numLines];
      face.style.cssText =
        'position:absolute;left:0;width:100%;top:50%;height:' + h + 'px;' +
        'display:flex;align-items:center;justify-content:' + _alignFlex(self.align) + ';' +
        'transform:translateY(-50%) rotateX(' + angle + 'deg) translateZ(' + apothem + 'px);' +
        'backface-visibility:hidden;white-space:nowrap;overflow:hidden;' +
        'font-size:' + fontSize + 'px;line-height:1;font-weight:800;' +
        
        'color:' + self._lineInk(i % numLines) + ';will-change:transform;';
      self._gradApply(face);
      ring.appendChild(face);
    }

    scaleWrap.appendChild(ring);
    self._stage.appendChild(scaleWrap);

    var dur      = _ms((COMPOSITIONS.cylinder && COMPOSITIONS.cylinder.duration) || 8000, self.speed); 
    var spinUpMs = _ms(1400, self.speed);
    var scaleMs  = _ms(1100, self.speed);

    var restAngle = self.loop ? 0 : (360 / N);
    try {
      scaleWrap.style.transform = 'scale(1.9)';
      scaleWrap.style.opacity = '0';
      self._anims.push(scaleWrap.animate(
        [{ transform: 'scale(1.9)', opacity: 0 },
         { opacity: 1, offset: 0.35 },
         { transform: 'scale(1)', opacity: 1 }],
        { duration: scaleMs, easing: 'cubic-bezier(.16,1,.3,1)', fill: 'forwards' }
      ));
    } catch (e) {}
    try {
      
      self._anims.push(ring.animate(
        [{ transform: 'rotateX(' + (restAngle - 540) + 'deg)' },
         { transform: 'rotateX(' + restAngle + 'deg)' }],
        { duration: spinUpMs, easing: 'cubic-bezier(.1,.85,.2,1)', fill: 'forwards' }
      ));
    } catch (e) {}
    
    if (self.loop) {
      var _loopT = setTimeout(function () {
        if (self._destroyed || !self._running) return;
        try {
          self._anims.push(ring.animate(
            [{ transform: 'rotateX(0deg)' }, { transform: 'rotateX(360deg)' }],
            { duration: dur, iterations: Infinity, easing: 'linear' }
          ));
        } catch (e) {}
      }, spinUpMs);
      self._timers.push(_loopT);
    }

    self._running = true;
  };

  KineticBlock.prototype._playCube = function () {
    var self = this;

    var srcLines = (self.lines || []).map(function (l) { return (l && l.text || '').trim(); }).filter(Boolean);   
    if (self.customMode && Array.isArray(self.customLines) && self.customLines.length) {
      var cl = self.customLines
        .map(function (c) { return (c && c.text || '').trim(); })
        .filter(Boolean);
      if (cl.length) srcLines = cl;
    }
    srcLines = srcLines.slice(0, 6); 
    if (!srcLines.length) {
      self._stage.innerHTML =
        '<span style="font-size:64px;opacity:0.18;letter-spacing:0.02em">Kinetic</span>';
      self._running = false;
      return;
    }

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var sizePct = (self.cubeSize > 0 ? self.cubeSize : 55) / 100;
    var E    = Math.max(60, Math.round(Math.min(stageW, stageH) * sizePct)); 
    var tile = E / 3;

    function _pc(c) {
      c = (c || '').trim(); var m;
      if ((m = /^#([0-9a-f]{3})$/i.exec(c)))  return [parseInt(m[1].charAt(0), 16) * 17, parseInt(m[1].charAt(1), 16) * 17, parseInt(m[1].charAt(2), 16) * 17];
      if ((m = /^#([0-9a-f]{6})/i.exec(c)))   return [parseInt(m[1].substr(0, 2), 16), parseInt(m[1].substr(2, 2), 16), parseInt(m[1].substr(4, 2), 16)];
      if ((m = /^rgba?\(([^)]+)\)/i.exec(c))) { var p = m[1].split(','); return [parseFloat(p[0]) || 0, parseFloat(p[1]) || 0, parseFloat(p[2]) || 0]; }
      return null;
    }
    function _mixc(rgb, tgt, t) {
      var o = [];
      for (var i = 0; i < 3; i++) o.push(Math.round(rgb[i] + (tgt[i] - rgb[i]) * t));
      return 'rgb(' + o.join(',') + ')';
    }
    var _rgb = _pc(self.color) || [255, 255, 255];
    var _lum = (0.299 * _rgb[0] + 0.587 * _rgb[1] + 0.114 * _rgb[2]) / 255;
    var tileCol, tileColB, textCol, bodyCol;
    if (_lum >= 0.5) {           
      tileCol  = 'rgb(16,17,20)';
      tileColB = 'rgb(30,32,37)';
      textCol  = self.color;
      bodyCol  = 'rgb(0,0,0)';
    } else {                     
      
      tileCol  = _mixc(_rgb, [255, 255, 255], 0.08 + (1 - _lum) * 0.14);
      tileColB = _mixc(_rgb, [255, 255, 255], 0.24 + (1 - _lum) * 0.22);
      textCol  = '#f5f5f5';
      bodyCol  = _mixc(_rgb, [0, 0, 0], 0.55);
    }

    self._stage.style.perspective = Math.round(Math.max(stageW, stageH) * 1.5) + 'px';
    self._stage.style.perspectiveOrigin = '50% 42%';
    var scaleWrap = document.createElement('div');
    scaleWrap.style.cssText = 'position:absolute;inset:0;transform-style:preserve-3d;will-change:transform,opacity;';
    var tumble = document.createElement('div');
    tumble.style.cssText = 'position:absolute;inset:0;transform-style:preserve-3d;will-change:transform;';
    var cubeEl = document.createElement('div');
    cubeEl.style.cssText = 'position:absolute;inset:0;transform-style:preserve-3d;';
    tumble.appendChild(cubeEl);
    scaleWrap.appendChild(tumble);
    self._stage.appendChild(scaleWrap);

    var FACES = [
      { n: [0, 0, 1],  place: 'rotateY(0deg)',    cr: function (p) { return [p[0] + 1, p[1] + 1]; } },  
      { n: [0, 0, -1], place: 'rotateY(180deg)',  cr: function (p) { return [1 - p[0], p[1] + 1]; } },  
      { n: [1, 0, 0],  place: 'rotateY(90deg)',   cr: function (p) { return [1 - p[2], p[1] + 1]; } },  
      { n: [-1, 0, 0], place: 'rotateY(-90deg)',  cr: function (p) { return [p[2] + 1, p[1] + 1]; } },  
      { n: [0, -1, 0], place: 'rotateX(90deg)',   cr: function (p) { return [p[0] + 1, p[2] + 1]; } },  
      { n: [0, 1, 0],  place: 'rotateX(-90deg)',  cr: function (p) { return [p[0] + 1, 1 - p[2]]; } }   
    ];

    var RUBIK = ['#009b48', '#0046ad', '#c41e3a', '#ff5800', '#ffffff', '#ffd500'];

    function _rubikInk(hex) {
      var c = _pc(hex) || [0, 0, 0];
      return ((0.299 * c[0] + 0.587 * c[1] + 0.114 * c[2]) / 255) >= 0.55 ? '#1d2327' : '#ffffff';
    }

    var _faceFont = [];
    var _fm = document.createElement('div');
    _fm.style.cssText = 'position:absolute;left:-9999px;top:-9999px;width:' + Math.round(E * 0.84) + 'px;' +
      'visibility:hidden;font-weight:800;line-height:1.06;letter-spacing:0.01em;word-break:normal;';
    self._stage.appendChild(_fm);
    
    var _faceStack = srcLines.join(String.fromCharCode(10));
    _fm.style.whiteSpace = 'pre-line';
    for (var fi = 0; fi < 6; fi++) {
      var base = Math.round(E * 0.22);
      _fm.style.fontSize = base + 'px';
      _fm.textContent = _faceStack;
      var sw = _fm.scrollWidth, sh = _fm.scrollHeight, cap = E * 0.84;
      var f = base;
      if (sh > cap) f = Math.floor(base * cap / sh);
      if (sw > cap) f = Math.min(f, Math.floor(base * cap / sw));
      _faceFont.push(Math.max(10, f));
    }
    if (_fm.parentNode) _fm.parentNode.removeChild(_fm);

    var _chars = srcLines.join('').replace(/\s+/g, '').split('');
    var _tileSeq = 0;

    function _faceText(fi, ink) {
      var d = document.createElement('div');
      d.style.cssText = 'position:absolute;left:0;top:0;width:' + E + 'px;height:' + E + 'px;' +
        'display:flex;align-items:center;justify-content:center;text-align:center;' +
        'font-size:' + _faceFont[fi] + 'px;font-weight:800;line-height:1.06;letter-spacing:0.01em;' +
        'color:' + (ink || textCol) + ';padding:' + Math.round(E * 0.08) + 'px;box-sizing:border-box;' +
        
        'white-space:pre-line;';
      d.textContent = _faceStack;
      return d;
    }

    var cubies = [];
    var gap = Math.max(1.5, tile * 0.045);       
    var rad = Math.round(tile * 0.1);            
    function matCss(m) {                          
      return 'matrix3d(' + m[0][0] + ',' + m[1][0] + ',' + m[2][0] + ',0,' +
                           m[0][1] + ',' + m[1][1] + ',' + m[2][1] + ',0,' +
                           m[0][2] + ',' + m[1][2] + ',' + m[2][2] + ',0,0,0,0,1)';
    }
    function applyT(c) {
      c.el.style.transform = 'translate3d(' + (c.pos[0] * tile) + 'px,' + (c.pos[1] * tile) + 'px,' + (c.pos[2] * tile) + 'px) ' + matCss(c.orient);
    }

    for (var cx = -1; cx <= 1; cx++) for (var cy = -1; cy <= 1; cy++) for (var cz = -1; cz <= 1; cz++) {
      if (cx === 0 && cy === 0 && cz === 0) continue;
      var cel = document.createElement('div');
      cel.style.cssText = 'position:absolute;left:50%;top:50%;width:' + tile + 'px;height:' + tile + 'px;' +
        'margin-left:' + (-tile / 2) + 'px;margin-top:' + (-tile / 2) + 'px;transform-style:preserve-3d;';
      var pos = [cx, cy, cz];
      for (var ff = 0; ff < 6; ff++) {
        var F = FACES[ff];
        var ax = F.n[0] !== 0 ? 0 : (F.n[1] !== 0 ? 1 : 2);
        var outward = (pos[ax] === F.n[ax]);
        
        var face = document.createElement('div');
        face.style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;' +
          'transform:' + F.place + ' translateZ(' + (tile / 2) + 'px);' +
          'backface-visibility:hidden;overflow:hidden;box-sizing:border-box;' +
          'background:' + bodyCol + ';';
        if (outward) {
          var sticker = document.createElement('div');
          sticker.style.cssText = 'position:absolute;inset:' + gap + 'px;overflow:hidden;' +
            'background:' + tileCol + ';border-radius:' + rad + 'px;';
          if (self.cubeStyle === 'tiles') {
            var seed = ((_tileSeq++) * 2654435761) >>> 0;
            
            var _front = (F.n[2] === 1 && pos[2] === 1);
            var _fi    = _front ? ((cy + 1) * 3 + (cx + 1)) : -1;
            var _spell = _front && _fi < _chars.length;
            var blank  = !_chars.length || (!_spell && (seed % 100) < 38);
            
            if (self.cubeMono) {
              if (((seed >> 4) & 1) === 1) sticker.style.background = tileColB;
            } else {
              
              sticker.style.background = RUBIK[ff];
            }
            
            {
              var ch = document.createElement('div');
              ch.style.cssText = 'position:absolute;inset:0;display:flex;align-items:center;justify-content:center;' +
                
                'font-size:' + Math.round(tile * 0.58) + 'px;font-weight:800;line-height:1;color:'
                  + (self.cubeMono ? textCol : _rubikInk(RUBIK[ff])) + ';';
              ch.textContent = blank ? '' : (_spell ? _chars[_fi] : _chars[(seed >> 7) % _chars.length]);
              cel._st = cel._st || {};
              cel._st[ff] = ch;                 
              sticker.appendChild(ch);
            }
          } else {
            
            var crv = F.cr(pos), fidx = ff;
            
            var _stick = self.cubeMono ? tileCol : RUBIK[fidx];
            sticker.style.background = _stick;
            var win = document.createElement('div');
            win.style.cssText = 'position:absolute;left:' + (-crv[0] * tile - gap) + 'px;top:' + (-crv[1] * tile - gap) + 'px;' +
              'width:' + E + 'px;height:' + E + 'px;';
            win.appendChild(_faceText(fidx, self.cubeMono ? textCol : _rubikInk(_stick)));
            sticker.appendChild(win);
          }
          face.appendChild(sticker);
        }
        cel.appendChild(face);
      }
      var cub = { el: cel, pos: pos, orient: [[1, 0, 0], [0, 1, 0], [0, 0, 1]] };
      applyT(cub);
      cubeEl.appendChild(cel);
      cubies.push(cub);
    }

    function rotMat(axis, d) {
      if (axis === 'x') return [[1, 0, 0], [0, 0, -d], [0, d, 0]];
      if (axis === 'y') return [[0, 0, d], [0, 1, 0], [-d, 0, 0]];
      return [[0, -d, 0], [d, 0, 0], [0, 0, 1]];
    }
    function mulMat(a, b) {
      var r = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
      for (var i = 0; i < 3; i++) for (var j = 0; j < 3; j++)
        r[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j];
      return r;
    }
    function mulVec(m, v) {
      return [Math.round(m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2]),
              Math.round(m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2]),
              Math.round(m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2])];
    }

    var twistMs = _ms(700, self.speed);
    var stagMs  = _ms(170, self.speed);
    var period  = _ms((COMPOSITIONS.cube && COMPOSITIONS.cube.duration) || 12000, self.speed);

    function twist(axis, layer, d) {
      if (self._destroyed || !self._running) return;
      var ai = axis === 'x' ? 0 : (axis === 'y' ? 1 : 2);
      var members = [];
      for (var i = 0; i < cubies.length; i++) if (cubies[i].pos[ai] === layer) members.push(cubies[i]);
      if (!members.length) return;
      var g = document.createElement('div');
      g.style.cssText = 'position:absolute;inset:0;transform-style:preserve-3d;will-change:transform;';
      cubeEl.appendChild(g);
      for (var j = 0; j < members.length; j++) g.appendChild(members[j].el);
      var rotFn = axis === 'x' ? 'rotateX' : (axis === 'y' ? 'rotateY' : 'rotateZ');
      try {
        var an = g.animate(
          [{ transform: rotFn + '(0deg)' }, { transform: rotFn + '(' + (d * 90) + 'deg)' }],
          { duration: twistMs, easing: 'cubic-bezier(.7,0,.3,1)', fill: 'forwards' }
        );
        self._anims.push(an);
        an.onfinish = function () {
          if (self._destroyed) return;
          var R = rotMat(axis, d);
          for (var k = 0; k < members.length; k++) {
            var c = members[k];
            c.pos = mulVec(R, c.pos);
            c.orient = mulMat(R, c.orient);
            applyT(c);
            cubeEl.appendChild(c.el);
          }
          if (g.parentNode) g.parentNode.removeChild(g);
        };
      } catch (e) {
        if (g.parentNode) { 
          var R2 = rotMat(axis, d);
          for (var k2 = 0; k2 < members.length; k2++) {
            var c2 = members[k2];
            c2.pos = mulVec(R2, c2.pos);
            c2.orient = mulMat(R2, c2.orient);
            applyT(c2);
            cubeEl.appendChild(c2.el);
          }
          g.parentNode.removeChild(g);
        }
      }
    }

    var ROUNDS = [
      { a: 'z', d: 1,  at: 0.10 },
      { a: 'x', d: 1,  at: 0.35 },
      { a: 'x', d: -1, at: 0.60 },
      { a: 'z', d: -1, at: 0.85 }
    ];
    function runCycle() {
      for (var ri = 0; ri < ROUNDS.length; ri++) {
        (function (rd) {
          var layers = [-1, 0, 1];
          for (var li = 0; li < layers.length; li++) {
            (function (layer, order) {
              self._timers.push(setTimeout(function () {
                twist(rd.a, layer, layer === 0 ? -rd.d : rd.d);
              }, Math.round(period * rd.at + order * stagMs)));
            })(layers[li], li);
          }
        })(ROUNDS[ri]);
      }
      if (self.loop) {
        self._timers.push(setTimeout(function () {
          if (self._destroyed || !self._running) return;
          runCycle();
        }, period));
      }
    }

    try {
      self._anims.push(tumble.animate(
        [{ transform: 'rotateX(35deg) rotateY(45deg)' },
         { transform: 'rotateX(395deg) rotateY(405deg)' }],
        { duration: period, iterations: self.loop ? Infinity : 1, easing: 'linear', fill: 'forwards' }
      ));
    } catch (e) { tumble.style.transform = 'rotateX(35deg) rotateY(45deg)'; }

    try {
      scaleWrap.style.transform = 'scale(1.6)';
      scaleWrap.style.opacity = '0';
      self._anims.push(scaleWrap.animate(
        [{ transform: 'scale(1.6)', opacity: 0 },
         { opacity: 1, offset: 0.4 },
         { transform: 'scale(1)', opacity: 1 }],
        { duration: _ms(900, self.speed), easing: 'cubic-bezier(.16,1,.3,1)', fill: 'forwards' }
      ));
    } catch (e) {}

    self._running = true;
    runCycle();
  };

  KineticBlock.prototype._compLines = function (max) {
    var self = this;
    var srcLines = (self.lines || []).map(function (l) { return (l && l.text || '').trim(); }).filter(Boolean);   
    if (self.customMode && Array.isArray(self.customLines) && self.customLines.length) {
      var cl = self.customLines
        .map(function (c) { return (c && c.text || '').trim(); })
        .filter(Boolean);
      if (cl.length) srcLines = cl;
    }
    srcLines = srcLines.slice(0, max);
    if (!srcLines.length) {
      self._stage.innerHTML =
        '<span style="font-size:64px;opacity:0.18;letter-spacing:0.02em">Kinetic</span>';
      self._running = false;
      return null;
    }
    return srcLines;
  };

  KineticBlock.prototype._compGenNext = function () {
    this._compGen = (this._compGen || 0) + 1;
    return this._compGen;
  };

  KineticBlock.prototype._playGlitch = function () {
    var self = this;
    var srcLines = self._compLines(3);
    if (!srcLines) return;

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var ix = self.intensity || 1;

    var holder = document.createElement('div');
    holder.style.cssText = 'position:absolute;inset:0;display:flex;flex-direction:column;'
      
      + 'align-items:' + _alignFlex(self.align) + ';justify-content:center;overflow:hidden;';
    self._stage.appendChild(holder);

    var meas = document.createElement('span');
    meas.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:nowrap;visibility:hidden;'
      + 'font-weight:900;line-height:1;font-family:' + (self.fontStack || 'inherit') + ';font-size:100px;';
    self._stage.appendChild(meas);

    var groups = [];   
    srcLines.forEach(function (text, li) {
      meas.textContent = text;
      var w100 = meas.offsetWidth || 1;
      
      var fs = Math.max(18, Math.min(stageH * (srcLines.length > 1 ? (0.68 / srcLines.length) : 0.5),
                                     Math.floor(100 * (stageW * 0.9) / w100)));
      var _glLk = self._lineLink(0);
      var line = document.createElement(_glLk ? 'a' : 'div');
      line.style.cssText = 'position:relative;line-height:1.08;font-weight:900;white-space:nowrap;'
        + 'font-size:' + fs + 'px;color:' + self._lineInk(li) + ';';
      self._gradApply(line);
      if (_glLk) self._wireLink(line, _glLk);
      var base = document.createElement('span');
      base.textContent = text;
      base.style.cssText = 'position:relative;display:inline-block;';
      line.appendChild(base);
      
      var slices = [];
      for (var i = 0; i < 5; i++) {
        var c = document.createElement('span');
        c.textContent = text;
        c.setAttribute('aria-hidden', 'true');
        c.style.cssText = 'position:absolute;left:0;top:0;display:inline-block;'
          + 'opacity:0;will-change:transform,clip-path;pointer-events:none;'
          + (i >= 3 ? 'color:' + (i === 3 ? 'rgb(255,0,64)' : 'rgb(0,229,255)') + ';' : '');
        line.appendChild(c);
        slices.push(c);
      }
      holder.appendChild(line);
      groups.push({ slices: slices, base: base });
    });
    if (meas.parentNode) meas.parentNode.removeChild(meas);

    var period  = _ms(4130, self.speed);   
    var burstMs = Math.min(560, period * 0.16);
    var gen = self._compGenNext();

    var burstIdx = 0;
    function burst() {
      if (gen !== self._compGen || self._destroyed || !self.el.isConnected) return;
      
      burstIdx++;
      var only = (groups.length > 1 && burstIdx % 3 !== 0) ? (burstIdx % groups.length) : -1;
      var steps = 6, step = 0;
      var iv = setInterval(function () {
        if (gen !== self._compGen) { clearInterval(iv); return; }
        step++;
        groups.forEach(function (g, gi) {
          if (only !== -1 && gi !== only) return;
          g.slices.forEach(function (c, i) {
            if (step >= steps) {   
              c.style.opacity = '0';
              c.style.transform = '';
              g.base.style.opacity = '1';
              return;
            }
            var band = i % 3;
            var top = band * 33 + (Math.random() * 10 - 5);
            var dx = (Math.random() * 2 - 1) * 14 * ix * (i >= 3 ? 0.6 : 1);
            c.style.opacity = i >= 3 ? '0.75' : '1';
            c.style.clipPath = 'inset(' + top + '% 0 ' + Math.max(0, 100 - top - 34) + '% 0)';
            c.style.transform = 'translateX(' + dx.toFixed(1) + 'px)';
            
            g.base.style.opacity = (Math.random() < 0.2) ? '0.4' : '1';
          });
        });
        if (step >= steps) clearInterval(iv);
      }, burstMs / steps);
      self._timers.push(iv);
    }
    
    self._timers.push(setTimeout(burst, _ms(700, self.speed)));
    if (self.loop) {
      var cyc = setInterval(function () {
        if (gen !== self._compGen) { clearInterval(cyc); return; }
        burst();
      }, period);
      self._timers.push(cyc);
    }
    self._running = true;
  };

  KineticBlock.prototype._playEcho = function () {
    var self = this;
    var srcLines = self._compLines(4);
    if (!srcLines) return;

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var ix = self.intensity || 1;

    var N_ECHO = self.echoCount || 5;
    var holder = document.createElement('div');
    
    holder.style.cssText = 'position:absolute;inset:0;overflow:visible;';
    self._stage.appendChild(holder);

    var meas = document.createElement('span');
    meas.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:nowrap;visibility:hidden;'
      + 'font-weight:900;line-height:1;font-family:' + (self.fontStack || 'inherit') + ';font-size:100px;';
    self._stage.appendChild(meas);
    function fitFor(text) {
      meas.textContent = text;
      var w100 = meas.offsetWidth || 1;
      
      var _fitW = Math.floor(100 * (stageW * 0.72) / w100);
      var _want = self.compFont > 0 ? self.compFont : Math.min(stageH * 0.44, _fitW);
      return Math.max(20, Math.min(_want, _fitW));
    }

    var _echoAnyLink = false;
    for (var _ei = 0; _ei < srcLines.length; _ei++) if (self._lineLink(_ei)) { _echoAnyLink = true; break; }
    var layers = [];
    for (var i = N_ECHO; i >= 0; i--) {   
      
      var l = document.createElement(_echoAnyLink ? 'a' : 'div');
      var k = i / N_ECHO;
      
      var _eL = self.align === 'left' ? '0%' : (self.align === 'right' ? '100%' : '50%');
      
      var _eTx = self.align === 'left' ? '0' : (self.align === 'right' ? '-100%' : '-50%');
      l.style.cssText = 'position:absolute;left:' + _eL + ';top:50%;white-space:nowrap;'
        + 'font-weight:900;line-height:1;color:' + self.color + ';'
        
        + 'opacity:' + (i === 0 ? 1 : (0.5 * Math.pow(1 - i / (N_ECHO + 1), 1.5)).toFixed(3)) + ';'
        + 'will-change:transform;transform:translate(' + _eTx + ',-50%);';
      holder.appendChild(l);
      layers.push({ el: l, depth: i });
    }

    var wordMs = _ms(3000, self.speed);
    var word = 0;
    function setWord(t) {
      var fs = fitFor(t);
      
      var _wi = srcLines.indexOf(t), _wl = (_wi >= 0) ? self._lineLink(_wi) : '';
      layers.forEach(function (o) {
        o.el.textContent = t;
        o.el.style.fontSize = fs + 'px';
        if (_echoAnyLink) {
          if (_wl) { self._wireLink(o.el, _wl); }
          else { o.el.removeAttribute('href'); o.el.style.pointerEvents = 'none'; o.el.style.cursor = ''; }
        }
      });
    }
    setWord(srcLines[0]);

    var period = _ms(3000, self.speed);
    layers.forEach(function (o) {
      var grow = 1 + (0.16 + o.depth * 0.055) * ix;
      try {
        self._anims.push(o.el.animate(
          [{ transform: 'translate(' + _eTx + ',-50%) scale(1)' },
           { transform: 'translate(' + _eTx + ',-50%) scale(' + grow.toFixed(3) + ')' },
           { transform: 'translate(' + _eTx + ',-50%) scale(1)' }],
          { duration: period, iterations: Infinity, easing: 'ease-in-out',
            delay: -o.depth * (period * 0.09) }
        ));
      } catch (e) {}
    });

    if (srcLines.length > 1 && self.loop) {
      var gen = self._compGenNext();
      var iv = setInterval(function () {
        if (gen !== self._compGen) { clearInterval(iv); return; }
        word = (word + 1) % srcLines.length;
        setWord(srcLines[word]);
      }, wordMs);
      self._timers.push(iv);
    }
    self._running = true;
  };

  KineticBlock.prototype._playCurtain = function () {
    var self = this;
    var srcLines = self._compLines(2);
    if (!srcLines) return;

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var ix = self.intensity || 1;

    var id = 'kcurt' + Math.round(stageW) + '_' + Math.round(stageH);
    var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    svg.setAttribute('width', '0'); svg.setAttribute('height', '0');
    svg.style.cssText = 'position:absolute;width:0;height:0;';
    var filter = document.createElementNS('http://www.w3.org/2000/svg', 'filter');
    filter.setAttribute('id', id);
    filter.setAttribute('x', '-15%'); filter.setAttribute('y', '-15%');
    filter.setAttribute('width', '130%'); filter.setAttribute('height', '130%');
    var turb = document.createElementNS('http://www.w3.org/2000/svg', 'feTurbulence');
    turb.setAttribute('type', 'fractalNoise');
    
    turb.setAttribute('baseFrequency', '0.004 0.02');
    turb.setAttribute('numOctaves', '2');
    turb.setAttribute('result', 'n');
    var disp = document.createElementNS('http://www.w3.org/2000/svg', 'feDisplacementMap');
    disp.setAttribute('in', 'SourceGraphic');
    disp.setAttribute('in2', 'n');
    disp.setAttribute('scale', String(Math.round(28 * ix)));
    disp.setAttribute('xChannelSelector', 'R');
    disp.setAttribute('yChannelSelector', 'G');
    filter.appendChild(turb); filter.appendChild(disp);
    svg.appendChild(filter);
    self._stage.appendChild(svg);

    var holder = document.createElement('div');
    
    holder.style.cssText = 'position:absolute;inset:0;min-height:' + Math.round(stageH) + 'px;'
      + 'display:flex;flex-direction:column;align-items:center;justify-content:center;overflow:hidden;'
      + 'filter:url(#' + id + ');';
    var meas = document.createElement('span');
    meas.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:nowrap;visibility:hidden;'
      + 'font-weight:900;line-height:1;font-family:' + (self.fontStack || 'inherit') + ';font-size:100px;';
    self._stage.appendChild(meas);

    var _cuRowH = stageH / srcLines.length;
    srcLines.forEach(function (text, li) {
      meas.textContent = text;
      var w100 = meas.offsetWidth || 1;
      var fs = Math.max(18, Math.floor(100 * (stageW * 0.94) / w100));

      var wrap = document.createElement('div');
      wrap.style.cssText = 'width:100%;height:' + _cuRowH + 'px;'
        + 'display:flex;align-items:center;justify-content:' + _alignFlex(self.align) + ';';
      var _cuLk = self._lineLink(li);
      var line = document.createElement(_cuLk ? 'a' : 'div');
      line.textContent = text;
      
      line.style.cssText = 'white-space:nowrap;font-weight:900;line-height:1;'
        + 'font-size:' + fs + 'px;color:' + self._lineInk(li) + ';'
        + 'transform:scaleY(' + (Math.max(1, (_cuRowH * 0.92) / (fs * 1.05))).toFixed(2) + ');'
        + 'transform-origin:50% 50%;';
      self._gradApply(line);
      if (_cuLk) self._wireLink(line, _cuLk);
      wrap.appendChild(line);
      holder.appendChild(wrap);
    });
    if (meas.parentNode) meas.parentNode.removeChild(meas);
    self._stage.appendChild(holder);

    var gen = self._compGenNext();
    var t0 = null, dur = _ms(8000, self.speed);
    function tick(now) {
      if (gen !== self._compGen || self._destroyed || !self.el.isConnected) return;
      if (t0 === null) t0 = now;
      var ph = ((now - t0) % dur) / dur;
      
      turb.setAttribute('baseFrequency', (0.004 + 0.0012 * Math.sin(ph * Math.PI * 2)).toFixed(5)
        + ' ' + (0.02 + 0.004 * Math.cos(ph * Math.PI * 2)).toFixed(5));
      disp.setAttribute('scale', String(Math.round((24 + 10 * Math.sin(ph * Math.PI * 2)) * ix)));
      if (self.loop || ph < 0.999) requestAnimationFrame(tick);
    }
    requestAnimationFrame(tick);
    self._running = true;
  };

  KineticBlock.prototype._playTypePulse = function () {
    var self = this;
    var srcLines = self._compLines(6);
    if (!srcLines) return;

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;

    var box = document.createElement('div');

    box.style.cssText = 'position:absolute;inset:0;display:flex;flex-direction:column;'
      + 'justify-content:center;overflow:visible;'
      + 'padding:' + Math.round(stageH * 0.06) + 'px 0;';
    var rows = [];
    
    var _ixFit = 1 + 0.9 * (self.intensity || 1);
    var fs = Math.max(16, Math.floor((stageH * 0.94) / (srcLines.length - 1 + _ixFit)));

    var _tpMeas = document.createElement('span');
    _tpMeas.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:pre;'
      + 'visibility:hidden;font-weight:900;line-height:1.02;'
      + 'font-family:' + (self.fontStack || 'inherit') + ';font-size:100px;';
    self._stage.appendChild(_tpMeas);
    var _tpInner = Math.max(40, Math.round(stageW * 0.94));

    var letters = [];
    srcLines.forEach(function (t, li) {
      _tpMeas.textContent = t;
      var w100 = _tpMeas.offsetWidth || 1;
      var rowFs = Math.max(16, Math.min(fs, Math.floor(100 * _tpInner / w100)));
      
      var fill = (w100 * rowFs / 100) / _tpInner;
      var row = document.createElement('div');
      
      row.style.cssText = 'display:flex;flex-wrap:nowrap;align-items:baseline;'
        + 'justify-content:' + (fill >= 0.88 ? 'space-between' : _alignFlex(self.align))
        + ';line-height:1.02;white-space:nowrap;';
      for (var i = 0; i < t.length; i++) {
        var ch = t.charAt(i);
        var s = document.createElement('span');
        s.textContent = ch === ' ' ? '\u00a0' : ch;
        
        s.style.cssText = 'display:inline-block;font-weight:900;font-size:' + rowFs + 'px;'
          
          + (self.fill === 'gradient' ? '' : ('color:' + self._lineInk(li) + ';'))
          + 'transition:font-size 620ms ease-in-out;';
        
        s._fsN = rowFs;
        s._fsB = Math.round(rowFs * (1 + 0.9 * (self.intensity || 1)));
        row.appendChild(s);
        if (ch !== ' ') letters.push(s);
      }
      
      if (self.fill === 'gradient') self._gradApply(row);
      box.appendChild(row);
      rows.push(row);
    });
    if (_tpMeas.parentNode) _tpMeas.parentNode.removeChild(_tpMeas);
    self._stage.appendChild(box);

    var gen = self._compGenNext();
    var beat = _ms(1500, self.speed);
    
    var _ixp = self.intensity || 1;
    var lit = [];
    var iv = setInterval(function () {
      if (gen !== self._compGen || self._destroyed || !self.el.isConnected) { clearInterval(iv); return; }
      lit.forEach(function (s) { s.style.fontSize = (s._fsN || 16) + 'px'; });
      lit = [];
      var n = Math.max(1, Math.round(letters.length * 0.06 * _ixp));
      for (var k = 0; k < n; k++) {
        var s = letters[(Math.round(k * 7919 + Date.now() / beat * 13) % letters.length + letters.length) % letters.length];
        s.style.fontSize = (s._fsB || s._fsN || 16) + 'px';
        lit.push(s);
      }
      if (!self.loop) clearInterval(iv);
    }, beat);
    self._timers.push(iv);
    self._running = true;
  };

  KineticBlock.prototype._playTide = function () {
    var self = this;
    var srcLines = self._compLines(4);
    if (!srcLines) return;

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;

    var meas = document.createElement('span');
    meas.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:nowrap;visibility:hidden;'
      + 'font-weight:900;line-height:1;font-family:' + (self.fontStack || 'inherit') + ';font-size:100px;';
    self._stage.appendChild(meas);
    var widest = 1;
    srcLines.forEach(function (t) { meas.textContent = t; if (meas.offsetWidth > widest) widest = meas.offsetWidth; });
    if (meas.parentNode) meas.parentNode.removeChild(meas);
    var fs = Math.max(18, Math.min(Math.floor(stageH / (srcLines.length + 0.8)),
                                   Math.floor(100 * (stageW * 0.86) / widest)));

    function stack(inverted) {
      var d = document.createElement('div');
      d.style.cssText = 'position:absolute;inset:0;display:flex;flex-direction:column;'
        + 'align-items:' + _alignFlex(self.align) + ';justify-content:center;overflow:hidden;'
        + (inverted ? 'background:' + self.color + ';' : '');
      srcLines.forEach(function (t, li) {
        
        var lk = (self.discButtons && self.discLinks && typeof self.discLinks[li] === 'string')
          ? self.discLinks[li].trim() : '';
        var l = document.createElement(lk ? 'a' : 'div');
        l.textContent = t;
        l.style.cssText = 'white-space:nowrap;font-weight:900;line-height:1.06;font-size:' + fs + 'px;'
          
          + 'color:' + (inverted ? '#fff' : self._lineInk(li)) + ';'
          + (lk ? 'pointer-events:auto;cursor:pointer;text-decoration:none;' : '');
        if (!inverted) self._gradApply(l);
        if (lk) {
          l.setAttribute('href', lk);
          if (typeof window !== 'undefined' && window._impulseEditorPreview) {
            l.addEventListener('click', function (e) { e.preventDefault(); });
          }
        }
        d.appendChild(l);
      });
      return d;
    }
    self._stage.appendChild(stack(false));
    var top = stack(true);
    self._stage.appendChild(top);

    if (self.tideBubbles) {
      var _bw = document.createElement('div');
      _bw.style.cssText = 'position:absolute;inset:0;overflow:hidden;pointer-events:none;';
      top.appendChild(_bw);
      for (var _bi = 0; _bi < 14; _bi++) {
        var _s = ((_bi + 1) * 2654435761) >>> 0;
        var _d = 8 + (_s % 22);                       
        var _x = ((_s >> 5) % 100);                   
        var _dur = _ms(5200 + ((_s >> 11) % 4600), self.speed);
        var _sway = 4 + ((_s >> 17) % 12);            
        var _b = document.createElement('div');
        _b.style.cssText = 'position:absolute;bottom:-10%;left:' + _x + '%;'
          + 'width:' + _d + 'px;height:' + _d + 'px;border-radius:50%;'
          + 'background:rgba(255,255,255,' + (0.10 + ((_s >> 23) % 14) / 100).toFixed(2) + ');'
          + 'will-change:transform;';
        _bw.appendChild(_b);
        try {
          self._anims.push(_b.animate([
            { transform: 'translate(0,0) scale(0.7)', opacity: 0 },
            { transform: 'translate(' + _sway + 'px,-40vh) scale(1)', opacity: 1, offset: 0.25 },
            { transform: 'translate(' + (-_sway) + 'px,-95vh) scale(1.06)', opacity: 1, offset: 0.85 },
            { transform: 'translate(0,-125vh) scale(1.1)', opacity: 0 }
          ], { duration: _dur, iterations: Infinity, easing: 'linear',
               delay: -((_s >> 3) % _dur) }));
        } catch (e) {}
      }
    }

    var gen = self._compGenNext();
    var t0 = null, dur = _ms(9000, self.speed);
    var _wvN = Math.max(64, Math.min(180, Math.round(stageW / 8)));
    function tick(now) {
      if (gen !== self._compGen || self._destroyed || !self.el.isConnected) return;
      if (t0 === null) t0 = now;
      var ph = ((now - t0) % dur) / dur;

      var base = 50 - 35 * Math.cos(ph * Math.PI * 2);   
      var pts = [];

      for (var i = 0; i <= _wvN; i++) {
        var x = i * 100 / _wvN;
        var y = base
              + 6.5 * Math.sin((x / 100) * Math.PI * 2.4 + ph * Math.PI * 8)
              
              + 3.0 * Math.sin((x / 100) * Math.PI * 4.6 - ph * Math.PI * 6);
        pts.push(x + '% ' + y.toFixed(2) + '%');
      }
      pts.push('100% 100%', '0% 100%');
      var poly = 'polygon(' + pts.join(',') + ')';
      top.style.clipPath = poly;
      top.style.webkitClipPath = poly;
      if (self.loop || ph < 0.999) requestAnimationFrame(tick);
    }
    requestAnimationFrame(tick);
    self._running = true;
  };

  

  function _alignFlex(a) {
    return a === 'left' ? 'flex-start' : (a === 'right' ? 'flex-end' : 'center');
  }

  var SCENE_COMPS = ['cylinder', 'sweep', 'brutal', 'cube', 'glitchloop', 'echo', 'helix',
                     'curtain', 'typepulse', 'tide', 'discs', 'vortex', 'wiper'];

  KineticBlock.prototype._sceneRemeasure = function () {
    var self = this;
    if (typeof requestAnimationFrame !== 'function' || !self._stage) return;
    var w0 = self._stage.offsetWidth, h0 = self._stage.offsetHeight;
    requestAnimationFrame(function () {
      requestAnimationFrame(function () {
        if (self._destroyed || !self.el.isConnected || !self._stage) return;
        var w1 = self._stage.offsetWidth, h1 = self._stage.offsetHeight;
        if (Math.abs(w1 - w0) < 3 && Math.abs(h1 - h0) < 3) { self._sceneFixN = 0; return; }
        self._sceneFixN = (self._sceneFixN || 0) + 1;
        if (self._sceneFixN > 2) return;
        
        self._clearAll();
        self._playOnce();
        self._lastW = self.el.offsetWidth;
        self._lastH = self.el.offsetHeight;
      });
    });
  };

  KineticBlock.prototype._lineInk = function (i) {
    return (this.discColors && this.discColors[i]) || this.color;
  };

  KineticBlock.prototype._gradApply = function (elm) {
    if (!elm || this.fill !== 'gradient') return;
    var c1 = this.gradC1 || '#ff2d55';
    var c2 = this.gradC2 || '#5e5cff';
    
    if (this.gradMode === 'wipe') {
      elm.style.backgroundImage = 'linear-gradient(90deg,' + c2 + ' 0%,' + c2 + ' 50%,'
        + c1 + ' 50%,' + c1 + ' 100%)';
    } else {
      elm.style.backgroundImage = 'linear-gradient(90deg,' + c1 + ',' + c2 + ',' + c1 + ')';
    }
    elm.style.backgroundSize = '200% 100%';
    elm.style.webkitBackgroundClip = 'text';
    elm.style.backgroundClip = 'text';
    elm.style.color = 'transparent';
    elm.style.webkitTextFillColor = 'transparent';
    
    if (!elm._kGradPadded) {
      elm.style.paddingBottom = '0.22em';
      elm.style.marginBottom = '-0.22em';
      elm._kGradPadded = true;
    }
    if (this.gradMode === 'static') return;
    try {
      if (this.gradMode === 'wipe') {
        
        this._anims.push(elm.animate(
          [{ backgroundPosition: '100% 50%', easing: 'ease-in-out' },
           { backgroundPosition: '0% 50%',   easing: 'ease-in-out', offset: 0.42 },
           { backgroundPosition: '0% 50%',   easing: 'ease-in-out', offset: 0.52 },
           { backgroundPosition: '100% 50%', easing: 'ease-in-out', offset: 0.88 },
           { backgroundPosition: '100% 50%' }],
          { duration: _ms(4200, this.gradSpeed || 1), iterations: Infinity }));
      } else {
        this._anims.push(elm.animate(
          [{ backgroundPosition: '0% 50%' }, { backgroundPosition: '200% 50%' }],
          { duration: _ms(6000, this.gradSpeed || 1), iterations: Infinity, easing: 'linear' }));
      }
    } catch (e) {}
  };

  KineticBlock.prototype._playWiper = function () {
    var self = this;
    var srcLines = self._compLines(4);
    if (!srcLines) return;

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;

    var meas = document.createElement('span');
    meas.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:nowrap;visibility:hidden;'
      + 'font-weight:900;line-height:1;font-family:' + (self.fontStack || 'inherit') + ';font-size:100px;';
    self._stage.appendChild(meas);
    var widest = 1;
    srcLines.forEach(function (t) { meas.textContent = t; if (meas.offsetWidth > widest) widest = meas.offsetWidth; });
    if (meas.parentNode) meas.parentNode.removeChild(meas);
    var fs = Math.max(18, Math.min(Math.floor(stageH / (srcLines.length + 0.6)),
                                   Math.floor(100 * (stageW * 0.88) / widest)));

    var pos = document.createElement('div');
    
    pos.style.cssText = 'position:absolute;inset:0;display:flex;flex-direction:column;'
      + 'align-items:' + _alignFlex(self.align) + ';justify-content:center;overflow:visible;';
    self._stage.appendChild(pos);

    function stack(ink) {
      var s = document.createElement('div');
      
      s.style.cssText = 'position:absolute;left:0;right:0;top:-30%;height:160%;'
        + 'display:flex;flex-direction:column;'
        + 'align-items:center;justify-content:center;will-change:clip-path;';
      srcLines.forEach(function (t, li) {
        var l = document.createElement('div');
        l.textContent = t;
        l.style.cssText = 'white-space:nowrap;font-weight:900;line-height:1.08;font-size:' + fs + 'px;'
          + 'color:' + ink + ';';
        s.appendChild(l);
      });
      pos.appendChild(s);
      return s;
    }
    
    var baseStack = stack((self.discColors && self.discColors[0]) || self.color);
    Array.prototype.forEach.call(baseStack.children, function (l) { self._gradApply(l); });
    
    var _wipeInk = self.accent
      || (self.fill === 'gradient' ? self.gradC2 : '')
      || (self.discColors && self.discColors[1])
      || '#f5f5f5';
    var over = stack(_wipeInk);

    var blade = document.createElement('div');
    var bw = Math.max(4, Math.round(fs * 0.12));
    blade.style.cssText = 'position:absolute;top:-8%;left:0;height:116%;width:' + bw + 'px;'
      + 'background:' + _wipeInk + ';transform:translateX(0) skewX(-12deg);'
      + 'will-change:transform;';
    pos.appendChild(blade);

    var outT = _ms(1500, self.speed);      
    var backT = _ms(620, self.speed);      
    var gen = self._compGenNext();

    function stroke(forward) {
      if (gen !== self._compGen || self._destroyed || !self.el.isConnected) return;
      var dur = forward ? outT : backT;
      
      var clipFrom = forward ? 'inset(0 0 0 0)' : 'inset(0 0 0 100%)';
      var clipTo   = forward ? 'inset(0 0 0 100%)' : 'inset(0 0 0 0)';
      var xFrom = forward ? 0 : stageW;
      var xTo   = forward ? stageW : 0;
      try {
        self._anims.push(over.animate(
          [{ clipPath: clipFrom }, { clipPath: clipTo }],
          { duration: dur, easing: 'ease-in-out', fill: 'forwards' }));
        self._anims.push(blade.animate(
          [{ transform: 'translateX(' + xFrom + 'px) skewX(-12deg)' },
           { transform: 'translateX(' + xTo + 'px) skewX(-12deg)' }],
          { duration: dur, easing: 'ease-in-out', fill: 'forwards' }));
      } catch (e) {}
      if (!self.loop && !forward) return;
      self._timers.push(setTimeout(function () { stroke(!forward); }, dur + _ms(900, self.speed)));
    }
    stroke(true);
    self._running = true;
  };

  
  
  function _glowOn(el) {
    var m = null;
    try { m = /^rgba?\(([^)]+)\)/i.exec(getComputedStyle(el).backgroundColor || ''); } catch (e) {}
    if (!m) return '';
    var p = m[1].split(',');
    function lift(i) {
      var c = parseFloat(p[i]) || 0;
      return Math.round(c + (255 - c) * 0.38);
    }
    return 'rgba(' + lift(0) + ',' + lift(1) + ',' + lift(2) + ',0.5)';
  }

  function _inkOn(el) {
    var m = null;
    try { m = /^rgba?\(([^)]+)\)/i.exec(getComputedStyle(el).backgroundColor || ''); } catch (e) {}
    if (!m) return '#ffffff';
    var p = m[1].split(',');
    var a = (p.length > 3) ? parseFloat(p[3]) : 1;
    
    if (!(a > 0.1)) return '#ffffff';
    var lum = (0.299 * (parseFloat(p[0]) || 0)
             + 0.587 * (parseFloat(p[1]) || 0)
             + 0.114 * (parseFloat(p[2]) || 0)) / 255;
    return lum >= 0.55 ? '#1d2327' : '#ffffff';
  }

  KineticBlock.prototype._playDiscs = function () {
    var self = this;
    var srcLines = self._compLines(4);
    if (!srcLines) return;

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var SVGNS = 'http://www.w3.org/2000/svg';

    var holder = document.createElement('div');
    
    holder.style.cssText = 'position:absolute;inset:0;overflow:'
      + (self.discClip ? 'hidden' : 'visible') + ';';
    self._stage.appendChild(holder);
    if (!self.discClip) {
      self._stage.style.overflow = 'visible';
      self.el.style.overflow = 'visible';
    }

    
    var _dBase = self.asBackground ? Math.max(stageW, stageH) : Math.min(stageW, stageH);
    
    var R = Math.round(_dBase * (self.asBackground ? 0.22 : 0.30) * (self.compScale > 0 ? self.compScale : 1));
    
    R = Math.min(R, Math.round(stageW * (self.discClip ? 0.46 : 0.80)));
    var POS = self.asBackground
      ? [[0.24, 0.30], [0.74, 0.64], [0.54, 0.20], [0.38, 0.80]]
      : [[0.36, 0.42], [0.62, 0.55], [0.5, 0.34], [0.44, 0.66]];
    
    var _dAlignDx = 0;

    var _rrArr = null;
    var _discFontEff = self.discFont;
    if (self.discFont > 0) {
      var _dm = document.createElement('span');
      _dm.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:nowrap;'
        + 'visibility:hidden;font-weight:' + (self.kWeight || '900') + ';line-height:1.05;'
        + 'font-family:' + (self.fontStack || 'inherit') + ';font-size:' + self.discFont + 'px;';
      self._stage.appendChild(_dm);
      _rrArr = srcLines.map(function (t) {
        _dm.textContent = t;
        var w = _dm.offsetWidth || 1;
        
        return Math.max(20, Math.ceil((w / 1.80) * 1.06));
      });
      if (_dm.parentNode) _dm.parentNode.removeChild(_dm);

      var _capR = stageW * 0.46;
      var _maxR = Math.max.apply(null, _rrArr);
      if (_capR > 12 && _maxR > _capR) {
        var _k = _capR / _maxR;
        _rrArr = _rrArr.map(function (v) { return Math.max(12, Math.round(v * _k)); });
        _discFontEff = Math.max(8, Math.round(_discFontEff * _k));
      }
      R = Math.max.apply(null, _rrArr);
    }

    if (self.align === 'left' || self.align === 'right') {
      var _minL = Infinity, _maxR = -Infinity;
      for (var _ai = 0; _ai < srcLines.length; _ai++) {
        var _ar = _rrArr ? _rrArr[_ai] : Math.round(R * (_ai % 2 === 0 ? 1 : 0.82));
        var _ac = stageW * POS[_ai % POS.length][0];
        if (_ac - _ar < _minL) _minL = _ac - _ar;
        if (_ac + _ar > _maxR) _maxR = _ac + _ar;
      }
      _dAlignDx = (self.align === 'left') ? -_minL : (stageW - _maxR);
    }

    var shapeLayer = document.createElement('div');
    shapeLayer.style.cssText = 'position:absolute;inset:0;';
    holder.appendChild(shapeLayer);

    var probe = document.createElement('span');
    probe.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:nowrap;visibility:hidden;'
      + 'font-weight:900;line-height:1;font-family:' + (self.fontStack || 'inherit') + ';font-size:100px;';
    self._stage.appendChild(probe);

    var inst2 = [];
    srcLines.forEach(function (t, i) {
      var pos = POS[i % POS.length];
      
      var rr = _rrArr ? _rrArr[i] : Math.round(R * (i % 2 === 0 ? 1 : 0.82));
      
      var cx = Math.round(stageW * pos[0] + _dAlignDx);
      var cy = Math.round(stageH * pos[1]);
      if (stageW > 2 * rr) cx = Math.min(Math.max(cx, rr), stageW - rr);
      else cx = Math.round(stageW / 2);
      if (stageH > 2 * rr) cy = Math.min(Math.max(cy, rr), stageH - rr);
      else cy = Math.round(stageH / 2);

      var discCol = (self.discColors && self.discColors[i])
                 || (self.customLines && self.customLines[i] && self.customLines[i].color)
                 || self.color;
      
      var lnk = (self.discButtons && self.discLinks && typeof self.discLinks[i] === 'string')
        ? self.discLinks[i].trim() : '';
      
      var wrap = document.createElement('div');
      wrap.className = 'kp-disc';
      wrap.style.cssText = 'position:absolute;width:' + (rr * 2) + 'px;height:' + (rr * 2) + 'px;'
        + 'left:' + (cx - rr) + 'px;top:' + (cy - rr) + 'px;';
      var disc = document.createElement(lnk ? 'a' : 'div');
      
      disc.style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;will-change:transform;'
        
        + (lnk ? 'pointer-events:auto;cursor:pointer;text-decoration:none;display:block;' : '');
      
      var face = document.createElement('div');
      
      face.style.cssText = 'position:relative;width:100%;height:100%;border-radius:50%;'
        + 'background:transparent;'
        + (lnk ? 'transition:transform 420ms ease-in-out;' : '');
      
      var fill = document.createElement('div');
      fill.style.cssText = 'position:absolute;inset:0;border-radius:50%;background:' + discCol + ';'
        + 'will-change:opacity,transform;';
      face.appendChild(fill);
      disc.appendChild(face);
      wrap.appendChild(disc);
      shapeLayer.appendChild(wrap);

      
      if (self.discGlow) {
        face.style.boxShadow = '0 0 ' + Math.round(rr * 0.42) + 'px ' + _glowOn(fill);
      }
      if (lnk) {
        disc.setAttribute('href', lnk);
        
        disc.setAttribute('aria-label', t);

        
        var _fadeMs = 460, _fadeEase = 'ease-in-out', _hoverAnims = [];
        var _hoverTo = function (fillOpacity, fillScale, inkTo) {
          _hoverAnims.forEach(function (a) { try { a.cancel(); } catch (e) {} });
          _hoverAnims = [];
          try {
            _hoverAnims.push(fill.animate(
              [{ opacity: getComputedStyle(fill).opacity, transform: fill.style.transform || 'scale(1)' },
               { opacity: String(fillOpacity), transform: 'scale(' + fillScale + ')' }],
              { duration: _fadeMs, easing: _fadeEase, fill: 'forwards' }));
            if (label) {
              _hoverAnims.push(label.animate(
                [{ color: getComputedStyle(label).color }, { color: inkTo }],
                { duration: _fadeMs, easing: _fadeEase, fill: 'forwards' }));
            }
          } catch (e) {
            fill.style.opacity = String(fillOpacity);
            if (label) label.style.color = inkTo;
          }
        };
        disc.addEventListener('mouseenter', function () {
          self._discHold = true;          
          face.style.transform = 'scale(1.06)';
          _hoverTo(0, 0.94, discCol);
        });
        disc.addEventListener('mouseleave', function () {
          self._discHold = false;
          face.style.transform = '';
          _hoverTo(1, 1, _labelInk);
        });
        if (typeof window !== 'undefined' && window._impulseEditorPreview) {
          
          disc.addEventListener('click', function (e) { e.preventDefault(); });
        }
      }

      
      
      var _fixedFs = self.discFont > 0 ? Math.round(_discFontEff) : 0;
      var _words   = String(t).split(/\s+/).filter(Boolean);
      var _single  = Math.round(rr * 1.80);   
      var _multi   = Math.round(rr * 1.52);   
      probe.style.whiteSpace   = 'nowrap';
      probe.style.wordBreak    = 'normal';
      probe.style.overflowWrap = 'normal';
      probe.style.lineHeight   = '1.05';
      probe.style.width        = 'auto';
      probe.style.fontSize     = '100px';
      
      probe.textContent = t;
      var _wAll = probe.offsetWidth || 1;
      var _wWord = 1;
      for (var _wi = 0; _wi < _words.length; _wi++) {
        probe.textContent = _words[_wi];
        if (probe.offsetWidth > _wWord) _wWord = probe.offsetWidth;
      }
      var _design = _fixedFs || Math.round(rr * 0.34);   
      var _oneFs  = Math.floor(100 * _single / _wAll);
      var _boxW, lfs;
      if (_oneFs >= _design || _words.length < 2) {
        
        _boxW = _single;
        lfs = Math.max(7, Math.min(_design, _oneFs));
      } else {
        
        _boxW = _multi;
        lfs = Math.max(7, Math.min(_design, Math.floor(100 * _multi / _wWord)));
      }
      
      probe.style.whiteSpace = 'normal';
      probe.style.width = _boxW + 'px';
      probe.style.fontSize = lfs + 'px';
      var _hCap = rr * 1.50;
      for (var _gg = 0; _gg < 8 && lfs > 7
           && (probe.scrollHeight > _hCap || probe.scrollWidth > _boxW + 1); _gg++) {
        lfs = Math.max(7, lfs - Math.max(1, Math.round(lfs * 0.07)));
        probe.style.fontSize = lfs + 'px';
      }
      var _box = _boxW;

      var _sub = (self.discSubs && typeof self.discSubs[i] === 'string') ? self.discSubs[i].trim() : '';
      if (_sub && rr * 2 < 230) _sub = '';
      
      var _labelInk = self.discInk || _inkOn(fill);
      var label = document.createElement('div');
      if (!_sub) label.textContent = t;

      
      label.style.cssText = 'position:absolute;left:' + Math.round(rr - _box / 2) + 'px;'
        + 'top:0;width:' + _box + 'px;height:100%;'
        + 'display:flex;align-items:center;justify-content:center;'
        + 'font-weight:' + (self.kWeight || '900') + ';line-height:1.05;font-size:' + lfs + 'px;color:' + _labelInk + ';'
        + 'text-align:center;white-space:normal;word-break:normal;overflow-wrap:normal;'
        + 'pointer-events:none;will-change:transform;'
        + (_sub ? 'flex-direction:column;' : '');
      if (_sub) {
        var _m = document.createElement('div');
        _m.textContent = t;
        _m.style.cssText = 'font-size:' + Math.round(lfs * 0.82) + 'px;line-height:1.05;';
        var _s2 = document.createElement('div');
        _s2.textContent = _sub;
        _s2.style.cssText = 'margin-top:' + Math.round(lfs * 0.16) + 'px;font-weight:700;'
          + 'font-size:' + Math.max(9, Math.round(lfs * 0.34)) + 'px;line-height:1.1;opacity:0.78;';
        label.appendChild(_m); label.appendChild(_s2);
      }
      disc.appendChild(label);

      var dur = _ms(12000 + i * 1900, self.speed);
      var amp = Math.round(R * 0.34);
      var s1 = (i % 2 === 0) ? 1.12 : 0.9, s2 = (i % 2 === 0) ? 0.92 : 1.14;
      var spin = (i % 2 === 0) ? 8 : -8;
      var frames = [
        { transform: 'translate(0,0) scale(1) rotate(0deg)' },
        { transform: 'translate(' + amp + 'px,' + (-amp * 0.6) + 'px) scale(' + s1 + ') rotate(' + spin + 'deg)' },
        { transform: 'translate(' + (amp * 0.3) + 'px,' + amp + 'px) scale(' + s2 + ') rotate(' + (-spin) + 'deg)' },
        { transform: 'translate(' + (-amp * 0.8) + 'px,' + (amp * 0.2) + 'px) scale(' + s1 + ') rotate(' + (spin * 0.5) + 'deg)' },
        { transform: 'translate(0,0) scale(1) rotate(0deg)' }
      ];
      var opts = { duration: dur, iterations: self.loop ? Infinity : 1,
                   easing: 'ease-in-out', delay: -i * (dur * 0.21) };
      try { self._anims.push(disc.animate(frames, opts)); } catch (e) {}
      
      var lframes = frames.map(function (f) {
        var _m = /rotate\((-?[0-9.]+)deg\)/.exec(f.transform);
        return { transform: 'rotate(' + (_m ? -parseFloat(_m[1]) : 0) + 'deg)' };
      });
      try { self._anims.push(label.animate(lframes, opts)); } catch (e) {}

      inst2.push({ disc: disc, label: label, depth: [2.0, 0.35, 1.25, 0.7][i % 4] });
    });
    if (probe.parentNode) probe.parentNode.removeChild(probe);

    (function () {
      var tx = 0, ty = 0, cx3 = 0, cy3 = 0, raf = null;
      function tick() {
        raf = null;
        
        cx3 += (tx - cx3) * 0.03;
        cy3 += (ty - cy3) * 0.03;
        for (var i = 0; i < inst2.length; i++) {
          var u = inst2[i];
          
          u.disc.style.marginLeft = (cx3 * u.depth).toFixed(1) + 'px';
          u.disc.style.marginTop  = (cy3 * u.depth).toFixed(1) + 'px';
        }
        if (Math.abs(tx - cx3) > 0.3 || Math.abs(ty - cy3) > 0.3) raf = requestAnimationFrame(tick);
      }
      function onMove(e) {
        var r = self.el.getBoundingClientRect();
        if (!r.width || !r.height) return;
        
        var amp = Math.min(24, R * 0.10);
        
        if (self._discHold) return;
        tx = ((e.clientX - (r.left + r.width / 2)) / (r.width / 2)) * amp;
        ty = ((e.clientY - (r.top + r.height / 2)) / (r.height / 2)) * amp;
        if (!raf) raf = requestAnimationFrame(tick);
      }
      
      window.addEventListener('pointermove', onMove, { passive: true });
      self._timers.push(setTimeout(function () {}, 0));
      var off = function () { window.removeEventListener('pointermove', onMove); if (raf) cancelAnimationFrame(raf); };
      self._discOff = off;
    })();

    self._running = true;
  };

  KineticBlock.prototype._playHelix = function () {
    var self = this;
    var srcLines = self._compLines(2);
    if (!srcLines) return;
    
    var text = srcLines.join('      ') + '      ';

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var ix = self.intensity || 1;

    var _dia = (self.cylDiameter > 0 ? self.cylDiameter : 70) / 100;
    var R  = Math.min(stageW, stageH) * (_dia / 2) * (0.85 + ix * 0.15);
    var fs = Math.max(18, Math.round(Math.min(stageH * 0.16, stageW * 0.09)));
    var perTurn = Math.max(8, Math.round((2 * Math.PI * R) / (fs * 0.62)));

    var pitch = (fs * 1.25) / perTurn;
    var turns = Math.min(9, Math.max(4, Math.floor((stageH * 0.9) / (fs * 1.25))));
    if (turns < 3) turns = 3;
    var total = perTurn * turns;

    self._stage.style.perspective = Math.round(stageW * 1.3) + 'px';
    self._stage.style.perspectiveOrigin = '50% 50%';
    
    self._stage.style.overflow = 'visible';
    self.el.style.overflow = 'visible';
    var spin = document.createElement('div');
    spin.style.cssText = 'position:absolute;left:50%;top:50%;width:0;height:0;'
      + 'transform-style:preserve-3d;will-change:transform;';
    var y0 = -(total * pitch) / 2;
    for (var i = 0; i < total; i++) {
      var ch = text.charAt(i % text.length);
      if (ch === ' ') continue;
      var ang = (i / perTurn) * 360;
      
      var y = y0 + i * pitch;
      
      var base = 'position:absolute;left:0;top:0;line-height:1;font-weight:800;'
        + 'font-size:' + fs + 'px;color:' + self.color + ';backface-visibility:hidden;'
        + 'transform:translate(-50%,-50%) rotateY(' + ang.toFixed(1) + 'deg) translateZ(' + Math.round(R) + 'px)'
        + ' translateY(' + Math.round(y) + 'px)';
      var s = document.createElement('span');
      s.textContent = ch;
      s.style.cssText = base + ';';
      spin.appendChild(s);
      var s2 = document.createElement('span');
      s2.textContent = ch;
      s2.setAttribute('aria-hidden', 'true');
      s2.style.cssText = base + ' rotateY(180deg);opacity:0.5;';
      spin.appendChild(s2);
    }
    self._stage.appendChild(spin);
    
    var dur = _ms(24000, self.speed);
    try {
      self._anims.push(spin.animate(
        [{ transform: 'rotateY(0deg)' }, { transform: 'rotateY(360deg)' }],
        { duration: dur, iterations: self.loop ? Infinity : 1, easing: 'linear' }
      ));
    } catch (e) {}
    self._running = true;
  };

  KineticBlock.prototype._drawAccents = function () {
    var self = this;
    var a = self.accent;
    if (!a || a === 'none') return;
    var stage = self._stage;
    var W = stage.offsetWidth  || self.el.offsetWidth  || 600;
    var H = stage.offsetHeight || self.el.offsetHeight || 300;
    var col = self.color;
    var dur = _ms(650, self.speed);
    function mk(css) { var d = document.createElement('div'); d.style.cssText = 'position:absolute;will-change:opacity;' + css; return d; }
    function fade(el, to) {
      el.style.opacity = '0'; stage.appendChild(el);
      try { self._anims.push(el.animate([{ opacity: 0 }, { opacity: to }], { duration: dur, easing: 'ease-in-out', fill: 'forwards' })); } catch (e) {}
    }
    if (a === 'slash' || a === 'backslash') {
      var sk = (a === 'backslash') ? 12 : -12;
      var s = mk('left:7%;top:15%;font-size:' + Math.round(H * 0.13) + 'px;font-weight:800;line-height:1;color:' + col + ';letter-spacing:0.04em;transform:skewX(' + sk + 'deg);');
      s.textContent = (a === 'backslash') ? '\\\\' : '//';
      fade(s, 1);
    } else if (a === 'brackets') {
      var bw = Math.max(10, Math.round(W * 0.025)), bh = Math.round(H * 0.5), th = Math.max(3, Math.round(H * 0.014));
      fade(mk('left:5%;top:25%;width:' + bw + 'px;height:' + bh + 'px;border-left:' + th + 'px solid ' + col + ';border-top:' + th + 'px solid ' + col + ';border-bottom:' + th + 'px solid ' + col + ';'), 1);
      fade(mk('right:5%;top:25%;width:' + bw + 'px;height:' + bh + 'px;border-right:' + th + 'px solid ' + col + ';border-top:' + th + 'px solid ' + col + ';border-bottom:' + th + 'px solid ' + col + ';'), 1);
    } else if (a === 'frame') {
      fade(mk('left:5%;right:5%;top:7%;bottom:7%;box-sizing:border-box;border:' + Math.max(2, Math.round(H * 0.011)) + 'px solid ' + col + ';'), 1);
    } else if (a === 'numeral') {
      var t = (self.accentText || '').trim() || '01';
      var nm = mk('left:0;right:0;top:50%;transform:translateY(-50%);text-align:center;font-size:' + Math.round(H * 0.62) + 'px;font-weight:900;line-height:1;color:' + col + ';');
      nm.textContent = t;
      nm.style.opacity = '0';
      stage.insertBefore(nm, stage.firstChild); 
      try { self._anims.push(nm.animate([{ opacity: 0 }, { opacity: 0.12 }], { duration: dur, easing: 'ease-in-out', fill: 'forwards' })); } catch (e) {}
    }
  };

  KineticBlock.prototype._playArc = function () {
    var self = this;
    self._clearAll(); 

    var srcLines = (self.lines || []).map(function (l) { return (l && l.text || '').trim(); }).filter(Boolean);   
    if (self.customMode && Array.isArray(self.customLines) && self.customLines.length) {
      var cl = self.customLines
        .map(function (c) { return (c && c.text || '').trim(); })
        .filter(Boolean);
      if (cl.length) srcLines = cl;
    }
    srcLines = srcLines.slice(0, 4);
    if (!srcLines.length) {
      self._stage.innerHTML =
        '<span style="font-size:64px;opacity:0.18;letter-spacing:0.02em">Kinetic</span>';
      self._running = false;
      return;
    }

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var ix     = self.intensity || 1;

    var persp = Math.round(stageW * 1.15);
    self._stage.style.perspective = persp + 'px';
    self._stage.style.perspectiveOrigin = '50% 50%';

    var _am = document.createElement('span');
    _am.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:nowrap;'
      + 'visibility:hidden;font-weight:900;line-height:1;'
      + 'font-family:' + (self.fontStack || 'inherit') + ';font-size:100px;';
    self._stage.appendChild(_am);
    var _aWidest = 1;
    srcLines.forEach(function (t) { _am.textContent = t; if (_am.offsetWidth > _aWidest) _aWidest = _am.offsetWidth; });
    if (_am.parentNode) _am.parentNode.removeChild(_am);
    
    var _aFitW = Math.floor(100 * (stageW * 0.84) / _aWidest);
    var _aAuto = Math.min(stageH * 0.82 / (srcLines.length * 1.3), _aFitW);
    var fontSize = Math.max(16, Math.round(Math.min(
      self.compFont > 0 ? self.compFont : _aAuto,
      _aFitW
    )));

    var rig = document.createElement('div');
    rig.style.cssText =
      'position:absolute;inset:0;display:flex;flex-direction:column;' +
      'align-items:' + _alignFlex(self.align) + ';justify-content:center;gap:' + Math.round(fontSize * 0.16) + 'px;' +
      'transform-style:preserve-3d;will-change:transform;';

    var flyers = [];
    srcLines.forEach(function (text, li) {
      var lineEl = document.createElement('div');
      lineEl.style.cssText =
        'display:flex;justify-content:' + _alignFlex(self.align) + ';align-items:baseline;' +
        'white-space:nowrap;transform-style:preserve-3d;' +
        'font-size:' + Math.round(fontSize * _tierScale(self.tier, li)) + 'px;line-height:1.1;font-weight:800;' +
        'color:' + self.color + ';';
      [].forEach.call(text, function (ch) {
        var span = document.createElement('span');
        var isSpace = (ch === ' ');
        span.textContent = isSpace ? ' ' : ch; 
        span.style.cssText =
          'display:inline-block;transform-style:preserve-3d;' +
          'will-change:transform,opacity;backface-visibility:hidden;';
        if (!isSpace) {
          var s = flyers.length;
          
          var zin  = Math.round(persp * (0.80 + 0.12 * _rand(s * 3 + 1)));   
          var ryin = Math.round((_rand(s * 3 + 2) * 2 - 1) * 52 * ix);       
          var rzin = Math.round((_rand(s * 3 + 3) * 2 - 1) * 18);
          var dxin = Math.round((_rand(s * 5 + 1) * 2 - 1) * stageW * 0.16);
          var zout = Math.round(persp * (0.80 + 0.12 * _rand(s * 7 + 4)));
          var ryout= Math.round((_rand(s * 7 + 5) * 2 - 1) * 52 * ix);
          var dxout= Math.round((_rand(s * 7 + 6) * 2 - 1) * stageW * 0.12);
          var poseIn  = 'translateZ(' + zin  + 'px) translateX(' + dxin  + 'px) rotateY(' + ryin  + 'deg) rotateZ(' + rzin + 'deg)';
          var poseOut = 'translateZ(' + zout + 'px) translateX(' + dxout + 'px) rotateY(' + ryout + 'deg)';
          var poseRest= 'translateZ(0px) translateX(0px) rotateY(0deg) rotateZ(0deg)';
          
          span.style.transform = poseIn;
          span.style.opacity = '0';
          flyers.push({ el: span, poseIn: poseIn, poseOut: poseOut, poseRest: poseRest });
        }
        lineEl.appendChild(span);
      });
      rig.appendChild(lineEl);
    });
    self._stage.appendChild(rig);

    var SNAP     = SPRING_IN ; 
    var n        = flyers.length;
    var perIn    = _ms(42, self.speed);
    var flyDur   = _ms(620, self.speed);
    var inEnd    = (n > 0 ? (n - 1) : 0) * perIn + flyDur;
    var holdMs   = _ms(1500, self.speed);
    var outStart = inEnd + holdMs;
    var perOut   = _ms(32, self.speed);
    var outDur   = _ms(520, self.speed);
    var outEnd   = outStart + (n > 0 ? (n - 1) : 0) * perOut + outDur;
    var totalMs  = outEnd + _ms(250, self.speed);

    var amp = Math.round(13 * (0.6 + ix * 0.4));
    try {
      self._anims.push(rig.animate(
        [{ transform: 'rotateY(-' + amp + 'deg)' },
         { transform: 'rotateY('  + amp + 'deg)' }],
        { duration: totalMs, easing: 'ease-in-out', fill: 'forwards' }
      ));
    } catch (e) {}

    flyers.forEach(function (o, idx) {
      var t = setTimeout(function () {
        if (self._destroyed) return;
        try {
          self._anims.push(o.el.animate(
            [{ transform: o.poseIn,   opacity: 0 },
             { opacity: 1, offset: 0.15 },   
             { transform: o.poseRest, opacity: 1 }],
            { duration: flyDur, easing: SNAP, fill: 'forwards' }
          ));
        } catch (e) {}
      }, idx * perIn);
      self._timers.push(t);
    });

    if (self.loop) {
      flyers.forEach(function (o, idx) {
        var t = setTimeout(function () {
          if (self._destroyed) return;
          try {
            self._anims.push(o.el.animate(
              [{ transform: o.poseRest, opacity: 1 },
               { opacity: 1, offset: 0.6 },     
               { transform: o.poseOut,  opacity: 0 }],
              { duration: outDur, easing: SNAP, fill: 'forwards' }
            ));
          } catch (e) {}
        }, outStart + idx * perOut);
        self._timers.push(t);
      });

      var loopT = setTimeout(function () {
        if (self._destroyed || !self._running) return;
        self._playArc();
      }, totalMs);
      self._timers.push(loopT);
    }

    self._drawAccents();
    self._running = true;
  };

  KineticBlock.prototype._playSlide = function () {
    var self = this;
    self._clearAll(); 

    var srcLines = (self.lines || []).map(function (l) { return (l && l.text || '').trim(); }).filter(Boolean);   
    if (self.customMode && Array.isArray(self.customLines) && self.customLines.length) {
      var cl = self.customLines
        .map(function (c) { return (c && c.text || '').trim(); })
        .filter(Boolean);
      if (cl.length) srcLines = cl;
    }
    srcLines = srcLines.slice(0, 4);
    if (!srcLines.length) {
      self._stage.innerHTML =
        '<span style="font-size:64px;opacity:0.18;letter-spacing:0.02em">Kinetic</span>';
      self._running = false;
      return;
    }

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var ix     = self.intensity || 1;

    var fontSize = Math.max(16, Math.round(Math.min(
      stageH * 0.80 / (srcLines.length * 1.32),
      stageW * 0.15
    )));

    var SNAP = SPRING_IN ;
    var dxIn  = Math.round(stageW * (0.10 + 0.05 * ix)); 
    var dxOut = Math.round(stageW * (0.14 + 0.05 * ix)); 

    var group = document.createElement('div');
    group.style.cssText =
      'display:flex;flex-direction:column;align-items:flex-start;' +
      'gap:' + Math.round(fontSize * 0.12) + 'px;';

    var flyers = [];

    var accent = document.createElement('div');
    accent.textContent = '//';
    accent.style.cssText =
      'font-size:' + Math.round(fontSize * 0.5) + 'px;font-weight:800;line-height:1;' +
      'letter-spacing:' + Math.round(fontSize * 0.04) + 'px;' +
      'transform:skewX(-12deg);color:' + self.color + ';opacity:0;' +
      'margin-bottom:' + Math.round(fontSize * 0.06) + 'px;will-change:transform,opacity;';
    group.appendChild(accent);
    flyers.push({ el: accent, poseIn: 'translateX(-' + Math.round(stageW * 0.06) + 'px) skewX(-12deg)',
                  poseRest: 'translateX(0) skewX(-12deg)',
                  poseOut: 'translateX(-' + dxOut + 'px) skewX(-12deg)' });

    srcLines.forEach(function (text, li) {
      var lineEl = document.createElement('div');
      lineEl.style.cssText =
        'display:flex;justify-content:flex-start;align-items:baseline;white-space:nowrap;' +
        'font-size:' + Math.round(fontSize * _tierScale(self.tier, li)) + 'px;' +
        'line-height:1.04;font-weight:800;color:' + self.color + ';' +
        'letter-spacing:' + (li === 0 ? '0' : '0.12em') + ';';
      [].forEach.call(text, function (ch) {
        var span = document.createElement('span');
        var isSpace = (ch === ' ');
        span.textContent = isSpace ? ' ' : ch; 
        span.style.cssText = 'display:inline-block;will-change:transform,opacity;';
        if (!isSpace) {
          span.style.transform = 'translateX(' + dxIn + 'px)';
          span.style.opacity = '0';
          flyers.push({ el: span,
                        poseIn: 'translateX(' + dxIn + 'px)',
                        poseRest: 'translateX(0)',
                        poseOut: 'translateX(-' + dxOut + 'px)' });
        }
        lineEl.appendChild(span);
      });
      group.appendChild(lineEl);
    });
    self._stage.appendChild(group);

    var n        = flyers.length;
    var perIn    = _ms(34, self.speed);
    var slideDur = _ms(520, self.speed);
    var inEnd    = (n > 0 ? (n - 1) : 0) * perIn + slideDur;
    var holdMs   = _ms(1500, self.speed);
    var outStart = inEnd + holdMs;
    var perOut   = _ms(26, self.speed);
    var outDur   = _ms(420, self.speed);
    var outEnd   = outStart + (n > 0 ? (n - 1) : 0) * perOut + outDur;
    var totalMs  = outEnd + _ms(250, self.speed);

    flyers.forEach(function (o, idx) {
      var t = setTimeout(function () {
        if (self._destroyed) return;
        try {
          self._anims.push(o.el.animate(
            [{ transform: o.poseIn, opacity: 0 },
             { opacity: 1, offset: 0.35 },
             { transform: o.poseRest, opacity: 1 }],
            { duration: slideDur, easing: SNAP, fill: 'forwards' }
          ));
        } catch (e) {}
      }, idx * perIn);
      self._timers.push(t);
    });

    if (self.loop) {
      flyers.forEach(function (o, idx) {
        var t = setTimeout(function () {
          if (self._destroyed) return;
          try {
            self._anims.push(o.el.animate(
              [{ transform: o.poseRest, opacity: 1 },
               { transform: o.poseOut, opacity: 0 }],
              { duration: outDur, easing: SNAP, fill: 'forwards' }
            ));
          } catch (e) {}
        }, outStart + idx * perOut);
        self._timers.push(t);
      });

      var loopT = setTimeout(function () {
        if (self._destroyed || !self._running) return;
        self._playSlide();
      }, totalMs);
      self._timers.push(loopT);
    }

    self._drawAccents();
    self._running = true;
  };

  KineticBlock.prototype._playBrutal = function () {
    var self = this;
    self._clearAll();

    var srcLines = (self.lines || []).map(function (l) { return (l && l.text || '').trim(); }).filter(Boolean);   
    if (self.customMode && Array.isArray(self.customLines) && self.customLines.length) {
      var cl = self.customLines.map(function (c) { return (c && c.text || '').trim(); }).filter(Boolean);
      if (cl.length) srcLines = cl;
    }
    srcLines = srcLines.slice(0, 4);
    if (!srcLines.length) {
      self._stage.innerHTML = '<span style="font-size:64px;opacity:0.18;letter-spacing:0.02em">Kinetic</span>';
      self._running = false; return;
    }

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var ix     = self.intensity || 1;
    
    var _bm = document.createElement('span');
    _bm.style.cssText = 'position:absolute;left:-9999px;top:-9999px;white-space:nowrap;visibility:hidden;'
      + 'font-weight:900;line-height:1;font-family:' + (self.fontStack || 'inherit') + ';font-size:100px;';
    self._stage.appendChild(_bm);
    var _bWidest = 1;
    srcLines.forEach(function (t) { _bm.textContent = t; if (_bm.offsetWidth > _bWidest) _bWidest = _bm.offsetWidth; });
    if (_bm.parentNode) _bm.parentNode.removeChild(_bm);
    var fontSize = Math.max(16, Math.round(Math.min(
      stageH * 0.80 / (srcLines.length * 1.32),
      stageW * 0.16,
      100 * (stageW * 0.84) / _bWidest      
    )));

    function _darken(c, f) {
      var h = (c || '').replace('#', '');
      if (!/^[0-9a-fA-F]{3}$|^[0-9a-fA-F]{6}$/.test(h)) return 'rgba(0,0,0,0.55)';
      if (h.length === 3) h = h.split('').map(function (x) { return x + x; }).join('');
      var r = Math.round(parseInt(h.substr(0,2),16) * f);
      var g = Math.round(parseInt(h.substr(2,2),16) * f);
      var b = Math.round(parseInt(h.substr(4,2),16) * f);
      return 'rgb(' + r + ',' + g + ',' + b + ')';
    }
    
    var _bC1 = (self.discColors && self.discColors[0]) || self.color;
    var _bC2 = (self.discColors && self.discColors[1]) || _darken(_bC1, 0.42);
    
    function _bFaceOf(li)  { return (li % 2 === 1) ? _bC2 : _bC1; }
    function _bDepthOf(li) { return (li % 2 === 1) ? _bC1 : _bC2; }
    function extrude(px, li) {
      var s = [], col = _bDepthOf(li);
      for (var i = 1; i <= px; i++) s.push(i + 'px ' + i + 'px 0 ' + col);
      return s.join(',');
    }

    var SNAP  = SPRING_IN ;
    var dxIn  = Math.round(stageW * (0.14 + 0.05 * ix));
    var dxOut = Math.round(stageW * (0.18 + 0.05 * ix));

    var group = document.createElement('div');
    group.style.cssText = 'display:flex;flex-direction:column;align-items:' + _alignFlex(self.align)
      + ';gap:' + Math.round(fontSize * 0.12) + 'px;';

    var flyers = [];
    srcLines.forEach(function (text, li) {
      var lineFs = Math.round(fontSize * _tierScale(self.tier, li));
      var depth  = Math.max(2, Math.round(lineFs * 0.08));
      var lineEl = document.createElement('div');
      lineEl.style.cssText =
        'display:flex;justify-content:flex-start;align-items:baseline;white-space:nowrap;' +
        
        'font-size:' + lineFs + 'px;line-height:1.04;font-weight:900;color:'
          + _bFaceOf(li) + ';' +
        'letter-spacing:' + (li === 0 ? '0' : '0.08em') + ';text-shadow:' + extrude(depth, li) + ';';
      [].forEach.call(text, function (ch) {
        var span = document.createElement('span');
        var isSpace = (ch === ' ');
        span.textContent = isSpace ? ' ' : ch; 
        span.style.cssText = 'display:inline-block;will-change:transform,opacity;';
        if (!isSpace) {
          span.style.transform = 'translateX(' + dxIn + 'px) skewX(-8deg)';
          span.style.opacity = '0';
          flyers.push({ el: span,
            poseIn:  'translateX(' + dxIn + 'px) skewX(-8deg)',
            poseRest:'translateX(0) skewX(0deg)',
            poseOut: 'translateX(-' + dxOut + 'px) skewX(-8deg)' });
        }
        lineEl.appendChild(span);
      });
      group.appendChild(lineEl);
    });
    self._stage.appendChild(group);

    var n = flyers.length;
    var perIn = _ms(32, self.speed), inDur = _ms(500, self.speed);
    var inEnd = (n > 0 ? (n - 1) : 0) * perIn + inDur;
    var holdMs = _ms(1500, self.speed), outStart = inEnd + holdMs;
    var perOut = _ms(24, self.speed), outDur = _ms(400, self.speed);
    var totalMs = outStart + (n > 0 ? (n - 1) : 0) * perOut + outDur + _ms(250, self.speed);

    flyers.forEach(function (o, idx) {
      var t = setTimeout(function () {
        if (self._destroyed) return;
        try { self._anims.push(o.el.animate(
          [{ transform: o.poseIn, opacity: 0 }, { opacity: 1, offset: 0.35 }, { transform: o.poseRest, opacity: 1 }],
          { duration: inDur, easing: SNAP, fill: 'forwards' })); } catch (e) {}
      }, idx * perIn);
      self._timers.push(t);
    });
    
    if (self.loop) {
      flyers.forEach(function (o, idx) {
        var t = setTimeout(function () {
          if (self._destroyed) return;
          try { self._anims.push(o.el.animate(
            [{ transform: o.poseRest, opacity: 1 }, { transform: o.poseOut, opacity: 0 }],
            { duration: outDur, easing: SNAP, fill: 'forwards' })); } catch (e) {}
        }, outStart + idx * perOut);
        self._timers.push(t);
      });
      var loopT = setTimeout(function () { if (!self._destroyed && self._running) self._playBrutal(); }, totalMs);
      self._timers.push(loopT);
    }
    self._drawAccents();
    self._running = true;
  };

  KineticBlock.prototype._playSweep = function () {
    var self = this;
    self._clearAll();

    var srcLines = (self.lines || []).map(function (l) { return (l && l.text || '').trim(); }).filter(Boolean);   
    if (self.customMode && Array.isArray(self.customLines) && self.customLines.length) {
      var cl = self.customLines.map(function (c) { return (c && c.text || '').trim(); }).filter(Boolean);
      if (cl.length) srcLines = cl;
    }
    srcLines = srcLines.slice(0, 4);
    if (!srcLines.length) {
      self._stage.innerHTML = '<span style="font-size:64px;opacity:0.18;letter-spacing:0.02em">Kinetic</span>';
      self._running = false; return;
    }

    var stageH = self._stage.offsetHeight || self.el.offsetHeight || 300;
    var stageW = self._stage.offsetWidth  || self.el.offsetWidth  || 600;
    var fontSize = Math.max(16, Math.round(Math.min(stageH * 0.80 / (srcLines.length * 1.3), stageW * 0.15)));

    var pos = document.createElement('div');
    pos.style.cssText = 'position:relative;display:inline-block;';

    var textWrap = document.createElement('div');
    
    var _swPad = Math.ceil(fontSize * 0.3);
    textWrap.style.cssText =
      'display:flex;flex-direction:column;align-items:flex-start;' +
      'padding-bottom:' + _swPad + 'px;margin-bottom:' + (-_swPad) + 'px;' +
      'padding-top:' + _swPad + 'px;margin-top:' + (-_swPad) + 'px;' +
      'gap:' + Math.round(fontSize * 0.1) + 'px;clip-path:inset(0 100% 0 0);will-change:clip-path;';
    srcLines.forEach(function (text, li) {
      var _swLk = self._lineLink(li);
      var lineEl = document.createElement(_swLk ? 'a' : 'div');
      lineEl.textContent = text;
      lineEl.style.cssText =
        'white-space:nowrap;font-size:' + Math.round(fontSize * _tierScale(self.tier, li)) + 'px;' +
        
        'line-height:1.05;font-weight:800;color:' + self._lineInk(li) + ';' +
        'letter-spacing:' + (li === 0 ? '0' : '0.1em') + ';';
      self._gradApply(lineEl);
      if (_swLk) self._wireLink(lineEl, _swLk);   
      textWrap.appendChild(lineEl);
    });
    pos.appendChild(textWrap);

    var bar = document.createElement('div');
    bar.style.cssText =
      'position:absolute;top:-6%;left:0;height:112%;width:' + Math.max(4, Math.round(fontSize * 0.12)) + 'px;' +
      'background:' + self.color + ';transform:translateX(0) skewX(-12deg);will-change:transform;opacity:0;';
    pos.appendChild(bar);

    self._stage.appendChild(pos);

    void pos.offsetWidth;
    var w = pos.offsetWidth || Math.round(stageW * 0.6);

    var revealMs = _ms(900, self.speed);
    var holdMs   = _ms(1700, self.speed);
    
    var outMs    = _ms(420, self.speed);
    var totalMs  = revealMs + holdMs + outMs + _ms(250, self.speed);

    try {
      self._anims.push(textWrap.animate(
        [{ clipPath: 'inset(0 100% 0 0)' }, { clipPath: 'inset(0 0 0 0)' }],
        { duration: revealMs, easing: 'ease-in-out', fill: 'forwards' }));
      self._anims.push(bar.animate(
        [{ transform: 'translateX(0) skewX(-12deg)', opacity: 1 },
         { transform: 'translateX(' + w + 'px) skewX(-12deg)', opacity: 1 }],
        { duration: revealMs, easing: 'ease-in-out', fill: 'forwards' }));
    } catch (e) {}

    if (self.loop) {
      
      var outT = setTimeout(function () {
        if (self._destroyed) return;
        try {
          self._anims.push(textWrap.animate(
            
            [{ clipPath: 'inset(0 0 0 0)' }, { clipPath: 'inset(0 100% 0 0)' }],
            { duration: outMs, easing: 'ease-in-out', fill: 'forwards' }));
          self._anims.push(bar.animate(
            [{ transform: 'translateX(' + w + 'px) skewX(-12deg)', opacity: 1 },
             { transform: 'translateX(0) skewX(-12deg)', opacity: 1 }],
            { duration: outMs, easing: 'ease-in-out', fill: 'forwards' }));
        } catch (e) {}
      }, revealMs + holdMs);
      self._timers.push(outT);

      var loopT = setTimeout(function () { if (!self._destroyed && self._running) self._playSweep(); }, totalMs);
      self._timers.push(loopT);
    }
    self._drawAccents();
    self._running = true;
  };

  
  KineticBlock.prototype._gradLetterCss = function () {
    if (this.fill !== 'gradient') return '';
    return '-webkit-background-clip:text;background-clip:text;' +
           '-webkit-text-fill-color:transparent;background-repeat:no-repeat;';
  };

  KineticBlock.prototype._applyGradientScope = function (lineEls) {
    if (this.fill !== 'gradient' || !this._stage) return;
    var self  = this;
    var stage = this._stage;
    var c1 = this.gradC1, c2 = this.gradC2;
    var scope = (this.gradScope === 'line' || this.gradScope === 'letter') ? this.gradScope : 'block';
    var dur = (this.gradMode === 'spin' ? 5 : 3.5) / this.gradSpeed;
    dur = Math.max(0.3, Math.round(dur * 100) / 100);
    
    stage.style.animation = (this.gradMode === 'spin' ? 'kg-spin ' : 'kg-roll ') + dur + 's linear infinite';
    var sW = stage.offsetWidth || 1, sH = stage.offsetHeight || 1;
    var lin = 'linear-gradient(90deg,' + c1 + ',' + c2 + ',' + c1 + ')';
    lineEls.forEach(function (le) {
      var lx = le.el.offsetLeft, ly = le.el.offsetTop;
      var lw = le.el.offsetWidth || 1, lh = le.el.offsetHeight || 1;
      var chars = le.el.querySelectorAll('.kp-char');
      [].forEach.call(chars, function (ci) {
        
        var cx = ci.offsetLeft, cy = ci.offsetTop;
        var cw = ci.offsetWidth || 1, ch = ci.offsetHeight || 1;
        var refL, refT, refW, refH;
        if (scope === 'block')      { refL = 0;  refT = 0;  refW = sW; refH = sH; }
        else if (scope === 'line')  { refL = lx; refT = ly; refW = lw; refH = lh; }
        else                        { refL = cx; refT = cy; refW = cw; refH = ch; }
        if (self.gradMode === 'spin') {
          var atX = (refL + refW / 2 - cx).toFixed(1);
          var atY = (refT + refH / 2 - cy).toFixed(1);
          ci.style.backgroundImage = 'conic-gradient(from var(--kg-angle,0deg) at ' + atX + 'px ' + atY + 'px,' + c1 + ',' + c2 + ',' + c1 + ')';
          
          ci.style.backgroundSize = cw + 'px ' + Math.round(ch * 2.6) + 'px';
        } else {
          var relX = (cx - refL).toFixed(1);
          var w = Math.max(1, refW).toFixed(1);
          ci.style.backgroundImage = lin;
          
          ci.style.backgroundSize = w + 'px 300%';
          ci.style.backgroundRepeat = 'repeat';
          ci.style.backgroundPosition = 'calc(' + (-relX) + 'px - var(--kg,0) * ' + w + 'px) 0';
        }
      });
    });
  };

  KineticBlock.prototype._lineLink = function (idx) {
    return (this.discButtons && this.discLinks && typeof this.discLinks[idx] === 'string')
      ? this.discLinks[idx].trim() : '';
  };
  KineticBlock.prototype._wireLink = function (el, href) {
    el.setAttribute('href', href);
    el.style.pointerEvents = 'auto';      
    el.style.cursor = 'pointer';
    el.style.textDecoration = 'none';
    el.style.color = 'inherit';
    if (typeof window !== 'undefined' && window._impulseEditorPreview) {
      el.addEventListener('click', function (e) { e.preventDefault(); });
    }
  };

  KineticBlock.prototype._buildLine = function (textLine, slot, heroFont, lineIdx) {
    
    var _lnk = (this.discButtons && this.discLinks && typeof this.discLinks[lineIdx] === 'string')
      ? this.discLinks[lineIdx].trim() : '';
    var lineEl = document.createElement(_lnk ? 'a' : 'div');
    if (_lnk) {
      lineEl.setAttribute('href', _lnk);
      
      lineEl.style.pointerEvents = 'auto';
      lineEl.style.cursor = 'pointer';
      lineEl.style.textDecoration = 'none';
      lineEl.style.color = 'inherit';
      if (typeof window !== 'undefined' && window._impulseEditorPreview) {
        
        lineEl.addEventListener('click', function (e) { e.preventDefault(); });
      }
    }
    
    var slotScale = 1;
    if (this._useCustom) {
      var s = parseFloat(slot.scale);
      if (isFinite(s) && s > 0) slotScale = s;
    }
    
    var fontSize;
    if (this._useCustom && slot.px > 0) {
      fontSize = Math.max(12, Math.round(slot.px)); 
    } else {
      fontSize = Math.max(12, Math.round(heroFont * slotScale));
    }
    
    var famCss = (this._useCustom && slot.font)   ? 'font-family:' + slot.font + ';' : '';
    var wtCss  = (this._useCustom && slot.weight) ? 'font-weight:' + slot.weight + ';' : '';
    
    var _lineColor = (this._useCustom && slot.color) ? slot.color : this.color;
    var colCss = 'color:' + _lineColor + ';';

    var _pxWrap = (this._useCustom && slot.px > 0);
    var _kWrap = this.maxWidth > 0 || _pxWrap;
    var _kWrapPct = this.maxWidth > 0 ? this.maxWidth : 90;
    var _kJust = this.align === 'left' ? 'flex-start' : (this.align === 'right' ? 'flex-end' : 'center');
    lineEl.style.cssText =
      'display:flex;flex-wrap:' + (_kWrap ? 'wrap' : 'nowrap') + ';justify-content:' + (_kWrap ? _kJust : 'center') + ';align-items:baseline;' +
      (_kWrap ? ('max-width:' + _kWrapPct + '%;') : '') +

      'column-gap:0.32em;' +
      (_kWrap ? ('align-content:flex-start;row-gap:'
        + Math.max(0, 0.10 + (this.lineGap / 100) * 0.45).toFixed(3) + 'em;') : '') +
      'font-size:' + fontSize + 'px;line-height:1;' + famCss + wtCss + colCss +
      'white-space:nowrap;direction:ltr;overflow:visible;' +
      'will-change:transform,opacity,filter';
    
    lineEl.className = (lineEl.className ? lineEl.className + ' ' : '') + 'kp-line';
    lineEl.setAttribute('data-role', slot.role || '');
    
    var _ctg = slot.target || (slot.enter && slot.enter.target) || 'letter';
    lineEl.setAttribute('data-cur-gran', (_ctg === 'line' || _ctg === 'whole') ? 'line' : (_ctg === 'word' ? 'word' : 'letter'));

    var MASK_BASE =
      'display:inline-block;line-height:1;overflow:hidden;vertical-align:baseline;';

    var _kFam = (this._useCustom && slot.font) ? slot.font : this.fontStack;
    var _kWt  = (this._useCustom && slot.weight) ? slot.weight : '800';
    var _descEm = _kDescentEm(textLine.words.join(' '), _kFam, _kWt);

    var _padEm  = Math.max(0.03, _descEm + 0.08);
    var MASK_CSS = MASK_BASE + 'padding-bottom:' + (Math.round(_padEm * 1000) / 1000) + 'em;';
    
    if (_kWrap) {
      MASK_CSS += 'margin-bottom:' + (-(Math.round(_padEm * 1000) / 1000)) + 'em;';
    }
    
    var _blurry = ['blur-in', 'blur-out', 'distort-in', 'distort-out', 'glitch-in', 'glitch-out'];
    if ((slot.enter && _blurry.indexOf(slot.enter.motion) !== -1) ||
        (slot.exit && _blurry.indexOf(slot.exit.motion) !== -1)) {
      var _bp = 0.45;
      MASK_CSS = MASK_BASE
        + 'padding:' + _bp + 'em ' + _bp + 'em ' + (Math.round((_padEm + _bp) * 1000) / 1000) + 'em;'
        + 'margin:-' + _bp + 'em -' + _bp + 'em -' + _bp + 'em;';
    }
    var INNER_CSS_W =
      'display:inline-block;line-height:1;' +
      'will-change:transform,opacity,filter,letter-spacing';
    var INNER_CSS_C =
      'display:inline-block;line-height:1;' +
      'will-change:transform,opacity,filter';
    
    if (this.fill === 'gradient') INNER_CSS_C += ';' + this._gradLetterCss()
      + 'padding-bottom:' + (Math.round(Math.max(_padEm, 0.34) * 1000) / 1000) + 'em;';

    textLine.words.forEach(function (w) {
      var wordMask = document.createElement('span');
      wordMask.className = 'kp-word-mask';
      wordMask.style.cssText = MASK_CSS;

      var wordInner = document.createElement('span');
      wordInner.className = 'kp-word';
      wordInner.style.cssText = INNER_CSS_W;

      [].forEach.call(w, function (ch) {
        var charMask = document.createElement('span');
        charMask.className = 'kp-char-mask';
        charMask.style.cssText = MASK_CSS;

        var charInner = document.createElement('span');
        charInner.className = 'kp-char';
        charInner.textContent = ch;
        charInner.style.cssText = INNER_CSS_C;

        charMask.appendChild(charInner);
        wordInner.appendChild(charMask);
      });

      wordMask.appendChild(wordInner);
      lineEl.appendChild(wordMask);
    });

    var enterMotion = slot.enter && MOTIONS[slot.enter.motion];
    if (enterMotion && enterMotion.initial) {
      var evtIx = (slot.enter.intensity != null) ? slot.enter.intensity : 1;
      var ix    = evtIx * (this.intensity || 1);
      var targets = this._getTargets(lineEl, (slot.enter.target || 'word'));
      var n = targets.length;
      targets.forEach(function (t, i) {
        var init = _resolve(enterMotion.initial, ix, i, n);
        if (init) t.style.cssText += ';' + init;
        
        if (init && /clip-path/.test(init)) {
          var _fsPx = parseFloat(getComputedStyle(t).fontSize) || 0;
          if (_fsPx > 0) {
            var _pad = Math.ceil(_fsPx * 0.3);
            t.style.paddingBottom = _pad + 'px';
            t.style.marginBottom = (-_pad) + 'px';
            t.style.paddingTop = _pad + 'px';
            t.style.marginTop = (-_pad) + 'px';
          }
        }
      });
    }
    return lineEl;
  };

  KineticBlock.prototype._getTargets = function (lineEl, target) {
    if (target === 'whole' || target === 'line') return [lineEl];
    if (target === 'word')   return [].slice.call(lineEl.querySelectorAll('.kp-word'));
    if (target === 'letter') return [].slice.call(lineEl.querySelectorAll('.kp-char'));
    return [lineEl];
  };

  KineticBlock.prototype._schedule = function (lineEl, evt) {
    var self = this;
    if (!evt || !evt.motion) return 0;
    var motion = MOTIONS[evt.motion];
    if (!motion) return 0;
    var startOffset  = _ms(evt.at || 0, self.speed);
    var dur          = _ms(evt.dur || motion.duration, self.speed);
    var staggerFn    = STAGGERS[evt.stagger || 'simultaneous'] || STAGGERS.simultaneous;
    var staggerScale = (evt.staggerScale != null) ? evt.staggerScale : 1;
    var evtIx        = (evt.intensity != null) ? evt.intensity : 1;
    var ix           = evtIx * (self.intensity || 1);
    var targets      = self._getTargets(lineEl, evt.target || 'word');
    var n            = targets.length;
    if (!n || !dur) return 0;

    var maxDelay = 0;
    var _inst = !!self._instantRefit;  
    targets.forEach(function (target, i) {
      var delay = staggerFn(i, n, dur) * staggerScale;
      var t = setTimeout(function () {
        if (self._destroyed) return;
        try {
          var kfData = _resolve(motion.kf, ix, i, n);
          var a = target.animate(kfData, {
            duration: dur,
            easing:   motion.easing,
            fill:     'forwards'
          });
          self._anims.push(a);
          if (_inst) { try { a.finish(); } catch (e2) {} }
        } catch (e) {}
      }, _inst ? 0 : (startOffset + delay));
      self._timers.push(t);
      if (delay > maxDelay) maxDelay = delay;
    });
    return startOffset + maxDelay + dur;
  };

  KineticBlock.prototype._buildDecor = function (shape, attachRect, stageRect, dc) {
    var widthMult  = (dc && dc.widthMult  != null) ? dc.widthMult  : shape.widthMult;
    var heightMult = (dc && dc.heightMult != null) ? dc.heightMult : shape.heightMult;
    var heightPx   = (dc && dc.heightPx   != null) ? dc.heightPx   : shape.heightPx;
    var placementOverride = (dc && dc.placement) ? dc.placement : null;
    var offsetOverride    = (dc && dc.offset != null) ? dc.offset : null;

    var w = (widthMult != null) ? attachRect.width * widthMult : null;
    var h;
    if (heightPx != null) {
      h = heightPx;
    } else if (heightMult != null) {
      h = attachRect.height * heightMult;
    } else {
      h = attachRect.height;
    }

    var top = attachRect.top - stageRect.top;
    var left = attachRect.left - stageRect.left;
    var placement = placementOverride || shape.placement || 'overlay';
    var offset = (offsetOverride != null) ? offsetOverride : (shape.offset || 0);
    var y, x;
    if (placement === 'below') {
      y = top + attachRect.height + offset;
      x = left + (attachRect.width - w) / 2;
    } else if (placement === 'above') {
      y = top - h - offset;
      x = left + (attachRect.width - w) / 2;
    } else if (placement === 'left-of') {
      y = top + (attachRect.height - h) / 2;
      x = left - w - offset;
    } else if (placement === 'right-of') {
      y = top + (attachRect.height - h) / 2;
      x = left + attachRect.width + offset;
    } else if (placement === 'overlay-mid') {
      
      y = top + (attachRect.height - h) / 2;
      x = left + (attachRect.width - w) / 2;
    } else {
      
      y = top + (attachRect.height - h) / 2;
      x = left + (attachRect.width - w) / 2;
    }

    var wrap = document.createElement('div');
    wrap.style.cssText =
      'position:absolute;left:' + Math.round(x) + 'px;top:' + Math.round(y) + 'px;' +
      'width:' + Math.round(w) + 'px;height:' + Math.round(h) + 'px;' +
      'pointer-events:none;color:' + this.color + ';' +
      (shape.behind ? 'z-index:-1;' : 'z-index:1;') +
      (shape.opacity != null ? 'opacity:' + shape.opacity + ';' : '');

    var svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="' + shape.viewBox + '" preserveAspectRatio="none" style="display:block;width:100%;height:100%;overflow:visible">' + shape.inner + '</svg>';
    wrap.innerHTML = svg;

    if (shape.drawn && dc && dc.enter && dc.enter.motion === 'draw-on') {
      var strokes = wrap.querySelectorAll('path, line, polyline, polygon, ellipse, circle, rect');
      [].forEach.call(strokes, function (el) {
        el.style.strokeDasharray  = '99999';
        el.style.strokeDashoffset = '99999';
      });
    }
    return wrap;
  };

  KineticBlock.prototype._scheduleDecor = function (decorEl, shape, evt) {
    var self = this;
    if (!evt || !evt.motion) return 0;
    var motion = DECOR_MOTIONS[evt.motion];
    if (!motion) return 0;
    var startOffset = _ms(evt.at || 0, self.speed);
    var dur = _ms(evt.dur || motion.duration, self.speed);
    
    var _inst = !!self._instantRefit;
    if (_inst) startOffset = 0;

    var t = setTimeout(function () {
      if (self._destroyed) return;
      try {
        if (motion.drawOn) {
          
          var strokes = decorEl.querySelectorAll('path, line, polyline, polygon, ellipse, circle, rect');
          [].forEach.call(strokes, function (el) {
            var len = (el.getTotalLength) ? el.getTotalLength() : 200;
            if (!len) len = 200;
            el.style.strokeDasharray = len + '';
            el._drawLength = len;
            var a = el.animate(
              [ { strokeDashoffset: len }, { strokeDashoffset: 0 } ],
              { duration: dur, easing: motion.easing, fill: 'forwards' }
            );
            
            a.onfinish = function () { el.style.strokeDashoffset = '0'; };
            self._anims.push(a);
            if (_inst) { try { a.finish(); } catch (e2) {} }
          });
        } else if (motion.drawOff) {
          var strokesOff = decorEl.querySelectorAll('path, line, polyline, polygon, ellipse, circle, rect');
          [].forEach.call(strokesOff, function (el) {
            var len = el._drawLength;
            if (!len) {
              len = (el.getTotalLength) ? el.getTotalLength() : 200;
              if (!len) len = 200;
              el.style.strokeDasharray = len + '';
              el._drawLength = len;
            }
            var a = el.animate(
              [ { strokeDashoffset: 0 }, { strokeDashoffset: len } ],
              { duration: dur, easing: motion.easing, fill: 'forwards' }
            );
            
            a.onfinish = function () { el.style.strokeDashoffset = len + ''; };
            self._anims.push(a);
            if (_inst) { try { a.finish(); } catch (e2) {} }
          });
        } else if (motion.kf) {
          var a = decorEl.animate(motion.kf, {
            duration: dur,
            easing: motion.easing,
            fill: 'forwards'
          });
          self._anims.push(a);
            if (_inst) { try { a.finish(); } catch (e2) {} }
        }
      } catch (e) {}
    }, startOffset);
    self._timers.push(t);
    return startOffset + dur;
  };

  KineticBlock.prototype._applyDecorInitial = function (decorEl, shape, enterEvt) {
    if (!enterEvt || !enterEvt.motion) return;
    var motion = DECOR_MOTIONS[enterEvt.motion];
    if (!motion || !motion.initial) return;
    decorEl.style.cssText += ';' + motion.initial;
  };

  KineticBlock.prototype.destroy = function () {
    this._destroyed = true;
    this._running   = false;
    if (this._stopCursorFX) this._stopCursorFX();
    if (this._io) { this._io.disconnect(); this._io = null; }
    if (this._ro) { try { this._ro.disconnect(); } catch (e) {} this._ro = null; }
    if (this._screenMO) { try { this._screenMO.disconnect(); } catch (e) {} this._screenMO = null; }
    if (this._safetyStop) { try { this._safetyStop(); } catch (e) {} }
    this._clearAll();
  };

  function initAll() {
    var blocks = document.querySelectorAll('.impulse-kinetic-block:not([data-kinetic])');
    [].forEach.call(blocks, function (el) {
      el.setAttribute('data-kinetic', '1');
      el._kineticInst = new KineticBlock(el);
    });
    if (_isScreenMode()) {
      var seen = document.querySelectorAll('.impulse-kinetic-block[data-kinetic]');
      [].forEach.call(seen, function (el) {
        var inst = el._kineticInst;
        if (!inst || inst._running) return;
        var sc = _kScreenEl(el);
        if (sc && sc.classList.contains('impulse-screen-active')) inst._run();
      });
    }
  }

  var ENTRY_MOTIONS_FOR_PANEL = [
    { group: 'Translate', motions: [
      { value: 'rise',                label: 'Rise' },
      { value: 'drop',                label: 'Drop' },
      { value: 'glide-from-l',        label: 'Glide from left' },
      { value: 'glide-from-r',        label: 'Glide from right' },
      { value: 'bounce-slide-l',      label: 'Bounce-slide left' },
      { value: 'bounce-slide-split',  label: 'Bounce-slide split' },
      { value: 'bounce-rise',         label: 'Bounce-rise' },
      { value: 'skew-in',             label: 'Skew' }
    ]},
    { group: 'Scale', motions: [
      { value: 'zoom-in',             label: 'Zoom' },
      { value: 'scatter-in',          label: 'Scatter' }
    ]},
    { group: 'Fade / blur', motions: [
      { value: 'fade-in',             label: 'Fade in' },
      { value: 'blur-in',             label: 'Blur in' },
      { value: 'spacing-in',          label: 'Letter-spacing in' },
      { value: 'letter-kick-in',      label: 'Letter kick' }
    ]},
    { group: 'Clip-mask', motions: [
      { value: 'circle-reveal',       label: 'Circle reveal' },
      { value: 'slit-open',           label: 'Slit open' },
      { value: 'box-in',              label: 'Box open' },
      { value: 'wipe-right',          label: 'Wipe right' },
      { value: 'wipe-left',           label: 'Wipe left' },
      { value: 'wipe-up',             label: 'Wipe up' },
      { value: 'wipe-down',           label: 'Wipe down' }
    ]},
    { group: 'Glitch / noise', motions: [
      { value: 'glitch-in',           label: 'Glitch' },
      { value: 'distort-in',          label: 'Distort' },
      { value: 'shake-in',            label: 'Shake' },
      { value: 'noise-flicker',       label: 'Static flicker' }
    ]},
    { group: '3D (procedural)', motions: [
      { value: 'flip-up-in',          label: 'Flip up' },
      { value: 'flip-down-in',        label: 'Flip down' },
      { value: 'spin-in',             label: 'Spin' },
      { value: 'swing-in',            label: 'Swing' },
      { value: 'unfold-in',           label: 'Unfold' },
      { value: 'curtain-in',          label: 'Curtain' },
      { value: 'depth-in',            label: 'Depth' },
      { value: 'depth-fly-in',        label: 'Depth fly' },
      { value: 'tumble-in',           label: 'Tumble' }
    ]},
    { group: 'Variable font', motions: [
      { value: 'weight-morph-in',     label: 'Weight morph' }
    ]}
  ];

  window.ImpulseKinetic = {
    init: initAll,
    initEl: function (el) {
      var prevH = 0, origMinH = el.style.minHeight;
      if (el._kineticInst) {
        prevH = el.offsetHeight;   
        try { el._kineticInst.destroy(); } catch (e) {}
        delete el._kineticInst;
        el.removeAttribute('data-kinetic');
      }
      el.setAttribute('data-kinetic', '1');
      
      if (prevH > 2) {
        el._kOrigMinH = origMinH;
        el._kHoldMinH = true;
        el.style.minHeight = Math.max(prevH, parseFloat(origMinH) || 0) + 'px';
        setTimeout(function () {
          if (el._kHoldMinH) { el.style.minHeight = el._kOrigMinH || ''; el._kHoldMinH = false; }
        }, 900);
      }
      el._kineticInst = new KineticBlock(el);
    },
    destroyEl: function (el) {
      if (el._kineticInst) { el._kineticInst.destroy(); delete el._kineticInst; }
      el.removeAttribute('data-kinetic');
    },
    
    compositions:      COMPOSITIONS,
    motions:           MOTIONS,
    staggers:          STAGGERS,
    entryMotionGroups: ENTRY_MOTIONS_FOR_PANEL
  };

  (function () {
    
    var _pw = window.impulsePreWarmScreen;
    window.impulsePreWarmScreen = function (screenEl) {
      if (_pw) _pw(screenEl);
      if (!screenEl || !screenEl.querySelectorAll) return;
      screenEl.querySelectorAll('.impulse-kinetic-block').forEach(function (el) {
        var inst = el._kineticInst;
        if (!inst || inst._shown || inst._running || inst._exiting) return;
        inst._run();
      });
    };
    var _pf = window.impulseOnScreenFocus;
    window.impulseOnScreenFocus = function (screenEl) {
      if (_pf) _pf(screenEl);
      screenEl.querySelectorAll('.impulse-kinetic-block').forEach(function (el) {
        var inst = el._kineticInst;
        if (!inst) return;
        
        if (!inst._shown && !inst._running && !inst._exiting) inst._run();
      });
    };
    
    var _pl = window.impulseOnScreenLeave;
    window.impulseOnScreenLeave = function (screenEl) {
      if (_pl) _pl(screenEl);
      if (!screenEl || !screenEl.querySelectorAll) return;
      screenEl.querySelectorAll('.impulse-kinetic-block').forEach(function (el) {
        var inst = el._kineticInst;
        if (!inst || !inst._shown) return;
        if (inst.scrollExit === 'spring' || inst.scrollExit === 'fade') inst._scrollExitAnim(inst.scrollExit);
      });
    };
    var _pr = window.impulseAnimatorReset;
    window.impulseAnimatorReset = function (screenEl) {
      if (_pr) _pr(screenEl);
      screenEl.querySelectorAll('.impulse-kinetic-block').forEach(function (el) {
        var inst = el._kineticInst;
        if (!inst) return;
        
        if (inst._exiting) return;
        inst._pause();
      });
    };
  })();

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