{"version":3,"sources":["jsdelivr-header.js","/gh/willmyerscode/infinite-gallery-slider@1.0.0/infinite-slider.js"],"names":[],"mappings":"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","file":"/gh/willmyerscode/infinite-gallery-slider@1.0.0/infinite-slider.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /gh/willmyerscode/infinite-gallery-slider@1.0.0/infinite-slider.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/**\n * Infinite Slider Plugin for Squarespace List Sections\n * Copyright Will-Myers.com\n *\n * Transforms a list section into an infinitely scrolling image slider\n * with configurable height, speed, and aspect ratio\n **/\n\nclass WMInfiniteSlider {\n  static pluginName = \"infinite-slider\";\n  static sharedCursor = null; // Singleton custom cursor\n  static cursorInstances = new Set(); // Track instances using the cursor\n\n  static emitEvent(type, detail = {}, elem = document) {\n    elem.dispatchEvent(new CustomEvent(`wm-${this.pluginName}${type}`, {detail, bubbles: true}));\n  }\n\n  constructor(el, settings = {}) {\n    this.el = el; // The .page-section element\n    this.settings = {\n      speedMobile: 30, // pixels per second - used for duration calculation\n      speedDesktop: 50, // pixels per second - used for duration calculation\n      reverse: false, // reverse animation direction\n      stopOnHover: false, // pause animation on hover\n      allowClickthrough: false, // allow clicking items to navigate to their button link\n      iconHtml:\n        '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M7 7h10v10\"/><path d=\"M7 17 17 7\"/></svg>', // HTML for clickthrough icon\n      customCursor: false, // enable custom cursor with item title\n      cursorTheme: null, // custom theme for cursor (defaults to section theme)\n      preserveStructure: false, // preserve original list section HTML structure\n      ...settings,\n    };\n    this.data = null;\n    this.sectionTitle = null;\n    this.sectionButton = null;\n    this.options = null;\n    this.styles = null;\n    this.originalContainer = null; // Original container (source of truth, hidden)\n    this.pluginContainer = null; // Duplicate container (where slider lives)\n    this.originalSlides = []; // Store original slide elements for preserve mode\n    this.pluginName = this.constructor.pluginName;\n    this.isBackend = window.top !== window.self;\n    this.resizeTimer = null;\n    this.imagesLoaded = false;\n    this.customCursorEl = null; // Reference to shared cursor (if enabled)\n    this._cursorHandlers = null; // Store cursor event handlers for cleanup\n\n    this.init();\n  }\n\n  init() {\n    WMInfiniteSlider.emitEvent(\":beforeInit\", {el: this.el}, this.el);\n    this.addDataAttribute();\n    this.extractData();\n\n    if (!this.data || this.data.length === 0) {\n      console.warn(`[${this.pluginName}] No items found`);\n      return;\n    }\n\n    this.removeOrHideOriginalListSectionContent();\n    this.buildLayout();\n    this.bindEvents();\n    WMInfiniteSlider.emitEvent(\":afterInit\", {el: this.el}, this.el);\n  }\n\n  addDataAttribute() {\n    this.el.setAttribute(\"data-wm-plugin\", this.pluginName);\n    \n    // Add clickthrough data attribute if enabled\n    if (this.settings.allowClickthrough) {\n      this.el.setAttribute(\"data-allow-clickthrough\", \"true\");\n    }\n  }\n\n  extractData() {\n    const container = this.el.querySelector(\".user-items-list-item-container\");\n    if (!container || !container.dataset.currentContext) {\n      console.error(`[${this.pluginName}] No data-current-context found`);\n      return;\n    }\n\n    const contextData = JSON.parse(container.dataset.currentContext);\n    this.originalContainer = container;\n    this.data = contextData.userItems || [];\n    this.options = contextData.options || {};\n    this.styles = contextData.styles || {};\n    this.sectionTitle = contextData.sectionTitle || null;\n    this.sectionButton = contextData.sectionButton || null;\n\n    // If preserving structure, capture original slide elements before they're removed\n    if (this.settings.preserveStructure) {\n      const slideSelector = \".list-item\";\n      const slides = container.querySelectorAll(slideSelector);\n\n      this.originalSlides = Array.from(slides);\n    }\n  }\n\n  removeOrHideOriginalListSectionContent() {\n    if (!this.originalContainer) return;\n\n    // Get section title and button elements\n    const sectionTitle = this.el.querySelector(\".list-section-title\");\n    const sectionButton = this.el.querySelector(\".list-section-button-container\");\n\n    // Hide or remove section title and button\n    if (this.isBackend) {\n      if (sectionTitle) sectionTitle.style.display = \"none\";\n      if (sectionButton) sectionButton.style.display = \"none\";\n    } else {\n      if (sectionTitle) sectionTitle.remove();\n      if (sectionButton) sectionButton.remove();\n    }\n\n    // Create duplicate container for the plugin (Squarespace won't touch this one)\n    this.pluginContainer = this.originalContainer.cloneNode(false); // Shallow clone (no children)\n    \n    // Remove Squarespace controller attributes so it doesn't get manipulated\n    this.pluginContainer.removeAttribute(\"data-controller\");\n    this.pluginContainer.removeAttribute(\"data-controllers-bound\");\n    \n    // Add identifier class for our plugin container\n    this.pluginContainer.classList.add(\"wm-plugin-container\");\n    \n    // Insert duplicate as sibling after the original\n    this.originalContainer.insertAdjacentElement(\"afterend\", this.pluginContainer);\n    \n    // Hide the original container (source of truth)\n    this.originalContainer.style.display = \"none\";\n  }\n\n  buildLayout() {\n    if (!this.pluginContainer) return;\n\n    const customContent = document.createElement(\"div\");\n    customContent.className = \"wm-plugin-content\";\n\n    // Create slider wrapper\n    const sliderWrapper = document.createElement(\"div\");\n    sliderWrapper.className = \"infinite-slider-wrapper\";\n\n    // Create slider track (ul for Squarespace consistency)\n    const sliderTrack = document.createElement(\"ul\");\n    sliderTrack.className = \"infinite-slider-track\";\n\n    // Apply reverse direction if enabled\n    if (this.settings.reverse) {\n      sliderTrack.dataset.reverse = \"true\";\n    }\n\n    // Build initial slides - use preserved structure or build from scratch\n    if (this.settings.preserveStructure && this.originalSlides.length > 0) {\n      this.el.dataset.preserveStructure = \"true\";\n\n      // Set system gap from spaceBetweenSlides if available\n      if (this.options.spaceBetweenSlides) {\n        const gapValue = this.options.spaceBetweenSlides.value || 20;\n        const gapUnit = this.options.spaceBetweenSlides.unit || \"px\";\n        this.el.style.setProperty(\"--system-slider-gap\", `${gapValue}${gapUnit}`);\n      }\n\n      if (this.options.minSlideHeight) {\n        const minSlideHeightValue = this.options.minSlideHeight.value || 75;\n        const minSlideHeightUnit = this.options.minSlideHeight.unit || \"vh\";\n        this.el.style.setProperty(\"--system-min-slide-height\", `${minSlideHeightValue}${minSlideHeightUnit}`);\n      }\n\n      // Set system width from maxColumns if available\n      if (this.options.maxColumns) {\n        const maxColumns = this.options.maxColumns;\n        // Calculate width as: min(var(--sqs-site-max-width), 100vw) / maxColumns\n        this.el.style.setProperty(\"--system-item-width\", `calc(min(var(--sqs-site-max-width, 1920px), 100vw) / ${maxColumns})`);\n      }\n\n      this.originalSlides.forEach((originalSlide, index) => {\n        const slide = this.cloneOriginalSlide(originalSlide, index);\n        sliderTrack.appendChild(slide);\n      });\n    } else {\n      this.data.forEach((item, index) => {\n        if (item.image) {\n          const slide = this.buildSlide(item, index);\n          sliderTrack.appendChild(slide);\n        }\n      });\n    }\n\n    sliderWrapper.appendChild(sliderTrack);\n    customContent.appendChild(sliderWrapper);\n    this.pluginContainer.appendChild(customContent);\n\n    // Create custom cursor if enabled (desktop only)\n    if (this.settings.customCursor && window.innerWidth >= 768) {\n      this.createCustomCursor();\n    }\n\n    // Wait for images to load before duplicating\n    this.waitForImages(sliderTrack).then(() => {\n      this.imagesLoaded = true;\n      this.duplicateSlides(sliderTrack);\n      this.calculateAnimation(sliderTrack);\n    });\n  }\n\n  buildSlide(item, index) {\n    const slide = document.createElement(\"li\");\n    slide.className = \"infinite-slider-item\";\n    slide.dataset.index = index;\n\n    // Determine if this item should be clickable\n    const hasLink = this.settings.allowClickthrough && item.button && item.button.buttonLink;\n\n    // Create wrapper (either <a> or <div>)\n    let imageWrapper;\n    if (hasLink) {\n      imageWrapper = document.createElement(\"a\");\n      imageWrapper.href = item.button.buttonLink;\n      imageWrapper.className = \"infinite-slider-image\";\n\n      if (item.button.buttonNewWindow) {\n        imageWrapper.target = \"_blank\";\n        imageWrapper.rel = \"noopener noreferrer\";\n      }\n    } else {\n      imageWrapper = document.createElement(\"div\");\n      imageWrapper.className = \"infinite-slider-image\";\n    }\n\n    const img = document.createElement(\"img\");\n    img.src = item.image.assetUrl;\n    img.alt = item.title || \"\";\n    img.loading = \"eager\"; // Load immediately for accurate measurements\n\n    // Set focal point if available\n    if (item.image.mediaFocalPoint) {\n      const {x, y} = item.image.mediaFocalPoint;\n      img.style.objectPosition = `${x * 100}% ${y * 100}%`;\n    }\n\n    imageWrapper.appendChild(img);\n    slide.appendChild(imageWrapper);\n\n    return slide;\n  }\n\n  cloneOriginalSlide(originalSlide, index) {\n    // Deep clone the original slide element\n    const slide = originalSlide.cloneNode(true);\n\n    // Sanitize the cloned slide\n    this.sanitizeClonedSlide(slide);\n\n    // Add our plugin class\n    slide.classList.add(\"infinite-slider-item\");\n\n    // Add index for cursor tracking\n    slide.dataset.index = index;\n\n    // Add clickthrough behavior for preserved mode\n    if (this.settings.allowClickthrough) {\n      const itemData = this.data[index];\n      const buttonLink = itemData?.button?.buttonLink;\n      \n      if (buttonLink) {\n        slide.style.cursor = \"pointer\";\n        slide.addEventListener(\"click\", (e) => {\n          // Don't intercept clicks on existing links\n          if (e.target.closest(\"a\")) return;\n          \n          if (itemData.button.buttonNewWindow) {\n            window.open(buttonLink, \"_blank\", \"noopener,noreferrer\");\n          } else {\n            window.location.href = buttonLink;\n          }\n        });\n      }\n    }\n\n    // Wrap in <li> if the original isn't already an li (for ul consistency)\n    if (slide.tagName.toLowerCase() !== 'li') {\n      const li = document.createElement('li');\n      li.className = 'infinite-slider-item-wrapper';\n      li.appendChild(slide);\n      li.dataset.index = index;\n      return li;\n    }\n\n    return slide;\n  }\n\n  sanitizeClonedSlide(slide) {\n    // Central location for cleaning/standardizing cloned HTML\n    // Remove transform from inline styles (but preserve other styles)\n    if (slide.style.transform) {\n      slide.style.transform = \"\";\n    }\n\n    // Remove aria-hidden attribute\n    slide.removeAttribute(\"aria-hidden\");\n\n    // Find and clean nested elements with transforms\n    const elementsWithTransform = slide.querySelectorAll('[style*=\"transform\"]');\n    elementsWithTransform.forEach(el => {\n      if (el.style.transform) {\n        el.style.transform = \"\";\n      }\n    });\n\n    // Load images immediately (change data-load to true or convert data-src to src)\n    const images = slide.querySelectorAll(\"img[data-src]\");\n    images.forEach(img => {\n      if (img.dataset.src && !img.src) {\n        img.src = img.dataset.src;\n      }\n      img.setAttribute(\"data-load\", \"true\");\n      img.loading = \"eager\";\n    });\n\n    // Remove any animation attributes that might conflict\n    slide.removeAttribute(\"data-animation-role\");\n    const animatedElements = slide.querySelectorAll(\"[data-animation-role]\");\n    animatedElements.forEach(el => {\n      el.removeAttribute(\"data-animation-role\");\n    });\n  }\n\n  waitForImages(container) {\n    const images = Array.from(container.querySelectorAll(\"img\"));\n\n    const imagePromises = images.map(img => {\n      if (img.complete && img.naturalHeight !== 0) {\n        return Promise.resolve();\n      }\n      return new Promise(resolve => {\n        img.addEventListener(\"load\", resolve, {once: true});\n        img.addEventListener(\"error\", resolve, {once: true});\n      });\n    });\n\n    return Promise.all(imagePromises);\n  }\n\n  duplicateSlides(sliderTrack) {\n    const originalSlides = Array.from(sliderTrack.children);\n    sliderTrack.dataset.originalCount = originalSlides.length;\n\n    // Calculate how many duplications we need\n    const viewportWidth = window.innerWidth;\n    const trackWidth = sliderTrack.scrollWidth;\n\n    // Loop guard: If the track is hidden (width 0), defer duplication until it's visible\n    if (trackWidth === 0) {\n      const attempts = parseInt(sliderTrack.dataset.duplicationAttempts || \"0\", 10);\n      if (attempts > 100) {\n        console.warn(`[${this.pluginName}] Unable to measure slider track width after multiple attempts.`);\n        return;\n      }\n      sliderTrack.dataset.duplicationAttempts = attempts + 1;\n      requestAnimationFrame(() => this.duplicateSlides(sliderTrack));\n      return;\n    }\n    delete sliderTrack.dataset.duplicationAttempts;\n\n    // Ensure at least 3x viewport coverage for seamless loop\n    const duplications = Math.max(2, Math.ceil((viewportWidth * 3) / trackWidth));\n\n    for (let i = 0; i < duplications; i++) {\n      originalSlides.forEach(slide => {\n        const clone = slide.cloneNode(true);\n        clone.classList.add(\"cloned\");\n        sliderTrack.appendChild(clone);\n      });\n    }\n  }\n\n  calculateAnimation(sliderTrack) {\n    // Force reflow for accurate measurements\n    sliderTrack.offsetHeight;\n\n    const originalSlides = Array.from(sliderTrack.children).filter(s => !s.classList.contains(\"cloned\"));\n    const gap = parseFloat(getComputedStyle(sliderTrack).gap || 0);\n\n    // Calculate the width of one set of original slides\n    let scrollDistance = 0;\n    originalSlides.forEach(slide => {\n      scrollDistance += slide.offsetWidth;\n    });\n    scrollDistance += gap * originalSlides.length;\n\n    // Loop guard: Ensure we have a valid scroll distance\n    if (scrollDistance === 0) {\n      console.warn(`[${this.pluginName}] Cannot calculate animation with zero scroll distance.`);\n      return;\n    }\n\n    // Determine speed based on viewport (settings control calculation logic only)\n    const isMobile = window.innerWidth < 768;\n    const speed = isMobile ? this.settings.speedMobile : this.settings.speedDesktop;\n\n    // Calculate duration (distance / speed)\n    const duration = scrollDistance / speed;\n\n    // ONLY set runtime-calculated values that can't be predetermined\n    // These are computed measurements, not styling preferences\n    this.el.style.setProperty(\"--scroll-distance\", `-${scrollDistance}px`);\n    this.el.style.setProperty(\"--scroll-duration\", `${duration}s`);\n\n    // Mark as initialized\n    sliderTrack.dataset.initialized = \"true\";\n  }\n\n  resetSlider() {\n    if (!this.imagesLoaded) return;\n\n    const sliderTrack = this.el.querySelector(\".infinite-slider-track\");\n    if (!sliderTrack || !sliderTrack.dataset.initialized) return;\n\n    // Clear all slides (both original and clones)\n    sliderTrack.innerHTML = \"\";\n    \n    // Rebuild slides from source of truth\n    if (this.settings.preserveStructure && this.originalSlides.length > 0) {\n      this.originalSlides.forEach((originalSlide, index) => {\n        const slide = this.cloneOriginalSlide(originalSlide, index);\n        sliderTrack.appendChild(slide);\n      });\n    } else {\n      this.data.forEach((item, index) => {\n        if (item.image) {\n          const slide = this.buildSlide(item, index);\n          sliderTrack.appendChild(slide);\n        }\n      });\n    }\n\n    // Remove initialized flag\n    delete sliderTrack.dataset.initialized;\n\n    // Recalculate\n    this.duplicateSlides(sliderTrack);\n    this.calculateAnimation(sliderTrack);\n  }\n\n  createCustomCursor() {\n    const sliderWrapper = this.el.querySelector(\".infinite-slider-wrapper\");\n    if (!sliderWrapper) return;\n\n    // Use or create singleton cursor\n    if (!WMInfiniteSlider.sharedCursor) {\n      // Get theme from settings or section\n      const theme = this.settings.cursorTheme || this.el.getAttribute(\"data-section-theme\") || \"\";\n      WMInfiniteSlider.initSharedCursor(theme);\n    }\n\n    // Register this instance\n    WMInfiniteSlider.cursorInstances.add(this);\n    this.customCursorEl = WMInfiniteSlider.sharedCursor.element;\n\n    // Track mouse movement for this slider\n    const mouseMoveHandler = e => {\n      WMInfiniteSlider.sharedCursor.targetX = e.clientX;\n      WMInfiniteSlider.sharedCursor.targetY = e.clientY;\n\n      const item = e.target.closest(\".infinite-slider-item\");\n      const textSpan = this.customCursorEl.querySelector(\".infinite-slider-cursor-text\");\n      const iconSpan = this.customCursorEl.querySelector(\".infinite-slider-cursor-icon\");\n\n      if (item) {\n        const index = parseInt(item.dataset.index, 10);\n        let title = \"\";\n        let hasLink = false;\n\n        if (this.settings.preserveStructure) {\n          // Extract title from preserved HTML structure\n          const titleElement = item.querySelector(\".list-item-content__title, .user-items-list-carousel__media-link, h1, h2, h3, h4\");\n          if (titleElement) {\n            title = titleElement.textContent.trim();\n          }\n\n          // Check if preserved structure has a link\n          hasLink = !!item.querySelector(\"a[href]\");\n        } else {\n          // Use data from JSON\n          const itemData = this.data[index];\n          if (itemData) {\n            title = itemData.title || \"\";\n            hasLink = this.settings.allowClickthrough && itemData.button && itemData.button.buttonLink;\n          }\n        }\n\n        if (title) {\n          textSpan.textContent = title;\n          this.customCursorEl.classList.add(\"active\");\n\n          // Show icon if item has link\n          if (hasLink) {\n            iconSpan.innerHTML = this.settings.iconHtml;\n            iconSpan.style.display = \"\";\n          } else {\n            iconSpan.style.display = \"none\";\n          }\n        }\n      } else {\n        this.customCursorEl.classList.remove(\"active\");\n        iconSpan.style.display = \"none\";\n      }\n    };\n\n    const mouseLeaveHandler = () => {\n      this.customCursorEl.classList.remove(\"active\");\n      const iconSpan = this.customCursorEl.querySelector(\".infinite-slider-cursor-icon\");\n      if (iconSpan) iconSpan.style.display = \"none\";\n    };\n\n    sliderWrapper.addEventListener(\"mousemove\", mouseMoveHandler);\n    sliderWrapper.addEventListener(\"mouseleave\", mouseLeaveHandler);\n\n    // Store handlers for cleanup\n    this._cursorHandlers = {mouseMoveHandler, mouseLeaveHandler, sliderWrapper};\n  }\n\n  static initSharedCursor(theme = \"\") {\n    // Create cursor element\n    const element = document.createElement(\"div\");\n    element.className = \"infinite-slider-custom-cursor\";\n\n    // Apply theme attribute\n    if (theme) {\n      element.setAttribute(\"data-section-theme\", theme);\n    }\n\n    // Create text span\n    const textSpan = document.createElement(\"span\");\n    textSpan.className = \"infinite-slider-cursor-text\";\n    element.appendChild(textSpan);\n\n    // Create icon span (hidden by default)\n    const iconSpan = document.createElement(\"span\");\n    iconSpan.className = \"infinite-slider-cursor-icon\";\n    element.appendChild(iconSpan);\n\n    document.querySelector(\"#siteWrapper\").appendChild(element);\n\n    // Initialize position at left edge, halfway down screen\n    const initialX = 0;\n    const initialY = window.innerHeight / 2;\n\n    // Store shared cursor state first\n    WMInfiniteSlider.sharedCursor = {\n      element,\n      targetX: initialX,\n      targetY: initialY,\n      currentX: initialX,\n      currentY: initialY,\n      rafId: null,\n    };\n\n    // Smooth interpolation function (linear interpolation)\n    const lerp = (start, end, factor) => start + (end - start) * factor;\n\n    // Animation loop for smooth cursor following using RAF\n    const animate = () => {\n      const cursor = WMInfiniteSlider.sharedCursor;\n\n      // Safety check - stop if cursor was destroyed\n      if (!cursor) return;\n\n      // Interpolate current position towards target (0.05 = lag factor)\n      cursor.currentX = lerp(cursor.currentX, cursor.targetX, 0.1);\n      cursor.currentY = lerp(cursor.currentY, cursor.targetY, 0.1);\n\n      // Default offsets (bottom-right of cursor)\n      let offsetX = 30;\n      const offsetY = 20;\n\n      // Check if cursor would flow off right edge\n      const elementWidth = element.offsetWidth;\n      const viewportWidth = window.innerWidth;\n      if (cursor.currentX + offsetX + elementWidth > viewportWidth) {\n        // Switch to left side of cursor (keep same vertical offset)\n        offsetX = -elementWidth - 10;\n      }\n\n      // Update position using transform for better performance\n      element.style.transform = `translate(${cursor.currentX + offsetX}px, ${cursor.currentY + offsetY}px)`;\n\n      // Continue animation loop\n      cursor.rafId = requestAnimationFrame(animate);\n    };\n\n    // Start animation loop\n    WMInfiniteSlider.sharedCursor.rafId = requestAnimationFrame(animate);\n  }\n\n  bindEvents() {\n    // Debounced resize handler\n    window.addEventListener(\"resize\", () => {\n      clearTimeout(this.resizeTimer);\n      this.resizeTimer = setTimeout(() => {\n        this.resetSlider();\n      }, 250);\n    });\n\n    // Pause on hover - only if stopOnHover is enabled\n    if (this.settings.stopOnHover) {\n      const sliderWrapper = this.el.querySelector(\".infinite-slider-wrapper\");\n      if (sliderWrapper) {\n        sliderWrapper.addEventListener(\"mouseenter\", () => {\n          this.el.classList.add(\"paused\");\n        });\n\n        sliderWrapper.addEventListener(\"mouseleave\", () => {\n          this.el.classList.remove(\"paused\");\n        });\n      }\n    }\n  }\n\n  destroy() {\n    // Remove custom content\n    const customContent = this.el.querySelector(\".wm-plugin-content\");\n    if (customContent) customContent.remove();\n\n    // Clean up custom cursor handlers\n    if (this._cursorHandlers) {\n      const {mouseMoveHandler, mouseLeaveHandler, sliderWrapper} = this._cursorHandlers;\n      sliderWrapper.removeEventListener(\"mousemove\", mouseMoveHandler);\n      sliderWrapper.removeEventListener(\"mouseleave\", mouseLeaveHandler);\n      this._cursorHandlers = null;\n    }\n\n    // Unregister from cursor instances\n    WMInfiniteSlider.cursorInstances.delete(this);\n\n    // Only destroy shared cursor if no instances are using it\n    if (WMInfiniteSlider.cursorInstances.size === 0 && WMInfiniteSlider.sharedCursor) {\n      cancelAnimationFrame(WMInfiniteSlider.sharedCursor.rafId);\n      WMInfiniteSlider.sharedCursor.element.remove();\n      WMInfiniteSlider.sharedCursor = null;\n    }\n\n    this.customCursorEl = null;\n\n    // Remove the plugin container (duplicate)\n    if (this.pluginContainer) {\n      this.pluginContainer.remove();\n      this.pluginContainer = null;\n    }\n\n    // Restore original container visibility\n    if (this.originalContainer) {\n      this.originalContainer.style.display = \"\";\n    }\n\n    // Restore section title and button\n    const sectionTitle = this.el.querySelector(\".list-section-title\");\n    const sectionButton = this.el.querySelector(\".list-section-button-container\");\n    if (sectionTitle) sectionTitle.style.display = \"\";\n    if (sectionButton) sectionButton.style.display = \"\";\n\n    // Remove data attributes and custom properties\n    this.el.removeAttribute(\"data-wm-plugin\");\n    this.el.removeAttribute(\"data-preserve-structure\");\n    this.el.removeAttribute(\"data-allow-clickthrough\");\n    this.el.style.removeProperty(\"--system-slider-gap\");\n    this.el.style.removeProperty(\"--system-item-width\");\n    this.el.style.removeProperty(\"--scroll-distance\");\n    this.el.style.removeProperty(\"--scroll-duration\");\n\n    // Clear timers\n    if (this.resizeTimer) {\n      clearTimeout(this.resizeTimer);\n    }\n\n    // Emit destroy event\n    WMInfiniteSlider.emitEvent(\":destroy\", {el: this.el}, this.el);\n  }\n}\n\n// Immediate initialization (no DOMContentLoaded)\n(function () {\n  const pluginName = \"infinite-slider\";\n  const sections = document.querySelectorAll(`[id^=\"${pluginName}\"]`);\n  const instances = [];\n\n  sections.forEach(section => {\n    const sectionId = section.id;\n    const settings = window.wmInfiniteSliderSettings?.[sectionId] || {};\n    const instance = new WMInfiniteSlider(section, settings);\n    instances.push(instance);\n  });\n\n  // Backend teardown: watch for edit mode activation\n  if (window.top !== window.self) {\n    const observer = new MutationObserver(() => {\n      if (document.body.classList.contains(\"sqs-edit-mode-active\")) {\n        instances.forEach(instance => {\n          if (instance && typeof instance.destroy === \"function\") {\n            instance.destroy();\n          }\n        });\n        observer.disconnect();\n      }\n    });\n\n    observer.observe(document.body, {\n      attributes: true,\n      attributeFilter: [\"class\"],\n    });\n  }\n})();\n"]}