PageSourceSearch

https://www.tridvajedna.cz/js/script-all.js?v=2026-08-26-5

js tridvajedna.cz collected 2026-09-26 13:42:58 UTC 53,719 bytes, 1,671 lines download raw bytes

1// ===== 1. UTILITY FUNCTIONS =====
2const regEx_email = /^[\ a-z0-9._-]+@[a-z0-9.-]+\.[a-z]{2,6}$/i;
3
4if(typeof String.prototype.trim !== 'function') {
5  String.prototype.trim = function() {
6    return this.replace(/^\s+|\s+$/g, '');
7  }
8}
9
10function isIE() {
11  return /*@cc_on!@*/false || !!document.documentMode;
12}
13
14Number.prototype.formatMoney = function(c, d, t){
15  var n = this,
16      c = isNaN(c = Math.abs(c)) ? 0 : c,
17      d = d == undefined ? "," : d,
18      t = t == undefined ? " " : t,
19      s = n < 0 ? "-" : "",
20      i = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(c))),
21      j = (j = i.length) > 3 ? j % 3 : 0;
22  return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
23};
24
25function removeMultipleSpaces(html) {
26  return html.replace(/\s+/g, ' ');
27}
28// ===== 2. VIDEO HANDLING =====
29document.querySelectorAll('.videoIsHere').forEach(container => {
30    const video = container.querySelector('video');
31    const img = container.querySelector('img');
32    
33    if (!video || !img) return;
34    
35    // Nastavení video atributů
36    video.setAttribute('playsinline', '');
37    
38    // Zkontrolujeme, zda některý z rodičovských elementů má třídu 'loopFalse'
39    const hasLoopFalseParent = container.closest('.loopFalse') !== null;
40    
41    // Nastavíme loop na true, pokud není přítomen rodič s třídou 'loopFalse'
42    video.loop = !hasLoopFalseParent;
43    
44    // Přidáme transition pro plynulé přechody obrázku
45    img.style.transition = 'opacity 0.5s ease-in-out';
46    
47    // Nastavíme obrázek jako viditelný na začátku
48    img.style.opacity = '1';
49    
50    const observer = new IntersectionObserver((entries) => {
51        entries.forEach(entry => {
52            if (entry.isIntersecting) {
53                setTimeout(() => {
54                    video.load();
55                }, 100);
56                observer.unobserve(container);
57            }
58        });
59    }, {
60        rootMargin: '50px',
61        threshold: 0.1
62    });
63    
64    observer.observe(container);
65    
66    let playPromise = null;
67    let resetTimeout = null;
68    
69    container.addEventListener('mouseenter', () => {
70        // Zrušíme případné čekání na reset
71        if (resetTimeout) {
72            clearTimeout(resetTimeout);
73            resetTimeout = null;
74        }
75        
76        // Skryjeme obrázek
77        img.style.opacity = '0';
78        
79        // Přehrajeme video od začátku
80        video.currentTime = 0;
81        
82        if (video.readyState >= 2) {
83            playPromise = video.play();
84        } else {
85            video.addEventListener('canplay', () => {
86                playPromise = video.play();
87            }, { once: true });
88        }
89    });
90    
91    container.addEventListener('mouseleave', () => {
92        // Zastavíme přehrávání videa
93        if (playPromise !== null) {
94            playPromise.then(() => {
95                video.pause();
96                
97                // Začneme zobrazovat obrázek ihned
98                img.style.opacity = '1';
99                
100                // Po 500ms vrátíme video na začátek
101                resetTimeout = setTimeout(() => {
102                    video.currentTime = 0;
103                }, 500);
104            }).catch(error => console.log('Chyba přehrávání:', error));
105        } else {
106            // Pokud video ještě nezačalo hrát, pouze zobrazíme obrázek
107            img.style.opacity = '1';
108        }
109    });
110});
111//// ===== 2. VIDEO HANDLING =====
112//document.querySelectorAll('.videoIsHere').forEach(container => {
113//    const video = container.querySelector('video');
114//    
115//    if (!video) return;
116//    
117//    video.setAttribute('playsinline', '');
118//    
119//    const observer = new IntersectionObserver((entries) => {
120//        entries.forEach(entry => {
121//            if (entry.isIntersecting) {
122//                setTimeout(() => {
123//                    video.load();
124//                }, 100);
125//                observer.unobserve(container);
126//            }
127//        });
128//    }, {
129//        rootMargin: '50px',
130//        threshold: 0.1
131//    });
132//    
133//    observer.observe(container);
134//    
135//    let playPromise = null;
136//    
137//    container.addEventListener('mouseenter', () => {
138//        if (video.readyState >= 2) {
139//            playPromise = video.play();
140//        } else {
141//            video.addEventListener('canplay', () => {
142//                playPromise = video.play();
143//            }, { once: true });
144//        }
145//    });
146//    
147//    container.addEventListener('mouseleave', () => {
148//        if (playPromise !== null) {
149//            playPromise.then(() => video.pause())
150//                      .catch(error => console.log('Chyba přehrávání:', error));
151//        }
152//    });
153//});
154
155// ===== 3. SCROLL HANDLING =====
156// ===== 3. SCROLL HANDLING =====
157// Hlavní vertikální instance Lenis
158const lenis = new Lenis({
159  duration: 1.2,
160  easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
161  direction: 'vertical',
162  gestureDirection: 'vertical',
163  smooth: true,
164  mouseMultiplier: 1.5,
165  smoothTouch: false,
166  touchMultiplier: 2,
167  infinite: false
168});
169
170function raf(time) {
171  lenis.raf(time);
172  requestAnimationFrame(raf);
173}
174requestAnimationFrame(raf);
175
176// Najdeme prvky s horizontálním skrolováním
177const horizontalScrollElements = document.querySelectorAll('.ref-submenu, .ref-menu');
178
179// Přidáme vlastní horizontální skrolování pro všechna nalezená prvky
180horizontalScrollElements.forEach(element => {
181  if (element) {
182    // Nastavíme CSS vlastnosti programově pro jistotu
183    element.style.overflowX = 'auto';
184    element.style.overflowY = 'hidden';
185    element.style.whiteSpace = 'nowrap';
186    
187    // Speciální obsluha události wheel pro horizontální skrolování
188    element.addEventListener('wheel', function(e) {
189      // Zkontrolujeme, zda prvek má horizontální přetečení
190      const hasHorizontalOverflow = element.scrollWidth > element.clientWidth;
191      
192      if (hasHorizontalOverflow && e.deltaY !== 0) {
193        // Pouze pokud má prvek přetečení, zabráníme výchozímu chování
194        
195        // Kontrola, zda jsme na konci skrolování
196        const isAtLeftEdge = element.scrollLeft <= 0;
197        const isAtRightEdge = element.scrollLeft + element.clientWidth >= element.scrollWidth;
198        
199        // Pokud jsme na kraji a uživatel se snaží skrolovat dál v tom směru,
200        // umožníme normální (vertikální) skrolování
201        if ((isAtLeftEdge && e.deltaY < 0) || (isAtRightEdge && e.deltaY > 0)) {
202          // Umožní běžné vertikální skrolování, když jsme na hranici horizontálního posunu
203          return;
204        }
205        
206        // Zastavíme propagaci události, aby ji nezachytil Lenis
207        e.stopPropagation();
208        // Zabráníme výchozímu chování
209        e.preventDefault();
210        
211        // Nastavíme rychlost skrolování
212        const scrollSpeed = 2;
213        // Převedeme vertikální pohyb na horizontální
214        element.scrollLeft += e.deltaY * scrollSpeed;
215      }
216      // V opačném případě necháme událost propadnout pro běžné vertikální skrolování
217    }, { passive: false }); // passive: false je nezbytné pro e.preventDefault()
218  }
219});
220
221function smoothScroll(target) {
222  const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
223  
224  if (isTouchDevice) {
225    if (typeof target === 'number') {
226      window.scrollTo({
227        top: 0,
228        behavior: 'smooth'
229      });
230    } else {
231      target.scrollIntoView({
232        behavior: 'smooth'
233      });
234    }
235  } else {
236    lenis.scrollTo(target, {
237      offset: 0,
238      duration: 5
239    });
240  }
241}
242
243document.querySelector('.scroll-top').addEventListener('click', function(e) {
244    e.preventDefault();
245    smoothScroll(0);
246});
247
248
249
250
251// Definujeme pole tříd, pro které nechceme použít smooth scroll
252const excludedClasses = ['carousel-control-next', 'carousel-control-prev'];
253
254document.querySelectorAll('a[href^="#"]').forEach(anchor => {
255  anchor.addEventListener('click', function (e) {
256    // Kontrola, zda prvek neobsahuje některou z vyloučených tříd
257    const shouldExclude = excludedClasses.some(className => 
258      this.classList.contains(className)
259    );
260    
261    // Pokud má prvek některou z vyloučených tříd, nechceme preventDefault a smooth scroll
262    if (shouldExclude) {
263      return;
264    }
265    
266    e.preventDefault();
267    const href = this.getAttribute('href');
268    
269    if (href === '#') {
270      return;
271    }
272    
273    let target;
274    // Podpora pro scroll na class: href="#class-nazevTridy"
275    if (href.startsWith('#class-')) {
276      const className = href.replace('#class-', '');
277      target = document.querySelector('.' + className);
278    } else {
279      target = document.querySelector(href);
280    }
281    
282    if (target) {
283      smoothScroll(target);
284    }
285  });
286});
287
288window.addEventListener('scroll', function() {
289    const scrollTop = document.querySelector('.scroll-top');
290    const viewportHeight = window.innerHeight;
291    
292    if (window.scrollY > viewportHeight) {
293        scrollTop.classList.add('show');
294    } else {
295        scrollTop.classList.remove('show');
296    }
297});
298
299// ===== 4. CUSTOM CURSOR =====
300class CustomCursor {
301  constructor() {
302    this.$cursor = $(".cursor");
303    
304    if (this.$cursor.length === 0) {
305      console.error('Cursor element nenalezen');
306      return;
307    }
308
309    this.isTouchDevice = 'ontouchstart' in document.documentElement;
310    this.init();
311  }
312
313  init() {
314    if (this.isTouchDevice) {
315      this.disableCursor();
316      return;
317    }
318    this.setupCursor();
319  }
320
321  disableCursor() {
322    this.$cursor.hide();
323    $('html, *').css('cursor', 'auto');
324  }
325
326  setupCursor() {
327    $(document).on('mousemove', (e) => {
328      requestAnimationFrame(() => {
329        this.$cursor.css({
330          top: e.clientY + 'px',
331          left: e.clientX + 'px'
332        });
333      });
334    });
335
336    const hoverElements = `
337      div:not(.whole-field-url) a, 
338      a:not(.container-link), 
339      .slide-down, 
340      #contactForm50Submit, 
341      .menu-toggler-svg, 
342      .mobile-menu-open, 
343      .next, 
344      .prev, 
345      .arrow-collapse
346    `;
347
348    $(hoverElements).hover(
349      () => this.$cursor.css('transform', 'scale(3.2)'),
350      () => this.$cursor.css('transform', 'scale(1)')
351    );
352
353    $("a.container-link, .whole-field-url a.stretched-link, button").hover(
354      () => {
355        this.$cursor
356          .addClass('arrow-up')
357          .css('transform', 'scale(3.2)');
358      },
359      () => {
360        this.$cursor
361          .removeClass('arrow-up')
362          .css('transform', 'scale(1)');
363      }
364    );
365	  
366	$("a.arrow-up-right, .arrow-up-right a").hover(
367      () => {
368        this.$cursor
369          .addClass('arrow-up-right')
370          .css('transform', 'scale(3.2)');
371      },
372      () => {
373        this.$cursor
374          .removeClass('arrow-up-right')
375          .css('transform', 'scale(1)');
376      }
377    );
378    
379    $(".slider-cover > div > div").hover(
380      () => {
381        this.$cursor
382          .addClass('slide-horizontal')
383          .css('transform', 'scale(3.2)');
384      },
385      () => {
386        this.$cursor
387          .removeClass('slide-horizontal')
388          .css('transform', 'scale(1)');
389      }
390    );
391
392    $(".prev, .carousel-control-prev").hover(
393      () => {
394        this.$cursor
395          .addClass('slide-left')
396          .css('transform', 'scale(3.2)');
397      },
398      () => {
399        this.$cursor
400          .removeClass('slide-left')
401          .css('transform', 'scale(1)');
402      }
403    );
404
405    $(".playVideo").hover(
406      () => {
407        this.$cursor
408          .addClass('playIcon')
409          .css('transform', 'scale(3.2)');
410      },
411      () => {
412        this.$cursor
413          .removeClass('playIcon')
414          .css('transform', 'scale(1)');
415      }
416    );
417
418    $(".modal").hover(
419      () => {
420        this.$cursor
421          .addClass('closeModal')
422          .css('transform', 'scale(3.2)');
423      },
424      () => {
425        this.$cursor
426          .removeClass('closeModal')
427          .css('transform', 'scale(1)');
428      }
429    );
430
431    $(".closeForm").hover(
432      () => {
433        this.$cursor
434          .addClass('closeFormIcon')
435          .css('transform', 'scale(3.2)');
436      },
437      () => {
438        this.$cursor
439          .removeClass('closeFormIcon')
440          .css('transform', 'scale(1)');
441      }
442    );
443    $("a.questionMark").hover( 
444      () => {
445        this.$cursor
446          .addClass('questionIconIcon')
447          .css('transform', 'scale(3.2)');
448      },
449      () => {
450        this.$cursor
451          .removeClass('questionIconIcon')
452          .css('transform', 'scale(1)');
453      }
454    );
455
456    $(".next, .carousel-control-next").hover(
457      () => {
458        this.$cursor
459          .addClass('slide-right')
460          .css('transform', 'scale(3.2)');
461      },
462      () => {
463        this.$cursor
464          .removeClass('slide-right')
465          .css('transform', 'scale(1)');
466      }
467    );
468
469    $('[data-toggle="lightbox"]').hover(
470      () => {
471        this.$cursor
472          .addClass('zoom')
473          .css('transform', 'scale(3.2)');
474      },
475      () => {
476        this.$cursor
477          .removeClass('zoom')
478          .css('transform', 'scale(1)');
479      }
480    );
481
482    $(document).on('mousedown', () => {
483      this.$cursor.css('transform', 'scale(0.2)');
484    }).on('mouseup', () => {
485      this.$cursor.css('transform', 'scale(1)');
486    });
487
488    $(document).on('mouseleave', () => {
489      this.$cursor.css('opacity', '0');
490    }).on('mouseenter', () => {
491      this.$cursor.css('opacity', '1');
492    });
493  }
494}
495
496// ===== 5. TEXT FORMATTING =====
497function lineUpFormat(selector, callback) {
498    const processedClass = 'ci-line-processed';
499    
500    function createLineUpStructure(element) {
501        const $element = $(element);
502        
503        if ($element.hasClass(processedClass)) {
504            return;
505        }
506        
507        const lineUpDiv = $('<div class="ci-line-element"></div>');
508        for(let i = 0; i < 8; i++) {
509            lineUpDiv.append('<div></div>');
510        }
511        
512        $element
513            .append(lineUpDiv)
514            .removeClass('ci-line')
515            .addClass('position-relative')
516            .addClass(processedClass); 
517    }
518
519    $(selector).each(function() {
520        createLineUpStructure(this);
521    });
522
523    if (typeof callback === 'function') {
524        callback();
525    }
526}
527
528function lightBoldFormat(selector) {
529    function wrapWordsInSpans(text) {
530        let processedText = text.replace(/<br\s*\/?>/gi, ' LINEBREAK_TOKEN ');
531        
532        return processedText.split(' ')
533            .map(word => {
534                if (word === 'LINEBREAK_TOKEN') {
535                    return '<span class="word clearBoth"></span>';
536                } else if (word) {
537                    return `<span class="word">${word}</span>`;
538                }
539                return '';
540            })
541            .join(' ');
542    }
543    
544    function processElement(element) {
545        let $element = $(element);
546        let $lineUp = $element.find('.ci-line-element').detach();
547        let containerWidth = $element.width();
548        let originalContent = $element.html()
549            .replace(/<span[^>]*>(.*?)<\/span>/g, '$1')
550            .trim();
551        
552        $element.html(wrapWordsInSpans(originalContent));
553        $element.append($lineUp);
554        
555        let currentWidth = 0;
556        let firstLineComplete = false;
557        
558        $element.find('span.word').each(function() {
559            let $word = $(this);
560            
561            if ($word.hasClass('clearBoth')) {
562                currentWidth = 0;
563                firstLineComplete = true;
564                return;
565            }
566            
567            let wordWidth = $word.outerWidth(true);
568            
569            if (!firstLineComplete) {
570                if (currentWidth + wordWidth > containerWidth) {
571                    firstLineComplete = true;
572                } else {
573                    $word.addClass('font-weight-light');
574                    currentWidth += wordWidth;
575                }
576            }
577        });
578    }
579    
580    let elements = $(selector);
581    elements.each(function() {
582        processElement(this);
583    });
584    
585    let resizeTimer;
586    $(window).on('resize', function() {
587        clearTimeout(resizeTimer);
588        resizeTimer = setTimeout(function() {
589            elements.each(function() {
590                processElement(this);
591            });
592        }, 250);
593    });
594}
595
596
597// ===== 6. IMAGE AND BACKGROUND HANDLING =====
598const handleResponsiveImages = (isResize = false) => {
599  // Detekce device pixel ratio (systémové měřítko)
600  const pixelRatio = window.devicePixelRatio || 1;
601  const isSystemScaled = pixelRatio > 1 && pixelRatio < 2; // Přibližně 125% = 1.25
602  const isRetina = pixelRatio >= 2; // Detekce retina displeje
603  
604  const getImageSize = (width) => {
605    // Pro tisk nebo printablePage vždy použijeme full velikost
606    if ($('body').hasClass('printablePage')) {
607      return 'full';
608    }
609    // Pro retina displeje vždy použijeme full velikost
610    if (isRetina) {
611      return 'full';
612    }
613    // Pokud je systémové měřítko aktivní (např. 125%), použijeme větší verzi obrázku
614    if (isSystemScaled) {
615      // Zvětšíme požadovanou velikost obrázku pro lepší ostrost
616      if (width < 321) return 'medium'; // Místo 'small'
617      else if (width < 641) return 'full'; // Místo 'medium'
618      else return 'full'; // Místo 'large'
619    } else {
620      // Původní logika
621      if (width < 321) return 'medium';
622      else if (width < 641) return 'large';
623      else if (width < 1025) return 'large';
624      else return 'full';
625    }
626  };
627	
628  const updateImageUrl = ($elem) => {
629    const isImage = $elem.is('img');
630    const dataSrcImageUrl = isImage ? 
631      $elem.attr('data-src') : 
632      $elem.attr('data-bg');
633    
634    if (!dataSrcImageUrl) return;
635    
636    const $parent = $elem.parent();
637    const $imageBox = $elem.closest('.image-box');
638    
639    // Kontrola, zda se v nadřazených prvcích nachází třída fullImage
640    const hasFullImageParent = $elem.parents('.fullImage').length > 0;
641    
642    // Pokud je rodič s třídou fullImage, vždy použijeme size "full", jinak standardní výpočet
643    const elementWidth = $imageBox.length ? 
644      $imageBox.width() : 
645      $parent.width();
646    const size = hasFullImageParent ? 'full' : getImageSize(elementWidth);
647    
648    let newUrl;
649    if (dataSrcImageUrl.includes('-small') || 
650        dataSrcImageUrl.includes('-medium') || 
651        dataSrcImageUrl.includes('-large') || 
652        dataSrcImageUrl.includes('-full')) {
653      newUrl = dataSrcImageUrl.replace(/-(?:small|medium|large|full)/, `-${size}`);
654    }
655    else if (dataSrcImageUrl.includes('/small/') || 
656             dataSrcImageUrl.includes('/medium/') || 
657             dataSrcImageUrl.includes('/large/') || 
658             dataSrcImageUrl.includes('/full/')) {
659      newUrl = dataSrcImageUrl.replace(/\/(small|medium|large|full)\//, `/${size}/`);
660    }
661    if (newUrl) {
662      if (isResize) {
663        if (isImage && $elem.attr('src')) {
664          $elem.attr('src', newUrl);
665        } else if ($elem.hasClass('image-box') && $elem.css('background-image') !== 'none') {
666          $elem.css('background-image', `url(${newUrl})`);
667        }
668      }
669      
670      if (isImage) {
671        $elem.attr('data-src', newUrl);
672        if (!isResize && !$elem.attr('src')) {
673          $elem.attr('src', newUrl);
674        }
675      } else if ($elem.hasClass('image-box')) {
676        $elem.attr('data-bg', newUrl);
677      }
678    }
679  };
680  $('img[data-responsive="YES"]').each(function() {
681    updateImageUrl($(this));
682  });
683  
684  $('.image-box[data-change-url="YES"]').each(function() {
685    updateImageUrl($(this));
686  });
687  
688  $('img[data-change-url="YES"]').each(function() {
689    updateImageUrl($(this));
690  });
691
692  
693};
694
695// Image hover effect plugin
696$.fn.showImageOrVideoOnOver = function(options) {
697  const config = $.extend({
698    lerp: 0.1
699  }, options);
700  
701  const lerp = (start, end, factor) => start * (1 - factor) + end * factor;
702  
703  const getViewportCenter = () => ({
704    x: window.innerWidth / 2,
705    y: window.innerHeight / 2
706  });
707  
708  return this.each(function() {
709    const container = $(this);
710    const movableElements = container.find('.moveByCursor');
711    let animationFrame;
712    
713    const positions = new Map();
714    
715    const center = getViewportCenter();
716    movableElements.each(function() {
717      positions.set(this, {
718        current: { x: center.x, y: center.y },
719        target: { x: center.x, y: center.y }
720      });
721    });
722    
723    const animate = () => {
724      movableElements.each(function() {
725        const element = $(this);
726        const pos = positions.get(this);
727        
728        pos.current.x = lerp(pos.current.x, pos.target.x, config.lerp);
729        pos.current.y = lerp(pos.current.y, pos.target.y, config.lerp);
730        
731        element.css({
732          'left': pos.current.x - (element.outerWidth() / 2) + 'px',
733          'top': pos.current.y - (element.outerHeight() / 2) + 'px'
734        });
735      });
736      
737      animationFrame = requestAnimationFrame(animate);
738    };
739    
740    container.on('mousemove', function(e) {
741      movableElements.each(function() {
742        const pos = positions.get(this);
743        pos.target.x = e.clientX;
744        pos.target.y = e.clientY;
745      });
746    });
747    
748    container.on('mouseenter', function() {
749      cancelAnimationFrame(animationFrame);
750      animate();
751    });
752    
753    container.on('mouseleave', function() {
754      cancelAnimationFrame(animationFrame);
755      const center = getViewportCenter();
756      
757      movableElements.each(function() {
758        const pos = positions.get(this);
759        if (!container.is(':hover')) {
760          pos.target = { x: center.x, y: center.y };
761          pos.current = { x: center.x, y: center.y };
762        }
763      });
764    });
765    
766    $(window).on('resize', function() {
767      const center = getViewportCenter();
768      movableElements.each(function() {
769        const pos = positions.get(this);
770        if (!container.is(':hover')) {
771          pos.target = { x: center.x, y: center.y };
772          pos.current = { x: center.x, y: center.y };
773        }
774      });
775    });
776    
777    movableElements.each(function() {
778      const element = $(this);
779      element.css({
780        'left': center.x - (element.outerWidth() / 2) + 'px',
781        'top': center.y - (element.outerHeight() / 2) + 'px'
782      });
783    });
784  });
785};
786
787// ===== 7. HEADER AND NAVIGATION HANDLING =====
788let lastScrollTop = 0;
789const header = document.getElementById('custom-navbar');
790const headerHeight = header.offsetHeight;
791
792function handleScroll() {
793    if (window.innerWidth >= 992) {
794        header.style.transform = 'translateY(0)';
795        return;
796    }
797
798    let currentScroll = window.pageYOffset || document.documentElement.scrollTop;
799    
800    if (currentScroll > lastScrollTop && currentScroll > headerHeight) {
801        header.style.transform = 'translateY(-100%)';
802    } else {
803        header.style.transform = 'translateY(0)';
804    }
805    
806    lastScrollTop = currentScroll;
807}
808
809window.addEventListener('scroll', handleScroll);
810window.addEventListener('resize', handleScroll);
811
812// Background color handling
813document.querySelectorAll('[class*="mybg-"]').forEach(element => {
814    const classes = element.className.split(' ');
815    const bgClass = classes.find(className => className.startsWith('mybg-'));
816    
817    if (bgClass) {
818        const color = bgClass.split('-')[1];
819        element.style.setProperty('background-color', '#' + color, 'important');
820    }
821});
822// Text color handling
823document.querySelectorAll('[class*="mytext-"]').forEach(element => {
824    const classes = element.className.split(' ');
825    const textClass = classes.find(className => className.startsWith('mytext-'));
826    
827    if (textClass) {
828        const color = textClass.split('-')[1];
829        element.style.setProperty('color', '#' + color, 'important');
830    }
831});
832
833// ===== 8. SECTION VISIBILITY TRACKING =====
834function initSectionObserver() {
835    const sections = document.querySelectorAll('[id]');
836    const navLinks = document.querySelectorAll('a[href^="#"]');
837    
838    if (sections.length === 0 || navLinks.length === 0) {
839        console.warn('Nebyly nalezeny žádné sekce nebo odkazy!');
840        return;
841    }
842
843    const observerOptions = {
844        root: null,
845        rootMargin: '-50% 0px -50% 0px', // Sledujeme střed viewportu
846        threshold: 0  // Stačí jakákoliv viditelnost
847    };
848
849    const observer = new IntersectionObserver((entries) => {
850        // Najdeme sekci, která je nejvíce ve viewportu
851        let maxVisibleSection = null;
852        let maxVisibleRatio = 0;
853
854        entries.forEach(entry => {
855            const rect = entry.boundingClientRect;
856            const windowHeight = window.innerHeight;
857            
858            // Vypočítáme, jak moc je sekce ve středu viewportu
859            const distanceFromCenter = Math.abs(
860                (rect.top + rect.height / 2) - (windowHeight / 2)
861            );
862
863            if (entry.isIntersecting && (!maxVisibleSection || distanceFromCenter < maxVisibleRatio)) {
864                maxVisibleSection = entry.target;
865                maxVisibleRatio = distanceFromCenter;
866            }
867        });
868
869        if (maxVisibleSection) {
870            navLinks.forEach(link => link.classList.remove('active'));
871            const activeLink = document.querySelector(`a[href="#${maxVisibleSection.id}"]`);
872            if (activeLink) activeLink.classList.add('active');
873        }
874    }, observerOptions);
875
876    sections.forEach(section => observer.observe(section));
877
878    navLinks.forEach(link => {
879        link.addEventListener('click', (e) => {
880            e.preventDefault();
881            const targetId = link.getAttribute('href').substring(1);
882            const targetElement = document.getElementById(targetId);
883            if (targetElement) {
884                targetElement.scrollIntoView({ behavior: 'smooth' });
885            }
886        });
887    });
888}
889
890if (document.readyState === 'loading') {
891    document.addEventListener('DOMContentLoaded', initSectionObserver);
892} else {
893    initSectionObserver();
894}
895
896// ===== 9. DOCUMENT READY HANDLERS =====
897$(document).ready(function() {
898    new CustomCursor();
899    
900    lineUpFormat('.ci-line', function() {
901        //lightBoldFormat('.lightBoldTitle');
902    });
903    
904    $('.showImageOrVideoOnOver').showImageOrVideoOnOver({
905        lerp: 0.025
906    });
907
908    const $showDifferencesToggle = $('#showDifferences');
909    if ($showDifferencesToggle.length) {
910        const updateDifferencesState = () => {
911            const $differencesLists = $('ul.activeDifferences');
912            if (!$differencesLists.length) return;
913            $differencesLists.toggleClass('isActive', $showDifferencesToggle.is(':checked'));
914        };
915
916        $showDifferencesToggle.on('change', updateDifferencesState);
917        updateDifferencesState();
918    }
919
920    $('[class*="more-items-"]').on('click touchstart', function() {
921		
922		// Počkej chvíli, aby se nový obsah stihl načíst a vložit do DOM
923		setTimeout(function() {
924			handleResponsiveImages(true);
925		}, 100);
926	});
927
928    // Header and content height setup
929    const headerHeight = $('header').outerHeight(true);
930    const footerHeight = $('footer').outerHeight(true);
931    const contentHeight = $(window).height() - headerHeight - footerHeight;
932    const fixedContentHeight = $(window).height() - footerHeight;
933
934    if ($('header').hasClass('fixed-top')) {
935        $('#main').css({ 'min-height': fixedContentHeight });
936    } else {
937        $('#main').css({ 'min-height': contentHeight });
938    }
939
940    // Lazy video loading
941    if ($('.lazy-video').length) {
942        $('.lazy-video').each(function() {
943            var lazyvideo = $(this);
944            var lazyvideoParent = $(this).parent();
945            var lazyTop = lazyvideo.offset().top;
946
947            if (lazyTop < $(window).height()) {
948                var src = lazyvideo.attr('data-src');
949                lazyvideo.attr('src', src);
950                if (!lazyvideoParent.hasClass('loaded')) {
951                    lazyvideoParent.trigger('load');
952                    lazyvideoParent.trigger('play');
953                    lazyvideoParent.addClass('loaded');
954                }
955            }
956        });
957    }
958
959    // Menu handlers
960    $('body').on('click', '.menu-toggler-svg', function(e) {
961        e.preventDefault();
962        $('body').toggleClass('modal-open mobile-open');
963        $('html').toggleClass('modal-open');
964    });
965
966    // Form handlers
967    // Proměnná pro uložení aktuální formClass
968    let currentFormClass = '';
969
970    $('.closeForm').on('click touchstart', function(e) {
971        e.preventDefault();
972        $('body').removeClass('formular-open');
973        $('html').removeClass('formular-open');
974        if (currentFormClass) {
975            $('body').removeClass(currentFormClass);
976            currentFormClass = '';
977        }
978    });
979
980    $(document).on('click touchstart', function(e) {
981        if ($('body').hasClass('formular-open')) {
982            // Ignorovat kliknutí na .openForm, .colForm a bootbox modal
983            if (!$(e.target).closest('.colForm').length && 
984                !$(e.target).closest('.openForm').length && 
985                !$(e.target).closest('.bootbox.modal').length) {
986                $('body').removeClass('formular-open');
987                $('html').removeClass('formular-open');
988                if (currentFormClass) {
989                    $('body').removeClass(currentFormClass);
990                    currentFormClass = '';
991                }
992            }
993        }
994    });
995
996    $(document).on('keydown', function(e) {
997        if (e.keyCode === 27 || e.key === 'Escape') {
998            if ($('body').hasClass('formular-open')) {
999                $('body').removeClass('formular-open');
1000                $('html').removeClass('formular-open');
1001                if (currentFormClass) {
1002                    $('body').removeClass(currentFormClass);
1003                    currentFormClass = '';
1004                }
1005            }
1006        }
1007    });
1008
1009    $('.openForm').on('click', function(e) {
1010        e.preventDefault();
1011        const $body = $('body');
1012        const $html = $('html');
1013
1014        if ($body.hasClass('formular-open')) {
1015            $body.removeClass('formular-open');
1016            $html.removeClass('formular-open');
1017            if (currentFormClass) {
1018                $body.removeClass(currentFormClass);
1019                currentFormClass = '';
1020            }
1021        } else {
1022            $body.addClass('formular-open');
1023            $html.addClass('formular-open');
1024
1025            // Extrakce formClass-xxx a přidání do body
1026            const classes = $(this).attr('class').split(' ');
1027            const formClassMatch = classes.find(cls => cls.startsWith('formClass-'));
1028            if (formClassMatch) {
1029                currentFormClass = formClassMatch.replace('formClass-', '');
1030                $body.addClass(currentFormClass);
1031            }
1032
1033            if ($(this).hasClass('getTitle')) {
1034                const btnText = $(this).attr("title");
1035                const pageTitle = document.title;
1036                const msg = btnText + ': ' + pageTitle + '\n\n';
1037                $('#formular_321 #contactForm50-value-dotaz').val(msg);
1038            }
1039            if ($(this).hasClass('getOnlyTitle')) {
1040                const btnText = $(this).attr("title");
1041                const pageTitle = document.title;
1042                const msg = btnText + '\n\n';
1043                $('#formular_321 #contactForm50-value-dotaz').val(msg);
1044            }
1045        }
1046    });
1047
1048    // External links handling
1049    $('a').each(function() {
1050        var a = new RegExp('/' + window.location.host + '/');
1051        if (!a.test(this.href)) {
1052            $(this).attr("target", "_blank");
1053        }
1054    });
1055
1056    // SVG handling
1057    var mySVGsToInject = document.querySelectorAll('img.inject-me');
1058    SVGInjector(mySVGsToInject, {
1059        evalScripts: 'once',
1060        pngFallback: 'assets/png',
1061        each: function (svg) {}
1062    });
1063
1064    if (!Modernizr.svg) {
1065        $('img[src$=".inject-me"]').each(function() {
1066            $(this).attr('src', $(this).attr('src').replace('.svg', '.png'));
1067        });
1068    }
1069
1070    // Cart handling
1071    $('#kosik1Form').submit(function(event) {
1072        if ($('#souhlas:checked').length == 0) {
1073            event.preventDefault();
1074            alert('Pro vytvoření objednávky, musíte souhlasit s Obchodními podmínkami.');
1075            return false;
1076        }
1077    });
1078
1079    if ($("#addToCartFormSubmiter").length) {
1080        $("#addToCartFormSubmiter").click(function(event) {
1081            event.preventDefault();
1082
1083            if (addToCartFormBeforeSubmit()) {
1084                var imageOffset = $(".mainProductImage").offset();
1085                var cartOffset = $(".openCart").offset();
1086
1087                if (typeof(imageOffset) != "undefined" && typeof(cartOffset) != "undefined") {
1088                    aTop = cartOffset.top;
1089                    aLeft = cartOffset.left;
1090
1091                    $(".mainProductImage").clone()
1092                        .appendTo('body')
1093                        .addClass('mainProductImage-copy')
1094                        .css({
1095                            position: "absolute",
1096                            top: imageOffset.top,
1097                            left: imageOffset.left
1098                        })
1099                        .css({zIndex: 9999999999999})
1100                        .animate({
1101                            top: aTop + "px",
1102                            left: aLeft + "px",
1103                            width: "20px",
1104                            opacity: 0
1105                        }, 666, 'swing', function() {
1106                            $("#addToCartForm").submit();
1107                        });
1108                } else {
1109                    $("#addToCartForm").submit();
1110                }
1111            }
1112        });
1113    }
1114	
1115	/*$('.accordion-button').on('click', function(e) {
1116		// Uložíme si referenci na prvek a zjistíme, zda má třídu .collapsed
1117		const $button = $(this);
1118		const isCollapsed = $button.hasClass('collapsed');
1119
1120		// Scrollujeme jen pokud je akordeon zavřený (má třídu .collapsed)
1121		if (isCollapsed) {
1122			const target = $button.closest(".accordion-item")[0];
1123
1124			// Počkáme než se panel otevře a pak scrollujeme
1125			setTimeout(function() {
1126				smoothScroll(target);
1127			}, 300);
1128		}
1129	});*/
1130  /*$('.accordion-button').on('click', function(e) {
1131    e.preventDefault(); // Stop browser's automatic behavior
1132    
1133    var $button = $(this);
1134    var isOpening = $button.hasClass('collapsed');
1135    
1136    // Manually trigger the accordion
1137    var targetId = $button.attr('data-bs-target');
1138    $(targetId).collapse('toggle');
1139    
1140    if (isOpening) {
1141        var $card = $button.closest('.accordion-item');
1142        
1143        setTimeout(function() {
1144            $('html, body').animate({
1145                scrollTop: $card.offset().top - 80
1146            }, 350);
1147        }, 450);
1148    }
1149  });*/
1150
1151  /*$('.accordion-button').on('click', function(e) {
1152    var $button = $(this);
1153    var isOpening = $button.hasClass('collapsed');
1154    
1155    if (isOpening) {
1156        // Don't prevent default - let Bootstrap handle the accordion
1157        var $card = $button.closest('.accordion-item');
1158        var targetId = $button.attr('data-bs-target') || $button.attr('data-target');
1159        var $targetCollapse = $(targetId);
1160        
1161        // Just add scroll behavior when it opens
1162        $targetCollapse.one('shown.bs.collapse', function() {
1163            setTimeout(function() {
1164                $('html, body').animate({
1165                    scrollTop: $card.offset().top - 80
1166                }, 100);
1167            }, 100);
1168        });
1169    }
1170});*/
1171  
1172});
1173
1174// ===== 10. WINDOW LOAD AND SCROLL HANDLERS =====
1175
1176// Window resize handler with debouncing
1177let resizeTimer;
1178$(window).on('resize', function() {
1179  console.log('Resize event triggered');
1180  
1181  // Use debounce to prevent too many calls
1182  clearTimeout(resizeTimer);
1183  resizeTimer = setTimeout(function() {
1184    console.log('Executing resize handler');
1185    
1186    // Handle responsive images with isResize=true
1187    handleResponsiveImages(true);
1188    
1189    // Adjust heights
1190    const headerHeight = $('header').outerHeight(true);
1191    const footerHeight = $('footer').outerHeight(true);
1192    const contentHeight = $(window).height() - headerHeight - footerHeight;
1193    const fixedContentHeight = $(window).height() - footerHeight;
1194
1195    if ($('header').hasClass('fixed-top')) {
1196      $('#main').css({ 'min-height': fixedContentHeight });
1197    } else {
1198      $('#main').css({ 'min-height': contentHeight });
1199    }
1200    
1201    // Mobile menu handling
1202    if ($(window).width() > 768) {
1203      $('body').removeClass('modal-open mobile-open');
1204      $('html').removeClass('modal-open');
1205    }
1206  }, 250); // Wait for 250ms after the last resize event
1207});
1208
1209// Window load handler
1210$(window).on("load", function() {
1211    handleResponsiveImages(false);
1212	
1213	new MiniLazyload({
1214        rootMargin: "500px",
1215        threshold: .5
1216    });
1217
1218    if ($("header").is(".fixed-top")) {
1219        var navbarHeight = $(".navbar").outerHeight(true);
1220        if ($("#main").children(":first").is(".pt-0")) {
1221            $("#main").css({"padding-top": 0});
1222        } else {
1223            $("#main").css({"padding-top": navbarHeight});
1224        }
1225        if ($("#main").children(":first").is(".text-white")) {
1226            $(".desktop-navbar:not(.on-end)").addClass("menu-white");
1227        } else {
1228            $(".desktop-navbar:not(.on-end)").removeClass("menu-white");
1229        }
1230    }
1231
1232    // Popup handling
1233    if (typeof($('[id*="popup-"]')) !== "undefined") {
1234        $('[id*="popup-"]').on('click', function() {
1235            $.cookie('cta-cookie', 'open', { expires: 1 });
1236        });
1237
1238        if ($.cookie('cta-cookie') !== 'open') {
1239            $('[id*="popup-"]').modal();
1240        }
1241    }
1242});
1243
1244// Combined scroll and load handler
1245$(window).on("scroll load", function() {
1246    // Header scroll effects
1247    if ($(this).scrollTop() > 10) {
1248        $('.desktop-navbar:not(.on-end)').removeClass("bg-transparent");
1249        if ($('#main').children(':first').is('.text-white')) {
1250            $('.desktop-navbar:not(.on-end)').removeClass("menu-white");
1251        }
1252        $('header').addClass('small-menu');
1253    } else {
1254        $('.desktop-navbar:not(.on-end)').addClass("bg-transparent");
1255        if ($('#main').children(':first').is('.text-white')) {
1256            $('.desktop-navbar:not(.on-end)').addClass("menu-white");
1257        }
1258        $('header').removeClass('small-menu');
1259    }
1260
1261    // Lazy video loading on scroll
1262    if ($('.lazy-video').length) {
1263        $('.lazy-video').each(function() {
1264            var lazyvideo = $(this);
1265            var lazyvideoParent = $(this).parent();
1266            var viewBottom = $(window).scrollTop() + $(window).height();
1267            var lazyTop = lazyvideo.offset().top;
1268
1269            if (lazyTop <= viewBottom) {
1270                var src = lazyvideo.attr('data-src');
1271                lazyvideo.attr('src', src);
1272                if (!lazyvideoParent.hasClass('loaded')) {
1273                    lazyvideoParent.trigger('load');
1274                    lazyvideoParent.trigger('play');
1275                    lazyvideoParent.addClass('loaded');
1276                }
1277            }
1278        });
1279    }
1280
1281    // Element tracking
1282    if ($('.track').length || $('.track-always').length) {
1283        var windowTop = $(window).scrollTop();
1284        var windowBottom = windowTop + $(window).height();
1285
1286        $('.track').each(function() {
1287            var divTop = $(this).offset().top;
1288            var divBottom = divTop + $(this).height();
1289            if ((divTop + divBottom) / 2 >= windowTop && 
1290                (divTop + divBottom) / 2 <= windowBottom) {
1291                $(this).addClass('in-view');
1292            }
1293        });
1294
1295        $('.track-always').each(function() {
1296            var divTop = $(this).offset().top;
1297            var divBottom = divTop + $(this).height();
1298            if ((divTop + divBottom) / 2 >= windowTop && 
1299                (divTop + divBottom) / 2 <= windowBottom) {
1300                $(this).addClass('in-view');
1301            } else {
1302                $(this).removeClass('in-view');
1303            }
1304        });
1305    }
1306});
1307
1308// Funkce pro přidání části URL za lomítkem jako třídy do body
1309function addPathAsClassToBody() {
1310  // Získání URL cesty za doménou
1311  const path = window.location.pathname;
1312  
1313  // Odstranění počátečního lomítka a získání prvé části cesty
1314  // Například z "/produkty/elektronika" získáme "produkty"
1315  const firstPathSegment = path.split('/').filter(segment => segment !== '')[0] || 'home';
1316  
1317  // Přidání třídy do body elementu
1318  document.body.classList.add(firstPathSegment);
1319  
1320  // Pro účely ladění můžeme vypsat do konzole
1321  //console.log(`Přidána třída '${firstPathSegment}' do body elementu`);
1322}
1323// Initialize tooltips
1324$('[data-toggle="tooltip"],[data-toggle-second="tooltip"]').tooltip({ trigger: 'hover' });
1325// Funkce pro dynamické přepočítávání cen podle hashtagu v URL
1326function updatePricesFromHash() {
1327    // Zkontrolujeme, zda existuje div s class "countPrice"
1328    const countPriceDiv = document.querySelector('.countPrice');
1329    if (!countPriceDiv) {
1330        return; // Pokud div neexistuje, funkce se ukončí
1331    }
1332    
1333    // Přečteme URL a extrahujeme hashtag
1334    const hash = window.location.hash;
1335    if (!hash || hash.length <= 1) {
1336        return; // Pokud není hashtag, ukončíme
1337    }
1338    
1339    // Extrahujeme hodnotu z hashtagu (odstraníme #)
1340    const hashValue = hash.substring(1);
1341    
1342    // Rozdělíme podle středníku na číselnou a textovou část
1343    const hashParts = hashValue.split(';');
1344    const priceValue = hashParts[0];
1345    const nameValue = hashParts[1] ? decodeURIComponent(hashParts[1]) : ''; // Dekódujeme URL encoding
1346    
1347    // Převedeme číselnou část na číslo
1348    const basePrice = parseFloat(priceValue);
1349    
1350    // Zkontrolujeme, zda je hodnota platné číslo
1351    if (isNaN(basePrice) || basePrice <= 0) {
1352        return; // Pokud není platné číslo, ukončíme
1353    }
1354    
1355    // Najdeme prvky s cenami v rámci countPrice divu
1356    const highPriceElement = countPriceDiv.querySelector('.yourPriceHigh');
1357    const middlePriceElement = countPriceDiv.querySelector('.yourPriceMiddle');
1358    const lowPriceElement = countPriceDiv.querySelector('.yourPriceLow');
1359    const nameElement = countPriceDiv.querySelector('.yourPriceName');
1360    
1361    // Aktualizujeme ceny podle koeficientů
1362    if (highPriceElement) {
1363        highPriceElement.textContent = Math.round(basePrice).toLocaleString('cs-CZ');
1364    }
1365    
1366    if (middlePriceElement) {
1367        const middlePrice = basePrice * 0.75;
1368        middlePriceElement.textContent = Math.round(middlePrice).toLocaleString('cs-CZ');
1369    }
1370    
1371    if (lowPriceElement) {
1372        const lowPrice = basePrice * 0.5;
1373        lowPriceElement.textContent = Math.round(lowPrice).toLocaleString('cs-CZ');
1374    }
1375    
1376    // Aktualizujeme název produktu, pokud je textová část k dispozici
1377    if (nameElement && nameValue) {
1378        nameElement.textContent = nameValue;
1379    }
1380}
1381
1382// Spustíme funkci při načtení stránky
1383document.addEventListener('DOMContentLoaded', updatePricesFromHash);
1384
1385// Spustíme funkci při změně hashtagu (pokud uživatel změní URL)
1386window.addEventListener('hashchange', updatePricesFromHash);
1387
1388// Nová jednoduchá funkce pro sledování scrollu a změnu barev
1389function initSectionColorTransition() {
1390  const sections = document.querySelectorAll('.changeSectionColor');
1391  
1392  // Pokud nejsou žádné sekce s třídou changeSectionColor, ukončíme
1393  if (sections.length === 0) return;
1394  
1395  let currentActiveIndex = 0;
1396  
1397  let lastDefinedColor = '#ffffff'; // Uchováváme poslední definovanou barvu
1398  
1399  // Funkce pro získání barvy ze sekce (z class)
1400  function getSectionColor(section) {
1401      const classList = section.className;
1402      const colorMatch = classList.match(/data-sectionColor;([a-fA-F0-9]{6})/);
1403      
1404      if (colorMatch && colorMatch[1]) {
1405          return '#' + colorMatch[1];
1406      }
1407      
1408      return null; // Vrátíme null místo fallback barvy
1409  }
1410  
1411  // Funkce pro aplikaci barvy na všechna sekce
1412  function applyColor(sectionIndex) {
1413      if (sectionIndex !== currentActiveIndex && sectionIndex >= 0 && sectionIndex < sections.length) {
1414          currentActiveIndex = sectionIndex;
1415          const sectionColor = getSectionColor(sections[currentActiveIndex]);
1416          
1417          // Pokud má sekce definovanou barvu, aktualizujeme lastDefinedColor
1418          if (sectionColor !== null) {
1419              lastDefinedColor = sectionColor;
1420          }
1421          // Jinak používáme poslední definovanou barvu (lastDefinedColor zůstává stejná)
1422          
1423          // Aplikujeme aktuální lastDefinedColor na všechna sekce
1424          sections.forEach(section => {
1425              section.style.setProperty('background-color', lastDefinedColor, 'important');
1426          });
1427      }
1428  }
1429  
1430  // Hlavní funkce pro detekci aktivní sekce
1431  function detectActiveSection() {
1432      const windowHeight = window.innerHeight;
1433      const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
1434      
1435      // Threshold: 50% výšky viewportu
1436      const threshold = windowHeight * 0.5;
1437      
1438      // Projdeme všechna sekce a najdeme tu, která je nejvíce viditelná
1439      let bestMatch = currentActiveIndex; // Zachováme současný index jako výchozí
1440      let bestVisibility = 0;
1441      let foundVisibleSection = false;
1442      
1443      sections.forEach((section, index) => {
1444          const rect = section.getBoundingClientRect();
1445          const sectionTop = rect.top;
1446          const sectionBottom = rect.bottom;
1447          
1448          // Vypočítáme, kolik procent sekce je viditelných
1449          let visibleHeight = 0;
1450          
1451          if (sectionTop < 0 && sectionBottom > 0) {
1452              // Sekce začíná nad viewportem
1453              visibleHeight = Math.min(sectionBottom, windowHeight);
1454          } else if (sectionTop >= 0 && sectionTop < windowHeight) {
1455              // Sekce začíná ve viewportu
1456              visibleHeight = Math.min(sectionBottom, windowHeight) - sectionTop;
1457          }
1458          
1459          // Pokud je viditelná alespoň polovina threshold, může být aktivní
1460          if (visibleHeight >= threshold) {
1461              foundVisibleSection = true;
1462              const visibility = visibleHeight / windowHeight;
1463              if (visibility > bestVisibility) {
1464                  bestVisibility = visibility;
1465                  bestMatch = index;
1466              }
1467          }
1468      });
1469      
1470      // Aplikujeme barvu pouze pokud jsme našli viditelnou sekci
1471      if (foundVisibleSection) {
1472          applyColor(bestMatch);
1473      }
1474      // Pokud žádná sekce není dostatečně viditelná, zachováme současnou barvu
1475  }
1476  
1477  // Inicializace - najdeme prvé sekce s definovanou barvou
1478  let initialColorSet = false;
1479  for (let i = 0; i < sections.length; i++) {
1480      const color = getSectionColor(sections[i]);
1481      if (color !== null) {
1482          lastDefinedColor = color;
1483          initialColorSet = true;
1484          break;
1485      }
1486  }
1487  
1488  // Pokud žádná sekce nemá definovanou barvu, použijeme výchozí
1489  if (!initialColorSet) {
1490      lastDefinedColor = '#ffffff';
1491  }
1492  
1493  // Aplikujeme počáteční barvu na všechna sekce
1494  sections.forEach(section => {
1495      section.style.setProperty('background-color', lastDefinedColor, 'important');
1496  });
1497  
1498  // Spustíme detekci aktivní sekce hned po inicializaci
1499  detectActiveSection();
1500  
1501  // Throttled scroll handler s unikátním názvem proměnné
1502  let colorTransitionTicking = false;
1503  function onColorTransitionScroll() {
1504      if (!colorTransitionTicking) {
1505          requestAnimationFrame(() => {
1506              detectActiveSection();
1507              colorTransitionTicking = false;
1508          });
1509          colorTransitionTicking = true;
1510      }
1511  }
1512  
1513  // Event listenery
1514  window.addEventListener('scroll', onColorTransitionScroll);
1515  window.addEventListener('resize', detectActiveSection);
1516}
1517
1518// Spustíme po načtení DOMu
1519document.addEventListener('DOMContentLoaded', initSectionColorTransition);
1520
1521// ===== 11. IMAGE COMPARE SLIDER =====
1522function initImageCompareSliders() {
1523    // Vynutí -full verzi obrázku (compare potřebuje plnou kvalitu)
1524    function toFullSizeUrl(url) {
1525        if (!url) return url;
1526        url = url.replace(/-(?:small|medium|large)(?=[\.\-])/, '-full');
1527        url = url.replace(/\/(small|medium|large)\//, '/full/');
1528        return url;
1529    }
1530
1531    document.querySelectorAll('.imageCompareSlider').forEach(container => {
1532        const images = container.querySelectorAll('img');
1533        if (images.length < 2) return;
1534
1535        const img1Src = toFullSizeUrl(images[0].getAttribute('data-src') || images[0].getAttribute('src'));
1536        const img2Src = toFullSizeUrl(images[1].getAttribute('data-src') || images[1].getAttribute('src'));
1537        const img1Alt = images[0].getAttribute('alt') || '';
1538        const img2Alt = images[1].getAttribute('alt') || '';
1539
1540        // Najdeme .item-1 a nahradíme obsah
1541        const itemCol = container.querySelector('.item-1');
1542        if (!itemCol) return;
1543
1544        itemCol.innerHTML = `
1545            <div class="image-compare-wrapper">
1546                <img src="${img2Src}" alt="${img2Alt}" class="image-compare-after img-fluid" draggable="false">
1547                <div class="image-compare-before">
1548                    <img src="${img1Src}" alt="${img1Alt}" draggable="false">
1549                </div>
1550                <div class="image-compare-handle"></div>
1551            </div>
1552        `;
1553
1554        const wrapper = itemCol.querySelector('.image-compare-wrapper');
1555        const beforeDiv = itemCol.querySelector('.image-compare-before');
1556        const handle = itemCol.querySelector('.image-compare-handle');
1557        const beforeImg = beforeDiv.querySelector('img');
1558
1559        // Inline styly pro wrapper
1560        Object.assign(wrapper.style, {
1561            position: 'relative',
1562            overflow: 'hidden',
1563            cursor: 'col-resize',
1564            userSelect: 'none',
1565            webkitUserSelect: 'none'
1566        });
1567
1568        // After obrázek (spodní vrstva — určuje rozměr)
1569        const afterImg = wrapper.querySelector('.image-compare-after');
1570        Object.assign(afterImg.style, {
1571            display: 'block',
1572            width: '100%',
1573            pointerEvents: 'none'
1574        });
1575
1576        // Before overlay (ořezávaný)
1577        Object.assign(beforeDiv.style, {
1578            position: 'absolute',
1579            top: '0',
1580            left: '0',
1581            height: '100%',
1582            width: '50%',
1583            overflow: 'hidden'
1584        });
1585
1586        // Before obrázek — šířka = celý wrapper, ne jen ořez
1587        Object.assign(beforeImg.style, {
1588            display: 'block',
1589            height: '100%',
1590            objectFit: 'cover',
1591            pointerEvents: 'none'
1592        });
1593
1594        // Handle (svislá čára + kolečko)
1595        Object.assign(handle.style, {
1596            position: 'absolute',
1597            top: '0',
1598            left: '50%',
1599            transform: 'translateX(-50%)',
1600            width: '4px',
1601            height: '100%',
1602            background: '#000',
1603            cursor: 'col-resize',
1604            zIndex: '2'
1605        });
1606
1607        function syncBeforeImgWidth() {
1608            beforeImg.style.width = wrapper.offsetWidth + 'px';
1609        }
1610        syncBeforeImgWidth(); 
1611
1612        let isTouchDragging = false;
1613
1614        function updatePosition(clientX) {
1615            const rect = wrapper.getBoundingClientRect();
1616            let pos = (clientX - rect.left) / rect.width;
1617            pos = Math.max(0, Math.min(1, pos));
1618
1619            beforeDiv.style.width = (pos * 100) + '%';
1620            handle.style.left = (pos * 100) + '%';
1621            syncBeforeImgWidth();
1622        }
1623
1624        // Desktop — handle sleduje kurzor při hoveru
1625        wrapper.addEventListener('mousemove', (e) => {
1626            updatePosition(e.clientX);
1627        });
1628
1629        // Touch — drag na mobilu i na notebooku s touchscreenem
1630        wrapper.addEventListener('touchstart', (e) => {
1631            isTouchDragging = true;
1632            updatePosition(e.touches[0].clientX);
1633        }, { passive: true });
1634
1635        document.addEventListener('touchmove', (e) => {
1636            if (!isTouchDragging) return;
1637            updatePosition(e.touches[0].clientX);
1638            e.preventDefault();
1639        }, { passive: false });
1640
1641        document.addEventListener('touchend', () => {
1642            isTouchDragging = false;
1643        });
1644
1645        // Resize sync
1646        window.addEventListener('resize', syncBeforeImgWidth);
1647    });
1648}
1649
1650document.addEventListener('DOMContentLoaded', initImageCompareSliders);
1651
1652// Spuštění funkce po načtení stránky
1653document.addEventListener('DOMContentLoaded', addPathAsClassToBody);
1654
1655// Initialize tooltips
1656$('[data-toggle="tooltip"],[data-toggle-second="tooltip"]').tooltip({ trigger: 'hover' });
1657
1658// ===== YOUTUBE MOVE =====
1659document.addEventListener('DOMContentLoaded', function() {
1660    const section = document.querySelector('.youtubeMove');
1661    if (!section) return;
1662
1663    const youtubeEl = section.querySelector('.youtubeToMove');
1664    if (!youtubeEl) return;
1665
1666    const articleList = section.querySelector('.article-list-1');
1667    if (!articleList) return;
1668
1669    const firstListItem = articleList.querySelector('.list-item');
1670    articleList.insertBefore(youtubeEl, firstListItem);
1671});

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.