/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = "./src/js/view/advanced-slider.js");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./src/js/_shared/advanced-slider.js":
/*!*******************************************!*\
  !*** ./src/js/_shared/advanced-slider.js ***!
  \*******************************************/
/*! exports provided: ADVANCED_SLIDER_EASING_CURVES, toAlphabet, toRoman, escapeHtml, getPaginationType, getPaginationPosition, buildPaginationConfig, mountPaginationHost, swiperLoader */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADVANCED_SLIDER_EASING_CURVES\", function() { return ADVANCED_SLIDER_EASING_CURVES; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"toAlphabet\", function() { return toAlphabet; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"toRoman\", function() { return toRoman; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"escapeHtml\", function() { return escapeHtml; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"getPaginationType\", function() { return getPaginationType; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"getPaginationPosition\", function() { return getPaginationPosition; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"buildPaginationConfig\", function() { return buildPaginationConfig; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"mountPaginationHost\", function() { return mountPaginationHost; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"swiperLoader\", function() { return swiperLoader; });\n/**\n * EA Advanced Slider — shared helpers\n *\n * Imported by BOTH `src/js/view/advanced-slider.js` (frontend + editor\n * preview iframe) and `src/js/edit/advanced-slider.js` (Elementor editor\n * control-change handler). Phase 6 is gradually moving duplicated helpers\n * here; until that migration is complete, the view and edit entries will\n * still each contain their own copies of some helpers — extract one piece\n * at a time and verify the editor + frontend both still work before\n * lifting the next one.\n *\n * Webpack 4's entry globber only scans `src/js/view/*` and `src/js/edit/*`\n * (see webpack.config.js — `outputEntry()`), so files under `src/js/_shared/`\n * are never treated as entry points. They're inlined into any bundle that\n * imports them. Net cost: one copy each in view + edit's minified output,\n * but a SINGLE source of truth in this directory.\n *\n * Conventions:\n *   - Export only pure functions / constants with no closure dependencies\n *     on either bundle's runtime state.\n *   - Helpers that need jQuery should accept `$` as a parameter instead\n *     of relying on a closure (view JS has helpers at IIFE-top, edit JS\n *     re-creates them per call — neither contract carries here).\n *   - Keep editor-only behaviour (rAF token tracking, swiper.destroy\n *     teardown) in `edit/advanced-slider.js`. This file is shared, not\n *     editor-flavoured.\n */\n\n/* ─────────── Constants ─────────── */\n\n/**\n * Easing presets for the Advanced Slider's slide-transition timing.\n *\n * Both bundles read `$scope.attr('data-easing')` (set by PHP from the\n * `eael_advanced_slider_transition_easing` control) and look the preset\n * up in this map. The selected curve is written via\n * `setProperty('transition-timing-function', curve, 'important')` so it\n * beats the SCSS rule `transition-timing-function: var(--eael-as-easing)\n * !important` in the cascade. See applyTransitionEasing in either entry.\n */\nvar ADVANCED_SLIDER_EASING_CURVES = {\n  smooth: 'cubic-bezier(0.4, 0, 0.2, 1)',\n  snappy: 'cubic-bezier(0.7, 0, 0.3, 1)',\n  spring: 'cubic-bezier(0.22, 1, 0.36, 1)',\n  soft: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)'\n};\n\n/**\n * Valid pagination types the user can select in the\n * `eael_advanced_slider_pagination_type` control. Anything else (including\n * an unrecognised legacy value) is coerced to 'tick_bars' by\n * getPaginationType() so the slider never renders without pagination.\n *\n * Order: discrete (Swiper-pagination-module) types first, custom-DOM\n * types last. Not user-facing — getPaginationType() is the only consumer.\n */\nvar PAGINATION_TYPES = ['dots', 'dots_vertical', 'fraction', 'tick_bars', 'progress_bar', 'thumbnails', 'numbered_index'];\n\n/* ─────────── Pure helpers (no jQuery, no closure deps) ─────────── */\n\n/**\n * 0 → 'A', 1 → 'B', 2 → 'C', ...  — index-label generator for the\n * 'numbered_index' pagination type's 'alphabet' format.\n * Wraps at 25 → 'Z'; consumers should cap slide count or fall through to\n * the default 'number' format for sliders with > 26 slides.\n */\nvar toAlphabet = function toAlphabet(num) {\n  return String.fromCharCode(65 + num); // 0 → A, 1 → B, 2 → C ...\n};\n\n/**\n * 1 → 'I', 4 → 'IV', 5 → 'V', 9 → 'IX', 10 → 'X', etc. — Roman numeral\n * generator for the 'numbered_index' pagination type's 'roman' format.\n * Slide indices are 1-based by convention for this format.\n */\nvar toRoman = function toRoman(num) {\n  var map = [{\n    v: 1000,\n    s: 'M'\n  }, {\n    v: 900,\n    s: 'CM'\n  }, {\n    v: 500,\n    s: 'D'\n  }, {\n    v: 400,\n    s: 'CD'\n  }, {\n    v: 100,\n    s: 'C'\n  }, {\n    v: 90,\n    s: 'XC'\n  }, {\n    v: 50,\n    s: 'L'\n  }, {\n    v: 40,\n    s: 'XL'\n  }, {\n    v: 10,\n    s: 'X'\n  }, {\n    v: 9,\n    s: 'IX'\n  }, {\n    v: 5,\n    s: 'V'\n  }, {\n    v: 4,\n    s: 'IV'\n  }, {\n    v: 1,\n    s: 'I'\n  }];\n  var result = '';\n  map.forEach(function (o) {\n    while (num >= o.v) {\n      result += o.s;\n      num -= o.v;\n    }\n  });\n  return result;\n};\n\n/**\n * Minimal HTML-entity escape. Used when injecting user-controlled strings\n * (slide image URLs, alt text) into innerHTML / attribute values.\n *\n * NOT a substitute for proper PHP escaping at render time — this is a\n * client-side defence-in-depth for strings that came from Elementor's\n * model (already kses'd at save time) and need to survive a JS round-trip.\n */\nvar escapeHtml = function escapeHtml(str) {\n  if (str === null || str === undefined) return '';\n  return String(str).replace(/[&<>\"']/g, function (c) {\n    return {\n      '&': '&amp;',\n      '<': '&lt;',\n      '>': '&gt;',\n      '\"': '&quot;',\n      \"'\": '&#39;'\n    }[c];\n  });\n};\n\n/**\n * Resolve the active pagination type from saved settings.\n *\n * - 'none' → renders no pagination\n * - Any value in PAGINATION_TYPES → that exact value\n * - Anything else (including undefined) → fall through to 'tick_bars'\n *   (the default for fresh sliders so the user sees pagination immediately\n *   and can switch it off via the dropdown).\n */\nvar getPaginationType = function getPaginationType(options) {\n  if ((options === null || options === void 0 ? void 0 : options.pagination_type) === 'none') return 'none';\n  if (options !== null && options !== void 0 && options.pagination_type && PAGINATION_TYPES.indexOf(options.pagination_type) !== -1) {\n    return options.pagination_type;\n  }\n  return 'tick_bars';\n};\n\n/**\n * Resolve the active pagination position from saved settings.\n *\n * Dots Vertical is the one type whose position is structurally fixed\n * (right rail) — the position control is hidden in the editor for that\n * type but a saved slider could still carry a stale position value, so\n * we force-override here. Everything else falls through to the saved\n * value or 'bottom' as default.\n */\nvar getPaginationPosition = function getPaginationPosition(options) {\n  if (getPaginationType(options) === 'dots_vertical') return 'right_center';\n  return (options === null || options === void 0 ? void 0 : options.pagination_position) || 'bottom';\n};\n\n/**\n * Build the Swiper pagination config object for a given type.\n *\n * Returns null for types that don't use Swiper's pagination module —\n * 'progress_bar', 'thumbnails', 'numbered_index' all render via custom\n * DOM in their own build*Nav() helpers (those stay in the view/edit\n * entries because they wire in Swiper-instance event listeners and\n * editor-only state).\n *\n * NOTE: do NOT pass `verticalClass: ''` here. Modern Swiper calls\n * `classList.add(params.verticalClass)` which throws DOMTokenList.add:\n * \"The empty string is not a valid token\", aborting the entire\n * swiperInstancePromise chain. We let Swiper apply its default\n * `.swiper-pagination-vertical` class and override the visual position\n * via the SCSS rule\n *   `.eael-advanced-slider-vertical .swiper-pagination.swiper-pagination-vertical`.\n */\nvar buildPaginationConfig = function buildPaginationConfig(type, el) {\n  if (!el || type === 'none' || type === 'progress_bar' || type === 'thumbnails' || type === 'numbered_index') return null;\n  var base = {\n    el: el,\n    clickable: true\n  };\n  if (type === 'fraction') {\n    return Object.assign({}, base, {\n      type: 'fraction',\n      renderFraction: function renderFraction(currentClass, totalClass) {\n        return '<span class=\"' + currentClass + ' eael-as-fraction-current\"></span>' + '<span class=\"eael-as-fraction-sep\">/</span>' + '<span class=\"' + totalClass + ' eael-as-fraction-total\"></span>';\n      }\n    });\n  }\n  if (type === 'tick_bars') {\n    // Bullets (not custom) so each tick is a clickable button.\n    // CSS styles `.eael-as-tick-bar` as a vertical bar.\n    return Object.assign({}, base, {\n      type: 'bullets',\n      bulletClass: 'eael-as-tick-bar',\n      bulletActiveClass: 'is-active',\n      bulletElement: 'button'\n    });\n  }\n  // 'dots' and 'dots_vertical'\n  return Object.assign({}, base, {\n    type: 'bullets',\n    bulletClass: 'eael-as-bullet',\n    bulletActiveClass: 'eael-as-bullet-active',\n    bulletElement: 'button'\n  });\n};\n\n/* ─────────── jQuery-aware helpers ($ passed as parameter) ─────────── */\n\n/**\n * Create the pagination host element and append it to $scope (the outer\n * .eael-advanced-slider). Always mount OUTSIDE the .swiper child element so\n * 3D effects (cards / flip / coverflow) — which apply preserve-3d to the\n * .swiper container — don't drag pagination into their 3D context (where\n * it would inherit perspective transforms and render at unintended depth).\n *\n * Signature: ($scope, $inner, type, position, $) — note `$inner` is\n * currently unused inside the helper but kept on the signature for\n * symmetry with future variants that may need it (e.g. mounting inside\n * .swiper for specific types).\n */\nvar mountPaginationHost = function mountPaginationHost($scope, $inner, type, position, $) {\n  if (type === 'none') return null;\n  var typeClass = 'eael-as-pagination--type-' + type.replace(/_/g, '-');\n  var posClass = 'eael-as-pagination--position-' + position.replace(/_/g, '-');\n  var $host = $('<div class=\"eael-as-pagination ' + typeClass + ' ' + posClass + '\"></div>');\n  $scope.append($host);\n  return $host;\n};\n\n/* ─────────── Swiper loader ─────────── */\n\n/**\n * Internal: wrap synchronous `new Swiper(...)` in a Promise so the loader\n * always returns the same shape.\n */\nvar swiperPromise = function swiperPromise(swiperElement, swiperConfig) {\n  return new Promise(function (resolve) {\n    var swiperInstance = new Swiper(swiperElement, swiperConfig);\n    resolve(swiperInstance);\n  });\n};\n\n/**\n * Async Swiper bootstrapper. Returns a Promise<Swiper>.\n *\n * Two paths because Elementor lazy-loads Swiper:\n *   - If global `Swiper` (constructor) is already on window, use it\n *     directly via swiperPromise.\n *   - Otherwise use elementorFrontend.utils.swiper, which kicks off the\n *     async fetch and resolves once Swiper's bundle has loaded.\n *\n * `typeof Swiper === 'function'` covers the loaded-but-not-yet-instantiated\n * case; `typeof Swiper === 'undefined'` is the not-yet-loaded case (also\n * routed through the async loader, falling through here would throw a\n * ReferenceError).\n */\nvar swiperLoader = function swiperLoader(swiperElement, swiperConfig) {\n  if ('undefined' === typeof Swiper || 'function' === typeof Swiper) {\n    var asyncSwiper = elementorFrontend.utils.swiper;\n    return new asyncSwiper(swiperElement, swiperConfig).then(function (newSwiperInstance) {\n      return newSwiperInstance;\n    });\n  }\n  return swiperPromise(swiperElement, swiperConfig);\n};\n\n//# sourceURL=webpack:///./src/js/_shared/advanced-slider.js?");

/***/ }),

/***/ "./src/js/view/advanced-slider.js":
/*!****************************************!*\
  !*** ./src/js/view/advanced-slider.js ***!
  \****************************************/
/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../_shared/advanced-slider.js */ \"./src/js/_shared/advanced-slider.js\");\nfunction ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }\nfunction _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }\nfunction _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }\nfunction _toPropertyKey(t) { var i = _toPrimitive(t, \"string\"); return \"symbol\" == _typeof(i) ? i : i + \"\"; }\nfunction _toPrimitive(t, r) { if (\"object\" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || \"default\"); if (\"object\" != _typeof(i)) return i; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (\"string\" === r ? String : Number)(t); }\nfunction _typeof(o) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && \"function\" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? \"symbol\" : typeof o; }, _typeof(o); }\nfunction _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\nfunction _unsupportedIterableToArray(r, a) { if (r) { if (\"string\" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return \"Object\" === t && r.constructor && (t = r.constructor.name), \"Map\" === t || \"Set\" === t ? Array.from(r) : \"Arguments\" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }\nfunction _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }\nfunction _iterableToArrayLimit(r, l) { var t = null == r ? null : \"undefined\" != typeof Symbol && r[Symbol.iterator] || r[\"@@iterator\"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t[\"return\"] && (u = t[\"return\"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }\nfunction _arrayWithHoles(r) { if (Array.isArray(r)) return r; }\n/**\n * EA Advanced Slider — view (frontend + editor preview iframe)\n * Wrapped in an IIFE so AdvancedSliderHandler is module-local and cannot collide\n * with the same identifier in src/js/edit/advanced-slider.js.\n */\n\n(function () {\n  var AdvancedSliderHandler = function AdvancedSliderHandler($scope, $) {\n    if (!$scope.hasClass('eael-advanced-slider')) return;\n    var options = $scope.data('options');\n    if ((options === null || options === void 0 ? void 0 : options.effect) === 'slide' && (options === null || options === void 0 ? void 0 : options.direction) === 'vertical' && (options === null || options === void 0 ? void 0 : options.manualScrolling) === 'yes') {\n      initVerticalSlider($scope, options, $);\n    } else if ((options === null || options === void 0 ? void 0 : options.effect) === 'slide' && (options === null || options === void 0 ? void 0 : options.direction) === 'horizontal' && (options === null || options === void 0 ? void 0 : options.marquee) === 'yes') {\n      initMarqueeSlider($scope, options, $);\n    } else {\n      initSwiperSlider($scope, options, $);\n    }\n  };\n  var initMarqueeSlider = function initMarqueeSlider($scope, options, $) {\n    var $inner = $scope.find('> .e-con-inner');\n    $inner.addClass('eael-as-track');\n    var $html = $scope.html();\n    if ($scope.hasClass('e-con-full')) {\n      $scope.html('');\n      $scope.append('<div class=\"eael-as-track\"></div>');\n    }\n    var $track = $scope.find('.eael-as-track');\n    if (options !== null && options !== void 0 && options.gap) {\n      $track.css('gap', (options === null || options === void 0 ? void 0 : options.gap) + 'px');\n    }\n    if ($scope.hasClass('e-con-full')) {\n      $track.html($html);\n    }\n    var duplicateTrackContent = function duplicateTrackContent() {\n      var $originalChildren = $track.children().clone(true);\n      if (!$originalChildren.length) {\n        return;\n      }\n      for (var i = 0; i < 4; i++) {\n        $track.append($originalChildren.clone(true));\n      }\n    };\n    duplicateTrackContent();\n\n    // Speed (px/sec)\n    var SPEED_PX_PER_SEC = (options === null || options === void 0 ? void 0 : options.speed) || 50;\n    function setDuration() {\n      // const totalWidth = $track[0].scrollWidth / 2;\n      var duration = SPEED_PX_PER_SEC / 20;\n      $track.css('--duration', duration + 's');\n      $track.css('--flex-wrap', 'nowrap');\n    }\n    setDuration();\n    $(window).on('resize', setDuration);\n    if ('yes' === (options === null || options === void 0 ? void 0 : options.pauseOnHover)) {\n      // Pause on hover\n      $track.on('mouseenter', function () {\n        $(this).css('animation-play-state', 'paused');\n      });\n      $track.on('mouseleave', function () {\n        $(this).css('animation-play-state', 'running');\n      });\n    }\n  };\n\n  /* Pagination helpers (eaelGetPaginationType, eaelGetPaginationPosition,\n     eaelEscapeHtml, eaelBuildPaginationConfig, eaelMountPaginationHost) are\n     imported from ../_shared/advanced-slider.js with `as eael*` aliases so\n     the existing callsites in this file don't need renaming. See Phase 6.1\n     commit message for the rationale on the dedup. */\n\n  /**\n   * Auto-fit slide height for 3D effects (cards / flip / coverflow).\n   * Measures the natural content height of every slide, picks the max, and\n   * sets the swiper container to that height so all slides fit without clipping.\n   * Re-runs on window resize and after images load.\n   */\n  var eaelAutoFitHeight = function eaelAutoFitHeight($scope, swiper, $) {\n    var $swiperEl = $scope.children('.swiper').first();\n    if (!$swiperEl.length) return;\n    var $slides = $swiperEl.find('> .swiper-wrapper > .swiper-slide');\n    if (!$slides.length) return;\n    var measure = function measure() {\n      // Snapshot the existing inline styles so we can restore them.\n      var slidesPrevHeight = [];\n      $slides.each(function () {\n        slidesPrevHeight.push(this.style.height);\n      });\n      var swiperPrevHeight = $swiperEl[0].style.height;\n\n      // Temporarily release height constraints so each slide reports its\n      // natural content height.\n      $slides.css('height', 'auto');\n      $swiperEl.css('height', 'auto');\n      // Force a synchronous reflow before measuring.\n      // eslint-disable-next-line no-unused-expressions\n      $swiperEl[0].offsetHeight;\n      var maxH = 0;\n      $slides.each(function () {\n        var h = this.scrollHeight;\n        if (h > maxH) maxH = h;\n      });\n\n      // Restore slide heights to fill the container, set container to max.\n      $slides.each(function (i) {\n        this.style.height = slidesPrevHeight[i] || '';\n      });\n      if (maxH > 0) {\n        $swiperEl.css('height', maxH + 'px');\n      } else {\n        $swiperEl[0].style.height = swiperPrevHeight;\n      }\n      if (swiper && typeof swiper.update === 'function') swiper.update();\n    };\n    measure();\n    // Re-measure when images inside slides finish loading. Debounce so a\n    // burst of image loads triggers exactly one measurement, not N.\n    var imgTimer;\n    var debouncedMeasure = function debouncedMeasure() {\n      clearTimeout(imgTimer);\n      imgTimer = setTimeout(measure, 150);\n    };\n    $scope.find('img').each(function () {\n      if (!this.complete) {\n        this.addEventListener('load', debouncedMeasure, {\n          once: true\n        });\n      }\n    });\n    // Re-measure on resize (debounced).\n    var resizeTimer;\n    $(window).off('resize.eaelAutoFit-' + ($scope.attr('id') || '')).on('resize.eaelAutoFit-' + ($scope.attr('id') || ''), function () {\n      clearTimeout(resizeTimer);\n      resizeTimer = setTimeout(measure, 150);\n    });\n  };\n\n  /**\n   * Time-based Autoplay Progress Bar (replicates demo V3 — Travel magazine\n   * \"Fade hero with timing\"). Includes play/pause toggle, animated linear bar\n   * that fills with autoplay countdown (resets on slide change), and a\n   * \"01 / 04\" fraction counter. Lives outside Swiper's pagination module.\n   */\n  var eaelBuildProgressBarNav = function eaelBuildProgressBarNav($scope, options, $) {\n    var position = ((options === null || options === void 0 ? void 0 : options.pagination_position) || 'bottom').replace(/_/g, '-');\n    /* pause/play SVG paths re-centered.\n       Pause: two 4-wide bars from x=8/x=14 (was 6/14). Optical center now at\n       x=12.5 instead of x=11, matching the geometric center of the 24-unit\n       viewBox.\n       Play: triangle from x=7, y=5 to x=18,y=12 to x=7,y=19 — the visual\n       weight (centroid) of a triangle sits ~1/3 from the base, so we shift\n       the path right of geometric center to make the rendered triangle\n       *appear* centered in the round button.\n       SVG sizing now lives in CSS (.eael-as-pb-toggle svg) so style changes\n       don't require a JS re-build. */\n    var $host = $('<div class=\"eael-as-pagination eael-as-pagination--type-progress-bar eael-as-pagination--position-' + position + '\">' + '<button type=\"button\" class=\"eael-as-pb-toggle\" aria-label=\"Pause autoplay\">' + '<svg class=\"eael-as-pb-pause\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><rect x=\"7\" y=\"5\" width=\"3.5\" height=\"14\" rx=\"1\"/><rect x=\"13.5\" y=\"5\" width=\"3.5\" height=\"14\" rx=\"1\"/></svg>' + '<svg class=\"eael-as-pb-play\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=\"display:none\" aria-hidden=\"true\"><path d=\"M7.5 5.2v13.6c0 .8.9 1.3 1.6.9l11-6.8c.6-.4.6-1.4 0-1.8l-11-6.8c-.7-.4-1.6 0-1.6.9z\"/></svg>' + '</button>' + '<div class=\"eael-as-pb-track\"><div class=\"eael-as-pb-fill\"></div></div>' + '<div class=\"eael-as-pb-counter\"><strong class=\"eael-as-pb-current\">01</strong><span class=\"eael-as-pb-sep\">/</span><span class=\"eael-as-pb-total\">01</span></div>' + '</div>');\n    $scope.append($host);\n    return {\n      $host: $host,\n      attach: function attach(swiper) {\n        if (!swiper) return;\n        var $fill = $host.find('.eael-as-pb-fill');\n        var $current = $host.find('.eael-as-pb-current');\n        var $total = $host.find('.eael-as-pb-total');\n        var $toggle = $host.find('.eael-as-pb-toggle');\n        var $iconPause = $host.find('.eael-as-pb-pause');\n        var $iconPlay = $host.find('.eael-as-pb-play');\n        var totalSlides = swiper.slides.length - (swiper.params.loop ? 2 * swiper.loopedSlides : 0);\n        var safeTotal = Math.max(1, totalSlides);\n        $total.text(String(safeTotal).padStart(2, '0'));\n        $current.text(String((swiper.realIndex || 0) + 1).padStart(2, '0'));\n\n        /* Make the fill animation work for ANY effect — not just\n           fade. Previously `paused = !(swiper.autoplay && swiper.autoplay.running)`\n           could latch true at attach time (e.g. coverflow/cards where\n           autoplay hasn't started its first tick yet) and the fill never\n           moved until the user clicked the toggle. Pin paused to the\n           actual autoplay-enabled flag. If autoplay is enabled at all,\n           the fill should animate; we'll start the swiper's autoplay if\n           it's not already running. */\n        var autoplayEnabled = !!(swiper.params.autoplay && (swiper.params.autoplay.delay || swiper.params.autoplay === true));\n        var delay = (options === null || options === void 0 ? void 0 : options.autoplay_speed) || swiper.params.autoplay && swiper.params.autoplay.delay || 3000;\n        /* A slide is on screen for `delay` (autoplay dwell) PLUS `speed`\n           (the slide transition) because Swiper autoplay defaults to\n           waitForTransition:true. With slow/panning transitions `speed`\n           can dwarf `delay` (e.g. delay 2000ms, speed 4881ms), so a fill\n           that spans only `delay` finishes ~5s before the next slide\n           arrives. Span the FULL visible cycle so the bar completes exactly\n           as the next slide settles. */\n        var transitionSpeed = swiper.params.speed || 0;\n        var cycle = delay + transitionSpeed;\n        var startTime = performance.now();\n        var paused = !autoplayEnabled;\n        // If autoplay is enabled but not yet running, kick it off so the\n        // fill has a real ticking baseline.\n        if (autoplayEnabled && swiper.autoplay && !swiper.autoplay.running) {\n          try {\n            swiper.autoplay.start();\n          } catch (e) {}\n        }\n        var setPausedUI = function setPausedUI(isPaused) {\n          paused = isPaused;\n          $iconPause.css('display', isPaused ? 'none' : '');\n          $iconPlay.css('display', isPaused ? '' : 'none');\n          $toggle.attr('aria-label', isPaused ? 'Resume autoplay' : 'Pause autoplay');\n        };\n        setPausedUI(paused);\n        $toggle.on('click', function () {\n          if (paused) {\n            startTime = performance.now();\n            if (swiper.autoplay) swiper.autoplay.start();\n            setPausedUI(false);\n          } else {\n            if (swiper.autoplay) swiper.autoplay.stop();\n            setPausedUI(true);\n          }\n        });\n        swiper.on('slideChange', function () {\n          startTime = performance.now();\n          $current.text(String((swiper.realIndex || 0) + 1).padStart(2, '0'));\n          // ensure the fill snaps back to 0 immediately so the\n          // next cycle starts visibly from empty even if the rAF tick\n          // happens to land mid-frame.\n          $fill.css('width', '0%');\n        });\n        swiper.on('autoplayStart', function () {\n          return setPausedUI(false);\n        });\n        swiper.on('autoplayStop', function () {\n          return setPausedUI(true);\n        });\n        swiper.on('autoplayPause', function () {\n          return setPausedUI(true);\n        });\n        swiper.on('autoplayResume', function () {\n          return setPausedUI(false);\n        });\n\n        /* rAF drives the fill across the full `cycle` (dwell + transition),\n           not Swiper's `autoplayTimeLeft` — that event only reports the\n           `delay` portion, so with long transitions the bar would finish\n           while the slide is still panning. startTime resets on slideChange\n           (above), so the bar empties when a slide starts moving and reaches\n           100% exactly as the next slide starts moving — staying locked to\n           the slider regardless of how large `speed` is. */\n        var _tick = function tick() {\n          if (!paused) {\n            var elapsed = performance.now() - startTime;\n            var pct = Math.min(100, elapsed / cycle * 100);\n            $fill.css('width', pct + '%');\n          }\n          requestAnimationFrame(_tick);\n        };\n        _tick();\n      }\n    };\n  };\n\n  /**\n   * Build the Thumbnails sub-Swiper. Auto-detects images per slide:\n   *   1. first <img> inside the slide\n   *   2. first inline background-image url(...)\n   *   3. fallback to a numbered placeholder\n   *\n   * IMPORTANT: returns a Promise-producing factory (`getThumbsSwiperAsync`),\n   * not a synchronous `new Swiper()`. On the frontend, Elementor loads Swiper\n   * asynchronously via `elementorFrontend.utils.swiper`, and `window.Swiper`\n   * may not be the canonical Swiper class until the loader resolves. Using\n   * `swiperLoader` ensures the thumbs sub-swiper uses the SAME Swiper class\n   * as the main slider, so the `mainSwiper.thumbs.swiper` reference is valid.\n   */\n  var eaelBuildThumbnailsNav = function eaelBuildThumbnailsNav($scope, $slides, options, $) {\n    var position = ((options === null || options === void 0 ? void 0 : options.pagination_position) || 'bottom').replace(/_/g, '-');\n    var $host = $('<div class=\"eael-as-thumbnails eael-as-thumbnails--position-' + position + '\"></div>');\n    var $thumbsSwiper = $('<div class=\"swiper eael-as-thumbnails-swiper\"></div>');\n    var $thumbsWrapper = $('<div class=\"swiper-wrapper\"></div>');\n    $slides.each(function (i) {\n      var $slide = $(this);\n      var imgSrc = $slide.find('img').first().attr('src') || '';\n      if (!imgSrc) {\n        var $bgEl = $slide.find('[style*=\"background-image\"]').first();\n        if ($bgEl.length) {\n          var m = ($bgEl.attr('style') || '').match(/background-image\\s*:\\s*url\\(['\"]?([^'\"\\)]+)/);\n          if (m) imgSrc = m[1];\n        }\n      }\n      var inner = imgSrc ? '<img src=\"' + Object(_shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"escapeHtml\"])(imgSrc) + '\" alt=\"\">' : '<span class=\"eael-as-thumb-num\">' + (i + 1) + '</span>';\n      $thumbsWrapper.append('<div class=\"swiper-slide eael-as-thumb\">' + inner + '</div>');\n    });\n    $thumbsSwiper.append($thumbsWrapper);\n    $host.append($thumbsSwiper);\n    $scope.append($host);\n    return {\n      $host: $host,\n      $thumbsSwiperEl: $thumbsSwiper,\n      // Returns a Promise that resolves to the thumbs Swiper instance.\n      getThumbsSwiperAsync: function getThumbsSwiperAsync() {\n        return Object(_shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"swiperLoader\"])($thumbsSwiper[0], {\n          slidesPerView: 'auto',\n          spaceBetween: 8,\n          centerInsufficientSlides: true,\n          watchSlidesProgress: true,\n          slideToClickedSlide: true\n        });\n      }\n    };\n  };\n\n  /**\n   * Numbered Index navigation rail. Generates 01/02/03 (number),\n   * A/B/C (alphabet), or I/II/III (roman) buttons that scrub the slider.\n   */\n  var eaelBuildNumberedIndexNav = function eaelBuildNumberedIndexNav($scope, $slides, options, $) {\n    var format = (options === null || options === void 0 ? void 0 : options.index_format) || 'number';\n    var $host = $('<nav class=\"eael-as-pagination eael-as-pagination--type-numbered-index eael-as-pagination--position-' + ((options === null || options === void 0 ? void 0 : options.pagination_position) || 'bottom').replace(/_/g, '-') + '\" aria-label=\"Slider navigation\"></nav>');\n    $slides.each(function (i) {\n      var label;\n      if (format === 'alphabet') label = String.fromCharCode(65 + i);else if (format === 'roman') {\n        var map = [[10, 'X'], [9, 'IX'], [5, 'V'], [4, 'IV'], [1, 'I']];\n        var n = i + 1,\n          s = '';\n        map.forEach(function (_ref) {\n          var _ref2 = _slicedToArray(_ref, 2),\n            v = _ref2[0],\n            sym = _ref2[1];\n          while (n >= v) {\n            s += sym;\n            n -= v;\n          }\n        });\n        label = s;\n      } else label = String(i + 1).padStart(2, '0');\n      $host.append('<button type=\"button\" class=\"eael-as-index-item' + (i === 0 ? ' is-active' : '') + '\" data-index=\"' + i + '\">' + '<span class=\"eael-as-index-label\">' + label + '</span>' + '<span class=\"eael-as-index-bar\" aria-hidden=\"true\"></span>' + '</button>');\n    });\n    $scope.append($host);\n    return {\n      $host: $host,\n      onSlideChange: function onSlideChange(idx) {\n        $host.find('.eael-as-index-item').removeClass('is-active');\n        $host.find('.eael-as-index-item[data-index=\"' + idx + '\"]').addClass('is-active');\n      },\n      bindClicks: function bindClicks(swiper) {\n        $host.on('click', '.eael-as-index-item', function () {\n          var idx = parseInt($(this).attr('data-index'), 10);\n          if (!isNaN(idx)) swiper.slideTo(idx);\n        });\n      }\n    };\n  };\n\n  /* toAlphabet, toRoman imported from ../_shared/advanced-slider.js (Phase 6.1). */\n\n  var initVerticalSlider = function initVerticalSlider($scope, options, $) {\n    var $inner = $scope.find('> .e-con-inner');\n    // `.e-con` covers nested Elementor flex containers as direct children.\n    // Pre-Elementor-4.x layouts used `.e-child` / `.elementor-widget`; the\n    // newer flex containers render as `.e-con` and were silently missed,\n    // producing zero-slide Swiper init and a raw stacked render.\n    var $slides = $inner.find('> .e-child, > .elementor-column, > .elementor-widget, > .e-con');\n    var $is_grid = $scope.hasClass('e-grid') || $scope.hasClass('e-con-full');\n    if ($is_grid && !$slides.length) {\n      $slides = $scope.find('> .e-child, > .elementor-column, > .elementor-widget, > .e-con');\n      $inner = $('<div class=\"eael-advanced-slider-inner\"></div>');\n      $slides.appendTo($inner);\n      $scope.append($inner);\n      $scope.css('display', 'block');\n    }\n    $slides.addClass('eael-advanced-slider-slide');\n    $inner.addClass('eael-advanced-slider-inner');\n    if ('yes' === (options === null || options === void 0 ? void 0 : options.indicator)) {\n      // Append indicator dynamically if not exist or indicator_type is not empty\n      var $indicator = $('<ul id=\"eael-advanced-slider-' + $scope.data('id') + '\" class=\"eael-as-indicator\"></ul>');\n      var mode = (options === null || options === void 0 ? void 0 : options.indicator_type) || '';\n      $slides.each(function (i) {\n        $(this).attr('data-index', i);\n        var label = mode === 'alphabet' ? Object(_shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"toAlphabet\"])(i) : mode === 'roman' ? Object(_shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"toRoman\"])(i + 1) : i + 1;\n        $indicator.append(\"<li class=\\\"eael-as-indicator-index\\\" data-index=\\\"\".concat(i, \"\\\">\").concat(label, \"</li>\"));\n      });\n      $scope.append($indicator);\n    }\n    var $indicators = $scope.find('.eael-as-indicator-index');\n    function update(entries) {\n      entries.forEach(function (entry) {\n        var i = $(entry.target).data('index');\n        $indicators.eq(i).toggleClass('expand', entry.isIntersecting);\n      });\n    }\n    function detect(slide) {\n      var options = {\n        threshold: 0.2\n      };\n      var io = new IntersectionObserver(update, options);\n      io.observe(slide);\n    }\n    function init() {\n      $slides.each(function () {\n        detect(this);\n      });\n    }\n    $(window).on('load', init);\n  };\n  var initSwiperSlider = function initSwiperSlider($scope, options, $) {\n    var $inner = $scope.find('> .e-con-inner');\n    if (!$inner.length) {\n      $inner = $scope.find('> .elementor-container, > .elementor-column-wrap > .elementor-widget-wrap, > .elementor-widget-wrap');\n    }\n    if (!$inner.length) {\n      $inner = $scope;\n    }\n    var $is_grid = $scope.hasClass('e-grid') || $scope.hasClass('e-con-full');\n    // `.e-con` catches nested Elementor flex containers (4.x) as direct\n    // children. Without it, sliders whose children are containers rather\n    // than widgets render with zero slides on the frontend.\n    var $slides = $inner.find('> .e-child, > .elementor-column, > .elementor-widget, > .e-con');\n    var $wrapper = $inner.find('> .swiper-wrapper');\n    if ($is_grid && !$slides.length) {\n      $slides = $scope.find('> .e-child, > .elementor-column, > .elementor-widget, > .e-con');\n      // Wrap slides in a new swiper-wrapper\n      $wrapper = $scope.find('> .swiper-wrapper');\n      $scope.css('display', 'block');\n    }\n    if ($wrapper.length === 0) {\n      $wrapper = $('<div class=\"swiper-wrapper\"></div>');\n      $slides.appendTo($wrapper);\n      if ($is_grid && !$inner.length) {\n        $inner = $scope;\n      }\n      $inner.append($wrapper);\n    }\n\n    // Add swiper container class\n    $inner.addClass('swiper');\n\n    // Make each slide valid. `.e-con` covers Elementor flex containers used as slides.\n    $wrapper.find('> .e-child, > .elementor-column, > .elementor-widget, > .e-con').addClass('swiper-slide');\n    var $navHost = $scope.find('.swiper-wrapper').parent();\n    var sliderDirection = (options === null || options === void 0 ? void 0 : options.direction) || 'horizontal';\n    var isCardsEffect = (options === null || options === void 0 ? void 0 : options.effect) === 'cards';\n    var isFadeEffect = (options === null || options === void 0 ? void 0 : options.effect) === 'fade';\n    var isFlipEffect = (options === null || options === void 0 ? void 0 : options.effect) === 'flip';\n    var isSingleSlideEffect = isFadeEffect || isFlipEffect;\n    var slidesPerViewValue = isCardsEffect ? 'auto' : isSingleSlideEffect ? 1 : (options === null || options === void 0 ? void 0 : options.items) || 3;\n    var spaceBetweenValue = isCardsEffect ? (options === null || options === void 0 ? void 0 : options.gap) || 0 : isSingleSlideEffect ? 0 : (options === null || options === void 0 ? void 0 : options.gap) || 10;\n\n    // Arrows mount whenever the Arrows toggle is on — including vertical\n    // direction (up/down nav). Previously gated on a non-vertical check\n    // which silently dropped arrows on vertical sliders in the frontend.\n    if ('yes' === (options === null || options === void 0 ? void 0 : options.navigation_arrows)) {\n      var $left_icon = '';\n      var $right_icon = '';\n      if (options !== null && options !== void 0 && options.navigation_icon_left) {\n        $left_icon = atob(options === null || options === void 0 ? void 0 : options.navigation_icon_left);\n      }\n      if (options !== null && options !== void 0 && options.navigation_icon_right) {\n        $right_icon = atob(options === null || options === void 0 ? void 0 : options.navigation_icon_right);\n      }\n\n      // Append navigation & pagination dynamically if not exist\n      if ($navHost.find('.swiper-button-next').length === 0) {\n        if ($right_icon) {\n          $navHost.append('<div class=\"swiper-button-next eael-as-nav-icon\" aria-label=\"Next\">' + $right_icon + '</div>');\n        } else {\n          $navHost.append('<div class=\"swiper-button-next\" aria-label=\"Next\"></div>');\n        }\n      }\n      if ($navHost.find('.swiper-button-prev').length === 0) {\n        if ($left_icon) {\n          $navHost.append('<div class=\"swiper-button-prev eael-as-nav-icon\" aria-label=\"Previous\">' + $left_icon + '</div>');\n        } else {\n          $navHost.append('<div class=\"swiper-button-prev\" aria-label=\"Previous\"></div>');\n        }\n      }\n    }\n\n    /* ──────────────── Pagination (new contract) ──────────────── */\n    var paginationType = Object(_shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"getPaginationType\"])(options);\n    var paginationPosition = Object(_shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"getPaginationPosition\"])(options);\n    var $paginationEl = null;\n    var thumbnailsNav = null;\n    var numberedIndexNav = null;\n    var progressBarNav = null;\n\n    // Mark the wrapper so CSS can scope styles per type/position.\n    $scope.addClass('eael-as-pag-' + paginationType.replace(/_/g, '-')).addClass('eael-as-pos-' + paginationPosition.replace(/_/g, '-'));\n    var $slidesForNav = $wrapper.find('> .swiper-slide');\n    if (paginationType === 'thumbnails') {\n      thumbnailsNav = eaelBuildThumbnailsNav($scope, $slidesForNav, options, $);\n    } else if (paginationType === 'numbered_index') {\n      numberedIndexNav = eaelBuildNumberedIndexNav($scope, $slidesForNav, options, $);\n    } else if (paginationType === 'progress_bar') {\n      progressBarNav = eaelBuildProgressBarNav($scope, options, $);\n    } else if (paginationType !== 'none') {\n      $paginationEl = Object(_shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"mountPaginationHost\"])($scope, $inner, paginationType, paginationPosition, $);\n    }\n\n    // \"Inline with arrows\": co-locate prev-arrow + pagination + next-arrow in a\n    // single flex row. Arrows mount in $inner and the pagination host in $scope,\n    // so without this they live in different parents and the position collapses\n    // to look identical to \"bottom\". Reparent all three into one row.\n    //\n    // The row MUST be appended to $scope (the outer .eael-advanced-slider,\n    // overflow:visible), NOT $inner (.swiper). For slide/fade effects .swiper is\n    // overflow:hidden and sized to the slide height, so a row appended there\n    // falls below the clip box and the arrows + pagination vanish. 3D effects\n    // (.swiper overflow:visible) hid the bug. $scope is the same non-clipped\n    // parent every other pagination position already mounts into.\n    if (paginationPosition === 'inline_with_arrows' && 'yes' === (options === null || options === void 0 ? void 0 : options.navigation_arrows)) {\n      var $pagHost = $scope.find('.eael-as-pagination--position-inline-with-arrows').first();\n      var $prevArrow = $navHost.find('> .swiper-button-prev').first();\n      var $nextArrow = $navHost.find('> .swiper-button-next').first();\n      if ($pagHost.length && $prevArrow.length && $nextArrow.length) {\n        // Tag the row with the pagination type so CSS can give wide-rail\n        // types (progress bar) a definite width instead of shrink-wrapping.\n        var $inlineRow = $('<div class=\"eael-as-inline-row eael-as-inline-row--' + paginationType.replace(/_/g, '-') + '\"></div>');\n        $inlineRow.append($prevArrow).append($pagHost).append($nextArrow);\n        $scope.append($inlineRow);\n      }\n    }\n\n    // Build responsive breakpoints for Swiper\n    var breakpoints = {};\n    if (!isCardsEffect && !isSingleSlideEffect) {\n      // Check if we have breakpoints data and responsive settings\n      if (typeof localize !== 'undefined' && localize.el_breakpoints && _typeof(localize.el_breakpoints) === 'object') {\n        var _localize$el_breakpoi;\n        var el_breakpoints = {},\n          bp_index = 0;\n        var desktopBreakPoint = (_localize$el_breakpoi = localize.el_breakpoints.widescreen) !== null && _localize$el_breakpoi !== void 0 && _localize$el_breakpoi.is_enabled ? localize.el_breakpoints.widescreen.value - 1 : 4800;\n\n        // Initialize base breakpoint\n        el_breakpoints[bp_index] = {\n          breakpoint: 0,\n          slidesPerView: 0,\n          spaceBetween: 0\n        };\n        bp_index++;\n\n        // Add desktop breakpoint\n        localize.el_breakpoints.desktop = {\n          is_enabled: true,\n          value: desktopBreakPoint\n        };\n\n        // Process each device breakpoint\n        ['mobile', 'mobile_extra', 'tablet', 'tablet_extra', 'laptop', 'desktop', 'widescreen'].forEach(function (device) {\n          var breakpoint = localize.el_breakpoints[device];\n          if (breakpoint && breakpoint.is_enabled) {\n            var _options$breakpoints, _options$margins;\n            // Get device-specific items and margin from options\n            var deviceItems = (options === null || options === void 0 || (_options$breakpoints = options.breakpoints) === null || _options$breakpoints === void 0 ? void 0 : _options$breakpoints[device]) || (device === 'desktop' ? (options === null || options === void 0 ? void 0 : options.items) || 3 : 3);\n            var deviceMargin = (options === null || options === void 0 || (_options$margins = options.margins) === null || _options$margins === void 0 ? void 0 : _options$margins[device]) || (device === 'desktop' ? (options === null || options === void 0 ? void 0 : options.gap) || 10 : 10);\n            el_breakpoints[bp_index] = {\n              breakpoint: breakpoint.value,\n              slidesPerView: deviceItems,\n              spaceBetween: deviceMargin\n            };\n            bp_index++;\n          }\n        });\n\n        // Convert el_breakpoints to Swiper breakpoints format\n        Object.keys(el_breakpoints).forEach(function (index) {\n          var _index = parseInt(index);\n          if (typeof el_breakpoints[_index + 1] !== 'undefined') {\n            breakpoints[el_breakpoints[index].breakpoint] = {\n              slidesPerView: el_breakpoints[_index + 1].slidesPerView,\n              spaceBetween: el_breakpoints[_index + 1].spaceBetween\n            };\n          }\n        });\n      }\n    }\n    var isAutoplayEnabled = (options === null || options === void 0 ? void 0 : options.autoplay) === 'yes' || (options === null || options === void 0 ? void 0 : options.autoplay) === true;\n    var shouldPauseOnHover = isAutoplayEnabled && (options === null || options === void 0 ? void 0 : options.pauseOnHover) === 'yes';\n\n    // Cards effect already centers; otherwise honor the user's centered_slides toggle\n    // (only meaningful for horizontal slide effect with > 1 items per view).\n    var isCenteredSlides = isCardsEffect || 'yes' === (options === null || options === void 0 ? void 0 : options.centered_slides) && (options === null || options === void 0 ? void 0 : options.effect) === 'slide' && sliderDirection === 'horizontal';\n\n    // Swiper builds its infinite loop by cloning slides at both ends. The\n    // loop is only safe once there are MORE real slides than are visible at\n    // once — with as many (or fewer) slides than slidesPerView the clones run\n    // out mid-cycle and Swiper either snaps backward to the first slide (the\n    // \"reverse jump\") or shows a blank gap.\n    //\n    // The previous guard (>= 2 × slidesPerView) was too strict: a 5-slide,\n    // 3-per-view slider failed 5 >= 6, so loop was silently dropped and\n    // autoplay rewound all the way back at the end. `> numericSPV` is the\n    // real minimum for a clean Swiper loop.\n    var realSlideCount = $wrapper.find('> .swiper-slide').length;\n    var numericSPV = slidesPerViewValue === 'auto' ? 1 : parseInt(slidesPerViewValue, 10) || 1;\n    var wantsLoop = 'yes' === (options === null || options === void 0 ? void 0 : options.loop);\n    var safeLoop = wantsLoop && realSlideCount > numericSPV;\n\n    // Swiper options\n    var swiperOptions = {\n      effect: (options === null || options === void 0 ? void 0 : options.effect) || 'slide',\n      slidesPerView: slidesPerViewValue,\n      slidesPerGroup: 1,\n      // advance one slide at a time even when slidesPerView > 1\n      spaceBetween: spaceBetweenValue,\n      grabCursor: true,\n      loop: safeLoop,\n      // Clone the FULL slide set on each side. This is the documented cure\n      // for Swiper 8's loop artifacts: with a full buffer the user can never\n      // reach an un-cloned edge, so there's no visible teleport (reverse\n      // jump) and no blank trailing slide. Cheap at realistic slide counts.\n      loopedSlides: safeLoop ? realSlideCount : undefined,\n      speed: (options === null || options === void 0 ? void 0 : options.speed) || 300,\n      direction: sliderDirection,\n      centeredSlides: isCenteredSlides,\n      autoHeight: isCardsEffect && sliderDirection === 'vertical',\n      // watchOverflow MUST stay false. When true, Swiper adds\n      // swiper-button-lock / swiper-pagination-lock and hides nav +\n      // pagination whenever slidesPerView >= slide count. Slide effect\n      // derives slidesPerView from \"Items Per Slide\" (default 2), so a\n      // 1–2 slide slider silently lost its navigation style on BOTH\n      // editor and frontend. fade/flip force perView 1 and cards/coverflow\n      // use 'auto', so only slide effect was bitten — matching the report.\n      watchOverflow: false,\n      observer: true,\n      // react to DOM mutations (editor friendly)\n      observeParents: true,\n      navigation: {\n        // Search $scope, not $navHost (.swiper): the inline_with_arrows\n        // reparent moves the arrows out of .swiper into the row under\n        // $scope, so a .swiper-scoped lookup would resolve to undefined and\n        // the arrows would no longer drive the slider.\n        nextEl: $scope.find('.swiper-button-next')[0],\n        prevEl: $scope.find('.swiper-button-prev')[0]\n      }\n    };\n\n    // Pagination — only attach if a pagination element exists for a Swiper-native type.\n    var paginationConfig = $paginationEl ? Object(_shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"buildPaginationConfig\"])(paginationType, $paginationEl[0]) : null;\n    if (paginationConfig) {\n      swiperOptions.pagination = paginationConfig;\n    }\n\n    // Thumbnails: do NOT pre-create the sub-Swiper here. On the frontend\n    // Elementor's swiper loader is async, and a synchronously-created sub-Swiper\n    // wouldn't share the same Swiper class. We create both swipers via the same\n    // async loader and connect them after both promises resolve (below).\n\n    if (isAutoplayEnabled) {\n      swiperOptions.autoplay = _objectSpread({\n        delay: (options === null || options === void 0 ? void 0 : options.autoplay_speed) || 3000,\n        disableOnInteraction: false\n      }, shouldPauseOnHover ? {\n        pauseOnMouseEnter: true\n      } : {});\n    }\n    if (!isCardsEffect) {\n      swiperOptions.breakpoints = breakpoints;\n    }\n    if ('coverflow' === (options === null || options === void 0 ? void 0 : options.effect)) {\n      // Tuned to match the V4 \"Photographer portfolio · 3D coverflow\" reference:\n      // moderate rotation, generous depth, no stretch — gives readable side\n      // slides instead of nearly-edge-on strips.\n      swiperOptions.coverflowEffect = {\n        rotate: typeof (options === null || options === void 0 ? void 0 : options.coverflow_rotation) === 'number' ? options.coverflow_rotation : 35,\n        depth: typeof (options === null || options === void 0 ? void 0 : options.coverflow_depth) === 'number' ? options.coverflow_depth : 200,\n        stretch: typeof (options === null || options === void 0 ? void 0 : options.coverflow_stretch) === 'number' ? options.coverflow_stretch : 0,\n        modifier: 1,\n        slideShadows: (options === null || options === void 0 ? void 0 : options.enable_background) !== false\n      };\n    } else if ('cards' === (options === null || options === void 0 ? void 0 : options.effect)) {\n      swiperOptions.cardsEffect = {\n        slideShadows: (options === null || options === void 0 ? void 0 : options.enable_background) !== false,\n        perSlideOffset: 9,\n        // matches reference demo (V5 stacked cards)\n        perSlideRotate: 2.4\n      };\n    } else if ('flip' === (options === null || options === void 0 ? void 0 : options.effect)) {\n      swiperOptions.flipEffect = {\n        slideShadows: (options === null || options === void 0 ? void 0 : options.enable_background) !== false,\n        limitRotation: true\n      };\n    }\n\n    // Initialize Swiper\n    var swiperInstancePromise = Object(_shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"swiperLoader\"])($inner[0], swiperOptions);\n\n    /**\n     * slidesPerView visual override — CSS-variable approach.\n     *\n     * Background: Elementor injects per-widget CSS for column-sized widgets\n     *   `width: var(--container-widget-width, 30%); max-width: 30%`\n     * Swiper writes its calculated slide width to `style.width` (no !important),\n     * and Elementor's `max-width: 30%` clamps it. Items Per Slide ends up with\n     * no visible effect — slides keep the column width.\n     *\n     * Fix: write Swiper's calculated slide size to a CSS custom property on\n     * the wrapper once per resize/breakpoint event. The companion rule in\n     * advanced-slider.scss (`.eael-advanced-slider:not(.cards):not(.flip)...`)\n     * applies the variable to every slide with `!important` and specificity\n     * high enough to beat Elementor's `.e-flex.e-con-row` injection.\n     *\n     * Performance: 1 setProperty call per event regardless of slide count.\n     * Previous implementation looped every slide and wrote 4-5 inline styles\n     * — for an 18-slide looped slider that was ~90 DOM writes per event.\n     */\n    var applySlideSizeVariable = function applySlideSizeVariable(swiper) {\n      if (!swiper || !swiper.slidesSizesGrid || !swiper.slidesSizesGrid[0]) return;\n      var effect = swiper.params.effect;\n      if (effect === 'cards' || effect === 'flip') return;\n\n      // slidesSizesGrid[0]: for slidesPerView = integer (our case for non-cards/flip),\n      // every entry has the same value. For horizontal it's width, for vertical it's height.\n      var size = swiper.slidesSizesGrid[0];\n\n      // Feedback-loop guard. If Swiper reports an absurdly large slide size\n      // (>5000px), the container is mismeasuring — probably has no fixed height\n      // and is collapsing to content size. Writing that value back via the CSS\n      // variable inflates slides → wrapper grows → next layout pass measures\n      // even bigger → exponential runaway. Real-world report: 8.9M px.\n      // Skip the write; CSS fallback `auto` (horizontal) / SCSS baseline 70vh\n      // (vertical) keep the slider from rendering as nothing.\n      if (size > 5000) return;\n      var isVertical = swiper.params.direction === 'vertical';\n      var wrapper = swiper.el && swiper.el.closest ? swiper.el.closest('.eael-advanced-slider') || swiper.el : swiper.el;\n      if (!wrapper) return;\n      if (isVertical) {\n        wrapper.style.setProperty('--eael-as-slide-h', size + 'px');\n      } else {\n        wrapper.style.setProperty('--eael-as-slide-w', size + 'px');\n      }\n    };\n    swiperInstancePromise.then(function (swiper) {\n      if (!swiper) return;\n      applySlideSizeVariable(swiper);\n      swiper.on('resize', function () {\n        return applySlideSizeVariable(swiper);\n      });\n      swiper.on('slidesUpdated', function () {\n        return applySlideSizeVariable(swiper);\n      });\n      swiper.on('breakpoint', function () {\n        return applySlideSizeVariable(swiper);\n      });\n    });\n\n    /**\n     * Transition Easing — write transition-timing-function inline directly on\n     * the wrapper and every slide, on every Swiper transition.\n     *\n     * Why JS instead of relying on CSS:\n     *   Swiper's effects modules write `style.transition = \"transform Xms\"`\n     *   (shorthand without timing-function) on slides for fade/cards/flip/\n     *   coverflow. Browser handling of the resulting longhand transitionTimingFunction\n     *   is inconsistent — sometimes empty (falls through to our `!important`\n     *   CSS rule), sometimes explicit `ease` (competes with our author-CSS\n     *   important against inline-without-important). The CSS approach was\n     *   intermittently winning; users reported all four presets felt the same.\n     *   Writing the timing-function inline on every transition guarantees\n     *   the inline declaration matches the user's selection — bypasses the\n     *   cascade entirely.\n     *\n     * Cost: ~(1 + slide_count) DOM writes per slide change. For a typical\n     *   6-slide-with-loop slider that's ~19 writes per transition. Not per\n     *   resize event like the old forceSwiperSlideWidths — only when the\n     *   user actually changes slides.\n     *\n     * The SCSS rule `transition-timing-function: var(--eael-as-easing) !important`\n     * stays as a defensive fallback for the initial paint before this hook\n     * fires.\n     */\n    /* ADVANCED_SLIDER_EASING_CURVES is imported from ../_shared/advanced-slider.js\n       (Phase 6.0 — first extraction to the shared partial). */\n    var applyTransitionEasing = function applyTransitionEasing(swiper) {\n      var preset = $scope.attr('data-easing') || 'spring';\n      var curve = _shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"ADVANCED_SLIDER_EASING_CURVES\"][preset] || _shared_advanced_slider_js__WEBPACK_IMPORTED_MODULE_0__[\"ADVANCED_SLIDER_EASING_CURVES\"].spring;\n      // setProperty with 'important' flag is required: the advanced-slider.scss\n      // rule `transition-timing-function: var(--eael-as-easing) !important`\n      // beats plain inline. We need inline-WITH-important to win the cascade.\n      if (swiper.wrapperEl) {\n        swiper.wrapperEl.style.setProperty('transition-timing-function', curve, 'important');\n      }\n      if (swiper.slides && swiper.slides.length) {\n        for (var i = 0; i < swiper.slides.length; i++) {\n          if (swiper.slides[i]) {\n            swiper.slides[i].style.setProperty('transition-timing-function', curve, 'important');\n          }\n        }\n      }\n    };\n    swiperInstancePromise.then(function (swiper) {\n      if (!swiper) return;\n      applyTransitionEasing(swiper); // initial paint\n      swiper.on('setTransition', function () {\n        return applyTransitionEasing(swiper);\n      }); // every slide change\n    });\n\n    // Auto-fit height for cards/flip/coverflow (default ON).\n    // Treat any value other than '' / 'no' as ON (handles 'yes' explicit + missing default).\n    if (['cards', 'flip', 'coverflow'].indexOf(options === null || options === void 0 ? void 0 : options.effect) !== -1 && (options === null || options === void 0 ? void 0 : options.auto_height) !== '' && (options === null || options === void 0 ? void 0 : options.auto_height) !== 'no') {\n      swiperInstancePromise.then(function (swiper) {\n        if (!swiper) return;\n        // Defer one tick so Swiper has finished its own size pass.\n        setTimeout(function () {\n          return eaelAutoFitHeight($scope, swiper, $);\n        }, 50);\n      });\n    }\n\n    // Thumbnails — connect the sub-Swiper to the main Swiper after BOTH async\n    // creates resolve. This is the recommended Swiper pattern for async loaders.\n    if (thumbnailsNav) {\n      Promise.all([swiperInstancePromise, thumbnailsNav.getThumbsSwiperAsync()]).then(function (_ref3) {\n        var _ref4 = _slicedToArray(_ref3, 2),\n          mainSwiper = _ref4[0],\n          thumbsSwiper = _ref4[1];\n        if (!mainSwiper || !thumbsSwiper) return;\n        // Wire thumbs reference into main swiper and let it sync.\n        if (!mainSwiper.thumbs) {\n          mainSwiper.thumbs = {\n            swiper: thumbsSwiper\n          };\n        } else {\n          mainSwiper.thumbs.swiper = thumbsSwiper;\n        }\n        if (typeof mainSwiper.thumbs.init === 'function') {\n          try {\n            mainSwiper.thumbs.init();\n          } catch (e) {/* no-op */}\n        }\n        if (typeof mainSwiper.thumbs.update === 'function') {\n          try {\n            mainSwiper.thumbs.update(true);\n          } catch (e) {/* no-op */}\n        }\n        // Manually link clickable thumbs + active-state class.\n        // BEST UX: highlight ALL currently-visible slides as active in the\n        // thumb strip, not just the leftmost one. With slidesPerView=2 and\n        // items 3+4 visible in the slider, thumbs 3 and 4 both light up.\n        // Matches what the editor preview does and what users expect from\n        // a thumbnail rail (it represents \"what's in view right now\").\n        var totalThumbs = thumbsSwiper.slides.length;\n        var numericSPV = function numericSPV() {\n          var v = mainSwiper.params.slidesPerView;\n          return v === 'auto' ? 1 : parseInt(v, 10) || 1;\n        };\n        var setActiveThumbs = function setActiveThumbs() {\n          var start = mainSwiper.realIndex || 0;\n          var count = Math.min(numericSPV(), totalThumbs);\n          for (var i = 0; i < totalThumbs; i++) {\n            thumbsSwiper.slides[i].classList.remove('swiper-slide-thumb-active');\n          }\n          for (var _i = 0; _i < count; _i++) {\n            var idx = (start + _i) % totalThumbs;\n            if (thumbsSwiper.slides[idx]) {\n              thumbsSwiper.slides[idx].classList.add('swiper-slide-thumb-active');\n            }\n          }\n          if (typeof thumbsSwiper.slideTo === 'function') {\n            thumbsSwiper.slideTo(start);\n          }\n        };\n        thumbsSwiper.on('click', function () {\n          var i = thumbsSwiper.clickedIndex;\n          if (typeof i === 'number' && mainSwiper.slideTo) {\n            mainSwiper.slideTo(i);\n          }\n        });\n        mainSwiper.on('slideChange', setActiveThumbs);\n        mainSwiper.on('breakpoint', setActiveThumbs); // re-sync if slidesPerView changes responsively\n        setActiveThumbs(); // initial state\n      })[\"catch\"](function () {/* ignore errors */});\n    }\n\n    // Wire numbered_index nav (lives outside Swiper's pagination module).\n    if (numberedIndexNav) {\n      swiperInstancePromise.then(function (swiper) {\n        if (!swiper) return;\n        numberedIndexNav.bindClicks(swiper);\n        swiper.on('slideChange', function () {\n          return numberedIndexNav.onSlideChange(swiper.realIndex);\n        });\n      });\n    }\n    if (progressBarNav) {\n      swiperInstancePromise.then(function (swiper) {\n        if (!swiper) return;\n        progressBarNav.attach(swiper);\n      });\n    }\n    if (shouldPauseOnHover) {\n      swiperInstancePromise.then(function (swiper) {\n        if (!(swiper !== null && swiper !== void 0 && swiper.autoplay)) {\n          return;\n        }\n        var stopAutoplay = function stopAutoplay() {\n          return swiper.autoplay.stop();\n        };\n        var startAutoplay = function startAutoplay() {\n          return swiper.autoplay.start();\n        };\n        $inner.on('mouseenter.eael-advanced-slider', stopAutoplay);\n        $inner.on('mouseleave.eael-advanced-slider', startAutoplay);\n      });\n    }\n    if ('cards' === (options === null || options === void 0 ? void 0 : options.effect)) {\n      if ($scope.hasClass('eael-advanced-slider-cards') || $scope.find(' > .eael-advanced-slider-cards').length) {\n        $scope.css('display', 'flex');\n      }\n    }\n  };\n\n  /* swiperLoader imported from ../_shared/advanced-slider.js (Phase 6.1). */\n\n  jQuery(window).on(\"elementor/frontend/init\", function () {\n    if (eael.elementStatusCheck('eaelAdvancedSlider') || window.isEditMode) {\n      return false;\n    }\n    elementorFrontend.hooks.addAction(\"frontend/element_ready/container\", AdvancedSliderHandler);\n    elementorFrontend.hooks.addAction(\"frontend/element_ready/section\", AdvancedSliderHandler);\n  });\n})();\n\n//# sourceURL=webpack:///./src/js/view/advanced-slider.js?");

/***/ })

/******/ });