PageSourceSearch

https://lyddager.no/wp-content/plugins/para-elementor-widgets/assets/js/widgets.js?ver=1786089401

js lyddager.no collected 2026-10-09 17:13:09 UTC 34,419 bytes, 1,001 lines download raw bytes

1(function($){
2
3  function readCols($root){
4    return {
5      d: parseInt($root.attr('data-cols-d') || '4', 10),
6      t: parseInt($root.attr('data-cols-t') || '2', 10),
7      m: parseInt($root.attr('data-cols-m') || '1', 10)
8    };
9  }
10
11  function setupAutoHideNav($root){
12    var timer = null;
13    var delay = 2500; // ms før pilene fades bort
14
15    function show(){
16      $root.addClass('is-nav-visible');
17      if(timer) clearTimeout(timer);
18      timer = setTimeout(hide, delay);
19    }
20
21    function hide(){
22      $root.removeClass('is-nav-visible');
23    }
24
25    // Desktop hover
26    $root.on('mouseenter', show);
27    $root.on('mouseleave', function(){
28      if(timer) clearTimeout(timer);
29      timer = setTimeout(hide, 600);
30    });
31
32    // Touch / drag / click
33    $root.on('touchstart mousedown', show);
34    $root.on('touchend mouseup', function(){
35      if(timer) clearTimeout(timer);
36      timer = setTimeout(hide, delay);
37    });
38
39    // Hvis piler klikkes, hold synlig litt
40    $root.on('click', '.pew-ls-nav', function(){
41      show();
42    });
43  }
44
45function buildOpts($root){
46  var c = readCols($root);
47
48  var nav = ($root.attr('data-nav') || 'arrows_dots');
49  var useArrows = (nav === 'arrows' || nav === 'arrows_dots');
50  var useDots = (nav === 'dots' || nav === 'arrows_dots');
51
52  var peek = ($root.attr('data-peek') === '1');
53  var peekFrac = parseFloat($root.attr('data-peek-frac') || '0.22');
54  if (isNaN(peekFrac)) peekFrac = 0.22;
55  if (peekFrac < 0.05) peekFrac = 0.05;
56  if (peekFrac > 0.45) peekFrac = 0.45;
57
58  var group = parseInt($root.attr('data-group') || '1', 10);
59  if (isNaN(group) || group < 1) group = 1;
60
61  function colsForWidth(w){
62    if (w >= 1025) return c.d;
63    if (w >= 768)  return c.t;
64    return c.m;
65  }
66
67  function applyPeekVar(){
68    // CSS-variabel basert på faktisk slide-bredde
69    var $sw = $root.find('.pew-ls__swiper');
70    if (!$sw.length) return;
71
72    var w = $sw[0].clientWidth || 0;
73    var perView = colsForWidth(window.innerWidth || 1200);
74    if (perView < 1) perView = 1;
75
76    var slideW = w / perView;
77    var px = Math.round(slideW * peekFrac);
78
79    $root.toggleClass('is-peek', !!peek);
80    $root[0].style.setProperty('--pew-peek', px + 'px');
81  }
82
83  return {
84    rtl: false,
85
86    // Viktig: behold heltall, ellers mister du “4 fullt synlige”
87    slidesPerView: c.d,
88    slidesPerGroup: group,
89    spaceBetween: 16,
90    speed: 350,
91    watchOverflow: true,
92
93    // Peek med loop for å vise “siste” litt til venstre på første slide
94    loop: !!peek,
95    loopAdditionalSlides: 3,
96
97    // IKKE centered (da blir det “3 i midten + litt på sidene” når du vil ha 4)
98    centeredSlides: false,
99    centeredSlidesBounds: false,
100
101    // Drag/touch
102    simulateTouch: true,
103    grabCursor: true,
104    followFinger: true,
105    threshold: 8,
106    touchStartPreventDefault: false,
107    touchMoveStopPropagation: true,
108
109    navigation: useArrows ? {
110      nextEl: $root.find('.pew-ls-nav--next')[0],
111      prevEl: $root.find('.pew-ls-nav--prev')[0]
112    } : false,
113
114    pagination: useDots ? {
115      el: $root.find('.pew-ls-pagination')[0],
116      clickable: true
117    } : false,
118
119    breakpoints: {
120      0:    { slidesPerView: c.m, slidesPerGroup: group, spaceBetween: 12 },
121      768:  { slidesPerView: c.t, slidesPerGroup: group, spaceBetween: 14 },
122      1025: { slidesPerView: c.d, slidesPerGroup: group, spaceBetween: 16 }
123    },
124
125    on: {
126      init: function(){ applyPeekVar(); },
127      resize: function(){ applyPeekVar(); },
128      breakpoint: function(){ applyPeekVar(); }
129    }
130  };
131}
132
133  function createSwiper(el, opts){
134    // Foretrekk global Swiper hvis den finnes
135    if (window.Swiper) {
136      return new window.Swiper(el, opts);
137    }
138
139    // Elementor sin wrapper kan være funksjon eller class
140    if (window.elementorFrontend && elementorFrontend.utils && elementorFrontend.utils.swiper) {
141      var Ctor = elementorFrontend.utils.swiper;
142      try { return new Ctor(el, opts); } catch(e) {}
143      try { return Ctor(el, opts); } catch(e) {}
144    }
145
146    return null;
147  }
148
149  function initOne($root){
150    if(!$root || !$root.length) return;
151
152    // Tving LTR (i tilfelle forelder har RTL/direction)
153    $root.css('direction', 'ltr');
154    $root.find('.pew-ls-pagination').css('direction', 'ltr');
155
156    // Auto-hide piler
157    setupAutoHideNav($root);
158
159    var el = $root.find('.pew-ls__swiper')[0];
160    if(!el) return;
161
162    // Ikke init 2 ganger
163    if (el.dataset && el.dataset.pewInit === '1') return;
164    if (el.dataset) el.dataset.pewInit = '1';
165
166    var inst = createSwiper(el, buildOpts($root));
167
168    // Elementor kan reflowe – oppdater litt etter init
169    if (inst && typeof inst.update === 'function') {
170      setTimeout(function(){ inst.update(); }, 60);
171      setTimeout(function(){ inst.update(); }, 260);
172    }
173
174    // Hvis Promise (noen Elementor-versjoner)
175    if (inst && typeof inst.then === 'function') {
176      inst.then(function(sw){
177        if(sw && sw.update){
178          setTimeout(function(){ sw.update(); }, 60);
179        }
180      }).catch(function(){});
181    }
182
183    // Vis piler kort ved init, så auto-hide
184    $root.addClass('is-nav-visible');
185    setTimeout(function(){ $root.removeClass('is-nav-visible'); }, 1800);
186  }
187
188function initSectionHeading($root){
189  if(!$root || !$root.length) return;
190
191  $root.each(function(){
192    var root = this;
193    var $item = $(root);
194    if (root.dataset && root.dataset.pewSectionHeadingInit === '1') return;
195    if (root.dataset) root.dataset.pewSectionHeadingInit = '1';
196
197    var slot = $item.find('[data-pew-animated-slot]')[0];
198    if (!slot) return;
199
200    var textEl = slot.querySelector('.pew-section-heading__animated-text');
201    if (!textEl) return;
202
203    var effect = $item.attr('data-effect') || 'none';
204    if (effect === 'none') return;
205
206    var reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
207    var words = [];
208    try { words = JSON.parse($item.attr('data-words') || '[]'); } catch(e) { words = []; }
209    words = words.filter(function(word){ return typeof word === 'string' && word.length; });
210    if (!words.length) return;
211
212    var speed = parseInt($item.attr('data-speed') || '70', 10);
213    var pause = parseInt($item.attr('data-pause') || '1800', 10);
214    var loopMode = $item.attr('data-loop') || 'loop';
215
216    if (isNaN(speed) || speed < 20) speed = 70;
217    if (isNaN(pause) || pause < 500) pause = 1800;
218    if (loopMode !== 'once') loopMode = 'loop';
219
220    if (reduceMotion) {
221      textEl.textContent = words[0];
222      return;
223    }
224
225    var index = 0;
226
227    function showStaticWord(i){
228      textEl.textContent = words[i] || words[0];
229    }
230
231    function showNextWord(){
232      index = (index + 1) % words.length;
233      $item.addClass('is-changing-word');
234      setTimeout(function(){
235        showStaticWord(index);
236        $item.removeClass('is-changing-word');
237      }, 180);
238    }
239
240    if (effect === 'fade' || effect === 'slide') {
241      showStaticWord(0);
242
243      if (words.length === 1) {
244        $item.addClass('is-changing-word');
245        setTimeout(function(){
246          $item.removeClass('is-changing-word');
247        }, 180);
248        return;
249      }
250
251      if (loopMode === 'once') {
252        var onceFadeIndex = 0;
253        var onceFadeTimer = setInterval(function(){
254          onceFadeIndex++;
255          if (onceFadeIndex >= words.length) {
256            clearInterval(onceFadeTimer);
257            showStaticWord(words.length - 1);
258            return;
259          }
260          index = onceFadeIndex - 1;
261          showNextWord();
262        }, pause);
263        return;
264      }
265
266      setInterval(showNextWord, pause);
267      return;
268    }
269
270    if (effect === 'typing') {
271      var charIndex = 0;
272      var deleting = false;
273
274      textEl.textContent = '';
275
276      function tick(){
277        var word = words[index];
278
279        if (!deleting) {
280          charIndex++;
281          textEl.textContent = word.substring(0, charIndex);
282
283          if (charIndex >= word.length) {
284            if (loopMode === 'once' && index >= words.length - 1) {
285              textEl.textContent = word;
286              return;
287            }
288
289            deleting = true;
290            setTimeout(tick, pause);
291            return;
292          }
293        } else {
294          charIndex--;
295          textEl.textContent = word.substring(0, charIndex);
296
297          if (charIndex <= 0) {
298            deleting = false;
299            index = (index + 1) % words.length;
300          }
301        }
302
303        setTimeout(tick, deleting ? Math.max(25, speed * 0.55) : speed);
304      }
305
306      tick();
307    }
308  });
309}
310
311  // Elementor editor + frontend
312  $(window).on('elementor/frontend/init', function(){
313    elementorFrontend.hooks.addAction('frontend/element_ready/para-livestudio-slider.default', function($scope){
314      initOne($scope.find('.pew-ls'));
315    });
316    elementorFrontend.hooks.addAction('frontend/element_ready/para-post-slider-card.default', function($scope){
317      initOne($scope.find('.pew-ls'));
318    });
319    elementorFrontend.hooks.addAction('frontend/element_ready/para-section-heading.default', function($scope){
320      initSectionHeading($scope.find('.pew-section-heading'));
321    });
322
323
324  });
325
326
327
328  // Frontend safety-net
329  $(function(){
330    $('.pew-ls').each(function(){
331      initOne($(this));
332    });
333
334    $('.pew-section-heading').each(function(){
335      initSectionHeading($(this));
336    });
337  });
338
339  function paraOpeningHoursLegacyToday(){
340    var now = new Date();
341    var y = now.getFullYear();
342    var m = String(now.getMonth() + 1).padStart(2, '0');
343    var d = String(now.getDate()).padStart(2, '0');
344    return y + '-' + m + '-' + d;
345  }
346
347  function paraOpeningHoursNumber(value){
348    var parsed = parseInt(value || '0', 10);
349    return Number.isFinite(parsed) ? parsed : 0;
350  }
351
352  function paraOpeningHoursRefreshDates(){
353    var now = Math.floor(Date.now() / 1000);
354    var legacyToday = paraOpeningHoursLegacyToday();
355
356    $('.pew-opening-hours__card[data-pew-opening-date]').each(function(){
357      var $card = $(this);
358      var date = $card.attr('data-pew-opening-date') || '';
359      var dayStart = paraOpeningHoursNumber($card.attr('data-pew-opening-day-start'));
360      var dayEnd = paraOpeningHoursNumber($card.attr('data-pew-opening-day-end'));
361      var pastAt = paraOpeningHoursNumber($card.attr('data-pew-opening-past-at'));
362      var mutePast = $card.attr('data-pew-opening-mute-past') === '1';
363      var markToday = $card.attr('data-pew-opening-mark-today') === '1';
364      var isToday = dayStart && dayEnd ? now >= dayStart && now < dayEnd : date === legacyToday;
365      var isPast = pastAt ? now >= pastAt : date < legacyToday;
366      var $dot = $card.find('.pew-opening-hours__status-dot');
367
368      if (!date) return;
369
370      $card.removeClass('is-past is-today');
371
372      if (mutePast && isPast) {
373        $card.addClass('is-past');
374      }
375
376      if (isPast) {
377        $dot.attr('aria-hidden', 'true').hide();
378      } else {
379        $dot.removeAttr('aria-hidden').show();
380      }
381
382      if (markToday && isToday) {
383        $card.addClass('is-today');
384      }
385    });
386  }
387
388  function paraOpeningHoursParseSchedule(raw){
389    if (!raw) return [];
390
391    try {
392      var parsed = JSON.parse(raw);
393      return Array.isArray(parsed) ? parsed : [];
394    } catch (error) {
395      return [];
396    }
397  }
398
399  function paraOpeningHoursOpenMessage(template, time){
400    return String(template || '').split('%s').join(String(time || ''));
401  }
402
403  function paraOpeningHoursClosedMessage(template, day, time){
404    var message = String(template || '');
405    message = message.split('%1$s').join(String(day || ''));
406    message = message.split('%2$s').join(String(time || ''));
407
408    if (message.indexOf('%s') !== -1) {
409      message = message.replace('%s', String(day || ''));
410      message = message.replace('%s', String(time || ''));
411    }
412
413    return message;
414  }
415
416  function paraOpeningHoursRefreshCompact(){
417    var now = Math.floor(Date.now() / 1000);
418
419    $('.pew-opening-hours__compact[data-pew-opening-schedule]').each(function(){
420      var $compact = $(this);
421      var schedule = paraOpeningHoursParseSchedule($compact.attr('data-pew-opening-schedule'));
422      var openLabel = $compact.attr('data-pew-opening-open-label') || 'ÅPENT';
423      var closedLabel = $compact.attr('data-pew-opening-closed-label') || 'STENGT';
424      var openTemplate = $compact.attr('data-pew-opening-open-template') || 'Holder åpent til klokken %s';
425      var closedTemplate = $compact.attr('data-pew-opening-closed-template') || 'Åpner igjen %1$s klokken %2$s';
426      var todayLabel = $compact.attr('data-pew-opening-today-label') || 'i dag';
427      var noUpcoming = $compact.attr('data-pew-opening-no-upcoming') || 'Ingen kommende åpningstid er satt.';
428      var active = null;
429      var next = null;
430
431      schedule.forEach(function(entry){
432        var openAt = paraOpeningHoursNumber(entry.open_at);
433        var closeAt = paraOpeningHoursNumber(entry.close_at);
434
435        if (!active && openAt && closeAt && now >= openAt && now < closeAt) {
436          active = entry;
437        }
438
439        if (openAt > now && (!next || openAt < paraOpeningHoursNumber(next.open_at))) {
440          next = entry;
441        }
442      });
443
444      if (active) {
445        $compact.removeClass('is-closed').addClass('is-open');
446        $compact.find('.pew-opening-hours__compact-badge').text(openLabel);
447        $compact.find('.pew-opening-hours__compact-message').text(
448          paraOpeningHoursOpenMessage(openTemplate, active.to)
449        );
450        return;
451      }
452
453      $compact.removeClass('is-open').addClass('is-closed');
454      $compact.find('.pew-opening-hours__compact-badge').text(closedLabel);
455
456      if (next) {
457        var dayStart = paraOpeningHoursNumber(next.day_start);
458        var dayEnd = paraOpeningHoursNumber(next.day_end);
459        var dayLabel = dayStart && dayEnd && now >= dayStart && now < dayEnd
460          ? todayLabel
461          : (next.day_name || '');
462
463        $compact.find('.pew-opening-hours__compact-message').text(
464          paraOpeningHoursClosedMessage(closedTemplate, dayLabel, next.from)
465        );
466      } else {
467        $compact.find('.pew-opening-hours__compact-message').text(noUpcoming);
468      }
469    });
470  }
471
472  function paraOpeningHoursRefresh(){
473    paraOpeningHoursRefreshDates();
474    paraOpeningHoursRefreshCompact();
475  }
476
477  $(document).ready(function(){
478    paraOpeningHoursRefresh();
479    setInterval(paraOpeningHoursRefresh, 30000);
480  });
481
482  $(window).on('focus pageshow', paraOpeningHoursRefresh);
483
484  document.addEventListener('visibilitychange', function(){
485    if (!document.hidden) {
486      paraOpeningHoursRefresh();
487    }
488  });
489
490  $(window).on('elementor/frontend/init', function(){
491    if (window.elementorFrontend && elementorFrontend.hooks) {
492      elementorFrontend.hooks.addAction('frontend/element_ready/para-opening-hours.default', function(){
493        paraOpeningHoursRefresh();
494      });
495    }
496  });
497})(jQuery);
498
499(function(){
500  'use strict';
501
502  function initParaEwSliders(root){
503    var scope = root || document;
504    scope.querySelectorAll('[data-para-ew-slider]').forEach(function(slider){
505      var track = slider.querySelector('[data-para-ew-slider-track]');
506      var prev = slider.querySelector('[data-para-ew-slider-prev]');
507      var next = slider.querySelector('[data-para-ew-slider-next]');
508      var dotsWrap = slider.querySelector('[data-para-ew-slider-dots]');
509      var scrollByCards = parseInt(slider.getAttribute('data-para-ew-slider-scroll-by') || '1', 10);
510
511      if (!track) { return; }
512      if (!scrollByCards || scrollByCards < 1) { scrollByCards = 1; }
513
514      function amount(){
515        var card = track.querySelector('.para-ew-employee-slider-card');
516        if (!card) { return Math.max(220, Math.round(track.clientWidth * 0.75)); }
517        var styles = window.getComputedStyle(track);
518        var gap = parseFloat(styles.columnGap || styles.gap || '0') || 0;
519        return (card.getBoundingClientRect().width + gap) * scrollByCards;
520      }
521
522      function maxScroll(){
523        return Math.max(0, track.scrollWidth - track.clientWidth);
524      }
525
526      function pageCount(){
527        var step = amount();
528        if (!step || maxScroll() <= 2) { return 1; }
529        return Math.max(1, Math.ceil(maxScroll() / step) + 1);
530      }
531
532      function activePage(){
533        var step = amount();
534        if (!step) { return 0; }
535        return Math.min(pageCount() - 1, Math.round(track.scrollLeft / step));
536      }
537
538      function updateDots(){
539        var dots = slider.querySelectorAll('.para-ew-employee-slider-dot');
540        if (!dots.length) { return; }
541        var active = activePage();
542        dots.forEach(function(dot, index){
543          dot.classList.toggle('is-active', index === active);
544        });
545      }
546
547      function buildDots(){
548        if (!dotsWrap) { return; }
549        dotsWrap.innerHTML = '';
550        var count = pageCount();
551        if (count <= 1) { return; }
552        for (var i = 0; i < count; i++) {
553          (function(index){
554            var dot = document.createElement('button');
555            dot.type = 'button';
556            dot.className = 'para-ew-employee-slider-dot' + (index === 0 ? ' is-active' : '');
557            dot.setAttribute('aria-label', 'GÃ¥ til slide ' + (index + 1));
558            dot.addEventListener('click', function(){
559              track.scrollTo({left: amount() * index, behavior: 'smooth'});
560            });
561            dotsWrap.appendChild(dot);
562          })(i);
563        }
564      }
565
566      function refresh(){
567        buildDots();
568        updateDots();
569      }
570
571      if (slider.getAttribute('data-para-ew-slider-ready') !== '1') {
572        slider.setAttribute('data-para-ew-slider-ready', '1');
573
574        if (prev) {
575          prev.addEventListener('click', function(){
576            track.scrollBy({left: -amount(), behavior: 'smooth'});
577          });
578        }
579
580        if (next) {
581          next.addEventListener('click', function(){
582            track.scrollBy({left: amount(), behavior: 'smooth'});
583          });
584        }
585
586        track.addEventListener('scroll', function(){
587          window.requestAnimationFrame(updateDots);
588        });
589
590        window.addEventListener('resize', refresh);
591      }
592
593      window.setTimeout(refresh, 40);
594    });
595  }
596
597  if (document.readyState === 'loading') {
598    document.addEventListener('DOMContentLoaded', function(){ initParaEwSliders(document); });
599  } else {
600    initParaEwSliders(document);
601  }
602
603  window.paraEwInitSliders = initParaEwSliders;
604
605  if (window.elementorFrontend && window.elementorFrontend.hooks) {
606    window.elementorFrontend.hooks.addAction('frontend/element_ready/para-employees.default', function($scope){
607      var el = $scope && $scope[0] ? $scope[0] : document;
608      initParaEwSliders(el);
609    });
610  }
611})();
612
613
614(function($){
615  function initParaLogoCarousel($scope){
616    var $widgets = $scope && $scope.length ? $scope.find('.para-ew-logo-carousel-slider') : $('.para-ew-logo-carousel-slider');
617    if ($scope && $scope.hasClass && $scope.hasClass('para-ew-logo-carousel-slider')) $widgets = $widgets.add($scope);
618
619    $widgets.each(function(){
620      var $wrap = $(this);
621      if ($wrap.data('paraLogoReady')) return;
622      $wrap.data('paraLogoReady', true);
623
624      var $track = $wrap.find('.para-ew-logo-carousel-track').first();
625      var $slides = $track.find('.para-ew-logo-carousel-slide');
626      var $dotsWrap = $wrap.find('.para-ew-logo-carousel-dots').first();
627      var autoplay = String($wrap.attr('data-autoplay') || '0') === '1';
628      var speed = parseInt($wrap.attr('data-autoplay-speed') || '3500', 10);
629      var pauseOnHover = $wrap.hasClass('slider-pause-on-hover');
630      var timer = null;
631      var paused = false;
632
633      if (!$track.length || !$slides.length) return;
634
635      function slideStep(){
636        var first = $slides.get(0);
637        if (!first) return Math.max(1, Math.round($track.width()));
638        var rect = first.getBoundingClientRect();
639        var gap = parseFloat(window.getComputedStyle($track.get(0)).columnGap || window.getComputedStyle($track.get(0)).gap || 0) || 0;
640        return Math.max(1, Math.round(rect.width + gap));
641      }
642
643      function maxScroll(){
644        return Math.max(0, $track.get(0).scrollWidth - $track.innerWidth());
645      }
646
647      function currentIndex(){
648        return Math.round($track.scrollLeft() / slideStep());
649      }
650
651      function goTo(index){
652        var max = maxScroll();
653        var left = Math.min(max, Math.max(0, index * slideStep()));
654        $track.get(0).scrollTo({left:left, behavior:'smooth'});
655      }
656
657      function next(){
658        var max = maxScroll();
659        var left = $track.scrollLeft();
660        if (left >= max - 2) {
661          $track.get(0).scrollTo({left:0, behavior:'smooth'});
662        } else {
663          $track.get(0).scrollBy({left:slideStep(), behavior:'smooth'});
664        }
665      }
666
667      function prev(){
668        var left = $track.scrollLeft();
669        if (left <= 2) {
670          $track.get(0).scrollTo({left:maxScroll(), behavior:'smooth'});
671        } else {
672          $track.get(0).scrollBy({left:-slideStep(), behavior:'smooth'});
673        }
674      }
675
676      function buildDots(){
677        if (!$dotsWrap.length) return;
678        $dotsWrap.empty();
679        var pages = Math.max(1, Math.ceil(maxScroll() / slideStep()) + 1);
680        for (var i = 0; i < pages; i++) {
681          $('<button type="button" class="para-ew-logo-carousel-dot" aria-label="GÃ¥ til slide '+(i+1)+'"></button>').attr('data-index', i).appendTo($dotsWrap);
682        }
683        updateDots();
684      }
685
686      function updateDots(){
687        if (!$dotsWrap.length) return;
688        var idx = currentIndex();
689        $dotsWrap.find('.para-ew-logo-carousel-dot').removeClass('is-active').eq(idx).addClass('is-active');
690      }
691
692      function stop(){
693        if (timer) window.clearInterval(timer);
694        timer = null;
695      }
696
697      function start(){
698        stop();
699        if (!autoplay) return;
700        timer = window.setInterval(function(){
701          if (!paused) next();
702        }, Math.max(1000, speed));
703      }
704
705      $wrap.on('click', '.para-ew-logo-carousel-arrow-next', function(e){ e.preventDefault(); next(); });
706      $wrap.on('click', '.para-ew-logo-carousel-arrow-prev', function(e){ e.preventDefault(); prev(); });
707      $wrap.on('click', '.para-ew-logo-carousel-dot', function(e){ e.preventDefault(); goTo(parseInt($(this).attr('data-index') || '0', 10)); });
708      $track.on('scroll', function(){ window.requestAnimationFrame(updateDots); });
709
710      if (pauseOnHover) {
711        $wrap.on('mouseenter focusin', function(){ paused = true; });
712        $wrap.on('mouseleave focusout', function(){ paused = false; });
713      }
714
715      var resizeTimer = null;
716      $(window).on('resize.paraLogoCarousel', function(){
717        window.clearTimeout(resizeTimer);
718        resizeTimer = window.setTimeout(function(){ buildDots(); }, 160);
719      });
720
721      buildDots();
722      start();
723    });
724  }
725
726  $(window).on('elementor/frontend/init', function(){
727    if (window.elementorFrontend && elementorFrontend.hooks) {
728      elementorFrontend.hooks.addAction('frontend/element_ready/para-logo-carousel.default', function($scope){
729        initParaLogoCarousel($scope);
730      });
731    }
732  });
733
734  $(function(){
735    initParaLogoCarousel($(document));
736  });
737})(jQuery);
738
739(function($){
740  'use strict';
741
742  function setOpen($item, open, animate){
743    var $panel = $item.children('.para-ew-accordion-panel');
744    var $button = $item.children('.para-ew-accordion-header');
745
746    if (!$panel.length || !$button.length) return;
747
748    if (open) {
749      $item.addClass('is-open');
750      $button.attr('aria-expanded', 'true');
751
752      if (!animate) {
753        $panel.css('height', 'auto');
754        return;
755      }
756
757      $panel.css('height', '0px');
758      var target = $panel[0].scrollHeight;
759      window.requestAnimationFrame(function(){
760        $panel.css('height', target + 'px');
761      });
762
763      window.setTimeout(function(){
764        if ($item.hasClass('is-open')) $panel.css('height', 'auto');
765      }, 310);
766    } else {
767      $button.attr('aria-expanded', 'false');
768
769      if (!animate) {
770        $item.removeClass('is-open');
771        $panel.css('height', '0px');
772        return;
773      }
774
775      var current = $panel[0].scrollHeight;
776      $panel.css('height', current + 'px');
777
778      window.requestAnimationFrame(function(){
779        $item.removeClass('is-open');
780        $panel.css('height', '0px');
781      });
782    }
783  }
784
785  function initAccordion($scope){
786    var $accordions = $scope.find('.para-ew-accordion');
787    if ($scope.hasClass('para-ew-accordion')) $accordions = $accordions.add($scope);
788
789    $accordions.each(function(){
790      var $accordion = $(this);
791      if ($accordion.data('paraAccordionReady')) return;
792      $accordion.data('paraAccordionReady', true);
793
794      $accordion.children('.para-ew-accordion-item').each(function(){
795        setOpen($(this), $(this).hasClass('is-open'), false);
796      });
797
798      $accordion.on('click', '.para-ew-accordion-header', function(e){
799        e.preventDefault();
800
801        var $button = $(this);
802        var $item = $button.closest('.para-ew-accordion-item');
803        var $root = $item.closest('.para-ew-accordion');
804        var mode = $root.attr('data-mode') || 'accordion';
805        var willOpen = !$item.hasClass('is-open');
806
807        if (mode === 'accordion' && willOpen) {
808          $root.children('.para-ew-accordion-item.is-open').not($item).each(function(){
809            setOpen($(this), false, true);
810          });
811        }
812
813        setOpen($item, willOpen, true);
814
815        if (willOpen && $root.attr('data-scroll-mobile') === 'yes' && window.matchMedia('(max-width: 767px)').matches) {
816          window.setTimeout(function(){
817            var top = $item.offset().top - 90;
818            $('html, body').stop(true).animate({ scrollTop: top }, 260);
819          }, 320);
820        }
821      });
822    });
823  }
824
825  $(window).on('resize', function(){
826    $('.para-ew-accordion .para-ew-accordion-item.is-open > .para-ew-accordion-panel').css('height', 'auto');
827  });
828
829  $(function(){
830    initAccordion($(document));
831  });
832
833  $(window).on('elementor/frontend/init', function(){
834    if (window.elementorFrontend && elementorFrontend.hooks) {
835      elementorFrontend.hooks.addAction('frontend/element_ready/para-accordion.default', function($scope){
836        initAccordion($scope);
837      });
838    }
839  });
840})(jQuery);
841
842(function($){
843  'use strict';
844
845  function formatNumber(value, decimals){
846    decimals = parseInt(decimals, 10) || 0;
847    try {
848      return new Intl.NumberFormat(undefined, { minimumFractionDigits: decimals, maximumFractionDigits: decimals }).format(value);
849    } catch(e) {
850      return Number(value).toFixed(decimals);
851    }
852  }
853
854  function animateStats($scope){
855    var $widgets = $scope.find('.para-ew-stats.has-counter-animation');
856    if ($scope.hasClass('para-ew-stats')) $widgets = $widgets.add($scope);
857
858    $widgets.each(function(){
859      var widget = this;
860      var $widget = $(widget);
861      var duration = parseInt($widget.attr('data-duration'), 10) || 1400;
862      var $numbers = $widget.find('.para-ew-stats-number');
863      if (!$numbers.length) return;
864
865      var run = function(){
866        if ($widget.data('paraStatsAnimated')) return;
867        $widget.data('paraStatsAnimated', true);
868
869        $numbers.each(function(){
870          var el = this;
871          var target = parseFloat($(el).attr('data-target')) || 0;
872          var decimals = parseInt($(el).attr('data-decimals'), 10) || 0;
873          var start = target < 0 ? target : 0;
874          var startTime = null;
875
876          function tick(timestamp){
877            if (!startTime) startTime = timestamp;
878            var progress = Math.min((timestamp - startTime) / duration, 1);
879            var eased = 1 - Math.pow(1 - progress, 3);
880            var current = start + (target - start) * eased;
881            el.textContent = formatNumber(current, decimals);
882            if (progress < 1) {
883              window.requestAnimationFrame(tick);
884            } else {
885              el.textContent = formatNumber(target, decimals);
886            }
887          }
888
889          window.requestAnimationFrame(tick);
890        });
891      };
892
893      if ('IntersectionObserver' in window) {
894        var observer = new IntersectionObserver(function(entries){
895          entries.forEach(function(entry){
896            if (entry.isIntersecting) {
897              run();
898              observer.unobserve(widget);
899            }
900          });
901        }, { threshold: 0.25 });
902        observer.observe(widget);
903      } else {
904        run();
905      }
906    });
907  }
908
909  $(window).on('elementor/frontend/init', function(){
910    elementorFrontend.hooks.addAction('frontend/element_ready/para-stats-counter.default', animateStats);
911  });
912
913  $(function(){
914    animateStats($(document));
915  });
916})(jQuery);
917
918/* PARA Button/Testimonial/Video additions */
919(function($){
920  function initTestimonials($root){
921    if(!$root || !$root.length) return;
922    $root.each(function(){
923      var root = this;
924      var $r = $(root);
925      if(!$r.hasClass('pew-testimonials--slider')) return;
926      if(root.dataset && root.dataset.pewTestimonialsInit === '1') return;
927      if(root.dataset) root.dataset.pewTestimonialsInit = '1';
928      var $track = $r.find('.pew-testimonials__track');
929      var $slides = $r.find('.pew-testimonials__slide');
930      var $dots = $r.find('.pew-testimonials__dots');
931      var index = 0;
932      var timer = null;
933      function perView(){ var v = parseInt(getComputedStyle(root).getPropertyValue('--pew-testimonial-cols') || '1', 10); return Math.max(1, isNaN(v) ? 1 : v); }
934      function maxIndex(){ return Math.max(0, $slides.length - perView()); }
935      function buildDots(){ $dots.empty(); var count = maxIndex() + 1; for(var i=0;i<count;i++){ $('<button class="pew-testimonials__dot" type="button" aria-label="GÃ¥ til slide '+(i+1)+'"></button>').appendTo($dots); } }
936      function go(i){ index = Math.max(0, Math.min(i, maxIndex())); var slide = $slides.get(0); if(!slide) return; var gap = parseFloat(getComputedStyle(root).getPropertyValue('--pew-testimonial-gap')) || 0; var w = slide.getBoundingClientRect().width + gap; $track.css('transform', 'translateX(' + (-index * w) + 'px)'); $dots.find('.pew-testimonials__dot').removeClass('is-active').eq(index).addClass('is-active'); }
937      function start(){ if(($r.attr('data-autoplay') || '') !== 'yes') return; stop(); var speed = parseInt($r.attr('data-autoplay-speed') || '4500', 10); timer = setInterval(function(){ go(index >= maxIndex() ? 0 : index + 1); }, Math.max(1200, speed)); }
938      function stop(){ if(timer) clearInterval(timer); timer = null; }
939      buildDots(); go(0); start();
940      $r.on('click', '.pew-testimonials__nav--next', function(){ stop(); go(index + 1); start(); });
941      $r.on('click', '.pew-testimonials__nav--prev', function(){ stop(); go(index - 1); start(); });
942      $r.on('click', '.pew-testimonials__dot', function(){ stop(); go($(this).index()); start(); });
943      $r.on('mouseenter focusin', stop).on('mouseleave focusout', start);
944      $(window).on('resize', function(){ buildDots(); go(index); });
945    });
946  }
947  function fmt(sec){ sec = Math.max(0, Math.floor(sec || 0)); var m = Math.floor(sec / 60); var s = sec % 60; return m + ':' + (s < 10 ? '0' : '') + s; }
948  function initVideo($root){
949    if(!$root || !$root.length) return;
950    $root.each(function(){
951      var root = this;
952      var $r = $(root);
953      if(root.dataset && root.dataset.pewVideoInit === '1') return;
954      if(root.dataset) root.dataset.pewVideoInit = '1';
955      var video = $r.find('video.pew-video__media').get(0);
956      var iframe = $r.find('iframe.pew-video__iframe').get(0);
957      var $overlay = $r.find('.pew-video__overlay');
958      function playYoutube(){ if(!iframe) return; var src = iframe.getAttribute('src') || iframe.getAttribute('data-src') || ''; if(!src) return; if(src.indexOf('autoplay=1') === -1) src += (src.indexOf('?') === -1 ? '?' : '&') + 'autoplay=1'; iframe.setAttribute('src', src); $r.addClass('is-playing'); }
959      if(video){
960        var $range = $r.find('.pew-video__range');
961        var $cur = $r.find('.pew-video__time--current');
962        var $dur = $r.find('.pew-video__time--duration');
963        function sync(){ var d = video.duration || 0; var c = video.currentTime || 0; $cur.text(fmt(c)); $dur.text(fmt(d)); if(d) $range.val(Math.round((c / d) * 1000)); $r.toggleClass('is-playing', !video.paused); $r.toggleClass('is-paused', video.paused); $r.toggleClass('is-muted', video.muted); }
964        function toggle(){ if(video.paused){ video.play().catch(function(){}); } else { video.pause(); } }
965        $overlay.on('click', toggle);
966        $r.find('.pew-video__toggle').on('click', toggle);
967        $r.find('.pew-video__mute').on('click', function(){ video.muted = !video.muted; sync(); });
968        $r.find('.pew-video__fullscreen').on('click', function(){ var el = $r.find('.pew-video__frame').get(0); if(el && el.requestFullscreen) el.requestFullscreen(); });
969        $range.on('input change', function(){ if(video.duration) video.currentTime = (parseFloat(this.value) / 1000) * video.duration; });
970        $(video).on('loadedmetadata timeupdate play pause volumechange ended', sync);
971        sync();
972      } else if(iframe){
973        $overlay.on('click', playYoutube);
974      }
975    });
976  }
977  function boot($scope){ initTestimonials($scope.find('.pew-testimonials')); initVideo($scope.find('.pew-video')); }
978  $(window).on('elementor/frontend/init', function(){ elementorFrontend.hooks.addAction('frontend/element_ready/global', boot); });
979  $(function(){ boot($(document)); });
980})(jQuery);
981
982(function($){
983  function initParaNotices($scope){
984    var $items = $scope.find('.pew-notice');
985    $items.each(function(){
986      var el = this;
987      var key = el.getAttribute('data-dismiss-key') || '';
988      if(key && window.sessionStorage && sessionStorage.getItem(key) === '1') $(el).addClass('is-dismissed');
989    });
990  }
991  $(document).on('click', '.pew-notice__close', function(e){
992    e.preventDefault();
993    var el = $(this).closest('.pew-notice').get(0);
994    if(!el) return;
995    var key = el.getAttribute('data-dismiss-key') || '';
996    if(key && window.sessionStorage) sessionStorage.setItem(key, '1');
997    $(el).addClass('is-dismissed');
998  });
999  $(window).on('elementor/frontend/init', function(){ elementorFrontend.hooks.addAction('frontend/element_ready/global', initParaNotices); });
1000  $(function(){ initParaNotices($(document)); });
1001})(jQuery);

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.