zoomora 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -73
- package/dist/zoomora.css +2 -2
- package/dist/zoomora.es.js +1210 -1221
- package/dist/zoomora.es.js.map +1 -1
- package/dist/zoomora.es.min.js +508 -519
- package/dist/zoomora.umd.js +1200 -1215
- package/dist/zoomora.umd.js.map +1 -1
- package/dist/zoomora.umd.min.js +507 -522
- package/package.json +2 -1
- package/src/styles/zoomora.scss +23 -4
- package/src/zoomora.js +1463 -1434
package/dist/zoomora.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zoomora.umd.js","names":[],"sources":["../src/styles/zoomora.scss","../src/styles/_variables.scss","../src/zoomora.js"],"sourcesContent":["/*!\n * Zoomora Lightbox Plugin v1.3.0\n * A modern, responsive lightbox plugin with zoom, fullscreen, and gallery features\n *\n * Copyright (c) 2026 Faruk Ahmed (FrontTheme)\n * Licensed under MIT License\n */\n\n@use 'variables' as *;\n\n// Font icons\n@font-face {\n font-family: \"Zoomora\";\n src: url(\"fonts/Zoomora.woff2\") format(\"woff2\"),\n url(\"fonts/Zoomora.ttf\") format(\"truetype\"),\n url(\"fonts/Zoomora.woff\") format(\"woff\");\n font-weight: normal;\n font-style: normal;\n font-display: block;\n}\n\n.zoomorai, [class^=\"zoomorai-\"], [class*=\" zoomorai-\"] {\n /* Use !important to prevent extensions from overriding this font. */\n font-family: \"Zoomora\" !important;\n font-style: normal;\n font-weight: normal;\n font-variant: normal;\n text-transform: none;\n line-height: 1;\n\n /* Better Font Rendering =========== */\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n.zoomorai-thumbnails:before {\n content: \"\\e900\";\n}\n\n.zoomorai-arrow-left:before {\n content: \"\\e901\";\n}\n\n.zoomorai-arrow-right:before {\n content: \"\\e902\";\n}\n\n.zoomorai-controls-on:before {\n content: \"\\e903\";\n}\n\n.zoomorai-zoom:before {\n content: \"\\e904\";\n}\n\n.zoomorai-controls-off:before {\n content: \"\\e905\";\n}\n\n.zoomorai-expand:before {\n content: \"\\e906\";\n}\n\n.zoomorai-collapse:before {\n content: \"\\e907\";\n}\n\n.zoomorai-close:before {\n content: \"\\e908\";\n}\n\n// ─── Runtime CSS custom properties ───────────────────────────────────────────\n// Sass variables are compiled away at build time; these :root declarations\n// expose the same values as overridable runtime variables so users can theme\n// Zoomora with plain CSS without recompiling the Sass source.\n//\n// :root {\n// --zoomora-overlay-bg: rgba(0, 0, 0, 0.92);\n// --zoomora-control-bg: rgba(255, 255, 255, 0.15);\n// --zoomora-control-hover: rgba(255, 255, 255, 0.25);\n// --zoomora-primary: #ff6b6b;\n// }\n// ─────────────────────────────────────────────────────────────────────────────\n:root {\n --zoomora-overlay-bg: #{rgba($dark-color, 0.95)};\n --zoomora-control-bg: rgba(255, 255, 255, 0.2);\n --zoomora-control-hover: rgba(255, 255, 255, 0.3);\n --zoomora-primary: #{$primary-color};\n}\n\n//Zoomora Lightbox Styles\n.zoomora {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: var(--zoomora-overlay-bg);\n backdrop-filter: blur(20px);\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n visibility: hidden;\n transition: $transition-slow;\n font-family: $font-family;\n font-size: $font-size-base;\n line-height: $line-height;\n}\n\n.zoomora.active {\n opacity: 1;\n visibility: visible;\n}\n\n.zoomora-container {\n position: relative;\n width: 100vw;\n height: 100vh;\n overflow: hidden;\n transform: scale(0.8);\n transition: transform 0.3s ease;\n}\n\n.zoomora.active .zoomora-container {\n transform: scale(1);\n}\n\n.zoomora-header {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n color: #fff;\n padding: 20px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n z-index: 10;\n}\n\n.zoomora-counter {\n font-size: 16px;\n font-weight: 600;\n background: rgba(255, 255, 255, 0.2);\n padding: 8px 16px;\n border-radius: 25px;\n backdrop-filter: blur(10px);\n}\n\n.zoomora-controls {\n display: flex;\n gap: 10px;\n}\n\n.zoomora-nav,\n.zoomora-btn {\n width: 50px;\n height: 50px;\n border: none;\n border-radius: 50%;\n background: var(--zoomora-control-bg);\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.3s ease;\n backdrop-filter: blur(10px);\n font-size: 18px;\n}\n\n.zoomora-btn:hover {\n background: var(--zoomora-control-hover);\n transform: scale(1.1);\n}\n\n.zoomora-content {\n position: relative;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n}\n\n.zoomora-media {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n cursor: pointer;\n}\n\n.zoomora-media:not(.dragging) {\n transition: transform 0.3s ease;\n}\n\n.zoomora-media.dragging {\n transition: none;\n}\n\n.zoomora-media.zoomed {\n cursor: grab;\n}\n\n.zoomora-media.zoomed:active {\n cursor: grabbing;\n}\n\n.zoomora-media.no-zoom {\n cursor: default;\n}\n\n.zoomora-slide-container {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.zoomora-slide {\n position: absolute;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n transition: opacity 0.3s ease, transform 0.3s ease;\n}\n\n.zoomora-slide.active {\n opacity: 1;\n}\n\niframe.zoomora-video {\n width: calc(100% - 200px);\n max-width: 800px;\n aspect-ratio: 16/9;\n border-radius: 16px;\n overflow: hidden;\n}\n\n.zoomora-slide.slide-effect {\n transform: translateX(100%);\n}\n\n.zoomora-slide.slide-effect.active {\n transform: translateX(0);\n}\n\n.zoomora-slide.slide-effect.prev {\n transform: translateX(-100%);\n}\n\n.zoomora-nav {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n width: 60px;\n height: 60px;\n font-size: 24px;\n z-index: 10;\n}\n\n.zoomora-nav:hover {\n background: var(--zoomora-control-hover);\n transform: translateY(-50%) scale(1.1);\n}\n\n.zoomora-nav.prev {\n left: 20px;\n}\n\n.zoomora-nav.next {\n right: 20px;\n}\n\n.zoomora-caption {\n position: absolute;\n bottom: 120px;\n left: 50%;\n transform: translateX(-50%) translateY(0);\n background: rgba($dark-color, 0.7);\n color: white;\n padding: 10px 20px;\n border-radius: 10px;\n backdrop-filter: blur(10px);\n max-width: 90%;\n text-align: center;\n font-size: 14px;\n z-index: 10;\n transition: bottom 0.3s ease, transform 0.3s ease;\n}\n\n.zoomora-caption.single-item-thumbnail {\n bottom: 20px !important;\n}\n\n.zoomora-thumbnails {\n position: absolute;\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%) translateY(0);\n display: flex;\n gap: 8px;\n background: rgba($dark-color, 0.5);\n padding: 8px;\n border-radius: 15px;\n backdrop-filter: blur(10px);\n max-width: 90%;\n overflow-x: auto;\n transition: opacity 0.3s ease, transform 0.3s ease;\n}\n\n.zoomora-thumbnails.thumbs-hidden {\n transform: translateX(-50%) translateY(100%) !important;\n opacity: 0 !important;\n pointer-events: none !important;\n}\n\n.zoomora-thumb {\n width: 40px;\n height: 60px;\n border-radius: 8px;\n overflow: hidden;\n cursor: pointer;\n opacity: 0.6;\n position: relative;\n transition: all 0.4s ease;\n}\n\n.zoomora-thumb:hover {\n opacity: 0.8;\n}\n\n.zoomora-thumb.active {\n background: linear-gradient(180deg, #fff, #fff) padding-box,\n linear-gradient(320deg, #4158D0, #C850C0, #0093E9) border-box;\n border: 2px solid transparent !important;\n opacity: 1;\n width: 80px;\n pointer-events: none;\n}\n\n.zoomora-thumb img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .zoomora-header {\n padding: 15px;\n }\n .zoomora-btn {\n width: 40px;\n height: 40px;\n font-size: 16px;\n }\n .zoomora-nav {\n width: 50px;\n height: 50px;\n font-size: 20px;\n }\n .zoomora-thumbnails {\n padding: 10px;\n }\n .zoomora-thumb {\n width: 50px;\n height: 50px;\n }\n .zoomora-thumb.active {\n width: 60px;\n }\n}\n\n/* Loading animation */\n.zoomora-loading {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 50px;\n height: 50px;\n border: 3px solid rgba(255, 255, 255, 0.3);\n border-top: 3px solid white;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n 0% {\n transform: translate(-50%, -50%) rotate(0deg);\n }\n 100% {\n transform: translate(-50%, -50%) rotate(360deg);\n }\n}\n\n/* Fullscreen styles */\n.zoomora.fullscreen {\n background: $dark-color;\n}\n\n.zoomora.fullscreen .zoomora-container {\n max-width: 100vw;\n max-height: 100vh;\n border-radius: 0;\n}\n\n/* Video container styles */\n.zoomora-video-container {\n position: relative;\n display: inline-block;\n width: 100%;\n height: 100%;\n}\n\n.zoomora-video-container video {\n width: 100%;\n height: 100%;\n object-fit: contain;\n max-width: max-content;\n}\n\n/* Play button overlay styles */\n.zoomora-play-button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 80px;\n height: 80px;\n background: rgba(255, 255, 255, 0.8);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.3s ease;\n z-index: 10;\n color: black;\n border: 3px solid rgba(255, 255, 255, 0.3);\n}\n\n.zoomora-play-button:hover {\n background: rgba(255, 255, 255, 0.9);\n border-color: rgba(255, 255, 255, 0.5);\n transform: translate(-50%, -50%) scale(1.1);\n}\n\n.zoomora-play-button svg {\n width: 32px;\n height: 32px;\n margin-left: 4px; /* Slight offset to center the triangle visually */\n}\n\n/* Alternative smaller play button style */\n.zoomora-play-button.small {\n width: 60px;\n height: 60px;\n}\n\n.zoomora-play-button.small svg {\n width: 24px;\n height: 24px;\n}\n\n/* Animation for play button appearance */\n@keyframes playButtonFadeIn {\n from {\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.8);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n}\n\n.zoomora-play-button {\n animation: playButtonFadeIn 0.3s ease-out;\n}\n\n/* Video loading state */\n.zoomora-video-container::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba($dark-color, 0.1);\n z-index: 1;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.3s ease;\n}\n\n.zoomora-video-container.loading::before {\n opacity: 1;\n}\n\n/* Responsive adjustments */\n@media (max-width: 768px) {\n .zoomora-play-button {\n width: 60px;\n height: 60px;\n }\n .zoomora-play-button svg {\n width: 24px;\n height: 24px;\n }\n}\n\n.zoomora-slides-container {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n.zoomora-slide {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n\n &.fade-effect {\n transition: opacity 300ms ease, transform 300ms ease;\n }\n\n &.slide-effect {\n transition: transform 300ms ease, opacity 300ms ease;\n }\n}\n\n.zoomora-header,\n.zoomora-caption,\n.zoomora-thumbnails,\n.zoomora-nav {\n transition: transform 300ms ease, opacity 300ms ease;\n}\n\n.zoomora.controls-hidden {\n cursor: none;\n\n .zoomora-header,\n .zoomora-caption,\n .zoomora-thumbnails,\n .zoomora-nav {\n pointer-events: none;\n }\n}\n\n.zoomora-btn.active {\n background-color: rgba(255, 255, 255, 0.2);\n}\n\n// Auto-hide button active state\n#zoomoraAutoHideBtn.active {\n color: var(--zoomora-primary);\n}",null,"/*!\n * Zoomora Lightbox Plugin v1.3.0\n * A modern, responsive lightbox plugin with zoom, fullscreen, and gallery features\n *\n * Copyright (c) 2026 Faruk Ahmed (FrontTheme)\n * Licensed under MIT License\n */\n\n// Import styles\nimport './styles/zoomora.scss';\n\n(function (global, factory) {\n 'use strict';\n\n if (typeof module === 'object' && typeof module.exports === 'object') {\n // CommonJS/Node.js\n module.exports = factory();\n } else if (typeof define === 'function' && define.amd) {\n // AMD\n define(factory);\n } else {\n // Browser globals\n global.Zoomora = factory();\n }\n}(typeof window !== 'undefined' ? window : this, function () {\n 'use strict';\n\n /**\n * Zoomora Lightbox Plugin\n * @class\n */\n class Zoomora {\n /**\n * Default configuration options\n * @type {Object}\n */\n static get defaults() {\n return {\n selector: '[data-zoomora]',\n showCounter: true,\n showThumbnails: true,\n showFullscreen: true,\n showZoom: true,\n transition: 'fade', // 'fade' or 'slide'\n useHref: false, // Use href instead of data-src\n maxZoomScale: 3, // Maximum zoom scale\n zoomStep: 0.1, // Zoom step for scroll wheel\n animationDuration: 300, // Animation duration in ms\n closeOnBackgroundClick: true, // Close lightbox when clicking on background\n onOpen: null, // Callback when lightbox opens\n onClose: null, // Callback when lightbox closes\n onNext: null, // Callback when navigating to next item\n onPrev: null, // Callback when navigating to previous item\n\n // Auto-hide controls\n showAutoHideToggle: true, // Show auto-hide toggle button\n autoHideDelay: 3000, // Delay in ms before hiding controls\n autoHideEnabled: false, // Default state of auto-hide\n };\n }\n\n /**\n * Constructor\n * @param {Object} options - Configuration options\n */\n constructor(options = {}) {\n this.options = {...Zoomora.defaults, ...options};\n this.currentIndex = 0;\n this.items = [];\n this.isZoomed = false;\n this.isFullscreen = false;\n this.isDragging = false;\n this.thumbnailsVisible = true;\n this.startX = 0;\n this.startY = 0;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n this.isInitialized = false;\n this.eventListeners = new Map();\n\n // Auto-hide controls\n this.autoHideEnabled = false;\n this.autoHideTimeout = null;\n this.autoHideDelay = 3000;\n this.isControlsVisible = true;\n\n this.lastDragTime = 0;\n this.boundMethods = {\n handleDocumentClick: this.handleDocumentClick.bind(this),\n handleKeydown: this.handleKeydown.bind(this),\n handleFullscreenChange: this.handleFullscreenChange.bind(this),\n handleZoomoraClick: this.handleZoomoraClick.bind(this),\n handleContentClick: this.handleContentClick.bind(this),\n handleMouseDown: this.handleMouseDown.bind(this),\n handleMouseMove: this.handleMouseMove.bind(this),\n handleMouseUp: this.handleMouseUp.bind(this),\n handleTouchStart: this.handleTouchStart.bind(this),\n handleTouchMove: this.handleTouchMove.bind(this),\n handleTouchEnd: this.handleTouchEnd.bind(this),\n handleWheel: this.handleWheel.bind(this),\n };\n\n this.init();\n }\n\n /**\n * Initialize the plugin\n */\n init() {\n if (this.isInitialized) {\n console.warn('Zoomora: Plugin already initialized');\n return;\n }\n\n try {\n this.createLightbox();\n this.bindEvents();\n\n this.isInitialized = true;\n } catch (error) {\n console.error('Zoomora: Initialization failed', error);\n }\n }\n\n /**\n * Static method to bind to anchor tags with href\n * @param {string} selector - CSS selector\n * @param {Object} options - Configuration options\n * @returns {Zoomora} - New Zoomora instance\n */\n static bind(selector, options = {}) {\n const enhancedOptions = {\n ...options,\n selector: selector,\n useHref: true\n };\n return new Zoomora(enhancedOptions);\n }\n\n /**\n * Create lightbox HTML structure\n */\n createLightbox() {\n // Check if lightbox already exists\n if (document.getElementById('zoomoraLightbox')) {\n console.warn('Zoomora: Lightbox already exists in DOM');\n return;\n }\n\n // Build auto-hide button conditionally\n const autoHideButtonHTML = this.options.showAutoHideToggle ? `\n <button class=\"zoomora-btn\" id=\"zoomoraAutoHideBtn\" title=\"Toggle Auto-Hide Controls\">\n <i class=\"zoomorai-controls-off\"></i>\n </button>\n ` : '';\n\n const zoomoraHTML = `\n <div class=\"zoomora\" id=\"zoomoraLightbox\">\n <div class=\"zoomora-container\">\n <div class=\"zoomora-header\" id=\"zoomoraHeader\">\n <div class=\"zoomora-counter\" id=\"zoomoraCounter\" ${!this.options.showCounter ? 'style=\"opacity:0;visibility:hidden;\"' : ''}>1 / 1</div>\n <div class=\"zoomora-controls\">\n ${this.options.showThumbnails ? `\n <button class=\"zoomora-btn\" id=\"zoomoraThumbnailBtn\" title=\"Toggle Thumbnails\">\n <i class=\"zoomorai-thumbnails\"></i>\n </button>\n ` : ''}\n ${autoHideButtonHTML}\n ${this.options.showZoom ? `\n <button class=\"zoomora-btn\" id=\"zoomoraZoomBtn\" title=\"Zoom\">\n <i class=\"zoomorai-zoom\"></i>\n </button>\n ` : ''}\n ${this.options.showFullscreen ? `\n <button class=\"zoomora-btn\" id=\"zoomoraFullscreenBtn\" title=\"Fullscreen\">\n <i class=\"zoomorai-expand\"></i>\n </button>\n <button class=\"zoomora-btn\" id=\"zoomoraCollapseBtn\" title=\"Exit Fullscreen\" style=\"display: none;\">\n <i class=\"zoomorai-collapse\"></i>\n </button>\n ` : ''}\n <button class=\"zoomora-btn\" id=\"zoomoraCloseBtn\" title=\"Close\">\n <i class=\"zoomorai-close\"></i>\n </button>\n </div>\n </div>\n \n <div class=\"zoomora-content\" id=\"zoomoraContent\">\n <div class=\"zoomora-loading\" id=\"zoomoraLoading\"></div>\n <div class=\"zoomora-slides-container\" id=\"zoomoraSlidesContainer\"></div>\n </div>\n \n <button class=\"zoomora-nav prev\" id=\"zoomoraPrevBtn\">\n <i class=\"zoomorai-arrow-left\"></i>\n </button>\n <button class=\"zoomora-nav next\" id=\"zoomoraNextBtn\">\n <i class=\"zoomorai-arrow-right\"></i>\n </button>\n \n <div class=\"zoomora-caption\" id=\"zoomoraCaption\" ${!this.options.showThumbnails ? 'style=\"bottom:20px;\"' : ''}></div>\n <div class=\"zoomora-thumbnails\" id=\"zoomoraThumbs\" ${!this.options.showThumbnails ? 'style=\"display:none;\"' : ''}></div>\n </div>\n </div>\n `;\n\n document.body.insertAdjacentHTML('beforeend', zoomoraHTML);\n\n // Cache DOM elements\n this.zoomora = document.getElementById('zoomoraLightbox');\n this.header = document.getElementById('zoomoraHeader');\n this.content = document.getElementById('zoomoraContent');\n this.slidesContainer = document.getElementById('zoomoraSlidesContainer');\n this.counter = document.getElementById('zoomoraCounter');\n this.thumbs = document.getElementById('zoomoraThumbs');\n this.loading = document.getElementById('zoomoraLoading');\n this.caption = document.getElementById('zoomoraCaption');\n this.prevBtn = document.getElementById('zoomoraPrevBtn');\n this.nextBtn = document.getElementById('zoomoraNextBtn');\n\n // Verify all elements were created\n if (!this.zoomora || !this.content || !this.counter || !this.thumbs || !this.loading || !this.caption) {\n throw new Error('Failed to create required DOM elements');\n }\n }\n\n /**\n * Bind event listeners\n */\n bindEvents() {\n // Document click handler for opening lightbox\n this.addEventListener(document, 'click', this.boundMethods.handleDocumentClick);\n\n // Control button handlers\n this.addEventListener(document.getElementById('zoomoraCloseBtn'), 'click', () => this.close());\n this.addEventListener(document.getElementById('zoomoraPrevBtn'), 'click', () => this.prev());\n this.addEventListener(document.getElementById('zoomoraNextBtn'), 'click', () => this.next());\n if (this.options.showZoom) {\n this.addEventListener(document.getElementById('zoomoraZoomBtn'), 'click', () => this.toggleZoom());\n }\n if (this.options.showFullscreen) {\n this.addEventListener(document.getElementById('zoomoraFullscreenBtn'), 'click', () => this.toggleFullscreen());\n this.addEventListener(document.getElementById('zoomoraCollapseBtn'), 'click', () => this.exitFullscreen());\n }\n if (this.options.showThumbnails) {\n this.addEventListener(document.getElementById('zoomoraThumbnailBtn'), 'click', () => this.toggleThumbnails());\n }\n\n // Fullscreen change events\n this.addEventListener(document, 'fullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'webkitfullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'mozfullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'MSFullscreenChange', this.boundMethods.handleFullscreenChange);\n\n // Keyboard navigation\n this.addEventListener(document, 'keydown', this.boundMethods.handleKeydown);\n\n // Lightbox click to close\n this.addEventListener(this.zoomora, 'click', this.boundMethods.handleZoomoraClick);\n\n // Content click for zoom toggle and background click\n this.addEventListener(this.content, 'click', this.boundMethods.handleContentClick);\n\n // Mouse drag events\n this.addEventListener(this.content, 'mousedown', this.boundMethods.handleMouseDown);\n this.addEventListener(this.content, 'mousemove', this.boundMethods.handleMouseMove);\n this.addEventListener(this.content, 'mouseup', this.boundMethods.handleMouseUp);\n this.addEventListener(this.content, 'mouseleave', this.boundMethods.handleMouseUp);\n\n // Touch events\n this.addEventListener(this.content, 'touchstart', this.boundMethods.handleTouchStart, {passive: false});\n this.addEventListener(this.content, 'touchmove', this.boundMethods.handleTouchMove, {passive: false});\n this.addEventListener(this.content, 'touchend', this.boundMethods.handleTouchEnd);\n\n // Scroll-wheel zoom\n if (this.options.showZoom) {\n this.addEventListener(this.content, 'wheel', this.boundMethods.handleWheel, {passive: false});\n }\n\n // Add auto-hide toggle button handler (only if enabled)\n if (this.options.showAutoHideToggle) {\n this.addEventListener(document.getElementById('zoomoraAutoHideBtn'), 'click', () => this.toggleAutoHide());\n\n // Add mouse/touch activity listeners for auto-hide\n this.addEventListener(this.zoomora, 'mousemove', () => this.handleUserActivity());\n this.addEventListener(this.zoomora, 'touchstart', () => this.handleUserActivity());\n this.addEventListener(this.zoomora, 'keydown', () => this.handleUserActivity());\n }\n }\n\n /**\n * Add event listener with cleanup tracking\n * @param {EventTarget} element - DOM element or document\n * @param {string} event - Event type\n * @param {Function} handler - Event handler\n * @param {Object} options - Event options\n */\n addEventListener(element, event, handler, options = {}) {\n if (!element) return;\n\n element.addEventListener(event, handler, options);\n\n // Track for cleanup\n const key = `${element.constructor.name}_${event}`;\n if (!this.eventListeners.has(key)) {\n this.eventListeners.set(key, []);\n }\n this.eventListeners.get(key).push({element, event, handler, options});\n }\n\n /**\n * Handle document click events\n * @param {Event} e - Click event\n */\n handleDocumentClick(e) {\n const target = e.target.closest(this.options.selector);\n if (target) {\n e.preventDefault();\n this.open(target);\n }\n }\n\n /**\n * Handle keyboard events\n * @param {KeyboardEvent} e - Keyboard event\n */\n handleKeydown(e) {\n if (!this.zoomora.classList.contains('active')) return;\n\n switch (e.key) {\n case 'Escape':\n if (this.isFullscreen) {\n this.exitFullscreen();\n } else {\n this.close();\n }\n break;\n case 'ArrowLeft':\n this.prev();\n break;\n case 'ArrowRight':\n this.next();\n break;\n case 'z':\n case 'Z':\n this.toggleZoom();\n break;\n case 'f':\n case 'F':\n this.toggleFullscreen();\n break;\n case 't':\n case 'T':\n this.toggleThumbnails();\n break;\n }\n }\n\n /**\n * Handle fullscreen change events\n */\n handleFullscreenChange() {\n const isInFullscreen = !!(\n document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement\n );\n\n // Only update if state changed from fullscreen to not fullscreen\n if (!isInFullscreen && this.isFullscreen) {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n // Update if entering fullscreen\n else if (isInFullscreen && !this.isFullscreen) {\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n }\n\n /**\n * Handle zoomora container clicks\n * @param {Event} e - Click event\n */\n handleZoomoraClick(e) {\n if (e.target === this.zoomora && this.options.closeOnBackgroundClick) {\n this.close();\n }\n }\n\n /**\n * Handle content clicks\n * @param {Event} e - Click event\n */\n handleContentClick(e) {\n // Ignore click if we just finished dragging (within 200ms)\n if (Date.now() - this.lastDragTime < 200) {\n return;\n }\n\n // Don't close on header clicks\n if (this.header && this.header.contains(e.target)) {\n return;\n }\n\n // Don't close on button clicks\n if (e.target.closest('button')) {\n return;\n }\n\n // Check if click is directly on actual media element (img, video, iframe)\n const mediaElement = e.target.closest('.zoomora-media, .zoomora-video, .zoomora-iframe');\n\n if (mediaElement) {\n // Only toggle zoom for images\n if (mediaElement.classList.contains('zoomora-media') && !mediaElement.classList.contains('no-zoom')) {\n this.toggleZoom();\n }\n return;\n }\n\n // Check if clicking inside video container but not on video itself\n const videoContainer = e.target.closest('.zoomora-video-container');\n if (videoContainer) {\n // If clicking on the play button, don't close\n if (e.target.closest('.zoomora-play-button')) {\n return;\n }\n // If clicking on background area of video container, close\n if (this.options.closeOnBackgroundClick) {\n this.close();\n }\n return;\n }\n\n // Check if clicking on background elements (including when zoomed)\n // This checks the actual target element, not just closest()\n const clickedElement = e.target;\n const isBackgroundElement =\n clickedElement.classList.contains('zoomora-content') ||\n clickedElement.classList.contains('zoomora-slide-container') ||\n clickedElement.classList.contains('zoomora-slide') ||\n clickedElement.classList.contains('zoomora-slides-container') ||\n clickedElement.id === 'zoomoraContent' ||\n clickedElement.id === 'zoomoraSlidesContainer';\n\n if (isBackgroundElement && this.options.closeOnBackgroundClick) {\n this.close();\n return;\n }\n\n // If we reach here and no media was clicked, close\n if (this.options.closeOnBackgroundClick) {\n this.close();\n }\n }\n\n /**\n * Handle mouse down events\n * @param {MouseEvent} e - Mouse event\n */\n handleMouseDown(e) {\n this.startDrag(e);\n }\n\n /**\n * Handle mouse move events\n * @param {MouseEvent} e - Mouse event\n */\n handleMouseMove(e) {\n this.drag(e);\n }\n\n /**\n * Handle mouse up events\n */\n handleMouseUp() {\n this.endDrag();\n }\n\n /**\n * Handle touch start events\n * @param {TouchEvent} e - Touch event\n */\n handleTouchStart(e) {\n this.startDrag(e);\n }\n\n /**\n * Handle touch move events\n * @param {TouchEvent} e - Touch event\n */\n handleTouchMove(e) {\n this.drag(e);\n }\n\n /**\n * Handle touch end events\n */\n handleTouchEnd() {\n this.endDrag();\n }\n\n /**\n * Handle scroll-wheel zoom\n * @param {WheelEvent} e - Wheel event\n */\n handleWheel(e) {\n const media = this.content.querySelector('.zoomora-media');\n if (!media || media.tagName !== 'IMG') return;\n\n const zoomConfig = this.calculateZoomLevels(media);\n if (!zoomConfig.canZoom) return;\n\n e.preventDefault();\n\n const maxScale = zoomConfig.levels[zoomConfig.levels.length - 1];\n const step = this.options.zoomStep || 0.1;\n const direction = e.deltaY < 0 ? 1 : -1; // scroll/pinch up = zoom in\n\n let newScale = (this.currentScale || 1) + (direction * step * maxScale);\n newScale = Math.max(1, Math.min(maxScale, newScale));\n\n if (newScale === this.currentScale) return;\n\n this.currentScale = newScale;\n this.isZoomed = newScale > 1;\n this.currentX = 0;\n this.currentY = 0;\n\n if (this.isZoomed) {\n media.style.transform = `scale(${newScale})`;\n media.style.cursor = 'grab';\n media.classList.add('zoomed');\n } else {\n media.style.transform = '';\n media.style.cursor = 'pointer';\n media.classList.remove('zoomed');\n }\n\n // Keep the click-to-cycle zoom index roughly in sync with the\n // continuous wheel scale, so a click after scrolling cycles sensibly.\n let nearestIndex = 0;\n zoomConfig.levels.forEach((level, index) => {\n if (Math.abs(level - newScale) < Math.abs(zoomConfig.levels[nearestIndex] - newScale)) {\n nearestIndex = index;\n }\n });\n media.dataset.zoomLevel = nearestIndex.toString();\n }\n\n /**\n * Get image source from element\n * @param {Element} item - DOM element\n * @returns {string} - Image source URL\n */\n getImageSource(item) {\n const src = item.dataset.src || item.src || item.getAttribute('src');\n const type = item.dataset.type || 'image';\n\n // Handle YouTube URLs for video types\n if (type === 'video' && src) {\n return this.convertToEmbedUrl(src);\n }\n\n return src;\n }\n\n /**\n * Convert YouTube URLs to embed format\n * @param url\n * @returns {*|string}\n */\n convertToEmbedUrl(url) {\n // If already an embed URL, return as is\n if (url.includes('youtube.com/embed/')) {\n return url;\n }\n\n // Handle different YouTube URL formats\n let videoId = null;\n let startTime = null;\n\n // Extract video ID and start time from different YouTube URL formats\n if (url.includes('youtube.com/watch')) {\n const urlParams = new URLSearchParams(url.split('?')[1]);\n videoId = urlParams.get('v');\n const t = urlParams.get('t');\n if (t) {\n // Convert time format (e.g., \"111s\" to seconds)\n startTime = t.replace('s', '');\n }\n } else if (url.includes('youtu.be/')) {\n const parts = url.split('/');\n const videoAndParams = parts[parts.length - 1];\n if (videoAndParams.includes('?')) {\n videoId = videoAndParams.split('?')[0];\n const urlParams = new URLSearchParams(videoAndParams.split('?')[1]);\n const t = urlParams.get('t');\n if (t) startTime = t.replace('s', '');\n } else {\n videoId = videoAndParams;\n }\n }\n\n if (videoId) {\n let embedUrl = `https://www.youtube.com/embed/${videoId}`;\n const params = new URLSearchParams();\n\n if (startTime) {\n params.append('start', startTime);\n }\n\n // Add other useful parameters\n params.append('rel', '0'); // Don't show related videos\n params.append('modestbranding', '1'); // Modest branding\n\n // Option: Add autoplay for YouTube videos (uncomment if desired)\n // params.append('autoplay', '1');\n\n if (params.toString()) {\n embedUrl += '?' + params.toString();\n }\n\n return embedUrl;\n }\n\n // If not a YouTube URL or couldn't parse, return original\n return url;\n }\n\n /**\n * Get thumbnail source from element\n * @param {Element} item - DOM element\n * @returns {string} - Thumbnail source URL\n */\n getThumbnailSource(item) {\n const type = item.dataset.type || 'image';\n\n // For video items, always use the img.src as thumbnail (poster image)\n if (type === 'video') {\n return item.src || item.getAttribute('src');\n }\n\n // For regular images, use data-src or fallback to src\n return item.dataset.src || item.src || item.getAttribute('src');\n }\n\n /**\n * Get group identifier from element\n * @param {Element} element - DOM element\n * @returns {string} - Group identifier\n */\n getGroup(element) {\n if (this.options.useHref) {\n return element.dataset.lightbox || element.dataset.gallery || 'default';\n }\n return element.dataset.zoomora || 'default';\n }\n\n /**\n * Open lightbox with specified element\n * @param {Element} element - DOM element to open\n */\n open(element) {\n if (!element) return;\n\n const group = this.getGroup(element);\n let groupSelector;\n\n if (this.options.useHref) {\n if (element.dataset.lightbox) {\n groupSelector = `[data-lightbox=\"${group}\"]`;\n } else if (element.dataset.gallery) {\n groupSelector = `[data-gallery=\"${group}\"]`;\n } else {\n groupSelector = this.options.selector;\n }\n } else {\n groupSelector = `[data-zoomora=\"${group}\"]`;\n }\n\n this.items = Array.from(document.querySelectorAll(groupSelector));\n this.currentIndex = Math.max(0, this.items.indexOf(element));\n\n this._activateLightbox();\n\n // Trigger callback\n if (typeof this.options.onOpen === 'function') {\n this.options.onOpen(element, this.currentIndex);\n }\n }\n\n /**\n * Open lightbox programmatically with image(s) not present in the DOM.\n * Accepts a single URL, an array of URLs, a config object, or an array\n * of config objects — so all of these work:\n *\n * lightbox.openImage('photo.jpg');\n * lightbox.openImage(['a.jpg', 'b.jpg'], { startIndex: 1 });\n * lightbox.openImage({ src: 'photo.jpg', caption: 'Hello' });\n * lightbox.openImage([\n * { src: 'a.jpg', caption: 'First' },\n * { src: 'https://youtu.be/xyz', type: 'video', thumb: 'poster.jpg' },\n * ]);\n *\n * @param {string|string[]|Object|Object[]} images - URL(s) or config object(s)\n * @param {Object} [opts] - Options\n * @param {number} [opts.startIndex=0] - Index to open at when passing an array\n */\n openImage(images, opts = {}) {\n const list = Array.isArray(images) ? images : [images];\n\n this.items = list.map(entry =>\n this.createVirtualItem(typeof entry === 'string' ? {src: entry} : entry)\n );\n\n this.currentIndex = Math.max(\n 0,\n Math.min(opts.startIndex || 0, this.items.length - 1)\n );\n\n this._activateLightbox();\n\n // Trigger callback\n if (typeof this.options.onOpen === 'function') {\n this.options.onOpen(this.items[this.currentIndex], this.currentIndex);\n }\n }\n\n /**\n * Create a virtual item that mimics a DOM element's interface so\n * programmatic images work through the existing render pipeline without\n * any changes to getImageSource, getThumbnailSource, updateCaption, etc.\n * @param {Object} config\n * @param {string} config.src - Full-size image/video/iframe URL\n * @param {string} [config.thumb] - Thumbnail URL (falls back to src)\n * @param {string} [config.type='image'] - 'image', 'video', or 'iframe'\n * @param {string} [config.caption=''] - Caption text\n * @param {string} [config.alt=''] - Alt text for the thumbnail img\n * @returns {Object} Virtual item\n */\n createVirtualItem({src, thumb, type = 'image', caption = '', alt = ''}) {\n const thumbSrc = thumb || src;\n return {\n dataset: {src, type, caption},\n src: thumbSrc,\n alt,\n title: caption,\n getAttribute: (name) => name === 'src' ? thumbSrc : null,\n };\n }\n\n /**\n * Shared activation sequence used by both open() and openImage().\n * Resets state, shows the lightbox, and triggers all UI updates.\n */\n _activateLightbox() {\n // Reset states\n this.isZoomed = false;\n this.isFullscreen = false;\n this.thumbnailsVisible = true;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n this.zoomora.classList.add('active');\n document.body.style.overflow = 'hidden';\n\n this.loadContent();\n this.updateThumbnails();\n this.updateCounter();\n this.updateNavigation();\n this.updateCaption();\n this.updateButtons();\n\n // Initialize auto-hide\n if (this.autoHideEnabled) {\n this.startAutoHideTimer();\n } else {\n this.showControls();\n }\n }\n\n /**\n * Close lightbox\n */\n close() {\n if (this.isFullscreen) {\n this.exitFullscreen();\n }\n\n this.zoomora.classList.remove('active');\n document.body.style.overflow = '';\n this.isZoomed = false;\n this.isFullscreen = false;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n const media = this.content.querySelector('.zoomora-media');\n if (media) {\n media.classList.remove('zoomed');\n media.style.transform = '';\n media.style.cursor = '';\n }\n\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n\n // Clean up auto-hide\n this.stopAutoHideTimer();\n this.showControls();\n\n // Trigger callback\n if (typeof this.options.onClose === 'function') {\n this.options.onClose(this.currentIndex);\n }\n }\n\n /**\n * Navigate to previous item\n */\n prev() {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n\n // Trigger callback\n if (typeof this.options.onPrev === 'function') {\n this.options.onPrev(this.currentIndex);\n }\n }\n }\n\n /**\n * Navigate to next item\n */\n next() {\n if (this.currentIndex < this.items.length - 1) {\n this.currentIndex++;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n\n // Trigger callback\n if (typeof this.options.onNext === 'function') {\n this.options.onNext(this.currentIndex);\n }\n }\n }\n\n /**\n * Load content for current item\n */\n loadContent() {\n if (!this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const src = this.getImageSource(item);\n const type = item.dataset.type || 'image';\n\n if (!src) {\n console.error('Zoomora: No source found for item');\n return;\n }\n\n // Reset zoom state\n this.isZoomed = false;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n // Show loading spinner\n this.loading.style.display = 'block';\n\n if (this.slidesContainer) {\n this.slidesContainer.innerHTML = '';\n }\n\n setTimeout(() => {\n this.renderContent(src, type, item);\n }, 100);\n }\n\n /**\n * Render content based on type\n * @param {string} src - Source URL\n * @param {string} type - Content type\n * @param {Element} item - Original item element\n */\n renderContent(src, type, item) {\n const slideContainer = document.createElement('div');\n slideContainer.className = 'zoomora-slide-container';\n\n // Create slide wrapper\n const slide = document.createElement('div');\n slide.className = `zoomora-slide ${this.options.transition === 'slide' ? 'slide-effect' : 'fade-effect'}`;\n slide.style.opacity = '0';\n slide.style.transform = this.options.transition === 'slide' ? 'translateX(100%)' : 'scale(0.8)';\n\n let mediaElement;\n\n try {\n switch (type) {\n case 'video':\n if (src.endsWith('.mp4') || src.endsWith('.webm') || src.endsWith('.ogg')) {\n const videoContainer = document.createElement('div');\n videoContainer.className = 'zoomora-video-container';\n\n mediaElement = document.createElement('video');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-video';\n mediaElement.setAttribute('preload', 'metadata');\n\n const posterSrc = item.src || item.getAttribute('src');\n if (posterSrc) {\n mediaElement.setAttribute('poster', posterSrc);\n }\n\n const playButton = document.createElement('div');\n playButton.className = 'zoomora-play-button';\n playButton.innerHTML = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"/></svg>`;\n\n playButton.addEventListener('click', () => {\n mediaElement.play();\n playButton.style.display = 'none';\n mediaElement.setAttribute('controls', '');\n });\n\n mediaElement.addEventListener('ended', () => {\n playButton.style.display = 'flex';\n });\n\n videoContainer.appendChild(mediaElement);\n videoContainer.appendChild(playButton);\n slideContainer.appendChild(videoContainer);\n } else {\n mediaElement = document.createElement('iframe');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-video';\n mediaElement.setAttribute('allowfullscreen', '');\n mediaElement.setAttribute('frameborder', '0');\n slideContainer.appendChild(mediaElement);\n }\n break;\n\n case 'iframe':\n mediaElement = document.createElement('iframe');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-iframe';\n mediaElement.setAttribute('frameborder', '0');\n slideContainer.appendChild(mediaElement);\n break;\n\n default:\n mediaElement = document.createElement('img');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-media';\n mediaElement.alt = item.alt || item.title || '';\n\n mediaElement.onload = () => {\n this.loading.style.display = 'none';\n this.checkZoomability(mediaElement);\n this.animateSlideIn(slide);\n };\n\n mediaElement.onerror = () => {\n this.loading.style.display = 'none';\n console.error('Zoomora: Failed to load image:', src);\n this.animateSlideIn(slide);\n };\n\n slideContainer.appendChild(mediaElement);\n }\n\n slide.appendChild(slideContainer);\n\n // Clear existing slides and add new one\n this.slidesContainer.innerHTML = '';\n this.slidesContainer.appendChild(slide);\n\n if (type !== 'image') {\n this.loading.style.display = 'none';\n this.animateSlideIn(slide);\n }\n\n } catch (error) {\n console.error('Zoomora: Error rendering content:', error);\n this.loading.style.display = 'none';\n }\n }\n\n // Animation helper\n animateSlideIn(slide) {\n // Force reflow\n slide.offsetHeight;\n\n // Add active class and animate\n slide.classList.add('active');\n\n if (this.options.transition === 'slide') {\n slide.style.transition = `transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`;\n slide.style.transform = 'translateX(0)';\n slide.style.opacity = '1';\n } else {\n slide.style.transition = `transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`;\n slide.style.transform = 'scale(1)';\n slide.style.opacity = '1';\n }\n }\n\n // Toggle auto-hide controls\n toggleAutoHide() {\n this.autoHideEnabled = !this.autoHideEnabled;\n const autoHideBtn = document.getElementById('zoomoraAutoHideBtn');\n\n if (this.autoHideEnabled) {\n autoHideBtn.classList.add('active');\n autoHideBtn.title = 'Disable Auto-Hide Controls';\n this.startAutoHideTimer();\n } else {\n autoHideBtn.classList.remove('active');\n autoHideBtn.title = 'Enable Auto-Hide Controls';\n this.stopAutoHideTimer();\n this.showControls();\n }\n }\n\n // Handle user activity\n handleUserActivity() {\n if (!this.autoHideEnabled) return;\n\n this.showControls();\n this.startAutoHideTimer();\n }\n\n // Start auto-hide timer\n startAutoHideTimer() {\n this.stopAutoHideTimer();\n\n this.autoHideTimeout = setTimeout(() => {\n this.hideControls();\n }, this.options.autoHideDelay);\n }\n\n // Stop auto-hide timer\n stopAutoHideTimer() {\n if (this.autoHideTimeout) {\n clearTimeout(this.autoHideTimeout);\n this.autoHideTimeout = null;\n }\n }\n\n // Show controls\n showControls() {\n if (this.isControlsVisible) return;\n\n this.isControlsVisible = true;\n this.zoomora.classList.remove('controls-hidden');\n\n // Animate controls back in\n if (this.header) {\n this.header.style.transform = 'translateY(0)';\n this.header.style.opacity = '1';\n }\n\n if (this.caption) {\n this.caption.style.transform = 'translateX(-50%) translateY(0)';\n this.caption.style.opacity = '1';\n }\n\n if (this.thumbs) {\n this.thumbs.style.transform = 'translateX(-50%) translateY(0)';\n this.thumbs.style.opacity = '1';\n }\n\n if (this.prevBtn) {\n this.prevBtn.style.transform = 'translateX(0)';\n this.prevBtn.style.opacity = '1';\n }\n\n if (this.nextBtn) {\n this.nextBtn.style.transform = 'translateX(0)';\n this.nextBtn.style.opacity = '1';\n }\n }\n\n // Hide controls\n hideControls() {\n if (!this.isControlsVisible) return;\n\n this.isControlsVisible = false;\n this.zoomora.classList.add('controls-hidden');\n\n // Animate controls out\n if (this.header) {\n this.header.style.transform = 'translateY(-100%)';\n this.header.style.opacity = '0';\n }\n\n if (this.caption) {\n this.caption.style.transform = 'translateX(-50%) translateY(100%)';\n this.caption.style.opacity = '0';\n }\n\n if (this.thumbs) {\n this.thumbs.style.transform = 'translateX(-50%) translateY(100%)';\n this.thumbs.style.opacity = '0';\n }\n\n if (this.prevBtn) {\n this.prevBtn.style.transform = 'translateX(-100%)';\n this.prevBtn.style.opacity = '0';\n }\n\n if (this.nextBtn) {\n this.nextBtn.style.transform = 'translateX(100%)';\n this.nextBtn.style.opacity = '0';\n }\n }\n\n /**\n * Check if image can be zoomed\n * @param {HTMLImageElement} img - Image element\n */\n checkZoomability(img) {\n if (!img || !img.naturalWidth || !img.naturalHeight) return;\n\n const imgRect = img.getBoundingClientRect();\n const renderedWidth = imgRect.width;\n const renderedHeight = imgRect.height;\n const naturalWidth = img.naturalWidth;\n const naturalHeight = img.naturalHeight;\n\n const isScaledDown = naturalWidth > renderedWidth || naturalHeight > renderedHeight;\n const zoomRatioX = naturalWidth / renderedWidth;\n const zoomRatioY = naturalHeight / renderedHeight;\n const maxZoomRatio = Math.max(zoomRatioX, zoomRatioY);\n\n // Store zoom info\n img.dataset.zoomRatio = maxZoomRatio.toString();\n img.dataset.naturalWidth = naturalWidth.toString();\n img.dataset.naturalHeight = naturalHeight.toString();\n img.dataset.renderedWidth = renderedWidth.toString();\n img.dataset.renderedHeight = renderedHeight.toString();\n\n // Enable zoom if significantly scaled down\n if (isScaledDown && maxZoomRatio > 1.1) {\n img.classList.remove('no-zoom');\n } else {\n img.classList.add('no-zoom');\n }\n }\n\n /**\n * Calculate zoom levels for an image\n * @param {HTMLImageElement} img - Image element\n * @returns {Object} Zoom configuration\n */\n calculateZoomLevels(img) {\n if (!img || !img.naturalWidth || !img.naturalHeight) {\n return {canZoom: false, levels: [], currentLevel: 0};\n }\n\n // Get CONTAINER size (not current displayed image size)\n const container = this.content.getBoundingClientRect();\n const containerWidth = container.width;\n const containerHeight = container.height;\n\n const naturalWidth = img.naturalWidth;\n const naturalHeight = img.naturalHeight;\n\n // Calculate what the ORIGINAL fit-to-screen scale would be\n const scaleToFitWidth = containerWidth / naturalWidth;\n const scaleToFitHeight = containerHeight / naturalHeight;\n const fitScale = Math.min(scaleToFitWidth, scaleToFitHeight);\n\n // If image naturally fits or is smaller than container, can't zoom\n if (fitScale >= 0.95) {\n return {canZoom: false, levels: [], currentLevel: 0};\n }\n\n // Respect the configured ceiling (falls back to 3x only if misconfigured)\n const configuredMax = Number(this.options.maxZoomScale);\n const maxZoom = Number.isFinite(configuredMax) && configuredMax > 0\n ? Math.max(1, configuredMax)\n : 3;\n\n // Calculate zoom levels based on FIT scale (not current scale)\n const levels = [1]; // Start with fit-to-screen\n\n // Add progressive levels up to the configured max: 1.5x, 2x, 3x, 4x, 5x...\n [1.5, 2, 3, 4, 5].forEach((candidate) => {\n if (candidate <= maxZoom && fitScale * candidate <= 1) {\n levels.push(candidate);\n }\n });\n\n // Add actual size (100%) as final level, capped at the configured max\n const actualSizeScale = Math.min(1 / fitScale, maxZoom);\n if (actualSizeScale > levels[levels.length - 1]) {\n levels.push(actualSizeScale);\n }\n\n return {\n canZoom: levels.length > 1,\n levels: levels,\n currentLevel: 0,\n baseScale: fitScale,\n naturalWidth: naturalWidth,\n naturalHeight: naturalHeight\n };\n }\n\n /**\n * Update counter display\n */\n updateCounter() {\n if (this.options.showCounter && this.counter) {\n this.counter.textContent = `${this.currentIndex + 1} / ${this.items.length}`;\n }\n }\n\n /**\n * Update caption display\n */\n updateCaption() {\n if (!this.caption || !this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const caption = item.dataset.caption || item.title || '';\n\n if (caption) {\n this.caption.textContent = caption;\n this.caption.style.transform = 'translateX(-50%) translateY(0)';\n this.caption.style.opacity = '1';\n this.caption.style.pointerEvents = 'auto';\n this.caption.style.transition = 'opacity 0.3s ease, transform 0.3s ease';\n } else {\n this.caption.style.transform = 'translateX(-50%) translateY(100%)';\n this.caption.style.opacity = '0';\n this.caption.style.pointerEvents = 'none';\n this.caption.style.transition = 'opacity 0.3s ease, transform 0.3s ease';\n }\n }\n\n /**\n * Update thumbnails display\n */\n updateThumbnails() {\n if (!this.options.showThumbnails || !this.thumbs) return;\n\n if (this.items.length === 1) {\n this.caption.classList.add('single-item-thumbnail');\n this.thumbs.style.display = 'none';\n return;\n }\n\n this.caption.classList.remove('single-item-thumbnail');\n\n this.thumbs.style.display = 'flex';\n this.thumbs.innerHTML = '';\n\n this.items.forEach((item, index) => {\n const thumb = document.createElement('div');\n thumb.className = 'zoomora-thumb';\n if (index === this.currentIndex) thumb.classList.add('active');\n\n const img = document.createElement('img');\n const thumbSrc = this.getThumbnailSource(item);\n\n if (thumbSrc) {\n img.src = thumbSrc;\n img.alt = item.alt || item.title || '';\n img.onerror = () => {\n thumb.style.display = 'none';\n };\n }\n\n thumb.appendChild(img);\n\n thumb.addEventListener('click', () => {\n this.currentIndex = index;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n });\n\n this.thumbs.appendChild(thumb);\n });\n }\n\n /**\n * Update navigation buttons\n */\n updateNavigation() {\n const prevBtn = document.getElementById('zoomoraPrevBtn');\n const nextBtn = document.getElementById('zoomoraNextBtn');\n\n if (prevBtn) {\n prevBtn.style.display = this.currentIndex > 0 ? 'flex' : 'none';\n }\n if (nextBtn) {\n nextBtn.style.display = this.currentIndex < this.items.length - 1 ? 'flex' : 'none';\n }\n }\n\n /**\n * Update control buttons\n */\n updateButtons() {\n const fullscreenBtn = document.getElementById('zoomoraFullscreenBtn');\n const collapseBtn = document.getElementById('zoomoraCollapseBtn');\n\n if (fullscreenBtn && collapseBtn) {\n if (this.isFullscreen) {\n fullscreenBtn.style.display = 'none';\n collapseBtn.style.display = 'flex';\n } else {\n fullscreenBtn.style.display = 'flex';\n collapseBtn.style.display = 'none';\n }\n }\n }\n\n /**\n * Toggle zoom state\n */\n toggleZoom() {\n const media = this.content.querySelector('.zoomora-media');\n if (!media || media.tagName !== 'IMG') return;\n\n // Calculate zoom levels\n const zoomConfig = this.calculateZoomLevels(media);\n\n if (!zoomConfig.canZoom) {\n return;\n }\n\n // Get or initialize current zoom level\n if (!media.dataset.zoomLevel) {\n media.dataset.zoomLevel = '0';\n }\n\n let currentLevel = parseInt(media.dataset.zoomLevel) || 0;\n\n // Cycle to next level\n currentLevel++;\n if (currentLevel >= zoomConfig.levels.length) {\n // Reset to fit-to-screen\n currentLevel = 0;\n }\n\n const targetScale = zoomConfig.levels[currentLevel];\n media.dataset.zoomLevel = currentLevel.toString();\n\n if (currentLevel === 0) {\n // Back to fit-to-screen\n this.isZoomed = false;\n this.isDragging = false;\n media.classList.remove('dragging');\n media.style.transform = '';\n media.style.cursor = 'pointer';\n media.classList.remove('zoomed');\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n } else {\n // Zoom in - reset position to center\n this.isZoomed = true;\n this.currentScale = targetScale;\n this.currentX = 0; // Always reset to center on zoom change\n this.currentY = 0;\n\n media.style.transform = `translate(0px, 0px) scale(${targetScale})`;\n media.style.cursor = 'grab';\n media.classList.add('zoomed');\n }\n }\n\n /**\n * Toggle fullscreen mode\n */\n toggleFullscreen() {\n if (!this.isFullscreen) {\n this.enterFullscreen();\n } else {\n this.exitFullscreen();\n }\n }\n\n /**\n * Enter fullscreen mode\n */\n enterFullscreen() {\n const element = this.zoomora;\n\n try {\n // Try standard API first\n if (element.requestFullscreen) {\n element.requestFullscreen()\n .then(() => {\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n })\n .catch(err => {\n console.warn('Zoomora: Fullscreen request failed:', err.message);\n this.fallbackFullscreen();\n });\n }\n // Try webkit (Safari, older Chrome)\n else if (element.webkitRequestFullscreen) {\n element.webkitRequestFullscreen();\n // Webkit doesn't return a promise, so set state immediately\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n // Try moz (Firefox)\n else if (element.mozRequestFullScreen) {\n element.mozRequestFullScreen();\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n // Try ms (IE11)\n else if (element.msRequestFullscreen) {\n element.msRequestFullscreen();\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n // Fallback to CSS fullscreen\n else {\n console.warn('Zoomora: Fullscreen API not supported, using CSS fallback');\n this.fallbackFullscreen();\n }\n } catch (error) {\n console.error('Zoomora: Error entering fullscreen:', error);\n this.fallbackFullscreen();\n }\n }\n\n /**\n * Exit fullscreen mode\n */\n exitFullscreen() {\n // First check if we're actually in fullscreen\n const isInFullscreen = !!(\n document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement\n );\n\n if (!isInFullscreen) {\n // Not in real fullscreen, just exit CSS fullscreen\n this.fallbackExitFullscreen();\n return;\n }\n\n try {\n // Try standard API first\n if (document.exitFullscreen) {\n document.exitFullscreen()\n .then(() => {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n })\n .catch(err => {\n console.warn('Zoomora: Exit fullscreen failed:', err.message);\n this.fallbackExitFullscreen();\n });\n }\n // Try webkit\n else if (document.webkitExitFullscreen) {\n document.webkitExitFullscreen();\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n // Try moz\n else if (document.mozCancelFullScreen) {\n document.mozCancelFullScreen();\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n // Try ms\n else if (document.msExitFullscreen) {\n document.msExitFullscreen();\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n // Fallback\n else {\n this.fallbackExitFullscreen();\n }\n } catch (error) {\n console.error('Zoomora: Error exiting fullscreen:', error);\n this.fallbackExitFullscreen();\n }\n }\n\n /**\n * Fallback fullscreen using CSS\n */\n fallbackFullscreen() {\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n\n /**\n * Exit CSS fullscreen\n */\n fallbackExitFullscreen() {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n\n /**\n * Toggle thumbnails visibility\n */\n toggleThumbnails() {\n if (this.items.length === 1) return;\n\n this.thumbnailsVisible = !this.thumbnailsVisible;\n if (this.thumbs) {\n this.thumbs.classList.toggle('thumbs-hidden', !this.thumbnailsVisible);\n\n if (!this.caption || !this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const caption = item.dataset.caption || item.title || '';\n\n if (caption && this.thumbs.classList.contains('thumbs-hidden')) {\n this.caption.style.bottom = '20px';\n this.caption.style.transition = 'bottom 0.3s ease, transform 0.3s ease';\n } else {\n this.caption.style.bottom = '120px';\n }\n }\n }\n\n /**\n * Start drag operation\n * @param {Event} e - Mouse or touch event\n */\n startDrag(e) {\n const media = this.content.querySelector('.zoomora-media');\n if (!media || !this.isZoomed) return;\n\n this.isDragging = true;\n media.classList.add('dragging');\n media.style.cursor = 'grabbing';\n\n this.startX = e.clientX || (e.touches && e.touches[0].clientX) || 0;\n this.startY = e.clientY || (e.touches && e.touches[0].clientY) || 0;\n\n // Read current position from transform\n const transform = window.getComputedStyle(media).transform;\n if (transform && transform !== 'none') {\n const matrix = new DOMMatrix(transform);\n this.currentX = matrix.m41;\n this.currentY = matrix.m42;\n } else {\n this.currentX = 0;\n this.currentY = 0;\n }\n\n e.preventDefault();\n }\n\n /**\n * Handle drag movement\n * @param {Event} e - Mouse or touch event\n */\n drag(e) {\n if (!this.isDragging) return;\n e.preventDefault();\n\n const media = this.content.querySelector('.zoomora-media');\n if (!media) return;\n\n const clientX = e.clientX || (e.touches && e.touches[0].clientX) || 0;\n const clientY = e.clientY || (e.touches && e.touches[0].clientY) || 0;\n\n const deltaX = clientX - this.startX;\n const deltaY = clientY - this.startY;\n\n let newX = this.currentX + deltaX;\n let newY = this.currentY + deltaY;\n\n // Calculate boundaries for BOTH width AND height\n const container = this.content.getBoundingClientRect();\n const mediaRect = media.getBoundingClientRect();\n\n // How much the scaled image overflows the container\n const overflowX = Math.max(0, (mediaRect.width - container.width) / 2);\n const overflowY = Math.max(0, (mediaRect.height - container.height) / 2);\n\n // Constrain drag to overflow boundaries\n if (overflowX > 0) {\n newX = Math.max(-overflowX, Math.min(overflowX, newX));\n } else {\n newX = 0; // Center horizontally if no overflow\n }\n\n if (overflowY > 0) {\n newY = Math.max(-overflowY, Math.min(overflowY, newY));\n } else {\n newY = 0; // Center vertically if no overflow\n }\n\n // Apply transform\n media.style.transform = `translate(${newX}px, ${newY}px) scale(${this.currentScale})`;\n\n // Update for next frame\n this.startX = clientX;\n this.startY = clientY;\n this.currentX = newX;\n this.currentY = newY;\n }\n\n /**\n * End drag operation\n */\n endDrag() {\n if (!this.isDragging) return;\n\n this.isDragging = false;\n this.lastDragTime = Date.now();\n\n const media = this.content.querySelector('.zoomora-media');\n if (media) {\n media.classList.remove('dragging');\n if (this.isZoomed) {\n media.style.cursor = 'grab';\n }\n }\n }\n\n /**\n * Go to specific item by index\n * @param {number} index - Item index\n */\n goTo(index) {\n if (index < 0 || index >= this.items.length) return;\n\n this.currentIndex = index;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n }\n\n /**\n * Get current item index\n * @returns {number} - Current index\n */\n getCurrentIndex() {\n return this.currentIndex;\n }\n\n /**\n * Get total number of items\n * @returns {number} - Total items\n */\n getTotalItems() {\n return this.items.length;\n }\n\n /**\n * Check if lightbox is open\n * @returns {boolean} - True if open\n */\n isOpen() {\n return this.zoomora && this.zoomora.classList.contains('active');\n }\n\n /**\n * Update options\n * @param {Object} newOptions - New options to merge\n */\n updateOptions(newOptions) {\n this.options = {...this.options, ...newOptions};\n }\n\n /**\n * Refresh the lightbox (re-scan for items)\n */\n refresh() {\n if (this.isOpen()) {\n const currentItem = this.items[this.currentIndex];\n if (currentItem) {\n this.open(currentItem);\n }\n }\n }\n\n /**\n * Destroy the lightbox instance\n */\n destroy() {\n if (!this.isInitialized) return;\n\n // Close if open\n if (this.isOpen()) {\n this.close();\n }\n\n // Clean up auto-hide\n this.stopAutoHideTimer();\n\n // Remove all event listeners\n this.eventListeners.forEach((listeners, _key) => {\n listeners.forEach(({element, event, handler, options}) => {\n if (element && element.removeEventListener) {\n element.removeEventListener(event, handler, options);\n }\n });\n });\n this.eventListeners.clear();\n\n // Remove DOM elements\n if (this.zoomora && this.zoomora.parentNode) {\n this.zoomora.parentNode.removeChild(this.zoomora);\n }\n\n // Reset properties\n this.isInitialized = false;\n this.items = [];\n this.currentIndex = 0;\n this.zoomora = null;\n this.content = null;\n this.counter = null;\n this.thumbs = null;\n this.loading = null;\n this.caption = null;\n }\n }\n\n // Export the class\n return Zoomora;\n}));"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"zoomora.umd.js","names":[],"sources":["../src/zoomora.js"],"sourcesContent":["/*!\n * Zoomora Lightbox Plugin v1.4.0\n * A modern, responsive lightbox plugin with zoom, fullscreen, and gallery features\n *\n * Copyright (c) 2026 Faruk Ahmed (FrontTheme)\n * Licensed under MIT License\n */\n\n// Import styles\nimport './styles/zoomora.scss';\n\n/**\n * Zoomora Lightbox Plugin\n * @class\n */\nclass Zoomora {\n /**\n * Default configuration options\n * @type {Object}\n */\n static get defaults() {\n return {\n selector: '[data-zoomora]',\n showCounter: true,\n showThumbnails: true,\n showFullscreen: true,\n showZoom: true,\n transition: 'fade', // 'fade' or 'slide'\n useHref: false, // Use href instead of data-src\n maxZoomScale: 3, // Maximum zoom scale\n zoomStep: 0.1, // Zoom step for scroll wheel\n animationDuration: 300, // Animation duration in ms\n closeOnBackgroundClick: true, // Close lightbox when clicking on background\n autoplayVideos: false, // Start YouTube and local videos when their slide opens\n onOpen: null, // Callback when lightbox opens\n onClose: null, // Callback when lightbox closes\n onNext: null, // Callback when navigating to next item\n onPrev: null, // Callback when navigating to previous item\n\n // Auto-hide controls\n showAutoHideToggle: true, // Show auto-hide toggle button\n autoHideDelay: 3000, // Delay in ms before hiding controls\n autoHideEnabled: false, // Default state of auto-hide\n };\n }\n\n /**\n * Constructor\n * @param {Object} options - Configuration options\n */\n constructor(options = {}) {\n this.options = {...Zoomora.defaults, ...options};\n this.currentIndex = 0;\n this.items = [];\n this.isZoomed = false;\n this.isFullscreen = false;\n this.isDragging = false;\n this.thumbnailsVisible = true;\n this.startX = 0;\n this.startY = 0;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n this.isInitialized = false;\n this.eventListeners = new Map();\n\n // Auto-hide controls\n this.autoHideEnabled = false;\n this.autoHideTimeout = null;\n this.autoHideDelay = 3000;\n this.isControlsVisible = true;\n\n this.lastDragTime = 0;\n this.boundMethods = {\n handleDocumentClick: this.handleDocumentClick.bind(this),\n handleKeydown: this.handleKeydown.bind(this),\n handleFullscreenChange: this.handleFullscreenChange.bind(this),\n handleZoomoraClick: this.handleZoomoraClick.bind(this),\n handleContentClick: this.handleContentClick.bind(this),\n handleMouseDown: this.handleMouseDown.bind(this),\n handleMouseMove: this.handleMouseMove.bind(this),\n handleMouseUp: this.handleMouseUp.bind(this),\n handleTouchStart: this.handleTouchStart.bind(this),\n handleTouchMove: this.handleTouchMove.bind(this),\n handleTouchEnd: this.handleTouchEnd.bind(this),\n handleWheel: this.handleWheel.bind(this),\n };\n\n this.init();\n }\n\n /**\n * Initialize the plugin\n */\n init() {\n if (this.isInitialized) {\n console.warn('Zoomora: Plugin already initialized');\n return;\n }\n\n try {\n this.createLightbox();\n this.bindEvents();\n\n this.isInitialized = true;\n } catch (error) {\n console.error('Zoomora: Initialization failed', error);\n }\n }\n\n /**\n * Static method to bind to anchor tags with href\n * @param {string} selector - CSS selector\n * @param {Object} options - Configuration options\n * @returns {Zoomora} - New Zoomora instance\n */\n static bind(selector, options = {}) {\n const enhancedOptions = {\n ...options,\n selector: selector,\n useHref: true\n };\n return new Zoomora(enhancedOptions);\n }\n\n /**\n * Create lightbox HTML structure\n */\n createLightbox() {\n // Check if lightbox already exists\n if (document.getElementById('zoomoraLightbox')) {\n console.warn('Zoomora: Lightbox already exists in DOM');\n return;\n }\n\n // Build auto-hide button conditionally\n const autoHideButtonHTML = this.options.showAutoHideToggle ? `\n <button class=\"zoomora-btn\" id=\"zoomoraAutoHideBtn\" title=\"Toggle Auto-Hide Controls\">\n <i class=\"zoomorai-controls-off\"></i>\n </button>\n ` : '';\n\n const zoomoraHTML = `\n <div class=\"zoomora\" id=\"zoomoraLightbox\">\n <div class=\"zoomora-container\">\n <div class=\"zoomora-header\" id=\"zoomoraHeader\">\n <div class=\"zoomora-counter\" id=\"zoomoraCounter\" ${!this.options.showCounter ? 'style=\"opacity:0;visibility:hidden;\"' : ''}>1 / 1</div>\n <div class=\"zoomora-controls\">\n ${this.options.showThumbnails ? `\n <button class=\"zoomora-btn\" id=\"zoomoraThumbnailBtn\" title=\"Toggle Thumbnails\">\n <i class=\"zoomorai-thumbnails\"></i>\n </button>\n ` : ''}\n ${autoHideButtonHTML}\n ${this.options.showZoom ? `\n <button class=\"zoomora-btn\" id=\"zoomoraZoomBtn\" title=\"Zoom\">\n <i class=\"zoomorai-zoom\"></i>\n </button>\n ` : ''}\n ${this.options.showFullscreen ? `\n <button class=\"zoomora-btn\" id=\"zoomoraFullscreenBtn\" title=\"Fullscreen\">\n <i class=\"zoomorai-expand\"></i>\n </button>\n <button class=\"zoomora-btn\" id=\"zoomoraCollapseBtn\" title=\"Exit Fullscreen\" style=\"display: none;\">\n <i class=\"zoomorai-collapse\"></i>\n </button>\n ` : ''}\n <button class=\"zoomora-btn\" id=\"zoomoraCloseBtn\" title=\"Close\">\n <i class=\"zoomorai-close\"></i>\n </button>\n </div>\n </div>\n \n <div class=\"zoomora-content\" id=\"zoomoraContent\">\n <div class=\"zoomora-loading\" id=\"zoomoraLoading\"></div>\n <div class=\"zoomora-slides-container\" id=\"zoomoraSlidesContainer\"></div>\n </div>\n \n <button class=\"zoomora-nav prev\" id=\"zoomoraPrevBtn\">\n <i class=\"zoomorai-arrow-left\"></i>\n </button>\n <button class=\"zoomora-nav next\" id=\"zoomoraNextBtn\">\n <i class=\"zoomorai-arrow-right\"></i>\n </button>\n \n <div class=\"zoomora-caption\" id=\"zoomoraCaption\" ${!this.options.showThumbnails ? 'style=\"bottom:20px;\"' : ''}></div>\n <div class=\"zoomora-thumbnails\" id=\"zoomoraThumbs\" ${!this.options.showThumbnails ? 'style=\"display:none;\"' : ''}></div>\n </div>\n </div>\n `;\n\n document.body.insertAdjacentHTML('beforeend', zoomoraHTML);\n\n // Cache DOM elements\n this.zoomora = document.getElementById('zoomoraLightbox');\n this.header = document.getElementById('zoomoraHeader');\n this.content = document.getElementById('zoomoraContent');\n this.slidesContainer = document.getElementById('zoomoraSlidesContainer');\n this.counter = document.getElementById('zoomoraCounter');\n this.thumbs = document.getElementById('zoomoraThumbs');\n this.loading = document.getElementById('zoomoraLoading');\n this.caption = document.getElementById('zoomoraCaption');\n this.prevBtn = document.getElementById('zoomoraPrevBtn');\n this.nextBtn = document.getElementById('zoomoraNextBtn');\n\n // Verify all elements were created\n if (!this.zoomora || !this.content || !this.counter || !this.thumbs || !this.loading || !this.caption) {\n throw new Error('Failed to create required DOM elements');\n }\n }\n\n /**\n * Bind event listeners\n */\n bindEvents() {\n // Document click handler for opening lightbox\n this.addEventListener(document, 'click', this.boundMethods.handleDocumentClick);\n\n // Control button handlers\n this.addEventListener(document.getElementById('zoomoraCloseBtn'), 'click', () => this.close());\n this.addEventListener(document.getElementById('zoomoraPrevBtn'), 'click', () => this.prev());\n this.addEventListener(document.getElementById('zoomoraNextBtn'), 'click', () => this.next());\n if (this.options.showZoom) {\n this.addEventListener(document.getElementById('zoomoraZoomBtn'), 'click', () => this.toggleZoom());\n }\n if (this.options.showFullscreen) {\n this.addEventListener(document.getElementById('zoomoraFullscreenBtn'), 'click', () => this.toggleFullscreen());\n this.addEventListener(document.getElementById('zoomoraCollapseBtn'), 'click', () => this.exitFullscreen());\n }\n if (this.options.showThumbnails) {\n this.addEventListener(document.getElementById('zoomoraThumbnailBtn'), 'click', () => this.toggleThumbnails());\n }\n\n // Fullscreen change events\n this.addEventListener(document, 'fullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'webkitfullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'mozfullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'MSFullscreenChange', this.boundMethods.handleFullscreenChange);\n\n // Keyboard navigation\n this.addEventListener(document, 'keydown', this.boundMethods.handleKeydown);\n\n // Lightbox click to close\n this.addEventListener(this.zoomora, 'click', this.boundMethods.handleZoomoraClick);\n\n // Content click for zoom toggle and background click\n this.addEventListener(this.content, 'click', this.boundMethods.handleContentClick);\n\n // Mouse drag events\n this.addEventListener(this.content, 'mousedown', this.boundMethods.handleMouseDown);\n this.addEventListener(this.content, 'mousemove', this.boundMethods.handleMouseMove);\n this.addEventListener(this.content, 'mouseup', this.boundMethods.handleMouseUp);\n this.addEventListener(this.content, 'mouseleave', this.boundMethods.handleMouseUp);\n\n // Touch events\n this.addEventListener(this.content, 'touchstart', this.boundMethods.handleTouchStart, {passive: false});\n this.addEventListener(this.content, 'touchmove', this.boundMethods.handleTouchMove, {passive: false});\n this.addEventListener(this.content, 'touchend', this.boundMethods.handleTouchEnd);\n\n // Scroll-wheel zoom\n if (this.options.showZoom) {\n this.addEventListener(this.content, 'wheel', this.boundMethods.handleWheel, {passive: false});\n }\n\n // Add auto-hide toggle button handler (only if enabled)\n if (this.options.showAutoHideToggle) {\n this.addEventListener(document.getElementById('zoomoraAutoHideBtn'), 'click', () => this.toggleAutoHide());\n\n // Add mouse/touch activity listeners for auto-hide\n this.addEventListener(this.zoomora, 'mousemove', () => this.handleUserActivity());\n this.addEventListener(this.zoomora, 'touchstart', () => this.handleUserActivity());\n this.addEventListener(this.zoomora, 'keydown', () => this.handleUserActivity());\n }\n }\n\n /**\n * Add event listener with cleanup tracking\n * @param {EventTarget} element - DOM element or document\n * @param {string} event - Event type\n * @param {Function} handler - Event handler\n * @param {Object} options - Event options\n */\n addEventListener(element, event, handler, options = {}) {\n if (!element) return;\n\n element.addEventListener(event, handler, options);\n\n // Track for cleanup\n const key = `${element.constructor.name}_${event}`;\n if (!this.eventListeners.has(key)) {\n this.eventListeners.set(key, []);\n }\n this.eventListeners.get(key).push({element, event, handler, options});\n }\n\n /**\n * Handle document click events\n * @param {Event} e - Click event\n */\n handleDocumentClick(e) {\n const target = e.target.closest(this.options.selector);\n if (target) {\n e.preventDefault();\n this.open(target);\n }\n }\n\n /**\n * Handle keyboard events\n * @param {KeyboardEvent} e - Keyboard event\n */\n handleKeydown(e) {\n if (!this.zoomora.classList.contains('active')) {\n this.handleTriggerKeydown(e);\n return;\n }\n\n switch (e.key) {\n case 'Escape':\n if (this.isFullscreen) {\n this.exitFullscreen();\n } else {\n this.close();\n }\n break;\n case 'ArrowLeft':\n this.prev();\n break;\n case 'ArrowRight':\n this.next();\n break;\n case 'z':\n case 'Z':\n this.toggleZoom();\n break;\n case 'f':\n case 'F':\n this.toggleFullscreen();\n break;\n case 't':\n case 'T':\n this.toggleThumbnails();\n break;\n }\n }\n\n /**\n * Open the lightbox with Enter or Space on a focused trigger\n * @param {KeyboardEvent} e - Keyboard event\n */\n handleTriggerKeydown(e) {\n if (e.key !== 'Enter' && e.key !== ' ') return;\n\n const trigger = e.target.closest(this.options.selector);\n if (!trigger) return;\n\n e.preventDefault();\n this.open(trigger);\n }\n\n /**\n * Handle fullscreen change events\n */\n handleFullscreenChange() {\n const isInFullscreen = !!(\n document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement\n );\n\n // Only update if state changed from fullscreen to not fullscreen\n if (!isInFullscreen && this.isFullscreen) {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n // Update if entering fullscreen\n else if (isInFullscreen && !this.isFullscreen) {\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n }\n\n /**\n * Handle zoomora container clicks\n * @param {Event} e - Click event\n */\n handleZoomoraClick(e) {\n if (e.target === this.zoomora && this.options.closeOnBackgroundClick) {\n this.close();\n }\n }\n\n /**\n * Handle content clicks\n * @param {Event} e - Click event\n */\n handleContentClick(e) {\n // Ignore click if we just finished dragging (within 200ms)\n if (Date.now() - this.lastDragTime < 200) {\n return;\n }\n\n // Don't close on header clicks\n if (this.header && this.header.contains(e.target)) {\n return;\n }\n\n // Don't close on button clicks\n if (e.target.closest('button')) {\n return;\n }\n\n // Check if click is directly on actual media element (img, video, iframe)\n const mediaElement = e.target.closest('.zoomora-media, .zoomora-video, .zoomora-iframe');\n\n if (mediaElement) {\n // Only toggle zoom for images\n if (mediaElement.classList.contains('zoomora-media') && !mediaElement.classList.contains('no-zoom')) {\n this.toggleZoom();\n }\n return;\n }\n\n // Check if clicking inside video container but not on video itself\n const videoContainer = e.target.closest('.zoomora-video-container');\n if (videoContainer) {\n // If clicking on the play button, don't close\n if (e.target.closest('.zoomora-play-button')) {\n return;\n }\n // If clicking on background area of video container, close\n if (this.options.closeOnBackgroundClick) {\n this.close();\n }\n return;\n }\n\n // Check if clicking on background elements (including when zoomed)\n // This checks the actual target element, not just closest()\n const clickedElement = e.target;\n const isBackgroundElement =\n clickedElement.classList.contains('zoomora-content') ||\n clickedElement.classList.contains('zoomora-slide-container') ||\n clickedElement.classList.contains('zoomora-slide') ||\n clickedElement.classList.contains('zoomora-slides-container') ||\n clickedElement.id === 'zoomoraContent' ||\n clickedElement.id === 'zoomoraSlidesContainer';\n\n if (isBackgroundElement && this.options.closeOnBackgroundClick) {\n this.close();\n return;\n }\n\n // If we reach here and no media was clicked, close\n if (this.options.closeOnBackgroundClick) {\n this.close();\n }\n }\n\n /**\n * Handle mouse down events\n * @param {MouseEvent} e - Mouse event\n */\n handleMouseDown(e) {\n this.startDrag(e);\n }\n\n /**\n * Handle mouse move events\n * @param {MouseEvent} e - Mouse event\n */\n handleMouseMove(e) {\n this.drag(e);\n }\n\n /**\n * Handle mouse up events\n */\n handleMouseUp() {\n this.endDrag();\n }\n\n /**\n * Handle touch start events\n * @param {TouchEvent} e - Touch event\n */\n handleTouchStart(e) {\n this.startDrag(e);\n }\n\n /**\n * Handle touch move events\n * @param {TouchEvent} e - Touch event\n */\n handleTouchMove(e) {\n this.drag(e);\n }\n\n /**\n * Handle touch end events\n */\n handleTouchEnd() {\n this.endDrag();\n }\n\n /**\n * Handle scroll-wheel zoom\n * @param {WheelEvent} e - Wheel event\n */\n handleWheel(e) {\n const media = this.content.querySelector('.zoomora-media');\n if (!media || media.tagName !== 'IMG') return;\n\n const zoomConfig = this.calculateZoomLevels(media);\n if (!zoomConfig.canZoom) return;\n\n e.preventDefault();\n\n const maxScale = zoomConfig.levels[zoomConfig.levels.length - 1];\n const step = this.options.zoomStep || 0.1;\n const direction = e.deltaY < 0 ? 1 : -1; // scroll/pinch up = zoom in\n\n let newScale = (this.currentScale || 1) + (direction * step * maxScale);\n newScale = Math.max(1, Math.min(maxScale, newScale));\n\n if (newScale === this.currentScale) return;\n\n this.currentScale = newScale;\n this.isZoomed = newScale > 1;\n this.currentX = 0;\n this.currentY = 0;\n\n if (this.isZoomed) {\n media.style.transform = `scale(${newScale})`;\n media.style.cursor = 'grab';\n media.classList.add('zoomed');\n } else {\n media.style.transform = '';\n media.style.cursor = 'pointer';\n media.classList.remove('zoomed');\n }\n\n // Keep the click-to-cycle zoom index roughly in sync with the\n // continuous wheel scale, so a click after scrolling cycles sensibly.\n let nearestIndex = 0;\n zoomConfig.levels.forEach((level, index) => {\n if (Math.abs(level - newScale) < Math.abs(zoomConfig.levels[nearestIndex] - newScale)) {\n nearestIndex = index;\n }\n });\n media.dataset.zoomLevel = nearestIndex.toString();\n }\n\n /**\n * Get image source from element\n * @param {Element} item - DOM element\n * @returns {string} - Image source URL\n */\n getImageSource(item) {\n const src = item.dataset.src || item.getAttribute('href') || item.src || item.getAttribute('src');\n const type = item.dataset.type || 'image';\n\n // Handle YouTube URLs for video types\n if (type === 'video' && src) {\n return this.convertToEmbedUrl(src);\n }\n\n return src;\n }\n\n /**\n * Convert YouTube URLs to embed format\n * @param url\n * @returns {*|string}\n */\n convertToEmbedUrl(url) {\n // If already an embed URL, return as is\n if (url.includes('youtube.com/embed/')) {\n return url;\n }\n\n // Handle different YouTube URL formats\n let videoId = null;\n let startTime = null;\n\n // Extract video ID and start time from different YouTube URL formats\n if (url.includes('youtube.com/watch')) {\n const urlParams = new URLSearchParams(url.split('?')[1]);\n videoId = urlParams.get('v');\n const t = urlParams.get('t');\n if (t) {\n // Convert time format (e.g., \"111s\" to seconds)\n startTime = t.replace('s', '');\n }\n } else if (url.includes('youtu.be/')) {\n const parts = url.split('/');\n const videoAndParams = parts[parts.length - 1];\n if (videoAndParams.includes('?')) {\n videoId = videoAndParams.split('?')[0];\n const urlParams = new URLSearchParams(videoAndParams.split('?')[1]);\n const t = urlParams.get('t');\n if (t) startTime = t.replace('s', '');\n } else {\n videoId = videoAndParams;\n }\n }\n\n if (videoId) {\n let embedUrl = `https://www.youtube.com/embed/${videoId}`;\n const params = new URLSearchParams();\n\n if (startTime) {\n params.append('start', startTime);\n }\n\n // Add other useful parameters\n params.append('rel', '0'); // Don't show related videos\n params.append('modestbranding', '1'); // Modest branding\n\n if (this.options.autoplayVideos) {\n params.append('autoplay', '1');\n }\n\n if (params.toString()) {\n embedUrl += '?' + params.toString();\n }\n\n return embedUrl;\n }\n\n // If not a YouTube URL or couldn't parse, return original\n return url;\n }\n\n /**\n * Get thumbnail source from element\n * Order: data-thumbnail, the trigger's own image or the image inside it, then data-src or href.\n * @param {Element|Object} item - DOM element or virtual item\n * @returns {string} - Thumbnail source URL\n */\n getThumbnailSource(item) {\n if (item.dataset.thumbnail) {\n return item.dataset.thumbnail;\n }\n\n const innerImage = item.querySelector?.('img');\n const imageSrc = item.getAttribute('src') || innerImage?.getAttribute('src');\n const type = item.dataset.type || 'image';\n\n if (type === 'video') {\n return imageSrc;\n }\n\n return imageSrc || item.dataset.src || item.getAttribute('href');\n }\n\n /**\n * Get group identifier from element\n * @param {Element} element - DOM element\n * @returns {string} - Group identifier\n */\n getGroup(element) {\n if (this.options.useHref) {\n return element.dataset.lightbox || element.dataset.gallery || 'default';\n }\n return element.dataset.zoomora || 'default';\n }\n\n /**\n * Open lightbox with specified element\n * @param {Element} element - DOM element to open\n */\n open(element) {\n if (!element) return;\n\n const group = this.getGroup(element);\n let groupSelector;\n\n if (this.options.useHref) {\n if (element.dataset.lightbox) {\n groupSelector = `[data-lightbox=\"${group}\"]`;\n } else if (element.dataset.gallery) {\n groupSelector = `[data-gallery=\"${group}\"]`;\n } else {\n groupSelector = this.options.selector;\n }\n } else {\n groupSelector = `[data-zoomora=\"${group}\"]`;\n }\n\n this.items = Array.from(document.querySelectorAll(groupSelector));\n this.currentIndex = Math.max(0, this.items.indexOf(element));\n\n this._activateLightbox();\n\n // Trigger callback\n if (typeof this.options.onOpen === 'function') {\n this.options.onOpen(element, this.currentIndex);\n }\n }\n\n /**\n * Open lightbox programmatically with image(s) not present in the DOM.\n * Accepts a single URL, an array of URLs, a config object, or an array\n * of config objects — so all of these work:\n *\n * lightbox.openImage('photo.jpg');\n * lightbox.openImage(['a.jpg', 'b.jpg'], { startIndex: 1 });\n * lightbox.openImage({ src: 'photo.jpg', caption: 'Hello' });\n * lightbox.openImage([\n * { src: 'a.jpg', caption: 'First' },\n * { src: 'https://youtu.be/xyz', type: 'video', thumb: 'poster.jpg' },\n * ]);\n *\n * @param {string|string[]|Object|Object[]} images - URL(s) or config object(s)\n * @param {Object} [opts] - Options\n * @param {number} [opts.startIndex=0] - Index to open at when passing an array\n */\n openImage(images, opts = {}) {\n const list = Array.isArray(images) ? images : [images];\n\n this.items = list.map(entry =>\n this.createVirtualItem(typeof entry === 'string' ? {src: entry} : entry)\n );\n\n this.currentIndex = Math.max(\n 0,\n Math.min(opts.startIndex || 0, this.items.length - 1)\n );\n\n this._activateLightbox();\n\n // Trigger callback\n if (typeof this.options.onOpen === 'function') {\n this.options.onOpen(this.items[this.currentIndex], this.currentIndex);\n }\n }\n\n /**\n * Create a virtual item that mimics a DOM element's interface so\n * programmatic images work through the existing render pipeline without\n * any changes to getImageSource, getThumbnailSource, updateCaption, etc.\n * @param {Object} config\n * @param {string} config.src - Full-size image/video/iframe URL\n * @param {string} [config.thumb] - Thumbnail URL (falls back to src)\n * @param {string} [config.type='image'] - 'image', 'video', or 'iframe'\n * @param {string} [config.caption=''] - Caption text\n * @param {string} [config.alt=''] - Alt text for the thumbnail img\n * @returns {Object} Virtual item\n */\n createVirtualItem({src, thumb, type = 'image', caption = '', alt = ''}) {\n const thumbSrc = thumb || src;\n return {\n dataset: {src, type, caption},\n src: thumbSrc,\n alt,\n title: caption,\n getAttribute: (name) => name === 'src' ? thumbSrc : null,\n };\n }\n\n /**\n * Shared activation sequence used by both open() and openImage().\n * Resets state, shows the lightbox, and triggers all UI updates.\n */\n _activateLightbox() {\n // Reset states\n this.isZoomed = false;\n this.isFullscreen = false;\n this.thumbnailsVisible = true;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n this.zoomora.classList.add('active');\n document.body.style.overflow = 'hidden';\n\n this.loadContent();\n this.updateThumbnails();\n this.updateCounter();\n this.updateNavigation();\n this.updateCaption();\n this.updateButtons();\n\n // Initialize auto-hide\n if (this.autoHideEnabled) {\n this.startAutoHideTimer();\n } else {\n this.showControls();\n }\n }\n\n /**\n * Close lightbox\n */\n close() {\n if (this.isFullscreen) {\n this.exitFullscreen();\n }\n\n this.zoomora.classList.remove('active');\n document.body.style.overflow = '';\n\n // Stop playing media; the next open builds fresh media elements\n const activeVideo = this.content.querySelector('video');\n if (activeVideo) {\n activeVideo.pause();\n }\n\n const activeIframe = this.content.querySelector('iframe');\n if (activeIframe) {\n activeIframe.src = 'about:blank';\n }\n\n this.isZoomed = false;\n this.isFullscreen = false;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n const media = this.content.querySelector('.zoomora-media');\n if (media) {\n media.classList.remove('zoomed');\n media.style.transform = '';\n media.style.cursor = '';\n }\n\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n\n // Clean up auto-hide\n this.stopAutoHideTimer();\n this.showControls();\n\n // Trigger callback\n if (typeof this.options.onClose === 'function') {\n this.options.onClose(this.currentIndex);\n }\n }\n\n /**\n * Navigate to previous item\n */\n prev() {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n\n // Trigger callback\n if (typeof this.options.onPrev === 'function') {\n this.options.onPrev(this.currentIndex);\n }\n }\n }\n\n /**\n * Navigate to next item\n */\n next() {\n if (this.currentIndex < this.items.length - 1) {\n this.currentIndex++;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n\n // Trigger callback\n if (typeof this.options.onNext === 'function') {\n this.options.onNext(this.currentIndex);\n }\n }\n }\n\n /**\n * Load content for current item\n */\n loadContent() {\n if (!this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const src = this.getImageSource(item);\n const type = item.dataset.type || 'image';\n\n if (!src) {\n console.error('Zoomora: No source found for item');\n return;\n }\n\n // Reset zoom state\n this.isZoomed = false;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n // Show loading spinner\n this.loading.style.display = 'block';\n\n if (this.slidesContainer) {\n this.slidesContainer.innerHTML = '';\n }\n\n setTimeout(() => {\n this.renderContent(src, type, item);\n }, 100);\n }\n\n /**\n * Render content based on type\n * @param {string} src - Source URL\n * @param {string} type - Content type\n * @param {Element} item - Original item element\n */\n renderContent(src, type, item) {\n const slideContainer = document.createElement('div');\n slideContainer.className = 'zoomora-slide-container';\n\n // Create slide wrapper\n const slide = document.createElement('div');\n slide.className = `zoomora-slide ${this.options.transition === 'slide' ? 'slide-effect' : 'fade-effect'}`;\n slide.style.opacity = '0';\n slide.style.transform = this.options.transition === 'slide' ? 'translateX(100%)' : 'scale(0.8)';\n\n let mediaElement;\n\n try {\n switch (type) {\n case 'video':\n if (src.endsWith('.mp4') || src.endsWith('.webm') || src.endsWith('.ogg')) {\n const videoContainer = document.createElement('div');\n videoContainer.className = 'zoomora-video-container';\n\n mediaElement = document.createElement('video');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-video';\n mediaElement.setAttribute('preload', 'metadata');\n\n const posterSrc = item.src || item.getAttribute('src');\n if (posterSrc) {\n mediaElement.setAttribute('poster', posterSrc);\n }\n\n const playButton = document.createElement('div');\n playButton.className = 'zoomora-play-button';\n playButton.innerHTML = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"/></svg>`;\n\n playButton.addEventListener('click', () => {\n mediaElement.play();\n playButton.style.display = 'none';\n mediaElement.setAttribute('controls', '');\n });\n\n mediaElement.addEventListener('ended', () => {\n playButton.style.display = 'flex';\n });\n\n videoContainer.appendChild(mediaElement);\n videoContainer.appendChild(playButton);\n if (this.options.autoplayVideos) {\n mediaElement.play()\n .then(() => {\n playButton.style.display = 'none';\n mediaElement.setAttribute('controls', '');\n })\n .catch(() => {\n // Autoplay blocked by the browser: the play button stays visible\n });\n }\n slideContainer.appendChild(videoContainer);\n } else {\n mediaElement = document.createElement('iframe');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-video';\n mediaElement.setAttribute('allowfullscreen', '');\n mediaElement.setAttribute('allow', 'autoplay; fullscreen; picture-in-picture');\n mediaElement.setAttribute('frameborder', '0');\n slideContainer.appendChild(mediaElement);\n }\n break;\n\n case 'iframe':\n mediaElement = document.createElement('iframe');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-iframe';\n mediaElement.setAttribute('frameborder', '0');\n slideContainer.appendChild(mediaElement);\n break;\n\n default:\n mediaElement = document.createElement('img');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-media';\n mediaElement.alt = item.alt || item.title || '';\n\n mediaElement.onload = () => {\n this.loading.style.display = 'none';\n this.checkZoomability(mediaElement);\n this.animateSlideIn(slide);\n };\n\n mediaElement.onerror = () => {\n this.loading.style.display = 'none';\n console.error('Zoomora: Failed to load image:', src);\n this.animateSlideIn(slide);\n };\n\n slideContainer.appendChild(mediaElement);\n }\n\n slide.appendChild(slideContainer);\n\n // Clear existing slides and add new one\n this.slidesContainer.innerHTML = '';\n this.slidesContainer.appendChild(slide);\n\n if (type !== 'image') {\n this.loading.style.display = 'none';\n this.animateSlideIn(slide);\n }\n\n } catch (error) {\n console.error('Zoomora: Error rendering content:', error);\n this.loading.style.display = 'none';\n }\n }\n\n // Animation helper\n animateSlideIn(slide) {\n // Force reflow\n slide.offsetHeight;\n\n // Add active class and animate\n slide.classList.add('active');\n\n if (this.options.transition === 'slide') {\n slide.style.transition = `transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`;\n slide.style.transform = 'translateX(0)';\n slide.style.opacity = '1';\n } else {\n slide.style.transition = `transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`;\n slide.style.transform = 'scale(1)';\n slide.style.opacity = '1';\n }\n }\n\n // Toggle auto-hide controls\n toggleAutoHide() {\n this.autoHideEnabled = !this.autoHideEnabled;\n const autoHideBtn = document.getElementById('zoomoraAutoHideBtn');\n\n if (this.autoHideEnabled) {\n autoHideBtn.classList.add('active');\n autoHideBtn.title = 'Disable Auto-Hide Controls';\n this.startAutoHideTimer();\n } else {\n autoHideBtn.classList.remove('active');\n autoHideBtn.title = 'Enable Auto-Hide Controls';\n this.stopAutoHideTimer();\n this.showControls();\n }\n }\n\n // Handle user activity\n handleUserActivity() {\n if (!this.autoHideEnabled) return;\n\n this.showControls();\n this.startAutoHideTimer();\n }\n\n // Start auto-hide timer\n startAutoHideTimer() {\n this.stopAutoHideTimer();\n\n this.autoHideTimeout = setTimeout(() => {\n this.hideControls();\n }, this.options.autoHideDelay);\n }\n\n // Stop auto-hide timer\n stopAutoHideTimer() {\n if (this.autoHideTimeout) {\n clearTimeout(this.autoHideTimeout);\n this.autoHideTimeout = null;\n }\n }\n\n // Show controls\n showControls() {\n if (this.isControlsVisible) return;\n\n this.isControlsVisible = true;\n this.zoomora.classList.remove('controls-hidden');\n\n // Animate controls back in\n if (this.header) {\n this.header.style.transform = 'translateY(0)';\n this.header.style.opacity = '1';\n }\n\n if (this.caption) {\n this.caption.style.transform = 'translateX(-50%) translateY(0)';\n this.caption.style.opacity = '1';\n }\n\n if (this.thumbs) {\n this.thumbs.style.transform = 'translateX(-50%) translateY(0)';\n this.thumbs.style.opacity = '1';\n }\n\n if (this.prevBtn) {\n this.prevBtn.style.transform = 'translateX(0)';\n this.prevBtn.style.opacity = '1';\n }\n\n if (this.nextBtn) {\n this.nextBtn.style.transform = 'translateX(0)';\n this.nextBtn.style.opacity = '1';\n }\n }\n\n // Hide controls\n hideControls() {\n if (!this.isControlsVisible) return;\n\n this.isControlsVisible = false;\n this.zoomora.classList.add('controls-hidden');\n\n // Animate controls out\n if (this.header) {\n this.header.style.transform = 'translateY(-100%)';\n this.header.style.opacity = '0';\n }\n\n if (this.caption) {\n this.caption.style.transform = 'translateX(-50%) translateY(100%)';\n this.caption.style.opacity = '0';\n }\n\n if (this.thumbs) {\n this.thumbs.style.transform = 'translateX(-50%) translateY(100%)';\n this.thumbs.style.opacity = '0';\n }\n\n if (this.prevBtn) {\n this.prevBtn.style.transform = 'translateX(-100%)';\n this.prevBtn.style.opacity = '0';\n }\n\n if (this.nextBtn) {\n this.nextBtn.style.transform = 'translateX(100%)';\n this.nextBtn.style.opacity = '0';\n }\n }\n\n /**\n * Check if image can be zoomed\n * @param {HTMLImageElement} img - Image element\n */\n checkZoomability(img) {\n if (!img || !img.naturalWidth || !img.naturalHeight) return;\n\n const imgRect = img.getBoundingClientRect();\n const renderedWidth = imgRect.width;\n const renderedHeight = imgRect.height;\n const naturalWidth = img.naturalWidth;\n const naturalHeight = img.naturalHeight;\n\n const isScaledDown = naturalWidth > renderedWidth || naturalHeight > renderedHeight;\n const zoomRatioX = naturalWidth / renderedWidth;\n const zoomRatioY = naturalHeight / renderedHeight;\n const maxZoomRatio = Math.max(zoomRatioX, zoomRatioY);\n\n // Store zoom info\n img.dataset.zoomRatio = maxZoomRatio.toString();\n img.dataset.naturalWidth = naturalWidth.toString();\n img.dataset.naturalHeight = naturalHeight.toString();\n img.dataset.renderedWidth = renderedWidth.toString();\n img.dataset.renderedHeight = renderedHeight.toString();\n\n // Enable zoom if significantly scaled down\n if (isScaledDown && maxZoomRatio > 1.1) {\n img.classList.remove('no-zoom');\n } else {\n img.classList.add('no-zoom');\n }\n }\n\n /**\n * Calculate zoom levels for an image\n * @param {HTMLImageElement} img - Image element\n * @returns {Object} Zoom configuration\n */\n calculateZoomLevels(img) {\n if (!img || !img.naturalWidth || !img.naturalHeight) {\n return {canZoom: false, levels: [], currentLevel: 0};\n }\n\n // Get CONTAINER size (not current displayed image size)\n const container = this.content.getBoundingClientRect();\n const containerWidth = container.width;\n const containerHeight = container.height;\n\n const naturalWidth = img.naturalWidth;\n const naturalHeight = img.naturalHeight;\n\n // Calculate what the ORIGINAL fit-to-screen scale would be\n const scaleToFitWidth = containerWidth / naturalWidth;\n const scaleToFitHeight = containerHeight / naturalHeight;\n const fitScale = Math.min(scaleToFitWidth, scaleToFitHeight);\n\n // If image naturally fits or is smaller than container, can't zoom\n if (fitScale >= 0.95) {\n return {canZoom: false, levels: [], currentLevel: 0};\n }\n\n // Respect the configured ceiling (falls back to 3x only if misconfigured)\n const configuredMax = Number(this.options.maxZoomScale);\n const maxZoom = Number.isFinite(configuredMax) && configuredMax > 0\n ? Math.max(1, configuredMax)\n : 3;\n\n // Calculate zoom levels based on FIT scale (not current scale)\n const levels = [1]; // Start with fit-to-screen\n\n // Add progressive levels up to the configured max: 1.5x, 2x, 3x, 4x, 5x...\n [1.5, 2, 3, 4, 5].forEach((candidate) => {\n if (candidate <= maxZoom && fitScale * candidate <= 1) {\n levels.push(candidate);\n }\n });\n\n // Add actual size (100%) as final level, capped at the configured max\n const actualSizeScale = Math.min(1 / fitScale, maxZoom);\n if (actualSizeScale > levels[levels.length - 1]) {\n levels.push(actualSizeScale);\n }\n\n return {\n canZoom: levels.length > 1,\n levels: levels,\n currentLevel: 0,\n baseScale: fitScale,\n naturalWidth: naturalWidth,\n naturalHeight: naturalHeight\n };\n }\n\n /**\n * Update counter display\n */\n updateCounter() {\n if (this.options.showCounter && this.counter) {\n this.counter.textContent = `${this.currentIndex + 1} / ${this.items.length}`;\n }\n }\n\n /**\n * Update caption display\n */\n updateCaption() {\n if (!this.caption || !this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const caption = item.dataset.caption || item.title || '';\n\n if (caption) {\n this.caption.textContent = caption;\n this.caption.style.transform = 'translateX(-50%) translateY(0)';\n this.caption.style.opacity = '1';\n this.caption.style.pointerEvents = 'auto';\n this.caption.style.transition = 'opacity 0.3s ease, transform 0.3s ease';\n } else {\n this.caption.style.transform = 'translateX(-50%) translateY(100%)';\n this.caption.style.opacity = '0';\n this.caption.style.pointerEvents = 'none';\n this.caption.style.transition = 'opacity 0.3s ease, transform 0.3s ease';\n }\n }\n\n /**\n * Update thumbnails display\n */\n updateThumbnails() {\n if (!this.options.showThumbnails || !this.thumbs) return;\n\n if (this.items.length === 1) {\n this.caption.classList.add('single-item-thumbnail');\n this.thumbs.style.display = 'none';\n return;\n }\n\n this.caption.classList.remove('single-item-thumbnail');\n\n this.thumbs.style.display = 'flex';\n this.thumbs.innerHTML = '';\n\n this.items.forEach((item, index) => {\n const thumb = document.createElement('div');\n thumb.className = 'zoomora-thumb';\n if (index === this.currentIndex) thumb.classList.add('active');\n\n const img = document.createElement('img');\n const thumbSrc = this.getThumbnailSource(item);\n\n if (thumbSrc) {\n img.src = thumbSrc;\n img.alt = item.alt || item.title || '';\n img.onerror = () => {\n thumb.style.display = 'none';\n };\n }\n\n thumb.appendChild(img);\n\n thumb.addEventListener('click', () => {\n this.currentIndex = index;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n });\n\n this.thumbs.appendChild(thumb);\n });\n }\n\n /**\n * Update navigation buttons\n */\n updateNavigation() {\n const prevBtn = document.getElementById('zoomoraPrevBtn');\n const nextBtn = document.getElementById('zoomoraNextBtn');\n\n if (prevBtn) {\n prevBtn.style.display = this.currentIndex > 0 ? 'flex' : 'none';\n }\n if (nextBtn) {\n nextBtn.style.display = this.currentIndex < this.items.length - 1 ? 'flex' : 'none';\n }\n }\n\n /**\n * Update control buttons\n */\n updateButtons() {\n const fullscreenBtn = document.getElementById('zoomoraFullscreenBtn');\n const collapseBtn = document.getElementById('zoomoraCollapseBtn');\n\n if (fullscreenBtn && collapseBtn) {\n if (this.isFullscreen) {\n fullscreenBtn.style.display = 'none';\n collapseBtn.style.display = 'flex';\n } else {\n fullscreenBtn.style.display = 'flex';\n collapseBtn.style.display = 'none';\n }\n }\n }\n\n /**\n * Toggle zoom state\n */\n toggleZoom() {\n const media = this.content.querySelector('.zoomora-media');\n if (!media || media.tagName !== 'IMG') return;\n\n // Calculate zoom levels\n const zoomConfig = this.calculateZoomLevels(media);\n\n if (!zoomConfig.canZoom) {\n return;\n }\n\n // Get or initialize current zoom level\n if (!media.dataset.zoomLevel) {\n media.dataset.zoomLevel = '0';\n }\n\n let currentLevel = parseInt(media.dataset.zoomLevel) || 0;\n\n // Cycle to next level\n currentLevel++;\n if (currentLevel >= zoomConfig.levels.length) {\n // Reset to fit-to-screen\n currentLevel = 0;\n }\n\n const targetScale = zoomConfig.levels[currentLevel];\n media.dataset.zoomLevel = currentLevel.toString();\n\n if (currentLevel === 0) {\n // Back to fit-to-screen\n this.isZoomed = false;\n this.isDragging = false;\n media.classList.remove('dragging');\n media.style.transform = '';\n media.style.cursor = 'pointer';\n media.classList.remove('zoomed');\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n } else {\n // Zoom in - reset position to center\n this.isZoomed = true;\n this.currentScale = targetScale;\n this.currentX = 0; // Always reset to center on zoom change\n this.currentY = 0;\n\n media.style.transform = `translate(0px, 0px) scale(${targetScale})`;\n media.style.cursor = 'grab';\n media.classList.add('zoomed');\n }\n }\n\n /**\n * Toggle fullscreen mode\n */\n toggleFullscreen() {\n if (!this.isFullscreen) {\n this.enterFullscreen();\n } else {\n this.exitFullscreen();\n }\n }\n\n /**\n * Enter fullscreen mode\n */\n enterFullscreen() {\n const element = this.zoomora;\n\n try {\n // Try standard API first\n if (element.requestFullscreen) {\n element.requestFullscreen()\n .then(() => {\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n })\n .catch(err => {\n console.warn('Zoomora: Fullscreen request failed:', err.message);\n this.fallbackFullscreen();\n });\n }\n // Try webkit (Safari, older Chrome)\n else if (element.webkitRequestFullscreen) {\n element.webkitRequestFullscreen();\n // Webkit doesn't return a promise, so set state immediately\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n // Try moz (Firefox)\n else if (element.mozRequestFullScreen) {\n element.mozRequestFullScreen();\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n // Try ms (IE11)\n else if (element.msRequestFullscreen) {\n element.msRequestFullscreen();\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n // Fallback to CSS fullscreen\n else {\n console.warn('Zoomora: Fullscreen API not supported, using CSS fallback');\n this.fallbackFullscreen();\n }\n } catch (error) {\n console.error('Zoomora: Error entering fullscreen:', error);\n this.fallbackFullscreen();\n }\n }\n\n /**\n * Exit fullscreen mode\n */\n exitFullscreen() {\n // First check if we're actually in fullscreen\n const isInFullscreen = !!(\n document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement\n );\n\n if (!isInFullscreen) {\n // Not in real fullscreen, just exit CSS fullscreen\n this.fallbackExitFullscreen();\n return;\n }\n\n try {\n // Try standard API first\n if (document.exitFullscreen) {\n document.exitFullscreen()\n .then(() => {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n })\n .catch(err => {\n console.warn('Zoomora: Exit fullscreen failed:', err.message);\n this.fallbackExitFullscreen();\n });\n }\n // Try webkit\n else if (document.webkitExitFullscreen) {\n document.webkitExitFullscreen();\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n // Try moz\n else if (document.mozCancelFullScreen) {\n document.mozCancelFullScreen();\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n // Try ms\n else if (document.msExitFullscreen) {\n document.msExitFullscreen();\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n // Fallback\n else {\n this.fallbackExitFullscreen();\n }\n } catch (error) {\n console.error('Zoomora: Error exiting fullscreen:', error);\n this.fallbackExitFullscreen();\n }\n }\n\n /**\n * Fallback fullscreen using CSS\n */\n fallbackFullscreen() {\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n\n /**\n * Exit CSS fullscreen\n */\n fallbackExitFullscreen() {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n\n /**\n * Toggle thumbnails visibility\n */\n toggleThumbnails() {\n if (this.items.length === 1) return;\n\n this.thumbnailsVisible = !this.thumbnailsVisible;\n if (this.thumbs) {\n this.thumbs.classList.toggle('thumbs-hidden', !this.thumbnailsVisible);\n\n if (!this.caption || !this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const caption = item.dataset.caption || item.title || '';\n\n if (caption && this.thumbs.classList.contains('thumbs-hidden')) {\n this.caption.style.bottom = '20px';\n this.caption.style.transition = 'bottom 0.3s ease, transform 0.3s ease';\n } else {\n this.caption.style.bottom = '120px';\n }\n }\n }\n\n /**\n * Start drag operation\n * @param {Event} e - Mouse or touch event\n */\n startDrag(e) {\n const media = this.content.querySelector('.zoomora-media');\n if (!media || !this.isZoomed) return;\n\n this.isDragging = true;\n media.classList.add('dragging');\n media.style.cursor = 'grabbing';\n\n this.startX = e.clientX || (e.touches && e.touches[0].clientX) || 0;\n this.startY = e.clientY || (e.touches && e.touches[0].clientY) || 0;\n\n // Read current position from transform\n const transform = window.getComputedStyle(media).transform;\n if (transform && transform !== 'none') {\n const matrix = new DOMMatrix(transform);\n this.currentX = matrix.m41;\n this.currentY = matrix.m42;\n } else {\n this.currentX = 0;\n this.currentY = 0;\n }\n\n e.preventDefault();\n }\n\n /**\n * Handle drag movement\n * @param {Event} e - Mouse or touch event\n */\n drag(e) {\n if (!this.isDragging) return;\n e.preventDefault();\n\n const media = this.content.querySelector('.zoomora-media');\n if (!media) return;\n\n const clientX = e.clientX || (e.touches && e.touches[0].clientX) || 0;\n const clientY = e.clientY || (e.touches && e.touches[0].clientY) || 0;\n\n const deltaX = clientX - this.startX;\n const deltaY = clientY - this.startY;\n\n let newX = this.currentX + deltaX;\n let newY = this.currentY + deltaY;\n\n // Calculate boundaries for BOTH width AND height\n const container = this.content.getBoundingClientRect();\n const mediaRect = media.getBoundingClientRect();\n\n // How much the scaled image overflows the container\n const overflowX = Math.max(0, (mediaRect.width - container.width) / 2);\n const overflowY = Math.max(0, (mediaRect.height - container.height) / 2);\n\n // Constrain drag to overflow boundaries\n if (overflowX > 0) {\n newX = Math.max(-overflowX, Math.min(overflowX, newX));\n } else {\n newX = 0; // Center horizontally if no overflow\n }\n\n if (overflowY > 0) {\n newY = Math.max(-overflowY, Math.min(overflowY, newY));\n } else {\n newY = 0; // Center vertically if no overflow\n }\n\n // Apply transform\n media.style.transform = `translate(${newX}px, ${newY}px) scale(${this.currentScale})`;\n\n // Update for next frame\n this.startX = clientX;\n this.startY = clientY;\n this.currentX = newX;\n this.currentY = newY;\n }\n\n /**\n * End drag operation\n */\n endDrag() {\n if (!this.isDragging) return;\n\n this.isDragging = false;\n this.lastDragTime = Date.now();\n\n const media = this.content.querySelector('.zoomora-media');\n if (media) {\n media.classList.remove('dragging');\n if (this.isZoomed) {\n media.style.cursor = 'grab';\n }\n }\n }\n\n /**\n * Go to specific item by index\n * @param {number} index - Item index\n */\n goTo(index) {\n if (index < 0 || index >= this.items.length) return;\n\n this.currentIndex = index;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n }\n\n /**\n * Get current item index\n * @returns {number} - Current index\n */\n getCurrentIndex() {\n return this.currentIndex;\n }\n\n /**\n * Get total number of items\n * @returns {number} - Total items\n */\n getTotalItems() {\n return this.items.length;\n }\n\n /**\n * Check if lightbox is open\n * @returns {boolean} - True if open\n */\n isOpen() {\n return this.zoomora && this.zoomora.classList.contains('active');\n }\n\n /**\n * Update options\n * @param {Object} newOptions - New options to merge\n */\n updateOptions(newOptions) {\n this.options = {...this.options, ...newOptions};\n }\n\n /**\n * Refresh the lightbox (re-scan for items)\n */\n refresh() {\n if (this.isOpen()) {\n const currentItem = this.items[this.currentIndex];\n if (currentItem) {\n this.open(currentItem);\n }\n }\n }\n\n /**\n * Destroy the lightbox instance\n */\n destroy() {\n if (!this.isInitialized) return;\n\n // Close if open\n if (this.isOpen()) {\n this.close();\n }\n\n // Clean up auto-hide\n this.stopAutoHideTimer();\n\n // Remove all event listeners\n this.eventListeners.forEach((listeners, _key) => {\n listeners.forEach(({element, event, handler, options}) => {\n if (element && element.removeEventListener) {\n element.removeEventListener(event, handler, options);\n }\n });\n });\n this.eventListeners.clear();\n\n // Remove DOM elements\n if (this.zoomora && this.zoomora.parentNode) {\n this.zoomora.parentNode.removeChild(this.zoomora);\n }\n\n // Reset properties\n this.isInitialized = false;\n this.items = [];\n this.currentIndex = 0;\n this.zoomora = null;\n this.content = null;\n this.counter = null;\n this.thumbs = null;\n this.loading = null;\n this.caption = null;\n }\n}\n\nexport default Zoomora;"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAeM,QAAQ;;;;;EAKZ,WAAW,WAAW;GACpB,OAAO;IACL,UAAU;IACV,aAAa;IACb,gBAAgB;IAChB,gBAAgB;IAChB,UAAU;IACV,YAAY;IACZ,SAAS;IACT,cAAc;IACd,UAAU;IACV,mBAAmB;IACnB,wBAAwB;IACxB,gBAAgB;IAChB,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,QAAQ;IAGR,oBAAoB;IACpB,eAAe;IACf,iBAAiB;GACnB;EACF;;;;;EAMA,YAAY,UAAU,CAAC,GAAG;GACxB,KAAK,UAAA,eAAA,eAAA,CAAA,GAAc,QAAQ,QAAA,GAAa,OAAO;GAC/C,KAAK,eAAe;GACpB,KAAK,QAAQ,CAAC;GACd,KAAK,WAAW;GAChB,KAAK,eAAe;GACpB,KAAK,aAAa;GAClB,KAAK,oBAAoB;GACzB,KAAK,SAAS;GACd,KAAK,SAAS;GACd,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,eAAe;GACpB,KAAK,gBAAgB;GACrB,KAAK,iCAAiB,IAAI,IAAI;GAG9B,KAAK,kBAAkB;GACvB,KAAK,kBAAkB;GACvB,KAAK,gBAAgB;GACrB,KAAK,oBAAoB;GAEzB,KAAK,eAAe;GACpB,KAAK,eAAe;IAClB,qBAAqB,KAAK,oBAAoB,KAAK,IAAI;IACvD,eAAe,KAAK,cAAc,KAAK,IAAI;IAC3C,wBAAwB,KAAK,uBAAuB,KAAK,IAAI;IAC7D,oBAAoB,KAAK,mBAAmB,KAAK,IAAI;IACrD,oBAAoB,KAAK,mBAAmB,KAAK,IAAI;IACrD,iBAAiB,KAAK,gBAAgB,KAAK,IAAI;IAC/C,iBAAiB,KAAK,gBAAgB,KAAK,IAAI;IAC/C,eAAe,KAAK,cAAc,KAAK,IAAI;IAC3C,kBAAkB,KAAK,iBAAiB,KAAK,IAAI;IACjD,iBAAiB,KAAK,gBAAgB,KAAK,IAAI;IAC/C,gBAAgB,KAAK,eAAe,KAAK,IAAI;IAC7C,aAAa,KAAK,YAAY,KAAK,IAAI;GACzC;GAEA,KAAK,KAAK;EACZ;;;;EAKA,OAAO;GACL,IAAI,KAAK,eAAe;IACtB,QAAQ,KAAK,qCAAqC;IAClD;GACF;GAEA,IAAI;IACF,KAAK,eAAe;IACpB,KAAK,WAAW;IAEhB,KAAK,gBAAgB;GACvB,SAAS,OAAO;IACd,QAAQ,MAAM,kCAAkC,KAAK;GACvD;EACF;;;;;;;EAQA,OAAO,KAAK,UAAU,UAAU,CAAC,GAAG;GAMlC,OAAO,IAAI,QAAA,eAAA,eAAA,CAAA,GAJN,OAAA,GAAA,CAAA,GAAA;IACO;IACV,SAAS;IAEsB,CAAC;EACpC;;;;EAKA,iBAAiB;GAEf,IAAI,SAAS,eAAe,iBAAiB,GAAG;IAC9C,QAAQ,KAAK,yCAAyC;IACtD;GACF;GAGA,MAAM,qBAAqB,KAAK,QAAQ,qBAAqB;;;;UAIvD;GAEN,MAAM,cAAc;;;;iEAIyC,CAAC,KAAK,QAAQ,cAAc,2CAAyC,GAAG;;kBAEvH,KAAK,QAAQ,iBAAiB;;;;oBAI5B,GAAG;kBACL,mBAAmB;kBACnB,KAAK,QAAQ,WAAW;;;;oBAItB,GAAG;kBACL,KAAK,QAAQ,iBAAiB;;;;;;;oBAO5B,GAAG;;;;;;;;;;;;;;;;;;;+DAmBwC,CAAC,KAAK,QAAQ,iBAAiB,2BAAyB,GAAG;iEACzD,CAAC,KAAK,QAAQ,iBAAiB,4BAA0B,GAAG;;;;GAKzH,SAAS,KAAK,mBAAmB,aAAa,WAAW;GAGzD,KAAK,UAAU,SAAS,eAAe,iBAAiB;GACxD,KAAK,SAAS,SAAS,eAAe,eAAe;GACrD,KAAK,UAAU,SAAS,eAAe,gBAAgB;GACvD,KAAK,kBAAkB,SAAS,eAAe,wBAAwB;GACvE,KAAK,UAAU,SAAS,eAAe,gBAAgB;GACvD,KAAK,SAAS,SAAS,eAAe,eAAe;GACrD,KAAK,UAAU,SAAS,eAAe,gBAAgB;GACvD,KAAK,UAAU,SAAS,eAAe,gBAAgB;GACvD,KAAK,UAAU,SAAS,eAAe,gBAAgB;GACvD,KAAK,UAAU,SAAS,eAAe,gBAAgB;GAGvD,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,WAAW,CAAC,KAAK,WAAW,CAAC,KAAK,UAAU,CAAC,KAAK,WAAW,CAAC,KAAK,SAC5F,MAAM,IAAI,MAAM,wCAAwC;EAE5D;;;;EAKA,aAAa;GAEX,KAAK,iBAAiB,UAAU,SAAS,KAAK,aAAa,mBAAmB;GAG9E,KAAK,iBAAiB,SAAS,eAAe,iBAAiB,GAAG,eAAe,KAAK,MAAM,CAAC;GAC7F,KAAK,iBAAiB,SAAS,eAAe,gBAAgB,GAAG,eAAe,KAAK,KAAK,CAAC;GAC3F,KAAK,iBAAiB,SAAS,eAAe,gBAAgB,GAAG,eAAe,KAAK,KAAK,CAAC;GAC3F,IAAI,KAAK,QAAQ,UACf,KAAK,iBAAiB,SAAS,eAAe,gBAAgB,GAAG,eAAe,KAAK,WAAW,CAAC;GAEnG,IAAI,KAAK,QAAQ,gBAAgB;IAC/B,KAAK,iBAAiB,SAAS,eAAe,sBAAsB,GAAG,eAAe,KAAK,iBAAiB,CAAC;IAC7G,KAAK,iBAAiB,SAAS,eAAe,oBAAoB,GAAG,eAAe,KAAK,eAAe,CAAC;GAC3G;GACA,IAAI,KAAK,QAAQ,gBACf,KAAK,iBAAiB,SAAS,eAAe,qBAAqB,GAAG,eAAe,KAAK,iBAAiB,CAAC;GAI9G,KAAK,iBAAiB,UAAU,oBAAoB,KAAK,aAAa,sBAAsB;GAC5F,KAAK,iBAAiB,UAAU,0BAA0B,KAAK,aAAa,sBAAsB;GAClG,KAAK,iBAAiB,UAAU,uBAAuB,KAAK,aAAa,sBAAsB;GAC/F,KAAK,iBAAiB,UAAU,sBAAsB,KAAK,aAAa,sBAAsB;GAG9F,KAAK,iBAAiB,UAAU,WAAW,KAAK,aAAa,aAAa;GAG1E,KAAK,iBAAiB,KAAK,SAAS,SAAS,KAAK,aAAa,kBAAkB;GAGjF,KAAK,iBAAiB,KAAK,SAAS,SAAS,KAAK,aAAa,kBAAkB;GAGjF,KAAK,iBAAiB,KAAK,SAAS,aAAa,KAAK,aAAa,eAAe;GAClF,KAAK,iBAAiB,KAAK,SAAS,aAAa,KAAK,aAAa,eAAe;GAClF,KAAK,iBAAiB,KAAK,SAAS,WAAW,KAAK,aAAa,aAAa;GAC9E,KAAK,iBAAiB,KAAK,SAAS,cAAc,KAAK,aAAa,aAAa;GAGjF,KAAK,iBAAiB,KAAK,SAAS,cAAc,KAAK,aAAa,kBAAkB,EAAC,SAAS,MAAK,CAAC;GACtG,KAAK,iBAAiB,KAAK,SAAS,aAAa,KAAK,aAAa,iBAAiB,EAAC,SAAS,MAAK,CAAC;GACpG,KAAK,iBAAiB,KAAK,SAAS,YAAY,KAAK,aAAa,cAAc;GAGhF,IAAI,KAAK,QAAQ,UACf,KAAK,iBAAiB,KAAK,SAAS,SAAS,KAAK,aAAa,aAAa,EAAC,SAAS,MAAK,CAAC;GAI9F,IAAI,KAAK,QAAQ,oBAAoB;IACnC,KAAK,iBAAiB,SAAS,eAAe,oBAAoB,GAAG,eAAe,KAAK,eAAe,CAAC;IAGzG,KAAK,iBAAiB,KAAK,SAAS,mBAAmB,KAAK,mBAAmB,CAAC;IAChF,KAAK,iBAAiB,KAAK,SAAS,oBAAoB,KAAK,mBAAmB,CAAC;IACjF,KAAK,iBAAiB,KAAK,SAAS,iBAAiB,KAAK,mBAAmB,CAAC;GAChF;EACF;;;;;;;;EASA,iBAAiB,SAAS,OAAO,SAAS,UAAU,CAAC,GAAG;GACtD,IAAI,CAAC,SAAS;GAEd,QAAQ,iBAAiB,OAAO,SAAS,OAAO;GAGhD,MAAM,MAAM,GAAG,QAAQ,YAAY,KAAK,GAAG;GAC3C,IAAI,CAAC,KAAK,eAAe,IAAI,GAAG,GAC9B,KAAK,eAAe,IAAI,KAAK,CAAC,CAAC;GAEjC,KAAK,eAAe,IAAI,GAAG,CAAC,CAAC,KAAK;IAAC;IAAS;IAAO;IAAS;GAAO,CAAC;EACtE;;;;;EAMA,oBAAoB,GAAG;GACrB,MAAM,SAAS,EAAE,OAAO,QAAQ,KAAK,QAAQ,QAAQ;GACrD,IAAI,QAAQ;IACV,EAAE,eAAe;IACjB,KAAK,KAAK,MAAM;GAClB;EACF;;;;;EAMA,cAAc,GAAG;GACf,IAAI,CAAC,KAAK,QAAQ,UAAU,SAAS,QAAQ,GAAG;IAC9C,KAAK,qBAAqB,CAAC;IAC3B;GACF;GAEA,QAAQ,EAAE,KAAV;IACE,KAAK;KACH,IAAI,KAAK,cACP,KAAK,eAAe;UAEpB,KAAK,MAAM;KAEb;IACF,KAAK;KACH,KAAK,KAAK;KACV;IACF,KAAK;KACH,KAAK,KAAK;KACV;IACF,KAAK;IACL,KAAK;KACH,KAAK,WAAW;KAChB;IACF,KAAK;IACL,KAAK;KACH,KAAK,iBAAiB;KACtB;IACF,KAAK;IACL,KAAK;KACH,KAAK,iBAAiB;KACtB;GACJ;EACF;;;;;EAMA,qBAAqB,GAAG;GACtB,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;GAExC,MAAM,UAAU,EAAE,OAAO,QAAQ,KAAK,QAAQ,QAAQ;GACtD,IAAI,CAAC,SAAS;GAEd,EAAE,eAAe;GACjB,KAAK,KAAK,OAAO;EACnB;;;;EAKA,yBAAyB;GACvB,MAAM,iBAAiB,CAAC,EACtB,SAAS,qBACT,SAAS,2BACT,SAAS,wBACT,SAAS;GAIX,IAAI,CAAC,kBAAkB,KAAK,cAAc;IACxC,KAAK,eAAe;IACpB,KAAK,QAAQ,UAAU,OAAO,YAAY;IAC1C,KAAK,cAAc;GACrB,OAEK,IAAI,kBAAkB,CAAC,KAAK,cAAc;IAC7C,KAAK,eAAe;IACpB,KAAK,QAAQ,UAAU,IAAI,YAAY;IACvC,KAAK,cAAc;GACrB;EACF;;;;;EAMA,mBAAmB,GAAG;GACpB,IAAI,EAAE,WAAW,KAAK,WAAW,KAAK,QAAQ,wBAC5C,KAAK,MAAM;EAEf;;;;;EAMA,mBAAmB,GAAG;GAEpB,IAAI,KAAK,IAAI,IAAI,KAAK,eAAe,KACnC;GAIF,IAAI,KAAK,UAAU,KAAK,OAAO,SAAS,EAAE,MAAM,GAC9C;GAIF,IAAI,EAAE,OAAO,QAAQ,QAAQ,GAC3B;GAIF,MAAM,eAAe,EAAE,OAAO,QAAQ,iDAAiD;GAEvF,IAAI,cAAc;IAEhB,IAAI,aAAa,UAAU,SAAS,eAAe,KAAK,CAAC,aAAa,UAAU,SAAS,SAAS,GAChG,KAAK,WAAW;IAElB;GACF;GAIA,IADuB,EAAE,OAAO,QAAQ,0BACvB,GAAG;IAElB,IAAI,EAAE,OAAO,QAAQ,sBAAsB,GACzC;IAGF,IAAI,KAAK,QAAQ,wBACf,KAAK,MAAM;IAEb;GACF;GAIA,MAAM,iBAAiB,EAAE;GASzB,KAPE,eAAe,UAAU,SAAS,iBAAiB,KACnD,eAAe,UAAU,SAAS,yBAAyB,KAC3D,eAAe,UAAU,SAAS,eAAe,KACjD,eAAe,UAAU,SAAS,0BAA0B,KAC5D,eAAe,OAAO,oBACtB,eAAe,OAAO,6BAEG,KAAK,QAAQ,wBAAwB;IAC9D,KAAK,MAAM;IACX;GACF;GAGA,IAAI,KAAK,QAAQ,wBACf,KAAK,MAAM;EAEf;;;;;EAMA,gBAAgB,GAAG;GACjB,KAAK,UAAU,CAAC;EAClB;;;;;EAMA,gBAAgB,GAAG;GACjB,KAAK,KAAK,CAAC;EACb;;;;EAKA,gBAAgB;GACd,KAAK,QAAQ;EACf;;;;;EAMA,iBAAiB,GAAG;GAClB,KAAK,UAAU,CAAC;EAClB;;;;;EAMA,gBAAgB,GAAG;GACjB,KAAK,KAAK,CAAC;EACb;;;;EAKA,iBAAiB;GACf,KAAK,QAAQ;EACf;;;;;EAMA,YAAY,GAAG;GACb,MAAM,QAAQ,KAAK,QAAQ,cAAc,gBAAgB;GACzD,IAAI,CAAC,SAAS,MAAM,YAAY,OAAO;GAEvC,MAAM,aAAa,KAAK,oBAAoB,KAAK;GACjD,IAAI,CAAC,WAAW,SAAS;GAEzB,EAAE,eAAe;GAEjB,MAAM,WAAW,WAAW,OAAO,WAAW,OAAO,SAAS;GAC9D,MAAM,OAAO,KAAK,QAAQ,YAAY;GACtC,MAAM,YAAY,EAAE,SAAS,IAAI,IAAI;GAErC,IAAI,YAAY,KAAK,gBAAgB,KAAM,YAAY,OAAO;GAC9D,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,QAAQ,CAAC;GAEnD,IAAI,aAAa,KAAK,cAAc;GAEpC,KAAK,eAAe;GACpB,KAAK,WAAW,WAAW;GAC3B,KAAK,WAAW;GAChB,KAAK,WAAW;GAEhB,IAAI,KAAK,UAAU;IACjB,MAAM,MAAM,YAAY,SAAS,SAAS;IAC1C,MAAM,MAAM,SAAS;IACrB,MAAM,UAAU,IAAI,QAAQ;GAC9B,OAAO;IACL,MAAM,MAAM,YAAY;IACxB,MAAM,MAAM,SAAS;IACrB,MAAM,UAAU,OAAO,QAAQ;GACjC;GAIA,IAAI,eAAe;GACnB,WAAW,OAAO,SAAS,OAAO,UAAU;IAC1C,IAAI,KAAK,IAAI,QAAQ,QAAQ,IAAI,KAAK,IAAI,WAAW,OAAO,gBAAgB,QAAQ,GAClF,eAAe;GAEnB,CAAC;GACD,MAAM,QAAQ,YAAY,aAAa,SAAS;EAClD;;;;;;EAOA,eAAe,MAAM;GACnB,MAAM,MAAM,KAAK,QAAQ,OAAO,KAAK,aAAa,MAAM,KAAK,KAAK,OAAO,KAAK,aAAa,KAAK;GAIhG,KAHa,KAAK,QAAQ,QAAQ,aAGrB,WAAW,KACtB,OAAO,KAAK,kBAAkB,GAAG;GAGnC,OAAO;EACT;;;;;;EAOA,kBAAkB,KAAK;GAErB,IAAI,IAAI,SAAS,oBAAoB,GACnC,OAAO;GAIT,IAAI,UAAU;GACd,IAAI,YAAY;GAGhB,IAAI,IAAI,SAAS,mBAAmB,GAAG;IACrC,MAAM,YAAY,IAAI,gBAAgB,IAAI,MAAM,GAAG,CAAC,CAAC,EAAE;IACvD,UAAU,UAAU,IAAI,GAAG;IAC3B,MAAM,IAAI,UAAU,IAAI,GAAG;IAC3B,IAAI,GAEF,YAAY,EAAE,QAAQ,KAAK,EAAE;GAEjC,OAAO,IAAI,IAAI,SAAS,WAAW,GAAG;IACpC,MAAM,QAAQ,IAAI,MAAM,GAAG;IAC3B,MAAM,iBAAiB,MAAM,MAAM,SAAS;IAC5C,IAAI,eAAe,SAAS,GAAG,GAAG;KAChC,UAAU,eAAe,MAAM,GAAG,CAAC,CAAC;KAEpC,MAAM,IAAI,IADY,gBAAgB,eAAe,MAAM,GAAG,CAAC,CAAC,EAC9C,CAAC,CAAC,IAAI,GAAG;KAC3B,IAAI,GAAG,YAAY,EAAE,QAAQ,KAAK,EAAE;IACtC,OACE,UAAU;GAEd;GAEA,IAAI,SAAS;IACX,IAAI,WAAW,iCAAiC;IAChD,MAAM,SAAS,IAAI,gBAAgB;IAEnC,IAAI,WACF,OAAO,OAAO,SAAS,SAAS;IAIlC,OAAO,OAAO,OAAO,GAAG;IACxB,OAAO,OAAO,kBAAkB,GAAG;IAEnC,IAAI,KAAK,QAAQ,gBACf,OAAO,OAAO,YAAY,GAAG;IAG/B,IAAI,OAAO,SAAS,GAClB,YAAY,MAAM,OAAO,SAAS;IAGpC,OAAO;GACT;GAGA,OAAO;EACT;;;;;;;EAQA,mBAAmB,MAAM;;GACvB,IAAI,KAAK,QAAQ,WACf,OAAO,KAAK,QAAQ;GAGtB,MAAM,cAAA,sBAAa,KAAK,mBAAA,QAAA,wBAAA,KAAA,IAAA,KAAA,IAAA,oBAAA,KAAA,MAAgB,KAAK;GAC7C,MAAM,WAAW,KAAK,aAAa,KAAK,MAAA,eAAA,QAAA,eAAA,KAAA,IAAA,KAAA,IAAK,WAAY,aAAa,KAAK;GAG3E,KAFa,KAAK,QAAQ,QAAQ,aAErB,SACX,OAAO;GAGT,OAAO,YAAY,KAAK,QAAQ,OAAO,KAAK,aAAa,MAAM;EACjE;;;;;;EAOA,SAAS,SAAS;GAChB,IAAI,KAAK,QAAQ,SACf,OAAO,QAAQ,QAAQ,YAAY,QAAQ,QAAQ,WAAW;GAEhE,OAAO,QAAQ,QAAQ,WAAW;EACpC;;;;;EAMA,KAAK,SAAS;GACZ,IAAI,CAAC,SAAS;GAEd,MAAM,QAAQ,KAAK,SAAS,OAAO;GACnC,IAAI;GAEJ,IAAI,KAAK,QAAQ,SACf,IAAI,QAAQ,QAAQ,UAClB,gBAAgB,mBAAmB,MAAM;QACpC,IAAI,QAAQ,QAAQ,SACzB,gBAAgB,kBAAkB,MAAM;QAExC,gBAAgB,KAAK,QAAQ;QAG/B,gBAAgB,kBAAkB,MAAM;GAG1C,KAAK,QAAQ,MAAM,KAAK,SAAS,iBAAiB,aAAa,CAAC;GAChE,KAAK,eAAe,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,OAAO,CAAC;GAE3D,KAAK,kBAAkB;GAGvB,IAAI,OAAO,KAAK,QAAQ,WAAW,YACjC,KAAK,QAAQ,OAAO,SAAS,KAAK,YAAY;EAElD;;;;;;;;;;;;;;;;;;EAmBA,UAAU,QAAQ,OAAO,CAAC,GAAG;GAC3B,MAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM;GAErD,KAAK,QAAQ,KAAK,KAAI,UACpB,KAAK,kBAAkB,OAAO,UAAU,WAAW,EAAC,KAAK,MAAK,IAAI,KAAK,CACzE;GAEA,KAAK,eAAe,KAAK,IACvB,GACA,KAAK,IAAI,KAAK,cAAc,GAAG,KAAK,MAAM,SAAS,CAAC,CACtD;GAEA,KAAK,kBAAkB;GAGvB,IAAI,OAAO,KAAK,QAAQ,WAAW,YACjC,KAAK,QAAQ,OAAO,KAAK,MAAM,KAAK,eAAe,KAAK,YAAY;EAExE;;;;;;;;;;;;;EAcA,kBAAkB,EAAC,KAAK,OAAO,OAAO,SAAS,UAAU,IAAI,MAAM,MAAK;GACtE,MAAM,WAAW,SAAS;GAC1B,OAAO;IACL,SAAS;KAAC;KAAK;KAAM;IAAO;IAC5B,KAAK;IACL;IACA,OAAO;IACP,eAAe,SAAS,SAAS,QAAQ,WAAW;GACtD;EACF;;;;;EAMA,oBAAoB;GAElB,KAAK,WAAW;GAChB,KAAK,eAAe;GACpB,KAAK,oBAAoB;GACzB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,eAAe;GAEpB,KAAK,QAAQ,UAAU,IAAI,QAAQ;GACnC,SAAS,KAAK,MAAM,WAAW;GAE/B,KAAK,YAAY;GACjB,KAAK,iBAAiB;GACtB,KAAK,cAAc;GACnB,KAAK,iBAAiB;GACtB,KAAK,cAAc;GACnB,KAAK,cAAc;GAGnB,IAAI,KAAK,iBACP,KAAK,mBAAmB;QAExB,KAAK,aAAa;EAEtB;;;;EAKA,QAAQ;GACN,IAAI,KAAK,cACP,KAAK,eAAe;GAGtB,KAAK,QAAQ,UAAU,OAAO,QAAQ;GACtC,SAAS,KAAK,MAAM,WAAW;GAG/B,MAAM,cAAc,KAAK,QAAQ,cAAc,OAAO;GACtD,IAAI,aACF,YAAY,MAAM;GAGpB,MAAM,eAAe,KAAK,QAAQ,cAAc,QAAQ;GACxD,IAAI,cACF,aAAa,MAAM;GAGrB,KAAK,WAAW;GAChB,KAAK,eAAe;GACpB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,eAAe;GAEpB,MAAM,QAAQ,KAAK,QAAQ,cAAc,gBAAgB;GACzD,IAAI,OAAO;IACT,MAAM,UAAU,OAAO,QAAQ;IAC/B,MAAM,MAAM,YAAY;IACxB,MAAM,MAAM,SAAS;GACvB;GAEA,KAAK,QAAQ,UAAU,OAAO,YAAY;GAC1C,KAAK,cAAc;GAGnB,KAAK,kBAAkB;GACvB,KAAK,aAAa;GAGlB,IAAI,OAAO,KAAK,QAAQ,YAAY,YAClC,KAAK,QAAQ,QAAQ,KAAK,YAAY;EAE1C;;;;EAKA,OAAO;GACL,IAAI,KAAK,eAAe,GAAG;IACzB,KAAK;IACL,KAAK,YAAY;IACjB,KAAK,cAAc;IACnB,KAAK,iBAAiB;IACtB,KAAK,iBAAiB;IACtB,KAAK,cAAc;IAGnB,IAAI,OAAO,KAAK,QAAQ,WAAW,YACjC,KAAK,QAAQ,OAAO,KAAK,YAAY;GAEzC;EACF;;;;EAKA,OAAO;GACL,IAAI,KAAK,eAAe,KAAK,MAAM,SAAS,GAAG;IAC7C,KAAK;IACL,KAAK,YAAY;IACjB,KAAK,cAAc;IACnB,KAAK,iBAAiB;IACtB,KAAK,iBAAiB;IACtB,KAAK,cAAc;IAGnB,IAAI,OAAO,KAAK,QAAQ,WAAW,YACjC,KAAK,QAAQ,OAAO,KAAK,YAAY;GAEzC;EACF;;;;EAKA,cAAc;GACZ,IAAI,CAAC,KAAK,MAAM,KAAK,eAAe;GAEpC,MAAM,OAAO,KAAK,MAAM,KAAK;GAC7B,MAAM,MAAM,KAAK,eAAe,IAAI;GACpC,MAAM,OAAO,KAAK,QAAQ,QAAQ;GAElC,IAAI,CAAC,KAAK;IACR,QAAQ,MAAM,mCAAmC;IACjD;GACF;GAGA,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,eAAe;GAGpB,KAAK,QAAQ,MAAM,UAAU;GAE7B,IAAI,KAAK,iBACP,KAAK,gBAAgB,YAAY;GAGnC,iBAAiB;IACf,KAAK,cAAc,KAAK,MAAM,IAAI;GACpC,GAAG,GAAG;EACR;;;;;;;EAQA,cAAc,KAAK,MAAM,MAAM;GAC7B,MAAM,iBAAiB,SAAS,cAAc,KAAK;GACnD,eAAe,YAAY;GAG3B,MAAM,QAAQ,SAAS,cAAc,KAAK;GAC1C,MAAM,YAAY,iBAAiB,KAAK,QAAQ,eAAe,UAAU,iBAAiB;GAC1F,MAAM,MAAM,UAAU;GACtB,MAAM,MAAM,YAAY,KAAK,QAAQ,eAAe,UAAU,qBAAqB;GAEnF,IAAI;GAEJ,IAAI;IACF,QAAQ,MAAR;KACE,KAAK;MACH,IAAI,IAAI,SAAS,MAAM,KAAK,IAAI,SAAS,OAAO,KAAK,IAAI,SAAS,MAAM,GAAG;OACzE,MAAM,iBAAiB,SAAS,cAAc,KAAK;OACnD,eAAe,YAAY;OAE3B,eAAe,SAAS,cAAc,OAAO;OAC7C,aAAa,MAAM;OACnB,aAAa,YAAY;OACzB,aAAa,aAAa,WAAW,UAAU;OAE/C,MAAM,YAAY,KAAK,OAAO,KAAK,aAAa,KAAK;OACrD,IAAI,WACF,aAAa,aAAa,UAAU,SAAS;OAG/C,MAAM,aAAa,SAAS,cAAc,KAAK;OAC/C,WAAW,YAAY;OACvB,WAAW,YAAY;OAEvB,WAAW,iBAAiB,eAAe;QACzC,aAAa,KAAK;QAClB,WAAW,MAAM,UAAU;QAC3B,aAAa,aAAa,YAAY,EAAE;OAC1C,CAAC;OAED,aAAa,iBAAiB,eAAe;QAC3C,WAAW,MAAM,UAAU;OAC7B,CAAC;OAED,eAAe,YAAY,YAAY;OACvC,eAAe,YAAY,UAAU;OACrC,IAAI,KAAK,QAAQ,gBACf,aAAa,KAAK,CAAC,CAChB,WAAW;QACV,WAAW,MAAM,UAAU;QAC3B,aAAa,aAAa,YAAY,EAAE;OAC1C,CAAC,CAAC,CACD,YAAY,CAEb,CAAC;OAEL,eAAe,YAAY,cAAc;MAC3C,OAAO;OACL,eAAe,SAAS,cAAc,QAAQ;OAC9C,aAAa,MAAM;OACnB,aAAa,YAAY;OACzB,aAAa,aAAa,mBAAmB,EAAE;OAC/C,aAAa,aAAa,SAAS,0CAA0C;OAC7E,aAAa,aAAa,eAAe,GAAG;OAC5C,eAAe,YAAY,YAAY;MACzC;MACA;KAEF,KAAK;MACH,eAAe,SAAS,cAAc,QAAQ;MAC9C,aAAa,MAAM;MACnB,aAAa,YAAY;MACzB,aAAa,aAAa,eAAe,GAAG;MAC5C,eAAe,YAAY,YAAY;MACvC;KAEF;MACE,eAAe,SAAS,cAAc,KAAK;MAC3C,aAAa,MAAM;MACnB,aAAa,YAAY;MACzB,aAAa,MAAM,KAAK,OAAO,KAAK,SAAS;MAE7C,aAAa,eAAe;OAC1B,KAAK,QAAQ,MAAM,UAAU;OAC7B,KAAK,iBAAiB,YAAY;OAClC,KAAK,eAAe,KAAK;MAC3B;MAEA,aAAa,gBAAgB;OAC3B,KAAK,QAAQ,MAAM,UAAU;OAC7B,QAAQ,MAAM,kCAAkC,GAAG;OACnD,KAAK,eAAe,KAAK;MAC3B;MAEA,eAAe,YAAY,YAAY;IAC3C;IAEA,MAAM,YAAY,cAAc;IAGhC,KAAK,gBAAgB,YAAY;IACjC,KAAK,gBAAgB,YAAY,KAAK;IAEtC,IAAI,SAAS,SAAS;KACpB,KAAK,QAAQ,MAAM,UAAU;KAC7B,KAAK,eAAe,KAAK;IAC3B;GAEF,SAAS,OAAO;IACd,QAAQ,MAAM,qCAAqC,KAAK;IACxD,KAAK,QAAQ,MAAM,UAAU;GAC/B;EACF;EAGA,eAAe,OAAO;GAEpB,MAAM;GAGN,MAAM,UAAU,IAAI,QAAQ;GAE5B,IAAI,KAAK,QAAQ,eAAe,SAAS;IACvC,MAAM,MAAM,aAAa,aAAa,KAAK,QAAQ,kBAAkB,mBAAmB,KAAK,QAAQ,kBAAkB;IACvH,MAAM,MAAM,YAAY;IACxB,MAAM,MAAM,UAAU;GACxB,OAAO;IACL,MAAM,MAAM,aAAa,aAAa,KAAK,QAAQ,kBAAkB,mBAAmB,KAAK,QAAQ,kBAAkB;IACvH,MAAM,MAAM,YAAY;IACxB,MAAM,MAAM,UAAU;GACxB;EACF;EAGA,iBAAiB;GACf,KAAK,kBAAkB,CAAC,KAAK;GAC7B,MAAM,cAAc,SAAS,eAAe,oBAAoB;GAEhE,IAAI,KAAK,iBAAiB;IACxB,YAAY,UAAU,IAAI,QAAQ;IAClC,YAAY,QAAQ;IACpB,KAAK,mBAAmB;GAC1B,OAAO;IACL,YAAY,UAAU,OAAO,QAAQ;IACrC,YAAY,QAAQ;IACpB,KAAK,kBAAkB;IACvB,KAAK,aAAa;GACpB;EACF;EAGA,qBAAqB;GACnB,IAAI,CAAC,KAAK,iBAAiB;GAE3B,KAAK,aAAa;GAClB,KAAK,mBAAmB;EAC1B;EAGA,qBAAqB;GACnB,KAAK,kBAAkB;GAEvB,KAAK,kBAAkB,iBAAiB;IACtC,KAAK,aAAa;GACpB,GAAG,KAAK,QAAQ,aAAa;EAC/B;EAGA,oBAAoB;GAClB,IAAI,KAAK,iBAAiB;IACxB,aAAa,KAAK,eAAe;IACjC,KAAK,kBAAkB;GACzB;EACF;EAGA,eAAe;GACb,IAAI,KAAK,mBAAmB;GAE5B,KAAK,oBAAoB;GACzB,KAAK,QAAQ,UAAU,OAAO,iBAAiB;GAG/C,IAAI,KAAK,QAAQ;IACf,KAAK,OAAO,MAAM,YAAY;IAC9B,KAAK,OAAO,MAAM,UAAU;GAC9B;GAEA,IAAI,KAAK,SAAS;IAChB,KAAK,QAAQ,MAAM,YAAY;IAC/B,KAAK,QAAQ,MAAM,UAAU;GAC/B;GAEA,IAAI,KAAK,QAAQ;IACf,KAAK,OAAO,MAAM,YAAY;IAC9B,KAAK,OAAO,MAAM,UAAU;GAC9B;GAEA,IAAI,KAAK,SAAS;IAChB,KAAK,QAAQ,MAAM,YAAY;IAC/B,KAAK,QAAQ,MAAM,UAAU;GAC/B;GAEA,IAAI,KAAK,SAAS;IAChB,KAAK,QAAQ,MAAM,YAAY;IAC/B,KAAK,QAAQ,MAAM,UAAU;GAC/B;EACF;EAGA,eAAe;GACb,IAAI,CAAC,KAAK,mBAAmB;GAE7B,KAAK,oBAAoB;GACzB,KAAK,QAAQ,UAAU,IAAI,iBAAiB;GAG5C,IAAI,KAAK,QAAQ;IACf,KAAK,OAAO,MAAM,YAAY;IAC9B,KAAK,OAAO,MAAM,UAAU;GAC9B;GAEA,IAAI,KAAK,SAAS;IAChB,KAAK,QAAQ,MAAM,YAAY;IAC/B,KAAK,QAAQ,MAAM,UAAU;GAC/B;GAEA,IAAI,KAAK,QAAQ;IACf,KAAK,OAAO,MAAM,YAAY;IAC9B,KAAK,OAAO,MAAM,UAAU;GAC9B;GAEA,IAAI,KAAK,SAAS;IAChB,KAAK,QAAQ,MAAM,YAAY;IAC/B,KAAK,QAAQ,MAAM,UAAU;GAC/B;GAEA,IAAI,KAAK,SAAS;IAChB,KAAK,QAAQ,MAAM,YAAY;IAC/B,KAAK,QAAQ,MAAM,UAAU;GAC/B;EACF;;;;;EAMA,iBAAiB,KAAK;GACpB,IAAI,CAAC,OAAO,CAAC,IAAI,gBAAgB,CAAC,IAAI,eAAe;GAErD,MAAM,UAAU,IAAI,sBAAsB;GAC1C,MAAM,gBAAgB,QAAQ;GAC9B,MAAM,iBAAiB,QAAQ;GAC/B,MAAM,eAAe,IAAI;GACzB,MAAM,gBAAgB,IAAI;GAE1B,MAAM,eAAe,eAAe,iBAAiB,gBAAgB;GACrE,MAAM,aAAa,eAAe;GAClC,MAAM,aAAa,gBAAgB;GACnC,MAAM,eAAe,KAAK,IAAI,YAAY,UAAU;GAGpD,IAAI,QAAQ,YAAY,aAAa,SAAS;GAC9C,IAAI,QAAQ,eAAe,aAAa,SAAS;GACjD,IAAI,QAAQ,gBAAgB,cAAc,SAAS;GACnD,IAAI,QAAQ,gBAAgB,cAAc,SAAS;GACnD,IAAI,QAAQ,iBAAiB,eAAe,SAAS;GAGrD,IAAI,gBAAgB,eAAe,KACjC,IAAI,UAAU,OAAO,SAAS;QAE9B,IAAI,UAAU,IAAI,SAAS;EAE/B;;;;;;EAOA,oBAAoB,KAAK;GACvB,IAAI,CAAC,OAAO,CAAC,IAAI,gBAAgB,CAAC,IAAI,eACpC,OAAO;IAAC,SAAS;IAAO,QAAQ,CAAC;IAAG,cAAc;GAAC;GAIrD,MAAM,YAAY,KAAK,QAAQ,sBAAsB;GACrD,MAAM,iBAAiB,UAAU;GACjC,MAAM,kBAAkB,UAAU;GAElC,MAAM,eAAe,IAAI;GACzB,MAAM,gBAAgB,IAAI;GAG1B,MAAM,kBAAkB,iBAAiB;GACzC,MAAM,mBAAmB,kBAAkB;GAC3C,MAAM,WAAW,KAAK,IAAI,iBAAiB,gBAAgB;GAG3D,IAAI,YAAY,KACd,OAAO;IAAC,SAAS;IAAO,QAAQ,CAAC;IAAG,cAAc;GAAC;GAIrD,MAAM,gBAAgB,OAAO,KAAK,QAAQ,YAAY;GACtD,MAAM,UAAU,OAAO,SAAS,aAAa,KAAK,gBAAgB,IAC9D,KAAK,IAAI,GAAG,aAAa,IACzB;GAGJ,MAAM,SAAS,CAAC,CAAC;GAGjB;IAAC;IAAK;IAAG;IAAG;IAAG;GAAC,CAAC,CAAC,SAAS,cAAc;IACvC,IAAI,aAAa,WAAW,WAAW,aAAa,GAClD,OAAO,KAAK,SAAS;GAEzB,CAAC;GAGD,MAAM,kBAAkB,KAAK,IAAI,IAAI,UAAU,OAAO;GACtD,IAAI,kBAAkB,OAAO,OAAO,SAAS,IAC3C,OAAO,KAAK,eAAe;GAG7B,OAAO;IACL,SAAS,OAAO,SAAS;IACjB;IACR,cAAc;IACd,WAAW;IACG;IACC;GACjB;EACF;;;;EAKA,gBAAgB;GACd,IAAI,KAAK,QAAQ,eAAe,KAAK,SACnC,KAAK,QAAQ,cAAc,GAAG,KAAK,eAAe,EAAE,KAAK,KAAK,MAAM;EAExE;;;;EAKA,gBAAgB;GACd,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,MAAM,KAAK,eAAe;GAErD,MAAM,OAAO,KAAK,MAAM,KAAK;GAC7B,MAAM,UAAU,KAAK,QAAQ,WAAW,KAAK,SAAS;GAEtD,IAAI,SAAS;IACX,KAAK,QAAQ,cAAc;IAC3B,KAAK,QAAQ,MAAM,YAAY;IAC/B,KAAK,QAAQ,MAAM,UAAU;IAC7B,KAAK,QAAQ,MAAM,gBAAgB;IACnC,KAAK,QAAQ,MAAM,aAAa;GAClC,OAAO;IACL,KAAK,QAAQ,MAAM,YAAY;IAC/B,KAAK,QAAQ,MAAM,UAAU;IAC7B,KAAK,QAAQ,MAAM,gBAAgB;IACnC,KAAK,QAAQ,MAAM,aAAa;GAClC;EACF;;;;EAKA,mBAAmB;GACjB,IAAI,CAAC,KAAK,QAAQ,kBAAkB,CAAC,KAAK,QAAQ;GAElD,IAAI,KAAK,MAAM,WAAW,GAAG;IAC3B,KAAK,QAAQ,UAAU,IAAI,uBAAuB;IAClD,KAAK,OAAO,MAAM,UAAU;IAC5B;GACF;GAEA,KAAK,QAAQ,UAAU,OAAO,uBAAuB;GAErD,KAAK,OAAO,MAAM,UAAU;GAC5B,KAAK,OAAO,YAAY;GAExB,KAAK,MAAM,SAAS,MAAM,UAAU;IAClC,MAAM,QAAQ,SAAS,cAAc,KAAK;IAC1C,MAAM,YAAY;IAClB,IAAI,UAAU,KAAK,cAAc,MAAM,UAAU,IAAI,QAAQ;IAE7D,MAAM,MAAM,SAAS,cAAc,KAAK;IACxC,MAAM,WAAW,KAAK,mBAAmB,IAAI;IAE7C,IAAI,UAAU;KACZ,IAAI,MAAM;KACV,IAAI,MAAM,KAAK,OAAO,KAAK,SAAS;KACpC,IAAI,gBAAgB;MAClB,MAAM,MAAM,UAAU;KACxB;IACF;IAEA,MAAM,YAAY,GAAG;IAErB,MAAM,iBAAiB,eAAe;KACpC,KAAK,eAAe;KACpB,KAAK,YAAY;KACjB,KAAK,cAAc;KACnB,KAAK,iBAAiB;KACtB,KAAK,iBAAiB;KACtB,KAAK,cAAc;IACrB,CAAC;IAED,KAAK,OAAO,YAAY,KAAK;GAC/B,CAAC;EACH;;;;EAKA,mBAAmB;GACjB,MAAM,UAAU,SAAS,eAAe,gBAAgB;GACxD,MAAM,UAAU,SAAS,eAAe,gBAAgB;GAExD,IAAI,SACF,QAAQ,MAAM,UAAU,KAAK,eAAe,IAAI,SAAS;GAE3D,IAAI,SACF,QAAQ,MAAM,UAAU,KAAK,eAAe,KAAK,MAAM,SAAS,IAAI,SAAS;EAEjF;;;;EAKA,gBAAgB;GACd,MAAM,gBAAgB,SAAS,eAAe,sBAAsB;GACpE,MAAM,cAAc,SAAS,eAAe,oBAAoB;GAEhE,IAAI,iBAAiB,aACnB,IAAI,KAAK,cAAc;IACrB,cAAc,MAAM,UAAU;IAC9B,YAAY,MAAM,UAAU;GAC9B,OAAO;IACL,cAAc,MAAM,UAAU;IAC9B,YAAY,MAAM,UAAU;GAC9B;EAEJ;;;;EAKA,aAAa;GACX,MAAM,QAAQ,KAAK,QAAQ,cAAc,gBAAgB;GACzD,IAAI,CAAC,SAAS,MAAM,YAAY,OAAO;GAGvC,MAAM,aAAa,KAAK,oBAAoB,KAAK;GAEjD,IAAI,CAAC,WAAW,SACd;GAIF,IAAI,CAAC,MAAM,QAAQ,WACjB,MAAM,QAAQ,YAAY;GAG5B,IAAI,eAAe,SAAS,MAAM,QAAQ,SAAS,KAAK;GAGxD;GACA,IAAI,gBAAgB,WAAW,OAAO,QAEpC,eAAe;GAGjB,MAAM,cAAc,WAAW,OAAO;GACtC,MAAM,QAAQ,YAAY,aAAa,SAAS;GAEhD,IAAI,iBAAiB,GAAG;IAEtB,KAAK,WAAW;IAChB,KAAK,aAAa;IAClB,MAAM,UAAU,OAAO,UAAU;IACjC,MAAM,MAAM,YAAY;IACxB,MAAM,MAAM,SAAS;IACrB,MAAM,UAAU,OAAO,QAAQ;IAC/B,KAAK,WAAW;IAChB,KAAK,WAAW;IAChB,KAAK,eAAe;GACtB,OAAO;IAEL,KAAK,WAAW;IAChB,KAAK,eAAe;IACpB,KAAK,WAAW;IAChB,KAAK,WAAW;IAEhB,MAAM,MAAM,YAAY,6BAA6B,YAAY;IACjE,MAAM,MAAM,SAAS;IACrB,MAAM,UAAU,IAAI,QAAQ;GAC9B;EACF;;;;EAKA,mBAAmB;GACjB,IAAI,CAAC,KAAK,cACR,KAAK,gBAAgB;QAErB,KAAK,eAAe;EAExB;;;;EAKA,kBAAkB;GAChB,MAAM,UAAU,KAAK;GAErB,IAAI;IAEF,IAAI,QAAQ,mBACV,QAAQ,kBAAkB,CAAC,CACxB,WAAW;KACV,KAAK,eAAe;KACpB,KAAK,QAAQ,UAAU,IAAI,YAAY;KACvC,KAAK,cAAc;IACrB,CAAC,CAAC,CACD,OAAM,QAAO;KACZ,QAAQ,KAAK,uCAAuC,IAAI,OAAO;KAC/D,KAAK,mBAAmB;IAC1B,CAAC;SAGA,IAAI,QAAQ,yBAAyB;KACxC,QAAQ,wBAAwB;KAEhC,KAAK,eAAe;KACpB,KAAK,QAAQ,UAAU,IAAI,YAAY;KACvC,KAAK,cAAc;IACrB,OAEK,IAAI,QAAQ,sBAAsB;KACrC,QAAQ,qBAAqB;KAC7B,KAAK,eAAe;KACpB,KAAK,QAAQ,UAAU,IAAI,YAAY;KACvC,KAAK,cAAc;IACrB,OAEK,IAAI,QAAQ,qBAAqB;KACpC,QAAQ,oBAAoB;KAC5B,KAAK,eAAe;KACpB,KAAK,QAAQ,UAAU,IAAI,YAAY;KACvC,KAAK,cAAc;IACrB,OAEK;KACH,QAAQ,KAAK,2DAA2D;KACxE,KAAK,mBAAmB;IAC1B;GACF,SAAS,OAAO;IACd,QAAQ,MAAM,uCAAuC,KAAK;IAC1D,KAAK,mBAAmB;GAC1B;EACF;;;;EAKA,iBAAiB;GASf,IAAI,CAAC,CAPmB,EACtB,SAAS,qBACT,SAAS,2BACT,SAAS,wBACT,SAAS,sBAGU;IAEnB,KAAK,uBAAuB;IAC5B;GACF;GAEA,IAAI;IAEF,IAAI,SAAS,gBACX,SAAS,eAAe,CAAC,CACtB,WAAW;KACV,KAAK,eAAe;KACpB,KAAK,QAAQ,UAAU,OAAO,YAAY;KAC1C,KAAK,cAAc;IACrB,CAAC,CAAC,CACD,OAAM,QAAO;KACZ,QAAQ,KAAK,oCAAoC,IAAI,OAAO;KAC5D,KAAK,uBAAuB;IAC9B,CAAC;SAGA,IAAI,SAAS,sBAAsB;KACtC,SAAS,qBAAqB;KAC9B,KAAK,eAAe;KACpB,KAAK,QAAQ,UAAU,OAAO,YAAY;KAC1C,KAAK,cAAc;IACrB,OAEK,IAAI,SAAS,qBAAqB;KACrC,SAAS,oBAAoB;KAC7B,KAAK,eAAe;KACpB,KAAK,QAAQ,UAAU,OAAO,YAAY;KAC1C,KAAK,cAAc;IACrB,OAEK,IAAI,SAAS,kBAAkB;KAClC,SAAS,iBAAiB;KAC1B,KAAK,eAAe;KACpB,KAAK,QAAQ,UAAU,OAAO,YAAY;KAC1C,KAAK,cAAc;IACrB,OAGE,KAAK,uBAAuB;GAEhC,SAAS,OAAO;IACd,QAAQ,MAAM,sCAAsC,KAAK;IACzD,KAAK,uBAAuB;GAC9B;EACF;;;;EAKA,qBAAqB;GACnB,KAAK,eAAe;GACpB,KAAK,QAAQ,UAAU,IAAI,YAAY;GACvC,KAAK,cAAc;EACrB;;;;EAKA,yBAAyB;GACvB,KAAK,eAAe;GACpB,KAAK,QAAQ,UAAU,OAAO,YAAY;GAC1C,KAAK,cAAc;EACrB;;;;EAKA,mBAAmB;GACjB,IAAI,KAAK,MAAM,WAAW,GAAG;GAE7B,KAAK,oBAAoB,CAAC,KAAK;GAC/B,IAAI,KAAK,QAAQ;IACf,KAAK,OAAO,UAAU,OAAO,iBAAiB,CAAC,KAAK,iBAAiB;IAErE,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,MAAM,KAAK,eAAe;IAErD,MAAM,OAAO,KAAK,MAAM,KAAK;IAG7B,KAFgB,KAAK,QAAQ,WAAW,KAAK,SAAS,OAEvC,KAAK,OAAO,UAAU,SAAS,eAAe,GAAG;KAC9D,KAAK,QAAQ,MAAM,SAAS;KAC5B,KAAK,QAAQ,MAAM,aAAa;IAClC,OACE,KAAK,QAAQ,MAAM,SAAS;GAEhC;EACF;;;;;EAMA,UAAU,GAAG;GACX,MAAM,QAAQ,KAAK,QAAQ,cAAc,gBAAgB;GACzD,IAAI,CAAC,SAAS,CAAC,KAAK,UAAU;GAE9B,KAAK,aAAa;GAClB,MAAM,UAAU,IAAI,UAAU;GAC9B,MAAM,MAAM,SAAS;GAErB,KAAK,SAAS,EAAE,WAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,WAAY;GAClE,KAAK,SAAS,EAAE,WAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,WAAY;GAGlE,MAAM,YAAY,OAAO,iBAAiB,KAAK,CAAC,CAAC;GACjD,IAAI,aAAa,cAAc,QAAQ;IACrC,MAAM,SAAS,IAAI,UAAU,SAAS;IACtC,KAAK,WAAW,OAAO;IACvB,KAAK,WAAW,OAAO;GACzB,OAAO;IACL,KAAK,WAAW;IAChB,KAAK,WAAW;GAClB;GAEA,EAAE,eAAe;EACnB;;;;;EAMA,KAAK,GAAG;GACN,IAAI,CAAC,KAAK,YAAY;GACtB,EAAE,eAAe;GAEjB,MAAM,QAAQ,KAAK,QAAQ,cAAc,gBAAgB;GACzD,IAAI,CAAC,OAAO;GAEZ,MAAM,UAAU,EAAE,WAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,WAAY;GACpE,MAAM,UAAU,EAAE,WAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,WAAY;GAEpE,MAAM,SAAS,UAAU,KAAK;GAC9B,MAAM,SAAS,UAAU,KAAK;GAE9B,IAAI,OAAO,KAAK,WAAW;GAC3B,IAAI,OAAO,KAAK,WAAW;GAG3B,MAAM,YAAY,KAAK,QAAQ,sBAAsB;GACrD,MAAM,YAAY,MAAM,sBAAsB;GAG9C,MAAM,YAAY,KAAK,IAAI,IAAI,UAAU,QAAQ,UAAU,SAAS,CAAC;GACrE,MAAM,YAAY,KAAK,IAAI,IAAI,UAAU,SAAS,UAAU,UAAU,CAAC;GAGvE,IAAI,YAAY,GACd,OAAO,KAAK,IAAI,CAAC,WAAW,KAAK,IAAI,WAAW,IAAI,CAAC;QAErD,OAAO;GAGT,IAAI,YAAY,GACd,OAAO,KAAK,IAAI,CAAC,WAAW,KAAK,IAAI,WAAW,IAAI,CAAC;QAErD,OAAO;GAIT,MAAM,MAAM,YAAY,aAAa,KAAK,MAAM,KAAK,YAAY,KAAK,aAAa;GAGnF,KAAK,SAAS;GACd,KAAK,SAAS;GACd,KAAK,WAAW;GAChB,KAAK,WAAW;EAClB;;;;EAKA,UAAU;GACR,IAAI,CAAC,KAAK,YAAY;GAEtB,KAAK,aAAa;GAClB,KAAK,eAAe,KAAK,IAAI;GAE7B,MAAM,QAAQ,KAAK,QAAQ,cAAc,gBAAgB;GACzD,IAAI,OAAO;IACT,MAAM,UAAU,OAAO,UAAU;IACjC,IAAI,KAAK,UACP,MAAM,MAAM,SAAS;GAEzB;EACF;;;;;EAMA,KAAK,OAAO;GACV,IAAI,QAAQ,KAAK,SAAS,KAAK,MAAM,QAAQ;GAE7C,KAAK,eAAe;GACpB,KAAK,YAAY;GACjB,KAAK,cAAc;GACnB,KAAK,iBAAiB;GACtB,KAAK,iBAAiB;GACtB,KAAK,cAAc;EACrB;;;;;EAMA,kBAAkB;GAChB,OAAO,KAAK;EACd;;;;;EAMA,gBAAgB;GACd,OAAO,KAAK,MAAM;EACpB;;;;;EAMA,SAAS;GACP,OAAO,KAAK,WAAW,KAAK,QAAQ,UAAU,SAAS,QAAQ;EACjE;;;;;EAMA,cAAc,YAAY;GACxB,KAAK,UAAA,eAAA,eAAA,CAAA,GAAc,KAAK,OAAA,GAAY,UAAU;EAChD;;;;EAKA,UAAU;GACR,IAAI,KAAK,OAAO,GAAG;IACjB,MAAM,cAAc,KAAK,MAAM,KAAK;IACpC,IAAI,aACF,KAAK,KAAK,WAAW;GAEzB;EACF;;;;EAKA,UAAU;GACR,IAAI,CAAC,KAAK,eAAe;GAGzB,IAAI,KAAK,OAAO,GACd,KAAK,MAAM;GAIb,KAAK,kBAAkB;GAGvB,KAAK,eAAe,SAAS,WAAW,SAAS;IAC/C,UAAU,SAAS,EAAC,SAAS,OAAO,SAAS,cAAa;KACxD,IAAI,WAAW,QAAQ,qBACrB,QAAQ,oBAAoB,OAAO,SAAS,OAAO;IAEvD,CAAC;GACH,CAAC;GACD,KAAK,eAAe,MAAM;GAG1B,IAAI,KAAK,WAAW,KAAK,QAAQ,YAC/B,KAAK,QAAQ,WAAW,YAAY,KAAK,OAAO;GAIlD,KAAK,gBAAgB;GACrB,KAAK,QAAQ,CAAC;GACd,KAAK,eAAe;GACpB,KAAK,UAAU;GACf,KAAK,UAAU;GACf,KAAK,UAAU;GACf,KAAK,SAAS;GACd,KAAK,UAAU;GACf,KAAK,UAAU;EACjB;CACF"}
|