PageSourceSearch

https://umantis.com/wp-content/themes/umantis-base/assets/js/main.js?ver=1787047907

js umantis.com collected 2026-10-02 05:18:00 UTC 24,900 bytes, 643 lines download raw bytes

1/**
2 * Umantis Clean Theme – main.js
3 *
4 * Drei Aufgaben, null Dependencies:
5 * 1. Mobile Navigation Toggle
6 * 2. Sticky Header mit Scroll-Erkennung
7 * 3. FAQ Accordion
8 *
9 * @package Umantis_Clean
10 * @version 1.0.0
11 */
12
13(function () {
14  'use strict';
15
16  // ─── 1. Mobile Navigation — full-screen overlay with inline accordion panels
17  const toggle      = document.getElementById('nav-toggle');
18  const nav         = document.getElementById('main-nav');
19  const megaPanels  = document.querySelector('[data-mega-panels]');
20  const megaNav     = document.querySelector('[data-mega-nav]');
21  const mqMobile    = window.matchMedia('(max-width: 1024px)');
22
23  /**
24   * Relocate panels so each sits inside its trigger's <li> on mobile
25   * (enables inline accordion) and back into the panels container on desktop
26   * (positioned-absolute overlay below the header).
27   */
28  function placePanelsForViewport() {
29    if (!megaPanels || !megaNav) return;
30    const isMobile = mqMobile.matches;
31    const panels = document.querySelectorAll('[data-mega-panel]');
32    panels.forEach(function (panel) {
33      const key = panel.getAttribute('data-mega-panel');
34      if (isMobile) {
35        const item = megaNav.querySelector('[data-mega-item="' + key + '"]');
36        if (item && !item.contains(panel)) item.appendChild(panel);
37      } else {
38        if (panel.parentElement !== megaPanels) megaPanels.appendChild(panel);
39      }
40    });
41  }
42  placePanelsForViewport();
43  if (mqMobile.addEventListener) {
44    mqMobile.addEventListener('change', function () {
45      // Close menu if we cross the breakpoint while it's open
46      if (nav && nav.classList.contains('is-open')) closeMobileMenu();
47      placePanelsForViewport();
48    });
49  }
50
51  /**
52   * Body scroll-lock while the mobile menu is open.
53   * Preserves current scroll position using a class-based pattern so browsers
54   * don't jump to the top on unlock.
55   */
56  let scrollYOnOpen = 0;
57  function lockBodyScroll(lock) {
58    const html = document.documentElement;
59    const body = document.body;
60    if (lock) {
61      scrollYOnOpen = window.scrollY;
62      body.style.position = 'fixed';
63      body.style.top = '-' + scrollYOnOpen + 'px';
64      body.style.left = '0';
65      body.style.right = '0';
66      html.style.overflow = 'hidden';
67    } else {
68      body.style.position = '';
69      body.style.top = '';
70      body.style.left = '';
71      body.style.right = '';
72      html.style.overflow = '';
73      window.scrollTo(0, scrollYOnOpen);
74    }
75  }
76
77  function closeMobileMenu() {
78    if (!nav || !toggle) return;
79    nav.classList.remove('is-open');
80    toggle.setAttribute('aria-expanded', 'false');
81    toggle.classList.remove('is-active');
82    lockBodyScroll(false);
83    // Also collapse any open accordion panel
84    document.querySelectorAll('.um-mega-panel.is-open').forEach(function (p) {
85      p.classList.remove('is-open');
86      p.setAttribute('aria-hidden', 'true');
87      const key = p.getAttribute('data-mega-panel');
88      const item = megaNav && megaNav.querySelector('[data-mega-item="' + key + '"]');
89      if (item) {
90        item.classList.remove('is-open');
91        const trg = item.querySelector('.um-mega-nav__trigger');
92        if (trg) trg.setAttribute('aria-expanded', 'false');
93      }
94    });
95  }
96
97  function openMobileMenu() {
98    if (!nav || !toggle) return;
99    nav.classList.add('is-open');
100    toggle.setAttribute('aria-expanded', 'true');
101    toggle.classList.add('is-active');
102    if (mqMobile.matches) lockBodyScroll(true);
103  }
104
105  if (toggle && nav) {
106    toggle.addEventListener('click', function (e) {
107      e.stopPropagation();
108      if (nav.classList.contains('is-open')) closeMobileMenu();
109      else openMobileMenu();
110    });
111
112    // ESC closes the mobile menu
113    document.addEventListener('keydown', function (e) {
114      if (e.key === 'Escape' && nav.classList.contains('is-open')) {
115        closeMobileMenu();
116        toggle.focus();
117      }
118    });
119
120    // Tapping a real navigation link closes the menu after navigation fires
121    nav.addEventListener('click', function (e) {
122      const link = e.target.closest('a[href]');
123      if (!link) return;
124      // On mobile, panel-triggers (e.g. "Kontakt", which is an <a href> WITH a
125      // mega panel) only toggle their accordion — they must NOT close the
126      // overlay or navigate. Bugfix: tapping "Kontakt" jumped to the page.
127      if (mqMobile.matches && link.classList.contains('has-panel')) return;
128      // Closing via timeout so the browser has started navigating first.
129      setTimeout(closeMobileMenu, 10);
130    });
131
132    // Prevent inside clicks from closing (outside click handler below triggers)
133    nav.addEventListener('click', function (e) { e.stopPropagation(); });
134  }
135
136
137  // ─── 2. Sticky Header ─────────────────────────────────────────────────
138  const header = document.getElementById('site-header');
139  const spacer = document.querySelector('.um-header-spacer');
140  const topbar = document.querySelector('.um-topbar');
141
142  if (header) {
143    // Threshold matches topbar height (minus small offset for early feedback)
144    // so the header slides to top:0 exactly as the topbar scrolls off-screen.
145    const topbarH = topbar ? topbar.offsetHeight : 32;
146    const threshold = Math.max(8, topbarH - 8);
147    const headerH = header.offsetHeight;
148
149    if (spacer) {
150      spacer.style.height = headerH + 'px';
151    }
152
153    function onScroll() {
154      header.classList.toggle('um-header--scrolled', window.scrollY > threshold);
155    }
156
157    let ticking = false;
158    window.addEventListener('scroll', function () {
159      if (!ticking) {
160        requestAnimationFrame(function () {
161          onScroll();
162          ticking = false;
163        });
164        ticking = true;
165      }
166    }, { passive: true });
167
168    onScroll();
169  }
170
171
172  // ─── 3. FAQ Accordion ─────────────────────────────────────────────────
173  const faqItems = document.querySelectorAll('.um-faq__item');
174
175  faqItems.forEach(function (item) {
176    const question = item.querySelector('.um-faq__question');
177    const answer   = item.querySelector('.um-faq__answer');
178
179    if (!question || !answer) return;
180
181    question.addEventListener('click', function () {
182      const isOpen = item.classList.contains('is-open');
183
184      // Alle schliessen (optional: für "nur einer offen" Verhalten)
185      faqItems.forEach(function (other) {
186        const otherAnswer = other.querySelector('.um-faq__answer');
187        if (other !== item && other.classList.contains('is-open')) {
188          other.classList.remove('is-open');
189          other.querySelector('.um-faq__question').setAttribute('aria-expanded', 'false');
190          if (otherAnswer) otherAnswer.style.maxHeight = '0';
191        }
192      });
193
194      // Toggle aktuelles Item
195      item.classList.toggle('is-open', !isOpen);
196      question.setAttribute('aria-expanded', !isOpen);
197
198      if (!isOpen) {
199        answer.style.maxHeight = answer.scrollHeight + 'px';
200      } else {
201        answer.style.maxHeight = '0';
202      }
203    });
204  });
205
206
207  // ─── 3.5 Scroll-Reveal Animationen (Intersection Observer) ────────────
208  // Alle Elemente mit .um-reveal werden beim Scrollen eingeblendet.
209  if ('IntersectionObserver' in window && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
210    const revealObserver = new IntersectionObserver(function (entries) {
211      entries.forEach(function (entry) {
212        if (entry.isIntersecting) {
213          entry.target.classList.add('is-revealed');
214          revealObserver.unobserve(entry.target);
215        }
216      });
217    }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
218
219    // Automatisch: alle Gutenberg-Groups, Columns, Sections und häufige Blocks
220    const revealTargets = document.querySelectorAll(
221      '.um-page-content .wp-block-group, ' +
222      '.um-page-content .wp-block-columns, ' +
223      '.um-page-content > h2, .um-page-content > h3, ' +
224      '.um-post-body__prose > .wp-block-group, ' +
225      '.um-post-body__prose > .wp-block-heading, ' +
226      '.um-post-body__prose > p, ' +
227      '.um-post-body__prose > ul, ' +
228      '.um-post-body__prose > ol, ' +
229      '.um-post-body__prose > figure, ' +
230      '.um-post-body__prose > blockquote, ' +
231      '.um-reveal, .um-hero__content, .um-feature, .um-stats__item, ' +
232      '.um-testimonial, .um-module-card, .um-case, .um-dual__card, ' +
233      '.um-process__step, .um-highlight-card, .um-stat-card, ' +
234      '.um-card--post'
235    );
236    revealTargets.forEach(function (el, i) {
237      // Skip elements taller than 2x viewport — they'd never trigger
238      // the IntersectionObserver reliably and stay invisible (opacity:0)
239      if (el.offsetHeight > window.innerHeight * 2) return;
240      el.classList.add('um-reveal');
241      // Kleine gestaffelte Verzögerung für Kaskaden-Effekt bei Grid-Children
242      const parent = el.parentElement;
243      if (parent && (parent.classList.contains('um-grid') ||
244          parent.classList.contains('wp-block-columns') ||
245          parent.classList.contains('um-process') ||
246          parent.classList.contains('um-testimonials') ||
247          parent.classList.contains('um-stats'))) {
248        const siblings = Array.from(parent.children).filter(c => c.classList.contains('um-reveal'));
249        const idx = siblings.indexOf(el);
250        if (idx >= 0) el.style.transitionDelay = (idx * 80) + 'ms';
251      }
252      revealObserver.observe(el);
253    });
254  } else {
255    // Fallback: sofort sichtbar
256    document.querySelectorAll('.um-reveal').forEach(function (el) {
257      el.classList.add('is-revealed');
258    });
259  }
260
261
262  // ─── 4. Mega-Nav (Desktop) — hover-intent + focus + keyboard + backdrop ─
263  // megaNav and megaPanels were already declared at the top for the mobile
264  // nav infrastructure; we reuse them here. Only the backdrop element is new.
265  const megaPanelsEl = megaPanels;
266  const megaBackdrop = document.querySelector('[data-mega-backdrop]');
267
268  if (megaNav && megaPanelsEl) {
269    const triggers = megaNav.querySelectorAll('.um-mega-nav__trigger.has-panel');
270    const panels   = megaPanelsEl.querySelectorAll('.um-mega-panel');
271
272    const OPEN_DELAY  = 80;   // ms hover-intent delay before opening
273    const CLOSE_DELAY = 220;  // ms grace period before closing (travel to panel)
274
275    let openKey   = null;
276    let openTimer = null;
277    let closeTimer = null;
278
279    // NOTE: On mobile we relocate panels out of megaPanelsEl into each
280    // trigger's <li>, so querying the whole document makes the lookup
281    // work for both viewports.
282    function panelByKey(key) {
283      return document.querySelector('[data-mega-panel="' + key + '"]');
284    }
285    function itemByKey(key) {
286      return megaNav.querySelector('[data-mega-item="' + key + '"]');
287    }
288
289    function openPanel(key) {
290      if (key === openKey) return;
291      closePanel(openKey, true);
292      const panel = panelByKey(key);
293      const item  = itemByKey(key);
294      if (!panel || !item) return;
295      panel.classList.add('is-open');
296      panel.setAttribute('aria-hidden', 'false');
297      item.classList.add('is-open');
298      const trigger = item.querySelector('.um-mega-nav__trigger');
299      if (trigger) trigger.setAttribute('aria-expanded', 'true');
300      if (megaBackdrop) megaBackdrop.classList.add('is-visible');
301      openKey = key;
302    }
303
304    function closePanel(key, immediate) {
305      if (!key) return;
306      const panel = panelByKey(key);
307      const item  = itemByKey(key);
308      if (!panel || !item) return;
309      panel.classList.remove('is-open');
310      panel.setAttribute('aria-hidden', 'true');
311      item.classList.remove('is-open');
312      const trigger = item.querySelector('.um-mega-nav__trigger');
313      if (trigger) trigger.setAttribute('aria-expanded', 'false');
314      if (openKey === key) openKey = null;
315      if (!openKey && megaBackdrop) megaBackdrop.classList.remove('is-visible');
316    }
317
318    function closeAll(immediate) {
319      panels.forEach(function (p) {
320        const k = p.getAttribute('data-mega-panel');
321        p.classList.remove('is-open');
322        p.setAttribute('aria-hidden', 'true');
323        const item = itemByKey(k);
324        if (item) item.classList.remove('is-open');
325        const trg = item && item.querySelector('.um-mega-nav__trigger');
326        if (trg) trg.setAttribute('aria-expanded', 'false');
327      });
328      openKey = null;
329      if (megaBackdrop) megaBackdrop.classList.remove('is-visible');
330    }
331
332    function scheduleOpen(key) {
333      clearTimeout(closeTimer);
334      clearTimeout(openTimer);
335      if (key === openKey) return;
336      openTimer = setTimeout(function () { openPanel(key); }, OPEN_DELAY);
337    }
338
339    function scheduleClose() {
340      clearTimeout(openTimer);
341      clearTimeout(closeTimer);
342      closeTimer = setTimeout(function () { closeAll(false); }, CLOSE_DELAY);
343    }
344
345    // Trigger hover / focus
346    triggers.forEach(function (trg) {
347      const item = trg.closest('[data-mega-item]');
348      const key  = item && item.getAttribute('data-mega-item');
349      if (!key) return;
350
351      item.addEventListener('mouseenter', function () { scheduleOpen(key); });
352      item.addEventListener('mouseleave', function () { scheduleClose(); });
353      trg.addEventListener('focus', function () { scheduleOpen(key); });
354
355      // Click toggles the panel.
356      trg.addEventListener('click', function (e) {
357        // On mobile EVERY panel-trigger toggles its inline accordion and never
358        // navigates — including anchors with an href like "Kontakt".
359        // stopPropagation keeps the overlay open (prevents the nav-close handler).
360        if (mqMobile.matches && trg.classList.contains('has-panel')) {
361          e.preventDefault();
362          e.stopPropagation();
363          if (openKey === key) closePanel(key, false);
364          else openPanel(key);
365          return;
366        }
367        // Desktop: only <button> toggles; anchors with href navigate as before.
368        if (trg.tagName === 'BUTTON') {
369          e.preventDefault();
370          if (openKey === key) closePanel(key, false);
371          else openPanel(key);
372        }
373      });
374
375      // Enter/Space on <a> trigger opens panel (doesn't navigate if no href)
376      trg.addEventListener('keydown', function (e) {
377        if (e.key === 'Enter' || e.key === ' ') {
378          if (trg.tagName === 'BUTTON' || (trg.tagName === 'A' && !trg.getAttribute('href'))) {
379            e.preventDefault();
380            if (openKey === key) closePanel(key, false);
381            else openPanel(key);
382          }
383        } else if (e.key === 'Escape' && openKey === key) {
384          closePanel(key, false);
385          trg.focus();
386        }
387      });
388    });
389
390    // Panels stay open while the cursor hovers the panel itself
391    panels.forEach(function (p) {
392      p.addEventListener('mouseenter', function () { clearTimeout(closeTimer); });
393      p.addEventListener('mouseleave', function () { scheduleClose(); });
394
395      // Focus-within keeps panel open for keyboard users
396      p.addEventListener('focusin', function () { clearTimeout(closeTimer); });
397      p.addEventListener('focusout', function (e) {
398        // If focus moves outside both panel and nav, schedule close
399        const next = e.relatedTarget;
400        if (!next || (!p.contains(next) && !megaNav.contains(next))) scheduleClose();
401      });
402
403      // Esc inside panel closes it
404      p.addEventListener('keydown', function (e) {
405        if (e.key === 'Escape') {
406          const key = p.getAttribute('data-mega-panel');
407          const item = itemByKey(key);
408          const trg = item && item.querySelector('.um-mega-nav__trigger');
409          closePanel(key, false);
410          if (trg) trg.focus();
411        }
412      });
413    });
414
415    // Click backdrop or outside → close
416    if (megaBackdrop) {
417      megaBackdrop.addEventListener('click', function () { closeAll(false); });
418    }
419    document.addEventListener('click', function (e) {
420      if (!openKey) return;
421      const header = document.getElementById('site-header');
422      if (header && !header.contains(e.target)) closeAll(false);
423    });
424  }
425
426
427  // ─── 5. Partner Grid Filtering ─────────────────────────────────────
428  var partnerFilters = document.querySelector('[data-partner-filters]');
429  var partnerGrid = document.querySelector('[data-partner-grid]');
430  if (partnerFilters && partnerGrid) {
431    var filterBtns = partnerFilters.querySelectorAll('.um-partner-filter');
432    var cards = partnerGrid.querySelectorAll('.um-partner-card');
433
434    partnerFilters.addEventListener('click', function (e) {
435      var btn = e.target.closest('.um-partner-filter');
436      if (!btn) return;
437      var filter = btn.getAttribute('data-filter');
438
439      // Update active pill
440      filterBtns.forEach(function (b) { b.classList.toggle('is-active', b === btn); });
441
442      // Filter cards
443      cards.forEach(function (card) {
444        if (filter === 'all') {
445          card.classList.remove('is-hidden');
446          card.style.position = '';
447          card.style.width = '';
448          card.style.height = '';
449          card.style.overflow = '';
450        } else {
451          var tags = (card.getAttribute('data-tags') || '').split(' ');
452          var match = tags.indexOf(filter) !== -1;
453          card.classList.toggle('is-hidden', !match);
454          if (!match) {
455            // Remove from flow so grid reflows
456            setTimeout(function () {
457              if (card.classList.contains('is-hidden')) {
458                card.style.position = 'absolute';
459                card.style.width = '0';
460                card.style.height = '0';
461                card.style.overflow = 'hidden';
462              }
463            }, 350);
464          } else {
465            card.style.position = '';
466            card.style.width = '';
467            card.style.height = '';
468            card.style.overflow = '';
469          }
470        }
471      });
472    });
473  }
474
475  // ─── 5b. Glossar: Letter-Nav Active State + Smooth Scroll ──────────
476  var glossarNav = document.querySelector('.um-glossar-nav');
477  var glossarGroups = document.querySelectorAll('.um-glossar-group');
478  if (glossarNav && glossarGroups.length) {
479    var letterLinks = glossarNav.querySelectorAll('.um-glossar-letter');
480
481    // Smooth scroll mit Sticky-Nav-Offset
482    letterLinks.forEach(function (link) {
483      link.addEventListener('click', function (e) {
484        var href = link.getAttribute('href');
485        if (!href || href === '#' || link.classList.contains('is-disabled')) {
486          if (link.classList.contains('is-disabled')) e.preventDefault();
487          return;
488        }
489        var target = document.querySelector(href);
490        if (!target) return;
491        e.preventDefault();
492        var offset = glossarNav.offsetHeight + 12;
493        var top = target.getBoundingClientRect().top + window.pageYOffset - offset;
494        window.scrollTo({ top: top, behavior: 'smooth' });
495        history.replaceState(null, '', href);
496      });
497    });
498
499    // IntersectionObserver → aktiver Buchstabe basierend auf Scroll-Position
500    if ('IntersectionObserver' in window) {
501      var activeMap = {};
502      var io = new IntersectionObserver(function (entries) {
503        entries.forEach(function (entry) {
504          activeMap[entry.target.id] = entry.isIntersecting ? entry.intersectionRatio : 0;
505        });
506        // Höchstes Ratio gewinnt
507        var topId = null, topRatio = 0;
508        Object.keys(activeMap).forEach(function (id) {
509          if (activeMap[id] > topRatio) { topRatio = activeMap[id]; topId = id; }
510        });
511        letterLinks.forEach(function (l) {
512          var h = l.getAttribute('href');
513          l.classList.toggle('is-active', topId && h === '#' + topId);
514        });
515      }, {
516        rootMargin: '-20% 0px -60% 0px',
517        threshold: [0, 0.25, 0.5, 0.75, 1],
518      });
519      glossarGroups.forEach(function (g) { io.observe(g); });
520    }
521  }
522
523  // ─── 5a. Homepage: Umantis Rainbow (HR-Suite visualization) ─────────
524  var rainbow = document.querySelector('[data-rainbow]');
525  if (rainbow) {
526    var allSegBtns = rainbow.querySelectorAll('[data-seg]');
527    var allPanels = rainbow.querySelectorAll('[data-panel-key]');
528
529    function activateSegment(key) {
530      // Show the matching panel, hide others
531      allPanels.forEach(function (p) {
532        p.style.display = p.getAttribute('data-panel-key') === key ? '' : 'none';
533      });
534
535      // Update active states on tab pills inside ALL visible panels
536      rainbow.querySelectorAll('.ur-tab').forEach(function (t) {
537        t.classList.toggle('is-active', t.getAttribute('data-seg') === key);
538      });
539
540      // Update band active states
541      rainbow.querySelectorAll('.ur-band').forEach(function (b) {
542        b.classList.toggle('is-active', b.getAttribute('data-seg') === key);
543      });
544    }
545
546    // Click handler on any [data-seg] element (SVG groups, bands, tabs)
547    rainbow.addEventListener('click', function (e) {
548      var segEl = e.target.closest('[data-seg]');
549      if (!segEl) return;
550      var key = segEl.getAttribute('data-seg');
551      if (key) activateSegment(key);
552    });
553  }
554
555  // ─── 5b. Homepage: Product Explorer Tabs ───────────────────────────────
556  const explorer = document.querySelector('[data-explorer]');
557  if (explorer) {
558    const tabs = explorer.querySelectorAll('[data-tab]');
559    const panels = explorer.querySelectorAll('[data-panel]');
560    tabs.forEach(function (tab) {
561      tab.addEventListener('click', function () {
562        const idx = tab.getAttribute('data-tab');
563        tabs.forEach(function (t) {
564          t.classList.toggle('is-active', t === tab);
565          t.style.color = t === tab ? 'var(--um-color-white, #faf7f2)' : 'rgba(250,247,242,0.6)';
566          t.style.background = t === tab ? 'rgba(222,50,60,0.12)' : 'transparent';
567          var icon = t.querySelector('span:first-child');
568          if (icon) {
569            icon.style.background = t === tab ? '#de323c' : 'rgba(255,255,255,0.08)';
570            icon.style.color = t === tab ? 'white' : 'rgba(250,247,242,0.7)';
571          }
572        });
573        panels.forEach(function (p) {
574          p.style.display = p.getAttribute('data-panel') === idx ? 'flex' : 'none';
575        });
576      });
577    });
578  }
579
580  // ─── 6. Homepage: Picker Quiz ────────────────────────────────────────
581  var picker = document.querySelector('[data-picker]');
582  if (picker) {
583    var currentStep = 0;
584    var answers = [];
585    var steps = picker.querySelectorAll('[data-step]');
586    var dots = picker.querySelectorAll('.um-hp-picker__dot');
587
588    function showStep(idx) {
589      steps.forEach(function (s) { s.style.display = 'none'; });
590      var target = idx === 'result'
591        ? picker.querySelector('[data-step="result"]')
592        : picker.querySelector('[data-step="' + idx + '"]');
593      if (target) target.style.display = '';
594
595      dots.forEach(function (d, i) {
596        d.style.background = i <= (idx === 'result' ? 3 : idx) ? '#de323c' : '';
597      });
598    }
599
600    picker.addEventListener('click', function (e) {
601      var opt = e.target.closest('.um-hp-picker__option');
602      if (opt) {
603        answers[currentStep] = opt.getAttribute('data-answer');
604        // Visual feedback
605        var siblings = opt.parentElement.querySelectorAll('.um-hp-picker__option');
606        siblings.forEach(function (s) {
607          s.style.borderColor = s === opt ? '#de323c' : '';
608          s.style.background = s === opt ? '#fdf5f5' : '#fff';
609        });
610
611        // Auto-advance after 400ms
612        setTimeout(function () {
613          currentStep++;
614          if (currentStep >= 3) {
615            // Determine result based on answers
616            var cCount = answers.filter(function (a) { return a === 'C'; }).length;
617            var titleEl = picker.querySelector('[data-picker-title]');
618            var descEl = picker.querySelector('[data-picker-desc]');
619            if (cCount >= 2) {
620              if (titleEl) titleEl.textContent = 'HR-Suite Flex';
621              if (descEl) descEl.textContent = 'Massgeschneidert für Ihre komplexen Strukturen, individuellen Prozesse und hohen Anforderungen.';
622            }
623            showStep('result');
624          } else {
625            showStep(currentStep);
626          }
627        }, 400);
628      }
629
630      // Reset button
631      if (e.target.closest('[data-picker-reset]')) {
632        currentStep = 0;
633        answers = [];
634        picker.querySelectorAll('.um-hp-picker__option').forEach(function (o) {
635          o.style.borderColor = '';
636          o.style.background = '#fff';
637        });
638        showStep(0);
639      }
640    });
641  }
642
643})();

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.