PageSourceSearch

https://gensondoor.com/wp-content/themes/genson-overhead-door-child-theme/inc/js/init.js?ver=1791470270

js gensondoor.com collected 2026-10-08 14:38:22 UTC 28,888 bytes, 856 lines download raw bytes

1jQuery(document).ready(function () {
2    // Add state change to header on scroll  ****************************** //
3
4    if (jQuery("#masthead").length) {
5        var header = jQuery("#masthead");
6        jQuery(window).scroll(function () {
7            var scroll = jQuery(window).scrollTop();
8            if (scroll >= 20) {
9                header.addClass("header-scroll");
10            } else {
11                header.removeClass("header-scroll");
12            }
13        });
14    }
15
16    //Tabbed Content  ****************************** //
17
18    if (jQuery(".tab-wrapper").length) {
19        var jQuerywrapper = jQuery(".tab-wrapper"),
20            jQueryallTabs = jQuerywrapper.find(
21                ".tab-content > div.tab-content__wrapper"
22            ),
23            jQuerytabMenu = jQuerywrapper.find(".tab-menu li");
24
25        jQueryallTabs.not(":first-of-type").hide();
26        jQuerytabMenu.filter(":first-of-type").addClass("active");
27        jQuerytabMenu.filter(":first-of-type").find(":first").width("100%");
28
29        jQuerytabMenu.each(function (i) {
30            jQuery(this).attr("data-tab", "tab" + i);
31        });
32
33        jQueryallTabs.each(function (i) {
34            jQuery(this).attr("data-tab", "tab" + i);
35        });
36
37        jQuerytabMenu.on("click", function () {
38            var dataTab = jQuery(this).data("tab"),
39                jQuerygetWrapper = jQuery(this).closest(jQuerywrapper);
40
41            jQuerygetWrapper.find(jQuerytabMenu).removeClass("active");
42            jQuery(this).addClass("active");
43
44            jQuerygetWrapper.find(jQueryallTabs).hide();
45            jQuerygetWrapper
46                .find(jQueryallTabs)
47                .filter("[data-tab=" + dataTab + "]")
48                .show();
49        });
50    }
51
52    // Tabbed Content Mobile - Optional  ****************************** //
53
54    if (jQuery('.tab-content-mobile').length) {
55        jQuery('.tab-mobile-single-wrap:first-of-type').addClass('active');
56        jQuery('.tab-mobile-single-wrap:first-of-type .tab-information').slideDown();
57
58        jQuery('.tab-topic').on('click', function () {
59
60            if (jQuery(this).parent('.tab-mobile-single-wrap').hasClass('active')) {
61
62                jQuery(this).siblings('.tab-information').slideToggle();
63
64            } else {
65
66                jQuery('.tab-mobile-single-wrap').removeClass('active');
67                jQuery('.tab-information').slideUp();
68                jQuery(this).parent('.tab-mobile-single-wrap').addClass('active');
69                jQuery(this).siblings('.tab-information').slideToggle();
70
71            };
72
73        });
74    }
75
76    // Product Tab Content  ****************************** //
77
78    if (jQuery(".individual-lines-wrapper").length) {
79        jQuery(".line-tab:first-of-type").addClass("active"); // Add active class to the first tab
80        jQuery(".line-tab-info:first-of-type").addClass("active"); // Add active class to the first content
81
82        jQuery(".line-tab").on("click", function () {
83            if (jQuery(this).hasClass("active")) {
84                // do nothing
85            } else {
86                var dataTab = jQuery(this).data("menu-tab"); // Get the data-tab value
87                console.log(dataTab);
88
89                jQuery(this).siblings(".line-tab").removeClass("active"); // Remove active class from siblings
90
91                jQuery(this) // Add active class to the clicked tab
92                    .closest(".line-tab-menu-wrapper")
93                    .siblings(".line-tab-info-wrapper")
94                    .children(".line-tab-info")
95                    .removeClass("active");
96
97                jQuery(this).closest(".line-tab-info").removeClass("active"); // Remove active class from all content
98                jQuery(this).addClass("active"); // Add active class to the clicked tab
99                jQuery("." + dataTab).addClass("active"); // Show the corresponding content based on data-tab value
100            }
101        });
102    }
103
104    // Product Sliders with Slick Loop  ****************************** //
105    // Loops through 10 numbers, giving each slider a unique class and also the next/prev buttons a unique class
106
107    [1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10].forEach(function (i) {
108        jQuery(`.prod-gallery-wrapper-${i}`).slick({
109            infinite: true,
110            slidesToShow: 3,
111            slidesToScroll: 1,
112            nextArrow: jQuery(`.next-btn-${i}`),
113            prevArrow: jQuery(`.prev-btn-${i}`),
114            responsive: [{
115                breakpoint: 768,
116                settings: {
117                    slidesToShow: 2,
118                    infinite: true,
119                },
120            },
121            {
122                breakpoint: 600,
123                settings: {
124                    slidesToShow: 2,
125                },
126            },
127            {
128                breakpoint: 550,
129                settings: {
130                    slidesToShow: 1,
131                    slidesToScroll: 1,
132                },
133            },
134            ],
135        });
136    });
137
138    // Timeline Slider  ****************************** //
139
140    if (jQuery(".timeline-slider").length) {
141        jQuery(".timeline-slider").slick({
142            infinite: false,
143            slidesToShow: 3,
144            slidesToScroll: 1,
145            arrows: true,
146            nextArrow: jQuery(".next-btn"),
147            prevArrow: jQuery(".prev-btn"),
148            responsive: [{
149                breakpoint: 475,
150                settings: {
151                    slidesToShow: 1,
152                },
153            },
154            {
155                breakpoint: 768,
156                settings: {
157                    slidesToShow: 2,
158                },
159            },
160            ],
161        });
162    }
163
164    // Reviews Tiny Slider  ****************************** //
165
166    if (jQuery(".reviews__slider").length) {
167        if (document.getElementsByClassName(".reviews__slider")) {
168            let reviews_slider = tns({
169                container: ".reviews__slider",
170                loop: true,
171                mouseDrag: true,
172                items: 3,
173                slideBy: 1,
174                edgePadding: 0,
175                gutter: 30,
176                autoplay: true,
177                autoplayButtonOutput: false,
178                nav: false,
179                controls: false,
180                speed: 600,
181                responsive: {
182                    375: {
183                        items: 1,
184                        edgePadding: 32,
185                    },
186                    768: {
187                        items: 2,
188                    },
189                    992: {
190                        items: 3,
191                        edgePadding: 0,
192                    },
193                },
194            });
195        }
196    }
197
198    // Trust Factor Tiny Slider For Hero Component  ****************************** //
199
200    if (jQuery(".trust-factors__slider").length) {
201        if (document.getElementsByClassName(".trust-factors__slider")) {
202            let tf_slider = tns({
203                container: ".trust-factors__slider",
204                autoWidth: true,
205                items: 5,
206                slideBy: 1,
207                gutter: 30,
208                autoplay: true,
209                autoplayButtonOutput: false,
210                mouseDrag: true,
211                nav: false,
212                controls: false,
213                speed: 600,
214                responsive: {
215                    375: {
216                        items: 1,
217                    },
218                    768: {
219                        items: 3,
220                    },
221                    992: {
222                        items: 5,
223                    },
224                },
225            });
226        }
227    }
228
229    // Trust Factor Tiny Slider For PB Layout  ****************************** //
230
231    if (jQuery(".section-trust-factors__slider").length) {
232        if (document.getElementsByClassName(".section-trust-factors__slider")) {
233            let tf_section_slider = tns({
234                container: ".section-trust-factors__slider",
235                //autoWidth: true,
236                items: 4,
237                slideBy: 1,
238                gutter: 30,
239                autoplay: true,
240                autoplayButtonOutput: false,
241                mouseDrag: true,
242                nav: false,
243                controls: false,
244                speed: 600,
245                responsive: {
246                    375: {
247                        items: 2,
248                    },
249                    768: {
250                        items: 4,
251                    },
252                    992: {
253                        items: 4,
254                    },
255                },
256            });
257        }
258    }
259
260    if (jQuery(".faqs__wrapper").length) {
261        jQuery(".faq-single:first-of-type").addClass("active");
262        jQuery(".faq-single:first-of-type .faq-content").slideDown();
263
264        jQuery(".faq-single").click(function () {
265            if (jQuery(this).hasClass("active")) {
266                jQuery(".faq-single").removeClass("active");
267                jQuery(".faq-content").slideUp();
268            } else {
269                jQuery(".faq-single").removeClass("active");
270                jQuery(this).addClass("active");
271                jQuery(".faq-content").slideUp();
272                jQuery(this).find(".faq-content").slideDown();
273            }
274        });
275    }
276
277
278    // core Value Accordion
279
280    jQuery(document).ready(function ($) {
281        if ($(".core-values-accordion-wrapper").length) {
282
283            // Hide all accordion content and side content
284            $(".core-value-accordion-item .cv-acc-content").hide();
285            $(".core-value-accordion-item").removeClass("cv-active");
286            $(".section-head .cv-acc-content").hide();
287            $(".core-values-image").hide();
288
289            // Open first accordion item
290            $(".core-value-accordion-item:first-of-type").addClass("cv-active");
291            $(".core-value-accordion-item:first-of-type .cv-acc-content").slideDown();
292
293            // Show first side content
294            $(".section-head .cv-acc-content:first-of-type").show();
295
296            // Show first background image
297            $(".core-values-image:first-of-type").show();
298
299            // Toggle accordion with content and image switching
300            $(".cv-acc-title").click(function () {
301                let parent = $(this).closest(".core-value-accordion-item");
302                let index = parent.index();
303
304                if (parent.hasClass("cv-active")) {
305                    // Close if already active
306                    $(".core-value-accordion-item").removeClass("cv-active");
307                    $(".core-value-accordion-item .cv-acc-content").slideUp();
308                    $(".section-head .cv-acc-content").hide();
309                    $(".core-values-image").hide();
310                } else {
311                    // Open clicked item
312                    $(".core-value-accordion-item").removeClass("cv-active");
313                    parent.addClass("cv-active");
314
315                    // Toggle accordion content
316                    $(".core-value-accordion-item .cv-acc-content").slideUp();
317                    parent.find(".cv-acc-content").slideDown();
318
319                    // Switch side content based on index
320                    $(".section-head .cv-acc-content").hide();
321                    $(".section-head .cv-acc-content").eq(index).show();
322
323                    // Switch background image based on index
324                    $(".core-values-image").hide();
325                    $(".core-values-image").eq(index).show();
326                }
327            });
328
329        }
330    });
331
332
333
334    // Magnifi Pop-up  ****************************** //
335
336    if (jQuery(".yt-video").length) {
337        jQuery(document).ready(function (jQuery) {
338            jQuery(".yt-video").magnificPopup({
339                type: "iframe",
340            });
341        });
342    }
343    if (jQuery(".image-popup").length) {
344        jQuery(document).ready(function (jQuery) {
345            jQuery(".image-popup").magnificPopup({
346                type: "image",
347            });
348        });
349    }
350    if (jQuery(".content-popup").length) {
351        jQuery(document).ready(function (jQuery) {
352            jQuery(".content-popup").magnificPopup({
353                type: "inline",
354                preloader: false,
355                focus: "#name",
356            });
357        });
358    }
359    if (jQuery(".popup").length) {
360        jQuery(document).ready(function (jQuery) {
361            jQuery(".popup").magnificPopup({
362                type: "iframe",
363            });
364        });
365    }
366
367    // Reloads Jquery script after FacetWP is triggered  ****************************** //
368    document.addEventListener("facetwp-loaded", function () {
369        if (jQuery(".image-popup").length) {
370            jQuery(document).ready(function (jQuery) {
371                jQuery(".image-popup").magnificPopup({
372                    type: "image",
373                });
374            });
375        }
376    });
377
378    // Single post scroll progress  ****************************** //
379
380    if (jQuery(".post-progress").length) {
381        window.onscroll = function () {
382            blogProgress();
383        };
384
385        function blogProgress() {
386            var winScroll =
387                document.body.scrollTop || document.documentElement.scrollTop;
388            var height =
389                document.documentElement.scrollHeight -
390                document.documentElement.clientHeight;
391            var scrolled = (winScroll / height) * 100;
392            document.getElementById("scroll-progress").style.width = scrolled + "%";
393        }
394    }
395
396    // Removes Card Links on PPC Page  ****************************** //
397
398    jQuery(".page-template-page-ppc .card--block-link").on("click", function (e) {
399        e.preventDefault();
400    });
401    jQuery(".page-template-page-ppc .ppc-no-link").on("click", function (e) {
402        e.preventDefault();
403    });
404
405    jQuery(".page-template-page-ppc .ppc-no-link").on("click", function (e) {
406        e.preventDefault();
407    });
408
409    // Removes Card Links on Product Pages  ****************************** //
410    jQuery("a.link-no").on("click", function (e) {
411        e.preventDefault();
412    });
413
414    // Removes Card Links on Project Slider  ****************************** //
415    jQuery(".proj-gal-single a ").on("click", function (e) {
416        e.preventDefault();
417    });
418
419    // Slick Slider ****************************** //
420
421    jQuery(".slick-center").slick({
422        centerMode: true,
423        slidesToShow: 3,
424        arrows: true,
425        nextArrow: jQuery(".next-btn-proj"),
426        prevArrow: jQuery(".prev-btn-proj"),
427        responsive: [{
428            breakpoint: 1200,
429            settings: {
430                arrows: false,
431                centerMode: true,
432                slidesToShow: 1,
433                // centerPadding: "200px",
434            },
435        },
436        {
437            breakpoint: 968,
438            settings: {
439                arrows: false,
440                centerMode: true,
441                slidesToShow: 1,
442                centerPadding: "60px",
443            },
444        },
445        {
446            breakpoint: 400,
447            settings: {
448                arrows: false,
449                centerMode: true,
450                slidesToShow: 1,
451                centerPadding: "20px",
452            },
453        },
454        ],
455    });
456
457    jQuery(".slick-center-process").slick({
458        centerMode: true,
459        slidesToShow: 3,
460        infinite: false,
461        dots: true,
462        responsive: [{
463            breakpoint: 968,
464            settings: {
465                arrows: false,
466                centerMode: true,
467                slidesToShow: 1,
468            },
469        },
470        {
471            breakpoint: 480,
472            settings: {
473                arrows: false,
474                centerMode: true,
475                slidesToShow: 1,
476            },
477        },
478        ],
479    });
480
481    jQuery(".slick-process-vert").slick({
482        //centerMode: true,
483        slidesToShow: 2,
484        infinite: false,
485        //dots: true,
486        vertical: true,
487        verticalSwiping: true,
488        responsive: [{
489            breakpoint: 968,
490            settings: {
491                arrows: false,
492                centerMode: true,
493                slidesToShow: 2,
494            },
495        },
496        {
497            breakpoint: 480,
498            settings: {
499                arrows: false,
500                centerMode: true,
501                slidesToShow: 2,
502            },
503        },
504        ],
505    });
506
507    jQuery(".slick-trust").slick({
508        infinite: true,
509        slidesToShow: 4,
510        slidesToScroll: 4,
511        autoplay: true,
512        autoplaySpeed: 5000,
513
514        responsive: [
515            {
516                breakpoint: 1699,
517                settings: {
518                    slidesToShow: 4,
519                    slidesToScroll: 4,
520                },
521            },
522            {
523                breakpoint: 991,
524                settings: {
525                    slidesToShow: 3,
526                    slidesToScroll: 3,
527                    dots: true,
528                },
529            },
530            {
531                breakpoint: 576,
532                settings: {
533                    slidesToShow: 2,
534                    slidesToScroll: 2,
535                    dots: true,
536                },
537            },
538            {
539                breakpoint: 420,
540                settings: {
541                    slidesToShow: 1,
542                    slidesToScroll: 1,
543                    dots: true,
544                },
545            },
546        ],
547    });
548
549    // Recent Article Tiny Slider  ****************************** //
550
551    if (jQuery(".recent-article-slider").length) {
552        if (document.getElementsByClassName(".recent-article-slider")) {
553            let reviews_slider = tns({
554                container: ".recent-article-slider",
555                loop: true,
556                mouseDrag: true,
557                items: 3,
558                slideBy: 1,
559                edgePadding: 0,
560                gutter: 24,
561                autoplay: false,
562                autoplayButtonOutput: false,
563                nav: false,
564                controls: true,
565                speed: 600,
566                responsive: {
567                    1: {
568                        items: 1,
569                    },
570                    768: {
571                        items: 2,
572                    },
573                    992: {
574                        items: 3,
575                    },
576                },
577            });
578        }
579    }
580
581    if (jQuery(".process-main-layout-flow .tab-wrapper").length) {
582        jQuery('.process-main-layout-flow .process_heading').on('click', function () {
583            if (jQuery(this).parents(".process-tab-content").hasClass("active")) {
584                jQuery(this).parents('.process-tab-content').removeClass("active");
585                jQuery(this).next('.process-info').slideUp();
586            } else {
587                jQuery(".process-main-layout-flow .process-tab-content").removeClass("active");
588                jQuery(".process-main-layout-flow .process-info").slideUp("active");
589                jQuery(this).parents('.process-tab-content').addClass("active");
590                jQuery(this).next('.process-info').slideDown();
591            }
592        });
593    }
594
595    if (jQuery(".company-promise .map-graphic-image").length) {
596        jQuery(function ($) {
597            const $section = $('.company-promise'); // change to your section selector
598            const addedClass = 'anim-active';
599
600            function checkSectionAtTop() {
601                const scrollTop = $(window).scrollTop();
602                const sectionOffset = $section.offset().top - 100;
603
604                if (scrollTop >= sectionOffset && !$section.hasClass(addedClass)) {
605                    $section.addClass(addedClass);
606                }
607            }
608
609            $(window).on('scroll resize', checkSectionAtTop);
610            checkSectionAtTop(); // run on page load
611        });
612    }
613
614    jQuery('.loc-tab-btn').on('click', function () {
615        var tab_id = jQuery(this).data('tab');
616
617        jQuery('.loc-tab-btn').removeClass('active');
618        jQuery(this).addClass('active');
619
620        jQuery('.location-tab-panel').removeClass('active');
621        jQuery('#' + tab_id).addClass('active');
622    });
623
624
625    jQuery('.area-tab-btn').on('click', function () {
626        var tabId = jQuery(this).data('tab');
627
628        // Remove active classes from tabs and tab content lists
629        jQuery('.area-tab-btn').removeClass('active');
630        jQuery('.service-tab-content').removeClass('active');
631
632        // Remove active from all maps
633        jQuery('.service-map--code').removeClass('active');
634
635        // Add active class to clicked tab and corresponding content & map
636        jQuery(this).addClass('active');
637        jQuery('#' + tabId).addClass('active');
638
639        // Activate matching map code div, assuming id "area-map-X"
640        var mapId = tabId.replace('area-tab', 'area-map');
641        jQuery('#' + mapId).addClass('active');
642    });
643
644    document.querySelectorAll('a[href^="#"]:not(.proj-gal-single a, .image-popup)').forEach(anchor => {
645        anchor.addEventListener('click', function (e) {
646            e.preventDefault();
647
648            const targetID = this.getAttribute('href').slice(1); // Remove the '#' from the href
649            const targetElement = document.getElementById(targetID);
650
651            if (targetElement) {
652                const headerHeight = document.querySelector('#masthead')?.offsetHeight || 0;
653                const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - headerHeight;
654
655                window.scrollTo({
656                    top: targetPosition,
657                    behavior: 'smooth'
658                });
659            }
660        });
661    });
662
663    jQuery('.form-with-cta .form_btn').on('click', function (e) {
664        e.preventDefault();
665        var parent = jQuery(this).closest('.form-with-cta');
666        parent.find('.form_inner').hide();
667        parent.find('.form-block').fadeIn();
668    });
669
670    console.log("All Scrips Loaded");
671}); // End Document.Ready
672
673(function () {
674    // Utility to decide if an element is visually hidden
675    function isHidden(el) {
676        if (!el) return true;
677        // hidden attribute or aria-hidden
678        if (el.hidden) return true;
679        if (el.getAttribute && el.getAttribute('aria-hidden') === 'true') return true;
680
681        // inline style explicitly hiding
682        var inlineStyle = el.getAttribute && el.getAttribute('style');
683        if (inlineStyle && /display\s*:\s*none/.test(inlineStyle)) return true;
684
685        // computed style (covers CSS rules)
686        var cs = window.getComputedStyle(el);
687        if (!cs || cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0') return true;
688
689        // fallback: if it's not in layout
690        if (el.offsetParent === null && cs.position !== 'fixed') return true;
691
692        return false;
693    }
694
695    // Apply or remove class on the nearest .tns-outer for one controls element
696    function syncControlsToOuter(controlsEl) {
697        var outer = controlsEl.closest ? controlsEl.closest('.tns-outer') : document.querySelector('.tns-outer');
698        if (!outer) return;
699        if (isHidden(controlsEl)) {
700            outer.classList.add('no-controls');
701        } else {
702            outer.classList.remove('no-controls');
703        }
704    }
705
706    // Set up observer for a particular controls element
707    function observeControls(controlsEl) {
708        // Initial sync
709        syncControlsToOuter(controlsEl);
710
711        // Observe attribute changes (style, class, hidden, aria-hidden)
712        var mo = new MutationObserver(function (mutations) {
713            // Quick check if any relevant attribute changed; debounce tiny bursts
714            var shouldSync = false;
715            for (var i = 0; i < mutations.length; i++) {
716                var m = mutations[i];
717                if (m.type === 'attributes' && (m.attributeName === 'style' || m.attributeName === 'class' || m.attributeName === 'hidden' || m.attributeName === 'aria-hidden')) {
718                    shouldSync = true;
719                    break;
720                }
721                if (m.type === 'childList') {
722                    shouldSync = true;
723                    break;
724                }
725            }
726            if (shouldSync) {
727                // small timeout to let other scripts finish
728                clearTimeout(controlsEl.__syncTimeout);
729                controlsEl.__syncTimeout = setTimeout(function () {
730                    syncControlsToOuter(controlsEl);
731                }, 50);
732            }
733        });
734
735        mo.observe(controlsEl, {
736            attributes: true,
737            attributeFilter: ['style', 'class', 'hidden', 'aria-hidden'],
738            childList: true,
739            subtree: false
740        });
741
742        // Also observe the nearest parent for inline style/class changes that might hide controls indirectly
743        var parent = controlsEl.parentElement;
744        if (parent) {
745            var parentMo = new MutationObserver(function () {
746                clearTimeout(controlsEl.__syncTimeout);
747                controlsEl.__syncTimeout = setTimeout(function () {
748                    syncControlsToOuter(controlsEl);
749                }, 50);
750            });
751            parentMo.observe(parent, { attributes: true, attributeFilter: ['style', 'class'] });
752        }
753    }
754
755    // Find existing controls and observe them
756    function initExistingControls() {
757        var controls = document.querySelectorAll('.tns-controls');
758        controls.forEach(function (ctrl) {
759            observeControls(ctrl);
760        });
761    }
762
763    // Watch for dynamically added controls (in case the slider is initialized after page load)
764    var bodyObserver = new MutationObserver(function (mutations) {
765        mutations.forEach(function (m) {
766            if (m.addedNodes && m.addedNodes.length) {
767                m.addedNodes.forEach(function (node) {
768                    if (!(node instanceof Element)) return;
769                    if (node.matches && node.matches('.tns-controls')) {
770                        observeControls(node);
771                    } else {
772                        var nested = node.querySelector && node.querySelector('.tns-controls');
773                        if (nested) observeControls(nested);
774                    }
775                });
776            }
777        });
778    });
779
780    document.addEventListener('DOMContentLoaded', function () {
781        initExistingControls();
782        bodyObserver.observe(document.body, { childList: true, subtree: true });
783    });
784
785    // If script loaded after DOM ready
786    if (document.readyState === 'interactive' || document.readyState === 'complete') {
787        initExistingControls();
788        bodyObserver.observe(document.body, { childList: true, subtree: true });
789    }
790})();
791if (jQuery(".process-wrapper").length) {
792    document.addEventListener("DOMContentLoaded", function () {
793        const steps = document.querySelectorAll(".multi-steps li");
794        const progressFill = document.querySelector(".progress-fill");
795        const handle = document.querySelector(".progress-handle");
796        const contents = document.querySelectorAll(".process-tab-content");
797        const track = document.querySelector(".progress-track");
798
799        let activeStep = 0;
800        let dragging = false;
801
802        function getStepPercent(index) {
803            if (steps.length <= 1) return 0;
804            return (index / (steps.length - 1)) * 100;
805        }
806
807        function updateStep(stepIndex) {
808            activeStep = stepIndex;
809
810            const percent = getStepPercent(stepIndex);
811            progressFill.style.width = `${percent}%`;
812            handle.style.left = `${percent}%`;
813
814            steps.forEach((step, i) => {
815                step.classList.toggle("is-active", i === stepIndex);
816            });
817
818            contents.forEach((content, i) => {
819                content.classList.toggle("active", i === stepIndex);
820            });
821        }
822
823        // Step click
824        steps.forEach((step, index) => {
825            step.addEventListener("click", () => updateStep(index));
826        });
827
828        // Drag
829        handle.addEventListener("mousedown", () => {
830            dragging = true;
831            document.body.style.userSelect = "none";
832        });
833
834        document.addEventListener("mouseup", () => {
835            dragging = false;
836            document.body.style.userSelect = "";
837        });
838
839        document.addEventListener("mousemove", (e) => {
840            if (!dragging) return;
841
842            const rect = track.getBoundingClientRect();
843            let offsetX = e.clientX - rect.left;
844            offsetX = Math.max(0, Math.min(offsetX, rect.width));
845
846            const percent = (offsetX / rect.width) * 100;
847            const stepIndex = Math.round((percent / 100) * (steps.length - 1));
848
849            updateStep(stepIndex);
850        });
851
852        // Initialize
853        updateStep(0);
854
855    });
856}

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.