PageSourceSearch

https://www.gurukrupabus.com/cms_builds/4516/gurukrupa-travels%C2%…/common/javascript/slider.js

js gurukrupabus.com collected 2026-10-02 01:31:56 UTC 170,786 bytes, 4,358 lines download raw bytes

1/**
2 * Custom Slider Library - JavaScript with Lazy Loading
3 * 
4 * Available CSS Classes:
5 * - no-arrows          : Hide arrow navigation buttons
6 * - no-slider-dots     : Hide dot navigation
7 * - slider-dots-bottom : Position dots at bottom center (default)
8 * - slider-dots-top    : Position dots at top center
9 * - slider-dots-left   : Position dots vertically on the left side
10 * - slider-dots-right  : Position dots vertically on the right side
11 * - infinite-loop      : Enable seamless infinite loop scrolling
12 * - lazy-load          : Enable lazy loading for images (enabled by default)
13 * - no-lazy-load       : Disable lazy loading and load all images immediately
14 * - preload-adjacent   : Preload previous/next slides for smoother transitions
15 * - vertical-slider    : Enable vertical sliding (bottom to top movement)
16 * 
17 * Required HTML Structure (with Lazy Loading):
18 * <div class="custom-slider" [optional-classes] [data-auto-slide-time="5000"] [data-lazy-threshold="0.1"]>
19 *   <div class="slider-container">
20 *     <div class="slider-wrapper">
21 *       <div class="slide">
22 *         <img data-lazy-src="{{image}}" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='800' height='400'%3E%3Crect width='100%25' height='100%25' fill='%23f0f0f0'/%3E%3C/svg%3E" alt="{{title}}" class="slide-bg-image lazy-image" loading="lazy" />
23 *         <div class="slide-overlay">
24 *           <h1>Title</h1>
25 *           <p>Description</p>
26 *         </div>
27 *       </div>
28 *       <div class="slide">
29 *         <img data-lazy-src="{{image2}}" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='800' height='400'%3E%3Crect width='100%25' height='100%25' fill='%23f0f0f0'/%3E%3C/svg%3E" alt="{{title2}}" class="slide-bg-image lazy-image" loading="lazy" />
30 *         <!-- More slides... -->
31 *       </div>
32 *     </div>
33 *   </div>
34 * </div>
35 * 
36 * Lazy Loading Configuration:
37 * - data-lazy-threshold: Intersection observer threshold (0.0 to 1.0, default: 0.1)
38 * - data-preload-distance: Number of slides to preload ahead/behind (default: 1)
39 * - data-placeholder-color: Placeholder background color (default: #f0f0f0)
40 * 
41 * Custom Timing:
42 * Use data-auto-slide-time attribute to set custom timing in milliseconds
43 * Default: 4000ms (4 seconds)
44 * Example: data-auto-slide-time="6000" for 6-second intervals
45 * 
46 * Usage:
47 * 1. Include slider.css in your HTML head
48 * 2. Include slider.js before closing body tag
49 * 3. Auto-initialization will handle all .custom-slider elements
50 * 4. Manual initialization: window.initCustomSlider(element)
51 * 
52 * Performance Features:
53 * - Lazy loading with Intersection Observer API
54 * - Progressive image loading
55 * - Placeholder images to prevent layout shift
56 * - Intelligent preloading of adjacent slides
57 * - Viewport-based slider initialization
58 * - Memory-efficient slide management
59 * 
60 * Features:
61 * - Touch/swipe support
62 * - Keyboard navigation (Arrow keys, Space to pause/resume)
63 * - Auto-play with custom timing
64 * - Responsive design
65 * - Accessibility features (ARIA attributes)
66 * - Hover to pause functionality
67 * - Multiple positioning options for navigation dots
68 * - Performance-optimized lazy loading
69 */
70
71// Custom Slider JavaScript Implementation with Lazy Loading
72class CustomSlider {
73    constructor(element) {
74        // Initialize error tracking
75        this.errorCount = 0;
76        this.maxErrors = 10;
77        this.isDestroyed = false;
78        this.isInitializing = true;
79        
80        try {
81            // Validate input element
82            if (!element) {
83                throw new Error('Slider element is required');
84            }
85            
86            // Comprehensive element validation (try instanceof first, then cross-context validation)
87            const isNativeHTMLElement = element instanceof HTMLElement;
88            
89            if (!isNativeHTMLElement) {
90                // Alternative validation for cross-context elements  
91                const isValidCrossContextElement = (
92                    element && 
93                    typeof element === 'object' &&
94                    element.nodeType === 1 && // ELEMENT_NODE
95                    (typeof element.tagName === 'string' || typeof element.nodeName === 'string') &&
96                    typeof element.classList === 'object' &&
97                    element.classList !== null &&
98                    typeof element.querySelector === 'function'
99                );
100                
101                if (!isValidCrossContextElement) {
102                    // Only log error if element fails ALL validation methods
103                    const errorDetails = {
104                        received: element,
105                        type: typeof element,
106                        nodeType: element?.nodeType,
107                        nodeName: element?.nodeName,
108                        constructor: element?.constructor?.name,
109                        isNode: element instanceof Node,
110                        isElement: element instanceof Element,
111                        isHTMLElement: element instanceof HTMLElement,
112                        hasTagName: !!element?.tagName,
113                        hasClassList: !!element?.classList,
114                        hasQuerySelector: typeof element?.querySelector === 'function'
115                    };
116                    
117                    console.error('🚨 Invalid element passed to CustomSlider:', errorDetails);
118                    throw new Error(`Slider element must be a valid HTML element. Received: ${typeof element} (${element?.constructor?.name || 'unknown'})`);
119                } else {
120                    console.info('ℹ️ Cross-context element detected - element is valid but from different execution context');
121                }
122            }
123            
124            // Core element validation with detailed errors
125            this.slider = element;
126            this.sliderWrapper = this.validateAndGetElement('.slider-wrapper', element);
127            
128            if (!this.sliderWrapper) {
129                throw new Error('Required .slider-wrapper element not found');
130            }
131            
132            this.slides = this.slider.querySelectorAll('.slide');
133            this.slideCount = this.slides.length;
134            
135            // Validate minimum requirements
136            if (this.slideCount === 0) {
137                console.warn('⚠️ Slider initialized with no slides');
138                this.slideCount = 0;
139            }
140            
141            // Initialize core properties with validation
142            this.currentSlide = 0;
143            this.autoSlideInterval = null;
144            this.isTransitioning = false;
145            this.startX = 0;
146            this.endX = 0;
147            
148            // Validate classList access
149            try {
150                this.isInfiniteLoop = this.slider.classList.contains('infinite-loop');
151                this.isCentered = this.slider.classList.contains('centered');
152                this.lazyLoadEnabled = !this.slider.classList.contains('no-lazy-load');
153            } catch (classError) {
154                console.error('⚠️ Error accessing classList:', classError);
155                this.isInfiniteLoop = false;
156                this.isCentered = false;
157                this.lazyLoadEnabled = true;
158            }
159            
160            this.originalSlideCount = this.slideCount;
161            this.cloneCount = 0;
162            this.isDragging = false;
163            this.startTransform = 0;
164            this.currentTransform = 0;
165            this.slidesPerView = 1;
166            this.centerOffset = 0;
167            
168            // Enhanced timeout tracking for race condition prevention
169            this.activeTimeouts = new Map(); // Changed to Map for better tracking
170            this.transitionTimeoutId = null;
171            this.infiniteLoopTimeoutId = null;
172            this.autoSlideTimeoutId = null;
173            this.initTimeoutId = null;
174
175            // Lazy loading configuration with validation
176            this.validateLazyLoadingConfig();
177            // Initialize state management with better validation
178            this.imageObserver = null;
179            this.loadedImages = new Set();
180            this.loadingImages = new Set();
181            this.priorityImages = new Set();
182            this.failedImages = new Set(); // Track failed images
183            
184            // Performance optimization flags
185            this.initialized = false;
186            this.isInViewport = false;
187            this.isVisible = true; // Track visibility
188            this.performanceMetrics = {
189                initTime: Date.now(),
190                imageLoadCount: 0,
191                errorCount: 0
192            };
193
194            // Initialize async to prevent blocking
195            this.initTimeoutId = this.safeSetTimeout(() => {
196                try {
197                    this.isInitializing = false;
198                    this.init();
199                } catch (initError) {
200                    console.error('🚨 SLIDER: Delayed init failed:', initError);
201                    this.handleCriticalError(initError);
202                }
203            }, 0);
204            
205        } catch (error) {
206            this.handleConstructorError(error, element);
207        }
208    }
209    
210    /**
211     * Enhanced element validation with detailed error reporting
212     */
213    validateAndGetElement(selector, parent = this.slider) {
214        try {
215            if (!parent || typeof parent.querySelector !== 'function') {
216                return null;
217            }
218            return parent.querySelector(selector);
219        } catch (error) {
220            console.error('🚨 Element validation failed:', { selector, error });
221            return null;
222        }
223    }
224    
225    /**
226     * Validate lazy loading configuration with safe defaults
227     */
228    validateLazyLoadingConfig() {
229        try {
230            this.preloadAdjacent = this.slider.classList.contains('preload-adjacent');
231            
232            // Safe attribute parsing with validation
233            const thresholdAttr = this.slider.getAttribute('data-lazy-threshold');
234            this.lazyThreshold = this.parseFloatSafe(thresholdAttr, 0.1, 0, 1);
235            
236            const distanceAttr = this.slider.getAttribute('data-preload-distance');
237            this.preloadDistance = this.parseIntSafe(distanceAttr, 1, 0, 10);
238            
239            this.placeholderColor = this.slider.getAttribute('data-placeholder-color') || '#f0f0f0';
240            
241            // Validate hex color
242            if (!/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(this.placeholderColor)) {
243                this.placeholderColor = '#f0f0f0';
244            }
245            
246            // Auto-slide timing with validation
247            const autoSlideAttr = this.slider.getAttribute('data-auto-slide-time');
248            this.autoSlideTime = this.parseIntSafe(autoSlideAttr, 4000, 0, 60000);
249            
250        } catch (error) {
251            console.error('🚨 Lazy loading config validation failed:', error);
252            this.setDefaultLazyConfig();
253        }
254    }
255    
256    /**
257     * Safe float parsing with bounds checking
258     */
259    parseFloatSafe(value, defaultValue, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
260        try {
261            const parsed = parseFloat(value);
262            if (isNaN(parsed)) return defaultValue;
263            return Math.max(min, Math.min(max, parsed));
264        } catch (error) {
265            return defaultValue;
266        }
267    }
268    
269    /**
270     * Safe integer parsing with bounds checking
271     */
272    parseIntSafe(value, defaultValue, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
273        try {
274            const parsed = parseInt(value);
275            if (isNaN(parsed)) return defaultValue;
276            return Math.max(min, Math.min(max, parsed));
277        } catch (error) {
278            return defaultValue;
279        }
280    }
281    
282    /**
283     * Set default lazy loading configuration
284     */
285    setDefaultLazyConfig() {
286        this.preloadAdjacent = false;
287        this.lazyThreshold = 0.1;
288        this.preloadDistance = 1;
289        this.placeholderColor = '#f0f0f0';
290        this.autoSlideTime = 4000;
291    }
292    
293    /**
294     * Enhanced constructor error handling
295     */
296    handleConstructorError(error, element) {
297        console.error('🚨 SLIDER CRASH: Constructor failed:', error);
298        console.error('🚨 SLIDER CRASH: Element details:', {
299            element: element,
300            className: element?.className,
301            tagName: element?.tagName,
302            hasSlides: element?.querySelectorAll('.slide').length || 0,
303            hasWrapper: !!element?.querySelector('.slider-wrapper')
304        });
305        
306        // Attempt minimal fallback initialization
307        try {
308            this.slider = element;
309            this.slideCount = 0;
310            this.initialized = false;
311            this.isDestroyed = true;
312            this.errorCount = this.maxErrors; // Mark as error-prone
313            
314            // Set safe defaults
315            this.setDefaultLazyConfig();
316            this.activeTimeouts = new Map();
317            this.loadedImages = new Set();
318            this.loadingImages = new Set();
319            this.priorityImages = new Set();
320            this.failedImages = new Set();
321            
322        } catch (fallbackError) {
323            console.error('🚨 SLIDER: Even fallback initialization failed:', fallbackError);
324        }
325    }
326    
327    /**
328     * Handle critical errors during operation
329     */
330    handleCriticalError(error)
331    {
332        this.errorCount++;
333        console.error(`🚨 SLIDER CRITICAL ERROR #${this.errorCount}:`, error);
334        
335        if (this.errorCount >= this.maxErrors) {
336            console.error('🚨 SLIDER: Max errors reached, disabling slider');
337            this.gracefulShutdown();
338        }
339    }
340    
341    /**
342     * Graceful shutdown when too many errors occur
343     */
344    gracefulShutdown() {
345        try {
346            this.isDestroyed = true;
347            this.stopAutoSlide();
348            this.clearAllTimeouts();
349            
350            if (this.imageObserver) {
351                this.imageObserver.disconnect();
352                this.imageObserver = null;
353            }
354            
355            // Add visual indicator of broken slider
356            if (this.slider && this.slider.style) {
357                this.slider.style.border = '2px dashed #ff6b6b';
358                this.slider.style.opacity = '0.5';
359                this.slider.setAttribute('data-slider-status', 'error');
360            }
361            
362        } catch (shutdownError) {
363            console.error('🚨 SLIDER: Error during shutdown:', shutdownError);
364        }
365    }
366    
367    /**
368     * Safe timeout management to prevent race conditions
369     */
370    safeSetTimeout(callback, delay, description = 'unknown') {
371        try {
372            const timeoutId = setTimeout(() => {
373                try {
374                    if (!this.isDestroyed) {
375                        callback();
376                    }
377                } catch (error) {
378                    console.error('🚨 SLIDER: Timeout callback error:', error);
379                    this.handleCriticalError(error);
380                } finally {
381                    this.activeTimeouts.delete(timeoutId);
382                }
383            }, delay);
384            
385            this.activeTimeouts.set(timeoutId, {
386                description,
387                timestamp: Date.now(),
388                delay
389            });
390            
391            return timeoutId;
392        } catch (error) {
393            console.error('🚨 SLIDER: Error creating timeout:', error);
394            return null;
395        }
396    }
397    
398    /**
399     * Clear all tracked timeouts
400     */
401    clearAllTimeouts() {
402        try {
403            for (const [timeoutId, info] of this.activeTimeouts.entries()) {
404                clearTimeout(timeoutId);
405            }
406            this.activeTimeouts.clear();
407            
408            // Clear specific timeout IDs
409            if (this.transitionTimeoutId) {
410                clearTimeout(this.transitionTimeoutId);
411                this.transitionTimeoutId = null;
412            }
413            
414            if (this.infiniteLoopTimeoutId) {
415                clearTimeout(this.infiniteLoopTimeoutId);
416                this.infiniteLoopTimeoutId = null;
417            }
418            
419            if (this.autoSlideTimeoutId) {
420                clearTimeout(this.autoSlideTimeoutId);
421                this.autoSlideTimeoutId = null;
422            }
423            
424            if (this.initTimeoutId) {
425                clearTimeout(this.initTimeoutId);
426                this.initTimeoutId = null;
427            }
428            
429        } catch (error) {
430            console.error('🚨 SLIDER: Error clearing timeouts:', error);
431        }
432    }
433
434    init() {
435        try {
436            // Prevent multiple initializations
437            if (this.initialized || this.isDestroyed) {
438                console.warn('⚠️ Slider already initialized or destroyed');
439                return;
440            }
441            
442            // Check if we have minimum requirements
443            if (this.slideCount === 0) {
444                console.warn('⚠️ Slider initialized with no slides, skipping setup');
445                this.initialized = true;
446                return;
447            }
448            
449            // Browser compatibility checks
450            if (!this.checkBrowserCompatibility()) {
451                console.warn('⚠️ Browser compatibility issues detected, using fallback mode');
452                this.lazyLoadEnabled = false;
453            }
454
455            // Set initial viewport state with error handling
456            try {
457                this.isInViewport = this.checkIfInViewport();
458            } catch (viewportError) {
459                console.error('⚠️ Viewport check failed:', viewportError);
460                this.isInViewport = true; // Assume visible on error
461            }
462
463            // Initialize lazy loading system first with validation
464            if (this.lazyLoadEnabled) {
465                try {
466                    this.initializeLazyLoading();
467                } catch (lazyError) {
468                    console.error('⚠️ Lazy loading initialization failed:', lazyError);
469                    this.lazyLoadEnabled = false;
470                }
471            }
472
473            // Setup infinite loop clones if enabled
474            if (this.isInfiniteLoop) {
475                try {
476                    this.setupInfiniteLoop();
477                    
478                    // Re-run lazy loading setup for cloned images if lazy loading is enabled
479                    if (this.lazyLoadEnabled) {
480                        this.setupLazyImages();
481                    }
482                } catch (infiniteError) {
483                    console.error('⚠️ Infinite loop setup failed:', infiniteError);
484                    this.isInfiniteLoop = false;
485                    this.slider.classList.remove('infinite-loop');
486                }
487            }
488
489            // Create navigation with validation
490            try {
491                this.createNavigation();
492            } catch (navError) {
493                console.error('⚠️ Navigation creation failed:', navError);
494            }
495            
496            // Enhanced dot creation with validation
497            try {
498                this.validateAndFixDots();
499                if (!this.dotsCreated) {
500                    this.createDots();
501                }
502            } catch (dotError) {
503                console.error('⚠️ Dots creation failed:', dotError);
504            }
505            
506            // Bind events with error handling
507            try {
508                this.bindEvents();
509            } catch (eventError) {
510                console.error('⚠️ Event binding failed:', eventError);
511            }
512            
513            // Load critical images immediately (current slide and adjacent slides)
514            if (this.lazyLoadEnabled) {
515                try {
516                    this.loadCriticalImages();
517                } catch (imageError) {
518                    console.error('⚠️ Critical image loading failed:', imageError);
519                }
520            }
521            
522            // Only start auto slide if time > 0 and no errors occurred
523            if (this.autoSlideTime > 0 && !this.isDestroyed) {
524                try {
525                    this.startAutoSlide();
526                } catch (autoError) {
527                    console.error('⚠️ Auto-slide start failed:', autoError);
528                }
529            }
530
531            // Initial setup with validation
532            try {
533                this.updateSlider();
534            } catch (updateError) {
535                console.error('⚠️ Initial slider update failed:', updateError);
536            }
537            
538            this.initialized = true;
539            this.performanceMetrics.initTime = Date.now() - this.performanceMetrics.initTime;
540            
541            // Add success indicator
542            if (this.slider) {
543                this.slider.setAttribute('data-slider-status', 'initialized');
544            }
545
546        } catch (error) {
547            console.error('🚨 SLIDER CRASH: Initialization failed:', error);
548            console.error('🚨 SLIDER CRASH: Slider state:', {
549                slideCount: this.slideCount,
550                currentSlide: this.currentSlide,
551                sliderWrapper: !!this.sliderWrapper,
552                lazyLoadEnabled: this.lazyLoadEnabled,
553                browserSupport: this.checkBrowserCompatibility()
554            });
555            this.handleCriticalError(error);
556        }
557    }
558    
559    /**
560     * Check browser compatibility for advanced features
561     */
562    checkBrowserCompatibility() {
563        const support = {
564            intersectionObserver: 'IntersectionObserver' in window,
565            classList: 'classList' in document.createElement('div'),
566            addEventListener: 'addEventListener' in window,
567            querySelector: 'querySelector' in document,
568            getBoundingClientRect: 'getBoundingClientRect' in document.createElement('div'),
569            setTimeout: 'setTimeout' in window,
570            JSON: 'JSON' in window
571        };
572        
573        const unsupportedFeatures = Object.keys(support).filter(key => !support[key]);
574        
575        if (unsupportedFeatures.length > 0) {
576            console.warn('⚠️ Unsupported browser features:', unsupportedFeatures);
577            return false;
578        }
579        
580        return true;
581    }
582
583    /**
584     * Check if slider is currently in viewport with error handling
585     */
586    checkIfInViewport() {
587        try {
588            if (!this.slider || !this.slider.getBoundingClientRect) {
589                return false;
590            }
591            
592            const rect = this.slider.getBoundingClientRect();
593            const windowHeight = window.innerHeight || document.documentElement.clientHeight;
594            const windowWidth = window.innerWidth || document.documentElement.clientWidth;
595            
596            return (
597                rect.top >= -100 && // Allow some margin above
598                rect.left >= -100 && // Allow some margin left
599                rect.bottom <= windowHeight + 100 && // Allow some margin below
600                rect.right <= windowWidth + 100 // Allow some margin right
601            );
602        } catch (error) {
603            console.error('⚠️ Viewport check error:', error);
604            return true; // Assume visible on error
605        }
606    }
607
608    /**
609     * Initialize lazy loading system with enhanced error handling and browser compatibility
610     */
611    initializeLazyLoading() {
612        try {
613            // Check for Intersection Observer support
614            if (!('IntersectionObserver' in window)) {
615                console.warn('⚠️ IntersectionObserver not supported, disabling lazy loading');
616                this.lazyLoadEnabled = false;
617                return;
618            }
619
620            // Create intersection observer for images with enhanced options
621            try {
622                this.imageObserver = new IntersectionObserver((entries) => {
623                    entries.forEach(entry => {
624                        try {
625                            if (entry.isIntersecting && entry.target) {
626                                this.loadImage(entry.target, false);
627                            }
628                        } catch (entryError) {
629                            console.error('⚠️ Intersection observer entry error:', entryError);
630                        }
631                    });
632                }, {
633                    root: null, // Use viewport instead of slider container
634                    rootMargin: '100px', // Increased margin for better preloading
635                    threshold: [0, this.lazyThreshold] // Multiple thresholds for better detection
636                });
637            } catch (observerError) {
638                console.error('⚠️ Failed to create intersection observer:', observerError);
639                this.lazyLoadEnabled = false;
640                return;
641            }
642
643            // Setup lazy loading for all images
644            this.setupLazyImages();
645            
646            // Create observer for slider visibility
647            this.createSliderObserver();
648            
649        } catch (error) {
650            console.error('⚠️ Lazy loading initialization error:', error);
651            this.lazyLoadEnabled = false;
652        }
653    }
654
655    /**
656     * Setup lazy loading attributes for all images with enhanced error handling
657     */
658    setupLazyImages() {
659        try {
660            if (!this.slider) {
661                console.error('⚠️ Cannot setup lazy images: slider element missing');
662                return;
663            }
664            
665            const images = this.slider.querySelectorAll('img');
666            
667            if (images.length === 0) {
668                console.info('ℹ️ No images found for lazy loading');
669                return;
670            }
671            
672            let processedCount = 0;
673            let errorCount = 0;
674            
675            images.forEach((img, index) => {
676                try {
677                    // Skip if image already processed
678                    if (img.dataset.lazyProcessed === 'true') {
679                        return;
680                    }
681                    
682                    // Validate image element
683                    if (!img || typeof img.setAttribute !== 'function') {
684                        errorCount++;
685                        return;
686                    }
687                    
688                    const lazySrc = img.dataset.lazySrc;
689                    const originalSrc = img.getAttribute('src');
690                    
691                    // If no data-lazy-src, convert existing src to lazy
692                    if (!lazySrc && originalSrc && !originalSrc.startsWith('data:')) {
693                        img.dataset.lazySrc = originalSrc;
694                        img.src = this.createPlaceholderImage(img);
695                    }
696                    
697                    // Add lazy loading classes safely
698                    if (img.classList) {
699                        img.classList.add('lazy-image');
700                    }
701                    
702                    // Add loading state handlers with error protection
703                    const loadHandler = () => {
704                        try {
705                            if (img.classList) {
706                                img.classList.add('loaded');
707                                img.classList.remove('loading');
708                            }
709                            this.performanceMetrics.imageLoadCount++;
710                        } catch (loadError) {
711                            console.error('⚠️ Image load handler error:', loadError);
712                        }
713                    };
714                    
715                    const errorHandler = (event) => {
716                        try {
717                            if (img.classList) {
718                                img.classList.add('error');
719                                img.classList.remove('loading');
720                            }
721                            this.failedImages.add(img);
722                            this.performanceMetrics.errorCount++;
723                            console.warn('⚠️ Image failed to load:', img.src);
724                        } catch (errorHandlerError) {
725                            console.error('⚠️ Image error handler error:', errorHandlerError);
726                        }
727                    };
728                    
729                    // Remove existing listeners to prevent duplicates
730                    img.removeEventListener('load', loadHandler);
731                    img.removeEventListener('error', errorHandler);
732                    
733                    // Add new listeners
734                    img.addEventListener('load', loadHandler);
735                    img.addEventListener('error', errorHandler);
736                    
737                    img.dataset.lazyProcessed = 'true';
738                    
739                    // Observe the image for lazy loading if observer exists
740                    if (this.imageObserver) {
741                        this.imageObserver.observe(img);
742                    }
743                    
744                    processedCount++;
745                    
746                } catch (imgError) {
747                    console.error(`⚠️ Error processing image ${index}:`, imgError);
748                    errorCount++;
749                }
750            });
751            
752            console.info(`ℹ️ Lazy loading setup: ${processedCount} images processed, ${errorCount} errors`);
753            
754        } catch (error) {
755            console.error('🚨 Setup lazy images failed:', error);
756        }
757    }
758
759    /**
760     * Create placeholder image data URL with validation
761     */
762    createPlaceholderImage(img) {
763        try {
764            if (!img) {
765                return 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="800" height="400"%3E%3Crect width="100%25" height="100%25" fill="%23f0f0f0"/%3E%3C/svg%3E';
766            }
767            
768            // Get dimensions with fallbacks
769            let width = 800;
770            let height = 400;
771            
772            try {
773                const widthAttr = img.getAttribute('width');
774                const heightAttr = img.getAttribute('height');
775                
776                if (widthAttr) width = parseInt(widthAttr) || width;
777                if (heightAttr) height = parseInt(heightAttr) || height;
778                
779                // Fallback to computed/offset dimensions
780                if (img.offsetWidth && img.offsetWidth > 0) width = img.offsetWidth;
781                if (img.offsetHeight && img.offsetHeight > 0) height = img.offsetHeight;
782                
783                // Ensure reasonable bounds
784                width = Math.max(50, Math.min(2000, width));
785                height = Math.max(50, Math.min(2000, height));
786                
787            } catch (dimError) {
788                console.warn('⚠️ Could not determine image dimensions:', dimError);
789            }
790            
791            // Validate placeholder color
792            const color = this.placeholderColor || '#f0f0f0';
793            const encodedColor = encodeURIComponent(color);
794            
795            return `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='${width}' height='${height}'%3E%3Crect width='100%25' height='100%25' fill='${encodedColor}'/%3E%3Ctext x='50%25' y='50%25' text-anchor='middle' dy='0.3em' fill='%23999' font-family='Arial' font-size='16'%3ELoading...%3C/text%3E%3C/svg%3E`;
796            
797        } catch (error) {
798            console.error('⚠️ Error creating placeholder:', error);
799            // Return minimal fallback
800            return 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="800" height="400"%3E%3Crect width="100%25" height="100%25" fill="%23f0f0f0"/%3E%3C/svg%3E';
801        }
802    }
803
804    /**
805     * Load critical images with enhanced error handling and performance optimization
806     */
807    loadCriticalImages() {
808        try {
809            if (!this.slides || this.slides.length === 0) {
810                console.warn('⚠️ No slides available for critical image loading');
811                return;
812            }
813            
814            const criticalSlides = new Set();
815            const startTime = performance.now ? performance.now() : Date.now();
816            
817            // Current slide
818            if (this.currentSlide >= 0 && this.currentSlide < this.slides.length) {
819                criticalSlides.add(this.currentSlide);
820            }
821            
822            // Adjacent slides for preloading with bounds checking
823            for (let i = 1; i <= this.preloadDistance; i++) {
824                const prevIndex = (this.currentSlide - i + this.slides.length) % this.slides.length;
825                const nextIndex = (this.currentSlide + i) % this.slides.length;
826                
827                if (prevIndex >= 0 && prevIndex < this.slides.length) {
828                    criticalSlides.add(prevIndex);
829                }
830                if (nextIndex >= 0 && nextIndex < this.slides.length) {
831                    criticalSlides.add(nextIndex);
832                }
833            }
834            
835            // Enhanced packages slider handling
836            const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
837                                    this.slider.classList.contains('custom-cards-slider');
838            
839            if (isPackagesSlider) {
840                try {
841                    const slideWidth = this.getSlideWidth();
842                    const containerWidth = this.slider.offsetWidth || 800;
843                    const visibleSlides = Math.ceil(containerWidth / slideWidth) + 2; // +2 for safety
844                    
845                    // Load all currently visible slides
846                    for (let i = 0; i < Math.min(visibleSlides, this.slides.length); i++) {
847                        const visibleSlideIndex = (this.currentSlide + i) % this.slides.length;
848                        if (visibleSlideIndex >= 0 && visibleSlideIndex < this.slides.length) {
849                            criticalSlides.add(visibleSlideIndex);
850                        }
851                    }
852                } catch (packagesError) {
853                    console.error('⚠️ Packages slider critical loading error:', packagesError);
854                }
855            }
856            
857            let loadedCount = 0;
858            let errorCount = 0;
859            
860            // Load images for critical slides
861            criticalSlides.forEach(slideIndex => {
862                try {
863                    if (this.slides[slideIndex]) {
864                        const slideImages = this.slides[slideIndex].querySelectorAll('img');
865                        slideImages.forEach(img => {
866                            try {
867                                if (img && !this.failedImages.has(img)) {
868                                    this.priorityImages.add(img);
869                                    this.loadImage(img, true);
870                                    loadedCount++;
871                                }
872                            } catch (imgError) {
873                                console.error('⚠️ Error loading critical image:', imgError);
874                                errorCount++;
875                            }
876                        });
877                    }
878                } catch (slideError) {
879                    console.error(`⚠️ Error processing slide ${slideIndex}:`, slideError);
880                    errorCount++;
881                }
882            });
883            
884            const endTime = performance.now ? performance.now() : Date.now();
885            //console.info(`ℹ️ Critical images loaded: ${loadedCount} images, ${errorCount} errors, ${Math.round(endTime - startTime)}ms`);
886            
887        } catch (error) {
888            console.error('🚨 Load critical images failed:', error);
889        }
890    }
891
892    /**
893     * Load individual image with enhanced error handling and race condition prevention
894     */
895    loadImage(img, isPriority = false) {
896        try {
897            // Validate image element
898            if (!img || !img.tagName || img.tagName.toLowerCase() !== 'img') {
899                console.warn('⚠️ Invalid image element provided to loadImage');
900                return;
901            }
902            
903            // Check if slider is destroyed
904            if (this.isDestroyed) {
905                return;
906            }
907            
908            // Check if image already has a real src (not placeholder)
909            const currentSrc = img.getAttribute('src');
910            if (currentSrc && !currentSrc.startsWith('data:') && this.loadedImages.has(img)) {
911                return;
912            }
913            
914            const lazySrc = img.dataset.lazySrc || currentSrc;
915            
916            // If no lazy src and current src is not a placeholder, mark as loaded
917            if (!lazySrc) {
918                if (currentSrc && !currentSrc.startsWith('data:')) {
919                    this.loadedImages.add(img);
920                    if (img.classList) {
921                        img.classList.add('loaded');
922                    }
923                }
924                return;
925            }
926            
927            // Skip if already processed or currently loading (prevent duplicate loading)
928            if (this.loadingImages.has(img) || this.loadedImages.has(img)) {
929                return;
930            }
931            
932            // Check if image was previously failed and should be retried
933            if (this.failedImages.has(img)) {
934                console.info('ℹ️ Retrying failed image:', lazySrc);
935                this.failedImages.delete(img);
936            }
937            
938            this.loadingImages.add(img);
939            if (img.classList) {
940                img.classList.add('loading');
941            }
942            
943            // For priority images or if not using lazy loading, load immediately
944            if (isPriority || !this.lazyLoadEnabled) {
945                try {
946                    img.src = lazySrc;
947                    this.loadedImages.add(img);
948                    this.loadingImages.delete(img);
949                    this.priorityImages.delete(img);
950                    
951                    if (img.classList) {
952                        img.classList.remove('loading');
953                        img.classList.add('loaded');
954                    }
955                    
956                    // Unobserve once loaded
957                    if (this.imageObserver) {
958                        this.imageObserver.unobserve(img);
959                    }
960                    return;
961                } catch (immediateLoadError) {
962                    console.error('⚠️ Immediate image load failed:', immediateLoadError);
963                    this.handleImageLoadError(img, lazySrc);
964                    return;
965                }
966            }
967            
968            // Create new image to preload for non-priority images
969            const preloadImg = new Image();
970            
971            // Set up timeout for image loading
972            const loadTimeout = this.safeSetTimeout(() => {
973                console.warn('⚠️ Image load timeout:', lazySrc);
974                this.handleImageLoadError(img, lazySrc, 'timeout');
975            }, 10000, `image-load-timeout-${lazySrc.substring(0, 50)}`);
976            
977            preloadImg.onload = () => {
978                try {
979                    // Clear timeout
980                    if (loadTimeout) {
981                        clearTimeout(loadTimeout);
982                        this.activeTimeouts.delete(loadTimeout);
983                    }
984                    
985                    // Check if slider is still active
986                    if (this.isDestroyed) {
987                        return;
988                    }
989                    
990                    // Update the actual image source
991                    img.src = lazySrc;
992                    this.loadedImages.add(img);
993                    this.loadingImages.delete(img);
994                    this.priorityImages.delete(img);
995                    
996                    if (img.classList) {
997                        img.classList.remove('loading');
998                        img.classList.add('loaded');
999                    }
1000                    
1001                    // Unobserve once loaded
1002                    if (this.imageObserver) {
1003                        this.imageObserver.unobserve(img);
1004                    }
1005                    
1006                } catch (onloadError) {
1007                    console.error('⚠️ Error in image onload handler:', onloadError);
1008                    this.handleImageLoadError(img, lazySrc);
1009                }
1010            };
1011            
1012            preloadImg.onerror = (errorEvent) => {
1013                try {
1014                    // Clear timeout
1015                    if (loadTimeout) {
1016                        clearTimeout(loadTimeout);
1017                        this.activeTimeouts.delete(loadTimeout);
1018                    }
1019                    
1020                    console.error('⚠️ Image load error:', lazySrc, errorEvent);
1021                    this.handleImageLoadError(img, lazySrc, 'load-error');
1022                    
1023                } catch (onerrorError) {
1024                    console.error('⚠️ Error in image onerror handler:', onerrorError);
1025                }
1026            };
1027            
1028            // Start loading
1029            preloadImg.src = lazySrc;
1030            
1031        } catch (error) {
1032            console.error('🚨 SLIDER CRASH: loadImage failed:', error);
1033            console.error('🚨 SLIDER CRASH: Image details during crash:', {
1034                imageSrc: img?.src,
1035                lazySrc: img?.dataset?.lazySrc,
1036                isPriority: isPriority,
1037                loadedImagesCount: this.loadedImages?.size,
1038                loadingImagesCount: this.loadingImages?.size
1039            });
1040            // Cleanup on error
1041            this.handleImageLoadError(img, img?.dataset?.lazySrc || img?.src);
1042        }
1043    }
1044    
1045    /**
1046     * Handle image loading errors consistently
1047     */
1048    handleImageLoadError(img, src, reason = 'unknown') {
1049        try {
1050            if (img && this.loadingImages) {
1051                this.loadingImages.delete(img);
1052                this.priorityImages.delete(img);
1053                this.failedImages.add(img);
1054                
1055                if (img.classList) {
1056                    img.classList.remove('loading');
1057                    img.classList.add('error');
1058                }
1059                
1060                // Set alt text if not present
1061                if (!img.alt) {
1062                    img.alt = 'Failed to load image';
1063                }
1064            }
1065            
1066            this.performanceMetrics.errorCount++;
1067            console.warn(`⚠️ Image load failed (${reason}):`, src);
1068            
1069        } catch (error) {
1070            console.error('🚨 Error handling image load error:', error);
1071        }
1072    }
1073
1074    /**
1075     * Create intersection observer for slider viewport detection
1076     */
1077    createSliderObserver() {
1078        const sliderObserver = new IntersectionObserver((entries) => {
1079            entries.forEach(entry => {
1080                this.isInViewport = entry.isIntersecting;
1081                
1082                if (entry.isIntersecting) {
1083                    // Slider is in viewport, ensure critical images are loaded
1084                    this.loadCriticalImages();
1085                    // Restart auto-slide if it was stopped
1086                    if (!this.autoSlideInterval && this.autoSlideTime > 0) {
1087                        this.startAutoSlide();
1088                    }
1089                }
1090            });
1091        }, {
1092            root: null,
1093            rootMargin: '100px',
1094            threshold: 0.1
1095        });
1096        
1097        sliderObserver.observe(this.slider);
1098    }
1099
1100    /**
1101     * Preload images for upcoming slides
1102     */
1103    preloadUpcomingSlides() {
1104        if (!this.lazyLoadEnabled || !this.preloadAdjacent) return;
1105        
1106        const upcomingSlides = new Set();
1107        
1108        // Calculate upcoming slides
1109        for (let i = 1; i <= this.preloadDistance; i++) {
1110            const nextIndex = (this.currentSlide + i) % this.slides.length;
1111            upcomingSlides.add(nextIndex);
1112        }
1113        
1114        // For packages slider, also preload slides that might become visible
1115        const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
1116                                this.slider.classList.contains('custom-cards-slider');
1117        
1118        if (isPackagesSlider) {
1119            const slideWidth = this.getSlideWidth();
1120            const containerWidth = this.slider.offsetWidth;
1121            const visibleSlides = Math.ceil(containerWidth / slideWidth);
1122            
1123            // Preload next batch of potentially visible slides
1124            for (let i = visibleSlides; i <= visibleSlides + this.preloadDistance; i++) {
1125                const preloadIndex = (this.currentSlide + i) % this.slides.length;
1126                upcomingSlides.add(preloadIndex);
1127            }
1128        }
1129        
1130        // Load images for upcoming slides
1131        upcomingSlides.forEach(slideIndex => {
1132            if (this.slides[slideIndex]) {
1133                const slideImages = this.slides[slideIndex].querySelectorAll('img[data-lazy-src]:not(.loaded):not(.loading)');
1134                slideImages.forEach(img => {
1135                    if (!this.loadedImages.has(img) && !this.loadingImages.has(img)) {
1136                        // Load with slight delay to not interfere with current transition
1137                        setTimeout(() => {
1138                            this.loadImage(img);
1139                        }, 100);
1140                    }
1141                });
1142            }
1143        });
1144    }
1145
1146    setupInfiniteLoop() {
1147        if (this.slideCount < 2) return; // Need at least 2 slides for infinite loop
1148        
1149        // Check if infinite loop is already set up
1150        if (this.infiniteLoopSetup) {
1151
1152            return;
1153        }
1154        
1155
1156        
1157        const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
1158                                this.slider.classList.contains('custom-cards-slider');
1159        
1160        if (isPackagesSlider) {
1161            // For packages slider, clone 2-3 slides on each side for smooth infinite scrolling
1162            this.cloneCount = Math.min(3, this.slideCount);
1163        } else {
1164            // For banner sliders, clone 1 slide on each side
1165            this.cloneCount = 1;
1166        }
1167        
1168
1169        
1170        // Store original slides before cloning
1171        const originalSlides = Array.from(this.slides);
1172        
1173        // Clone first slides and append to end
1174        for (let i = 0; i < this.cloneCount; i++) {
1175            const clone = originalSlides[i].cloneNode(true);
1176            clone.classList.add('slide-clone', 'slide-clone-end');
1177            clone.setAttribute('data-clone-index', i);
1178            clone.setAttribute('data-original-index', i);
1179            
1180            // Fix lazy loading for cloned images
1181            this.setupClonedImages(clone, i);
1182            
1183            this.sliderWrapper.appendChild(clone);
1184        }
1185        
1186        // Clone last slides and prepend to beginning
1187        for (let i = this.cloneCount - 1; i >= 0; i--) {
1188            const originalIndex = this.slideCount - 1 - i;
1189            const clone = originalSlides[originalIndex].cloneNode(true);
1190            clone.classList.add('slide-clone', 'slide-clone-start');
1191            clone.setAttribute('data-clone-index', originalIndex);
1192            clone.setAttribute('data-original-index', originalIndex);
1193            
1194            // Fix lazy loading for cloned images
1195            this.setupClonedImages(clone, originalIndex);
1196            
1197            this.sliderWrapper.insertBefore(clone, this.sliderWrapper.firstChild);
1198        }
1199        
1200        // Update slides collection to include clones
1201        this.slides = this.sliderWrapper.querySelectorAll('.slide');
1202        
1203        // Adjust current slide to account for prepended clones
1204        this.currentSlide = this.cloneCount;
1205        
1206        // Mark as set up to prevent re-execution
1207        this.infiniteLoopSetup = true;
1208        
1209
1210
1211    }
1212
1213    /**
1214     * Setup lazy loading for cloned slide images
1215     */
1216    setupClonedImages(clonedSlide, originalIndex) {
1217        if (!this.lazyLoadEnabled) return;
1218        
1219        const clonedImages = clonedSlide.querySelectorAll('img');
1220        const originalSlide = this.slides[originalIndex];
1221        const originalImages = originalSlide.querySelectorAll('img');
1222        
1223        clonedImages.forEach((clonedImg, imgIndex) => {
1224            const originalImg = originalImages[imgIndex];
1225            if (originalImg) {
1226                // Copy lazy loading attributes from original
1227                const lazySrc = originalImg.dataset.lazySrc;
1228                const originalSrc = originalImg.getAttribute('src');
1229                
1230                if (lazySrc) {
1231                    clonedImg.dataset.lazySrc = lazySrc;
1232                    clonedImg.dataset.lazyProcessed = 'true';
1233                    clonedImg.classList.add('lazy-image');
1234                    
1235                    // Set placeholder if original has one
1236                    if (originalSrc && originalSrc.startsWith('data:')) {
1237                        clonedImg.src = originalSrc;
1238                    } else {
1239                        clonedImg.src = this.createPlaceholderImage(clonedImg);
1240                    }
1241                    
1242                    // Add event listeners
1243                    clonedImg.addEventListener('load', () => {
1244                        clonedImg.classList.add('loaded');
1245                        clonedImg.classList.remove('loading');
1246                    });
1247                    
1248                    clonedImg.addEventListener('error', () => {
1249                        clonedImg.classList.add('error');
1250                        clonedImg.classList.remove('loading');
1251
1252                    });
1253                    
1254                    // Observe for lazy loading if observer exists
1255                    if (this.imageObserver) {
1256                        this.imageObserver.observe(clonedImg);
1257                    }
1258                } else if (originalSrc && !originalSrc.startsWith('data:')) {
1259                    // Original doesn't use lazy loading, copy src directly
1260                    clonedImg.src = originalSrc;
1261                    clonedImg.classList.add('loaded');
1262                }
1263            }
1264        });
1265    }
1266
1267    createNavigation() {
1268        if (this.slider.classList.contains('no-arrows')) return;
1269        
1270        // AGGRESSIVE CHECK: Remove any existing navigation first
1271        const existingNav = this.slider.querySelectorAll('.slider-navigation');
1272        if (existingNav.length > 0) {
1273
1274            existingNav.forEach(nav => nav.remove());
1275        }
1276        
1277        // Double-check the flag
1278        if (this.navigationCreated) {
1279
1280            return;
1281        }
1282
1283        const navigation = document.createElement('div');
1284        navigation.className = 'slider-navigation';
1285
1286        const prevBtn = document.createElement('button');
1287        prevBtn.className = 'slider-btn prev-btn';
1288        prevBtn.innerHTML = '&#8249;';
1289        prevBtn.setAttribute('aria-label', 'Previous slide');
1290
1291        const nextBtn = document.createElement('button');
1292        nextBtn.className = 'slider-btn next-btn';
1293        nextBtn.innerHTML = '&#8250;';
1294        nextBtn.setAttribute('aria-label', 'Next slide');
1295
1296        navigation.appendChild(prevBtn);
1297        navigation.appendChild(nextBtn);
1298        this.slider.appendChild(navigation);
1299
1300        // Store references
1301        this.prevBtn = prevBtn;
1302        this.nextBtn = nextBtn;
1303        this.navigationCreated = true;
1304        
1305
1306    }
1307
1308    /**
1309     * Clean up duplicate dots without affecting infinite loop functionality
1310     */
1311    cleanupDuplicateDots() {
1312        try {
1313            // Find all dot containers in this slider
1314            const allDotContainers = this.slider.querySelectorAll('.slider-dots');
1315            
1316            if (allDotContainers.length <= 1) {
1317                return; // No duplicates found
1318            }
1319            
1320
1321            
1322            // Keep the first properly constructed container, remove others
1323            let keptContainer = null;
1324            const containersToRemove = [];
1325            
1326            allDotContainers.forEach((container, index) => {
1327                const dots = container.querySelectorAll('.dot');
1328                const expectedDotCount = this.isInfiniteLoop ? this.originalSlideCount : this.slideCount;
1329                
1330                if (!keptContainer && dots.length === expectedDotCount) {
1331                    // Keep the first container with correct dot count
1332                    keptContainer = container;
1333
1334                } else {
1335                    containersToRemove.push(container);
1336                }
1337            });
1338            
1339            // Remove duplicate containers
1340            containersToRemove.forEach((container, index) => {
1341
1342                container.remove();
1343            });
1344            
1345            // Update dots reference if we kept a container
1346            if (keptContainer) {
1347                this.dots = keptContainer.querySelectorAll('.dot');
1348                this.dotsCreated = true;
1349            } else {
1350                // No good container found, reset for recreation
1351                this.dots = null;
1352                this.dotsCreated = false;
1353            }
1354            
1355
1356            
1357        } catch (error) {
1358            console.error('🚨 Error cleaning up duplicate dots:', error);
1359        }
1360    }
1361
1362    /**
1363     * Check for and fix any dot-related issues without touching infinite loop
1364     */
1365    validateAndFixDots() {
1366        try {
1367            const expectedDotCount = this.isInfiniteLoop ? this.originalSlideCount : this.slideCount;
1368            const dotContainers = this.slider.querySelectorAll('.slider-dots');
1369            
1370            // Check for multiple containers
1371            if (dotContainers.length > 1) {
1372
1373                this.cleanupDuplicateDots();
1374                return;
1375            }
1376            
1377            // Check for incorrect dot count in single container
1378            if (dotContainers.length === 1) {
1379                const container = dotContainers[0];
1380                const dots = container.querySelectorAll('.dot');
1381                
1382                if (dots.length !== expectedDotCount) {
1383
1384                    container.remove();
1385                    this.dotsCreated = false;
1386                    this.createDots();
1387                    return;
1388                }
1389                
1390                // Dots look good, just update reference
1391                this.dots = dots;
1392                this.dotsCreated = true;
1393            }
1394            
1395            // No container exists and dots should exist
1396            if (dotContainers.length === 0 && !this.slider.classList.contains('no-slider-dots')) {
1397
1398                this.dotsCreated = false;
1399                this.createDots();
1400            }
1401            
1402        } catch (error) {
1403            console.error('🚨 Error validating dots:', error);
1404        }
1405    }
1406
1407    createDots() {
1408        if (this.slider.classList.contains('no-slider-dots')) return;
1409        
1410        // Enhanced cleanup - Remove ALL existing dots first with better detection
1411        const existingDots = this.slider.querySelectorAll('.slider-dots');
1412        if (existingDots.length > 0) {
1413
1414            existingDots.forEach(dots => {
1415                // Remove event listeners before removing element
1416                const dotButtons = dots.querySelectorAll('.dot');
1417                dotButtons.forEach(dot => {
1418                    dot.replaceWith(dot.cloneNode(true)); // Remove all event listeners
1419                });
1420                dots.remove();
1421            });
1422        }
1423        
1424        // Triple-check: Look for any orphaned dot elements
1425        const orphanedDots = this.slider.querySelectorAll('.dot:not(.slider-
1425dots .dot)');
1426        if (orphanedDots.length > 0) {
1427
1428            orphanedDots.forEach(dot => dot.remove());
1429        }
1430        
1431        // Check flag after cleanup
1432        if (this.dotsCreated) {
1433
1434            this.dotsCreated = false;
1435        }
1436
1437        const dotsContainer = document.createElement('div');
1438        dotsContainer.className = 'slider-dots';
1439
1440        // Determine position class
1441        if (this.slider.classList.contains('slider-dots-top')) {
1442            dotsContainer.classList.add('slider-dots-top');
1443        } else if (this.slider.classList.contains('slider-dots-left')) {
1444            dotsContainer.classList.add('slider-dots-left');
1445        } else if (this.slider.classList.contains('slider-dots-right')) {
1446            dotsContainer.classList.add('slider-dots-right');
1447        } else if (this.slider.classList.contains('slider-dots-right-center')) {
1448            dotsContainer.classList.add('slider-dots-right-center');
1449        } else if (this.slider.classList.contains('slider-dots-left-center')) {
1450            dotsContainer.classList.add('slider-dots-left-center');
1451        } else {
1452            dotsContainer.classList.add('slider-dots-bottom');
1453        }
1454
1455        // Create dots - ONLY for original slides, not clones
1456        const dotCount = this.isInfiniteLoop ? this.originalSlideCount : this.slideCount;
1457
1458        
1459        for (let i = 0; i < dotCount; i++) {
1460            const dot = document.createElement('button');
1461            dot.className = 'dot';
1462            if (i === 0) dot.classList.add('active');
1463            dot.setAttribute('data-slide', i);
1464            dot.setAttribute('aria-label', `Go to slide ${i + 1}`);
1465            dotsContainer.appendChild(dot);
1466        }
1467
1468        // Add unique identifier to prevent conflicts
1469        dotsContainer.setAttribute('data-slider-dots-id', `dots-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`);
1470        
1471        this.slider.appendChild(dotsContainer);
1472        this.dots = dotsContainer.querySelectorAll('.dot');
1473        this.dotsCreated = true;
1474        
1475
1476    }
1477
1478    /**
1479     * Enhanced event binding with proper error handling and memory management
1480     */
1481    bindEvents() {
1482        try {
1483            // Create bound handler methods to maintain context and enable proper cleanup
1484            this.prevSlideHandler = () => this.prevSlide();
1485            this.nextSlideHandler = () => this.nextSlide();
1486            this.mouseEnterHandler = () => this.stopAutoSlide();
1487            this.mouseLeaveHandler = () => this.startAutoSlide();
1488            this.touchStartHandler = (e) => this.handleTouchStart(e);
1489            this.touchMoveHandler = (e) => this.handleTouchMove(e);
1490            this.touchEndHandler = (e) => this.handleTouchEnd(e);
1491            this.mouseDownHandler = (e) => this.handleMouseStart(e);
1492            this.mouseMoveHandler = (e) => this.handleMouseMove(e);
1493            this.mouseUpHandler = (e) => this.handleMouseEnd(e);
1494            this.keydownHandler = (e) => this.handleKeyboard(e);
1495            
1496            // Arrow buttons with validation
1497            if (this.prevBtn && this.prevBtn.addEventListener) {
1498                this.prevBtn.addEventListener('click', this.prevSlideHandler);
1499            }
1500            if (this.nextBtn && this.nextBtn.addEventListener) {
1501                this.nextBtn.addEventListener('click', this.nextSlideHandler);
1502            }
1503
1504            // Dots navigation with comprehensive error handling
1505            if (this.dots && this.dots.length > 0) {
1506                this.dotClickHandlers = [];
1507                this.dotMousedownHandlers = [];
1508                
1509                this.dots.forEach((dot, index) => {
1510                    try {
1511                        if (dot && dot.addEventListener) {
1512                            const clickHandler = (e) => {
1513                                try {
1514                                    e.stopPropagation();
1515                                    if (!this.isDestroyed) {
1516                                        this.goToSlide(index);
1517                                    }
1518                                } catch (clickError) {
1519                                    console.error('⚠️ Dot click error:', clickError);
1520                                }
1521                            };
1522                            
1523                            const mousedownHandler = (e) => {
1524                                try {
1525                                    e.stopPropagation();
1526                                } catch (mousedownError) {
1527                                    console.error('⚠️ Dot mousedown error:', mousedownError);
1528                                }
1529                            };
1530                            
1531                            dot.addEventListener('click', clickHandler);
1532                            dot.addEventListener('mousedown', mousedownHandler);
1533                            
1534                            // Store handlers for cleanup
1535                            this.dotClickHandlers[index] = clickHandler;
1536                            this.dotMousedownHandlers[index] = mousedownHandler;
1537                        }
1538                    } catch (dotError) {
1539                        console.error(`⚠️ Error binding events for dot ${index}:`, dotError);
1540                    }
1541                });
1542            }
1543
1544            // Slider events with validation
1545            if (this.slider && this.slider.addEventListener) {
1546                // Hover events
1547                this.slider.addEventListener('mouseenter', this.mouseEnterHandler);
1548                this.slider.addEventListener('mouseleave', this.mouseLeaveHandler);
1549
1550                // Touch events
1551                this.slider.addEventListener('touchstart', this.touchStartHandler, { passive: false });
1552                this.slider.addEventListener('touchmove', this.touchMoveHandler, { passive: false });
1553                this.slider.addEventListener('touchend', this.touchEndHandler);
1554
1555                // Mouse events for desktop dragging
1556                this.slider.addEventListener('mousedown', this.mouseDownHandler);
1557                this.slider.addEventListener('mousemove', this.mouseMoveHandler);
1558                this.slider.addEventListener('mouseup', this.mouseUpHandler);
1559                this.slider.addEventListener('mouseleave', this.mouseUpHandler); // Also handle mouse leave as mouse up
1560
1561                // Keyboard events
1562                this.slider.addEventListener('keydown', this.keydownHandler);
1563
1564                // Make slider focusable for keyboard navigation
1565                this.slider.setAttribute('tabindex', '0');
1566            }
1567            
1568        } catch (error) {
1569            console.error('⚠️ Event binding failed:', error);
1570        }
1571    }
1572
1573    updateSlider() {
1574        try {
1575            // Early validation checks
1576            if (!this.sliderWrapper || this.isTransitioning || this.isDestroyed) {
1577                if (this.isDestroyed) {
1578                    console.warn('⚠️ updateSlider called on destroyed slider');
1579                }
1580                return;
1581            }
1582
1583            // Clear any existing transition timeout to prevent conflicts
1584            if (this.transitionTimeoutId) {
1585                clearTimeout(this.transitionTimeoutId);
1586                this.activeTimeouts.delete(this.transitionTimeoutId);
1587                this.transitionTimeoutId = null;
1588            }
1589
1590            this.isTransitioning = true;
1591            const startTime = performance.now ? performance.now() : Date.now();
1592        
1593            // Validate current slide bounds
1594            if (this.currentSlide < 0 || this.currentSlide >= this.slides.length) {
1595                console.warn(`⚠️ Current slide index out of bounds: ${this.currentSlide}/${this.slides.length}`);
1596                this.currentSlide = Math.max(0, Math.min(this.slides.length - 1, this.currentSlide));
1597            }
1598            
1599            // Calculate transform based on slider type
1600            const transformResult = this.calculateTransform();
1601            if (!transformResult.success) {
1602                console.error('⚠️ Transform calculation failed');
1603                this.isTransitioning = false;
1604                return;
1605            }
1606            
1607            // Apply transform with error handling
1608            try {
1609                this.sliderWrapper.style.transform = transformResult.transform;
1610            } catch (transformError) {
1611                console.error('⚠️ Failed to apply transform:', transformError);
1612                this.isTransitioning = false;
1613                return;
1614            }
1615
1616            // Update dots with validation
1617            this.updateDots();
1618            
1619            // Update active slide class for centered mode
1620            if (this.isCentered && this.slides.length > 0) {
1621                this.updateActiveSlideClasses();
1622            }
1623
1624            // Update ARIA attributes for accessibility
1625            this.updateAriaAttributes();
1626
1627            // Enhanced lazy loading with error protection
1628            if (this.lazyLoadEnabled && !this.isDestroyed) {
1629                this.safeSetTimeout(() => {
1630                    if (!this.isDestroyed) {
1631                        try {
1632                            this.loadCriticalImages();
1633                            // Preload upcoming slides with delay
1634                            this.safeSetTimeout(() => {
1635                                if (!this.isDestroyed) {
1636                                    this.preloadUpcomingSlides();
1637                                }
1638                            }, 100, 'preload-upcoming');
1639                        } catch (lazyError) {
1640                            console.error('⚠️ Lazy loading during update failed:', lazyError);
1641                        }
1642                    }
1643                }, 0, 'update-lazy-loading');
1644            }
1645
1646            // Set transition end timeout with race condition protection
1647            this.transitionTimeoutId = this.safeSetTimeout(() => {
1648                try {
1649                    if (!this.isDestroyed) {
1650                        this.isTransitioning = false;
1651                        this.transitionTimeoutId = null;
1652                    }
1653                } catch (timeoutError) {
1654                    console.error('⚠️ Transition timeout error:', timeoutError);
1655                    // Force reset the flag
1656                    this.isTransitioning = false;
1657                    this.transitionTimeoutId = null;
1658                }
1659            }, 500, 'transition-end');
1660            
1661            const endTime = performance.now ? performance.now() : Date.now();
1662            const duration = Math.round(endTime - startTime);
1663            
1664            if (duration > 16) { // Log if update takes longer than 1 frame
1665                console.warn(`⚠️ Slow updateSlider: ${duration}ms`);
1666            }
1667            
1668        } catch (error) {
1669            console.error('🚨 SLIDER CRASH: updateSlider failed:', error);
1670            console.error('🚨 SLIDER CRASH: Slider state during crash:', {
1671                currentSlide: this.currentSlide,
1672                slideCount: this.slideCount,
1673                isTransitioning: this.isTransitioning,
1674                sliderWrapper: !!this.sliderWrapper,
1675                sliderClasses: this.slider?.className
1676            });
1677            // Force reset transition state
1678            this.isTransitioning = false;
1679            if (this.transitionTimeoutId) {
1680                clearTimeout(this.transitionTimeoutId);
1681                this.activeTimeouts.delete(this.transitionTimeoutId);
1682                this.transitionTimeoutId = null;
1683            }
1684            this.handleCriticalError(error);
1685        }
1686    }
1687    
1688    /**
1689     * Calculate transform value based on slider type
1690     */
1691    calculateTransform() {
1692        try {
1693            const isVerticalSlider = this.slider.classList.contains('vertical-slider');
1694            const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
1695                                    this.slider.classList.contains('custom-cards-slider');
1696            
1697            if (isVerticalSlider) {
1698                // Vertical slider: move from bottom to top with centering support
1699                const slideHeight = this.getSlideHeight();
1700                const containerHeight = this.slider.offsetHeight || 600;
1701                let translateY = -this.currentSlide * slideHeight;
1702                
1703                // If centered, add offset to keep active slide in center
1704                if (this.isCentered) {
1705                    const centerOffset = (containerHeight - slideHeight) / 2;
1706                    translateY += centerOffset;
1707                }
1708                
1709                return {
1710                    success: true,
1711                    transform: `translateY(${translateY}px)`
1712                };
1713            } else if (isPackagesSlider) {
1714                const slideWidth = this.getSlideWidth();
1715                const containerWidth = this.slider.offsetWidth || 800;
1716                this.slidesPerView = Math.floor(containerWidth / slideWidth);
1717                
1718                let translateX;
1719                
1720                if (this.isCentered) {
1721                    // Centered mode: position active slide in center
1722                    this.centerOffset = (containerWidth - slideWidth) / 2;
1723                    translateX = -this.currentSlide * slideWidth + this.centerOffset;
1724                } else {
1725                    // Standard mode: align to left edge
1726                    const maxSlide = Math.max(0, this.slideCount - this.slidesPerView);
1727                    
1728                    // Ensure currentSlide doesn't exceed maxSlide
1729                    if (this.currentSlide > maxSlide) {
1730                        this.currentSlide = maxSlide;
1731                    }
1732                    
1733                    translateX = -this.currentSlide * slideWidth;
1734                }
1735                
1736                return {
1737                    success: true,
1738                    transform: `translateX(${translateX}px)`
1739                };
1740            } else {
1741                // Default behavior for banner-style sliders
1742                const translateX = -this.currentSlide * 100;
1743                return {
1744                    success: true,
1745                    transform: `translateX(${translateX}%)`
1746                };
1747            }
1748            
1749        } catch (error) {
1750            console.error('⚠️ Transform calculation error:', error);
1751            return { success: false, transform: null };
1752        }
1753    }
1754    
1755    /**
1756     * Update dots with enhanced error handling
1757     */
1758    updateDots() {
1759        try {
1760            if (!this.dots || this.dots.length === 0) {
1761                return;
1762            }
1763            
1764            let activeIndex = this.currentSlide;
1765            if (this.isInfiniteLoop) {
1766                // Calculate the actual slide index (excluding clones)
1767                activeIndex = (this.currentSlide - this.cloneCount + this.originalSlideCount) % this.originalSlideCount;
1768            }
1769            
1770            // Validate activeIndex
1771            if (activeIndex < 0 || activeIndex >= this.dots.length) {
1772                activeIndex = 0;
1773            }
1774            
1775            this.dots.forEach((dot, index) => {
1776                try {
1777                    if (dot && dot.classList) {
1778                        dot.classList.toggle('active', index === activeIndex);
1779                    }
1780                } catch (dotError) {
1781                    console.error(`⚠️ Error updating dot ${index}:`, dotError);
1782                }
1783            });
1784            
1785        } catch (error) {
1786            console.error('⚠️ Dots update error:', error);
1787        }
1788    }
1789    
1790    /**
1791     * Update active slide classes
1792     */
1793    updateActiveSlideClasses() {
1794        try {
1795            this.slides.forEach((slide, index) => {
1796                try {
1797                    if (slide && slide.classList) {
1798                        slide.classList.toggle('active', index === this.currentSlide);
1799                    }
1800                } catch (slideError) {
1801                    console.error(`⚠️ Error updating slide class ${index}:`, slideError);
1802                }
1803            });
1804        } catch (error) {
1805            console.error('⚠️ Active slide classes update error:', error);
1806        }
1807    }
1808    
1809    /**
1810     * Update ARIA attributes for accessibility
1811     */
1812    updateAriaAttributes() {
1813        try {
1814            this.slides.forEach((slide, index) => {
1815                try {
1816                    if (slide && slide.setAttribute) {
1817                        slide.setAttribute('aria-hidden', index !== this.currentSlide);
1818                    }
1819                } catch (ariaError) {
1820                    console.error(`⚠️ Error updating ARIA for slide ${index}:`, ariaError);
1821                }
1822            });
1823        } catch (error) {
1824            console.error('⚠️ ARIA attributes update error:', error);
1825        }
1826    }
1827    
1828    /**
1829     * Get slide width with caching and comprehensive error handling
1830     */
1831    getSlideWidth() {
1832        try {
1833            // Use cached value if available and valid
1834            if (this.cachedSlideWidth && this.lastWidthCheck && 
1835                (Date.now() - this.lastWidthCheck) < 1000) { // Cache for 1 second
1836                return this.cachedSlideWidth;
1837            }
1838            
1839            if (!this.slides || this.slides.length === 0) {
1840                console.warn('⚠️ No slides available for width calculation');
1841                return 380; // Default fallback
1842            }
1843            
1844            const firstSlide = this.slides[0];
1845            if (!firstSlide) {
1846                console.warn('⚠️ First slide not found');
1847                return 380;
1848            }
1849            
1850            let slideWidth = 380; // Safe default
1851            
1852            try {
1853                // Get computed styles with fallback
1854                const styles = window.getComputedStyle ? window.getComputedStyle(firstSlide) : null;
1855                
1856                if (styles) {
1857                    const marginLeft = parseFloat(styles.marginLeft) || 0;
1858                    const marginRight = parseFloat(styles.marginRight) || 0;
1859                    const offsetWidth = firstSlide.offsetWidth || 380;
1860                    
1861                    slideWidth = offsetWidth + marginLeft + marginRight;
1862                    
1863                    // Ensure reasonable bounds
1864                    slideWidth = Math.max(100, Math.min(2000, slideWidth));
1865                } else {
1866                    // Fallback if getComputedStyle not available
1867                    slideWidth = firstSlide.offsetWidth || 380;
1868                }
1869                
1870            } catch (styleError) {
1871                console.error('⚠️ Error calculating slide width:', styleError);
1872                slideWidth = firstSlide.offsetWidth || 380;
1873            }
1874            
1875            // Cache the result
1876            this.cachedSlideWidth = slideWidth;
1877            this.lastWidthCheck = Date.now();
1878            
1879            return slideWidth;
1880            
1881        } catch (error) {
1882            console.error('⚠️ getSlideWidth failed:', error);
1883            return 380; // Safe fallback
1884        }
1885    }
1886
1887    /**
1888     * Get slide height with caching and comprehensive error handling (for vertical sliders)
1889     */
1890    getSlideHeight() {
1891        try {
1892            // Use cached value if available and valid
1893            if (this.cachedSlideHeight && this.lastHeightCheck && 
1894                (Date.now() - this.lastHeightCheck) < 1000) { // Cache for 1 second
1895                return this.cachedSlideHeight;
1896            }
1897            
1898            if (!this.slides || this.slides.length === 0) {
1899                console.warn('⚠️ No slides available for height calculation');
1900                return 400; // Default fallback
1901            }
1902            
1903            const firstSlide = this.slides[0];
1904            if (!firstSlide) {
1905                console.warn('⚠️ First slide not found');
1906                return 400;
1907            }
1908            
1909            let slideHeight = 400; // Safe default
1910            
1911            try {
1912                // Get computed styles with fallback
1913                const styles = window.getComputedStyle ? window.getComputedStyle(firstSlide) : null;
1914                
1915                if (styles) {
1916                    const marginTop = parseFloat(styles.marginTop) || 0;
1917                    const marginBottom = parseFloat(styles.marginBottom) || 0;
1918                    const offsetHeight = firstSlide.offsetHeight || 400;
1919                    
1920                    slideHeight = offsetHeight + marginTop + marginBottom;
1921                    
1922                    // Ensure reasonable bounds
1923                    slideHeight = Math.max(100, Math.min(2000, slideHeight));
1924                } else {
1925                    // Fallback if getComputedStyle not available
1926                    slideHeight = firstSlide.offsetHeight || 400;
1927                }
1928                
1929            } catch (styleError) {
1930                console.error('⚠️ Error calculating slide height:', styleError);
1931                slideHeight = firstSlide.offsetHeight || 400;
1932            }
1933            
1934            // Cache the result
1935            this.cachedSlideHeight = slideHeight;
1936            this.lastHeightCheck = Date.now();
1937            
1938            return slideHeight;
1939            
1940        } catch (error) {
1941            console.error('⚠️ getSlideHeight failed:', error);
1942            return 400; // Safe fallback
1943        }
1944    }
1945
1946    nextSlide() {
1947        try {
1948            if (this.isTransitioning || this.isDestroyed) {
1949                return;
1950            }
1951            
1952            if (!this.slides || this.slides.length === 0) {
1953                console.warn('⚠️ nextSlide called with no slides');
1954                return;
1955            }
1956            
1957            const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
1958                                    this.slider.classList.contains('custom-cards-slider');
1959        
1960            if (this.isInfiniteLoop) {
1961                this.handleInfiniteNextSlide(isPackagesSlider);
1962            } else {
1963                this.handleNormalNextSlide(isPackagesSlider);
1964            }
1965            
1966        } catch (error) {
1967            console.error('🚨 SLIDER CRASH: nextSlide failed:', error);
1968            this.handleNavigationError(error, 'nextSlide');
1969        }
1970    }
1971    
1972    /**
1973     * Handle infinite loop next slide logic
1974     */
1975    handleInfiniteNextSlide(isPackagesSlider) {
1976        try {
1977            this.currentSlide++;
1978            this.updateSlider();
1979            
1980            // Check if we need to jump back to the beginning
1981            if (isPackagesSlider) {
1982                const maxSlideIndex = this.originalSlideCount + this.cloneCount;
1983                if (this.currentSlide >= maxSlideIndex) {
1984                    this.handleInfiniteLoopReset('next');
1985                }
1986            } else {
1987                if (this.currentSlide >= this.originalSlideCount + this.cloneCount) {
1988                    this.handleInfiniteLoopReset('next');
1989                }
1990            }
1991        } catch (error) {
1992            console.error('⚠️ Infinite next slide error:', error);
1993            throw error;
1994        }
1995    }
1996    
1997    /**
1998     * Handle normal next slide logic
1999     */
2000    handleNormalNextSlide(isPackagesSlider) {
2001        try {
2002            if (isPackagesSlider) {
2003                const slideWidth = this.getSlideWidth();
2004                const containerWidth = this.slider.offsetWidth || 800;
2005                const slidesPerView = Math.floor(containerWidth / slideWidth);
2006                const maxSlide = Math.max(0, this.slideCount - slidesPerView);
2007                
2008                if (this.currentSlide < maxSlide) {
2009                    this.currentSlide++;
2010                } else {
2011                    this.currentSlide = 0; // Loop back to start
2012                }
2013            } else {
2014                this.currentSlide = (this.currentSlide + 1) % this.slideCount;
2015            }
2016            this.updateSlider();
2017        } catch (error) {
2018            console.error('⚠️ Normal next slide error:', error);
2019            throw error;
2020        }
2021    }
2022    
2023    /**
2024     * Handle infinite loop reset with timeout management
2025     */
2026    handleInfiniteLoopReset(direction) {
2027        try {
2028            // Clear any existing infinite loop timeout to prevent conflicts
2029            if (this.infiniteLoopTimeoutId) {
2030                clearTimeout(this.infiniteLoopTimeoutId);
2031                this.activeTimeouts.delete(this.infiniteLoopTimeoutId);
2032            }
2033            
2034            // Determine reset delay based on slider type - much faster for vertical sliders
2035            const resetDelay = this.isVertical ? 5 : 500;
2036            
2037            this.infiniteLoopTimeoutId = this.safeSetTimeout(() => {
2038                try {
2039                    if (this.isDestroyed) return;
2040                    
2041                    this.sliderWrapper.style.transition = 'none';
2042                    
2043                    if (direction === 'next') {
2044                        this.currentSlide = this.cloneCount;
2045                    } else {
2046                        this.currentSlide = this.originalSlideCount + this.cloneCount - 1;
2047                    }
2048                    
2049                    this.updateSliderInstantly();
2050                    
2051                    // Re-enable transition for next slide - faster for vertical sliders
2052                    const transitionDelay = this.isVertical ? 5 : 50;
2053                    this.safeSetTimeout(() => {
2054                        if (!this.isDestroyed && this.sliderWrapper) {
2055                            this.sliderWrapper.style.transition = this.isVertical ? 
2056                                'transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94)' :
2057                                '';
2058                        }
2059                    }, transitionDelay, 'enable-transition');
2060                    
2061                    this.infiniteLoopTimeoutId = null;
2062                    
2063                } catch (resetError) {
2064                    console.error('⚠️ Infinite loop reset error:', resetError);
2065                    // Recovery: reset styles and position
2066                    if (this.sliderWrapper) {
2067                        this.sliderWrapper.style.transition = '';
2068                    }
2069                    this.currentSlide = this.cloneCount;
2070                    this.updateSlider();
2071                    this.infiniteLoopTimeoutId = null;
2072                }
2073            }, resetDelay, 'infinite-loop-reset');
2074            
2075        } catch (error) {
2076            console.error('⚠️ Infinite loop reset setup error:', error);
2077        }
2078    }
2079
2080    prevSlide() {
2081        try {
2082            if (this.isTransitioning || this.isDestroyed) {
2083                return;
2084            }
2085            
2086            if (!this.slides || this.slides.length === 0) {
2087                console.warn('⚠️ prevSlide called with no slides');
2088                return;
2089            }
2090            
2091            const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
2092                                    this.slider.classList.contains('custom-cards-slider');
2093        
2094            if (this.isInfiniteLoop) {
2095                this.handleInfinitePrevSlide(isPackagesSlider);
2096            } else {
2097                this.handleNormalPrevSlide(isPackagesSlider);
2098            }
2099            
2100        } catch (error) {
2101            console.error('🚨 SLIDER CRASH: prevSlide failed:', error);
2102            this.handleNavigationError(error, 'prevSlide');
2103        }
2104    }
2105    
2106    /**
2107     * Handle infinite loop prev slide logic
2108     */
2109    handleInfinitePrevSlide(isPackagesSlider) {
2110        try {
2111            this.currentSlide--;
2112            this.updateSlider();
2113            
2114            // Check if we've reached the cloned slides at the beginning
2115            if (this.currentSlide < this.cloneCount) {
2116                this.handleInfiniteLoopReset('prev');
2117            }
2118        } catch (error) {
2119            console.error('⚠️ Infinite prev slide error:', error);
2120            throw error;
2121        }
2122    }
2123    
2124    /**
2125     * Handle normal prev slide logic
2126     */
2127    handleNormalPrevSlide(isPackagesSlider) {
2128        try {
2129            if (isPackagesSlider) {
2130                const slideWidth = this.getSlideWidth();
2131                const containerWidth = this.slider.offsetWidth || 800;
2132                const slidesPerView = Math.floor(containerWidth / slideWidth);
2133                const maxSlide = Math.max(0, this.slideCount - slidesPerView);
2134                
2135                if (this.currentSlide > 0) {
2136                    this.currentSlide--;
2137                } else {
2138                    this.currentSlide = maxSlide; // Loop to end
2139                }
2140            } else {
2141                this.currentSlide = (this.currentSlide - 1 + this.slideCount) % this.slideCount;
2142            }
2143            this.updateSlider();
2144        } catch (error) {
2145            console.error('⚠️ Normal prev slide error:', error);
2146            throw error;
2147        }
2148    }
2149    
2150    /**
2151     * Handle navigation errors consistently
2152     */
2153    handleNavigationError(error, method) {
2154        console.error(`🚨 SLIDER CRASH: State during ${method} crash:`, {
2155            currentSlide: this.currentSlide,
2156            slideCount: this.slideCount,
2157            isInfiniteLoop: this.isInfiniteLoop,
2158            isTransitioning: this.isTransitioning,
2159            isDestroyed: this.isDestroyed
2160        });
2161        
2162        // Force reset transition state and attempt recovery
2163        this.isTransitioning = false;
2164        try {
2165            this.updateSlider();
2166        } catch (recoveryError) {
2167            console.error(`🚨 SLIDER CRASH: ${method} recovery attempt failed:`, recoveryError);
2168            this.handleCriticalError(recoveryError);
2169        }
2170    }
2171
2172    goToSlide(index) {
2173        try {
2174            if (this.isTransitioning) return;
2175            
2176            // Stop auto-slide temporarily when manually navigating
2177            this.stopAutoSlide();
2178        
2179        if (this.isInfiniteLoop) {
2180            // Convert logical index to actual slide position (accounting for clones)
2181            this.currentSlide = index + this.cloneCount;
2182        } else {
2183            if (index === this.currentSlide) return;
2184            this.currentSlide = index;
2185        }
2186        
2187        this.updateSlider();
2188        
2189        // Restart auto-slide after navigation  
2190        if (this.autoSlideTimeoutId) {
2191            clearTimeout(this.autoSlideTimeoutId);
2192        }
2193        
2194        this.autoSlideTimeoutId = setTimeout(() => {
2195            this.autoSlideTimeoutId = null;
2196            this.startAutoSlide();
2197        }, 1000); // Wait 1 second before resuming auto-slide
2198        } catch (error) {
2199            console.error('🚨 SLIDER CRASH: goToSlide failed:', error);
2200            console.error('🚨 SLIDER CRASH: State during goToSlide crash:', {
2201                targetIndex: index,
2202                currentSlide: this.currentSlide,
2203                slideCount: this.slideCount,
2204                isInfiniteLoop: this.isInfiniteLoop
2205            });
2206            // Force reset transition state
2207            this.isTransitioning = false;
2208        }
2209    }
2210
2211    updateSliderInstantly() {
2212        // Same as updateSlider but without transition effects
2213        if (!this.sliderWrapper) return;
2214
2215        const isVerticalSlider = this.slider.classList.contains('vertical-slider');
2216        const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
2217                                this.slider.classList.contains('custom-cards-slider');
2218        
2219        if (isVerticalSlider) {
2220            // Handle vertical slider transforms
2221            const slideHeight = this.getSlideHeight();
2222            const containerHeight = this.slider.offsetHeight || 600;
2223            
2224            // For centered vertical sliders, adjust the transform to account for centering
2225            let translateY = -this.currentSlide * slideHeight;
2226            
2227            // If centered, add offset to keep active slide in center
2228            if (this.isCentered) {
2229                const centerOffset = (containerHeight - slideHeight) / 2;
2230                translateY += centerOffset;
2231            }
2232            
2233            this.sliderWrapper.style.transform = `translateY(${translateY}px)`;
2234        } else if (isPackagesSlider) {
2235            const slideWidth = this.getSlideWidth();
2236            let translateX;
2237            
2238            if (this.isCentered) {
2239                const containerWidth = this.slider.offsetWidth;
2240                this.centerOffset = (containerWidth - slideWidth) / 2;
2241                translateX = -this.currentSlide * slideWidth + this.centerOffset;
2242            } else {
2243                translateX = -this.currentSlide * slideWidth;
2244            }
2245            
2246            this.sliderWrapper.style.transform = `translateX(${translateX}px)`;
2247        } else {
2248            const translateX = -this.currentSlide * 100;
2249            this.sliderWrapper.style.transform = `translateX(${translateX}%)`;
2250        }
2251
2252        // Update dots (only for actual slides, not clones)
2253        if (this.dots) {
2254            this.dots.forEach((dot, index) => {
2255                let activeIndex = this.currentSlide;
2256                if (this.isInfiniteLoop) {
2257                    activeIndex = (this.currentSlide - this.cloneCount + this.originalSlideCount) % this.originalSlideCount;
2258                }
2259                dot.classList.toggle('active', index === activeIndex);
2260            });
2261        }
2262
2263        // Update active slide class for centered mode
2264        if (this.isCentered) {
2265            this.slides.forEach((slide, index) => {
2266                slide.classList.toggle('active', index === this.currentSlide);
2267            });
2268        }
2269    }
2270
2271    startAutoSlide() {
2272        try {
2273            if (this.slideCount <= 1) return;
2274            this.stopAutoSlide();
2275            
2276            this.autoSlideInterval = setInterval(() => {
2277                try {
2278                    this.nextSlide();
2279                } catch (error) {
2280                    console.error('🚨 SLIDER CRASH: Auto-slide nextSlide failed:', error);
2281                    // Stop auto-slide on repeated failures
2282                    this.stopAutoSlide();
2283                }
2284            }, this.autoSlideTime);
2285        } catch (error) {
2286            console.error('🚨 SLIDER CRASH: startAutoSlide failed:', error);
2287            console.error('🚨 SLIDER CRASH: Auto-slide state:', {
2288                slideCount: this.slideCount,
2289                autoSlideTime: this.autoSlideTime,
2290                currentSlide: this.currentSlide
2291            });
2292        }
2293    }
2294
2295    stopAutoSlide() {
2296        if (this.autoSlideInterval) {
2297            clearInterval(this.autoSlideInterval);
2298            this.autoSlideInterval = null;
2299        }
2300    }
2301
2302    handleTouchStart(e) {
2303        try {
2304            // Don't start drag if touching links or buttons
2305            if (e.target.closest('a') || 
2306                e.target.tagName === 'A' ||
2307                e.target.closest('button') ||
2308                e.target.tagName === 'BUTTON' ||
2309                e.target.classList.contains('dot') ||
2310                e.target.classList.contains('slider-btn')) {
2311                return;
2312            }
2313            const isVerticalSlider = this.slider.classList.contains('vertical-slider');
2314            if (isVerticalSlider) {
2315                this.startDrag(e.touches[0].clientY);
2316            } else {
2317                this.startDrag(e.touches[0].clientX);
2318            }
2319        } catch (error) {
2320            console.error('🚨 SLIDER CRASH: handleTouchStart failed:', error);
2321            console.error('🚨 SLIDER CRASH: Touch event details:', {
2322                touchesLength: e?.touches?.length,
2323                targetElement: e?.target?.tagName,
2324                targetClass: e?.target?.className
2325            });
2326        }
2327    }
2328
2329    handleTouchMove(e) {
2330        try {
2331            if (!this.isDragging) return;
2332            e.preventDefault();
2333            const isVerticalSlider = this.slider.classList.contains('vertical-slider');
2334            if (isVerticalSlider) {
2335                this.updateDrag(e.touches[0].clientY);
2336            } else {
2337                this.updateDrag(e.touches[0].clientX);
2338            }
2339        } catch (error) {
2340            console.error('🚨 SLIDER CRASH: handleTouchMove failed:', error);
2341            this.isDragging = false;
2342        }
2343    }
2344
2345    handleTouchEnd(e) {
2346        try {
2347            if (!this.isDragging) return;
2348            const isVerticalSlider = this.slider.classList.contains('vertical-slider');
2349            if (isVerticalSlider) {
2350                this.endDrag(e.changedTouches[0].clientY);
2351            } else {
2352                this.endDrag(e.changedTouches[0].clientX);
2353            }
2354        } catch (error) {
2355            console.error('🚨 SLIDER CRASH: handleTouchEnd failed:', error);
2356            this.isDragging = false;
2357        }
2358    }
2359
2360    handleMouseStart(e) {
2361        try {
2362            // Don't start drag if clicking on dots, buttons, or links
2363            if (e.target.classList.contains('dot') || 
2364                e.target.classList.contains('slider-btn') ||
2365                e.target.closest('.slider-dots') ||
2366                e.target.closest('.slider-navigation') ||
2367                e.target.closest('a') || // Allow clicks on links
2368                e.target.tagName === 'A' || // Direct anchor tags
2369                e.target.closest('button') || // Allow clicks on buttons
2370                e.target.tagName === 'BUTTON') { // Direct button tags
2371                return;
2372            }
2373            
2374            e.preventDefault();
2375            const isVerticalSlider = this.slider.classList.contains('vertical-slider');
2376            if (isVerticalSlider) {
2377                this.startDrag(e.clientY);
2378            } else {
2379                this.startDrag(e.clientX);
2380            }
2381        } catch (error) {
2382            console.error('🚨 SLIDER CRASH: handleMouseStart failed:', error);
2383            console.error('🚨 SLIDER CRASH: Mouse event details:', {
2384                clientX: e?.clientX,
2385                targetElement: e?.target?.tagName,
2386                targetClass: e?.target?.className
2387            });
2388        }
2389    }
2390
2391    handleMouseMove(e) {
2392        try {
2393            if (!this.isDragging) return;
2394            e.preventDefault();
2395            const isVerticalSlider = this.slider.classList.contains('vertical-slider');
2396            if (isVerticalSlider) {
2397                this.updateDrag(e.clientY);
2398            } else {
2399                this.updateDrag(e.clientX);
2400            }
2401        } catch (error) {
2402            console.error('🚨 SLIDER CRASH: handleMouseMove failed:', error);
2403            this.isDragging = false;
2404        }
2405    }
2406
2407    handleMouseEnd(e) {
2408        try {
2409            if (!this.isDragging) return;
2410            const isVerticalSlider = this.slider.classList.contains('vertical-slider');
2411            if (isVerticalSlider) {
2412                this.endDrag(e.clientY);
2413            } else {
2414                this.endDrag(e.clientX);
2415            }
2416        } catch (error) {
2417            console.error('🚨 SLIDER CRASH: handleMouseEnd failed:', error);
2418            this.isDragging = false;
2419        }
2420    }
2421
2422    startDrag(clientPos) {
2423        try {
2424            this.isDragging = true;
2425            const isVerticalSlider = this.slider.classList.contains('vertical-slider');
2426            
2427            if (isVerticalSlider) {
2428                this.startY = clientPos;
2429                // Get current transform value for vertical slider
2430                const slideHeight = this.getSlideHeight();
2431                this.startTransform = -this.currentSlide * slideHeight;
2432            } else {
2433                this.startX = clientPos;
2434                // Get current transform value for horizontal slider
2435                const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
2436                                        this.slider.classList.contains('custom-cards-slider');
2437                
2438                if (isPackagesSlider) {
2439                    const slideWidth = this.getSlideWidth();
2440                    this.startTransform = -this.currentSlide * slideWidth;
2441                } else {
2442                    this.startTransform = -this.currentSlide * 100;
2443                }
2444            }
2445            
2446            this.stopAutoSlide();
2447            this.currentTransform = this.startTransform;
2448        
2449            // Disable CSS transitions during drag
2450            this.sliderWrapper.style.transition = 'none';
2451            
2452            // Add dragging class for cursor changes
2453            this.slider.classList.add('dragging');
2454        } catch (error) {
2455            console.error('🚨 SLIDER CRASH: startDrag failed:', error);
2456            this.isDragging = false;
2457        }
2458    }
2459
2460    updateDrag(clientPos) {
2461        try {
2462            if (!this.isDragging) return;
2463        
2464            const isVerticalSlider = this.slider.classList.contains('vertical-slider');
2465            
2466            if (isVerticalSlider) {
2467                // Handle vertical dragging
2468                const deltaY = clientPos - this.startY;
2469                this.currentTransform = this.startTransform + deltaY;
2470                this.sliderWrapper.style.transform = `translateY(${this.currentTransform}px)`;
2471            } else {
2472                // Handle horizontal dragging
2473                const deltaX = clientPos - this.startX;
2474                const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
2475                                        this.slider.classList.contains('custom-cards-slider');
2476                
2477                if (isPackagesSlider) {
2478                    // For packages slider, translate by pixel amount
2479                    this.currentTransform = this.startTransform + deltaX;
2480                    this.sliderWrapper.style.transform = `translateX(${this.currentTransform}px)`;
2481                } else {
2482                    // For banner slider, convert pixels to percentage
2483                    const containerWidth = this.slider.offsetWidth;
2484                    const deltaPercentage = (deltaX / containerWidth) * 100;
2485                    this.currentTransform = this.startTransform + deltaPercentage;
2486                    this.sliderWrapper.style.transform = `translateX(${this.currentTransform}%)`;
2487                }
2488            }
2489        } catch (error) {
2490            console.error('🚨 SLIDER CRASH: updateDrag failed:', error);
2491            this.isDragging = false;
2492        }
2493    }
2494
2495    endDrag(clientPos) {
2496        try {
2497            if (!this.isDragging) return;
2498            
2499            this.isDragging = false;
2500            const isVerticalSlider = this.slider.classList.contains('vertical-slider');
2501            
2502            // Re-enable CSS transitions
2503            this.sliderWrapper.style.transition = '';
2504            this.slider.classList.remove('dragging');
2505            
2506            if (isVerticalSlider) {
2507                // Handle vertical slider direction
2508                this.endY = clientPos;
2509                const deltaY = this.startY - this.endY;
2510                const threshold = 50; // Minimum drag distance to trigger slide change
2511                
2512                if (Math.abs(deltaY) > threshold) {
2513                    if (deltaY > 0) {
2514                        // Swiped up = next slide (move from bottom to top)
2515                        this.nextSlide();
2516                    } else {
2517                        // Swiped down = previous slide 
2518                        this.prevSlide();
2519                    }
2520                } else {
2521                    // Snap back to current slide
2522                    this.updateSlider();
2523                }
2524                
2525                // Reset values for vertical slider
2526                this.startY = 0;
2527                this.endY = 0;
2528            } else {
2529                // Handle horizontal slider (existing logic)
2530                this.endX = clientPos;
2531                const deltaX = this.startX - this.endX;
2532                
2533                const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
2534                                        this.slider.classList.contains('custom-cards-slider');
2535                
2536                if (this.isCentered && isPackagesSlider) {
2537                    // For centered mode, snap to the nearest slide
2538                    const slideWidth = this.getSlideWidth();
2539                    const dragDistance = Math.abs(deltaX);
2540                    const threshold = slideWidth * 0.2; // 20% of slide width to trigger change
2541                    
2542                    if (dragDistance > threshold) {
2543                        if (deltaX > 0) {
2544                            this.nextSlide();
2545                        } else {
2546                            this.prevSlide();
2547                        }
2548                    } else {
2549                        // Snap back to current slide
2550                        this.updateSlider();
2551                    }
2552                } else {
2553                    // Standard behavior
2554                    const threshold = 50; // Minimum drag distance to trigger slide change
2555                    
2556                    if (Math.abs(deltaX) > threshold) {
2557                        if (deltaX > 0) {
2558                            this.nextSlide();
2559                        } else {
2560                            this.prevSlide();
2561                        }
2562                    } else {
2563                        // Snap back to current slide
2564                        this.updateSlider();
2565                    }
2566                }
2567                
2568                // Reset values for horizontal slider
2569                this.startX = 0;
2570                this.endX = 0;
2571            }
2572            
2573            this.startTransform = 0;
2574            this.currentTransform = 0;
2575            
2576            // Restart auto-slide
2577            this.startAutoSlide();
2578        } catch (error) {
2579            console.error('🚨 SLIDER CRASH: endDrag failed:', error);
2580            // Force cleanup on error
2581            this.isDragging = false;
2582            this.slider.classList.remove('dragging');
2583            this.sliderWrapper.style.transition = '';
2584            this.startX = 0;
2585            this.endX = 0;
2586            this.startY = 0;
2587            this.endY = 0;
2588            this.startTransform = 0;
2589            this.currentTransform = 0;
2590            this.startAutoSlide();
2591        }
2592    }
2593
2594    handleKeyboard(e) {
2595        try {
2596            switch (e.key) {
2597                case 'ArrowLeft':
2598                    e.preventDefault();
2599                    this.prevSlide();
2600                    break;
2601                case 'ArrowRight':
2602                    e.preventDefault();
2603                    this.nextSlide();
2604                    break;
2605                case ' ':
2606                    e.preventDefault();
2607                    if (this.autoSlideInterval) {
2608                        this.stopAutoSlide();
2609                    } else {
2610                        this.startAutoSlide();
2611                    }
2612                    break;
2613            }
2614        } catch (error) {
2615            console.error('🚨 SLIDER CRASH: handleKeyboard failed:', error);
2616            console.error('🚨 SLIDER CRASH: Keyboard event details:', {
2617                key: e?.key,
2618                keyCode: e?.keyCode,
2619                autoSlideActive: !!this.autoSlideInterval
2620            });
2621        }
2622    }
2623
2624    /**
2625     * Enhanced destroy method with comprehensive cleanup and memory leak prevention
2626     */
2627    destroy() {
2628        try {
2629            console.info('ℹ️ Destroying slider instance');
2630            
2631            // Prevent multiple destroy calls
2632            if (this.isDestroyed) {
2633                console.warn('⚠️ Slider already destroyed');
2634                return;
2635            }
2636            
2637            this.isDestroyed = true;
2638            
2639            // Stop all auto-slide activities
2640            this.stopAutoSlide();
2641            
2642            // Clear ALL timeouts comprehensively
2643            this.clearAllTimeouts();
2644            
2645            // Reset transition flag to prevent getting stuck
2646            this.isTransitioning = false;
2647            
2648            // Enhanced intersection observer cleanup
2649            if (this.imageObserver) {
2650                try {
2651                    this.imageObserver.disconnect();
2652                    this.imageObserver = null;
2653                } catch (observerError) {
2654                    console.error('⚠️ Error disconnecting image observer:', observerError);
2655                }
2656            }
2657            
2658            // Clear image caches and sets
2659            if (this.loadedImages) {
2660                this.loadedImages.clear();
2661                this.loadedImages = null;
2662            }
2663            if (this.loadingImages) {
2664                this.loadingImages.clear();
2665                this.loadingImages = null;
2666            }
2667            if (this.priorityImages) {
2668                this.priorityImages.clear();
2669                this.priorityImages = null;
2670            }
2671            if (this.failedImages) {
2672                this.failedImages.clear();
2673                this.failedImages = null;
2674            }
2675            
2676            // Reset all initialization flags
2677            this.infiniteLoopSetup = false;
2678            this.navigationCreated = false;
2679            this.dotsCreated = false;
2680            
2681            // Enhanced DOM cleanup with error handling
2682            this.cleanupDOMElements();
2683            
2684            // Enhanced event listener cleanup
2685            this.removeAllEventListeners();
2686            
2687            // Reset slider wrapper styles safely
2688            if (this.sliderWrapper && this.sliderWrapper.style) {
2689                try {
2690                    this.sliderWrapper.style.transform = '';
2691                    this.sliderWrapper.style.transition = '';
2692                } catch (styleError) {
2693                    console.error('⚠️ Error resetting wrapper styles:', styleError);
2694                }
2695            }
2696            
2697            // Reset slider element safely
2698            if (this.slider) {
2699                try {
2700                    this.slider.classList.remove('initialized', 'dragging');
2701                    this.slider.removeAttribute('tabindex');
2702                    this.slider.setAttribute('data-slider-status', 'destroyed');
2703                } catch (sliderError) {
2704                    console.error('⚠️ Error resetting slider element:', sliderError);
2705                }
2706            }
2707            
2708            // Remove from global instance tracking
2709            if (typeof window !== 'undefined' && window.sliderInstances && window.sliderInstances.has && window.sliderInstances.has(this.slider)) {
2710                try {
2711                    window.sliderInstances.delete(this.slider);
2712                } catch (globalError) {
2713                    console.error('⚠️ Error removing from global instances:', globalError);
2714                }
2715            }
2716            
2717            // Clear references to DOM elements
2718            this.slider = null;
2719            this.sliderWrapper = null;
2720            this.slides = null;
2721            this.dots = null;
2722            this.prevBtn = null;
2723            this.nextBtn = null;
2724            
2725            console.info('✅ Slider destroyed successfully');
2726            
2727        } catch (error) {
2728            console.error('🚨 Error during slider destruction:', error);
2729            // Force cleanup on error
2730            this.isDestroyed = true;
2731            this.isTransitioning = false;
2732        }
2733    }
2734    
2735    /**
2736     * Clean up DOM elements created by the slider
2737     */
2738    cleanupDOMElements() {
2739        try {
2740            if (!this.slider) return;
2741            
2742            // Remove navigation elements
2743            const navigations = this.slider.querySelectorAll('.slider-navigation');
2744            navigations.forEach(nav => {
2745                try {
2746                    nav.remove();
2747                } catch (navError) {
2748                    console.error('⚠️ Error removing navigation:', navError);
2749                }
2750            });
2751            
2752            // Remove dot containers
2753            const dotContainers = this.slider.querySelectorAll('.slider-dots');
2754            dotContainers.forEach(dots => {
2755                try {
2756                    dots.remove();
2757                } catch (dotError) {
2758                    console.error('⚠️ Error removing dots:', dotError);
2759                }
2760            });
2761            
2762            // Remove cloned slides
2763            const clonedSlides = this.slider.querySelectorAll('.slide-clone');
2764            clonedSlides.forEach(clone => {
2765                try {
2766                    clone.remove();
2767                } catch (cloneError) {
2768                    console.error('⚠️ Error removing clone:', cloneError);
2769                }
2770            });
2771            
2772        } catch (error) {
2773            console.error('⚠️ DOM cleanup error:', error);
2774        }
2775    }
2776    
2777    /**
2778     * Remove all event listeners comprehensively
2779     */
2780    removeAllEventListeners() {
2781        try {
2782            // Remove button event listeners
2783            if (this.prevBtn) {
2784                this.prevBtn.removeEventListener('click', this.prevSlideHandler);
2785            }
2786            if (this.nextBtn) {
2787                this.nextBtn.removeEventListener('click', this.nextSlideHandler);
2788            }
2789            
2790            // Remove dot event listeners
2791            if (this.dots) {
2792                this.dots.forEach((dot, index) => {
2793                    if (dot && dot.removeEventListener) {
2794                        dot.removeEventListener('click', this.dotClickHandlers?.[index]);
2795                        dot.removeEventListener('mousedown', this.dotMousedownHandlers?.[index]);
2796                    }
2797                });
2798            }
2799            
2800            // Remove slider event listeners
2801            if (this.slider) {
2802                this.slider.removeEventListener('mouseenter', this.mouseEnterHandler);
2803                this.slider.removeEventListener('mouseleave', this.mouseLeaveHandler);
2804                this.slider.removeEventListener('touchstart', this.touchStartHandler);
2805                this.slider.removeEventListener('touchmove', this.touchMoveHandler);
2806                this.slider.removeEventListener('touchend', this.touchEndHandler);
2807                this.slider.removeEventListener('mousedown', this.mouseDownHandler);
2808                this.slider.removeEventListener('mousemove', this.mouseMoveHandler);
2809                this.slider.removeEventListener('mouseup', this.mouseUpHandler);
2810                this.slider.removeEventListener('mouseleave', this.mouseLeaveHandler);
2811                this.slider.removeEventListener('keydown', this.keydownHandler);
2812            }
2813            
2814            // Clear handler references
2815            this.prevSlideHandler = null;
2816            this.nextSlideHandler = null;
2817            this.dotClickHandlers = null;
2818            this.dotMousedownHandlers = null;
2819            this.mouseEnterHandler = null;
2820            this.mouseLeaveHandler = null;
2821            this.touchStartHandler = null;
2822            this.touchMoveHandler = null;
2823            this.touchEndHandler = null;
2824            this.mouseDownHandler = null;
2825            this.mouseMoveHandler = null;
2826            this.mouseUpHandler = null;
2827            this.keydownHandler = null;
2828            
2829        } catch (error) {
2830            console.error('⚠️ Event listener cleanup error:', error);
2831        }
2832    }
2833
2834    /**
2835     * Get performance metrics for debugging
2836     */
2837    getPerformanceMetrics() {
2838        return {
2839            totalSlides: this.slideCount,
2840            loadedImages: this.loadedImages.size,
2841            loadingImages: this.loadingImages.size,
2842            priorityImages: this.priorityImages.size,
2843            lazyLoadEnabled: this.lazyLoadEnabled,
2844            isInViewport: this.isInViewport,
2845            initialized: this.initialized,
2846            currentSlide: this.currentSlide
2847        };
2848    }
2849}
2850
2851// Auto-initialize all custom sliders with lazy loading optimization
2852function initCustomSliders() {
2853    try {
2854        // Find all sliders (check both initialized and uninitialized)
2855        const allSliders = document.querySelectorAll('.custom-slider');
2856        const sliderInstances = [];
2857        
2858
2859        
2860        // COMPREHENSIVE CLEANUP - Force destroy existing instances and clean DOM
2861        allSliders.forEach((slider, index) => {
2862
2863            
2864            // Force destroy existing instance if it exists
2865            if (window.sliderInstances && window.sliderInstances.has(slider)) {
2866
2867                const existingInstance = window.sliderInstances.get(slider);
2868                existingInstance.destroy();
2869                window.sliderInstances.delete(slider);
2870            }
2871            
2872            // Force remove initialized class
2873            slider.classList.remove('initialized');
2874            
2875            // AGGRESSIVE DOM CLEANUP - Remove ALL generated elements
2876            const navigations = slider.querySelectorAll('.slider-navigation');
2877            const dotContainers = slider.querySelectorAll('.slider-dots');
2878            const clonedSlides = slider.querySelectorAll('.slide-clone');
2879            
2880            navigations.forEach(nav => {
2881
2882                nav.remove();
2883            });
2884            
2885            dotContainers.forEach(dots => {
2886
2887                dots.remove();
2888            });
2889            
2890            clonedSlides.forEach(clone => {
2891
2892                clone.remove();
2893            });
2894            
2895            // Reset wrapper styles
2896            const wrapper = slider.querySelector('.slider-wrapper');
2897            if (wrapper) {
2898                wrapper.style.transform = '';
2899                wrapper.style.transition = '';
2900            }
2901            
2902            // Remove slider-specific attributes and classes
2903            slider.removeAttribute('tabindex');
2904            slider.classList.remove('dragging');
2905            
2906
2907        });
2908        
2909        // Wait a moment for DOM cleanup to complete
2910        setTimeout(() => {
2911            // Now find sliders that need initialization with enhanced validation
2912            const potentialSliders = document.querySelectorAll('.custom-slider:not(.initialized)');
2913            const validSliders = [];
2914            
2915            // Filter and validate slider elements
2916            potentialSliders.forEach((element, index) => {
2917                try {
2918                    if (!element) {
2919                        console.warn(`⚠️ Found null/undefined slider at index ${index}`);
2920                        return;
2921                    }
2922                    
2923                    // Check if it's a valid HTMLElement (with cross-context support)
2924                    const isValidHTMLElement = (
2925                        element instanceof HTMLElement ||
2926                        (
2927                            element && 
2928                            typeof element === 'object' &&
2929                            element.nodeType === 1 && // ELEMENT_NODE
2930                            (typeof element.tagName === 'string' || typeof element.nodeName === 'string') &&
2931                            typeof element.classList === 'object' &&
2932                            element.classList !== null &&
2933                            typeof element.querySelector === 'function'
2934                        )
2935                    );
2936                    
2937                    if (!isValidHTMLElement) {
2938                        console.error(`🚨 Invalid slider element at index ${index}:`, {
2939                            type: typeof element,
2940                            nodeType: element?.nodeType,
2941                            nodeName: element?.nodeName,
2942                            constructor: element?.constructor?.name,
2943                            element: element
2944                        });
2945                        return;
2946                    }
2947                    
2948                    // Additional validation checks
2949                    if (!element.classList || typeof element.classList.contains !== 'function') {
2950                        console.error(`🚨 Slider element missing classList at index ${index}:`, element);
2951                        return;
2952                    }
2953                    
2954                    // Check for required wrapper
2955                    const wrapper = element.querySelector('.slider-wrapper');
2956                    if (!wrapper) {
2957                        console.warn(`⚠️ Slider at index ${index} missing .slider-wrapper, skipping initialization`);
2958                        return;
2959                    }
2960                    
2961                    // Check for slides
2962                    const slides = element.querySelectorAll('.slide');
2963                    if (slides.length === 0) {
2964                        console.info(`ℹ️ Slider at index ${index} has no slides, but will still initialize`);
2965                    }
2966                    
2967                    validSliders.push(element);
2968                    
2969                } catch (validationError) {
2970                    console.error(`🚨 Error validating slider element at index ${index}:`, validationError);
2971                }
2972            });
2973            
2974            console.info(`ℹ️ Found ${validSliders.length} valid sliders out of ${potentialSliders.length} potential sliders`);
2975
2976            // Lazy initialization using Intersection Observer for better performance
2977            if ('IntersectionObserver' in window && validSliders.length > 0) {
2978                const initObserver = new IntersectionObserver((entries) => {
2979                    entries.forEach(entry => {
2980                        if (entry.isIntersecting) {
2981                            const slider = entry.target;
2982                            
2983                            // Double-check element validity before initialization (cross-context support)
2984                            const isValidElement = (
2985                                slider instanceof HTMLElement ||
2986                                (
2987                                    slider && 
2988                                    typeof slider === 'object' &&
2989                                    slider.nodeType === 1 &&
2990                                    (typeof slider.tagName === 'string' || typeof slider.nodeName === 'string') &&
2991                                    typeof slider.classList === 'object' &&
2992                                    slider.classList !== null &&
2993                                    typeof slider.querySelector === 'function'
2994                                )
2995                            );
2996                            
2997                            if (!isValidElement) {
2998                                console.error('🚨 Non-HTMLElement detected during intersection:', slider);
2999                                return;
3000                            }
3001                            
3002                            try {
3003                                const instance = new CustomSlider(slider);
3004                                sliderInstances.push(instance);
3005                                window.sliderInstances.set(slider, instance);
3006                                slider.classList.add('initialized');
3007                                initObserver.unobserve(slider); // Stop observing once initialized
3008                                
3009                                console.info('✅ Slider initialized successfully via intersection observer');
3010                            } catch (error) {
3011                                console.error('🚨 Failed to initialize slider via intersection observer:', error);
3012                                console.error('🚨 Problematic slider element:', {
3013                                    element: slider,
3014                                    className: slider?.className,
3015                                    tagName: slider?.tagName,
3016                                    isHTMLElement: slider instanceof HTMLElement
3017                                });
3018                            }
3019                        }
3020                    });
3021                }, {
3022                    root: null,
3023                    rootMargin: '100px', // Start loading 100px before entering viewport
3024                    threshold: 0.1
3025                });
3026
3027                // Observe all valid sliders for lazy initialization
3028                validSliders.forEach((slider, index) => {
3029                    try {
3030                        // Final validation before observing (cross-context support)
3031                        const isValidElement = (
3032                            slider instanceof HTMLElement ||
3033                            (
3034                                slider && 
3035                                typeof slider === 'object' &&
3036                                slider.nodeType === 1 &&
3037                                (typeof slider.tagName === 'string' || typeof slider.nodeName === 'string') &&
3038                                typeof slider.classList === 'object' &&
3039                                slider.classList !== null &&
3040                                typeof slider.querySelector === 'function'
3041                            )
3042                        );
3043                        
3044                        if (!isValidElement) {
3045                            console.error(`🚨 Invalid element detected before observing at index ${index}:`, slider);
3046                            return;
3047                        }
3048                        
3049                        // Check if slider is already in viewport
3050                        const rect = slider.getBoundingClientRect();
3051                        const isInViewport = (
3052                            rect.top >= -100 &&
3053                            rect.left >= -100 &&
3054                            rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) + 100 &&
3055                            rect.right <= (window.innerWidth || document.documentElement.clientWidth) + 100
3056                        );
3057
3058                        if (isInViewport) {
3059                            // Initialize immediately if already visible
3060                            console.info(`ℹ️ Initializing visible slider ${index + 1}/${validSliders.length}`);
3061                            try {
3062                                const instance = new CustomSlider(slider);
3063                                sliderInstances.push(instance);
3064                                window.sliderInstances.set(slider, instance);
3065                                slider.classList.add('initialized');
3066                                console.info('✅ Visible slider initialized successfully');
3067                            } catch (error) {
3068                                console.error('🚨 Failed to initialize visible slider:', error);
3069                                console.error('🚨 Problematic slider element:', {
3070                                    element: slider,
3071                                    className: slider?.className,
3072                                    tagName: slider?.tagName,
3073                                    isHTMLElement: slider instanceof HTMLElement
3074                                });
3075                            }
3076                        } else {
3077                            // Use intersection observer for off-screen sliders
3078                            initObserver.observe(slider);
3079                        }
3080                    } catch (observeError) {
3081                        console.error(`🚨 Error setting up observation for slider ${index}:`, observeError);
3082                    }
3083                });
3084            } else {
3085                // Fallback: Initialize all sliders immediately if no Intersection Observer
3086                console.info('ℹ️ IntersectionObserver not available, initializing all sliders immediately');
3087                validSliders.forEach((slider, index) => {
3088                    try {
3089                        // Final validation before initialization (cross-context support)
3090                        const isValidElement = (
3091                            slider instanceof HTMLElement ||
3092                            (
3093                                slider && 
3094                                typeof slider === 'object' &&
3095                                slider.nodeType === 1 &&
3096                                (typeof slider.tagName === 'string' || typeof slider.nodeName === 'string') &&
3097                                typeof slider.classList === 'object' &&
3098                                slider.classList !== null &&
3099                                typeof slider.querySelector === 'function'
3100                            )
3101                        );
3102                        
3103                        if (!isValidElement) {
3104                            console.error(`🚨 Invalid element detected during fallback initialization at index ${index}:`, slider);
3105                            return;
3106                        }
3107                        
3108                        console.info(`ℹ️ Initializing slider ${index + 1}/${validSliders.length}`);
3109                        const instance = new CustomSlider(slider);
3110                        sliderInstances.push(instance);
3111                        window.sliderInstances.set(slider, instance);
3112                        slider.classList.add('initialized');
3113                        console.info('✅ Slider initialized successfully via fallback');
3114                    } catch (error) {
3115                        console.error(`🚨 Failed to initialize slider ${index + 1}:`, error);
3116                        console.error('🚨 Problematic slider element:', {
3117                            element: slider,
3118                            className: slider?.className,
3119                            tagName: slider?.tagName,
3120                            isHTMLElement: slider instanceof HTMLElement
3121                        });
3122                    }
3123                });
3124            }
3125            }, 50); // Small delay to ensure DOM cleanup
3126        
3127    } catch (error) {
3128        console.error('🚨 SLIDER CRASH: initCustomSliders failed:', error);
3129        console.error('🚨 SLIDER CRASH: Global initialization state:', {
3130            totalSliders: document.querySelectorAll('.custom-slider').length,
3131            uninitializedSliders: document.querySelectorAll('.custom-slider:not(.initialized)').length,
3132            hasIntersectionObserver: 'IntersectionObserver' in window
3133        });
3134        return [];
3135    }
3136}
3137
3138// Global slider instance tracking
3139if (typeof window !== 'undefined') {
3140    window.sliderInstances = window.sliderInstances || new Map();
3141}
3142
3143// Global function for manual initialization
3144window.initCustomSlider = function (element) {
3145    try {
3146        // Enhanced element validation (cross-context support)
3147        if (!element) {
3148            console.error('🚨 initCustomSlider: No element provided');
3149            return null;
3150        }
3151        
3152        const isValidHTMLElement = (
3153            element instanceof HTMLElement ||
3154            (
3155                element && 
3156                typeof element === 'object' &&
3157                element.nodeType === 1 && // ELEMENT_NODE
3158                (typeof element.tagName === 'string' || typeof element.nodeName === 'string') &&
3159                typeof element.classList === 'object' &&
3160                element.classList !== null &&
3161                typeof element.querySelector === 'function'
3162            )
3163        );
3164        
3165        if (!isValidHTMLElement) {
3166            console.error('🚨 initCustomSlider: Invalid element provided:', {
3167                received: element,
3168                type: typeof element,
3169                nodeType: element?.nodeType,
3170                nodeName: element?.nodeName,
3171                constructor: element?.constructor?.name,
3172                isNode: element instanceof Node,
3173                isElement: element instanceof Element,
3174                isHTMLElement: element instanceof HTMLElement
3175            });
3176            return null;
3177        }
3178        
3179        // Check if slider already has an instance
3180        if (window.sliderInstances && window.sliderInstances.has(element)) {
3181            console.info('ℹ️ Destroying existing slider instance');
3182            try {
3183                const existingInstance = window.sliderInstances.get(element);
3184                existingInstance.destroy();
3185                window.sliderInstances.delete(element);
3186            } catch (destroyError) {
3187                console.error('⚠️ Error destroying existing instance:', destroyError);
3188            }
3189        }
3190        
3191        console.info('ℹ️ Creating new slider instance');
3192        const instance = new CustomSlider(element);
3193        
3194        if (window.sliderInstances) {
3195            window.sliderInstances.set(element, instance);
3196        }
3197        
3198        console.info('✅ Manual slider initialization successful');
3199        return instance;
3200    } catch (error) {
3201        console.error('🚨 SLIDER CRASH: Manual initialization failed:', error);
3202        console.error('🚨 SLIDER CRASH: Element details:', {
3203            element: element,
3204            className: element?.className,
3205            tagName: element?.tagName,
3206            isHTMLElement: element instanceof HTMLElement
3207        });
3208        return null;
3209    }
3210};
3211
3212// Global function to manually initialize all sliders (for debugging)
3213window.initAllSliders = function() {
3214    try {
3215        console.info('ℹ️ Manual initialization of all sliders requested');
3216        
3217        // Pre-validate environment
3218        if (typeof document === 'undefined') {
3219            console.error('🚨 Document not available');
3220            return [];
3221        }
3222        
3223        if (!document.querySelectorAll) {
3224            console.error('🚨 querySelectorAll not supported');
3225            return [];
3226        }
3227        
3228        return initCustomSliders();
3229    } catch (error) {
3230        console.error('🚨 SLIDER CRASH: Manual initialization of all sliders failed:', error);
3231        return [];
3232    }
3233};
3234
3235// Global function to force reinitialize all sliders (destroys existing first)
3236window.reinitializeAllSliders = function() {
3237    try {
3238        console.info('ℹ️ Force reinitializing all sliders');
3239        
3240        // Pre-validate environment
3241        if (typeof document === 'undefined' || !document.querySelectorAll) {
3242            console.error('🚨 DOM not available for reinitialization');
3243            return [];
3244        }
3245        
3246        // Force remove initialized class from all sliders to ensure reinit
3247        const allSliders = document.querySelectorAll('.custom-slider');
3248        console.info(`ℹ️ Found ${allSliders.length} slider elements for reinitialization`);
3249        
3250        let validatedCount = 0;
3251        allSliders.forEach((slider, index) => {
3252            try {
3253                // Validate element before processing (cross-context support)
3254                const isValidElement = (
3255                    slider instanceof HTMLElement ||
3256                    (
3257                        slider &&
3258                        typeof slider === 'object' &&
3259                        slider.nodeType === 1 &&
3260                        (typeof slider.tagName === 'string' || typeof slider.nodeName === 'string') &&
3261                        typeof slider.classList === 'object' &&
3262                        slider.classList !== null &&
3263                        typeof slider.querySelector === 'function'
3264                    )
3265                );
3266                
3267                if (!isValidElement) {
3268                    console.warn(`⚠️ Skipping invalid element at index ${index}:`, slider);
3269                    return;
3270                }
3271                
3272                validatedCount++;
3273                
3274                if (window.sliderInstances && window.sliderInstances.has(slider)) {
3275                    try {
3276                        const existingInstance = window.sliderInstances.get(slider);
3277                        existingInstance.destroy();
3278                    } catch (destroyError) {
3279                        console.error(`⚠️ Error destroying slider ${index}:`, destroyError);
3280                    }
3281                }
3282                slider.classList.remove('initialized');
3283            } catch (sliderError) {
3284                console.error(`🚨 Error processing slider ${index} for reinitialization:`, sliderError);
3285            }
3286        });
3287        
3288        console.info(`ℹ️ Processed ${validatedCount} valid sliders for reinitialization`);
3289        
3290        // Clear the entire instances map
3291        if (window.sliderInstances) {
3292            window.sliderInstances.clear();
3293        }
3294        
3295        return initCustomSliders();
3296    } catch (error) {
3297        console.error('🚨 SLIDER CRASH: Force reinitializing all sliders failed:', error);
3298        return [];
3299    }
3300};
3301
3302// Global function to check for slider health and potential duplicates
3303window.checkSliderDuplicates = function() {
3304    const allSliders = document.querySelectorAll('.custom-slider');
3305    const duplicateReport = {
3306        totalSliders: allSliders.length,
3307        duplicateNavigations: 0,
3308        duplicateDots: 0,
3309        multipleInstances: 0,
3310        healthySliders: 0,
3311        issues: []
3312    };
3313    
3314    allSliders.forEach((slider, index) => {
3315        const navigations = slider.querySelectorAll('.slider-navigation');
3316        const dotContainers = slider.querySelectorAll('.slider-dots');
3317        const hasMultipleInstances = window.sliderInstances && window.sliderInstances.has(slider);
3318        
3319        // Check for duplicate navigation
3320        if (navigations.length > 1) {
3321            duplicateReport.duplicateNavigations++;
3322            duplicateReport.issues.push(`Slider ${index}: Found ${navigations.length} navigation elements`);
3323        }
3324        
3325        // Check for duplicate dots
3326        if (dotContainers.length > 1) {
3327            duplicateReport.duplicateDots++;
3328            duplicateReport.issues.push(`Slider ${index}: Found ${dotContainers.length} dot containers`);
3329        }
3330        
3331        // Check instance tracking
3332        if (hasMultipleInstances) {
3333            duplicateReport.multipleInstances++;
3334        }
3335        
3336        // Mark as healthy if no issues
3337        if (navigations.length <= 1 && dotContainers.length <= 1) {
3338            duplicateReport.healthySliders++;
3339        }
3340        
3341        
3342    });
3343    
3344
3345
3346
3347
3348
3349
3350    
3351    if (duplicateReport.issues.length > 0) {
3352
3353
3354    } else {
3355
3356    }
3357    
3358    return duplicateReport;
3359};
3360
3361// Global function to instantly fix duplicate dots issue
3362window.fixSliderDuplicatesNow = function() {
3363
3364    
3365    const allSliders = document.querySelectorAll('.custom-slider');
3366    let fixedCount = 0;
3367    
3368    allSliders.forEach((slider, index) => {
3369        const dotContainers = slider.querySelectorAll('.slider-dots');
3370        const navigations = slider.querySelectorAll('.slider-navigation');
3371        
3372        // Fix duplicate dots
3373        if (dotContainers.length > 1) {
3374
3375            // Keep only the first dots container, remove the rest
3376            for (let i = 1; i < dotContainers.length; i++) {
3377                dotContainers[i].remove();
3378            }
3379            fixedCount++;
3380        }
3381        
3382        // Fix duplicate navigation
3383        if (navigations.length > 1) {
3384
3385            // Keep only the first navigation, remove the rest
3386            for (let i = 1; i < navigations.length; i++) {
3387                navigations[i].remove();
3388            }
3389            fixedCount++;
3390        }
3391    });
3392    
3393
3394    
3395    // Run a verification check
3396    setTimeout(() => {
3397
3398        checkSliderDuplicates();
3399    }, 100);
3400    
3401    return fixedCount;
3402};
3403
3404// Global function to emergency clean broken sliders 
3405window.emergencySliderCleanup = function() {
3406
3407    
3408    const allSliders = document.querySelectorAll('.custom-slider');
3409    let cleanedCount = 0;
3410    let elementsRemoved = 0;
3411    
3412    allSliders.forEach((slider, index) => {
3413
3414        
3415        // Force destroy any tracked instances
3416        if (window.sliderInstances && window.sliderInstances.has(slider)) {
3417            try {
3418                const instance = window.sliderInstances.get(slider);
3419                instance.destroy();
3420                window.sliderInstances.delete(slider);
3421
3422            } catch (error) {
3423
3424                window.sliderInstances.delete(slider);
3425            }
3426        }
3427        
3428        // Remove ALL navigation elements
3429        const navigations = slider.querySelectorAll('.slider-navigation');
3430        navigations.forEach(nav => nav.remove());
3431        elementsRemoved += navigations.length;
3432        
3433        // Remove ALL dot containers
3434        const dotContainers = slider.querySelectorAll('.slider-dots');
3435        dotContainers.forEach(dots => dots.remove());
3436        elementsRemoved += dotContainers.length;
3437        
3438        // Remove ALL cloned slides
3439        const clonedSlides = slider.querySelectorAll('.slide-clone');
3440        clonedSlides.forEach(clone => clone.remove());
3441        elementsRemoved += clonedSlides.length;
3442        
3443        // Reset all styles and classes
3444        const wrapper = slider.querySelector('.slider-wrapper');
3445        if (wrapper) {
3446            wrapper.style.transform = '';
3447            wrapper.style.transition = '';
3448        }
3449        
3450        slider.classList.remove('initialized', 'dragging');
3451        slider.removeAttribute('tabindex');
3452        
3453        if (navigations.length > 0 || dotContainers.length > 0 || clonedSlides.length > 0) {
3454            cleanedCount++;
3455
3456        }
3457    });
3458    
3459    // Clear global instances map
3460    if (window.sliderInstances) {
3461        window.sliderInstances.clear();
3462    }
3463    
3464
3465
3466
3467
3468    
3469    return {
3470        slidersProcessed: allSliders.length,
3471        slidersWithDuplicates: cleanedCount,
3472        elementsRemoved: elementsRemoved
3473    };
3474};
3475
3476// Global function to safely and completely reinitialize sliders
3477window.safeReinitializeAllSliders = function() {
3478
3479    
3480    // First, emergency cleanup
3481    const cleanupResult = window.emergencySliderCleanup();
3482
3483    
3484    // Wait a moment for DOM to settle
3485    setTimeout(() => {
3486
3487        const result = initCustomSliders();
3488
3489        return result;
3490    }, 100);
3491    
3492    return cleanupResult;
3493};
3494
3495// Global function to clean up duplicate elements without full reinit
3496window.cleanupSliderDuplicates = function() {
3497    const allSliders = document.querySelectorAll('.custom-slider');
3498    let cleanedCount = 0;
3499    
3500    allSliders.forEach((slider, index) => {
3501        let cleaned = false;
3502        
3503        // Remove duplicate navigation elements (keep only the first one)
3504        const navigations = slider.querySelectorAll('.slider-navigation');
3505        if (navigations.length > 1) {
3506
3507            for (let i = 1; i < navigations.length; i++) {
3508                navigations[i].remove();
3509                cleaned = true;
3510            }
3511        }
3512        
3513        // Remove duplicate dot containers (keep only the first one)
3514        const dotContainers = slider.querySelectorAll('.slider-dots');
3515        if (dotContainers.length > 1) {
3516
3517            for (let i = 1; i < dotContainers.length; i++) {
3518                dotContainers[i].remove();
3519                cleaned = true;
3520            }
3521        }
3522        
3523        if (cleaned) {
3524            cleanedCount++;
3525        }
3526    });
3527    
3528
3529    return cleanedCount;
3530};
3531
3532window.debugSliders = function() {
3533    const sliders = document.querySelectorAll('.custom-slider');
3534    const packages = document.querySelectorAll('.packages_1');
3535    const packagesSliders = document.querySelectorAll('.custom-cards-slider');
3536    
3537
3538
3539
3540
3541    
3542    // Check if packages widget exists at all
3543    packages.forEach((pkg, index) => {
3544
3545
3546
3547    });
3548    
3549    sliders.forEach((slider, index) => {
3550        const slides = slider.querySelectorAll('.slide');
3551        const clones = slider.querySelectorAll('.slide-clone');
3552        const wrapper = slider.querySelector('.slider-wrapper');
3553        const navigation = slider.querySelector('.slider-navigation');
3554        const lazyImages = slider.querySelectorAll('.lazy-image');
3555        const loadedImages = slider.querySelectorAll('.lazy-image.loaded');
3556        const loadingImages = slider.querySelectorAll('.lazy-image.loading');
3557        
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569        
3570        // Performance metrics
3571
3572
3573
3574
3575
3576        
3577        // Log clone information
3578        clones.forEach((clone, cloneIndex) => {
3579
3580        });
3581        
3582        // Log image loading status
3583        lazyImages.forEach((img, imgIndex) => {
3584
3585        });
3586    });
3587    
3588    // Also check for any template placeholders that weren't processed
3589    const unprocessedTemplates = document.querySelectorAll('*');
3590    let foundTemplates = 0;
3591    unprocessedTemplates.forEach(el => {
3592        if (el.innerHTML && el.innerHTML.includes('{{#each packagesList}}')) {
3593            foundTemplates++;
3594
3595        }
3596    });
3597
3598    
3599    // Performance summary
3600    const totalImages = document.querySelectorAll('.lazy-image').length;
3601    const totalLoaded = document.querySelectorAll('.lazy-image.loaded').length;
3602
3603
3604
3605
3606};
3607
3608// Global function to get performance metrics for all sliders
3609window.getSliderPerformanceMetrics = function() {
3610    const sliders = document.querySelectorAll('.custom-slider.initialized');
3611    const metrics = {
3612        totalSliders: sliders.length,
3613        totalImages: 0,
3614        loadedImages: 0,
3615        loadingImages: 0,
3616        loadCompletion: 0,
3617        sliders: []
3618    };
3619    
3620    sliders.forEach((slider, index) => {
3621        const lazyImages = slider.querySelectorAll('.lazy-image');
3622        const loadedImages = slider.querySelectorAll('.lazy-image.loaded');
3623        const loadingImages = slider.querySelectorAll('.lazy-image.loading');
3624        
3625        const sliderMetrics = {
3626            index: index,
3627            classes: slider.className,
3628            totalImages: lazyImages.length,
3629            loadedImages: loadedImages.length,
3630            loadingImages: loadingImages.length,
3631            loadCompletion: lazyImages.length > 0 ? Math.round((loadedImages.length / lazyImages.length) * 100) : 0
3632        };
3633        
3634        metrics.sliders.push(sliderMetrics);
3635        metrics.totalImages += sliderMetrics.totalImages;
3636        metrics.loadedImages += sliderMetrics.loadedImages;
3637        metrics.loadingImages += sliderMetrics.loadingImages;
3638    });
3639    
3640    metrics.loadCompletion = metrics.totalImages > 0 ? Math.round((metrics.loadedImages / metrics.totalImages) * 100) : 0;
3641    
3642    return metrics;
3643};
3644
3645// Global function to check for crashed sliders and get health status
3646window.checkSliderHealth = function() {
3647    const allSliders = document.querySelectorAll('.custom-slider');
3648    const initializedSliders = document.querySelectorAll('.custom-slider.initialized');
3649    const healthReport = {
3650        totalSliders: allSliders.length,
3651        initializedSliders: initializedSliders.length,
3652        crashedSliders: [],
3653        healthySliders: [],
3654        issues: []
3655    };
3656    
3657    allSliders.forEach((slider, index) => {
3658        const isInitialized = slider.classList.contains('initialized');
3659        const hasWrapper = !!slider.querySelector('.slider-wrapper');
3660        const slides = slider.querySelectorAll('.slide');
3661        const hasSlides = slides.length > 0;
3662        
3663        const sliderInfo = {
3664            index: index,
3665            element: slider,
3666            className: slider.className,
3667            isInitialized: isInitialized,
3668            hasWrapper: hasWrapper,
3669            slideCount: slides.length,
3670            hasSlides: hasSlides,
3671            position: slider.getBoundingClientRect()
3672        };
3673        
3674        // Check for potential issues
3675        if (!isInitialized && hasSlides) {
3676            healthReport.issues.push(`Slider ${index}: Has slides but not initialized`);
3677            healthReport.crashedSliders.push(sliderInfo);
3678        } else if (isInitialized && !hasWrapper) {
3679            healthReport.issues.push(`Slider ${index}: Initialized but missing wrapper`);
3680            healthReport.crashedSliders.push(sliderInfo);
3681        } else if (isInitialized && !hasSlides) {
3682            healthReport.issues.push(`Slider ${index}: Initialized but no slides found`);
3683            healthReport.crashedSliders.push(sliderInfo);
3684        } else if (isInitialized && hasWrapper && hasSlides) {
3685            healthReport.healthySliders.push(sliderInfo);
3686        }
3687    });
3688    
3689
3690
3691
3692
3693
3694    
3695    if (healthReport.issues.length > 0) {
3696
3697    } else {
3698
3699    }
3700    
3701    return healthReport;
3702};
3703
3704// Export for module systems
3705if (typeof module !== 'undefined' && module.exports) {
3706    module.exports = { CustomSlider, initCustomSliders };
3707}
3708
3709// Global error tracking for slider-related crashes
3710if (typeof window !== 'undefined') {
3711    // Track slider-related errors globally
3712    let sliderErrorCount = 0;
3713    const originalConsoleError = console.error;
3714    
3715    console.error = function(...args) {
3716        // Check if this is a slider-related error
3717        const errorMessage = args.join(' ').toLowerCase();
3718        if (errorMessage.includes('slider') || errorMessage.includes('🚨 slider crash')) {
3719            sliderErrorCount++;
3720            
3721            // Add timestamp and error count to slider errors
3722            originalConsoleError.apply(console, [
3723                `🚨 SLIDER ERROR #${sliderErrorCount} [${new Date().toLocaleTimeString()}]:`,
3724                ...args
3725            ]);
3726            
3727            // Log error summary every 5 errors
3728            if (sliderErrorCount % 5 === 0) {
3729                originalConsoleError.apply(console, [
3730                    `⚠️ SLIDER ERROR SUMMARY: ${sliderErrorCount} slider-related errors detected. Run checkSliderHealth() for diagnosis.`
3731                ]);
3732            }
3733        } else {
3734            originalConsoleError.apply(console, args);
3735        }
3736    };
3737    
3738    // Global function to get error statistics
3739    window.getSliderErrorCount = function() {
3740        return sliderErrorCount;
3741    };
3742    
3743    // Global function to reset error count
3744    window.resetSliderErrorCount = function() {
3745        const previousCount = sliderErrorCount;
3746        sliderErrorCount = 0;
3747
3748        return previousCount;
3749    };
3750
3751    /**
3752     * Global function to disable infinite loop on any slider and convert it to normal slider
3753     * @param {Element|string} sliderElement - The slider element or CSS selector
3754     * @returns {boolean} - Success status
3755     */
3756    window.disableInfiniteLoop = function(sliderElement) {
3757        try {
3758            let slider;
3759            
3760            // Handle different input types
3761            if (typeof sliderElement === 'string') {
3762                slider = document.querySelector(sliderElement);
3763            } else if (sliderElement instanceof Element) {
3764                slider = sliderElement;
3765            } else {
3766                console.error('🚨 disableInfiniteLoop: Invalid slider element provided');
3767                return false;
3768            }
3769            
3770            if (!slider) {
3771                console.error('🚨 disableInfiniteLoop: Slider element not found');
3772                return false;
3773            }
3774            
3775            // Check if slider has infinite loop enabled
3776            if (!slider.classList.contains('infinite-loop')) {
3777
3778                return true;
3779            }
3780            
3781
3782            
3783            // Get the slider instance if it exists
3784            const sliderInstance = slider.sliderInstance;
3785            if (!sliderInstance) {
3786                console.error('🚨 disableInfiniteLoop: Slider instance not found. Slider may not be initialized.');
3787                return false;
3788            }
3789            
3790            // 1. Stop any auto-slide and clear timeouts
3791            if (sliderInstance.autoSlideInterval) {
3792                clearInterval(sliderInstance.autoSlideInterval);
3793                sliderInstance.autoSlideInterval = null;
3794            }
3795            
3796            if (sliderInstance.autoSlideTimeoutId) {
3797                clearTimeout(sliderInstance.autoSlideTimeoutId);
3798                sliderInstance.autoSlideTimeoutId = null;
3799            }
3800            
3801            if (sliderInstance.infiniteLoopTimeoutId) {
3802                clearTimeout(sliderInstance.infiniteLoopTimeoutId);
3803                sliderInstance.infiniteLoopTimeoutId = null;
3804            }
3805            
3806            // Clear all active timeouts
3807            if (sliderInstance.activeTimeouts) {
3808                sliderInstance.activeTimeouts.forEach(timeoutId => clearTimeout(timeoutId));
3809                sliderInstance.activeTimeouts.clear();
3810            }
3811            
3812            // 2. Remove cloned slides
3813            const clonedSlides = slider.querySelectorAll('.slide-clone');
3814
3815            
3816            clonedSlides.forEach(clone => {
3817                try {
3818                    clone.remove();
3819                } catch (error) {
3820
3821                }
3822            });
3823            
3824            // 3. Update slider instance properties
3825            sliderInstance.isInfiniteLoop = false;
3826            sliderInstance.infiniteLoopSetup = false;
3827            sliderInstance.cloneCount = 0;
3828            
3829            // 4. Reset slides collection to only include original slides
3830            sliderInstance.slides = slider.querySelectorAll('.slide:not(.slide-clone)');
3831            sliderInstance.slideCount = sliderInstance.slides.length;
3832            sliderInstance.originalSlideCount = sliderInstance.slideCount;
3833            
3834            // 5. Reset current slide position to within normal bounds
3835            if (sliderInstance.currentSlide >= sliderInstance.slideCount) {
3836                sliderInstance.currentSlide = 0;
3837            } else if (sliderInstance.currentSlide < 0) {
3838                sliderInstance.currentSlide = 0;
3839            }
3840            
3841            // 6. Remove infinite-loop class from slider element
3842            slider.classList.remove('infinite-loop');
3843            
3844            // 7. Remove transition temporarily for instant positioning
3845            const sliderWrapper = slider.querySelector('.slider-wrapper');
3846            if (sliderWrapper) {
3847                sliderWrapper.style.transition = 'none';
3848                
3849                // Update slider position instantly
3850                sliderInstance.updateSliderInstantly();
3851                
3852                // Re-enable transitions after a short delay
3853                setTimeout(() => {
3854                    sliderWrapper.style.transition = '';
3855                }, 100);
3856            }
3857            
3858            // 8. Recreate navigation dots for normal slider behavior
3859            if (sliderInstance.dots && sliderInstance.dots.length > 0) {
3860
3861                
3862                // Remove existing dots
3863                const dotsContainer = slider.querySelector('.slider-dots');
3864                if (dotsContainer) {
3865                    dotsContainer.innerHTML = '';
3866                    
3867                    // Create new dots for actual slides only
3868                    for (let i = 0; i < sliderInstance.slideCount; i++) {
3869                        const dot = document.createElement('button');
3870                        dot.classList.add('slider-dot');
3871                        dot.setAttribute('data-slide', i);
3872                        dot.setAttribute('aria-label', `Go to slide ${i + 1}`);
3873                        
3874                        if (i === sliderInstance.currentSlide) {
3875                            dot.classList.add('active');
3876                        }
3877                        
3878                        // Add click event listener for normal slider behavior
3879                        dot.addEventListener('click', () => {
3880                            if (sliderInstance.isTransitioning) return;
3881                            sliderInstance.currentSlide = i;
3882                            sliderInstance.updateSlider();
3883                        });
3884                        
3885                        dotsContainer.appendChild(dot);
3886                    }
3887                    
3888                    // Update dots collection
3889                    sliderInstance.dots = dotsContainer.querySelectorAll('.slider-dot');
3890                }
3891            }
3892            
3893            // 9. Update navigation behavior for normal slider
3894            sliderInstance.nextSlide = function() {
3895                try {
3896                    if (this.isTransitioning) return;
3897                    
3898                    const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
3899                                            this.slider.classList.contains('custom-cards-slider');
3900                    
3901                    if (isPackagesSlider) {
3902                        // For packages slider, calculate max slides considering visible slides
3903                        const slideWidth = this.getSlideWidth();
3904                        const containerWidth = this.slider.offsetWidth;
3905                        const slidesPerView = Math.floor(containerWidth / slideWidth);
3906                        const maxSlide = Math.max(0, this.slideCount - slidesPerView);
3907                        
3908                        if (this.currentSlide < maxSlide) {
3909                            this.currentSlide++;
3910                        } else {
3911                            this.currentSlide = 0; // Loop back to start
3912                        }
3913                    } else {
3914                        // Default behavior - loop back to beginning
3915                        this.currentSlide = (this.currentSlide + 1) % this.slideCount;
3916                    }
3917                    
3918                    this.updateSlider();
3919                } catch (error) {
3920                    console.error('Error in normal nextSlide:', error);
3921                }
3922            };
3923            
3924            sliderInstance.prevSlide = function() {
3925                try {
3926                    if (this.isTransitioning) return;
3927                    
3928                    const isPackagesSlider = this.slider.classList.contains('packages-slider') || 
3929                                            this.slider.classList.contains('custom-cards-slider');
3930                    
3931                    if (isPackagesSlider) {
3932                        // For packages slider
3933                        if (this.currentSlide > 0) {
3934                            this.currentSlide--;
3935                        } else {
3936                            // Jump to last possible position
3937                            const slideWidth = this.getSlideWidth();
3938                            const containerWidth = this.slider.offsetWidth;
3939                            const slidesPerView = Math.floor(containerWidth / slideWidth);
3940                            this.currentSlide = Math.max(0, this.slideCount - slidesPerView);
3941                        }
3942                    } else {
3943                        // Default behavior - loop to end
3944                        this.currentSlide = (this.currentSlide - 1 + this.slideCount) % this.slideCount;
3945                    }
3946                    
3947                    this.updateSlider();
3948                } catch (error) {
3949                    console.error('Error in normal prevSlide:', error);
3950                }
3951            };
3952            
3953            sliderInstance.goToSlide = function(index) {
3954                try {
3955                    if (this.isTransitioning) return;
3956                    if (index === this.currentSlide) return;
3957                    
3958                    // Ensure index is within bounds for normal slider
3959                    if (index < 0) index = 0;
3960                    if (index >= this.slideCount) index = this.slideCount - 1;
3961                    
3962                    this.currentSlide = index;
3963                    this.updateSlider();
3964                } catch (error) {
3965                    console.error('Error in normal goToSlide:', error);
3966                }
3967            };
3968            
3969            // 10. Restart auto-slide if it was enabled
3970            const autoSlideTime = parseInt(slider.getAttribute('data-auto-slide-time')) || 4000;
3971            if (autoSlideTime > 0) {
3972                setTimeout(() => {
3973                    sliderInstance.startAutoSlide();
3974                }, 1000);
3975            }
3976            
3977
3978            
3979            
3980            return true;
3981            
3982        } catch (error) {
3983            console.error('🚨 Error disabling infinite loop:', error);
3984            return false;
3985        }
3986    };
3987
3988    /**
3989     * Global function to disable infinite loop on all sliders on the page
3990     * @returns {Object} - Results summary
3991     */
3992    window.disableAllInfiniteLoops = function() {
3993        const results = {
3994            total: 0,
3995            success: 0,
3996            failed: 0,
3997            alreadyDisabled: 0,
3998            details: []
3999        };
4000        
4001        try {
4002            const allSliders = document.querySelectorAll('.custom-slider, .packages-slider, .testimonials_2_custom-card-slider');
4003            results.total = allSliders.length;
4004            
4005
4006            
4007            allSliders.forEach((slider, index) => {
4008                try {
4009                    const sliderClass = slider.className;
4010                    const hasInfiniteLoop = slider.classList.contains('infinite-loop');
4011                    
4012                    if (!hasInfiniteLoop) {
4013                        results.alreadyDisabled++;
4014                        results.details.push({
4015                            index: index + 1,
4016                            className: sliderClass,
4017                            status: 'already-disabled'
4018                        });
4019                        return;
4020                    }
4021                    
4022                    const success = window.disableInfiniteLoop(slider);
4023                    if (success) {
4024                        results.success++;
4025                        results.details.push({
4026                            index: index + 1,
4027                            className: sliderClass,
4028                            status: 'success'
4029                        });
4030                    } else {
4031                        results.failed++;
4032                        results.details.push({
4033                            index: index + 1,
4034                            className: sliderClass,
4035                            status: 'failed'
4036                        });
4037                    }
4038                } catch (error) {
4039                    results.failed++;
4040                    results.details.push({
4041                        index: index + 1,
4042                        className: slider.className,
4043                        status: 'error',
4044                        error: error.message
4045                    });
4046                }
4047            });
4048            
4049            
4050            
4051            return results;
4052            
4053        } catch (error) {
4054            console.error('🚨 Error disabling infinite loops:', error);
4055            results.failed = results.total;
4056            return results;
4057        }
4058    };
4059
4060    /**
4061     * Global function to check which sliders have infinite loop enabled
4062     * @returns {Array} - List of sliders with infinite loop status
4063     */
4064    window.checkInfiniteLoopStatus = function() {
4065        const sliders = document.querySelectorAll('.custom-slider, .packages-slider, .testimonials_2_custom-card-slider');
4066        const status = [];
4067        
4068        sliders.forEach((slider, index) => {
4069            const hasInfiniteLoop = slider.classList.contains('infinite-loop');
4070            const sliderInstance = slider.sliderInstance;
4071            const isInitialized = !!sliderInstance;
4072            
4073            status.push({
4074                index: index + 1,
4075                element: slider,
4076                className: slider.className,
4077                hasInfiniteLoopClass: hasInfiniteLoop,
4078                isInitialized: isInitialized,
4079                instanceInfiniteLoop: isInitialized ? sliderInstance.isInfiniteLoop : null,
4080                slideCount: isInitialized ? sliderInstance.slideCount : null,
4081                cloneCount: isInitialized ? sliderInstance.cloneCount : null,
4082                currentSlide: isInitialized ? sliderInstance.currentSlide : null
4083            });
4084        });
4085        
4086        console.table(status);
4087        return status;
4088    };
4089
4090    /**
4091     * Global function to toggle infinite loop on a specific slider
4092     * @param {Element|string} sliderElement - The slider element or CSS selector
4093     * @param {boolean} enable - Whether to enable (true) or disable (false) infinite loop
4094     * @returns {boolean} - Success status
4095     */
4096    window.toggleInfiniteLoop = function(sliderElement, enable) {
4097        try {
4098            let slider;
4099            
4100            if (typeof sliderElement === 'string') {
4101                slider = document.querySelector(sliderElement);
4102            } else if (sliderElement instanceof Element) {
4103                slider = sliderElement;
4104            } else {
4105                console.error('🚨 toggleInfiniteLoop: Invalid slider element provided');
4106                return false;
4107            }
4108            
4109            if (!slider) {
4110                console.error('🚨 toggleInfiniteLoop: Slider element not found');
4111                return false;
4112            }
4113            
4114            const currentlyEnabled = slider.classList.contains('infinite-loop');
4115            
4116            if (enable === true && !currentlyEnabled) {
4117                // Enable infinite loop - add class and reinitialize
4118                slider.classList.add('infinite-loop');
4119
4120                
4121                // Destroy and reinitialize the slider to set up infinite loop
4122                if (slider.sliderInstance) {
4123                    slider.sliderInstance.destroy();
4124                }
4125                
4126                // Small delay to allow cleanup
4127                setTimeout(() => {
4128                    window.initCustomSlider(slider);
4129                }, 100);
4130                
4131                return true;
4132                
4133            } else if (enable === false && currentlyEnabled) {
4134                // Disable infinite loop
4135                return window.disableInfiniteLoop(slider);
4136                
4137            } else {
4138
4139                return true;
4140            }
4141            
4142        } catch (error) {
4143            console.error('🚨 Error toggling infinite loop:', error);
4144            return false;
4145        }
4146    };
4147
4148    // Add infinite loop control to global slider helpers
4149    if (typeof window.sliderHelpers === 'object') {
4150        window.sliderHelpers.disableInfiniteLoop = window.disableInfiniteLoop;
4151        window.sliderHelpers.disableAllInfiniteLoops = window.disableAllInfiniteLoops;
4152        window.sliderHelpers.checkInfiniteLoopStatus = window.checkInfiniteLoopStatus;
4153        window.sliderHelpers.toggleInfiniteLoop = window.toggleInfiniteLoop;
4154        window.sliderHelpers.cleanupDuplicateDots = window.cleanupDuplicateDots;
4155        window.sliderHelpers.fixDotDuplicatesNow = window.fixDotDuplicatesNow;
4156        window.sliderHelpers.checkDotsHealth = window.checkDotsHealth;
4157    }
4158
4159    /**
4160     * Global function to clean up duplicate dots across all sliders without affecting infinite loop
4161     * @returns {Object} - Cleanup results
4162     */
4163    window.cleanupDuplicateDots = function() {
4164        const results = {
4165            total: 0,
4166            fixed: 0,
4167            failed: 0,
4168            details: []
4169        };
4170        
4171        try {
4172            const allSliders = document.querySelectorAll('.custom-slider, .packages-slider, .testimonials_2_custom-card-slider');
4173            results.total = allSliders.length;
4174            
4175
4176            
4177            allSliders.forEach((slider, index) => {
4178                try {
4179                    const sliderInstance = slider.sliderInstance;
4180                    const sliderClass = slider.className;
4181                    
4182                    if (!sliderInstance) {
4183                        results.details.push({
4184                            index: index + 1,
4185                            className: sliderClass,
4186                            status: 'no-instance',
4187                            message: 'Slider instance not found'
4188                        });
4189                        return;
4190                    }
4191                    
4192                    // Use the instance's cleanup method
4193                    sliderInstance.cleanupDuplicateDots();
4194                    sliderInstance.validateAndFixDots();
4195                    
4196                    results.fixed++;
4197                    results.details.push({
4198                        index: index + 1,
4199                        className: sliderClass,
4200                        status: 'fixed',
4201                        dotsCount: sliderInstance.dots ? sliderInstance.dots.length : 0
4202                    });
4203                    
4204                } catch (error) {
4205                    results.failed++;
4206                    results.details.push({
4207                        index: index + 1,
4208                        className: slider.className,
4209                        status: 'error',
4210                        error: error.message
4211                    });
4212                }
4213            });
4214            
4215            
4216            
4217            return results;
4218            
4219        } catch (error) {
4220            console.error('🚨 Error cleaning up duplicate dots:', error);
4221            results.failed = results.total;
4222            return results;
4223        }
4224    };
4225
4226    /**
4227     * Global function to immediately fix dot duplicates (emergency function)
4228     * @returns {boolean} - Success status
4229     */
4230    window.fixDotDuplicatesNow = function() {
4231        try {
4232
4233            
4234            // Find and remove all extra dot containers
4235            const allDotContainers = document.querySelectorAll('.slider-dots');
4236            const processedSliders = new Set();
4237            let removedContainers = 0;
4238            
4239            allDotContainers.forEach(container => {
4240                const parentSlider = container.closest('.custom-slider, .packages-slider, .testimonials_2_custom-card-slider');
4241                if (!parentSlider) return;
4242                
4243                const sliderId = parentSlider.className;
4244                if (processedSliders.has(parentSlider)) {
4245                    // This slider already has a dot container, remove this one
4246
4247                    container.remove();
4248                    removedContainers++;
4249                } else {
4250                    processedSliders.add(parentSlider);
4251                    
4252                    // Validate this container
4253                    const sliderInstance = parentSlider.sliderInstance;
4254                    if (sliderInstance) {
4255                        const expectedDots = sliderInstance.isInfiniteLoop ? sliderInstance.originalSlideCount : sliderInstance.slideCount;
4256                        const actualDots = container.querySelectorAll('.dot').length;
4257                        
4258                        if (actualDots !== expectedDots) {
4259
4260                            container.remove();
4261                            sliderInstance.dotsCreated = false;
4262                            sliderInstance.createDots();
4263                        }
4264                    }
4265                }
4266            });
4267            
4268
4269            return true;
4270            
4271        } catch (error) {
4272            console.error('🚨 Emergency dot fix failed:', error);
4273            return false;
4274        }
4275    };
4276
4277    /**
4278     * Global function to check dots health across all sliders
4279     * @returns {Array} - Detailed health report
4280     */
4281    window.checkDotsHealth = function() {
4282        const healthReport = [];
4283        
4284        try {
4285            const allSliders = document.querySelectorAll('.custom-slider, .packages-slider, .testimonials_2_custom-card-slider');
4286            
4287            allSliders.forEach((slider, index) => {
4288                const sliderInstance = slider.sliderInstance;
4289                const dotContainers = slider.querySelectorAll('.slider-dots');
4290                const totalDots = slider.querySelectorAll('.dot').length;
4291                
4292                const health = {
4293                    index: index + 1,
4294                    element: slider,
4295                    className: slider.className,
4296                    isInitialized: !!sliderInstance,
4297                    dotContainerCount: dotContainers.length,
4298                    totalDotCount: totalDots,
4299                    expectedDots: null,
4300                    isHealthy: false,
4301                    issues: [],
4302                    infiniteLoop: false
4303                };
4304                
4305                if (sliderInstance) {
4306                    health.infiniteLoop = sliderInstance.isInfiniteLoop;
4307                    health.expectedDots = health.infiniteLoop ? sliderInstance.originalSlideCount : sliderInstance.slideCount;
4308                    
4309                    // Check for issues
4310                    if (dotContainers.length > 1) {
4311                        health.issues.push(`Multiple dot containers (${dotContainers.length})`);
4312                    }
4313                    
4314                    if (dotContainers.length === 0 && !slider.classList.contains('no-slider-dots')) {
4315                        health.issues.push('Missing dot container');
4316                    }
4317                    
4318                    if (totalDots !== health.expectedDots && !slider.classList.contains('no-slider-dots')) {
4319                        health.issues.push(`Incorrect dot count (${totalDots}, expected ${health.expectedDots})`);
4320                    }
4321                    
4322                    health.isHealthy = health.issues.length === 0;
4323                } else {
4324                    health.issues.push('Slider not initialized');
4325                }
4326                
4327                healthReport.push(health);
4328            });
4329            
4330            const healthySlidersCount = healthReport.filter(h => h.isHealthy).length;
4331            const unhealthySlidersCount = healthReport.length - healthySlidersCount;
4332            
4333
4334            if (unhealthySlidersCount > 0) {
4335
4336                healthReport.filter(h => !h.isHealthy).forEach(report => {
4337
4338                });
4339            }
4340            
4341            console.table(healthReport.map(h => ({
4342                Index: h.index,
4343                ClassName: h.className.split(' ').slice(0, 2).join(' '),
4344                Containers: h.dotContainerCount,
4345                Dots: h.totalDotCount,
4346                Expected: h.expectedDots,
4347                Healthy: h.isHealthy ? '✅' : '❌',
4348                Issues: h.issues.join('; ')
4349            })));
4350            
4351            return healthReport;
4352            
4353        } catch (error) {
4354            console.error('🚨 Health check failed:', error);
4355            return [];
4356        }
4357    };
4358}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.