PageSourceSearch

https://tochka-school.ru/themes/school-point/assets/js/new-main.js?ver=2.43.35

js tochka-school.ru collected 2026-10-02 15:03:20 UTC 407,551 bytes, 11,772 lines download raw bytes

1// const btnFixed = document.querySelector('[data-element="btn-fixed"]')
2
3// if (btnFixed) btnFixedInit()
4
5// function btnFixedInit () {
6//   const start = btnFixed.getAttribute('data-btn-fixed-start')
7//   const end = btnFixed.getAttribute('data-btn-fixed-end')
8//   const body = document.getElementsByTagName('body')[0]
9//   window.addEventListener('scroll', checkBtnFixed, { passive: true })
10
11//   function checkBtnFixed () {
12//     if (window.pageYOffset > start && body.scrollHeight - window.pageYOffset > end && !checkBtnFixedHide()) {
13//       btnFixed.classList.add('btn-fixed_active')
14//     } else {
15//       btnFixed.classList.remove('btn-fixed_active')
16//     }
17//   }
18
19//   const sectionsWhenBtnHide = document.querySelectorAll('[data-btn-fixed-hide="true"]')
20
21//   function checkBtnFixedHide () {
22//     let isHide = false
23//     for (let i = 0; i < sectionsWhenBtnHide.length; i++) {
24//       if (elementInViewport(sectionsWhenBtnHide[i])) isHide = true
25//     }
26//     return isHide
27//   }
28
29//   function elementInViewport(el) {
30//     let top = el.offsetTop
31//     let left = el.offsetLeft
32//     let width = el.offsetWidth
33//     let height = el.offsetHeight
34
35//     while(el.offsetParent) {
36//       el = el.offsetParent
37//       top += el.offsetTop
38//       left += el.offsetLeft
39//     }
40
41//     return (
42//       top < (window.pageYOffset + window.innerHeight) &&
43//       left < (window.pageXOffset + window.innerWidth) &&
44//       (top + height) > window.pageYOffset &&
45//       (left + width) > window.pageXOffset
46//     )
47//   }
48  
49// }
50
51const aboutSchoolChatsSlider = document.querySelector('.about-school-chats__slider')
52
53if (aboutSchoolChatsSlider) aboutSchoolChatsSliderInit()
54
55function aboutSchoolChatsSliderInit () {
56  let sliderSwiper
57
58  function initSlider () {
59    sliderSwiper = new Swiper(aboutSchoolChatsSlider, {
60      mousewheel: { forceToAxis: true },
61      slidesPerView: 'auto',
62      spaceBetween: 10,
63      a11y: false,
64    })
65  }
66
67  window.addEventListener('resize', checkSlider)
68
69  checkSlider()
70
71  function checkSlider () {
72    if (window.innerWidth < 744) {
73      if (!sliderSwiper || sliderSwiper.destroyed) {
74        initSlider()
75      }
76    } else {
77      if (sliderSwiper && !sliderSwiper.destroyed) {
78        sliderSwiper.destroy(true, true)
79        sliderSwiper = null
80      }
81    }
82  }
83}
84
85const aboutSchoolGallerySlider = document.querySelector('.about-school-gallery__slider')
86
87if (aboutSchoolGallerySlider) aboutSchoolGallerySliderInit()
88
89function aboutSchoolGallerySliderInit () {
90  let sliderSwiper
91
92  function initSlider () {
93    sliderSwiper = new Swiper(aboutSchoolGallerySlider, {
94      mousewheel: { forceToAxis: true },
95      slidesPerView: 'auto',
96      spaceBetween: 10,
97      a11y: false,
98      grid: {
99        rows: 2,
100        fill: 'row',
101      },
102    })
103  }
104
105  window.addEventListener('resize', checkSlider)
106
107  checkSlider()
108
109  function checkSlider () {
110    if (window.innerWidth < 744) {
111      if (!sliderSwiper || sliderSwiper.destroyed) {
112        initSlider()
113      }
114    } else {
115      if (sliderSwiper && !sliderSwiper.destroyed) {
116        sliderSwiper.destroy(true, true)
117        sliderSwiper = null
118      }
119    }
120  }
121}
122
123
124dataHrefLinksInit()
125
126function dataHrefLinksInit(node) {
127  if (node) {
128    if (node.getAttribute("data-href-link") || node.href) {
129      node.addEventListener('click', addHandler)
130    } else {
131      const dataHrefLinkInsideNode = node.querySelectorAll('[data-href-link]')
132      for (let i = 0; i < dataHrefLinkInsideNode.length; i++) {
133        dataHrefLinkInsideNode[i].addEventListener('click', addHandler)
134      }
135    }
136  } else {
137    const dataHrefLinks = document.querySelectorAll('[data-href-link]')
138    for (let i = 0; i < dataHrefLinks.length; i++) {
139      dataHrefLinks[i].addEventListener('click', addHandler)
140    }
141  }
142
143  function addHandler (e) {
144    e.preventDefault()
145    let href = ''
146    if (this.getAttribute('data-href-link')) {
147      href = this.getAttribute('data-href-link')
148    } else if (this.href) {
149      href = this.href
150    }
151    if (href) window.open(href, '_blank')
152  }
153}
154
155
156const allCourses = document.querySelector('.all-courses')
157 
158 if (allCourses) allCoursesInit()
159 
160 function allCoursesInit () {
161   const config = { attributes: false, childList: true, characterData: true, subtree: true }
162
163   const stickyHeader = document.querySelector('.sticky-header')
164   const body = document.querySelector('body')
165   const wrap = document.querySelector('.all-courses__wrap')
166   const urlFilter = allCourses.getAttribute('data-item-h')
167   const h1Filter = allCourses.getAttribute('data-hname')
168   const metaNameFilter = allCourses.getAttribute('data-meta_name')
169   const metaDescriptionFilter = allCourses.getAttribute('data-meta_descr')
170   const openers = allCourses.querySelectorAll("[data-element='all-courses-filter-opener']")
171   const filterh1block = allCourses.querySelector(".all-courses_h1")
172   const filterSubjectWrap = allCourses.querySelector(".all-courses__filter-wrap_subject")
173   const findBtn = allCourses.querySelector('.all-courses__find')
174   const reset = allCourses.querySelector('.all-courses__reset')
175   const grades = allCourses.querySelector("[data-ftype='class_select']")
176   const subjects = allCourses.querySelector("[data-ftype='class_subjects']")
177   const tags = allCourses.querySelector("[data-ftype='class_tags']")
178   const tile = document.querySelector('.all-courses__tile')
179   const filterSumr = allCourses.querySelector('[data-role="filter-sumr"]')
180   const filterNewy = allCourses.querySelector('[data-role="filter-newy"]')
181   const filterHeadline = filterSubjectWrap.querySelector('.all-courses__filter-headline.desk')
182   let timerReload = setTimeout(() => window.location.reload(), 300000)
183
184
185   filterSumr?.addEventListener('change', () => {
186    const checkedCollegeInputs = allCourses.querySelectorAll('[data-filter-college]:checked')
187    checkedCollegeInputs.forEach(college => {
188      college.checked = false
189      const opener = college.closest(".all-courses__filter")?.querySelector('.all-courses__filter-top')
190      if (!opener) return
191      opener.innerHTML = ''
192      const span = document.createElement('span')
193      span.innerHTML = opener.getAttribute('data-default-text')
194      opener.append(span)
195      const tabs = filterSubjectWrap.querySelectorAll('.all-courses__filter-tab')
196      if (tabs.length) tabs[0].click()
197    })
198    makeFiltration(1)
199    toggleReset()
200  })
201
202
203   filterNewy?.addEventListener('change', () => {
204    makeFiltration(1)
205    toggleReset()
206   })
207
208
209
210
211   if (reset) reset.addEventListener('click', resetFilters)
212 
213   function resetFilters () {
214     for (let i = 0; i < openers.length; i++) {
215       const wrap = openers[i].nextElementSibling
216       const items = wrap.querySelectorAll("input")
217       items.forEach((item) => {
218         item.checked = false
219       })
220       updateFilter(openers[i], wrap, false, true)
221     }
222
223     makeFiltration(1, true)
224     if (reset) reset.classList.remove('active')
225   }
226
227   function resetFilter (opener) {
228    const wrap = opener.nextElementSibling
229    const items = wrap.querySelectorAll("input")
230    items.forEach((item) => {
231      item.checked = false
232    })
233    updateFilter(opener, wrap)
234  }
235 
236   moreBtnInit()
237
238
239   function moreBtnInit () {
240     const moreBtn = allCourses.querySelector('.all-courses__more-button')
241     if (moreBtn) moreBtn.addEventListener('click', () => makeFiltration(moreBtn.getAttribute('data-v')))
242   }
243 
244  const observer = new MutationObserver(function observerCallback(mutations) {
245    mutations.forEach(
246      (mutation) => {
247        if (mutation.addedNodes.length) {
248          mutation.addedNodes.forEach((node) => {
249            if (node?.classList?.contains('all-courses__item')) {
250              dataHrefLinksInit(node)
251              togglePrice(node)
252              fancyboxAjaxCardsReInit(node)
253              initCommonAnalytics(node)
254            }
255          })
256        }
257      })
258     moreBtnInit()
259   })
260
261   function updateBodyDataParams (grades_result, subjects_result, tags_result) {
262    grades_result = grades_result === '' || grades_result === null || grades_result === undefined ? 'all' : grades_result;
263    subjects_result = subjects_result === '' || subjects_result === null || subjects_result === undefined ? 'all' : subjects_result;
264    tags_result = tags_result === '' || tags_result === null || tags_result === undefined ? 'all' : tags_result;
265    body.setAttribute('data-filter-stage', grades_result)
266    body.setAttribute('data-filter-subject', subjects_result)
267    body.setAttribute('data-filter-goal', tags_result)
268    const grades = grades_result !== 'all' ? '_grade' : ''
269    const subjects = subjects_result !== 'all' ? '_subject' : ''
270    const tags = tags_result !== 'all' ? '_tag' : ''
271    const dataPageType = `catalog${grades}${subjects}${tags}`
272    body.setAttribute('data-page-type', dataPageType)
273   }
274
275 
276   if (tile) observer.observe(tile, config)
277 
278   if (tile) togglePrice()
279 
280   function togglePrice (node) {
281    if (node) {
282      togglePriceHandler(node)
283    } else {
284      const items = tile?.querySelectorAll(".all-courses__item")
285      items.forEach((item) => {
286        togglePriceHandler(item)
287      })
288    }
289    function togglePriceHandler (item) {
290       const toggle = item.querySelectorAll('.all-courses__radio-input')
291       if (!toggle.length) return
292       const boxes = item.querySelectorAll('.all-courses__box')
293      const textReplace = item.querySelector('.all-courses__info.text-replace')
294      let texts
295      if (textReplace) {
296        texts = textReplace.querySelectorAll('.all-courses__info-span')
297      }
298      for (let i = 0; i < toggle.length; i++) {
299         toggle[i].addEventListener('change', toggleBoxes)
300         if (texts) toggle[i].addEventListener('change', toggleTexts)
301       }
302 
303       function toggleBoxes () {
304         for (let i = 0; i < boxes.length; i++) {
305           if (boxes[i].classList.contains('hide')) {
306             boxes[i].classList.remove('hide')
307           } else {
308             boxes[i].classList.add('hide')
309           }
310         }
311       }
312     function toggleTexts () {
313        for (let i = 0; i < texts.length; i++) {
314          if (texts[i].classList.contains('hide')) {
315            texts[i].classList.remove('hide')
316          } else {
317            texts[i].classList.add('hide')
318          }
319        }
320      }
321    }
322  }
323 
324
325   initTabs()
326 
327   function initTabs () {
328     const tabsParent = filterSubjectWrap.querySelector('.all-courses__filter-tabs')
329     const list = filterSubjectWrap.querySelector('.all-courses__filter-list')
330     const tabs = filterSubjectWrap.querySelectorAll('.all-courses__filter-tab')
331     const subjectsBoxes = filterSubjectWrap.querySelectorAll('.all-courses__filter-box')
332
333        if (!tabs.length || !subjectsBoxes.length) return
334
335        filterSubjectWrap.addEventListener('scroll', wrapScrollHandler, { passive: true })
336
337        function wrapScrollHandler () {
338          subjectsBoxes.forEach((subjectBox) => {
339            if (filterSubjectWrap.scrollTop >= subjectBox.offsetTop - 90 - 65) {
340              const oldTab = filterSubjectWrap.querySelector('.all-courses__filter-tab.active')
341              if (oldTab) oldTab.classList.remove('active')
342              const index = subjectBox.getAttribute('data-index')
343              const tab = filterSubjectWrap.querySelector('[data-index="' + index + '"]')
344              if (tab) {
345                tabsParent.scrollLeft = tab.offsetLeft - tabsParent.clientWidth/2 + tab.clientWidth/2
346                tab.classList.add('active')
347              }
348            }
349          })
350        }
351 
352    let timeout
353    let firstToggle = true
354
355    tabs.forEach((tab) => {
356      tab.addEventListener('click', changeTab)
357      tab.addEventListener('mouseenter', changeTab)
358    })
359
360    function changeTab (e) {
361      e.stopPropagation()
362      clearTimeout(timeout)
363      timeout = setTimeout(() => toggle(this),100)
364
365      function toggle (that) {
366        if (!that.closest('.all-courses__filter-wrap')?.querySelector('.all-courses__filter-tab:hover') && !firstToggle && e.type !== 'click') return
367        firstToggle = false
368        filterSubjectWrap.removeEventListener('scroll', wrapScrollHandler, { passive: true })
369        const oldTab = filterSubjectWrap.querySelector('.all-courses__filter-tab.active')
370        if (oldTab) oldTab.classList.remove('active')
371
372        that.classList.add('active')
373        filterHeadline.innerHTML = that.getAttribute('data-text')
374
375        subjectsBoxes.forEach((subjectsBox) => {
376          subjectsBox.classList.add('hide')
377        })
378
379        const index = that.getAttribute('data-index')
380        const activeSubjectsBox = list.querySelector('[data-index="' + index + '"]')
381        activeSubjectsBox.classList.remove('hide')
382
383        filterSubjectWrap.scrollTop = activeSubjectsBox.offsetTop - 90 - 60
384
385        tabsParent.scrollLeft = that.offsetLeft - tabsParent.clientWidth/2 + that.clientWidth/2
386        setTimeout(() => filterSubjectWrap.addEventListener('scroll', wrapScrollHandler, { passive: true }), 200)
387      }
388    }
389
390    tabs[0]?.click()
391  }
392
393
394   findBtn.addEventListener('click', findHandler)
395 
396   function findHandler () {
397     let valid = true
398     for (let i = 0; i < openers.length; i++) {
399       const wrap = openers[i].nextElementSibling
400       const itemChecked = wrap.querySelector(["input:checked"])
401       if (!itemChecked) valid = false
402     }
403 
404     if (valid) {
405       makeFiltration()
406     }
407   }
408 
409 
410   for (let i = 0; i < openers.length; i++) {
411     openers[i].addEventListener("click", (e)=> openFilter(openers[i], e))
412 
413     const wrap = openers[i].nextElementSibling
414
415     const closeBtn = wrap.querySelector('.all-courses__filter-close')
416     if (closeBtn) closeBtn.addEventListener('click', () => closeFilter(openers[i]))
417
418     const filterTopReset = openers[i].parentElement.querySelector('.all-courses__filter-top-reset')
419     if (filterTopReset) filterTopReset.addEventListener('click', () => resetFilter(openers[i]))
420
421     const items = wrap.querySelectorAll("[data-element='all-courses-filter-input']")
422     items.forEach((item) => {
423       item.addEventListener('change', () => updateFilter(openers[i], wrap))
424     })
425
426     const informerButtons = wrap.querySelectorAll('.all-courses__filter-informer-button')
427     informerButtons.forEach(informerButton => {
428      informerButton.addEventListener('click', function () {
429        const input = this.closest('.all-courses__filter-box')?.querySelector("[data-element='all-courses-filter-input']")
430        if (input) {
431          input.checked = true
432          updateFilter(openers[i], wrap)
433        }
434      })
435     })
436
437
438     const resetFilterBtn = wrap.querySelector('.all-courses__reset-filter')
439    if (resetFilterBtn) resetFilterBtn.addEventListener('click', () => resetFilter(openers[i]))
440   }
441 
442   function openFilter (opener, e) {
443     e.stopPropagation()
444     if (opener.classList.contains('active')) {
445      closeFilter(opener)
446     } else {
447        const oldOpen = allCourses.querySelector(".all-courses__filter-top.active")
448        if (oldOpen) oldOpen.classList.remove('active')
449        closeSelectFilter()
450        opener.classList.add('active')
451 
452        const filter = opener.parentElement
453        const oldFilter = allCourses.querySelector(".all-courses__filter.open")
454        if (oldFilter) oldFilter.classList.remove('open')
455        if (filter) filter.classList.add('open')
456     }
457     hideHeader()
458   }
459    
460    function closeSelectFilter () {
461        const oldSelectFilterOpen = document.querySelector(".select-filter.active")
462        if (oldSelectFilterOpen) {
463          oldSelectFilterOpen.classList.remove('active')
464          oldSelectFilterOpen.querySelector('.select-filter__top').classList.remove('active')
465        }
466      }
467
468      
469      checkResetFilterTop(grades?.nextElementSibling)
470      checkResetFilterTop(grades?.nextElementSibling)
471      checkResetFilterTop(tags?.nextElementSibling)
472
473      function checkResetFilterTop (wrap) {
474        const resetFilterTop = wrap?.parentElement.querySelector('.all-courses__filter-top-reset')
475        const item = wrap?.querySelector(["input:checked"])
476        if (item) {
477          if (resetFilterTop) resetFilterTop.classList.add('active')
478        }
479      }
480
481    function sortFilterFields() {
482        const getParsedData = (element, attribute) => {
483          if (!element) return []
484          try {
485            const data = element.getAttribute(attribute)
486            return data ? JSON.parse(data) : []
487          } catch (e) {
488            console.error(`Ошибка парсинга JSON в атрибуте ${attribute}:`, e)
489            return []
490          }
491        }
492
493        const filterBlockInputs = (blockElement, allowedValues, hasActiveFilters) => {
494          const inputs = blockElement.nextElementSibling.querySelectorAll('input')
495          const allowedStrings = allowedValues.map(String)
496
497
498          inputs.forEach(input => {
499            const parent = input.closest('.all-courses__filter-item')
500            if (!parent) return
501
502            const dataItemId = input.getAttribute('data-item-id')
503            const inputValues = dataItemId ? [dataItemId] : input.value.split('|')
504
505            const isAllowed = inputValues.some(val => allowedStrings.includes(val))
506            const isForbidden = hasActiveFilters && !isAllowed
507
508            parent.classList.toggle('disabled', isForbidden)
509          })
510        }
511
512        function calculateSubjects () {
513          const boxes = subjects.nextElementSibling.querySelectorAll('.all-courses__filter-box')
514          boxes.forEach(box => {
515            const notForbiddenInputs = box.querySelectorAll('.all-courses__filter-item:not(.disabled)')
516            const tab = subjects.nextElementSibling.querySelector(`.all-courses__filter-tab[data-index='${box.getAttribute('data-index') || ''}']`)
517            if (tab.querySelector('span')) tab.querySelector('span').innerHTML = notForbiddenInputs.length.toString()
518            if (notForbiddenInputs.length === 0) {
519              tab.style.display = 'none'
520              box.style.display = 'none'
521              box.previousElementSibling.style.display = 'none'
522            } else {
523              tab.style.display = ''
524              box.style.display = ''
525              box.previousElementSibling.style.display = ''
526            }
527          })
528          const tabs = filterSubjectWrap.querySelectorAll('.all-courses__filter-tab')
529          const tabsActive = Array.from(tabs).filter(tab => tab.style.display !== 'none')
530          if (tabsActive.length === 1) {
531            tabsActive[0].click()
532            tabsActive[0].style.display === 'none'
533            filterSubjectWrap.classList.add('all-courses__filter-wrap_hide-tabs')
534          } else if (tabsActive.length > 0) {
535            tabsActive[0].click()
536            filterSubjectWrap.classList.remove('all-courses__filter-wrap_hide-tabs')
537          } else {
538            if (filterHeadline) filterHeadline.innerHTML = ''
539          }
540        }
541
542        function getResultArray (array_1, array_2) {
543          if (array_1.length === 0) return array_2
544          if (array_2.length === 0) return array_1
545          return array_1.filter(item => array_2.includes(item))
546        }
547
548        const checkedGrade = grades.nextElementSibling.querySelector('input:checked')
549        const checkedSubject = subjects.nextElementSibling.querySelector('input:checked')
550        const checkedTag = tags.nextElementSibling.querySelector('input:checked')
551
552        const hasGrade = !!checkedGrade
553        const hasSubject = !!checkedSubject
554        const hasTag = !!checkedTag
555
556        const grades_1 = getParsedData(checkedSubject, 'data-grades')
557        const grades_2 = getParsedData(checkedTag, 'data-grades')
558        const allowedGrades = getResultArray(grades_1, grades_2)
559
560        const subjects_1 = getParsedData(checkedGrade, 'data-subjects')
561        const subjects_2 = getParsedData(checkedTag, 'data-subjects')
562        const allowedSubjects = getResultArray(subjects_1, subjects_2)
563
564        const tags_1 = getParsedData(checkedGrade, 'data-tags')
565        const tags_2 = getParsedData(checkedSubject, 'data-tags')
566        const allowedTags = getResultArray(tags_1, tags_2)
567
568        filterBlockInputs(grades, allowedGrades, hasSubject || hasTag)
569        filterBlockInputs(subjects, allowedSubjects, hasGrade || hasTag)
570        filterBlockInputs(tags, allowedTags, hasGrade || hasSubject)
571        calculateSubjects()
572      }
573
574
575    async function updateFilter (opener, wrap, noScroll, noFiltration) {
576     if(opener.getAttribute('data-ftype') === 'class_select' || opener.getAttribute('data-ftype') === 'class_tags') {
577       //filterSubjectsList.innerHTML = "<div class='tile-loader-box'><div class='tile-loader'></div></div>";
578       if (!noFiltration) makeFiltration()
579
580    //    updateFilter(openers[1], openers[1].nextElementSibling, true)
581     } else {
582       if (!noFiltration) makeFiltration()
583     }
584     opener.innerHTML = `<div class='all-courses__filter-top-text'>${opener.getAttribute('data-default-text')}</div>`
585     const resetFilterBtn = wrap.querySelector('.all-courses__reset-filter')
586     const resetFilterTop = wrap.parentElement.querySelector('.all-courses__filter-top-reset')
587     const item = wrap.querySelector(["input:checked"])
588        if (item) {
589          opener.innerHTML = ''
590          span = document.createElement('span')
591          span.innerHTML = item.nextElementSibling.innerHTML
592          opener.append(span)
593          if (resetFilterBtn) resetFilterBtn.classList.add('active')
594          if (resetFilterTop) resetFilterTop.classList.add('active')
595        } else {
596          if (resetFilterBtn) resetFilterBtn.classList.remove('active')
597          if (resetFilterTop) resetFilterTop.classList.remove('active')
598        }
599        toggleReset()
600        closeFilter(opener)
601        sortFilterFields()
602  }
603
604  function toggleReset () {
605
606     const itemsAll = allCourses.querySelectorAll('input:not(.select-filter__input):checked')
607     itemsAll.filter
608     if (itemsAll.length) {
609       if (reset) reset.classList.add('active')
610     } else {
611       if (reset) reset.classList.remove('active')
612     }
613   }
614 
615   window.addEventListener('click', closeAllFilters)
616 
617   function closeAllFilters () {
618     if (window.innerWidth >= 744) {
619       const oldOpen = allCourses.querySelector(".all-courses__filter-top.active")
620       if (oldOpen) oldOpen.classList.remove('active')
621       showHeader()
622     }
623   }
624 
625   function closeFilter (opener) {
626     opener.classList.remove('active')
627     const filter = opener.parentElement
628     if (filter) filter.classList.remove('open')
629     showHeader()
630   }
631 
632   async function makeFiltration (p_paginate = 1, isReset = false) {
633    if(p_paginate === 1 ){
634        $('.filtered_elements').html("<div class='tile-loader'></div>");
635        $('.more_b').html("");
636     }
637    clearTimeout(timerReload)
638    timerReload = setTimeout(() => window.location.reload(), 700000)
639     const grades_wrap = grades.nextElementSibling
640     const grades_items = grades_wrap.querySelectorAll(["input:checked"])
641     let grades_result = ''
642     let grade_first = 0
643     let grade_item = ''
644     let grade_h1_part= ''
645     grades_items.forEach((item, i) => {
646       if (i > 0) grades_result += '|'
647       if (grade_first == 0) grade_first = item.value
648       if (grade_item === '') grade_item = item.getAttribute('data-item')
649       if (grade_h1_part === '') grade_h1_part = item.getAttribute('data-hname')
650       grades_result += item.value
651     })
652     let subjects_result = ''
653     let subject_first = 0
654     let subject_item = ''
655     let subject_h1_part= ''
656     try{
657       const subjects_wrap = subjects.nextElementSibling
658       const subjects_items = subjects_wrap.querySelectorAll(["input:checked"])
659       subjects_items.forEach((item, i) => {
660         if (i > 0) subjects_result += '|'
661         if (subject_first == 0) subject_first = item.value
662         if (subject_item === '') subject_item = item.getAttribute('data-item')
663         if (subject_h1_part === '') subject_h1_part = item.getAttribute('data-hname')
664         subjects_result += item.value
665       })
666     }catch(e){}
667     let tags_result = ''
668     let tag_first = 0
669     let tag_item = ''
670     let tag_h1_part= ''
671     try{
672       const tags_wrap = tags.nextElementSibling
673       const tags_items = tags_wrap.querySelectorAll(["input:checked"])
674       tags_items.forEach((item, i) => {
675         if (i > 0) tags_result += '|'
676         if (tag_first == 0) tag_first = item.value
677         if (tag_item === '') tag_item = item.getAttribute('data-item')
678         if (tag_h1_part === '') tag_h1_part = item.getAttribute('data-hname')
679         tags_result += item.value
680       })
681     }catch(e){}
682     let utm_f = allCourses.getAttribute('data-utm');
683     if(utm_f != null && utm_f != '' && utm_f != undefined){
684    }else{
685        utm_f = ''
686    }
687     let promo_f = '';
688     let promo_f_param = '';
689     let promo_ = allCourses.getAttribute('data-promo');
690    if(promo_ != null && promo_ != '' && promo_ != undefined){
691        promo_f = promo_;
692        promo_f_param = '?promo='+promo_f;
693    }
694    if(grade_item === '' && grade_h1_part === ''){ 
695        grades_result = 'all'
696    }
697    if(subject_item === '' && subject_h1_part === ''){
698        subjects_result = 'all'
699        //tags_result = ''
700    }
701    let summerny = ''
702    if (filterSumr?.checked) {
703      summerny = filterSumr.getAttribute('data-value')
704    } else if (filterNewy?.checked) {
705      summerny = filterNewy.getAttribute('data-value')
706    }
707
708     var obData = {
709         'grade': grades_result,
710         'subject': subjects_result,
711         'tag': tags_result,
712         'utm_t': utm_f,
713         'promo': promo_f,
714         'pagePaginate': p_paginate,
715         'summerny': summerny,
716       };
717    // console.log(obData);
718     $.request('FilterCourseFunctions::onPaginateAllCourses', {
719       data: obData
720     })
721    //  let url = new URL(window.location.href)
722     let url = urlFilter
723    //  let useFilterReplaceState = false
724    //  if (grade_first > 0){
725    //    url.searchParams.set('gr', grade_first);
726    //    useFilterReplaceState = true
727    //  }
728    //  if (subject_first > 0){
729    //    url.searchParams.set('subject', subject_first);
730    //    useFilterReplaceState = true
731    //  }
732    //  if (tag_first > 0){
733    //    url.searchParams.set('tag', tag_first);
734    //    useFilterReplaceState = true
735    //  }
736    //  if (useFilterReplaceState === true) history.replaceState(null, "", url.toString())
737     if (subject_item !== "") {
738        url = url + '/' + subject_item
739     }
740    if (grade_item !== "") {
741        if (subject_item !== "") {
742        }else{
743            url = url + '/all'
744        }
745        url = url + '/' + grade_item
746     }
747    if (tag_item !== "") {
748        if (grade_item !== "") {
749        }else{
750            if (subject_item !== "") {
751            }else{
752                url = url + '/all'
753            }
754            url = url + '/all'
755        }
756        url = url + '/' + tag_item
757    }
758    url = url + utm_f
759     history.replaceState(null, "", url.toString())
760     let new_h1 = h1Filter
761     let new_title = metaNameFilter
762     let new_description = metaDescriptionFilter
763
764
765
766     new_h1 = 'Курсы'
767
768     const tagPurposeChecked = allCourses.querySelector('.all-courses__filter_purpose input:checked')
769     let special
770     if (tagPurposeChecked) special = tagPurposeChecked.getAttribute('data-special') === "special"
771
772     const grCollegeChecked = allCourses.querySelector('.all-courses__filter-item_college input
772:checked')
773     let specialcollege
774     if (grCollegeChecked) specialcollege = grCollegeChecked.getAttribute('data-special-college') === "specialcollege"
775
776     if(special){
777        new_h1 = 'Семейное онлайн-обучение'
778     }
779     if (subject_h1_part !== "" && !special) {
780         if (subject_h1_part === "семейному обучению") {
781            new_h1 = 'Семейное обучение'
782         }else{
783            new_h1 = new_h1 + ' по '+ subject_h1_part
784         }
785     }else{
786     }
787     if (grade_h1_part !== "") {
788        new_h1 = new_h1 + ' для ' + grade_h1_part  
789     }else{
790     }
791     if(specialcollege){
792        new_h1 = 'Направления'
793        new_h1 = new_h1 + ' ' + grade_h1_part  
794        if (subject_h1_part !== "" && !special) {
795             if (subject_h1_part === "семейному обучению") {
796                new_h1 = 'Семейное обучение'
797             }else{
798                new_h1 = new_h1 + ' по '+ subject_h1_part
799             }
800         }else{
801         }
802     }
803     if (tag_h1_part !== "") {
804        new_h1 = new_h1 + ', чтобы ' + tag_h1_part
805     }
806     if (new_h1 === 'Курсы' || new_h1 === 'Семейное онлайн-обучение' || new_h1 === 'Направления'){
807        new_h1 = h1Filter
808     }
809        
810
811     if(special){
812        new_title = new_h1 + ' в «Точке Знаний»'
813        new_description = new_h1 + ' в «Точке Знаний». ✔️ Интересные и понятные онлайн-занятия с преподавателями. ✔️ Персональный тьютор. ✔️ Подготовка к ЕГЭ, ОГЭ и ВПР. ✔️ Учитесь в удобном темпе, все курсы доступны в записи!'
814     }else{
815        new_title = new_h1 + ' в онлайн-школе «Точка Знаний»'
816        new_description = new_h1 + ' в онлайн-школе «Точка Знаний». ✔️ Интересные и понятные онлайн-занятия с преподавателями. ✔️ Персональный тьютор. ✔️ Подготовка к ЕГЭ, ОГЭ и ВПР. ✔️ Учитесь в удобном темпе, все курсы доступны в записи!'
817     }
818     
819     
820        
821
822     if (isReset) {
823       filterh1block.innerHTML = new_h1 + `<svg viewBox="0 0 42 42" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="21" cy="21" r="21" fill="#6683C2" fill-opacity="0.24"></circle><path d="M20.25 29C20.25 29.4142 20.5858 29.75 21 29.75C21.4142 29.75 21.75 29.4142 21.75 29L21 29L20.25 29ZM21.5303 12.4697C21.2374 12.1768 20.7626 12.1768 20.4697 12.4697L15.6967 17.2426C15.4038 17.5355 15.4038 18.0104 15.6967 18.3033C15.9896 18.5962 16.4645 18.5962 16.7574 18.3033L21 14.0607L25.2426 18.3033C25.5355 18.5962 26.0104 18.5962 26.3033 18.3033C26.5962 18.0104 26.5962 17.5355 26.3033 17.2426L21.5303 12.4697ZM21 29L21.75 29L21.75 13L21 13L20.25 13L20.25 29L21 29Z" fill="#003C56"></path></svg>`
824     } else {
825       filterh1block.textContent = new_h1
826     }
827
828     document.title = new_title
829     const meta= document.getElementsByTagName("meta")
830     for (let i= 0; i < meta.length; i++) {
831         if (meta[i].name.toLowerCase() === "description") {
832           meta[i].content = new_description
833         }
834     }
835
836    // updateBodyDataParams(grades_result, subjects_result, tags_result)
837    updateBodyDataParams(grade_item, subject_item, tag_item)
838    if (p_paginate <= 1) {
839      allCourses.setAttribute('data-action', 'filter_apply')
840      sendCommonAnalytics('element_click', allCourses)
841    }
842   }
843 
844   function showHeader () {
845     stickyHeader.classList.remove('hide')
846     body.classList.remove('no-scroll')
847     wrap.classList.remove('active')
848   }
849   function hideHeader () {
850     if (window.innerWidth < 744) {
851       stickyHeader.classList.add('hide')
852       body.classList.add('no-scroll')
853       wrap.classList.add('active')
854     }
855 
856   }
857
858   setTimeout(() => sortFilterFields(), 200)
859 }
860
861
862const ymAsync = (id, goal, params) => new Promise(resolve => {
863  if (typeof ym !== 'function') return resolve()
864
865  const timeout = setTimeout(resolve, 500)
866
867  try {
868    ym(id, 'reachGoal', goal, params, () => {
869      clearTimeout(timeout)
870      resolve()
871    })
872  } catch {
873    clearTimeout(timeout)
874    resolve()
875  }
876})
877
878const gtagAsync = (goal, params) => new Promise(resolve => {
879  if (typeof gtag !== 'function') return resolve()
880
881  const timeout = setTimeout(resolve, 500)
882
883  try {
884    gtag('event', goal, {
885      ...params,
886      event_callback: () => {
887        clearTimeout(timeout)
888        resolve()
889      },
890    })
891  } catch {
892    clearTimeout(timeout)
893    resolve()
894  }
895})
896
897const mailruAsync = (goal, isSessionStorageSave = false) => new Promise(resolve => {
898  const key = `mailru_goal_${goal}`
899
900  if (isSessionStorageSave) {
901    try {
902      if (sessionStorage.getItem(key)) {
903        resolve()
904        return
905      }
906    } catch {
907    }
908  }
909
910  if (!window._tmr || typeof window._tmr.push !== 'function') {
911    resolve()
912    return
913  }
914
915  let settled = false
916
917  const finish = (sent = false) => {
918    if (settled) return
919
920    settled = true
921    clearTimeout(timeout)
922
923    if (sent && isSessionStorageSave) {
924      try {
925        sessionStorage.setItem(key, '1')
926      } catch {
927      }
928    }
929
930    resolve()
931  }
932
933  const timeout = setTimeout(() => {
934    finish(false)
935  }, 1000)
936
937  try {
938    window._tmr.push({
939      type: 'onready',
940      callback: () => {
941        if (settled) return
942
943        try {
944          window._tmr.reachGoal({
945            id: 3515465,
946            goal,
947          })
948
949          finish(true)
950        } catch {
951          finish(false)
952        }
953      },
954    })
955  } catch {
956    finish(false)
957  }
958})
959
960const analytics = {
961  ym(goal, params) {
962    return ymAsync(97240877, goal, params)
963  },
964
965  gtag(goal, params) {
966    return gtagAsync(goal, params)
967  },
968
969  mailru(goal, isSessionStorageSave = false) {
970    return mailruAsync(goal, isSessionStorageSave)
971  },
972
973  reachGoal(goal, params) {
974    return Promise.allSettled([
975      ymAsync(97240877, goal, params),
976      gtagAsync(goal, params),
977    ])
978  },
979}
980
981const animateCounters = document.querySelectorAll('.animate-counter')
982
983if (animateCounters.length) animateCountersInit()
984
985function animateCountersInit () {
986    const observer = new IntersectionObserver((entries) => {
987        entries.forEach(entry => {
988          if (entry.isIntersecting) {
989            animateCounter(entry.target, 0, entry.target.getAttribute('data-animate-counter-end'), 1000)
990            observer.unobserve(entry.target)
991          }
992        })
993    }, {
994        root: null,
995        scrollMargin : "0px 0px -150px 0px",
996        threshold: 1
997    })
998
999    for (let i = 0; i < animateCounters.length; i++) {
1000        animateCounterInit(animateCounters[i])
1001    }
1002
1003    function animateCounterInit (counter) {
1004        observer.observe(counter)
1005    }
1006
1007    function animateCounter(element, startValue, endValue, duration) {
1008        let currentValue = startValue
1009        const increment = (endValue - startValue) / (duration / 10)
1010        const toFixed = element.getAttribute('data-to-fixed')
1011        const counterInterval = setInterval(() => {
1012          currentValue += increment;
1013          if ((increment > 0 && currentValue >= endValue) || (increment < 0 && currentValue <= endValue)) {
1014            currentValue = endValue
1015            clearInterval(counterInterval)
1016          }
1017          element.textContent = (+currentValue).toFixed(toFixed).toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ")
1018        }, 10)
1019    }
1020}
1021
1022const animationsOnScroll = document.querySelectorAll('[data-animate-on-scroll]')
1023
1024if (animationsOnScroll.length) animationsOnScrollInit()
1025
1026function animationsOnScrollInit () {
1027  gsap.registerPlugin(ScrollTrigger)
1028
1029  for (let i = 0; i < animationsOnScroll.length; i++) {
1030   initGsapScrollTrigger(animationsOnScroll[i])
1031  }
1032
1033  function initGsapScrollTrigger (node) {
1034    if (node.classList.contains('langs-cap__decor-box')) {
1035      gsap.to(node, {
1036        scrollTrigger: {
1037          trigger: node,
1038          start: "top 95%",
1039          onEnter: () => node.classList.add("active")
1040        }
1041      })
1042    } else {
1043      gsap.to(node, {
1044        scrollTrigger: {
1045          trigger: node,
1046          start: "top 80%",
1047          onEnter: () => node.classList.add("active")
1048        }
1049      })
1050    }
1051  }
1052}
1053
1054
1055const articleBottomShareBtns = document.querySelectorAll('.article-bottom__share-btn')
1056
1057articleBottomShareBtns.forEach(shareBtn => {
1058  shareBtn.addEventListener('click', function(event) {
1059    const isMobile = window.matchMedia("(pointer: coarse)").matches || /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
1060
1061    const shareUrl = this.getAttribute('data-url')
1062    if (!shareUrl) return
1063
1064    if (navigator.share && isMobile) {
1065      event.preventDefault()
1066
1067      navigator.share({
1068        url: shareUrl,
1069      })
1070        .then()
1071        .catch((error) => console.log('Ошибка шеринга:', error))
1072    } else {
1073      const type = this.getAttribute('data-share-type')
1074      let baseUrl = ''
1075      switch (type) {
1076        case 'vk':
1077          baseUrl = 'https://vk.com/share.php?url='
1078          break;
1079        case 'tg':
1080          baseUrl = 'https://t.me/share/url?url='
1081          break;
1082        case 'max':
1083          baseUrl = 'https://max.ru/:share?text='
1084          break;
1085      }
1086      const finalUrl = `${baseUrl}${encodeURIComponent(shareUrl)}`
1087      const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
1088      if (type === 'max' && !isSafari) {
1089        const shareWindow = window.open(`max://share?text=${encodeURIComponent(shareUrl)}`, '_blank')
1090
1091        setTimeout(() => {
1092          try {
1093            if (shareWindow && !shareWindow.closed) {
1094              shareWindow.location.href = finalUrl
1095            }
1096          } catch (e) {
1097            window.open(`https://max.ru{encodedUrl}`, '_blank')
1098          }
1099        }, 500)
1100      } else {
1101        window.open(finalUrl, '_blank')
1102      }
1103    }
1104  })
1105})
1106
1107
1108
1109const articleVideoBoxArray = document.querySelectorAll("[data-element='article__video-box']")
1110
1111if (articleVideoBoxArray.length) articleVideoBoxArrayInit()
1112
1113function articleVideoBoxArrayInit () {
1114  for (let i = 0; i < articleVideoBoxArray.length; i++) {
1115    articleVideoBoxArray[i].addEventListener('click', () => articleVideoBoxInit(articleVideoBoxArray[i]), { once: true })
1116  }
1117
1118  function articleVideoBoxInit (box) {
1119    const video = box.querySelector('video')
1120    video.controls = true
1121    box.classList.add('active')
1122  }
1123}
1124
1125const blogList = document.querySelector('.blog__list')
1126
1127if (blogList) blogListInit()
1128
1129function blogListInit () {
1130  const config = { attributes: false, childList: true, characterData: true, subtree: true }
1131  const observer = new MutationObserver(function observerCallback(mutations) {
1132    mutations.forEach(
1133      (mutation) => {
1134        if (mutation.addedNodes.length) {
1135          mutation.addedNodes.forEach((node) => {
1136            if (node?.classList?.contains('blog__item')) {
1137              initCommonAnalytics(node)
1138            }
1139          })
1140        }
1141      })
1142  })
1143
1144  observer.observe(blogList, config)
1145}
1146
1147const btnFixed = document.querySelector('[data-element="btn-fixed"]')
1148 
1149 if (btnFixed) btnFixedInit()
1150 
1151 function btnFixedInit () {
1152   const start = btnFixed.getAttribute('data-btn-fixed-start') || 0
1153   const end = btnFixed.getAttribute('data-btn-fixed-end') || 0
1154   const body = document.getElementsByTagName('body')[0]
1155   const promo = document.querySelector('.promo')
1156   window.addEventListener('scroll', checkBtnFixed, { passive: true })
1157 
1158   function checkBtnFixed () {
1159     const cake = document.querySelector('.cake.cake_active')
1160     if (window.scrollY > start && body.scrollHeight - window.pageYOffset > end && !checkBtnFixedHide()) {
1161       btnFixed.classList.add('active')
1162        if (cake) btnFixed.classList.add('active-with-cake-offset')
1163        if (promo) {
1164            promo.classList.add('transition')
1165            promo.classList.remove('transition-with-cake')
1166        }
1167        if (promo && cake) promo.classList.add('transition-with-cake-offset')
1168     } else {
1169       btnFixed.classList.remove('active')
1170       btnFixed.classList.remove('active-with-cake-offset')
1171       if (promo) promo.classList.remove('transition')
1172       if (promo && cake) {
1173        promo.classList.remove('transition-with-cake-offset')
1174        promo.classList.add('transition-with-cake')
1175      }
1176     }
1177   }
1178 
1179   const sectionsWhenBtnHide = document.querySelectorAll('[data-btn-fixed-hide="true"]')
1180 
1181   function checkBtnFixedHide () {
1182     let isHide = false
1183     for (let i = 0; i < sectionsWhenBtnHide.length; i++) {
1184       if (elementInViewport(sectionsWhenBtnHide[i])) isHide = true
1185     }
1186     return isHide
1187   }
1188 
1189   function elementInViewport(el) {
1190     let top = el.offsetTop
1191     let left = el.offsetLeft
1192     let width = el.offsetWidth
1193     let height = el.offsetHeight
1194 
1195     while(el.offsetParent) {
1196       el = el.offsetParent
1197       top += el.offsetTop
1198       left += el.offsetLeft
1199     }
1200 
1201     return (
1202       top < (window.pageYOffset + window.innerHeight) &&
1203       left < (window.pageXOffset + window.innerWidth) &&
1204       (top + height) > window.pageYOffset &&
1205       (left + width) > window.pageXOffset
1206     )
1207   }
1208 }
1209
1210const btnScrollToTop = document.querySelector('.btn-scroll-to-top')
1211
1212if (btnScrollToTop) btnScrollToTopInit()
1213
1214function btnScrollToTopInit () {
1215  const promo = document.querySelector('.promo')
1216
1217  if (btnScrollToTop) {
1218    btnScrollToTop.addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' }))
1219    if (promo) btnScrollToTop.classList.add('active-promo')
1220    window.addEventListener('scroll', toggleAllCoursesTop, { passive: true })
1221
1222    function toggleAllCoursesTop () {
1223      if (window.scrollY > 0) {
1224        btnScrollToTop.classList.add('active')
1225      } else {
1226        btnScrollToTop.classList.remove('active')
1227      }
1228    }
1229  }
1230}
1231
1232const cake = document.querySelector('.cake')
1233
1234if (cake) checkCake()
1235
1236function checkCake() {
1237  const cakeButton = cake.querySelector('.cake__button')
1238  const btnScrollToTop = document.querySelector('.btn-scroll-to-top')
1239  if (!getCookie('cakes_policy')) {
1240    cake.classList.add('cake_active')
1241    if (btnScrollToTop) btnScrollToTop.classList.add('active-cake')
1242
1243    cakeButton.addEventListener('click', function () {
1244      setCake('cakes_policy', 'true', 365)
1245      cake.classList.remove('cake_active')
1246      const btnFixed = document.querySelector('[data-element="btn-fixed"]')
1247      const promo = document.querySelector('.promo')
1248      if (promo) {
1249        promo.classList.remove('transition-with-cake')
1250        promo.classList.remove('transition-with-cake-offset')
1251      }
1252      if (btnFixed) btnFixed.classList.remove('active-with-cake-offset')
1253      if (btnScrollToTop) btnScrollToTop.classList.remove('active-cake')
1254    })
1255    const footer = document.querySelector('footer')
1256    if (footer) window.addEventListener('scroll', () => switchCake(footer), { passive: true })
1257  }
1258}
1259
1260function switchCake (footer) {
1261  const scrollHeight = document.documentElement.scrollHeight
1262  const currentScroll = window.scrollY
1263  const clientHeight = document.documentElement.clientHeight
1264
1265  const distanceToBottom = scrollHeight - (currentScroll + clientHeight);
1266  if (distanceToBottom < footer.clientHeight) {
1267    cake.classList.add('hide')
1268  } else {
1269    cake.classList.remove('hide')
1270  }
1271}
1272
1273
1274function setCake(name, value, days) {
1275  let expires = ""
1276  if (days) {
1277    let date = new Date()
1278    date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000))
1279    expires = "; expires=" + date.toUTCString()
1280  }
1281  document.cookie = name + "=" + (value || "") + expires + "; path=/"
1282}
1283
1284function setViewportProperty() {
1285   let vh = window.innerHeight * 0.01
1286   document.documentElement.style.setProperty('--vh', `${vh}px`)
1287 }
1288 
1289 window.addEventListener('resize', setViewportProperty)
1290 
1291 setViewportProperty()
1292
1293const cards = document.querySelector("[data-element='cards']")
1294
1295if (cards) cardsInit()
1296
1297function cardsInit () {
1298  const cardsBoxes = cards.querySelectorAll("[data-element='cards-box']")
1299
1300  cardsBoxes.forEach((box) => {
1301    box.addEventListener('click', toggleBox)
1302  })
1303
1304  function toggleBox () {
1305    const oldActive = cards.querySelector('.active')
1306    if (oldActive) oldActive.classList.remove('active')
1307    this.classList.add('active')
1308  }
1309}
1310
1311const catalogAchievementsSlider = document.querySelector(".catalog-achievements__slider")
1312
1313if (catalogAchievementsSlider) catalogAchievementsSliderInit()
1314
1315function catalogAchievementsSliderInit () {
1316  const pointer = document.querySelector(".catalog-achievements__pointer")
1317  const slider = new Swiper(catalogAchievementsSlider, {
1318    mousewheel: { forceToAxis: true },
1319    slidesPerView: 'auto',
1320    spaceBetween: 20,
1321    a11y: false,
1322    navigation: {
1323      nextEl: '.catalog-achievements__btn_next',
1324      prevEl: '.catalog-achievements__btn_prev',
1325    },
1326    scrollbar: {
1327      el: '.catalog-achievements__scrollbar',
1328      draggable: true,
1329    },
1330  })
1331
1332  slider.on('slideChange', function () {
1333    if (pointer) pointer.style.display = 'none'
1334  })
1335}
1336
1337const catalogTile = document.querySelector(".catalog-tile")
1338
1339if (catalogTile) catalogTileInit()
1340
1341function catalogTileInit () {
1342  const catalogTileFilterTops = catalogTile.querySelectorAll(".catalog-tile__filter-top")
1343  const filterSubject = catalogTile.querySelector(".catalog-tile__filter_subject")
1344  const stickyHeader = document.querySelector('.sticky-header')
1345  const body = document.querySelector('body')
1346  const filterSumr = catalogTile.querySelector('[data-role="filter-sumr"]')
1347  const filterNewy = catalogTile.querySelector('[data-role="filter-newy"]')
1348  const filterSubjectWrap = catalogTile.querySelector(".catalog-tile__filter-wrap")
1349  const filterHeadline = filterSubjectWrap.querySelector('.catalog-tile__filter-headline.desk')
1350
1351
1352  filterSumr?.addEventListener('change', () => makeFiltration(1))
1353  filterNewy?.addEventListener('change', () => makeFiltration(1))
1354
1355
1356  catalogTileFilterTops[0].addEventListener("click", (e)=> openFilter(catalogTileFilterTops[0], e))
1357
1358  document.addEventListener('click', function () {
1359    catalogTileFilterTops[0].classList.remove('active')
1360    showHeader()
1361  })
1362
1363  function openFilter (opener, e) {
1364    e.stopPropagation()
1365    if (opener.classList.contains('active')) {
1366      opener.classList.remove('active')
1367      showHeader()
1368      opener.parentElement.classList.remove('active')
1369    } else {
1370      opener.classList.add('active')
1371      opener.parentElement.classList.add('active')
1372      hideHeader()
1373    }
1374  }
1375
1376  function showHeader () {
1377    stickyHeader.classList.remove('mob-hide')
1378    body.classList.remove('no-scroll-mob')
1379  }
1380
1381  function hideHeader () {
1382    stickyHeader.classList.add('mob-hide')
1383    body.classList.add('no-scroll-mob')
1384  }
1385
1386  const config = { attributes: true, childList: true, characterData: true, subtree: true }
1387  const tile = catalogTile.querySelector('.catalog-tile__list')
1388  const subjectInputs = catalogTile.querySelectorAll('.catalog-tile__filter-input_subject')
1389  const subjectInputText = catalogTile.querySelector('.catalog-tile__filter_subject .catalog-tile__filter-top-text')
1390
1391  const observer = new MutationObserver(function observerCallback(mutations) {
1392    mutations.forEach(
1393      (mutation) => {
1394        if (mutation.addedNodes.length) {
1395          mutation.addedNodes.forEach((node) => {
1396            if (node?.classList?.contains('catalog-tile__item')) {
1397              initCommonAnalytics(node)
1398            }
1399          })
1400        }
1401      })
1402    moreBtnInit()
1403  })
1404
1405
1406
1407  if (tile) observer.observe(tile, config)
1408
1409  const reset = catalogTile.querySelector('.catalog-tile__reset-filter')
1410  if (reset) reset.addEventListener('click', resetFilters)
1411
1412  function resetFilters () {
1413    const items = catalogTile.querySelectorAll("input")
1414    items.forEach((item) => {
1415      if (item.hasAttribute('data-default-garde') || item.hasAttribute('data-default-subject')) {
1416        item.checked = true
1417      }else{
1418        item.checked = false
1419      }
1420    })
1421    reset.style.display = 'none'
1422    subjectInputText.innerHTML = "Все предметы"
1423    makeFiltration()
1424  }
1425
1426  for (let i = 0; i < subjectInputs.length; i++) {
1427    subjectInputs[i].addEventListener('change', updateFilter)
1428    subjectInputs[i].addEventListener('change', changeSubjectInputText)
1429  }
1430
1431  function changeSubjectInputText () {
1432    subjectInputText.innerHTML = this.getAttribute('data-text')
1433    const span = document.createElement('span')
1434    span.innerHTML = this.getAttribute('data-text')
1435    subjectInputText.innerHTML = ''
1436    subjectInputText.append(span)
1437  }
1438
1439  moreBtnInit()
1440
1441  function moreBtnInit () {
1442    const moreBtn = catalogTile.querySelector('.all-courses__more-button')
1443    if (moreBtn) {
1444      const newBtn = replaceBtn(moreBtn)
1445      newBtn.addEventListener('click', () => makeFiltration(newBtn.getAttribute('data-v')))
1446    }
1447  }
1448
1449  function replaceBtn (oldElement) {
1450    const newElement = oldElement.cloneNode(true)
1451    oldElement.parentNode.replaceChild(newElement, oldElement)
1452    return newElement
1453  }
1454
1455
1456  function updateFilter () {
1457    const itemsAll = catalogTile.querySelectorAll(["input:checked"])
1458    if (itemsAll.length) {
1459      if (reset) reset.style.display = 'flex'
1460    } else {
1461      if (reset) reset.style.display = 'none'
1462    }
1463    makeFiltration()
1464  }
1465
1466  function makeFiltration (p_paginate = 1) {
1467    let subjects_result = ''
1468    try{
1469      const subjects_items = catalogTile.querySelectorAll('.catalog-tile__filter-input_subject:checked')
1470      subjects_items.forEach((item, i) => {
1471        if (i > 0) subjects_result += '|'
1472        subjects_result += item.value
1473      })
1474    }catch(e){}
1475
1476    let utm_f = tile.getAttribute('data-utm');
1477    let promo_f = tile.getAttribute('data-promo');
1478
1479    if(p_paginate === 1 ){
1480      $('.filtered_elements').html("<div class='tile-loader'></div>");
1481      $('.more_b').html("");
1482    }
1483
1484    var obData = {
1485      'subject': subjects_result,
1486      'utm_t': utm_f,
1487      'promo': promo_f,
1488      'pagePaginate': p_paginate,
1489      'summerny': getSummerny(),
1490    };
1491    console.log(obData);
1492    $.request('ModelUrl::onPaginateTeacher', {
1493      data: obData
1494    })
1495  }
1496  function getSummerny () {
1497    let summerny = ''
1498    if (filterSumr?.checked) {
1499      summerny = filterSumr.getAttribute('data-value')
1500    } else if (filterNewy?.checked) {
1501      summerny = filterNewy.getAttribute('data-value')
1502    }
1503    return summerny
1504  }
1505
1506
1507  initTabs()
1508
1509  function initTabs () {
1510    const tabsParent = filterSubject.querySelector('.catalog-tile__filter-tabs')
1511    const list = filterSubjectWrap.querySelector('.catalog-tile__filter-list')
1512    const tabs = filterSubject.querySelectorAll('.catalog-tile__filter-tab')
1513    const subjectsBoxes = filterSubjectWrap.querySelectorAll('.catalog-tile__filter-box')
1514
1515    if (!tabs.length || !subjectsBoxes.length) return
1516
1517    filterSubjectWrap.addEventListener('scroll', wrapScrollHandler, { passive: true })
1518
1519    function wrapScrollHandler () {
1520      subjectsBoxes.forEach((subjectBox) => {
1521        if (filterSubjectWrap.scrollTop >= subjectBox.offsetTop - 90 - 65) {
1522          const oldTab = filterSubjectWrap.querySelector('.catalog-tile__filter-tab.active')
1523          if (oldTab) oldTab.classList.remove('active')
1524          const index = subjectBox.getAttribute('data-index')
1525          const tab = filterSubjectWrap.querySelector('[data-index="' + index + '"]')
1526          if (tab) {
1527            tabsParent.scrollLeft = tab.offsetLeft - tabsParent.clientWidth/2 + tab.clientWidth/2
1528            tab.classList.add('active')
1529          }
1530        }
1531      })
1532    }
1533
1534    let timeout
1535    let firstToggle = true
1536
1537
1538    tabs.forEach((tab) => {
1539      tab.addEventListener('click', changeTab)
1540      tab.addEventListener('mouseenter', changeTab)
1541    })
1542
1543
1544    function changeTab (e) {
1545      e.stopPropagation()
1546      clearTimeout(timeout)
1547      timeout = setTimeout(() => toggle(this),100)
1548
1549      function toggle (that) {
1550        if (!that.closest('.catalog-tile__filter-wrap').querySelector('.catalog-tile__filter-tab:hover') && !firstToggle) return
1551        firstToggle = false
1552        filterSubjectWrap.removeEventListener('scroll', wrapScrollHandler, { passive: true })
1553        const oldTab = filterSubjectWrap.querySelector('.catalog-tile__filter-tab.active')
1554        if (oldTab) oldTab.classList.remove('active')
1555
1556
1557        that.classList.add('active')
1558        filterHeadline.innerHTML = that.getAttribute('data-text')
1559
1560        subjectsBoxes.forEach((subjectsBox) => {
1561          subjectsBox.classList.add('hide')
1562        })
1563
1564
1565        const index = that.getAttribute('data-index')
1566        const activeSubjectsBox = list.querySelector('[data-index="' + index + '"]')
1567        activeSubjectsBox.classList.remove('hide')
1568
1569
1570        filterSubjectWrap.scrollTop = activeSubjectsBox.offsetTop - 90 - 60
1571
1572        tabsParent.scrollLeft = that.offsetLeft - tabsParent.clientWidth/2 + that.clientWidth/2
1573        setTimeout(() => filterSubjectWrap.addEventListener('scroll', wrapScrollHandler, { passive: true }), 200)
1574      }
1575    }
1576
1577    setTimeout(() => tabs[0].click(),200)
1578  }
1579
1580}
1581
1582const collegeAiProfessions = document.querySelector(".college-ai-professions")
1583
1584if (collegeAiProfessions) collegeAiProfessionsInit()
1585
1586function collegeAiProfessionsInit () {
1587  const tabs = collegeAiProfessions.querySelector(".college-ai-professions__tabs")
1588  const collegeAiProfessionsTabs = collegeAiProfessions.querySelectorAll(".college-ai-professions__tab")
1589  const collegeAiProfessionsAreas = collegeAiProfessions.querySelectorAll(".college-ai-professions__area")
1590
1591  collegeAiProfessionsTabs.forEach((item, index) => {
1592    item.addEventListener('click', function () {
1593      const oldItem = collegeAiProfessions.querySelector('.college-ai-professions__tab.active')
1594      if (oldItem) oldItem.classList.remove('active')
1595      this.classList.add('active')
1596      const oldBox = collegeAiProfessions.querySelector('.college-ai-professions__area.active')
1597      if (oldBox) oldBox.classList.remove('active')
1598      collegeAiProfessionsAreas[index].classList.add('active')
1599      tabs.scrollLeft = item.offsetLeft - tabs.clientWidth/2 + item.clientWidth/2
1600    })
1601  })
1602}
1603
1604
1605const collegeHow = document.querySelector(".college-how")
1606
1607if (collegeHow) collegeHowInit()
1608
1609function collegeHowInit () {
1610  const togglers = collegeHow.querySelectorAll('.college-how__more')
1611
1612  togglers.forEach((toggler) => {
1613    toggler.addEventListener('click', toggleArea)
1614  })
1615
1616  function toggleArea () {
1617    const area = this.closest('.college-how__area')
1618    if (area.classList.contains('college-how__area_full')) {
1619      area.classList.remove('college-how__area_full')
1620      this.textContent = 'Подробнее'
1621    } else {
1622      area.classList.add('college-how__area_full')
1623      this.textContent = 'Свернуть'
1624    }
1625  }
1626}
1627
1628const collegeMainDirections = document.querySelector(".college-main-directions")
1629
1630if (collegeMainDirections) collegeMainDirectionsInit()
1631
1632function collegeMainDirectionsInit () {
1633  const nav = collegeMainDirections.querySelector(".college-main-directions__nav")
1634  const collegeMainDirectionsNavItems = collegeMainDirections.querySelectorAll(".college-main-directions__nav-item")
1635  const collegeMainDirectionsBoxes = collegeMainDirections.querySelectorAll(".college-main-directions__box")
1636
1637  collegeMainDirectionsNavItems.forEach((item, index) => {
1638    item.addEventListener('click', function () {
1639      const oldItem = collegeMainDirections.querySelector('.college-main-directions__nav-item.active')
1640      if (oldItem) oldItem.classList.remove('active')
1641      this.classList.add('active')
1642      const oldBox = collegeMainDirections.querySelector('.college-main-directions__box.active')
1643      if (oldBox) oldBox.classList.remove('active')
1644      collegeMainDirectionsBoxes[index].classList.add('active')
1645      nav.scrollLeft = item.offsetLeft - nav.clientWidth/2 + item.clientWidth/2
1646    })
1647  })
1648}
1649
1650const BLOCK_READ_THRESHOLD = 10 * 1000
1651
1652initCommonAnalytics()
1653
1654function initCommonAnalytics (container = document) {
1655  if (!container || typeof container?.querySelectorAll !== 'function') return
1656
1657  const dataActions = Array.from(container.querySelectorAll('[data-action]'))
1658  const dataBlocks = Array.from(container.querySelectorAll('[data-block]'))
1659
1660  if (container && typeof container.getAttribute === 'function') {
1661    if (container.matches('[data-action]')) dataActions.push(container)
1662    if (container.matches('[data-block]')) dataBlocks.push(container)
1663  }
1664
1665  dataActions.forEach(dataAction => {
1666    dataAction.addEventListener('click', () => {
1667      sendCommonAnalytics('element_click', dataAction)
1668    })
1669  })
1670
1671  if (dataBlocks.length > 0) {
1672    const states = new WeakMap()
1673
1674    dataBlocks.forEach(block => {
1675      states.set(block, {
1676        viewTimer: null,
1677        viewed: false,
1678        read: false,
1679        visible: false,
1680        visibleSince: null,
1681        readTime: 0,
1682      })
1683    })
1684
1685    const observer = new IntersectionObserver(entries => {
1686      entries.forEach(entry => {
1687        const block = entry.target
1688        const state = states.get(block)
1689
1690        if (!state || state.read || !block.isConnected) return
1691
1692        const vh = window.innerHeight
1693        const need = Math.min(
1694          entry.boundingClientRect.height * 0.5,
1695          vh * 0.5
1696        )
1697
1698        const isVisible =
1699          entry.isIntersecting &&
1700          entry.intersectionRect.height >= need
1701
1702        if (isVisible) {
1703          state.visible = true
1704
1705          if (!document.hidden && state.visibleSince === null) {
1706            state.visibleSince = performance.now()
1707          }
1708
1709          if (!state.viewed && !state.viewTimer) {
1710            state.viewTimer = setTimeout(() => {
1711              if (state.viewed || !block.isConnected) {
1712                state.viewTimer = null
1713                return
1714              }
1715
1716              state.viewed = true
1717              state.viewTimer = null
1718
1719              sendCommonAnalytics('block_view', block)
1720            }, 1000)
1721          }
1722        } else {
1723          state.visible = false
1724
1725          if (state.visibleSince !== null) {
1726            state.readTime += performance.now() - state.visibleSince
1727            state.visibleSince = null
1728          }
1729
1730          if (state.viewTimer) {
1731            clearTimeout(state.viewTimer)
1732            state.viewTimer = null
1733          }
1734        }
1735      })
1736    }, {
1737      threshold: Array.from({ length: 101 }, (_, index) => index / 100)
1738    })
1739
1740    const handleVisibilityChange = () => {
1741      const now = performance.now()
1742
1743      dataBlocks.forEach(block => {
1744        const state = states.get(block)
1745
1746        if (!state || state.read || !state.visible) return
1747
1748        if (document.hidden) {
1749          if (state.visibleSince !== null) {
1750            state.readTime += now - state.visibleSince
1751            state.visibleSince = null
1752          }
1753        } else if (block.isConnected) {
1754          state.visibleSince = now
1755        }
1756      })
1757    }
1758
1759    document.addEventListener('visibilitychange', handleVisibilityChange)
1760
1761    const readInterval = setInterval(() => {
1762      if (document.hidden) return
1763
1764      const now = performance.now()
1765
1766      dataBlocks.forEach(block => {
1767        const state = states.get(block)
1768
1769        if (!state || state.read) return
1770
1771        if (!block.isConnected) {
1772          if (state.viewTimer) {
1773            clearTimeout(state.viewTimer)
1774            state.viewTimer = null
1775          }
1776
1777          state.visible = false
1778          state.visibleSince = null
1779          state.read = true
1780
1781          observer.unobserve(block)
1782
1783          return
1784        }
1785
1786        if (!state.visible || state.visibleSince === null) return
1787
1788        state.readTime += now - state.visibleSince
1789        state.visibleSince = now
1790
1791        if (state.readTime >= BLOCK_READ_THRESHOLD) {
1792          state.read = true
1793
1794          sendCommonAnalytics('block_read', block)
1795
1796          observer.unobserve(block)
1797        }
1798      })
1799
1800      const allBlocksFinished = dataBlocks.every(block => {
1801        return states.get(block).read
1802      })
1803
1804      if (allBlocksFinished) {
1805        clearInterval(readInterval)
1806
1807        document.removeEventListener(
1808          'visibilitychange',
1809          handleVisibilityChange
1810        )
1811
1812        observer.disconnect()
1813      }
1814    }, 100)
1815
1816    dataBlocks.forEach(block => observer.observe(block))
1817  }
1818}
1819
1820
1821const getAnalyticsParams = (goal, node) => {
1822  const pageType = node?.closest('[data-page-type]')?.getAttribute('data-page-type') || 'unknown'
1823
1824  const pageName = node.querySelector('#page_name')?.value
1825  let pageNameParsed = ''
1826  try {
1827    pageNameParsed = pageName ? new URL(pageName)?.pathname?.substring(1) : false
1828  } catch (e) {
1829    console.log(e)
1830  }
1831
1832  let block = node?.getAttribute('data-block') || node?.closest('[data-block]')?.getAttribute('data-block') || 'none'
1833  const blockIndex = node?.getAttribute('data-block-index') || node?.closest('[data-block]')?.getAttribute('data-block-index')
1834  if (block !== 'none' && blockIndex) block = block + blockIndex
1835  const action = node?.getAttribute('data-action')
1836  const form = node?.getAttribute('data-form') || pageNameParsed || 'unknown'
1837  const dataElid = node?.getAttribute('data-elid') || node?.closest('[data-elid]')?.getAttribute('data-elid')
1838
1839  const common = {
1840    ...(dataElid ? { entity_id: dataElid } : {}),
1841    filter_stage: node?.closest('[data-filter-stage]')?.getAttribute('data-filter-stage') || 'none',
1842    filter_subject: node?.closest('[data-filter-subject]')?.getAttribute('data-filter-subject') || 'none',
1843    filter_goal: node?.closest('[data-filter-goal]')?.getAttribute('data-filter-goal') || 'none',
1844  }
1845
1846  return {
1847    google: goal === 'submit_form' ? {
1848      submit_form: form,
1849      page_type: pageType,
1850      block_name: block,
1851      ...common,
1852    } : {
1853      ...(goal === 'block_view' ? { block_view: block } : {}),
1854      ...(goal === 'block_read' ? { block_read: block } : {}),
1855      ...(goal !== 'block_view' && goal !== 'block_read' ? { [goal]: action, block_name: block } : {}
1856      ),
1857
1858      ...common,
1859      page_type: pageType,
1860    },
1861
1862    ym: goal === 'submit_form' ? {
1863      [goal]: {
1864        [pageType]: {
1865          [block] : {
1866            [form]: 1
1867          }
1868        },
1869      },
1870    } : {
1871      ...common,
1872      [goal]: {
1873        [pageType]: {
1874          ...(goal === 'block_view' ? { [block]: 1 } : {}),
1875          ...(goal === 'block_read' ? { [block]: 1 } : {}),
1876          ...(goal !== 'block_view' && goal !== 'block_read' ? { [block] : { [action]: 1 } } : {}),
1877        },
1878      },
1879    },
1880  }
1881}
1882
1883
1884async function sendCommonAnalytics (goal, node) {
1885  const params = getAnalyticsParams(goal, node)
1886
1887  async function sendMailru () {
1888    const goalMailru = node.getAttribute('data-analytics-mailru')
1889    if (goalMailru) {
1890      await analytics.mailru(goalMailru)
1891    }
1892  }
1893
1894
1895  await Promise.all([
1896    analytics.gtag(goal, params.google),
1897    analytics.ym(goal, params.ym),
1898    sendMailru()
1899  ])
1900
1901}
1902
1903
1904
1905const costAreas = document.querySelectorAll('.cost__area')
1906 
1907 if (costAreas.length) costAreasInit()
1908 
1909 function costAreasInit () {
1910   for (let i = 0; i < costAreas.length; i++) {
1911     costAreaInit(costAreas[i])
1912   }
1913 
1914   function costAreaInit (area) {
1915     const checkbox = area.querySelector('.cost__checkbox')
1916     if (!checkbox) return
1917 
1918     checkbox.addEventListener('change', changePrice)
1919     checkbox.addEventListener('change', changeHref)
1920 
1921     const button = area.querySelector('.cost__button')
1922     const newHref = checkbox.getAttribute('new-href')
1923     const initialHref = button.getAttribute('href')
1924 
1925     function changeHref () {
1926       const href = button.getAttribute('href')
1927       if (href === newHref) {
1928         button.setAttribute('href', initialHref)
1929       } else {
1930         button.setAttribute('href', newHref)
1931       }
1932     }
1933 
1934     const price_full_old_checkbox_off = checkbox.getAttribute('data-price-full-old-checkbox-off')
1935     const price_full_old_checkbox_on = checkbox.getAttribute('data-price-full-old-checkbox-on')
1936     const price_full_current_checkbox_off = checkbox.getAttribute('data-price-full-current-checkbox-off')
1937     const price_full_current_checkbox_on = checkbox.getAttribute('data-price-full-current-checkbox-on')
1938     const price_plan_old_checkbox_off = checkbox.getAttribute('data-price-plan-old-checkbox-off')
1939     const price_plan_old_checkbox_on = checkbox.getAttribute('data-price-plan-old-checkbox-on')
1940     const price_plan_current_checkbox_off = checkbox.getAttribute('data-price-plan-current-checkbox-off')
1941     const price_plan_current_checkbox_on = checkbox.getAttribute('data-price-plan-current-checkbox-on')
1942 
1943     const priceFullCurrentNode = area.querySelector('[data-element="price-full-current"]')
1944     const priceFullOldNode = area.querySelector('[data-element="price-full-old"]')
1945     const pricePlanCurrentNode = area.querySelector('[data-element="price-plan-current"]')
1946     const pricePlanOldNode = area.querySelector('[data-element="price-plan-old"]')
1947 
1948     function changePrice () {
1949       sendCommonAnalytics('element_click', checkbox)
1950       if (this.checked) {
1951         if (priceFullCurrentNode) priceFullCurrentNode.innerHTML = price_full_current_checkbox_on
1952         if (priceFullOldNode) priceFullOldNode.innerHTML = price_full_old_checkbox_on
1953         if (pricePlanCurrentNode) pricePlanCurrentNode.innerHTML = price_plan_current_checkbox_on
1954         if (pricePlanOldNode) pricePlanOldNode.innerHTML = price_plan_old_checkbox_on
1955       }
1956       else {
1957         if (priceFullCurrentNode) priceFullCurrentNode.innerHTML = price_full_current_checkbox_off
1958         if (priceFullOldNode) priceFullOldNode.innerHTML = price_full_old_checkbox_off
1959         if (pricePlanCurrentNode) pricePlanCurrentNode.innerHTML = price_plan_current_checkbox_off
1960         if (pricePlanOldNode) pricePlanOldNode.innerHTML = price_plan_old_checkbox_off
1961       }
1962     }
1963   }
1964 }
1965
1966const courseAboutVideoWraps = document.querySelectorAll("[data-element='course-about-video-wrap']")
1967
1968for (let i = 0; i < courseAboutVideoWraps.length; i++) {
1969  courseAboutVideoWrapInit(courseAboutVideoWraps[i])
1970}
1971
1972function courseAboutVideoWrapInit (videoWrap) {
1973  const courseAboutVideo = videoWrap.querySelector("[data-element='course-about-video']")
1974  const soundBtn = videoWrap.querySelector(".course-about__sound")
1975  let startPlayTime = courseAboutVideo.getAttribute('data-play-start')
1976   if (!startPlayTime) startPlayTime = 0
1977
1978   if (courseAboutVideo.readyState >= 2) {
1979    videoLoaded()
1980   }
1981 
1982  courseAboutVideo.addEventListener('loadeddata', videoLoaded)
1983  courseAboutVideo.addEventListener('play', videoLoaded)
1984
1985  setTimeout(() => {
1986    try {
1987      courseAboutVideo.currentTime = startPlayTime
1988    } catch (e) {
1989      console.log(e)
1990    }
1991  }, 1000)
1992
1993
1994  function videoLoaded () {
1995    videoWrap.classList.add('loaded')
1996  }
1997
1998  videoWrap.addEventListener('click', playVideo)
1999
2000  function playVideo (e) {
2001    e.stopPropagation()
2002    if (courseAboutVideo.muted) {
2003        courseAboutVideo.muted = false
2004        courseAboutVideo.loop = false
2005        courseAboutVideo.currentTime = 0
2006        courseAboutVideo.controls = true
2007
2008
2009 
2010        soundBtn.classList.add('hide')
2011        setTimeout(() => courseAboutVideo.play(), 100)
2012    } else {
2013        courseAboutVideo.muted = true
2014        courseAboutVideo.controls = false
2015        soundBtn.classList.remove('hide')
2016    }
2017  }
2018}
2019
2020const selectArray = document.querySelectorAll('[data-role="custom-select"]')
2021
2022for (let i = 0; i < selectArray.length; i++) {
2023  customSelect(selectArray[i])
2024}
2025
2026const dataRedirectLinks = document.querySelectorAll('[data-redirect]')
2027
2028if (dataRedirectLinks.length) dataRedirectLinksInit()
2029
2030function dataRedirectLinksInit () {
2031  for (let i = 0; i < dataRedirectLinks.length; i++) {
2032    dataRedirectLinks[i].addEventListener('click', dataRedirect)
2033  }
2034}
2035
2036function dataRedirect (e) {
2037  e.preventDefault()
2038  window.open(this.href, '_blank');
2039}
2040
2041const diagnostika_b = document.querySelector('.diagnostika_b');
2042
2043if (diagnostika_b) diagnostika_bInit()
2044
2045function diagnostika_bInit () {
2046  /* ================= 1. Колесо знаний ================= */
2047
2048  // Оси идут по часовой стрелке от «12 часов», ровно как в Figma.
2049  var WHEEL_AXES = [
2050    { label: 'Дроби',     value: 86, gap: false },
2051    { label: 'Уравнения', value: 52, gap: true  },
2052    { label: 'Функции',   value: 40, gap: true  },
2053    { label: 'Геометрия', value: 66, gap: false },
2054    { label: 'Проценты',  value: 90, gap: false },
2055    { label: 'Степени',   value: 48, gap: true  },
2056    { label: 'Стат.',     value: 78, gap: false },
2057    { label: 'Задачи',    value: 44, gap: true  }
2058  ];
2059
2060  // Геометрия снята с двух контрольных макетов Figma (76:3 и 76:4).
2061  //   box  — размер области колеса, cx/cy — центр, r — радиус внешнего кольца,
2062  //   dot  — диаметр вершины,
2063  //   gaps — отступ подписи от внешнего кольца: n/e/s/w по сторонам света,
2064  //          d — по диагоналям. На Desktop дизайнер развёл подписи
2065  //          несимметрично, чтобы они уложились в 470×450.
2066  var WHEEL_PRESETS = {
2067    desktop: {
2068      box: [470, 450], cx: 235, cy: 222, r: 163, dot: 11,
2069      gaps: { n: 25, e: 14, s: 30, w: 30, d: 21.2 }
2070    },
2071    tablet: {
2072      box: [654, 470], cx: 327, cy: 231, r: 170, dot: 10,
2073      gaps: { n: 26, e: 26, s: 26, w: 26, d: 18.4 }
2074    }
2075  };
2076
2077  // Колесо есть только на Desktop и Tablet: в макете Mobile его нет.
2078  var MOBILE_QUERY = '(max-width: 600px)';
2079  var TABLET_QUERY = '(max-width: 1180px)';
2080
2081  var SVG_NS = 'http://www.w3.org/2000/svg';
2082
2083  function svgEl(name, attrs) {
2084    var node = document.createElementNS(SVG_NS, name);
2085    for (var key in attrs) { node.setAttribute(key, attrs[key]); }
2086    return node;
2087  }
2088
2089  function currentPreset() {
2090    if (window.matchMedia(MOBILE_QUERY).matches) { return null; }
2091    if (window.matchMedia(TABLET_QUERY).matches) { return WHEEL_PRESETS.tablet; }
2092    return WHEEL_PRESETS.desktop;
2093  }
2094
2095  function renderWheel(host, p) {
2096    var w = p.box[0];
2097    var h = p.box[1];
2098
2099    host.textContent = '';
2100
2101    var svg = svgEl('svg', {
2102      'class': 'wheel__chart',
2103      viewBox: '0 0 ' + w + ' ' + h,
2104      preserveAspectRatio: 'xMidYMid meet',
2105      focusable: 'false',
2106      'aria-hidden': 'true'
2107    });
2108
2109    // Сетка: 4 кольца
2110    [0.25, 0.5, 0.75, 1].forEach(function (k) {
2111      svg.appendChild(svgEl('circle', {
2112        cx: p.cx, cy: p.cy, r: p.r * k,
2113        fill: 'none', stroke: '#003C56', 'stroke-opacity': '0.1'
2114      }));
2115    });
2116
2117    // Спицы
2118    var spokes = '';
2119    WHEEL_AXES.forEach(function (_, i) {
2120      var a = (Math.PI / 4) * i;
2121      spokes += 'M' + p.cx + ' ' + p.cy +
2122        'L' + (p.cx + p.r * Math.sin(a)) + ' ' + (p.cy - p.r * Math.cos(a));
2123    });
2124    svg.appendChild(svgEl('path', { d: spokes, stroke: '#003C56', 'stroke-opacity': '0.1', fill: 'none' }));
2125
2126    // Программа класса — пунктирное кольцо 0.8R
2127    svg.appendChild(svgEl('circle', {
2128      cx: p.cx, cy: p.cy, r: p.r * 0.8,
2129      fill: 'none', stroke: '#6683C2', 'stroke-opacity': '0.7',
2130      'stroke-width': '1.4', 'stroke-dasharray': '5 5'
2131    }));
2132
2133    // Профиль ученика
2134    var points = WHEEL_AXES.map(function (axis, i) {
2135      var a = (Math.PI / 4) * i;
2136      var rr = p.r * (axis.value / 100);
2137      return [p.cx + rr * Math.sin(a), p.cy - rr * Math.cos(a)];
2138    });
2139    svg.appendChild(svgEl('polygon', {
2140      points: points.map(function (pt) { return pt[0].toFixed(2) + ',' + pt[1].toFixed(2); }).join(' '),
2141      fill: '#6683C2', 'fill-opacity': '0.18',
2142      stroke: '#6683C2', 'stroke-width': '2', 'stroke-linejoin': 'round'
2143    }));
2144
2145    // Вершины
2146    points.forEach(function (pt, i) {
2147      svg.appendChild(svgEl('circle', WHEEL_AXES[i].gap
2148        ? { cx: pt[0], cy: pt[1], r: p.dot / 2 - 1, fill: '#FFFFFF', stroke: '#F37E60', 'stroke-width': '2' }
2149        : { cx: pt[0], cy: pt[1], r: p.dot / 2, fill: '#003C56' }
2150      ));
2151    });
2152
2153    host.appendChild(svg);
2154
2155    // Подписи — HTML поверх SVG, позиционируются в процентах от области колеса
2156    WHEEL_AXES.forEach(function (axis, i) {
2157      var a = (Math.PI / 4) * i;
2158      var sin = Math.sin(a);
2159      var cos = Math.cos(a);
2160      var px = p.cx + p.r * sin;
2161      var py = p.cy - p.r * cos;
2162      var diagonal = Math.abs(sin) > 0.01 && Math.abs(cos) > 0.01;
2163      var x, y;
2164
2165      if (diagonal) {
2166        x = px + p.gaps.d * Math.sign(sin);
2167        y = py - p.gaps.d * Math.sign(cos);
2168      } else if (Math.abs(sin) < 0.01) {          // вертикальная ось
2169        x = p.cx;
2170        y = py - (cos > 0 ? p.gaps.n : -p.gaps.s);
2171      } else {                                     // горизонтальная ось
2172        x = px + (sin > 0 ? p.gaps.e : -p.gaps.w);
2173        y = p.cy;
2174      }
2175
2176      // Выравнивание бокса подписи относительно точки на оси
2177      var tx = sin > 0.01 ? '0' : (sin < -0.01 ? '-100%' : '-50%');
2178      var ty = cos > 0.01 ? '-100%' : (cos < -0.01 ? '0' : '-50%');
2179
2180      var el = document.createElement('span');
2181      el.className = 'wheel__label' + (axis.gap ? ' wheel__label--gap' : '');
2182      el.style.left = (x / w * 100) + '%';
2183      el.style.top = (y / h * 100) + '%';
2184      el.style.transform = 'translate(' + tx + ', ' + ty + ')';
2185      el.innerHTML = axis.label + '<b>' + axis.value + '%</b>';
2186      host.appendChild(el);
2187    });
2188  }
2189
2190  var wheelHost = document.getElementById('knowledge-wheel');
2191  if (wheelHost) {
2192    var lastPreset;
2193
2194    var syncWheel = function () {
2195      var preset = currentPreset();
2196      if (preset === lastPreset) { return; }
2197      lastPreset = preset;
2198      if (preset) { renderWheel(wheelHost, preset); } else { wheelHost.textContent = ''; }
2199    };
2200
2201    syncWheel();
2202
2203    var resizeTimer;
2204    window.addEventListener('resize', function () {
2205      clearTimeout(resizeTimer);
2206      resizeTimer = setTimeout(syncWheel, 150);
2207    });
2208  }
2209
2210}
2211
2212const diagnostika = document.querySelector('.diagnostika');
2213
2214if (diagnostika) diagnostikaInit()
2215
2216function diagnostikaInit() {
2217  /* ================= 1. Колесо знаний ================= */
2218
2219// Оси идут по часовой стрелке от «12 часов», ровно как в Figma.
2220  var WHEEL_AXES = [
2221    { label: 'Дроби',     value: 86, gap: false },
2222    { label: 'Уравнения', value: 52, gap: true  },
2223    { label: 'Функции',   value: 40, gap: true  },
2224    { label: 'Геометрия', value: 66, gap: false },
2225    { label: 'Проценты',  value: 90, gap: false },
2226    { label: 'Степени',   value: 48, gap: true  },
2227    { label: 'Стат.',     value: 78, gap: false },
2228    { label: 'Задачи',    value: 44, gap: true  }
2229  ];
2230
2231// Геометрия из трёх контрольных макетов Figma.
2232// box   — размер области колеса, cx/cy — центр, r — радиус внешнего кольца,
2233// gapC  — отступ подписи на вертикальных/горизонтальных осях,
2234// gapD  — отступ подписи на диагоналях, dot — диаметр вершины.
2235  var WHEEL_PRESETS = {
2236    desktop: { box: [470, 450], cx: 235, cy: 222, r: 163, gapC: 25, gapD: 21, dot: 11 },
2237    tablet:  { box: [654, 470], cx: 327, cy: 231, r: 170, gapC: 26, gapD: 18.4, dot: 10 },
2238    mobile:  { box: [290, 300], cx: 145, cy: 148, r: 78,  gapC: 18, gapD: 12.73, dot: 8 }
2239  };
2240
2241  var SVG_NS = 'http://www.w3.org/2000/svg';
2242
2243  function svgEl(name, attrs) {
2244    var node = document.createElementNS(SVG_NS, name);
2245    for (var key in attrs) { node.setAttribute(key, attrs[key]); }
2246    return node;
2247  }
2248
2249  function currentPreset() {
2250    if (window.matchMedia('(max-width: 600px)').matches) { return WHEEL_PRESETS.mobile; }
2251    if (window.matchMedia('(max-width: 1180px)').matches) { return WHEEL_PRESETS.tablet; }
2252    return WHEEL_PRESETS.desktop;
2253  }
2254
2255  function renderWheel(host) {
2256    var p = currentPreset();
2257    var w = p.box[0];
2258    var h = p.box[1];
2259
2260    host.textContent = '';
2261
2262    var svg = svgEl('svg', {
2263      'class': 'wheel__chart',
2264      viewBox: '0 0 ' + w + ' ' + h,
2265      preserveAspectRatio: 'xMidYMid meet',
2266      focusable: 'false',
2267      'aria-hidden': 'true'
2268    });
2269
2270    // Сетка: 4 кольца
2271    [0.25, 0.5, 0.75, 1].forEach(function (k) {
2272      svg.appendChild(svgEl('circle', {
2273        cx: p.cx, cy: p.cy, r: p.r * k,
2274        fill: 'none', stroke: '#003C56', 'stroke-opacity': '0.1'
2275      }));
2276    });
2277
2278    // Спицы
2279    var spokes = '';
2280    WHEEL_AXES.forEach(function (_, i) {
2281      var a = (Math.PI / 4) * i;
2282      spokes += 'M' + p.cx + ' ' + p.cy +
2283        'L' + (p.cx + p.r * Math.sin(a)) + ' ' + (p.cy - p.r * Math.cos(a));
2284    });
2285    svg.appendChild(svgEl('path', { d: spokes, stroke: '#003C56', 'stroke-opacity': '0.1', fill: 'none' }));
2286
2287    // Программа класса — пунктирное кольцо 0.8R
2288    svg.appendChild(svgEl('circle', {
2289      cx: p.cx, cy: p.cy, r: p.r * 0.8,
2290      fill: 'none', stroke: '#6683C2', 'stroke-opacity': '0.7',
2291      'stroke-width': '1.5', 'stroke-dasharray': '6 5'
2292    }));
2293
2294    // Профиль ученика
2295    var points = WHEEL_AXES.map(function (axis, i) {
2296      var a = (Math.PI / 4) * i;
2297      var rr = p.r * (axis.value / 100);
2298      return [p.cx + rr * Math.sin(a), p.cy - rr * Math.cos(a)];
2299    });
2300    svg.appendChild(svgEl('polygon', {
2301      points: points.map(function (pt) { return pt[0].toFixed(2) + ',' + pt[1].toFixed(2); }).join(' '),
2302      fill: '#6683C2', 'fill-opacity': '0.18',
2303      stroke: '#6683C2', 'stroke-width': '2', 'stroke-linejoin': 'round'
2304    }));
2305
2306    // Вершины
2307    points.forEach(function (pt, i) {
2308      var axis = WHEEL_AXES[i];
2309      svg.appendChild(svgEl('circle', axis.gap
2310        ? { cx: pt[0], cy: pt[1], r: p.dot / 2 - 1, fill: '#FFFFFF', stroke: '#F37E60', 'stroke-width': '2' }
2311        : { cx: pt[0], cy: pt[1], r: p.dot / 2, fill: '#003C56' }
2312      ));
2313    });
2314
2315    host.appendChild(svg);
2316
2317    // Подписи — HTML поверх SVG, позиционируются в процентах от области колеса
2318    WHEEL_AXES.forEach(function (axis, i) {
2319      var a = (Math.PI / 4) * i;
2320      var sin = Math.sin(a);
2321      var cos = Math.cos(a);
2322      var diagonal = Math.abs(sin) > 0.01 && Math.abs(cos) > 0.01;
2323      var gap = diagonal ? p.gapD : p.gapC;
2324
2325      var x = p.cx + (p.r * sin) + (diagonal ? gap * Math.sign(sin) : gap * sin);
2326      var y = p.cy - (p.r * cos) - (diagonal ? gap * Math.sign(cos) : gap * cos);
2327
2328      // Выравнивание бокса подписи относительно точки на оси
2329      var tx = sin > 0.01 ? '0' : (sin < -0.01 ? '-100%' : '-50%');
2330      var ty = cos > 0.01 ? '-100%' : (cos < -0.01 ? '0' : '-50%');
2331
2332      var el = document.createElement('span');
2333      el.className = 'wheel__label' + (axis.gap ? ' wheel__label--gap' : '');
2334      el.style.left = (x / w * 100) + '%';
2335      el.style.top = (y / h * 100) + '%';
2336      el.style.transform = 'translate(' + tx + ', ' + ty + ')';
2337      el.innerHTML = axis.label + '<b>' + axis.value + '%</b>';
2338      host.appendChild(el);
2339    });
2340  }
2341
2342  var wheelHost = document.getElementById('knowledge-wheel');
2343  if (wheelHost) {
2344    renderWheel(wheelHost);
2345
2346    var lastWidthBucket = null;
2347    var resizeTimer;
2348    window.addEventListener('resize', function () {
2349      clearTimeout(resizeTimer);
2350      resizeTimer = setTimeout(function () {
2351        var bucket = currentPreset();
2352        if (bucket !== lastWidthBucket) {
2353          lastWidthBucket = bucket;
2354          renderWheel(wheelHost);
2355        }
2356      }, 150);
2357    });
2358  }
2359
2360  /* ================= 3. FAQ-аккордеон ================= */
2361
2362  Array.prototype.forEach.call(document.querySelectorAll('.faq-item'), function (item) {
2363    var trigger = item.querySelector('.faq-item__q');
2364    if (!trigger) { return; }
2365    trigger.addEventListener('click', function () {
2366      var willOpen = !item.classList.contains('is-open');
2367      item.classList.toggle('is-open', willOpen);
2368      trigger.setAttribute('aria-expanded', willOpen ? 'true' : 'false');
2369    });
2370  });
2371}
2372
2373
2374const discountAugust = document.querySelector('[data-element="discount-august"]')
2375
2376if (discountAugust) discountAugustInit()
2377
2378function discountAugustInit () {
2379  const stickyHeader = document.querySelector('.sticky-header')
2380  const close = document.querySelector('[data-element="discount-august__close"]')
2381  close.addEventListener('click', removeDiscount)
2382
2383  function removeDiscount (e) {
2384    e.preventDefault()
2385    discountAugust.remove()
2386    window.removeEventListener('scroll', checkScroll)
2387    stickyHeader.classList.remove('predzaps-top-hide-no-transition')
2388    stickyHeader.classList.remove('predzaps-top-hide')
2389  }
2390
2391  window.addEventListener('scroll', checkScroll, { passive: true })
2392
2393  function checkScroll () {
2394    if (window.scrollY > 100) {
2395      stickyHeader.classList.add('predzaps-top-hide')
2396      setTimeout(() => stickyHeader.classList.add('predzaps-top-hide-no-transition'), 300)
2397    } else if (window.scrollY <= 20) {
2398      stickyHeader.classList.remove('predzaps-top-hide-no-transition')
2399      setTimeout(() => stickyHeader.classList.remove('predzaps-top-hide'), 100)
2400    }
2401  }
2402}
2403
2404const discount = document.querySelector('[data-element="discount"]')
2405
2406if (discount) discountInit()
2407
2408function discountInit () {
2409  const close = document.querySelector('[data-element="discount__close"]')
2410  close.addEventListener('click', removeDiscount)
2411
2412  function removeDiscount (e) {
2413    e.preventDefault()
2414    discount.remove()
2415  }
2416}
2417
2418const educatorSkillsItems = document.querySelectorAll('.educator-skills__item')
2419
2420if (educatorSkillsItems.length) educatorSkillsItemsInit()
2421
2422function educatorSkillsItemsInit () {
2423  const line = document.querySelector('.educator-skills__line')
2424
2425  function resizeHandler () {
2426    if (window.innerWidth < 1440) {
2427      line.style.bottom = `${educatorSkillsItems[educatorSkillsItems.length - 1].clientHeight - 4}px`
2428    } else {
2429      line.style.bottom = '20px'
2430    }
2431  }
2432
2433  resizeHandler()
2434
2435  window.addEventListener('resize', resizeHandler)
2436}
2437
2438const egeCapTabsArray = document.querySelectorAll('.ege-cap__tabs')
2439
2440for (let i = 0; i < egeCapTabsArray.length; i++) {
2441  egeCapTabsInit(egeCapTabsArray[i])
2442}
2443
2444function egeCapTabsInit (tabs) {
2445  const tab = tabs.querySelector('a.ege-cap__tab')
2446  if (tab) tab.addEventListener('click', () => tabs.classList.add('active'))
2447}
2448
2449const egeTileToggle = document.querySelectorAll('.ege-tile__toggle')
2450
2451for (let i = 0; i < egeTileToggle.length; i++) {
2452  egeTileToggleInit(egeTileToggle[i])
2453}
2454
2455function egeTileToggleInit (tabs) {
2456  const tab = tabs.querySelector('a.ege-tile__toggle-item')
2457  if (tab) tab.addEventListener('click', () => tabs.classList.add('active'))
2458}
2459
2460const egeTile = document.querySelector(".ege-tile")
2461
2462if (egeTile) egeTileInit()
2463
2464function egeTileInit () {
2465  const egeTileFilterTop = egeTile.querySelector(".ege-tile__filter-top")
2466  const stickyHeader = document.querySelector('.sticky-header')
2467  const body = document.querySelector('body')
2468  const filterSumr = egeTile.querySelector('[data-role="filter-sumr"]')
2469  const filterNewy = egeTile.querySelector('[data-role="filter-newy"]')
2470
2471
2472
2473  egeTileFilterTop.addEventListener("click", (e)=> openFilter(egeTileFilterTop, e))
2474  filterSumr?.addEventListener('change', () => makeFiltration(1))
2475  filterNewy?.addEventListener('change', () => makeFiltration(1))
2476
2477  document.addEventListener('click', function () {
2478    egeTileFilterTop.classList.remove('active')
2479  })
2480
2481  function openFilter (opener, e) {
2482    e.stopPropagation()
2483    if (opener.classList.contains('active')) {
2484      opener.classList.remove('active')
2485      showHeader()
2486    } else {
2487      closeSelectFilter()
2488      opener.classList.add('active')
2489      hideHeader()
2490    }
2491  }
2492
2493  function closeSelectFilter () {
2494    const oldSelectFilterOpen = document.querySelector(".select-filter.active")
2495    if (oldSelectFilterOpen) {
2496      oldSelectFilterOpen.classList.remove('active')
2497      oldSelectFilterOpen.querySelector('.select-filter__top').classList.remove('active')
2498    }
2499  }
2500
2501  function showHeader () {
2502    stickyHeader.classList.remove('hide')
2503    body.classList.remove('no-scroll')
2504  }
2505
2506  function hideHeader () {
2507    if (window.innerWidth < 744) {
2508      stickyHeader.classList.add('hide')
2509      body.classList.add('no-scroll')
2510    }
2511  }
2512
2513  const config = { attributes: true, childList: true, characterData: true, subtree: true }
2514  const tile = egeTile.querySelector('.all-courses__tile')
2515  const classInputs = egeTile.querySelectorAll('.ege-tile__tab-input_class')
2516  const subjectInputs = egeTile.querySelectorAll('.ege-tile__filter-input_subject')
2517  const subjectInputText = egeTile.querySelector('.ege-tile__filter-top-text')
2518
2519  const observer = new MutationObserver(function observerCallback(mutations) {
2520    mutations.forEach(
2521      (mutation) => {
2522        if (mutation.addedNodes.length) {
2523          mutation.addedNodes.forEach((node) => {
2524            if (node?.classList?.contains('all-courses__item')) {
2525              dataHrefLinksInit(node)
2526              togglePrice(node)
2527              fancyboxAjaxCardsReInit(node)
2528              initCommonAnalytics(node)
2529            }
2530          })
2531        }
2532      })
2533    moreBtnInit()
2534  })
2535
2536  if (tile) togglePrice()
2537
2538  function togglePrice (node) {
2539    if (node) {
2540      togglePriceHandler(node)
2541    } else {
2542      const items = tile?.querySelectorAll(".all-courses__item")
2543      items.forEach((item) => {
2544        togglePriceHandler(item)
2545      })
2546    }
2547    function togglePriceHandler (item) {
2548      const toggle = item.querySelectorAll('.all-courses__radio-input')
2549      if (!toggle.length) return
2550      const boxes = item.querySelectorAll('.all-courses__box')
2551      const textReplace = item.querySelector('.all-courses__info.text-replace')
2552      let texts
2553      if (textReplace) {
2554        texts = textReplace.querySelectorAll('.all-courses__info-span')
2555      }
2556      for (let i = 0; i < toggle.length; i++) {
2557        toggle[i].addEventListener('change', toggleBoxes)
2558        if (texts) toggle[i].addEventListener('change', toggleTexts)
2559      }
2560
2561      function toggleBoxes () {
2562        for (let i = 0; i < boxes.length; i++) {
2563          if (boxes[i].classList.contains('hide')) {
2564            boxes[i].classList.remove('hide')
2565          } else {
2566            boxes[i].classList.add('hide')
2567          }
2568        }
2569      }
2570
2571      function toggleTexts () {
2572        for (let i = 0; i < texts.length; i++) {
2573          if (texts[i].classList.contains('hide')) {
2574            texts[i].classList.remove('hide')
2575          } else {
2576            texts[i].classList.add('hide')
2577          }
2578        }
2579      }
2580    }
2581  }
2582
2583  if (tile) observer.observe(tile, config)
2584
2585  const reset = egeTile.querySelector('.ege-tile__reset-filter')
2586  if (reset) reset.addEventListener('click', resetFilters)
2587
2588  function resetFilters () {
2589    const items = egeTile.querySelectorAll("input")
2590    items.forEach((item) => {
2591      if (item.hasAttribute('data-default-garde')) {
2592        item.checked = true
2593      }else{
2594        item.checked = false
2595      }
2596    })
2597    reset.style.display = 'none'
2598    subjectInputText.innerHTML = "Все предметы"
2599    makeFiltration();
2600  }
2601
2602  for (let i = 0; i < classInputs.length; i++) {
2603    classInputs[i].addEventListener('change', updateFilter)
2604  }
2605
2606  for (let i = 0; i < subjectInputs.length; i++) {
2607    subjectInputs[i].addEventListener('change', updateFilter)
2608    subjectInputs[i].addEventListener('change', changeSubjectInputText)
2609  }
2610
2611  function changeSubjectInputText () {
2612    subjectInputText.innerHTML = this.getAttribute('data-text')
2613  }
2614
2615  moreBtnInit()
2616
2617  function moreBtnInit () {
2618    const moreBtn = egeTile.querySelector('.all-courses__more-button')
2619    if (moreBtn) {
2620      const newBtn = replaceBtn(moreBtn)
2621      newBtn.addEventListener('click', () => makeFiltration(newBtn.getAttribute('data-v')))
2622    }
2623  }
2624
2625  function replaceBtn (oldElement) {
2626    const newElement = oldElement.cloneNode(true)
2627    oldElement.parentNode.replaceChild(newElement, oldElement)
2628    return newElement
2629  }
2630
2631
2632  function updateFilter () {
2633    const itemsAll = egeTile.querySelectorAll(["input:checked"])
2634    if (itemsAll.length) {
2635      if (reset) reset.style.display = 'flex'
2636    } else {
2637      if (reset) reset.style.display = 'none'
2638    }
2639    makeFiltration()
2640  }
2641
2642  function makeFiltration (p_paginate = 1) {
2643    const grades_items = egeTile.querySelectorAll('.ege-tile__tab-input_class:checked')
2644    let grades_result = ''
2645    let grade_first = 0
2646    grades_items.forEach((item, i) => {
2647      if (i > 0) grades_result += '|'
2648      if (grade_first == 0) grade_first = item.value
2649      grades_result += item.value
2650    })
2651    let subjects_result = ''
2652    try{
2653      const subjects_items = egeTile.querySelectorAll('.ege-tile__filter-input_subject:checked')
2654      subjects_items.forEach((item, i) => {
2655        if (i > 0) subjects_result += '|'
2656        subjects_result += item.value
2657      })
2658    }catch(e){}
2659
2660    let utm_f = tile.getAttribute('data-utm');
2661    let promo_f = tile.getAttribute('data-promo');
2662    let oge_ege_type = tile.getAttribute('data-oge-ege');
2663
2664    if(p_paginate === 1 ){
2665        $('.filtered_elements').html("<div class='tile-loader'></div>");
2666        $('.more_b').html("");
2667    }
2668
2669    var obData = {
2670      'grade': grades_result,
2671      'subject': subjects_result,
2672      'utm_t': utm_f,
2673      'promo': promo_f,
2674      'oge_ege_type': oge_ege_type,
2675      'pagePaginate': p_paginate,
2676      'summerny': getSummerny(),
2677    };
2678    $.request('DirectionFunctions::onPaginateAllCourses', {
2679      data: obData
2680    })
2681    // if (grade_first > 0){
2682    //   let url = new URL(window.location.href)
2683    //   url.searchParams.set('gr', grade_first);
2684    //   history.replaceState(null, "", url.toString())
2685    // }
2686    // }
2687  }
2688  function getSummerny () {
2689    let summerny = ''
2690    if (filterSumr?.checked) {
2691      summerny = filterSumr.getAttribute('data-value')
2692    } else if (filterNewy?.checked) {
2693      summerny = filterNewy.getAttribute('data-value')
2694    }
2695    return summerny
2696  }
2697
2698}
2699
2700const eye = document.querySelector('.eye')
2701
2702if (eye) eyeInit()
2703
2704function eyeInit() {
2705  const body = document.querySelector('body')
2706  const isActive = localStorage.getItem('tochka-school-eye')
2707  if (isActive === "true") {
2708    activateEye()
2709  }
2710  eye.addEventListener('click', toggleEye)
2711
2712  function toggleEye () {
2713    if (eye.classList.contains('active')) {
2714      resetEye()
2715    } else {
2716      activateEye()
2717    }
2718  }
2719
2720  function activateEye () {
2721    eye.classList.add('active')
2722    body.classList.add('eye-active')
2723    localStorage.setItem('tochka-school-eye', 'true')
2724  }
2725
2726  function resetEye () {
2727    eye.classList.remove('active')
2728    body.classList.remove('eye-active')
2729    localStorage.setItem('tochka-school-eye', '')
2730  }
2731}
2732
2733
2734const famDoc = document.querySelector('.fam-doc')
2735
2736if (famDoc) famDocInit()
2737
2738function famDocInit () {
2739  const toggle = famDoc.querySelector('.fam-doc__button')
2740  toggle?.addEventListener('click', toggleDoc)
2741
2742  function toggleDoc () {
2743    if (famDoc.classList.contains('open')) {
2744      famDoc.classList.remove('open')
2745      toggle.innerHTML = 'Открыть расписание аттестации'
2746    } else {
2747      famDoc.classList.add('open')
2748      toggle.innerHTML = 'Скрыть расписание аттестации'
2749    }
2750  }
2751}
2752
2753
2754
2755const familyHowSlider = document.querySelector('[data-element="family-h
2755ow-slider"]')
2756
2757if (familyHowSlider) familyHowSliderInit()
2758
2759function familyHowSliderInit () {
2760  let familyHowSliderSwiper
2761
2762  function initSlider () {
2763    familyHowSliderSwiper = new Swiper(familyHowSlider, {
2764      slidesPerView: 'auto',
2765      spaceBetween: 40,
2766      a11y: false,
2767      navigation: {
2768        nextEl: '.family-how__nav-btn_next',
2769        prevEl: '.family-how__nav-btn_prev',
2770      },
2771      scrollbar: {
2772        el: '.family-how__scrollbar',
2773        draggable: true,
2774      },
2775    })
2776  }
2777
2778  window.addEventListener('resize', checkSlider)
2779
2780  checkSlider()
2781
2782  function checkSlider () {
2783    if (window.innerWidth >= 744) {
2784      if (!familyHowSliderSwiper || familyHowSliderSwiper.destroyed) {
2785        initSlider()
2786      }
2787    } else {
2788      if (familyHowSliderSwiper && !familyHowSliderSwiper.destroyed) {
2789        familyHowSliderSwiper.destroy(true, true)
2790        familyHowSliderSwiper = null
2791      }
2792    }
2793  }
2794}
2795
2796const familyProgram = document.querySelector('.family-program')
2797 
2798 if (familyProgram) familyProgramInit()
2799 
2800 function familyProgramInit () {
2801   const wrap = document.querySelector('.family-program__wrap')
2802   const overlay = document.querySelector('.family-program__overlay')
2803 
2804   overlay.addEventListener('scroll', function () {
2805     wrap.classList.add('hide-hint')
2806   }, {once: true})
2807
2808    if (overlay.scrollWidth <= overlay.clientWidth) {
2809        wrap.classList.add('hide-hint')
2810    }
2811 }
2812
2813
2814
2815
2816const scheduleFamily = document.querySelector('[data-element="family-schedule"]')
2817
2818if (scheduleFamily) scheduleFamilyInit()
2819
2820function scheduleFamilyInit () {
2821  let offsetHeader
2822  const toggleBottom = scheduleFamily.querySelector('[data-element="family-schedule__toggle-bottom"]')
2823  const programStretch = document.querySelector('.program-stretch')
2824  const toggleTop = document.querySelector('[data-element="family-schedule__toggle-top"]')
2825  const table = scheduleFamily.querySelector('[data-element="family-schedule__box"]')
2826  const row = scheduleFamily.querySelector('[data-element="family-schedule__row"]')
2827  const cells = scheduleFamily.querySelectorAll('[data-element="family-schedule__cell"]')
2828  const cellTime = scheduleFamily.querySelector('[data-element="family-schedule__time"]')
2829
2830  const isSummer = toggleTop?.classList.contains('summer')
2831 
2832  tableFixedCalculate()
2833
2834  function tableFixedCalculate() {
2835    if (window.innerWidth <= 360) {
2836      offsetHeader = 70
2837    } else if (window.innerWidth < 1200) {
2838      offsetHeader = 82
2839    } else {
2840      offsetHeader = 108
2841    }
2842    if (window.innerWidth < 1440) {
2843      for (let i = 0; i < cells.length; i++) {
2844        cells[i].style.height = cells[i].parentNode.offsetHeight + 'px'
2845      }
2846    } else {
2847      for (let i = 0; i < cells.length; i++) {
2848        cells[i].style.height = 'auto'
2849      }
2850    }
2851  }
2852
2853  window.addEventListener('scroll', rowFixedCalculate)
2854  window.addEventListener('resize', tableFixedCalculate)
2855
2856  rowFixedCalculate()
2857
2858  function rowFixedCalculate () {
2859    if (window.innerWidth >= 1440) {
2860      row.style.transform = 'none'
2861      cellTime.style.transform = 'none'
2862    } else {
2863      const topCoord = table.getBoundingClientRect().top
2864      const bottomCoord = table.getBoundingClientRect().bottom
2865      if (topCoord < offsetHeader && bottomCoord > 100) {
2866        row.style.transform = row.style.transform.slice(0, row.style.transform.length - 2) - 400 + 'px'
2867        cellTime.style.transform = cellTime.style.transform.slice(0, cellTime.style.transform.length - 2) - 400 + 'px'
2868        window.requestAnimationFrame(updateRowFixedTop)
2869      } else {
2870        row.style.transform = ''
2871        cellTime.style.transform = ''
2872      }
2873    }
2874  }
2875
2876  function updateRowFixedTop () {
2877    row.style.transform = 'translateY(' + (offsetHeader - table.getBoundingClientRect().top) + 'px' + ')'
2878    cellTime.style.transform = 'translateY(' + (offsetHeader - table.getBoundingClientRect().top) + 'px' + ')'
2879  }
2880
2881  toggleBottom.addEventListener('click', toggleTable)
2882  toggleTop?.addEventListener('click', toggleTable)
2883  toggleBottom.addEventListener('click', scrollToTable)
2884
2885
2886
2887  function toggleTable () {
2888    if (table.classList.contains('hide')) {
2889      showTable()
2890      programStretch?.classList.add('program-stretch_active')
2891    } else {
2892      hideTable()
2893      programStretch?.classList.remove('program-stretch_active')
2894    }
2895  }
2896
2897  function scrollToTable () {
2898    const y = scheduleFamily.getBoundingClientRect().top + window.scrollY - 100
2899    window.scrollTo({top: y, behavior: 'smooth'})
2900  }
2901
2902  function hideTable () {
2903    table.classList.add('hide')
2904    toggleBottom.classList.add('reverse')
2905    toggleTop.classList.add('reverse')
2906     if (!isSummer) {
2907       toggleBottom.innerHTML = "Показать расписание"
2908       toggleTop.innerHTML = "Показать расписание"
2909   } else {
2910       toggleBottom.innerHTML = "Расписание на май"
2911       toggleTop.innerHTML = "Расписание на май"
2912     }
2913     toggleBottom.classList.add('hide')
2914  }
2915
2916  function showTable () {
2917    table.classList.remove('hide')
2918    toggleBottom.classList.remove('reverse')
2919    toggleTop.classList.remove('reverse')
2920     toggleBottom.innerHTML = "Свернуть расписание"
2921     toggleTop.innerHTML = "Свернуть расписание"
2922     toggleBottom.classList.remove('hide')
2923    row.style.transform = 'none'
2924    cellTime.style.transform = 'none'
2925    setTimeout(() => tableFixedCalculate(), 100)
2926  }
2927}
2928
2929const familyTeachersSlider = document.querySelector('.family-teachers__slider')
2930
2931if (familyTeachersSlider) familyTeachersSliderInit()
2932
2933function familyTeachersSliderInit () {
2934  let swiper
2935   if (window.innerWidth >= 744) {
2936     swiper = new Swiper(familyTeachersSlider, {
2937      mousewheel: { forceToAxis: true },
2938      slidesPerView: 'auto',
2939      autoHeight: true,
2940      spaceBetween: 500,
2941      effect: 'fade',
2942      fadeEffect: {
2943        crossFade: true
2944      },
2945      a11y: false,
2946      pagination: {
2947        el: '.family-teachers__pagination',
2948        clickable: true,
2949      },
2950      breakpoints: {
2951         744: {
2952           effect: 'fade',
2953           navigation: {
2954             nextEl: '.family-teachers__nav-btn_next',
2955             prevEl: '.family-teachers__nav-btn_prev',
2956           },
2957           scrollbar: {
2958             el: '.family-teachers__scrollbar',
2959             draggable: true,
2960           },
2961         }
2962       }
2963     })
2964   } else {
2965     swiper = new Swiper(familyTeachersSlider, {
2966       slidesPerView: 'auto',
2967       autoHeight: true,
2968       spaceBetween: 200,
2969       fadeEffect: {
2970         crossFade: true
2971       },
2972       a11y: false,
2973       pagination: {
2974         el: '.family-teachers__pagination',
2975         clickable: true,
2976       },
2977       breakpoints: {
2978         744: {
2979           effect: 'fade',
2980           navigation: {
2981            nextEl: '.family-teachers__nav-btn_next',
2982            prevEl: '.family-teachers__nav-btn_prev',
2983          },
2984          scrollbar: {
2985            el: '.family-teachers__scrollbar',
2986            draggable: true,
2987          },
2988        }
2989      }
2990    })
2991   }
2992 
2993   const isTrialPage = familyTeachersSlider.closest('.family-teachers.trial-lessons')
2994   const boxes = familyTeachersSlider.querySelectorAll('.family-teachers__box')
2995 
2996   for (let i = 0; i < boxes.length; i++) {
2997     const list = boxes[i].querySelector('.family-teachers__list')
2998     if (isTrialPage && window.innerWidth >= 1440) {
2999       if (list.clientHeight > 250) moreBtnInit(boxes[i])
3000     } else {
3001       if (list.clientHeight > 150) moreBtnInit(boxes[i])
3002     }
3003
3004   }
3005 
3006   function moreBtnInit (box) {
3007     box.classList.add('hide')
3008     const btn = box.querySelector('.family-teachers__more')
3009     btn.classList.add('active')
3010     btn.addEventListener('click', toggleBox)
3011 
3012     function toggleBox () {
3013       if (box.classList.contains('hide')) {
3014         box.classList.remove('hide')
3015         btn.innerHTML = 'Свернуть'
3016       } else {
3017         box.classList.add('hide')
3018         btn.innerHTML = 'Показать полностью'
3019       }
3020       swiper.update()
3021     }
3022   }
3023 }
3024
3025function fancyboxAjaxCardsReInit (node) {
3026  if (node && typeof node.querySelectorAll === 'function') {
3027    const fancyboxItems = node.querySelectorAll('[data-fancybox]')
3028    if (fancyboxItems.length) {
3029      fancyboxItems.forEach((item) => {
3030        if (!$.data(item, 'fancybox')) {
3031          $(item).fancybox({
3032            beforeShow: function (instance) {
3033              try {
3034                const form = document.querySelector(this.src)
3035                const openButton = instance.current.opts.$orig
3036                if (form) {
3037                  setDataFtitle(openButton, form)
3038                  setBannerName(openButton, form)
3039                }
3040              } catch (e) {
3041              }
3042            },
3043            afterClose: function () {
3044              try {
3045                const form = document.querySelector(this.src)
3046                if (form) {
3047                  setDefaultDataFtitle(form)
3048                  setDefaultBannerName(form)
3049                }
3050              } catch (e) {
3051
3052              }
3053            }
3054          })
3055        }
3056      })
3057    }
3058  }
3059}
3060
3061
3062const faqAllBg = document.querySelectorAll('.faq-all__bg')
3063
3064if (faqAllBg.length) {
3065  setFaqAllBgWidth()
3066
3067  window.addEventListener('resize', setFaqAllBgWidth, { passive: true })
3068
3069  function setFaqAllBgWidth() {
3070    for (let i = 0; i < faqAllBg.length; i++) {
3071      faqAllBg[i].style.width = `${document.documentElement.clientWidth - 1}px`
3072    }
3073  }
3074}
3075
3076const faqAllSidebarDesc = document.querySelector('.faq-all__sidebar_desc')
3077
3078if (faqAllSidebarDesc) faqAllSidebarDescInit()
3079
3080function faqAllSidebarDescInit () {
3081  const faqAllLinkArray = faqAllSidebarDesc.querySelectorAll('.faq-all__link')
3082  const faqAllTitleArray = document.querySelectorAll('.faq-all__title')
3083
3084  window.addEventListener('scroll', checkScroll, { passive: true })
3085
3086  function checkScroll () {
3087    for (let i = faqAllTitleArray.length - 1; i > -1; i--) {
3088      if (faqAllTitleArray[i].getBoundingClientRect().top < 300) {
3089        removeOldLinkActive()
3090        faqAllLinkArray[i].classList.add('active')
3091        break
3092      } else {
3093        faqAllLinkArray[i].classList.remove('active')
3094      }
3095    }
3096  }
3097
3098  function removeOldLinkActive () {
3099    const oldActive = faqAllSidebarDesc.querySelector('.faq-all__link.active')
3100    if (oldActive) oldActive.classList.remove('active')
3101  }
3102}
3103
3104const faqAllSidebarMob = document.querySelector('.faq-all__sidebar_mob')
3105
3106if (faqAllSidebarMob) faqAllSidebarMobInit()
3107
3108function faqAllSidebarMobInit () {
3109  const name = faqAllSidebarMob.querySelector('.faq-all__name')
3110  const layer = faqAllSidebarMob.querySelector('.faq-all__layer')
3111
3112  let scrollDown = true
3113  let lastScrollTop = 0
3114
3115  window.addEventListener('scroll', checkScrollDirection, { passive: true })
3116
3117  function checkScrollDirection () {
3118    const st = window.scrollY
3119    if (st - lastScrollTop > 7) {
3120      scrollDown = true
3121    } else if (st - lastScrollTop < -7) {
3122      scrollDown = false
3123    }
3124    lastScrollTop = st <= 0 ? 0 : st
3125    if (scrollDown) {
3126      faqAllSidebarMob.classList.remove('fixed')
3127    } else {
3128      faqAllSidebarMob.classList.add('fixed')
3129    }
3130  }
3131
3132  name.addEventListener('click', toggleSidebar)
3133  layer.addEventListener('click', closeSidebar)
3134
3135  function toggleSidebar () {
3136    if (name.classList.contains('active')) {
3137      closeSidebar()
3138    } else {
3139      window.removeEventListener('scroll', checkScrollDirection)
3140      name.classList.add('active')
3141    }
3142  }
3143
3144  function closeSidebar () {
3145    name.classList.remove('active')
3146    window.addEventListener('scroll', checkScrollDirection, {passive: true})
3147  }
3148
3149  const articleLinkArray = faqAllSidebarMob.querySelectorAll('.faq-all__link')
3150
3151  for (let i = 0; i < articleLinkArray.length; i++) {
3152    articleLinkArray[i].addEventListener('click', toggleLinkActive)
3153  }
3154
3155  function toggleLinkActive () {
3156    const oldActive = faqAllSidebarMob.querySelector('.faq-all__link.active')
3157    if (oldActive) oldActive.classList.remove('active')
3158    this.classList.add('active')
3159    name.classList.remove('active')
3160    window.addEventListener('scroll', checkScrollDirection, {passive: true})
3161  }
3162}
3163
3164const faqItems = document.querySelectorAll("[data-element='faq-item']")
3165
3166for (let i = 0; i < faqItems.length; i++) {
3167  faqItems[i].addEventListener("click", toggleFaqItem)
3168
3169  function toggleFaqItem () {
3170    this.classList.toggle('active')
3171  }
3172}
3173
3174const filterBlock = document.querySelector('[data-element="filter-block"]')
3175
3176if (filterBlock) filterBlockInit()
3177
3178function filterBlockInit () {
3179  const requestFunctionName = filterBlock.getAttribute('data-request-function')
3180  const filtered_elements = filterBlock.querySelector('.filtered_elements')
3181  const filterSumr = filterBlock.querySelector('[data-role="filter-sumr"]')
3182  const filterNewy = filterBlock.querySelector('[data-role="filter-newy"]')
3183  const subjectInputs = filterBlock.querySelectorAll('.langs-tile__filter-input_subject')
3184  const config = { attributes: false, childList: true, characterData: false, subtree: true }
3185
3186  const body = document.querySelector('body')
3187  let isTileInit = false
3188
3189  const observer = new MutationObserver(function (mutationRecords) {
3190    for (const mutation of mutationRecords) {
3191      if (
3192        mutation.target.closest('.tile__subject') ||
3193        mutation.target.closest('.fam-price__more') ||
3194        mutation.target.closest('.tile__tileb') ||
3195        mutation.target.closest('.it-tile__pagination') ||
3196        mutation.target.closest('.all-courses__more') ||
3197        mutation.target.closest('.tile__more') ||
3198        mutation.addedNodes[0]?.id === 'ignore-me'
3199      ) {
3200        continue
3201      }
3202
3203      mutation.addedNodes.forEach((node) => {
3204        if (
3205          node?.classList?.contains('all-courses__item') ||
3206          node?.classList?.contains('tile__item')
3207        ) {
3208          dataHrefLinksInit(node)
3209          togglePrice(node)
3210          initCommonAnalytics(node)
3211        } else if (node && typeof node.querySelectorAll === 'function') {
3212          const nodes = node.querySelectorAll('.tile__item, .fam-price__slide')
3213
3214          nodes.forEach((node) => {
3215            dataHrefLinksInit(node)
3216            initCommonAnalytics(node)
3217          })
3218        }
3219
3220        fancyboxAjaxCardsReInit(node)
3221      })
3222
3223      moreBtnInit()
3224      tmore_bInit()
3225
3226      if (filterBlock.classList.contains('tile') && !isTileInit) {
3227        isTileInit = true
3228        tileInit(filterBlock)
3229      }
3230
3231      if (filterBlock.classList.contains('fam-price')) {
3232        famPriceInit(filterBlock)
3233      }
3234    }
3235  })
3236
3237  window.addEventListener('click', (e) => {
3238    closeSubjectFilter()
3239  })
3240  
3241  const tileSubject = document.querySelector('[data-element="tile__subject"]')
3242  const tileSubjectContent = document.querySelector('[data-element="tile__subject-content"]')
3243  const tileSubjectInputs = document.querySelectorAll('[data-element="tile__subject-input"]')
3244  const tileSubjectScroller = document.querySelector('[data-element="tile__subject-scroller"]')
3245  const tileSubjectBox = document.querySelector('[data-element="tile__subject-box"]')
3246  const tileSubjectCurrentReset = document.querySelector('[data-element="tile__subject-current-reset"]')
3247  const tileSubjectReset = document.querySelector('[data-element="tile__subject-reset"]')
3248  const tileSubjectButton = document.querySelector('.tile__subject-button')
3249  const tileSubjectCurrent = document.querySelector('[data-element="tile__subject-current"]')
3250  const tileSubjectCurrentValueSpan = document.querySelector('[data-element="tile__subject-current-value-span"]')
3251
3252  if (tileSubjectButton) tileSubjectButton.addEventListener('click', closeSubjectFilter)
3253
3254  if (tileSubjectReset) tileSubjectCurrentReset.addEventListener('click', resetSubjectFilter)
3255  if (tileSubjectCurrent && tileSubjectReset) tileSubjectReset.addEventListener('click', resetSubjectFilter)
3256
3257  if (tileSubjectScroller && tileSubjectBox) tileSubjectScrollerInit()
3258  if (tileSubject) tileSubjectInit()
3259
3260
3261
3262  if (filtered_elements) observer.observe(filtered_elements, config)
3263
3264  moreBtnInit()
3265  tmore_bInit()
3266  togglePrice()
3267  if (filterBlock.classList.contains('tile')) tileInit(filterBlock)
3268  if (filterBlock.classList.contains('fam-price')) famPriceInit(filterBlock)
3269
3270  filterSumr?.addEventListener('change', () => makeFiltration(1))
3271  filterNewy?.addEventListener('change', () => makeFiltration(1))
3272
3273  for (let i = 0; i < subjectInputs.length; i++) {
3274    subjectInputs[i].addEventListener('change', () => makeFiltration(1))
3275  }
3276
3277  if (tileSubjectContent) swipeTileSubjectContent()
3278
3279  function swipeTileSubjectContent () {
3280    let startY = 0
3281    let currentY = 0
3282    let isSwiping = false
3283
3284    const TRIGGER_THRESHOLD = 150
3285
3286    tileSubjectContent.addEventListener('touchstart', (e) => {
3287      if (e.target.closest('.tile__subject-box')) {
3288        isSwiping = false
3289        return
3290      }
3291
3292      startY = e.touches[0].clientY
3293      currentY = startY
3294      isSwiping = true
3295
3296      tileSubjectContent.style.transition = 'none'
3297    })
3298
3299    tileSubjectContent.addEventListener('touchmove', (e) => {
3300      if (!isSwiping) return
3301
3302      currentY = e.touches[0].clientY
3303      const diffY = currentY - startY
3304
3305      if (diffY > 0) {
3306        tileSubjectContent.style.transform = `translateY(${diffY}px)`
3307      }
3308    })
3309
3310    tileSubjectContent.addEventListener('touchend', () => {
3311      if (!isSwiping) return
3312
3313      isSwiping = false
3314
3315      const diffY = currentY - startY
3316
3317      tileSubjectContent.style.transition = 'transform 0.3s ease-out'
3318
3319      if (diffY > TRIGGER_THRESHOLD) {
3320        tileSubjectContent.style.transform = 'translateY(100%)'
3321
3322        setTimeout(() => {
3323          closeSubjectFilter()
3324          tileSubjectContent.style.transform = 'translateY(0)'
3325        }, 300)
3326      } else {
3327        tileSubjectContent.style.transform = 'translateY(0)'
3328      }
3329
3330      startY = 0
3331      currentY = 0
3332    })
3333  }
3334
3335  function tileSubjectScrollerInit () {
3336    const topMarker = document.createElement('div')
3337    topMarker.style.width = '100%'
3338    const bottomMarker = document.createElement('div')
3339    bottomMarker.style.width = '100%'
3340
3341    tileSubjectBox.prepend(topMarker)
3342    tileSubjectBox.append(bottomMarker)
3343
3344    const tileSubjectBoxObserver = new IntersectionObserver((entries) => {
3345      entries.forEach(entry => {
3346        const isTop = entry.target === topMarker
3347        if (isTop) {
3348          tileSubjectScroller.classList.toggle('tile__subject-scroller_top-shadow', !entry.isIntersecting)
3349        } else {
3350          tileSubjectScroller.classList.toggle('tile__subject-scroller_bottom-shadow', !entry.isIntersecting)
3351        }
3352      })
3353    }, {
3354      root: tileSubjectBox,
3355      threshold: 1.0
3356    })
3357
3358    tileSubjectBoxObserver.observe(topMarker)
3359    tileSubjectBoxObserver.observe(bottomMarker)
3360  }
3361
3362
3363
3364  function makeFiltration (p_paginate = 1) {
3365    let subjects_result = getLangSubjectResult()
3366    let utm_f = filtered_elements.getAttribute('data-utm')
3367    let promo_f = filtered_elements.getAttribute('data-promo')
3368    let data_direction = filtered_elements.getAttribute('data-direction')
3369    let grd = filterSumr?.getAttribute('data-grd')
3370    let oge_ege_type = filtered_elements.getAttribute('data-oge-ege');
3371
3372    if(p_paginate === 1 ){
3373      $('.filtered_elements').html("<div class='tile-loader'></div>");
3374      $('.more_b').html("");
3375    }
3376
3377    var obData = {
3378      'utm_t': utm_f,
3379      'promo': promo_f,
3380      'pagePaginate': p_paginate,
3381      'summerny': getSummerny(),
3382    }
3383
3384    if (data_direction) obData['direction'] = data_direction
3385    if (grd) obData['grade'] = grd
3386    if (oge_ege_type) obData['teacher'] = oge_ege_type
3387    if (subjects_result) obData['subject'] = subjects_result
3388
3389
3390    console.log(obData)
3391
3392    $.request(requestFunctionName, {
3393      data: obData
3394    })
3395  }
3396
3397  function getSummerny () {
3398    let summerny = ''
3399    if (filterSumr?.checked) {
3400      summerny = filterSumr.getAttribute('data-value')
3401    } else if (filterNewy?.checked) {
3402      summerny = filterNewy.getAttribute('data-value')
3403    }
3404    return summerny
3405  }
3406
3407  function getLangSubjectResult () {
3408    let subjects_result = ''
3409    try{
3410      const subjects_items = document.querySelectorAll('.langs-tile__filter-input_subject:checked')
3411      subjects_items.forEach((item, i) => {
3412        if (i > 0) subjects_result += '|'
3413        subjects_result += item.value
3414      })
3415      return subjects_result
3416    }catch(e){}
3417  }
3418
3419
3420  function moreBtnInit () {
3421    const moreBtn = filterBlock.querySelector('[data-role="more-btn"]')
3422    if (moreBtn) {
3423      const newBtn = replaceBtn(moreBtn)
3424      newBtn.addEventListener('click', () => makeFiltration(newBtn.getAttribute('data-v')))
3425    }
3426  }
3427
3428  function replaceBtn (oldElement) {
3429    const newElement = oldElement.cloneNode(true)
3430    oldElement.parentNode.replaceChild(newElement, oldElement)
3431    return newElement
3432  }
3433
3434
3435  function tmore_bInit () {
3436    try {
3437      const moreBtns = document.querySelectorAll('.tmore_b')
3438      moreBtns.forEach(btn => {
3439        const newBtn = replaceBtn(btn)
3440        newBtn.addEventListener('click', () => request(newBtn))
3441      })
3442    } catch (error) {
3443    }
3444
3445
3446
3447  }
3448  function request (moreBtn) {
3449    var attr = moreBtn?.getAttribute('data-v') || 1
3450    var attr_g = filtered_elements.querySelector('[data-element="tile__tab-input"]:checked')?.getAttribute('data-g') || ''
3451    var attr_s = filtered_elements.querySelector('[data-element="tile__subject-input"]:checked')?.getAttribute('data-s') || ''
3452    var attr_utm = filtered_elements.getAttribute('data-utm')
3453    // console.log('attr: ', attr, 'attr_g: ', attr_g, 'attr_s: ', attr_s, 'attr_utm: ', attr_utm);
3454    $('.tile__tileb.active').html("<div class='tile-loader'></div>");
3455    if ((typeof attr !== 'undefined' && attr !== false) && (typeof attr_g !== 'undefined' && attr_g !== false)) {
3456      let summerny = ''
3457      if (filterSumr?.checked) {
3458        summerny = filterSumr.getAttribute('data-value')
3459      } else if (filterNewy?.checked) {
3460        summerny = filterNewy.getAttribute('data-value')
3461      }
3462      $.request('MainFunctions::onPaginateSingleModel', {
3463        data: {
3464          'pagePaginate': attr,
3465          'grade': attr_g,
3466          'subject': attr_s,
3467          'utm_t': attr_utm,
3468          'summerny': summerny,
3469        }
3470      });
3471
3472    }
3473
3474  }
3475
3476  function tileSubjectInit () {
3477    if (tileSubjectCurrent) tileSubjectCurrent.addEventListener('click', toggleSubjectFilter)
3478
3479    tileSubjectInputs.forEach((input) => {
3480      input.addEventListener('change', updateFilter)
3481    })
3482
3483    function updateFilter () {
3484      tileSubjectCurrentValueSpan.innerHTML = this.getAttribute('data-text')
3485      tileSubjectCurrent.classList.add('value-selected')
3486      request()
3487    }
3488  }
3489
3490  function toggleSubjectFilter (e) {
3491    e.stopPropagation()
3492    this.classList.toggle('active')
3493    filtered_elements.classList.toggle('filtered_elements_z-index-max')
3494    body.classList.toggle('no-scroll-lg')
3495  }
3496
3497  function resetSubjectFilter (e) {
3498    e?.stopPropagation?.()
3499    tileSubjectCurrentValueSpan.innerHTML = tileSubjectCurrentValueSpan.getAttribute('data-default-text')
3500    tileSubjectCurrent.classList.remove('value-selected')
3501    const selectedSubject = document.querySelector('[data-element="tile__subject-input"]:checked')
3502    if (selectedSubject) selectedSubject.checked = false
3503    request()
3504  }
3505
3506  function closeSubjectFilter () {
3507    const tileSubjectCurrent = document.querySelector('[data-element="tile__subject-current"]')
3508    if (tileSubjectCurrent) tileSubjectCurrent.classList.remove('active')
3509    filtered_elements.classList.remove('filtered_elements_z-index-max')
3510    body.classList.remove('no-scroll-lg')
3511  }
3512
3513  function tileInit (tile) {
3514    const tileTabs = tile.querySelectorAll('[data-element="tile__tab-input"]')
3515    const tiles = tile.querySelectorAll('.tile__tile')
3516    const tileCounters = tile.querySelectorAll('.tile__nav-counter')
3517    const btnMoreArray = tile.querySelectorAll('.tile__tileb')
3518
3519    const tabs = tile.querySelectorAll('.tile__subject-tab')
3520    const headline = tile.querySelector('.tile__subject-headline')
3521    const subjectInputs = tile.querySelectorAll('.tile__subject-input')
3522
3523    let timeout
3524    let firstToggle = true
3525
3526    tabs.forEach((tab) => {
3527      tab.addEventListener('click', changeTab)
3528      tab.addEventListener('mouseenter', changeTab)
3529    })
3530
3531    const activeTab = tile.querySelector('.tile__subject-tab.active')
3532    if (!activeTab) {
3533      const firstNotHideTab = tile.querySelector('.tile__subject-tab:not(.hide)')
3534      if (firstNotHideTab) firstNotHideTab.click()
3535    }
3536
3537    function changeTab (e) {
3538      e.stopPropagation()
3539      clearTimeout(timeout)
3540      timeout = setTimeout(() => toggle(this),100)
3541
3542      function toggle (that) {
3543        if (!that.closest('.tile__subject-inner')?.querySelector('.tile__subject-tab:hover') && !firstToggle && e.type !== 'click') return
3544        firstToggle = false
3545        const oldTab = tile.querySelector('.tile__subject-tab.active')
3546        if (oldTab) oldTab.classList.remove('active')
3547
3548        that.classList.add('active')
3549        headline.innerHTML = that.getAttribute('data-text')
3550
3551        const subjectIndexes = getParsedData(that, 'data-index')
3552
3553        subjectInputs.forEach((subjectInput) => {
3554          const inputValues = subjectInput.value.split('|')
3555          const isAllowed = subjectIndexes.some(val => inputValues.includes(val))
3556          console.log('inputValues - '+inputValues);
3557          console.log('subjectIndexes - '+subjectIndexes);
3558          console.log('isAllowed - '+isAllowed);
3559          if (isAllowed) {
3560            subjectInput.closest('.tile__subject-label').classList.remove('hide')
3561          } else {
3562            subjectInput.closest('.tile__subject-label').classList.add('hide')
3563          }
3564        })
3565      }
3566    }
3567
3568    tileTabs.forEach((tab) => {
3569      tab.addEventListener('change', toggleTab)
3570    })
3571
3572    function toggleTab () {
3573      const oldBtnMore = filtered_elements.querySelector('.tile__tileb.active')
3574      if (oldBtnMore) oldBtnMore.classList.remove('active')
3575
3576      const oldActiveTile = filtered_elements.querySelector('.tile__tile.active')
3577      if (oldActiveTile) oldActiveTile.classList.remove('active')
3578      
3579      const oldActiveTileCounter = filtered_elements.querySelector('.tile__nav-counter.active')
3580      if (oldActiveTileCounter) oldActiveTileCounter.classList.remove('active')
3581
3582      const id = this.value
3583      tiles[id].classList.add('active')
3584      tileCounters[id].classList.add('active')
3585      btnMoreArray[id].classList.add('active')
3586      syncTileTabs(id)
3587      sortSubjects(this)
3588      sortSubjectsTabs()
3589      resetSubjectFilter()
3590    }
3591
3592    function getParsedData (element, attribute) {
3593      if (!element) return []
3594      try {
3595        const data = element.getAttribute(attribute)
3596        return data ? JSON.parse(data) : []
3597      } catch (e) {
3598        console.error(`Ошибка парсинга JSON в атрибуте ${attribute}:`, e)
3599        return []
3600      }
3601    }
3602
3603    function sortSubjectsTabs () {
3604      tabs.forEach((tab) => {
3605        const indexes = getParsedData(tab, 'data-index')
3606        let counter = 0
3607        tileSubjectInputs.forEach(input => {
3608          const inputValues = input.value.split('|')
3609          const isAllowed = inputValues.some(val => indexes.includes(val))
3610          if (isAllowed && !input.closest('.tile__subject-label')?.classList.contains('disabled')) counter += 1
3611        })
3612        const counterSpan = tab.querySelector('span')
3613        counterSpan.innerHTML = counter
3614        if (counterSpan) counterSpan.innerHTML = counter
3615        if (counter === 0) {
3616          tab.classList.add('hide')
3617        } else {
3618          tab.classList.remove('hide')
3619        }
3620      })
3621      const activeTab = tile.querySelector('.tile__subject-tab.active')
3622      if (activeTab) {
3623        if (activeTab.classList.contains('hide')) {
3624          activeTab.classList.remove('active')
3625          const firstNotHideTab = tile.querySelector('.tile__subject-tab:not(.hide)')
3626          if (firstNotHideTab) firstNotHideTab.click()
3627        }
3628      }
3629    }
3630
3631    function sortSubjects (tab) {
3632      const subjects = getParsedData(tab, 'data-subjects')
3633      const allowedStrings = subjects.map(String)
3634      tileSubjectInputs.forEach(input => {
3635        const parent = input.closest('.tile__subject-label')
3636        if (!parent) return
3637        const inputValues = input.value.split('|')
3638        const isAllowed = inputValues.some(val => allowedStrings.includes(val))
3639        parent.classList.toggle('disabled', !isAllowed)
3640      })
3641    }
3642
3643    function syncTileTabs(id) {
3644      tileTabs.forEach((tab) => {
3645        if (tab.value === id) {
3646          tab.checked = true
3647          tab.setAttribute('checked', true)
3648        }
3649      })
3650    }
3651  }
3652
3653
3654  
3655  function togglePrice (node) {
3656    if (node) {
3657      togglePriceHandler(node)
3658    } else {
3659      const items = filtered_elements?.querySelectorAll(".all-courses__item")
3660      items.forEach((item) => {
3661        togglePriceHandler(item)
3662      })
3663    }
3664    function togglePriceHandler (item) {
3665      const toggle = item.querySelectorAll('.all-courses__radio-input')
3666      if (!toggle.length) return
3667      const boxes = item.querySelectorAll('.all-courses__box')
3668      const textReplace = item.querySelector('.all-courses__info.text-replace')
3669      let texts
3670      if (textReplace) {
3671        texts = textReplace.querySelectorAll('.all-courses__info-span')
3672      }
3673      for (let i = 0; i < toggle.length; i++) {
3674        toggle[i].addEventListener('change', toggleBoxes)
3675        if (texts) toggle[i].addEventListener('change', toggleTexts)
3676      }
3677
3678      function toggleBoxes () {
3679        for (let i = 0; i < boxes.length; i++) {
3680          if (boxes[i].classList.contains('hide')) {
3681            boxes[i].classList.remove('hide')
3682          } else {
3683            boxes[i].classList.add('hide')
3684          }
3685        }
3686      }
3687
3688      function toggleTexts () {
3689        for (let i = 0; i < texts.length; i++) {
3690          if (texts[i].classList.contains('hide')) {
3691            texts[i].classList.remove('hide')
3692          } else {
3693            texts[i].classList.add('hide')
3694          }
3695        }
3696      }
3697    }
3698  }
3699
3700  function famPriceInit (famPrice) {
3701    const tabs = famPrice.querySelectorAll('.fam-price__tab')
3702    const slides = famPrice.querySelectorAll('.fam-price__slide')
3703
3704    for (let i = 0; i < tabs.length; i++) {
3705      tabs[i].addEventListener('click', toggleSlide)
3706    }
3707
3708    function toggleSlide () {
3709      const oldTabActive = famPrice.querySelector('.fam-price__tab.active')
3710      if (oldTabActive) oldTabActive.classList.remove('active')
3711      this.classList.add('active')
3712
3713      const oldActiveSlide = famPrice.querySelector('.fam-price__slide.active')
3714      if (oldActiveSlide) oldActiveSlide.classList.remove('active')
3715
3716      const newSlide = slides[this.getAttribute('data-id')]
3717      newSlide.classList.add('active')
3718    }
3719
3720    const famPriceLists = famPrice.querySelectorAll('.fam-price__list')
3721
3722    for (let i = 0; i < famPriceLists.length; i++) {
3723      const list = famPriceLists[i]
3724      const items = list.querySelectorAll('.fam-price__item')
3725      const btn = list.querySelector('.fam-price__more')
3726
3727      if (items.length > 8) {
3728        btn.style.display = 'flex'
3729        btn.addEventListener('click', toggleList)
3730        hideList()
3731      }
3732
3733      function hideList () {
3734        list.classList.remove('active')
3735        for (let j = items.length - 1; j > 7; j--) {
3736          items[j].style.display = 'none'
3737        }
3738        btn.innerHTML = `Показать ещё +${items.length - 8}`
3739      }
3740
3741      function showList () {
3742        list.classList.add('active')
3743        for (let j = items.length - 1; j > 7; j--) {
3744          items[j].style.display = 'flex'
3745        }
3746        btn.innerHTML = `Свернуть`
3747      }
3748
3749      function toggleList () {
3750        if (list.classList.contains('active')) {
3751          hideList()
3752        } else {
3753          showList()
3754        }
3755      }
3756    }
3757  }
3758
3759}
3760
3761
3762const footerNewDoc = document.querySelector('[data-element="footer-new-doc"]')
3763
3764if (footerNewDoc) footerNewDocInit()
3765
3766function footerNewDocInit () {
3767  footerNewDoc.addEventListener('click', () => footerNewDoc.classList.toggle('active'))
3768}
3769
3770const footerQuizDocsSpan = document.querySelector('.footer-quiz__docs-span');
3771
3772if (footerQuizDocsSpan) footerQuizDocsSpanInit()
3773
3774function footerQuizDocsSpanInit () {
3775  footerQuizDocsSpan.addEventListener('click', () => {
3776    footerQuizDocsSpan.classList.toggle('footer-quiz__docs-span_active');
3777  })
3778}
3779
3780const footerTitleArray = document.querySelectorAll('[data-element="footer__title"]')
3781
3782if (footerTitleArray.length) footerTitleArrayInit()
3783
3784function footerTitleArrayInit () {
3785  for (let i = 0; i < footerTitleArray.length; i++) {
3786    footerTitleArray[i].addEventListener('click', toggleFooterTitle)
3787  }
3788
3789  function toggleFooterTitle () {
3790    this.classList.toggle('active')
3791  }
3792}
3793
3794const FORM_MAP = {
3795  'external-form':           ['externalFormData'],
3796  'phone-form':              ['phoneFormData'],
3797  'review-form':             ['reviewFormData'],
3798  'family-order-form':       ['consultFormData'],
3799  'order-form':              ['orderFormData'],
3800  'order-form-email':        ['orderFormEmailData'],
3801  'order-form-teacher':      ['orderFormTeacherData'],
3802  'trial':                   ['trialFormData'],
3803  'blog-phone':              ['blogPhoneFormData'],
3804  'blog-email':              ['blogEmailFormData'],
3805  'blog-phone-email':        ['blogPhoneEmailFormData'],
3806  'newsletter':              ['newsletterFormData'],
3807  'pre-cap__form':           ['preFormData'],
3808  'pre-reg__form':           ['preFormData'],
3809  'pre-webinar-cap__form':   ['preWebinarFormData'],
3810  'library-popup':           ['libraryPopupFormData'],
3811  'newsletter-off-form':     ['newsletterOffForm'],
3812  'trial-lessons':           ['trialLessons'],
3813  'lib-access':              ['libAccess'],
3814  'college_new_cap__form':   ['collegeNewFormData'],
3815  'college-land-order__form':['collegeLandOrderForm'],
3816  'ege-cap__form_college-ai':['egeCapFormCollegeAi'],
3817  'ege-cap__form_vacancy-cap':['egeCapFormVacancyCap'],
3818  'try-free-popup-order':     ['tryFreePopupOrder'],
3819}
3820
3821
3822function getType(elementName) {
3823  return FORM_MAP[elementName] || null
3824}
3825
3826Object.keys(FORM_MAP).forEach((elementName) => {
3827  const pair = getType(elementName)
3828  if (!pair) return
3829  const [dataType] = pair
3830  document.querySelectorAll(`[data-element="${elementName}"]`).forEach((el) => globalFormInit(el, dataType))
3831})
3832
3833window.captchaWidget = null
3834let captchaPassed = false
3835
3836//   console.log('📍 Инициализация капчи...');
3837// try {
3838//   window.captchaWidget = window.smartCaptcha.render('captcha-container', {
3839//     sitekey: 'ysc1_y2y3Y8WvF9G06BcBNlGlgx4nfWsr2ms4kPjqJ0ite8d30716', // <- проверьте ключ!
3840//     invisible: true,
3841//     callback: (token) => {
3842//       console.log('✅ Callback капчи вызван с токеном:', token)
3843//       captchaToken = token
3844//       captchaPassed = true
3845//     }
3846//   });
3847// } catch (e) {
3848
3849// }
3850//   console.log('📍 Виджет создан:', window.captchaWidget);
3851
3852
3853async function sendGlobalFormCommonAnalytics (globalForm) {
3854  const goal = globalForm.getAttribute('data-form-goal');
3855  if (goal) {
3856    const dataFormType = globalForm.getAttribute('data-form');
3857    await analytics.ym(goal, { [goal] : dataFormType })
3858  } else {
3859    await sendCommonAnalytics('submit_form', globalForm)
3860  }
3861}
3862
3863
3864   
3865function globalFormInit (form, type) {
3866    
3867
3868  const globalForm = form
3869  const btnSubmit = globalForm.querySelector('.btn-warning')
3870  const selectPlaceholder = globalForm.querySelector('.modal-order-new__select-placeholder')
3871  const input = globalForm.querySelector("[data-element='input-phone-intl']")
3872
3873  const classSelectTop = globalForm.querySelector('.modal-order-new__select-top')
3874  const inputHidden = globalForm.querySelector("[data-element='input-phone-hidden']")
3875  const linkTo = globalForm.getAttribute("data-docex")
3876
3877  const policy = form.querySelector('[name="policy"]')
3878  const utm_input = globalForm.querySelector('[name="utm"]')
3879
3880  const classSelectInputs = globalForm.querySelectorAll('.modal-order-new__select-input')
3881
3882  for (let i = 0; i < classSelectInputs.length; i++) {
3883    classSelectInputs[i].addEventListener('change', validate)
3884    classSelectInputs[i].addEventListener('change', () => {
3885      if (classSelectTop) classSelectTop.classList.remove('error')
3886    })
3887  }
3888
3889  let iti
3890  let data_phone_pattern_exists = false;
3891//   console.log(input)
3892  if (input) {
3893      if (input.hasAttribute('data-phone-pattern')) {
3894        data_phone_pattern_exists = true;
3895      }
3896      if(data_phone_pattern_exists){
3897            input.addEventListener('input', function () {
3898              let tempValue = input.value
3899              const cleanNumber = tempValue.replace(/[^+\d]/g, '')
3900              inputHidden.value = cleanNumber
3901              validate()
3902            })
3903      }else{
3904            iti = window.intlTelInput(input, {
3905              utilsScript: "../libs/intlTelInputWithUtils.min",
3906              initialCountry: 'ru',
3907              separateDialCode: true,
3908              strictMode: true
3909            })
3910
3911            input.addEventListener('input', function () {
3912              let tempValue = input.value
3913              inputHidden.value = input.value
3914              const cleanNumber = tempValue.replace(/[^+\d]/g, '')
3915              if (iti.selectedCountryData.dialCode === "7" && cleanNumber.length > 10) {
3916                inputHidden.value = cleanNumber.substring(cleanNumber.length - 10)
3917                input.value = cleanNumber.substring(cleanNumber.length - 10)
3918              }
3919              inputHidden.value = iti.selectedCountryData.dialCode + ' ' + inputHidden.value
3920              validate()
3921            })
3922      }
3923  }
3924
3925  function resetError () {
3926    if (input) input.classList.remove("error")
3927  }
3928  
3929  let inputSms
3930  let isSubmitting = false
3931
3932  const email = globalForm.querySelector('[name="email"]')
3933  if (email) {
3934    email.addEventListener('input', () => validate)
3935    // email.addEventListener('change', () => validateEmail(email))
3936  }
3937
3938  const textarea = globalForm.querySelector('[name="content"]')
3939  if (textarea && textarea?.hasAttribute('data-required')) {
3940    textarea.addEventListener('input', validate)
3941    textarea.addEventListener('input', () => textarea.classList.remove('error'))
3942  }
3943
3944
3945  const name = globalForm.querySelector('[name="name"]')
3946  if (name) {
3947    name.addEventListener('input', validate)
3948    name.addEventListener('input', () => name.classList.remove('error'))
3949  }
3950
3951  if (policy) {
3952    policy.addEventListener('input', validate)
3953    policy.addEventListener('input', () => policy.closest('label').classList.remove('error-text'))
3954  }
3955
3956  function validate () {
3957    const isNameValid = name ? name?.value : true
3958    const isTextareaValid = (textarea && textarea?.hasAttribute('data-required')) ? textarea?.value : true
3959    const isPhoneValid = input ? iti?.isValidNumber() : true
3960    const isEmailValid = email ? validateEmail(email) : true
3961    const isPolicyValid = policy ? policy?.checked : true
3962    const isSelectValid = classSelectInputs.length ? globalForm.querySelector('.modal-order-new__select-input:checked') : true
3963    if (!isNameValid || !isEmailValid || !isSelectValid || !isPhoneValid || !isPolicyValid || !isTextareaValid) {
3964      btnSubmit.classList.add('btn-fake-disabled')
3965    } else {
3966      btnSubmit.classList.remove('btn-fake-disabled')
3967    }
3968  }
3969  
3970
3971  globalForm.addEventListener('submit', async (e) => {
3972    e.preventDefault()
3973    e.stopImmediatePropagation();
3974    
3975    const isToggleThanksBlock = globalForm.hasAttribute('data-toggle-thanks-block')
3976
3977    resetError()
3978
3979    let isValid = true
3980
3981    if (classSelectTop) {
3982      const isSelectChecked = globalForm.querySelector('.modal-order-new__select-input:checked')
3983      if (!isSelectChecked) {
3984        classSelectTop.classList.add('error')
3985        selectPlaceholder.innerHTML = 'Выберите класс'
3986        isValid = false
3987      }
3988    }
3989
3990    if (email) {
3991      if (!validateEmail(email)) {
3992        email.classList.add('error')
3993        if (!email.value) email.placeholder = 'Введите почту'
3994        isValid = false
3995      }
3996    }
3997
3998    if (name) {
3999      if (!name.value) {
4000        name.classList.add('error')
4001        name.placeholder = `Введите имя`
4002        isValid = false
4003      }
4004    }
4005
4006    if (textarea && textarea?.hasAttribute('data-required')) {
4007      if (!textarea.value) {
4008        textarea.classList.add('error')
4009        textarea.placeholder = `Введите вопрос`
4010        isValid = false
4011      }
4012    }
4013
4014
4015    if (input) {
4016      if (!iti?.isValidNumber()) {
4017        input.classList.add("error")
4018        if (input && !input?.value) input.placeholder = `Введите телефон`
4019      }
4020    }
4021
4022    if (!isValid) return
4023
4024    
4025    if (input && !input?.value?.trim()) {
4026      input.classList.add("error")
4027    } else if (iti?.isValidNumber() || !input || type == 'libraryPopupFormData' || type == 'blogPhoneFormData' || type == 'blogPhoneEmailFormData' || data_phone_pattern_exists) {
4028
4029      
4030
4031      inputSms = `<input class="modal-order-new__input modal-order-new__input_sms" required name="sms_code" type="text" placeholder="Введите код из смс">`
4032
4033      
4034        if (email) {
4035            email_value = email.value
4036        }
4037
4038        btnSubmit.disabled = true;
4039        const dataRequest = globalForm.getAttribute('data-request');
4040        if (type === 'preFormData') {
4041          e.stopPropagation()
4042          if (globalForm.classList.contains('predzaps-new-cap__form') || globalForm.classList.contains('predzaps-new-order__form') || globalForm.classList.contains('college_new__form')) {
4043            btnSubmit.classList.add('loading')
4044          }
4045          const loader = document.querySelector('.form-loader')
4046          if (loader) loader.classList.add('active')
4047          if (checkHoneypot()) return
4048          const formData = new FormData(globalForm)
4049            const formObject = {}
4050            formData.forEach((value, key) => {
4051              formObject[key] = value;
4052            })
4053          $.request('MainFunctions::' + dataRequest, {
4054            data: formObject,
4055            success: async function(response) {
4056
4057                let hasErrors = false
4058
4059                for (let key in response) {
4060                  if (key.startsWith('.')) {
4061                    const className = key.substring(1)
4062                    const element = document.querySelector('.' + className)
4063
4064                    if (element) {
4065                      element.innerHTML = response[key]
4066                      hasErrors = true;
4067                      btnSubmit.disabled = false;
4068                      if (globalForm.classList.contains('predzaps-new-cap__form') || globalForm.classList.contains('predzaps-new-order__form') || globalForm.classList.contains('college_new__form')) {
4069                          btnSubmit.classList.remove('loading')
4070                      }
4071                    }
4072                  }
4073                }
4074                if (hasErrors) {
4075                  isSubmitting = false
4076                  return
4077                }
4078                await sendGlobalFormCommonAnalytics(globalForm)
4079                
4080                const utmValue = utm_input ? utm_input.value.trim() : ''
4081                clearForm()
4082                const params = new URLSearchParams()
4083                params.set('cemail', email_value)
4084                const utmParams = new URLSearchParams(utmValue.replace(/^\?+/, ''))
4085                utmParams.forEach((value, key) => {
4086                    params.set(key, value)
4087                })
4088                const finalLink = linkTo + '?' + params.toString()
4089                location.assign(finalLink)
4090          },
4091          error: function(error) {
4092            // console.error('❌ Ошибка отправки:', error);
4093            isSubmitting = false
4094            return false
4095          }
4096        })
4097        return false
4098
4099          // setTimeout(() => {
4100          //     globalForm.submit();
4101          //     setTimeout(() => {
4102          //       clearForm();
4103          //         location.assign(linkTo + `?cemail=${email_value}`);
4104          //         // location.assign(linkTo + '?email='+email_value)
4105          //     }, 100)
4106          // }, 100)
4107        } else {
4108            let linkTo_ = linkTo;
4109            let linkTo_base = linkTo_
4110            if (utm_input) {
4111              utm_f = utm_input.value;
4112              if(utm_f != null && utm_f != '' && utm_f != undefined){
4113              }else{
4114                utm_f = ''
4115              }
4116              if (utm_f.length > 0) {
4117                linkTo_ = linkTo_ + utm_f;
4118              }
4119            }
4120            if (isTargetLink(linkTo_base)) {
4121              if (cookieParams) {
4122                linkTo_ += (linkTo_.includes("?") ? "&" : "?") + cookieParams;
4123              }
4124            }
4125
4126            if (checkHoneypot()) return
4127
4128            
4129
4130            try {
4131              e.stopPropagation();
4132              console.log('isSubmitting:', isSubmitting);
4133              if (isSubmitting) return false;
4134
4135            //   if (!captchaPassed) {
4136            //     // console.log('🔄 Вызов execute...');
4137                captchaToken = null;
4138            //     window.smartCaptcha.execute(window.captchaWidget);
4139
4140            //     await new Promise((resolve, reject) => {
4141            //       const checkToken = setInterval(() => {
4142            //         if (captchaToken) {
4143            //           clearInterval(checkToken);
4144            //           resolve();
4145            //         }
4146            //       }, 100);
4147
4148            //       setTimeout(() => {
4149            //         clearInterval(checkToken);
4150            //         reject(new Error('Таймаут капчи'));
4151            //       }, 100000);
4152            //     });
4153
4154            //     // console.log('✅ Токен получен:', captchaToken);
4155            //   } else {
4156            //     // console.log('✅ Капча уже пройдена, пропускаем проверку');
4157            //   }
4158                
4159
4160            //   if (captchaToken) {
4161                // console.log(globalForm);
4162                isSubmitting = true;
4163                //   console.log('Отправка формы:', globalForm);
4164
4165                const dataRequest = globalForm.getAttribute('data-request');
4166                const formData = new FormData(globalForm);
4167                const formObject = {};
4168                formData.forEach((value, key) => {
4169                  formObject[key] = value;
4170                });
4171                formObject['smart-token'] = captchaToken;
4172                const isResend = globalForm.querySelector('.form-enter-sms-resend.active')
4173                if (isResend) {
4174                  formObject['resend_sms'] = true
4175                  const timer = globalForm.querySelector('.form-enter-sms-resend')
4176                  timer.classList.remove('active')
4177                  timer.innerHTML = 'Получить новый код через <span>02:00</span>'
4178                } else {
4179                  const sms_code = globalForm.querySelector('input[name="sms_code"]')?.value
4180                  if (sms_code) formObject['sms_code'] = sms_code
4181                }
4182
4183                const callPhoneButton = globalForm.querySelector('[data-role="global-form-call-phone"]')
4184                if (callPhoneButton) formObject['already_call'] = true
4185
4186                //formObject.captcha_token = captchaToken;
4187
4188                clearErrorMessages(globalForm)
4189                $.request('MainFunctions::' + dataRequest, {
4190                  data: formObject,
4191                  success: async function(response) {
4192                    // console.log('Ответ:', response);
4193                    let hasErrors = false;
4194
4195                    for (let key in response) {
4196                      if (key.startsWith('.')) {
4197                        const className = key.substring(1);
4198                        const element = document.querySelector('.' + className);
4199
4200                        if (element) {
4201                          element.innerHTML = response[key];
4202                          hasErrors = true;
4203                          btnSubmit.disabled = false;
4204                          const isResendBlockReady = globalForm.querySelector('.form-enter-sms-resend.ready')
4205                          if (isResendBlockReady) {
4206                            isResendBlockReady.classList.add('active')
4207                          }
4208                        }
4209                      }
4210                    }
4211
4212                    if (hasErrors) {
4213                      isSubmitting = false;
4214                      return;
4215                    }
4216
4217                    if (response['requires_verification']) {
4218                      showSmsInput(response)
4219                      if (!globalForm.classList.contains('form-enter-sms-code')) showSmsInput(response)
4220                      btnSubmit.disabled = false
4221                      isSubmitting = false;
4222                    } else if (response['requires_phonecall_verification']) {
4223                      showFormPhoneCall(response)
4224                      btnSubmit.disabled = false
4225                      isSubmitting = false;
4226                    } else {
4227                      await sendGlobalFormCommonAnalytics(globalForm)
4228                      clearForm();
4229                      if (isToggleThanksBlock) {
4230                        globalForm.classList.add('global-form-thanks-state')
4231                      } else if (type === 'preFormData') {
4232                        location.assign(linkTo + `?cemail=${email_value}`);
4233                      } else if (type === 'collegeNewFormData' || type === 'collegeLandOrderForm') {
4234                        await analytics.ym('send-main-form')
4235                        await analytics.mailru('lead', true)
4236                        location.assign(linkTo_);
4237                      } else if (type === 'trialLessons') {
4238                          await analytics.gtag('generate_lead')
4239                          location.assign(linkTo_);
4240                      } else if (globalForm.id === 'fixAsk') {
4241                          if (window.tfPopups) window.tfPopups.close('fixAsk')
4242                          if (window.tfPopups) window.tfPopups.open('fixDone')
4243                      } else {
4244                        location.assign(linkTo_);
4245                      }
4246                    }
4247                  },
4248                  error: function(error) {
4249                    // console.error('❌ Ошибка отправки:', error);
4250                    isSubmitting = false;
4251                  }
4252                });
4253
4254                return false;
4255            //   }else{
4256            //     return false;
4257            //   }
4258
4259            } catch (error) {
4260              // console.error('❌ Ошибка:', error);
4261              // alert('Ошибка проверки капчи');
4262              return false;
4263            }
4264        }
4265
4266    } else {
4267      input.classList.add("error")
4268    }
4269
4270  })
4271
4272  function clearErrorMessages (form) {
4273    const v_message_block = form.querySelector('.v_message_block')
4274    if (!v_message_block) return
4275    v_message_block.innerHTML = ''
4276  }
4277
4278  function showFormPhoneCall (response) {
4279    globalForm.classList.add('form-enter-sms-code')
4280    const submitButton = globalForm.querySelector('.btn-warning') ||
4281      globalForm.querySelector('.btn-orange')
4282    if (submitButton) {
4283      submitButton.innerHTML = 'Уже позвонил'
4284      submitButton.classList.add('form-enter-sms-btn-transparent')
4285      submitButton.insertAdjacentHTML('beforebegin', `<div class="form-enter-sms-call">Пожалуйста, позвоните по этому бесплатному номеру для прохождения верификации!</div>`)
4286      submitButton.insertAdjacentHTML('beforebegin', `<a href="tel:${response['call_phone']}" class="modal-order-new__button btn-warning" data-role="global-form-call-phone" type="button">Позвонить</a>`)
4287      submitButton.insertAdjacentHTML('afterend', `<div class="form-enter-sms-note">Ожидаем звонок с номера <br> ${inputHidden.value}</div>`)
4288
4289    }
4290    const title = globalForm.querySelector('.modal-order-new__title') ||
4291      globalForm.querySelector('.ege-cap__title') ||
4292      globalForm.querySelector('.pre-cap__headline') ||
4293      globalForm.querySelector('[data-element="form-enter-sms-title"]')
4294    if (title) {
4295      title.innerHTML = `<a href="tel:${response['call_phone']}" class="form-enter-sms-phone">${response['call_phone_pretty']}</a>`
4296    }
4297  }
4298
4299  function showSmsInput () {
4300    if (globalForm.classList.contains('form-enter-sms-code')) return
4301    const title = globalForm.querySelector('.modal-order-new__title') ||
4302      globalForm.querySelector('.ege-cap__title') ||
4303      globalForm.querySelector('.pre-cap__headline') ||
4304      globalForm.querySelector('.ege-order__title') ||
4305      globalForm.querySelector('[data-element="form-enter-sms-title"]')
4306    if (title) {
4307      title.innerHTML = 'Введите код подтверждения'
4308    }
4309    const submitBtn = globalForm.querySelector('.btn-warning') ||
4310      globalForm.querySelector('.btn-orange')
4311    const formatPhone = formatPhoneNumber(inputHidden.value)
4312    submitBtn.insertAdjacentHTML('beforebegin', `<div class="form-enter-sms-text">Отправили код на номер <span>${formatPhone}</span></div>`)
4313    if (inputSms) submitBtn.insertAdjacentHTML('beforebegin', inputSms)
4314    submitBtn.insertAdjacentHTML('afterend', `<button type="button" class="form-enter-sms-resend">Получить новый код через <span>02:00</span></button>`)
4315    globalForm.classList.add('form-enter-sms-code')
4316    initResendSmsTimer()
4317  }
4318
4319  function formatPhoneNumber(value) {
4320    const trimmed = value.trim()
4321    const clean = trimmed.replace(/\D/g, '')
4322
4323    const isRussian = (
4324      clean.length === 11 &&
4325      (trimmed.startsWith('+7') || trimmed.startsWith('7') || trimmed.startsWith('8'))
4326    )
4327
4328    if (isRussian) {
4329      const match = clean.slice(-10).match(/^(\d{3})(\d{3})(\d{2})(\d{2})$/)
4330      if (match) {
4331        return `+7 (${match[1]}) ${match[2]}-${match[3]}-${match[4]}`
4332      }
4333    }
4334    return trimmed.startsWith('+') ? trimmed : '+' + trimmed
4335  }
4336
4337
4338  function initResendSmsTimer () {
4339    const timer = globalForm.querySelector('.form-enter-sms-resend')
4340    const timerSpan = globalForm.querySelector('.form-enter-sms-resend span')
4341    if (!timer || !timerSpan) return
4342
4343    let timeInSecs
4344    let ticker
4345
4346    timeInSecs = 2 * 60
4347    // timeInSecs = 4
4348    ticker = setInterval(tick, 1000)
4349
4350    function tick() {
4351      let secs = timeInSecs
4352      if (secs <= 0) {
4353        clearInterval(ticker)
4354        timer.classList.add('active')
4355        timer.classList.add('ready')
4356        timer.innerHTML = 'Получить новый код'
4357        timer.addEventListener('click', () => {
4358          const sms_code = globalForm.querySelector('input[name="sms_code"]')
4359          if (sms_code) sms_code.value = ''
4360          timer.innerHTML = 'Получить новый код через <span>02:00</span>'
4361          timer.classList.remove('ready')
4362          initResendSmsTimer()
4363          const submitEvent = new SubmitEvent("submit")
4364          globalForm.dispatchEvent(submitEvent)
4365        })
4366        return
4367      }
4368      timeInSecs--
4369
4370      let mins = Math.floor(secs / 60)
4371      secs %= 60
4372
4373      let displayMins = (mins < 10) ? "0" + mins : mins
4374      let displaySecs = (secs < 10) ? "0" + secs : secs
4375
4376      timerSpan.innerHTML = displayMins + ":" + displaySecs
4377    }
4378  }
4379
4380
4381  function clearForm () {
4382    const inputs = globalForm.querySelectorAll('input')
4383    for (let i = 0; i < inputs.length; i++) {
4384      inputs[i].value = ''
4385    }
4386  }
4387
4388  if (input) input.addEventListener('input', resetError)
4389
4390  function validateEmail (email) {
4391    return /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(email.value)
4392  }
4393  function checkHoneypot() {
4394    const honeypots = form.querySelector('.modal-exter__input')
4395    return honeypots && honeypots?.value
4396  }
4397}
4398
4399// Проверка, начинается ли ссылка с одного из целевых URL
4400function isTargetLink(href) {
4401  const targets = [
4402    "https://salebot.site/",
4403    "https://s.salebot.pro/",
4404    "https://sbsite.pro/",
4405    "https://r.bothelp.io/max",
4406    "https://vk.com/app7062840",
4407    "https://vk.ru/app7062840"
4408  ];
4409  return targets.some(prefix => href?.startsWith(prefix));
4410}
4411
4412// Собираем значения из нужных cookie
4413const cookies = ['_fbc', '_fbp', '_ga', '_ym_uid', 'roistat_visit'];
4414let cookieParams = '';
4415
4416cookies.forEach(name => {
4417  const value = getCookie(name);
4418  if (value) {
4419    if (cookieParams) cookieParams += '&';
4420    cookieParams += `${name}=${encodeURIComponent(value)}`;
4421  }
4422});
4423
4424// Функция для получения значения cookie по имени
4425function getCookie(name) {
4426  const matches = document.cookie.match(new RegExp(
4427    "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=\"?([^\";]*)\"?"
4428  ));
4429  return matches ? decodeURIComponent(matches[1]) : undefined;
4430}
4431
4432const urlParams = location.search.slice(1); // убираем '?'
4433
4434const buttonsModalGenerate = document.querySelectorAll('[data-modal-generate]')
4435
4436for (let i = 0; i < buttonsModalGenerate.length; i++) {
4437  buttonsModalGenerate[i].addEventListener('click', generateModal)
4438}
4439
4440function generateModal (e) {
4441  e.preventDefault()
4442  e.stopImmediatePropagation()
4443  const dataBlock = this.closest('[data-block]')?.getAttribute('data-block')
4444  const form = document.createElement('form')
4445  form.classList.add('modal-order-new')
4446  form.setAttribute('data-request-validate', '')
4447  form.id = 'modal-generated'
4448  form.setAttribute('autocomplete', 'off')
4449  if (dataBlock) form.setAttribute('data-block', dataBlock)
4450
4451  const dataFormType = this.getAttribute('data-form-type')
4452  form.setAttribute('data-form', dataFormType || 'order')
4453
4454  const dataFormGoal = this.getAttribute('data-form-goal')
4455  if (dataFormGoal) form.setAttribute('data-form-goal', dataFormGoal)
4456
4457
4458  const dataRequest = this.getAttribute('data-request')
4459  if (dataRequest) form.setAttribute('data-request', dataRequest)
4460
4461  const dataDocex = this.getAttribute('data-docex')
4462  if (dataDocex) form.setAttribute('data-docex', dataDocex)
4463
4464  const captcha = document.createElement('div')
4465  captcha.classList.add('captcha')
4466  form.appendChild(captcha)
4467
4468  const title = document.createElement('div')
4469  title.classList.add('modal-order-new__title')
4470  title.innerHTML = this.getAttribute('data-title-text')
4471  form.appendChild(title)
4472
4473  const dataText = this.getAttribute('data-text')
4474  if (dataText) {
4475    const text = document.createElement('p')
4476    text.classList.add('modal-order-new__text')
4477    text.innerHTML = dataText
4478    form.appendChild(text)
4479  }
4480
4481
4482  const dataHiddenInputs = this.getAttribute('data-hidden-inputs')
4483  const dataHiddenInputsParsed = dataHiddenInputs ? JSON.parse(dataHiddenInputs) : []
4484  for (let i = 0; i < dataHiddenInputsParsed.length; i++) {
4485    generateHiddenInput(form, dataHiddenInputsParsed[i].name, dataHiddenInputsParsed[i].value)
4486  }
4487
4488  const dataUtm = this.hasAttribute('data-utm')
4489  if (dataUtm) generateHiddenInput(form, 'utm', this.getAttribute('data-utm'))
4490
4491  const inputExter = `<input class="modal-exter__input"
4492    type="text"
4493    name="${this.getAttribute('data-random-name')}"
4494    style="${this.getAttribute('data-random-style')}"
4495    tabindex="-1"
4496    autocomplete="new-password"
4497    autocorrect="off"
4498    autocapitalize="off"
4499    spellcheck="false">
4500  `
4501  form.insertAdjacentHTML('beforeend', inputExter)
4502
4503  const isName = this.getAttribute('data-name')
4504  if (isName) {
4505    const nameHtml = `
4506      <input class="modal-order-new__input" name="name" placeholder="Имя" type="text">
4507    `
4508    form.insertAdjacentHTML('beforeend', nameHtml)
4509  }
4510
4511  const isPhone = this.getAttribute('data-phone')
4512  if (isPhone) {
4513    const phoneHtml = `
4514      <input class="modal-order-new__input" name="phone" placeholder="Номер телефона" type="tel" data-element="input-phone-intl">
4515      <input name="tel" type="hidden" required data-element="input-phone-hidden">
4516    `
4517    form.insertAdjacentHTML('beforeend', phoneHtml)
4518  }
4519
4520  const isEmail = this.getAttribute('data-email')
4521  if (isEmail) {
4522    const emailHtml = `<input class="modal-order-new__input" name="email" placeholder="E-mail" type="email">`
4523    form.insertAdjacentHTML('beforeend', emailHtml)
4524  }
4525
4526  const labels = `
4527    <label class="modal-order-new__checkbox">
4528      <input class="modal-order-new__checkbox-input" name="news" type="checkbox">
4529      <div class="modal-order-new__checkbox-view"></div>
4530      <div class="modal-order-new__checkbox-text">
4531        Даю
4532        <a href="${document.querySelector('body').getAttribute('data-news-agreement')}" data-redirect >Cогласие</a>
4533        на получение информационной и&nbsp;рекламной рассылки
4534      </div>
4535    </label>
4536    <label class="modal-order-new__checkbox">
4537      <input class="modal-order-new__checkbox-input" name="policy" type="checkbox">
4538      <div class="modal-order-new__checkbox-view"></div>
4539      <div class="modal-order-new__checkbox-text">
4540        Даю
4541        <a href="${document.querySelector('body').getAttribute('data-policy-agreement')}" data-redirect >Cогласие</a>
4542        на обработку персональных данных в соответствие с
4543        <a href="${document.querySelector('body').getAttribute('data-policy-policy')}" data-redirect >Политикой</a>
4544      </div>
4545    </label>
4546  `
4547  const button = `<button class="modal-order-new__button btn-warning btn-fake-disabled">${this.getAttribute('data-button-text')}</button>`
4548
4549  form.insertAdjacentHTML('beforeend', labels)
4550  form.insertAdjacentHTML('beforeend', button)
4551
4552  const v_counter = dataHiddenInputsParsed.find((input) => input.name === 'v')
4553  const v_counter_value = v_counter ? v_counter.value : ''
4554  form.insertAdjacentHTML('beforeend', `<div class="v_message_block v_messages${v_counter_value}"></div>`)
4555
4556
4557  const body = document.querySelector('body')
4558  body.appendChild(form)
4559
4560  const dataFormElement = this.getAttribute('data-form-element')
4561  globalFormInit(form, dataFormElement)
4562
4563  const dataRedirectLinks = form.querySelectorAll('[data-redirect]')
4564
4565  for (let i = 0; i < dataRedirectLinks.length; i++) {
4566    dataRedirectLinks[i].addEventListener('click', dataRedirect)
4567  }
4568
4569  function dataRedirect (e) {
4570    e.preventDefault()
4571    window.open(this.href, '_blank');
4572  }
4573
4574
4575  $.fancybox.open({
4576    src: '#modal-generated',
4577    opts: {
4578      touch: false,
4579      afterClose: function() {
4580        const node = document.getElementById('modal-generated')
4581        node.remove()
4582      }
4583    },
4584  })
4585}
4586
4587function generateHiddenInput (form, name, value) {
4588  const input = document.createElement('input')
4589  input.type = 'hidden'
4590  input.name = name
4591  input.value = value
4592  form.appendChild(input)
4593}
4594
4595
4596
4597const headerNew = document.querySelector('[data-element="header-new"]')
4598
4599if (headerNew) headerNewInit()
4600
4601function headerNewInit () {
4602  window.addEventListener('scroll', toggleHeader, {passive: true})
4603
4604  function toggleHeader () {
4605    if (window.scrollY > 0) {
4606      headerNew.classList.add('thin')
4607    } else {
4608      headerNew.classList.remove('thin')
4609    }
4610  }
4611}
4612
4613const header = document.querySelector('[data-element="header"]')
4614
4615if (header) headerInit()
4616
4617function headerInit () {
4618  const stickyHeader = document.querySelector('.sticky-header')
4619  const body = document.querySelector('body')
4620  const headerStages = document.querySelector('.header__stages')
4621    let lastScrollTop = 0
4622    let scrollDown = true
4623    const headerArea = header.querySelector('.header__area')
4624    const reviewsTileSidebar = document.querySelector('.reviews-tile__sidebar')
4625    const nav = header.querySelector('.nav')
4626    const navMenus = header.querySelectorAll('.nav__menu')
4627    const navBtns = header.querySelectorAll('.nav__btns')
4628    const familyScroller = header.querySelector('.nav__area_family .nav__scroller')
4629    const ed1Scroller = header.querySelector('.nav__area_ed1 .nav__scroller')
4630    const headerLayer = document.querySelector('.header-layer')
4631
4632  window.addEventListener('scroll', checkHeader, { passive: true })
4633  window.addEventListener('scroll', checkScrollDirection, { passive: true })
4634  window.addEventListener('resize', checkHeader, { passive: true })
4635
4636  checkHeader()
4637
4638  function checkHeader () {
4639    if (window.scrollY > 10) {
4640      header.classList.add('header_white')
4641      stickyHeader.classList.add('white')
4642    } else {
4643      header.classList.remove('header_white')
4644      stickyHeader.classList.remove('white')
4645    }
4646
4647
4648  }
4649
4650  function checkScrollDirection () {
4651     const st = window.scrollY
4652     if (st - lastScrollTop > 7) {
4653       scrollDown = true
4654     } else if (st - lastScrollTop < -7) {
4655       scrollDown = false
4656     }
4657     lastScrollTop = st <= 0 ? 0 : st
4658     if (scrollDown) {
4659       if (headerStages) header.classList.add('stages-hide')
4660       header.classList.add('thin')
4661       if (reviewsTileSidebar) reviewsTileSidebar.classList.add('space')
4662     } else {
4663       if (headerStages) header.classList.remove('stages-hide')
4664       header.classList.remove('thin')
4665       if (reviewsTileSidebar) reviewsTileSidebar.classList.remove('space')
4666     }
4667   }
4668 
4669
4670  const menuBtn = document.querySelector('.header__nav-item_menu')
4671  const layer = document.querySelector('.header__layer')
4672  const stretch = document.querySelector('.trial-stretch')
4673
4674  const navCloseBtns = header.querySelectorAll('.nav__close')
4675    for (let i = 0; i < navCloseBtns.length; i++) {
4676     navCloseBtns[i].addEventListener('click', closeMenu)
4677    }
4678  menuBtn.addEventListener('click', toggleMenu)
4679  layer.addEventListener('click', closeMenu)
4680
4681  function toggleMenu () {
4682    header.classList.toggle('open')
4683    headerLayer.classList.toggle('active')
4684    fixHeaderTop()
4685    fixMenuHeight()
4686    stickyHeader.classList.toggle('open')
4687    body.classList.toggle('no-scroll')
4688  }
4689
4690  function fixHeaderTop () {
4691    if (header.classList.contains('open') && stretch && stretch?.getBoundingClientRect().top === 0) {
4692      header.style.top = stretch.clientHeight + 'px'
4693    }
4694    if (!header.classList.contains('open') && stretch) {
4695      header.style.top = '0'
4696    }
4697  }
4698
4699  function fixMenuHeight () {
4700    if (header.classList.contains('open') && stretch && stretch?.getBoundingClientRect().top === 0 && window.innerWidth < 744) {
4701      const vh = document.documentElement.style.getPropertyValue('--vh')
4702      nav.style.height = `${(vh.slice(0, -2) * 100) - 80 - stretch.clientHeight}px`
4703      for (let i = 0; i < navMenus.length; i++) {
4704        navMenus[i].style.height = `${(vh.slice(0, -2) * 100) - 80 - 70 - stretch.clientHeight}px`
4705      }
4706      for (let i = 0; i < navBtns.length; i++) {
4707        navBtns[i].style.height = `${(vh.slice(0, -2) * 100) - 80 - 70 - stretch.clientHeight}px`
4708      }
4709      if (familyScroller) familyScroller.style.height = `${(vh.slice(0, -2) * 100) - 210 - stretch.clientHeight}px`
4710      if (ed1Scroller) ed1Scroller.style.height = `${(vh.slice(0, -2) * 100) - 210 - stretch.clientHeight}px`
4711    } else {
4712      nav.removeAttribute('style')
4713      for (let i = 0; i < navMenus.length; i++) {
4714        navMenus[i].removeAttribute('style')
4715      }
4716      for (let i = 0; i < navBtns.length; i++) {
4717        navBtns[i].removeAttribute('style')
4718      }
4719      if (familyScroller) familyScroller.removeAttribute('style')
4720      if (ed1Scroller) ed1Scroller.removeAttribute('style')
4721    }
4722  }
4723
4724  function closeMenu () {
4725    header.classList.remove('open')
4726    headerLayer.classList.remove('active')
4727    if (stretch) {
4728      header.style.top = '0'
4729      nav.removeAttribute('style')
4730      for (let i = 0; i < navMenus.length; i++) {
4731        navMenus[i].removeAttribute('style')
4732      }
4733      for (let i = 0; i < navBtns.length; i++) {
4734        navBtns[i].removeAttribute('style')
4735      }
4736      if (familyScroller) familyScroller.removeAttribute('style')
4737      if (ed1Scroller) ed1Scroller.removeAttribute('style')
4738    }
4739    stickyHeader.classList.remove('open')
4740    body.classList.remove('no-scroll')
4741    headerArea.classList.remove('hide')
4742     const activeArea = document.querySelector('.nav__area.active-mob')
4743     if (activeArea) activeArea.classList.remove('active-mob')
4744  }
4745}
4746
4747const helpSidebarItems = document.querySelectorAll('.help-sidebar__item')
4748const helpLineMenu = document.querySelector('.help-line__menu')
4749const helpLineSearch = document.querySelector('.help-line__search')
4750const helpSidebar = document.querySelector('.help-sidebar')
4751const helpSearchArticle = document.querySelector('.help-search_article')
4752const helpSearchInputs = document.querySelectorAll('.help-search__input')
4753const helpSidebarClose = document.querySelector('.help-sidebar__close')
4754const helpArticleNav = document.querySelector('.help-article-nav')
4755let timerHideHelpSearchMob
4756
4757helpSidebarItems.forEach(item => {
4758  item.addEventListener('click', (e) => item.classList.toggle('help-sidebar__item_active'))
4759})
4760
4761if (helpLineMenu) helpLineMenuInit()
4762if (helpLineSearch) helpLineSearchInit()
4763
4764function helpLineMenuInit () {
4765  const body = document.querySelector('body')
4766  helpLineMenu.addEventListener('click', openSidebar)
4767  function openSidebar() {
4768    body.classList.add('no-scroll-mob')
4769    helpSidebar?.classList.add('help-sidebar_active')
4770  }
4771  helpSidebarClose.addEventListener('click', closeSidebar)
4772  function closeSidebar() {
4773    body.classList.remove('no-scroll-mob')
4774    helpSidebar?.classList.remove('help-sidebar_active')
4775  }
4776}
4777
4778function helpLineSearchInit () {
4779  helpLineSearch.addEventListener('click', showHelpSearchMob)
4780  function showHelpSearchMob () {
4781    helpSearchArticle?.classList.add('help-search_show')
4782    setTimeout(() => helpSearchArticle.querySelector('.help-search__input')?.focus(), 500)
4783  }
4784}
4785
4786function hideHelpSearchMob () {
4787  helpSearchArticle?.classList.remove('help-search_show')
4788}
4789
4790if (helpSearchInputs.length) helpSearchInputsInit()
4791
4792async function loadHelpJson() {
4793  let path = helpSearchInputs[0].getAttribute('data-json-path')
4794  try {
4795    const response = await fetch(path)
4796    if (!response.ok) throw new Error('Error loading JSON')
4797    return await response.json()
4798  } catch (error) {
4799    console.error('Error loading JSON:', error)
4800  }
4801}
4802
4803function searchAdvanced(query, preparedData) {
4804  const q = query.toLowerCase().trim()
4805  const words = q.split(' ')
4806
4807  const exact = preparedData.filter(item =>
4808    item.name.toLowerCase() === q ||
4809    item.keywordsArray.includes(q)
4810  )
4811  if (exact.length) return exact
4812
4813  const includes = preparedData.filter(item => {
4814    const text = (item.name + ' ' + item.keywords).toLowerCase()
4815    return words.every(w => text.includes(w))
4816  })
4817  if (includes.length) return includes
4818
4819  return fuse.search({
4820    $and: words.map(word => ({
4821      $or: [
4822        { name: word },
4823        { keywordsArray: word }
4824      ]
4825    }))
4826  })
4827}
4828
4829function smartSearch(query, preparedData) {
4830  const results = searchAdvanced(query, preparedData)
4831  return normalizeResults(results)
4832    .sort((a, b) => a.score - b.score)
4833    .map(res => res.item)
4834}
4835
4836function normalizeResults(results) {
4837  return results.map(res => {
4838    if (res.item) return res
4839    return { item: res, score: 0 }
4840  })
4841}
4842
4843
4844async function helpSearchInputsInit () {
4845  const helpJson = await loadHelpJson()
4846  let fuse
4847  let preparedData
4848  if (helpJson) {
4849    preparedData = helpJson.map(item => ({
4850      ...item,
4851      keywordsArray: item.keywords
4852        .toLowerCase()
4853        .split(',')
4854        .map(k => k.trim())
4855    }))
4856    fuse = new Fuse(preparedData, {
4857      includeScore: true,
4858      threshold: 0.3,
4859      ignoreLocation: true,
4860      minMatchCharLength: 2,
4861
4862      keys: [
4863        { name: 'name', weight: 0.6 },
4864        { name: 'keywordsArray', weight: 0.4 }
4865      ]
4866    })
4867  }
4868
4869  for (let i = 0; i < helpSearchInputs.length; i++) {
4870    helpSearchInputInit(helpSearchInputs[i])
4871  }
4872
4873  function helpSearchInputInit (input) {
4874    const helpSearch = input.closest('.help-search')
4875    const helpSearchList = helpSearch.querySelector('.help-search__list')
4876    const helpSearchAll = helpSearch.querySelector('.help-search__all')
4877    const srfullResults = input.getAttribute('data-srfull-results')
4878    const srResults = input.getAttribute('data-sr-results')
4879    const dataUtm = input.getAttribute('data-utm')
4880
4881    input.addEventListener('input', search)
4882    input.addEventListener('input', updateHelpSearchAllHref)
4883    input.addEventListener('focus', search)
4884    input.addEventListener('keydown', (e) => {
4885      if (e.key === 'Enter') {
4886        debouncedSearch.cancel?.()
4887        handleSearch(e.target.value)
4888      }
4889    })
4890
4891    document.addEventListener('click', hideSearchResults)
4892    if (helpSearch.classList.contains('help-search_article')) {
4893      input.addEventListener('blur', () => setTimerHideHelpSearchMob(false))
4894      input.addEventListener('focus', () => setTimerHideHelpSearchMob(true))
4895    }
4896
4897    function updateHelpSearchAllHref () {
4898      helpSearchAll.href = `${srfullResults}?q=${input.value}`
4899    }
4900
4901    function search () {
4902      if (this.value.length > 3) {
4903        if (helpJson) {
4904          debouncedSearch(this.value)
4905        }
4906      } else {
4907        hideSearchResults()
4908      }
4909    }
4910
4911    function debounce(fn, delay = 300) {
4912      let timeout
4913
4914      function debounced(...args) {
4915        clearTimeout(timeout)
4916
4917        timeout = setTimeout(() => {
4918          fn.apply(this, args)
4919        }, delay)
4920      }
4921
4922      debounced.cancel = () => clearTimeout(timeout)
4923
4924      return debounced
4925    }
4926
4927    const debouncedSearch = debounce(handleSearch, 300)
4928
4929    function handleSearch (query) {
4930      if (!query.trim()) {
4931        generateResultList([])
4932        hideSearchResults()
4933        return
4934      }
4935
4936      const result = smartSearch(query, preparedData)
4937      if (helpSearchList) generateResultList(result)
4938      showSearchResults()
4939    }
4940
4941    function generateResultList (result) {
4942      helpSearchList.innerHTML = ''
4943      result.forEach((item) => {
4944        const a = document.createElement('a')
4945        a.href = `${srResults}/${item.slug}?${dataUtm}`
4946        a.innerHTML = item.name
4947        a.classList.add('help-search__item')
4948        helpSearchList.appendChild(a)
4949      })
4950    }
4951
4952    function showSearchResults () {
4953      helpSearch?.classList.add('help-search_active')
4954    }
4955
4956    function hideSearchResults (e) {
4957      if (!e?.target?.closest('.help-search__result')) {
4958        helpSearch?.classList.remove('help-search_active')
4959      }
4960    }
4961  }
4962}
4963
4964function setTimerHideHelpSearchMob (stop) {
4965  if (stop) {
4966    clearTimeout(timerHideHelpSearchMob)
4967    helpArticleNav?.classList.add('help-article-nav_active')
4968  } else {
4969    timerHideHelpSearchMob = setTimeout(hideHelpSearchMob, 10000)
4970    helpArticleNav?.classList.remove('help-article-nav_active')
4971  }
4972}
4973
4974
4975const howSlider = document.querySelector('[data-element="how-slider"]')
4976
4977if (howSlider) howSliderInit()
4978
4979function howSliderInit () {
4980  let howSliderSwiper
4981
4982  function initSlider () {
4983    howSliderSwiper = new Swiper(howSlider, {
4984      mousewheel: { forceToAxis: true },
4985      slidesPerView: 'auto',
4986      spaceBetween: 30,
4987      a11y: false,
4988      navigation: {
4989        nextEl: '.how__nav-btn_next',
4990        prevEl: '.how__nav-btn_prev',
4991      },
4992      scrollbar: {
4993        el: '.how__scrollbar',
4994        draggable: true,
4995      },
4996    })
4997  }
4998
4999  window.addEventListener('resize', checkSlider)
5000
5001  checkSlider()
5002
5003  function checkSlider () {
5004    if (window.innerWidth >= 1360) {
5005      if (!howSliderSwiper || howSliderSwiper.destroyed) {
5006        initSlider()
5007      }
5008    } else {
5009      if (howSliderSwiper && !howSliderSwiper.destroyed) {
5010        howSliderSwiper.destroy(true, true)
5011        howSliderSwiper = null
5012      }
5013    }
5014  }
5015}
5016
5017const oldPromoAnimateNodes = document.querySelectorAll(".old-promo-animate")
5018
5019if (oldPromoAnimateNodes.length) oldPromoAnimateInit()
5020
5021function oldPromoAnimateInit () {
5022  const delayStep = 0.05
5023
5024  const observer = new IntersectionObserver((entries) => {
5025    entries.forEach((entry, index) => {
5026      if (entry.isIntersecting) {
5027        observer.unobserve(entry.target)
5028        entry.target.style.setProperty('transition-delay', `${index * delayStep}s`);
5029        entry.target.classList.add('old-promo-animate_active')
5030      }
5031    });
5032  }, {
5033    root: null,
5034    rootMargin: '0px 0px -50px 0px',
5035    threshold: 1
5036  })
5037
5038  for (let i = 0; i < oldPromoAnimateNodes.length; i++) {
5039    observer.observe(oldPromoAnimateNodes[i])
5040  }
5041}
5042
5043
5044const parsingOgeLessonVideoBox = document.querySelectorAll('.parsing-oge-lesson__video-box')
5045for (let i = 0; i < parsingOgeLessonVideoBox.length; i++) {
5046  parsingOgeLessonVideoBox[i].addEventListener('click', function () {
5047    parsingOgeLessonVideoBox[i].classList.add('active')
5048    const iframe = parsingOgeLessonVideoBox[i].querySelector('iframe')
5049    iframe.src = iframe.src.replace('autoplay=0', 'autoplay=1')
5050  })
5051}
5052
5053
5054const how = document.querySelector("[data-element='how']")
5055
5056if (how) howInit()
5057
5058function howInit () {
5059  const btn = document.querySelector("[data-element='how-button']")
5060  btn.addEventListener('click', function () {
5061    this.style.display = "none"
5062    how.classList.add('active')
5063  })
5064}
5065
5066const information = document.querySelector('.information')
5067
5068if (information) informationInit()
5069
5070function informationInit () {
5071  const togglers = document.querySelectorAll('[data-information-toggler]')
5072  const accordions = document.querySelectorAll('[data-information-accordion]')
5073  const sidebarOpenBtn = document.querySelector('.information__sidebar-open')
5074  const sidebarCloseBtn = document.querySelector('.information__sidebar-close')
5075  const sidebar = document.querySelector('.information__sidebar')
5076  const body = document.querySelector('body')
5077
5078  for (let i = 0; i < accordions.length; i++) {
5079    accordions[i].addEventListener('click', () => {
5080      const oldToggler = document.querySelector('.information__button.active')
5081      if (oldToggler && !accordions[i].classList.contains('active')) oldToggler.classList.remove('active')
5082      accordions[i].classList.toggle('active')
5083    })
5084  }
5085
5086  for (let i = 0; i < togglers.length; i++) {
5087    togglers[i].addEventListener('click', toggleBox)
5088  }
5089
5090  function toggleBox () {
5091    const id = this.getAttribute('data-information-button-id')
5092    const box = information.querySelector('[data-information-box-id="' + id + '"]')
5093    if (box) {
5094      const oldActive = document.querySelector('.information__box.active')
5095      if (oldActive) oldActive.classList.remove('active')
5096      const oldToggler = document.querySelector('.information__button.active')
5097      if (oldToggler && !this.classList.contains('information__btn')) oldToggler.classList.remove('active')
5098      box.classList.add('active')
5099      this.classList.add('active')
5100      closeSidebar()
5101      window.scrollTo(0, 0)
5102    }
5103  }
5104
5105  sidebarOpenBtn.addEventListener('click', openSidebar)
5106  sidebarCloseBtn.addEventListener('click', closeSidebar)
5107
5108  function openSidebar () {
5109    sidebar.classList.add('active')
5110    body.classList.add('no-scroll')
5111  }
5112
5113  function closeSidebar () {
5114    sidebar.classList.remove('active')
5115    body.classList.remove('no-scroll')
5116  }
5117}
5118
5119const instructionVideoBox = document.querySelector('.instruction__video-box')
5120
5121if (instructionVideoBox) instructionVideoBoxInit()
5122
5123function instructionVideoBoxInit() {
5124  const iframe = instructionVideoBox.querySelector('iframe')
5125  if (!iframe) {
5126    const video = instructionVideoBox.querySelector('video')
5127    instructionVideoBox.addEventListener('click', function () {
5128      this.classList.add('active')
5129      if (video) video.play()
5130    }, { once: true })
5131  }
5132}
5133
5134const itCapCards = document.querySelector('.it-cap__cards')
5135
5136if (itCapCards) itCapCardsInit()
5137
5138function itCapCardsInit () {
5139  let itCapCardsSwiper
5140
5141  function initSlider () {
5142    itCapCardsSwiper = new Swiper(itCapCards, {
5143      mousewheel: { forceToAxis: true },
5144      slidesPerView: 'auto',
5145      allowTouchMove: false,
5146      spaceBetween: 25,
5147      autoplay: {
5148        delay: 3000,
5149      },
5150      speed: 1000,
5151      loop: true,
5152    })
5153  }
5154
5155  window.addEventListener('resize', checkSlider)
5156
5157  checkSlider()
5158
5159  function checkSlider () {
5160    if (window.innerWidth >= 1440) {
5161      if (!itCapCardsSwiper || itCapCardsSwiper.destroyed) {
5162        initSlider()
5163      }
5164    } else {
5165      if (itCapCardsSwiper && !itCapCardsSwiper.destroyed) {
5166        itCapCardsSwiper.destroy(true, true)
5167        itCapCardsSwiper = null
5168      }
5169    }
5170  }
5171}
5172
5173
5174const itHowSlider = document.querySelector(".it-how__slider")
5175
5176if (itHowSlider) itHowSliderInit()
5177
5178function itHowSliderInit () {
5179  let itHowSliderSwiper
5180
5181  function initSlider () {
5182    itHowSliderSwiper = new Swiper(itHowSlider, {
5183      mousewheel: { forceToAxis: true },
5184      slidesPerView: 'auto',
5185      spaceBetween: 20,
5186      a11y: false,
5187      navigation: {
5188        nextEl: '.it-how__nav-btn_next',
5189        prevEl: '.it-how__nav-btn_prev',
5190      },
5191      scrollbar: {
5192        el: '.it-how__scrollbar',
5193        draggable: true,
5194      },
5195      breakpoints: {
5196        1440: {
5197          spaceBetween: 30,
5198        }
5199      }
5200    })
5201  }
5202
5203  window.addEventListener('resize', checkSlider)
5204
5205  checkSlider()
5206
5207  function checkSlider () {
5208    if (window.innerWidth >= 744) {
5209      if (!itHowSliderSwiper || itHowSliderSwiper.destroyed) {
5210        initSlider()
5211      }
5212    } else {
5213      if (itHowSliderSwiper && !itHowSliderSwiper.destroyed) {
5214        itHowSliderSwiper.destroy(true, true)
5215        itHowSliderSwiper = null
5216      }
5217    }
5218  }
5219}
5220
5221const itTileItems = document.querySelectorAll('.it-tile__item')
5222
5223for (let i = 0; i < itTileItems.length; i++) {
5224  itTileMoreInit(itTileItems[i])
5225}
5226
5227function itTileMoreInit (parent) {
5228  const btn = parent.querySelector('.it-tile__more')
5229  const descr = parent.querySelector('.it-tile__author-descr')
5230
5231  if (btn && descr) {
5232    if ((descr.clientHeight > 68 && window.innerWidth >= 1440) || (descr.clientHeight > 50 && window.innerWidth < 1440)) {
5233      descr.classList.add('hide')
5234    } else {
5235      btn.remove()
5236    }
5237  }
5238}
5239
5240const langsTeachersSlider = document.querySelector('.langs-teachers__slider')
5241
5242if (langsTeachersSlider) langsTeachersSliderInit()
5243
5244function langsTeachersSliderInit () {
5245  let swiper
5246  if (window.innerWidth >= 744) {
5247    swiper = new Swiper(langsTeachersSlider, {
5248      mousewheel: { forceToAxis: true },
5249      slidesPerView: 'auto',
5250      autoHeight: true,
5251      spaceBetween: 500,
5252      effect: 'fade',
5253      fadeEffect: {
5254        crossFade: true
5255      },
5256      a11y: false,
5257      pagination: {
5258        el: '.langs-teachers__pagination',
5259        clickable: true,
5260      },
5261      breakpoints: {
5262        744: {
5263          effect: 'fade',
5264          navigation: {
5265            nextEl: '.langs-teachers__nav-btn_next',
5266            prevEl: '.langs-teachers__nav-btn_prev',
5267          },
5268          scrollbar: {
5269            el: '.langs-teachers__scrollbar',
5270            draggable: true,
5271          },
5272        }
5273      }
5274    })
5275  } else {
5276    swiper = new Swiper(langsTeachersSlider, {
5277      mousewheel: { forceToAxis: true },
5278      slidesPerView: 'auto',
5279      autoHeight: true,
5280      spaceBetween: 200,
5281      fadeEffect: {
5282        crossFade: true
5283      },
5284      a11y: false,
5285      pagination: {
5286        el: '.langs-teachers__pagination',
5287        clickable: true,
5288      },
5289      breakpoints: {
5290        744: {
5291          effect: 'fade',
5292          navigation: {
5293            nextEl: '.langs-teachers__nav-btn_next',
5294            prevEl: '.langs-teachers__nav-btn_prev',
5295          },
5296          scrollbar: {
5297            el: '.langs-teachers__scrollbar',
5298            draggable: true,
5299          },
5300        }
5301      }
5302    })
5303  }
5304
5305  const boxes = langsTeachersSlider.querySelectorAll('.langs-teachers__box')
5306
5307  for (let i = 0; i < boxes.length; i++) {
5308    const list = boxes[i].querySelector('.langs-teachers__list')
5309    if (list.clientHeight > 150) moreBtnInit(boxes[i])
5310  }
5311
5312  function moreBtnInit (box) {
5313    box.classList.add('hide')
5314    const btn = box.querySelector('.langs-teachers__more')
5315    btn.classList.add('active')
5316    btn.addEventListener('click', toggleBox)
5317
5318    function toggleBox () {
5319      if (box.classList.contains('hide')) {
5320        box.classList.remove('hide')
5321        btn.innerHTML = 'Свернуть'
5322      } else {
5323        box.classList.add('hide')
5324        btn.innerHTML = 'Показать полностью'
5325      }
5326      swiper.update()
5327    }
5328  }
5329}
5330
5331
5332
5333const animateItems = document.querySelectorAll('.library-cap__animate')
5334 
5335 if (animateItems.length) animateItemsInit()
5336 
5337 function animateItemsInit () {
5338   const speed = 50
5339   let itemsIndex = 0
5340   const text = document.querySelector('.library-cap__text')
5341   const cursor = text.querySelector('.library-cap__cursor')
5342 
5343   createString(animateItems[itemsIndex])
5344 
5345   function createString (item) {
5346     item.classList.add('active')
5347     const string = item.querySelector('.library-cap__animate-string')
5348     const cleanString = string.innerHTML.replace(/&nbsp;|\u00A0/g, ' ');
5349     const text = [...cleanString]
5350     let stringWithSpans = ''
5351     text.forEach((char, i) => {
5352       stringWithSpans += `<span>${char}</span>`
5353     })
5354     string.innerHTML = stringWithSpans
5355     animateString(string)
5356   }
5357 
5358   function animateString (string) {
5359     const spans = string.querySelectorAll('span')
5360     const length = spans.length
5361     let index = 0
5362     animateSpan()
5363 
5364     function animateSpan () {
5365       spans[index].classList.add('active')
5366       calculateCoords(spans[index])
5367       index += 1
5368       if (index < length) {
5369         setTimeout(animateSpan, speed)
5370       } else {
5371         setTimeout(animateHide, 1000)
5372       }
5373     }
5374     function animateHide () {
5375       const spans = string.querySelectorAll('span')
5376       let index = spans.length - 1
5377       animateSpanHide()
5378 
5379       function animateSpanHide () {
5380         spans[index].classList.remove('active')
5381         index -= 1
5382         calculateCoords(spans[index])
5383         if (index < 0) {
5384           cursor.style.left = `${cursor.style.left.slice(0, -2) - 22}px`
5385           const oldActive = document.querySelector('.library-cap__animate.active')
5386           setTimeout(function () {
5387             oldActive.classList.remove('active')
5388           }, 50)
5389           setTimeout(function () {
5390             const oldString = oldActive.querySelector('.library-cap__animate-string')
5391             oldString.innerHTML = oldString.getAttribute('data-text')
5392             itemsIndex += 1
5393             if (itemsIndex >= animateItems.length) itemsIndex = 0
5394             createString(animateItems[itemsIndex])
5395           }, 100)
5396         } else {
5397           setTimeout(animateSpanHide, speed*0.7)
5398         }
5399       }
5400     }
5401   }
5402 
5403   function calculateCoords (span) {
5404     if (!span) return
5405     const top = span.getBoundingClientRect().top - text.getBoundingClientRect().top
5406     const left = span.getBoundingClientRect().left - text.getBoundingClientRect().left
5407     cursor.style.top = `${top}px`
5408     cursor.style.left = `${left}px`
5409   }
5410 }
5411
5412const libraryCap = document.querySelector('.library-cap')
5413 
5414 if (libraryCap) libraryCapInit()
5415 
5416 function libraryCapInit () {
5417   const libraryTile = document.querySelector('.library-tile')
5418   const libraryWhy = document.querySelector('.library-why')
5419   const libraryInformer = document.querySelector('.library-informer')
5420   const config = { attributes: false, childList: true, characterData: true, subtree: true }
5421   const openers = libraryCap.querySelectorAll("[data-element='library-cap-filter-opener']")
5422   const grades = libraryCap.querySelector("[data-ftype='class_select']")
5423   const subjects = libraryCap.querySelector("[data-ftype='class_subjects']")
5424   const filterSubjectBox = libraryCap.querySelector(".library-cap__filter.library-cap__filter_subject")
5425   const filterSubjectsList = libraryCap.querySelector(".library-cap__filter-wrap.class_subjects")
5426   const filterClassBox = libraryCap.querySelector(".library-cap__filter.library-cap__filter_class")
5427   const tile = document.querySelector('.library-tile')
5428
5429    const title = document.querySelector('.library-tile__title')
5430    const urlFilter = libraryCap.getAttribute('data-item-h')
5431    const h1Filter = libraryCap.getAttribute('data-hname')
5432    const metaName = libraryCap.getAttribute('data-meta_name')
5433    const metaDescription = libraryCap.getAttribute('data-meta_descr')
5434    const stickyHeader = document.querySelector('.sticky-header')
5435    const body = document.querySelector('body')
5436    const crumbsNewList = document.querySelector('.crumbs-new__list')
5437    const crumbs = document.querySelector('.crumbs-new')
5438    const filterSubject = document.querySelector(".library-cap__filter_subject")
5439    const filterSubjectWrap = filterSubject.querySelector(".library-cap__filter-wrap")
5440
5441
5442   const observer = new MutationObserver(function() {
5443     const wrap = openers[1].nextElementSibling
5444     const items = wrap.querySelectorAll("[data-element='library-cap-filter-input']")
5445     items.forEach((item) => {
5446       item.addEventListener('change', () => updateFilter(openers[1], wrap))
5447     })
5448     initInformerButtons()
5449   })
5450
5451   initTabs()
5452
5453   const observerPoster = new MutationObserver(function() {
5454     initLibraryPosters()
5455     initTabs()
5456     initFilterTabs()
5457     initCommonAnalytics(tile.firstElementChild)
5458   })
5459 
5460   observerPoster.observe(tile, config)
5461 
5462   const save = libraryCap.querySelector(".library-cap__button")
5463   if (save) save.addEventListener('click', saveHandler)
5464 
5465   function saveHandler () {
5466     let valid = true
5467     for (let i = 0; i < openers.length; i++) {
5468       const wrap = openers[i].nextElementSibling
5469       const itemChecked = wrap.querySelector(["input:checked"])
5470       if (!itemChecked) {
5471         valid = false
5472         openers[i].classList.add('error')
5473         setError()
5474       }
5475     }
5476 
5477     if (valid) {
5478       makeFiltration()
5479       scrollToTile()
5480     }
5481   }
5482
5483   const subjectWrap =  libraryCap.querySelector('.library-cap__filter.library-cap__filter_subject .library-cap__filter-wrap')
5484   const icon = libraryCap.querySelector('.library-cap__filter-icon')
5485   const labels = subjectWrap.querySelectorAll('.library-cap__filter-item')
5486   if (labels.length < 7 && icon) icon.remove()
5487 
5488   const reset = libraryCap.querySelector("[data-element='library-cap-filter-reset']")
5489   if (reset) reset.addEventListener('click', resetFilters)
5490 
5491   function resetFilters () {
5492     filterSubjectBox.classList.add('disable')
5493     for (let i = 0; i < openers.length; i++) {
5494       const wrap = openers[i].nextElementSibling
5495       const items = wrap.querySelectorAll("[data-element='library-cap-filter-input']")
5496       items.forEach((item) => {
5497         item.checked = false
5498       })
5499       updateFilter(openers[i], wrap, true, true)
5500     }
5501     makeFiltration()
5502     hideBlocks()
5503   }
5504
5505   function updateBodyDataParams (grades_result, subjects_result) {
5506    body.setAttribute('data-filter-stage', grades_result ? grades_result : 'all')
5507    body.setAttribute('data-filter-subject', subjects_result ? subjects_result : 'all')
5508    const grades = grades_result ? '_grade' : ''
5509    const subjects = subjects_result ? '_subject' : ''
5510    const dataPageType = `library${grades}${subjects}`
5511    body.setAttribute('data-page-type', dataPageType)
5512   }
5513
5514 
5515   async function makeFiltration () {
5516     const grades_wrap = grades.nextElementSibling
5517     const grades_items = grades_wrap.querySelectorAll(["input:checked"])
5518     let grades_result = ''
5519     let grade_first = 0
5520     let grade_h1_part= '' 
5521     let grade_item = '' 
5522     let grade_breadname = ''
5523     grades_items.forEach((item, i) => {
5524       if (i > 0) grades_result += '|'
5525       if (grade_first == 0) grade_first = item.value
5526       if (grade_item === '') {
5527         grade_item = item.getAttribute('data-item')
5528         grade_breadname = item.getAttribute('data-breadname')
5529       }
5530       if (grade_h1_part === '') grade_h1_part = item.getAttribute('data-hname') 
5531       grades_result += item.value
5532     })
5533     let subjects_result = ''
5534     let subject_item = '' 
5535     let subject_breadname = ''
5536     let subject_h1_part= '' 
5537     try{
5538       const subjects_wrap = subjects.nextElementSibling
5539       const subjects_items = subjects_wrap.querySelectorAll(["input:checked"])
5540       subjects_items.forEach((item, i) => {
5541         if (i > 0) subjects_result += '|'
5542         subjects_result += item.value
5543         if (subject_item === '') {
5544           subject_item = item.getAttribute('data-item')
5545           subject_breadname = item.getAttribute('data-breadname')
5546         }
5547         if (subject_h1_part === '') subject_h1_part = item.getAttribute('data-hname') 
5548       })
5549     }catch(e){}
5550     let utm_f = libraryCap.getAttribute('data-utm');
5551     $('.filtered_elements').html("<div class='tile-loader'></div>");
5552     $.request('VideoCourseFunctions::onPaginateAllCourses', {
5553       data: {
5554         'grade': grades_result,
5555         'subject': subjects_result,
5556         'utm_t': utm_f
5557       }
5558     })
5559    if (urlFilter ) {
5560        let url = urlFilter
5561        let new_h1 = 'Видеоуроки'
5562        let new_title = new_h1
5563        let new_description = 'Бесплатные видеоуроки '
5564        let base_subject = ''
5565        let base_grade = ''
5566        let urlGrade
5567        let urlSubject
5568
5569        if (grade_first > 0 ){
5570          // let url = new URL(window.location.href)
5571          // url.searchParams.set('gr', grade_first);
5572          
5573            if (grade_item) {
5574              urlGrade = url + '/' + grade_item
5575            }
5576
5577            if (subject_item) {
5578              urlSubject = url + '/' + grade_item + '/' + subject_item
5579            }
5580
5581            generateCrumbs()
5582
5583           
5584           
5585          if (grade_item !== "") {
5586            url = url + '/' + grade_item
5587            if (subject_item !== "") {
5588              url = url + '/' + subject_item
5589            }
5590            
5591          }
5592          
5593
5594            if (subject_h1_part !== "") {
5595              base_subject = ' по '+ subject_h1_part
5596              new_h1 = new_h1 + base_subject
5597              new_description = new_description + base_subject
5598            }else{
5599            }
5600            if (grade_h1_part !== "") {
5601              base_grade = ' для ' + grade_h1_part
5602              new_h1 = new_h1 + base_grade
5603              new_description = new_description + base_grade
5604            }else{
5605            }
5606            try{
5607                title.innerHTML = new_h1
5608            }catch(lib_er){}
5609        } else {
5610            generateCrumbs()
5611        } 
5612
5613        url = url + utm_f
5614        history.replaceState(null, "", url.toString())
5615
5616        new_title = new_h1 + ' в онлайн-школе «Точка Знаний»'
5617        new_description = new_description + ' в одном месте. Пошаговые объяснения, разбор сложных тем и примеры решения. Смотрите уроки онлайн в удобном формате!'
5618        console.log(new_title);
5619
5620        
5621        document.title = new_title
5622        const meta= document.getElementsByTagName("meta")
5623        for (let i= 0; i < meta.length; i++) {
5624          if (meta[i].name.toLowerCase() === "description") {
5625            meta[i].content = new_description
5626          }
5627        }
5628
5629        updateBodyDataParams(grades_result, subjects_result)
5630
5631        function generateCrumbs () {
5632            if (crumbsNewList) {
5633              crumbsNewList.innerHTML = ''
5634              createCrumbsItem('/', 'Главная')
5635              if (urlGrade) {
5636                createCrumbsItem(urlFilter, 'Библиотека пробных уроков')
5637              } else  {
5638                createCrumbsItem(false, 'Библиотека пробных уроков')
5639              }
5640              if (urlGrade && urlSubject) {
5641                createCrumbsItem(urlGrade, grade_breadname)
5642                createCrumbsItem(false, subject_breadname)
5643              } else if (urlGrade) {
5644                createCrumbsItem(false, grade_breadname)
5645              }
5646            }
5647        }
5648        function createCrumbsItem (url, text) {
5649            let item
5650            if (url) {
5651              item = document.createElement('a')
5652              item.href = url
5653            } else {
5654              item = document.createElement('span')
5655            }
5656            item.classList.add('crumbs-new__item')
5657            item.innerHTML = text
5658            crumbsNewList.appendChild(item)
5659        }
5660
5661    }
5662    initLibraryPosters()
5663     // }
5664 
5665   }
5666 
5667   function scrollToTile () {
5668     showBlocks()
5669     const banner = document.querySelector('.discount')
5670     const bannerHeight = banner ? banner.clientHeight : 0
5671     const theElement = document.getElementById('library-tile')
5672     let offset
5673     if (window.innerWidth < 744) {
5674       offset = 84 + bannerHeight
5675     } else if (window.innerWidth < 1200) {
5676       offset = 102 + bannerHeight
5677     } else {
5678       offset = 120 + bannerHeight
5679     }
5680     window.scrollTo(0, theElement.getBoundingClientRect().top + scrollY - offset)
5681   }
5682
5683   function showBlocks () {
5684     if (libraryTile) libraryTile.classList.remove('hide')
5685     if (libraryWhy) libraryWhy.classList.remove('hide')
5686     if (libraryInformer) libraryInformer.classList.remove('hide')
5687   }
5688
5689   function hideBlocks () {
5690     if (libraryTile) libraryTile.classList.add('hide')
5691     if (libraryWhy) libraryWhy.classList.add('hide')
5692     if (libraryInformer) libraryInformer.classList.add('hide')
5693   }
5694 
5695   for (let i = 0; i < openers.length; i++) {
5696     openers[i].addEventListener("click", (e)=> openFilter(openers[i], e))
5697 
5698     const wrap = openers[i].nextElementSibling
5699     const items = wrap.querySelectorAll("[data-element='library-cap-filter-input']")
5700     items.forEach((item) => {
5701       item.addEventListener('change', () => updateFilter(openers[i], wrap))
5702     })
5703     if (i === 1) {
5704       window.onload = function() {
5705         observer.observe(wrap, config)
5706       }
5707     }
5708   }
5709
5710    initInformerButtons()
5711
5712    function initInformerButtons () {
5713        const informerButtons = subjects.nextElementSibling.querySelectorAll('.all-courses__filter-informer-button')
5714        informerButtons.forEach(informerButton => {
5715          informerButton.addEventListener('click', function () {
5716            const input = this.closest('.library-cap__filter-box')?.querySelector("[data-element='library-cap-filter-input']")
5717            if (input) {
5718              input.checked = true
5719              updateFilter(subjects, subjects.nextElementSibling)
5720            }
5721          })
5722        })
5723    }
5724
5725 
5726   function openFilter (opener, e) {
5727     e.stopPropagation()
5728     if (opener.parentElement.classList.contains('library-cap__filter_subject') && !filterClassBox.querySelector(["input:checked"])) {
5729       setError()
5730     } else {
5731       resetError()
5732       if (opener.classList.contains('active')) {
5733         closeFilter(opener)
5734       } else {
5735         const oldOpen = libraryCap.querySelector(".library-cap__filter-top.active")
5736         if (oldOpen) oldOpen.classList.remove('active')
5737         opener.classList.add('active')
5738 
5739         const filter = opener.parentElement
5740         const oldFilter = libraryCap.querySelector(".library-cap__filter.open")
5741         if (oldFilter) oldFilter.classList.remove('open')
5742         if (filter) filter.classList.add('open')
5743
5744         stickyHeader.classList.add('mob-hide')
5745         crumbs.classList.add('crumbs-new_mob-hide')
5746         body.classList.add('no-scroll-mob')
5747       }
5748     }
5749   }
5750
5751   window.addEventListener('click', closeAllFilters)
5752 
5753   function closeAllFilters () {
5754     const oldOpen = libraryCap.querySelector(".library-cap__filter-top.active")
5755     if (oldOpen) oldOpen.classList.remove('active')
5756     stickyHeader.classList.remove('mob-hide')
5757     crumbs.classList.remove('crumbs-new_mob-hide')
5758     body.classList.remove('no-scroll-mob')
5759   }
5760 
5761   function closeFilter (opener) {
5762     opener.classList.remove('active')
5763     const filter = opener.parentElement
5764     if (filter) filter.classList.remove('open')
5765     stickyHeader.classList.remove('mob-hide')
5766     crumbs.classList.remove('crumbs-new_mob-hide')
5767     body.classList.remove('no-scroll-mob')
5768   }
5769 
5770   async function updateFilter (opener, wrap, noScroll, noFiltration) {
5771     resetError()
5772     if(opener.getAttribute('data-ftype') === 'class_select') {
5773       filterSubjectsList.innerHTML = "<div class='tile-loader-box'><div class='tile-loader'></div></div>";
5774    //    makeFiltration()
5775       updateFilter(openers[1], openers[1].nextElementSibling, true)
5776       if (!noFiltration) updateFilter(openers[1], openers[1].nextElementSibling, true)
5777     } else {
5778       if (!noFiltration) makeFiltration()
5779       if (!noScroll) scrollToTile()
5780     }
5781     opener.innerHTML = opener.getAttribute('data-default-text')
5782     const items = wrap.querySelectorAll(["input:checked"])
5783     if (items.length) {
5784       opener.innerHTML = 'Выбрано: '
5785       items.forEach((item) => {
5786         const span = document.createElement("span")
5787         span.innerHTML = item.nextElementSibling.innerHTML
5788         span.classList.add('span')
5789         opener.append(span)
5790       })
5791     }
5792     const itemsAll = libraryCap.querySelectorAll(["input:checked"])
5793     if (itemsAll.length) {
5794       if (reset) reset.classList.add('show')
5795     } else {
5796       if (reset) reset.classList.remove('show')
5797     }
5798     closeFilter(opener)
5799   }
5800
5801   initLibraryPosters()
5802
5803   function setError () {
5804     openers[0].parentElement.classList.add('library-cap__filter_error')
5805     openers[1].parentElement.classList.add('library-cap__filter_error')
5806   }
5807 
5808   function resetError () {
5809     openers[0].parentElement.classList.remove('library-cap__filter_error')
5810     openers[1].parentElement.classList.remove('library-cap__filter_error')
5811   }
5812 
5813   function initTabs () {
5814     const tabs = tile.querySelectorAll('.library-tile__tab')
5815     if (!tabs.length) return
5816 
5817     const items = tile.querySelectorAll('.library-tile__item')
5818 
5819     for (let i = 0; i < tabs.length; i++) {
5820       tabs[i].addEventListener('click', tabFiltration)
5821     }
5822 
5823     function tabFiltration () {
5824       const oldActive = document.querySelector('.library-tile__tab.active')
5825       if (oldActive) oldActive.classList.remove('active')
5826       this.classList.add('active')
5827       for (let i = 0; i < items.length; i++) {
5828         items[i].style.display = 'none'
5829       }
5830       const dataIndex = this.getAttribute('data-index')
5831       const filteredItems = tile.querySelectorAll('[data-index="' + dataIndex + '"]')
5832       for (let i = 0; i < filteredItems.length; i++) {
5833         filteredItems[i].style.display = 'flex'
5834       }
5835     }
5836   }
5837
5838   initFilterTabs()
5839
5840  function initFilterTabs () {
5841    const filterHeadline = filterSubjectWrap.querySelector('.library-cap__filter-headline')
5842    const tabsParent = filterSubject.querySelector('.library-cap__filter-tabs')
5843    const list = filterSubjectWrap.querySelector('.library-cap__filter-list')
5844    const tabs = filterSubject.querySelectorAll('.library-cap__filter-tab')
5845    const subjectsBoxes = filterSubjectWrap.querySelectorAll('.library-cap__filter-box')
5846
5847    if (!tabs.length || !subjectsBoxes.length) return
5848
5849    filterSubjectWrap.addEventListener('scroll', wrapScrollHandler, { passive: true })
5850
5851    function wrapScrollHandler () {
5852      subjectsBoxes.forEach((subjectBox) => {
5853        if (filterSubjectWrap.scrollTop >= subjectBox.offsetTop - 90 - 65) {
5854          const oldTab = filterSubjectWrap.querySelector('.library-cap__filter-tab.active')
5855          if (oldTab) oldTab.classList.remove('active')
5856          const index = subjectBox.getAttribute('data-index')
5857          const tab = filterSubjectWrap.querySelector('[data-index="' + index + '"]')
5858          if (tab) {
5859            tabsParent.scrollLeft = tab.offsetLeft - tabsParent.clientWidth/2 + tab.clientWidth/2
5860            tab.classList.add('active')
5861          }
5862        }
5863      })
5864    }
5865
5866    let timeout
5867    let firstToggle = true
5868
5869    tabs.forEach((tab) => {
5870      tab.addEventListener('click', changeTab)
5871      tab.addEventListener('mouseenter', changeTab)
5872    })
5873
5874    function changeTab (e) {
5875      e.stopPropagation()
5876      clearTimeout(timeout)
5877      timeout = setTimeout(() => toggle(this),100)
5878
5879      function toggle (that) {
5880        if (!that.closest('.library-cap__filter-wrap')?.querySelector('.library-cap__filter-tab:hover') && !firstToggle) return
5881        firstToggle = false
5882        filterSubjectWrap.removeEventListener('scroll', wrapScrollHandler, { passive: true })
5883        const oldTab = filterSubjectWrap.querySelector('.library-cap__filter-tab.active')
5884        if (oldTab) oldTab.classList.remove('active')
5885
5886        that.classList.add('active')
5887        if (filterHeadline) filterHeadline.innerHTML = that.getAttribute('data-text')
5888
5889        subjectsBoxes.forEach((subjectsBox) => {
5890          subjectsBox.classList.add('hide')
5891        })
5892
5893        const index = that.getAttribute('data-index')
5894        const activeSubjectsBox = list.querySelector('[data-index="' + index + '"]')
5895        activeSubjectsBox.classList.remove('hide')
5896
5897        filterSubjectWrap.scrollTop = activeSubjectsBox.offsetTop - 90 - 60
5898
5899        tabsParent.scrollLeft = that.offsetLeft - tabsParent.clientWidth/2 + that.clientWidth/2
5900        setTimeout(() => filterSubjectWrap.addEventListener('scroll', wrapScrollHandler, { passive: true }), 200)
5901      }
5902    }
5903
5904    setTimeout(() => tabs[0].click(),200)
5905  }
5906
5907 }
5908
5909initLibraryPosters()
5910
5911function initLibraryPosters () {
5912  const videoBoxes = document.querySelectorAll('.library-tile__video-box')
5913  for (let i = 0; i < videoBoxes.length; i++) {
5914    videoBoxes[i].addEventListener('click', function () {
5915      videoBoxes[i].classList.add('active')
5916      const iframe = videoBoxes[i].querySelector('iframe')
5917      iframe.src = iframe.src.replace('autoplay=0', 'autoplay=1')
5918    })
5919  }
5920 
5921 }
5922
5923const lottieAnimations = document.querySelectorAll('[data-path]')
5924
5925for (let i = 0; i < lottieAnimations.length; i++) {
5926  lottie.loadAnimation({
5927    container: lottieAnimations[i],
5928    renderer: 'svg',
5929    loop: true,
5930    autoplay: true,
5931    path: lottieAnimations[i].getAttribute('data-path')
5932  })
5933}
5934
5935const marathonChildThemes = document.querySelector('[data-element="marathon-child__themes"]')
5936
5937if (marathonChildThemes) marathonChildThemesInit()
5938
5939function marathonChildThemesInit () {
5940  const navItems = document.querySelectorAll('[data-element="marathon-child__nav-item"]')
5941  const boxes = document.querySelectorAll('[data-element="marathon-child__box"]')
5942
5943  for (let i = 0; i < navItems.length; i++) {
5944    navItems[i].addEventListener('click', toggleBox)
5945  }
5946
5947  function toggleBox () {
5948    const oldNav = marathonChildThemes.querySelector('.marathon-child__nav-item_active')
5949    oldNav.classList.remove('marathon-child__nav-item_active')
5950    this.classList.add('marathon-child__nav-item_active')
5951    const oldBox = marathonChildThemes.querySelector('.marathon-child__box_active')
5952    oldBox.classList.remove('marathon-child__box_active')
5953    const index = this.getAttribute('data-index')
5954    boxes[index].classList.add('marathon-child__box_active')
5955  }
5956
5957  const marathonChildClose = document.querySelector('[data-element="marathon-child__close"]')
5958
5959  marathonChildThemes.addEventListener('click', openModal)
5960  marathonChildClose.addEventListener('click', closeModal)
5961  window.addEventListener('click', windowCloseModal)
5962
5963  function openModal () {
5964    marathonChildThemes.classList.add('marathon-child__themes_active')
5965  }
5966
5967  function closeModal (e) {
5968    e.stopPropagation()
5969    marathonChildThemes.classList.remove('marathon-child__themes_active')
5970  }
5971
5972  function windowCloseModal (e) {
5973    if (!e.target.classList.contains('marathon-child__themes') && !e.target.closest('.marathon-child__themes')) {
5974      marathonChildThemes.classList.remove('marathon-child__themes_active')
5975    }
5976  }
5977}
5978
5979const marathonInformer = document.querySelector('[data-element="marathon-informer"]')
5980
5981if (marathonInformer) marathonInformerInit()
5982
5983function marathonInformerInit () {
5984  const close = document.querySelector('[data-element="marathon-informer__close"]')
5985  close.addEventListener('click', removeMarathon)
5986
5987  function removeMarathon (e) {
5988    e.preventDefault()
5989    localStorage.setItem('isMarathonInformerShown', 'true')
5990    marathonInformer.remove()
5991  }
5992
5993  const isShown = localStorage.getItem('isMarathonInformerShown')
5994
5995  if (!isShown || marathonInformer.getAttribute('show-always')) {
5996    marathonInformer.style.display = 'block'
5997  }
5998}
5999
6000const marathonOrderSelect = document.querySelector("[data-element='marathon-order__select']")
6001
6002if (marathonOrderSelect) marathonOrderSelectInit()
6003
6004function marathonOrderSelectInit () {
6005  const button = document.querySelector("[data-element='marathon-order__button']")
6006  const priceOld = document.querySelector("[data-element='marathon-order__price-old']")
6007  const priceNew = document.querySelector("[data-element='marathon-order__price-new']")
6008  const opener = marathonOrderSelect.closest('.custom-select-container').querySelector('.custom-select-opener')
6009
6010  marathonOrderSelect.addEventListener('change', updateButton)
6011  button.addEventListener('click', validateButton)
6012
6013  function validateButton (e) {
6014    if (!marathonOrderSelect.value) {
6015      e.preventDefault()
6016      opener.classList.add('error')
6017    } else {
6018      window.open(button.href)
6019    }
6020  }
6021
6022  function updateButton () {
6023    opener.classList.remove('error')
6024
6025    const link = this.options[this.selectedIndex].getAttribute('data-product-link')
6026    const priceOldValue = this.options[this.selectedIndex].getAttribute('data-product-old-price')
6027    const priceNewValue = this.options[this.selectedIndex].getAttribute('data-product-new-price')
6028
6029    button.href = link
6030    if (priceOldValue) {
6031      priceOld.style.display = 'block'
6032      priceOld.innerHTML =`${priceOldValue}`
6033    } else {
6034      priceOld.style.display = 'none'
6035    }
6036    priceNew.innerHTML =`${priceNewValue}`
6037  }
6038}
6039
6040const maxDiscount = document.querySelector('.max-discount')
6041
6042if (maxDiscount) maxDiscountInit()
6043
6044function maxDiscountInit () {
6045  const stickyHeader = document.querySelector('.sticky-header')
6046  const timer = maxDiscount.querySelector('.max-discount__timer')
6047
6048  window.addEventListener('scroll', checkScroll, { passive: true })
6049
6050  function checkScroll () {
6051    if (window.scrollY > 100) {
6052      stickyHeader.classList.add('predzaps-top-hide')
6053      setTimeout(() => stickyHeader.classList.add('predzaps-top-hide-no-transition'), 300)
6054    } else if (window.scrollY <= 20) {
6055      stickyHeader.classList.remove('predzaps-top-hide-no-transition')
6056      setTimeout(() => stickyHeader.classList.remove('predzaps-top-hide'), 100)
6057    }
6058  }
6059
6060  if (timer) offerTimerInit(timer)
6061
6062  function offerTimerInit (timer) {
6063    const date = timer.getAttribute('date-end')
6064    const countDownDate = new Date(date).getTime()
6065
6066    const nodes = timer.querySelectorAll('.max-discount__number')
6067
6068    const interval = setInterval(updateTimer, 1000)
6069
6070    function updateTimer () {
6071      const now = new Date().getTime();
6072      const distance = countDownDate - now;
6073
6074      const days = Math.floor(distance / (1000 * 60 * 60 * 24))
6075      const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
6076      const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))
6077      const seconds = Math.floor((distance % (1000 * 60)) / 1000)
6078
6079      nodes[0].innerHTML = days
6080      nodes[1].innerHTML = hours
6081      nodes[2].innerHTML = minutes
6082      nodes[3].innerHTML = seconds
6083
6084      if (distance < 0) {
6085        clearInterval(interval);
6086        nodes[0].innerHTML = "0"
6087        nodes[1].innerHTML = "0"
6088        nodes[2].innerHTML = "0"
6089        nodes[3].innerHTML = "0"
6090      }
6091    }
6092  }
6093}
6094
6095(function () {
6096  const configs = [
6097    {
6098      id: 'offer-tile',
6099      itemSelector: '.offer-tile__item',
6100      tileSelector: '.offer-tile__tile',
6101      requestFromAttribute: true,
6102      isEnrich: false
6103    },
6104    {
6105      id: 'enrich-tile',
6106      itemSelector: '.all-courses__item',
6107      tileSelector: '.all-courses__tile',
6108      requestFromAttribute: false,
6109      isEnrich: true
6110    }
6111  ]
6112
6113  configs.forEach(initTile)
6114
6115  function initTile (config) {
6116    const root = document.getElementById(config.id)
6117    if (!root) return
6118
6119    const isEnrich = config.isEnrich
6120    const filterTops = root.querySelectorAll('.offer-tile__filter-top')
6121    const filterSubject = root.querySelector('.offer-tile__filter_subject')
6122    const filterClass = root.querySelector('.offer-tile__filter_class')
6123    const stickyHeader = document.querySelector('.sticky-header')
6124    const body = document.body
6125    const tile = root.querySelector(config.tileSelector)
6126    const classInputs = root.querySelectorAll('.offer-tile__filter-input_class')
6127    const subjectInputs = root.querySelectorAll('.offer-tile__filter-input_subject')
6128    const reset = root.querySelector('.offer-tile__reset-filter')
6129    const configObserver = {
6130      attributes: true,
6131      childList: true,
6132      characterData: true,
6133      subtree: true
6134    }
6135    const isSumPage = root.classList.contains('offer-tile_sum')
6136    const requestFunction = root.getAttribute('data-request-function')
6137    const filterSumr = root.querySelector('[data-role="filter-sumr"]')
6138    const filterNewy = root.querySelector('[data-role="filter-newy"]')
6139
6140    if (!filterTops.length || !filterSubject || !filterClass) return
6141
6142    initAnchorScroll()
6143    initFilterOpeners()
6144    initResetButtons()
6145    initInputs()
6146    initObserver()
6147    moreBtnInit()
6148
6149    if (isEnrich) {
6150      if (tile) togglePrice()
6151      initSimpleTabs()
6152    } else {
6153      sortSubjectsInit()
6154      initAdvancedTabs()
6155    }
6156
6157    function initAnchorScroll () {
6158      if (!window.location.href.includes(`#${config.id}`)) return
6159
6160      window.addEventListener('load', function () {
6161        const offset = window.innerWidth < 744 ? 60 : 80
6162
6163        window.scrollTo({
6164          top: root.getBoundingClientRect().top + window.scrollY - offset,
6165          behavior: 'smooth'
6166        })
6167      }, { once: true })
6168    }
6169
6170    function initFilterOpeners () {
6171      filterTops.forEach((opener) => {
6172        opener.addEventListener('click', (e) => openFilter(opener, e))
6173
6174        const wrap = opener.nextElementSibling
6175
6176        const informerButtons = wrap.querySelectorAll('.all-courses__filter-informer-button')
6177        informerButtons.forEach(informerButton => {
6178          informerButton.addEventListener('click', function () {
6179            const input = this.closest('.offer-tile__filter-box')?.querySelector("[data-element='offer-tile-filter-input']")
6180            if (input) {
6181              input.checked = true
6182              input.dispatchEvent(new Event('change', { bubbles: true }))
6183            }
6184          })
6185        })
6186      })
6187
6188      document.addEventListener('click', () => {
6189        filterTops.forEach((opener) => opener.classList.remove('active'))
6190        showHeader()
6191      })
6192    }
6193
6194    function openFilter (opener, e) {
6195      e.stopPropagation()
6196
6197      if (!opener.classList.contains('active')) {
6198        root.querySelector('.offer-tile__filter-top.active')?.classList.remove('active')
6199        root.querySelector('.offer-tile__filter.active')?.classList.remove('active')
6200        closeSelectFilter()
6201      }
6202
6203      if (opener.classList.contains('active')) {
6204        opener.classList.remove('active')
6205        opener.parentElement.classList.remove('active')
6206        showHeader()
6207      } else {
6208        opener.classList.add('active')
6209        opener.parentElement.classList.add('active')
6210        hideHeader()
6211      }
6212    }
6213
6214    function closeSelectFilter () {
6215      const opened = document.querySelector('.select-filter.active')
6216      if (!opened) return
6217
6218      opened.classList.remove('active')
6219      opened.querySelector('.select-filter__top')?.classList.remove('active')
6220    }
6221
6222    function showHeader () {
6223      stickyHeader?.classList.remove('hide')
6224      body.classList.remove('no-scroll')
6225    }
6226
6227    function hideHeader () {
6228      if (window.innerWidth < 744) {
6229        stickyHeader?.classList.add('hide')
6230        body.classList.add('no-scroll')
6231      }
6232    }
6233
6234    function initResetButtons () {
6235      if (isEnrich) {
6236        reset?.addEventListener('click', resetFilters)
6237        return
6238      }
6239
6240      const resetClassButton = filterClass.querySelector(
6241        '.offer-tile__filter-top-reset'
6242      )
6243
6244      const resetSubjectButton = filterSubject.querySelector(
6245        '.offer-tile__filter-top-reset'
6246      )
6247
6248      resetClassButton?.addEventListener('click', resetClass)
6249      resetSubjectButton?.addEventListener('click', () => resetSubject(true))
6250      reset?.addEventListener('click', resetFilters)
6251
6252      function resetClass () {
6253        const activeInput = filterClass.querySelector(
6254          '.offer-tile__filter-input:checked'
6255        )
6256
6257        if (!activeInput) return
6258
6259        activeInput.checked = false
6260        const defaultClassInput = filterClass.querySelector('input[value=""],input[value="all"]')
6261        if (defaultClassInput) defaultClassInput.checked = true
6262        resetClassButton.classList.remove('active')
6263        setTopText(filterTops[0], 'Все классы')
6264        resetSortSubjects()
6265        makeFiltration()
6266      }
6267
6268      function resetSubject (shouldFilter = false) {
6269        setTopText(filterTops[1], 'Все предметы')
6270        resetSubjectButton.classList.remove('active')
6271
6272        const activeInput = filterSubject.querySelector(
6273          '.offer-tile__filter-input:checked'
6274        )
6275
6276        if (activeInput) activeInput.checked = false
6277
6278        sortGradesInit()
6279
6280        if (shouldFilter) makeFiltration()
6281      }
6282    }
6283
6284    function resetFilters () {
6285      if (isEnrich) {
6286        root.querySelectorAll('input').forEach((input) => {
6287          input.checked =
6288            input.hasAttribute('data-default-garde') ||
6289            input.hasAttribute('data-default-subject')
6290        })
6291      } else {
6292        root.querySelectorAll('input').forEach((input) => {
6293          input.checked = false
6294        })
6295
6296        filterClass
6297          .querySelector('.offer-tile__filter-top-reset')
6298          ?.classList.remove('active')
6299
6300        filterSubject
6301          .querySelector('.offer-tile__filter-top-reset')
6302          ?.classList.remove('active')
6303
6304        resetSortSubjects()
6305        sortGradesInit()
6306      }
6307
6308      setTopText(filterTops[0], 'Все классы')
6309      setTopText(filterTops[1], 'Все предметы')
6310
6311      const defaultClassInput = filterClass.querySelector('input[value=""],input[value="all"]')
6312      if (defaultClassInput) defaultClassInput.checked = true
6313
6314      makeFiltration()
6315    }
6316
6317    function initInputs () {
6318      const updateEnrich = () => updateFilter()
6319      const updateOffer = (isClass) => updateFilter(isClass)
6320
6321      classInputs.forEach((input) => {
6322        input.addEventListener('change', () => {
6323          isEnrich ? updateEnrich() : updateOffer(true)
6324        })
6325
6326        input.addEventListener('change', changeClassInputText)
6327      })
6328
6329      subjectInputs.forEach((input) => {
6330        input.addEventListener('change', () => {
6331          isEnrich ? updateEnrich() : updateOffer(false)
6332        })
6333
6334        input.addEventListener('change', changeSubjectInputText)
6335      })
6336
6337      filterSumr?.addEventListener('change', updateFilter)
6338      filterNewy?.addEventListener('change', updateFilter)
6339    }
6340
6341    function changeClassInputText () {
6342      setTopText(filterTops[0], this.getAttribute('data-text'))
6343
6344      if (!isEnrich) {
6345        filterClass
6346          .querySelector('.offer-tile__filter-top-reset')
6347          ?.classList.toggle('active', this.value !== 'all' && this.value !== '')
6348      }
6349    }
6350
6351    function changeSubjectInputText () {
6352      setTopText(filterTops[1], this.getAttribute('data-text'))
6353
6354      if (!isEnrich) {
6355        filterSubject
6356          .querySelector('.offer-tile__filter-top-reset')
6357          ?.classList.add('active')
6358      }
6359    }
6360
6361    function setTopText (element, text) {
6362      if (element) {
6363        if (text === 'Все предметы' || text === 'Все классы') {
6364          element.innerHTML = `${text || ''}`
6365        } else {
6366          element.innerHTML = `<span>${text || ''}</span>`
6367        }
6368      }
6369    }
6370
6371    function updateFilter (isClassUpdated) {
6372      if (!isEnrich) {
6373        if (isClassUpdated) {
6374          sortSubjectsInit()
6375        } else {
6376          sortGradesInit()
6377        }
6378      }
6379
6380      makeFiltration()
6381    }
6382
6383    function selectedClass () {
6384      return filterClass.querySelector('input:checked')
6385    }
6386
6387    function sortSubjectsInit () {
6388      resetSortSubjects()
6389
6390      const subjects = selectedClass()?.getAttribute('data-subjects')
6391
6392      if (subjects) {
6393        hideAllSubjects()
6394        sortSubjects(subjects)
6395      }
6396    }
6397
6398    function sortGradesInit () {
6399      const checkedSubject = filterSubject.querySelector('input:checked')
6400      const hasSubject = !!checkedSubject
6401      const allowedGrades = getParsedData(checkedSubject, 'data-grades')
6402      filterBlockInputs(filterClass, allowedGrades, hasSubject)
6403    }
6404
6405    const getParsedData = (element, attribute) => {
6406      if (!element) return []
6407      try {
6408        const data = element.getAttribute(attribute)
6409        return data ? JSON.parse(data) : []
6410      } catch (e) {
6411        console.error(`Ошибка парсинга JSON в атрибуте ${attribute}:`, e)
6412        return []
6413      }
6414    }
6415
6416    const filterBlockInputs = (blockElement, allowedValues, hasActiveFilters) => {
6417      const inputs = blockElement.querySelectorAll('input')
6418      const allowedStrings = allowedValues.map(String)
6419
6420      inputs.forEach(input => {
6421        const parent = input.closest('.offer-tile__filter-item')
6422        if (!parent || input.value === "" || input.value === "all") return
6423
6424        const dataItemId = input.getAttribute('data-item-id')
6425        const inputValues = dataItemId ? [dataItemId] : input.value.split('|')
6426
6427        const isAllowed = inputValues.some(val => allowedStrings.includes(val))
6428        const isForbidden = hasActiveFilters && !isAllowed
6429
6430        parent.classList.toggle('disabled', isForbidden)
6431      })
6432    }
6433
6434    function sortSubjects (subjectsJSON) {
6435      let subjectsParsed
6436
6437      try {
6438        subjectsParsed = JSON.parse(subjectsJSON)
6439      } catch (e) {
6440        return
6441      }
6442
6443      if (!subjectsParsed) return
6444
6445      let activeTabSet = false
6446
6447      const allowedSubjects = new Set(subjectsParsed.map(String))
6448
6449      subjectInputs.forEach((subject) => {
6450        const dataItemId = subject.getAttribute('data-item-id')
6451        const inputValues = dataItemId ? [dataItemId] : subject.value.split('|')
6452        const isAllowed = inputValues.some(val => allowedSubjects.has(val))
6453        if (!isAllowed) return
6454
6455        const label = subject.closest('.offer-tile__filter-item')
6456        if (!label) return
6457
6458        label.style.display = 'block'
6459
6460        const index = label.getAttribute('data-index')
6461
6462        const tab = filterSubject.querySelector(
6463          `.offer-tile__filter-tab[data-index="${index}"]`
6464        )
6465
6466        if (tab) {
6467          tab.classList.remove('hide')
6468
6469          if (!activeTabSet) {
6470            tab.click()
6471            activeTabSet = true
6472          }
6473        }
6474      })
6475
6476      updateTabsCounters()
6477    }
6478
6479    function updateTabsCounters () {
6480      const wrap = filterSubject.querySelector('.offer-tile__filter-wrap')
6481      const boxes = wrap?.querySelectorAll('.offer-tile__filter-box') || []
6482
6483      boxes.forEach((box) => {
6484        const index = box.getAttribute('data-index')
6485        const tab = wrap.querySelector(`[data-index="${index}"]`)
6486        const labels = box.querySelectorAll('[style*="display: block"]')
6487        const counter = tab?.querySelector('span')
6488        const title = box.previousElementSibling
6489
6490        if (counter) counter.innerText = labels.length
6491
6492        box.classList.toggle('hide-mob', labels.length === 0)
6493        title?.classList.toggle('hide-mob', labels.length === 0)
6494      })
6495    }
6496
6497    function hideAllSubjects () {
6498      filterSubject
6499        .querySelectorAll('.offer-tile__filter-tab')
6500        .forEach((tab) => tab.classList.add('hide'))
6501
6502      filterSubject
6503        .querySelector('.offer-tile__filter-tab.active')
6504        ?.classList.remove('active')
6505
6506      filterSubject
6507        .querySelectorAll('.offer-tile__filter-item')
6508        .forEach((item) => {
6509          item.style.display = 'none'
6510        })
6511    }
6512
6513    function resetSortSubjects () {
6514      filterSubject
6515        .querySelectorAll('.offer-tile__filter-tab')
6516        .forEach((tab) => tab.classList.remove('hide'))
6517
6518      filterSubject
6519        .querySelector('.offer-tile__filter-tab.active')
6520        ?.classList.remove('active')
6521
6522      filterSubject
6523        .querySelector('.offer-tile__filter-tab')
6524        ?.click()
6525
6526      filterSubject
6527        .querySelectorAll('.offer-tile__filter-item')
6528        .forEach((item) => {
6529          item.style.display = 'block'
6530        })
6531
6532      updateTabsCounters()
6533    }
6534
6535    function initObserver () {
6536      if (!tile) return
6537
6538      const observer = new MutationObserver((mutations) => {
6539        mutations.forEach((mutation) => {
6540          if (!mutation.addedNodes.length) return
6541
6542          mutation.addedNodes.forEach((node) => {
6543            if (!node?.classList?.contains(config.itemSelector.slice(1))) return
6544
6545            dataHrefLinksInit(node)
6546
6547            if (isEnrich) togglePrice(node)
6548
6549            fancyboxAjaxCardsReInit(node)
6550            initCommonAnalytics(node)
6551          })
6552        })
6553
6554        moreBtnInit()
6555      })
6556
6557      observer.observe(tile, configObserver)
6558    }
6559
6560    function togglePrice (node) {
6561      const items = node
6562        ? [node]
6563        : [...tile.querySelectorAll('.all-courses__item')]
6564
6565      items.forEach((item) => {
6566        const toggles = item.querySelectorAll('.all-courses__radio-input')
6567
6568        if (!toggles.length) return
6569
6570        const boxes = item.querySelectorAll('.all-courses__box')
6571        const textReplace = item.querySelector('.all-courses__info.text-replace')
6572        const texts = textReplace?.querySelectorAll('.all-courses__info-span')
6573
6574        toggles.forEach((toggle) => {
6575          toggle.addEventListener('change', () => toggleElements(boxes))
6576
6577          if (texts) {
6578            toggle.addEventListener('change', () => toggleElements(texts))
6579          }
6580        })
6581      })
6582    }
6583
6584    function toggleElements (elements) {
6585      elements.forEach((element) => element.classList.toggle('hide'))
6586    }
6587
6588    function moreBtnInit () {
6589      const moreBtn = root.querySelector('.all-courses__more-button')
6590
6591      if (!moreBtn) return
6592
6593      const newBtn = replaceBtn(moreBtn)
6594
6595      newBtn.addEventListener('click', () => {
6596        makeFiltration(newBtn.getAttribute('data-v'))
6597      })
6598    }
6599
6600    function replaceBtn (element) {
6601      const newElement = element.cloneNode(true)
6602
6603      element.parentNode.replaceChild(newElement, element)
6604
6605      return newElement
6606    }
6607
6608    function makeFiltration (page = 1) {
6609      const activeClass = filterClass.querySelector('input:checked')
6610      const activeSubject = filterSubject.querySelector('input:checked')
6611
6612      if (!activeSubject && (activeClass?.value === "" || activeClass?.value === "all")) {
6613        if (reset) reset.style.display = 'none'
6614      } else {
6615        if (reset) reset.style.display = 'flex'
6616      }
6617
6618      const gradesResult = [
6619        ...root.querySelectorAll(
6620          '.offer-tile__filter-input_class:checked'
6621        )
6622      ].map((item) => item.value).join('|')
6623
6624      const subjectsResult = [
6625        ...root.querySelectorAll(
6626          '.offer-tile__filter-input_subject:checked'
6627        )
6628      ].map((item) => item.value).join('|')
6629
6630      const requestData = {
6631        grade: gradesResult,
6632        subject: subjectsResult,
6633        utm_t: tile?.getAttribute('data-utm'),
6634        promo: tile?.getAttribute('data-promo'),
6635        pagePaginate: page
6636      }
6637
6638      if (isEnrich) {
6639        requestData.summerny = getSummerny()
6640      }
6641
6642      if (page === 1) {
6643        $('.filtered_elements').html("<div class='tile-loader'></div>")
6644        $('.more_b').html('')
6645      }
6646
6647      $.request(
6648        isEnrich
6649          ? 'DirectionFunctions::onPaginateAllCourses'
6650          : requestFunction,
6651        {
6652          data: requestData
6653        }
6654      )
6655
6656      if (!isEnrich && isSumPage && gradesResult && gradesResult !== 'all') {
6657
6658        const url = new URL(window.location.href)
6659        url.searchParams.set('gr', gradesResult.split('|')[0])
6660        history.replaceState(null, '', url.toString())
6661
6662      } else if (gradesResult === 'all') {
6663
6664        const url = new URL(window.location.href)
6665        url.searchParams.delete('gr')
6666        history.replaceState(null, '', url.toString())
6667
6668      }
6669    }
6670
6671    function getSummerny () {
6672      if (filterSumr?.checked) {
6673        return filterSumr.getAttribute('data-value') || ''
6674      }
6675
6676      if (filterNewy?.checked) {
6677        return filterNewy.getAttribute('data-value') || ''
6678      }
6679
6680      return ''
6681    }
6682
6683    function initSimpleTabs () {
6684      const tabsParent = filterSubject.querySelector(
6685        '.offer-tile__filter-tabs'
6686      )
6687
6688      const tabs = filterSubject.querySelectorAll(
6689        '.offer-tile__filter-tab'
6690      )
6691
6692      const subjects = filterSubject.querySelectorAll(
6693        '.offer-tile__filter-item'
6694      )
6695
6696      if (!tabs.length || !subjects.length) return
6697
6698      tabs.forEach((tab) => {
6699        tab.addEventListener('click', (e) => {
6700          e.stopPropagation()
6701
6702          filterSubject
6703            .querySelector('.offer-tile__filter-tab.active')
6704            ?.classList.remove('active')
6705
6706          tab.classList.add('active')
6707
6708          subjects.forEach((subject) => {
6709            subject.classList.add('hide')
6710          })
6711
6712          const index = tab.getAttribute('data-index')
6713
6714          filterSubject
6715            .querySelectorAll(`[data-index="${index}"]`)
6716            .forEach((subject) => {
6717              subject.classList.remove('hide')
6718            })
6719
6720          if (tabsParent) {
6721            tabsParent.scrollLeft =
6722              tab.offsetLeft -
6723              tabsParent.clientWidth / 2 +
6724              tab.clientWidth / 2
6725          }
6726        })
6727      })
6728
6729      tabs[0].click()
6730    }
6731
6732    function initAdvancedTabs () {
6733      const wrap = filterSubject.querySelector(
6734        '.offer-tile__filter-wrap'
6735      )
6736
6737      const tabsParent = wrap?.querySelector(
6738        '.offer-tile__filter-tabs'
6739      )
6740
6741      const list = wrap?.querySelector(
6742        '.offer-tile__filter-list'
6743      )
6744
6745      const tabs = wrap?.querySelectorAll(
6746        '.offer-tile__filter-tab'
6747      ) || []
6748
6749      const boxes = wrap?.querySelectorAll(
6750        '.offer-tile__filter-box'
6751      ) || []
6752
6753      const headline = filterSubject.querySelector(
6754        '.offer-tile__filter-headline.desk'
6755      )
6756
6757      if (!wrap || !tabs.length || !boxes.length) return
6758
6759      let timeout
6760      let firstToggle = true
6761
6762      const toggle = (tab, event) => {
6763        if (
6764          !tab.closest('.offer-tile__filter-wrap')
6765            ?.querySelector('.offer-tile__filter-tab:hover') &&
6766          !firstToggle &&
6767          event.type !== 'click'
6768        ) {
6769          return
6770        }
6771
6772        firstToggle = false
6773
6774        wrap.removeEventListener('scroll', onScroll)
6775
6776        wrap
6777          .querySelector('.offer-tile__filter-tab.active')
6778          ?.classList.remove('active')
6779
6780        tab.classList.add('active')
6781
6782        if (headline) {
6783          headline.innerHTML = tab.getAttribute('data-text') || ''
6784        }
6785
6786        boxes.forEach((box) => {
6787          box.classList.add('hide')
6788
6789          if (
6790            box.previousElementSibling?.classList.contains(
6791              'all-courses__filter-box-title'
6792            )
6793          ) {
6794            box.previousElementSibling.style.display = 'none'
6795          }
6796        })
6797
6798        const index = tab.getAttribute('data-index')
6799
6800        const activeBox = list?.querySelector(
6801          `[data-index="${index}"]`
6802        )
6803
6804        if (activeBox) {
6805          activeBox.classList.remove('hide')
6806
6807          if (activeBox.previousElementSibling) {
6808            activeBox.previousElementSibling.style.display = ''
6809          }
6810
6811          wrap.scrollTop = activeBox.offsetTop - 150
6812        }
6813
6814        if (tabsParent) {
6815          tabsParent.scrollLeft =
6816            tab.offsetLeft -
6817            tabsParent.clientWidth / 2 +
6818            tab.clientWidth / 2
6819        }
6820
6821        setTimeout(() => {
6822          wrap.addEventListener('scroll', onScroll, { passive: true })
6823        }, 200)
6824      }
6825
6826      const onScroll = () => {
6827        const visibleBoxes = [...boxes].filter(
6828          (box) => !box.classList.contains('hide-mob')
6829        )
6830
6831        visibleBoxes.forEach((box) => {
6832          if (wrap.scrollTop >= box.offsetTop - 155) {
6833            wrap
6834              .querySelector('.offer-tile__filter-tab.active')
6835              ?.classList.remove('active')
6836
6837            const tab = wrap.querySelector(
6838              `[data-index="${box.getAttribute('data-index')}"]`
6839            )
6840
6841            if (tab) {
6842              tab.classList.add('active')
6843
6844              if (tabsParent) {
6845                tabsParent.scrollLeft =
6846                  tab.offsetLeft -
6847                  tabsParent.clientWidth / 2 +
6848                  tab.clientWidth / 2
6849              }
6850            }
6851          }
6852        })
6853      }
6854
6855      wrap.addEventListener('scroll', onScroll, { passive: true })
6856
6857      tabs.forEach((tab) => {
6858        const handler = (event) => {
6859          clearTimeout(timeout)
6860          event.stopPropagation()
6861          timeout = setTimeout(() => toggle(tab, event), 100)
6862        }
6863
6864        tab.addEventListener('click', handler)
6865        tab.addEventListener('mouseenter', handler)
6866      })
6867
6868      tabs[0]?.click()
6869    }
6870  }
6871})()
6872
6873
6874$("[data-fancybox]").fancybox({
6875  beforeShow: function(instance){
6876    try {
6877      const form = document.querySelector(this.src)
6878      const openButton = instance.current.opts.$orig
6879      if (form) {
6880        setDataFtitle(openButton, form)
6881        setBannerName(openButton, form)
6882      }
6883    } catch (e) {}
6884  },
6885  afterClose: function() {
6886    try {
6887      const form = document.querySelector(this.src)
6888      if (form) {
6889        setDefaultDataFtitle(form)
6890        setDefaultBannerName(form)
6891      }
6892    } catch (e) {}
6893  }
6894})
6895
6896function setBannerName (button, form) {
6897  const input = form.querySelector('input[name="banner_v"]')
6898  const value = button.attr('data-banner')
6899  if (input && value) input.value = value
6900}
6901
6902function setDefaultBannerName (form) {
6903  const input = form.querySelector('input[name="banner_v"]')
6904  if (input) input.value = ''
6905}
6906
6907function setDataFtitle (button, form) {
6908  const title = button.attr('data-ftitle')
6909  const titleTag = form.querySelector('.modal-order-new__title')
6910  if (title && title?.length > 1 && titleTag) {
6911    titleTag.innerHTML = title
6912  }
6913}
6914
6915function setDefaultDataFtitle (form) {
6916  const titleTag = form.querySelector('.modal-order-new__title')
6917  if (titleTag) {
6918    const defaultTitle = titleTag.getAttribute('data-default-title')
6919    if (defaultTitle) titleTag.innerHTML = defaultTitle
6920  }
6921}
6922
6923
6924const modalOrderNewSelects = document.querySelectorAll(".modal-order-new__select")
6925
6926for (let i = 0; i < modalOrderNewSelects.length; i++) {
6927  modalOrderNewSelectInit(modalOrderNewSelects[i])
6928}
6929
6930function modalOrderNewSelectInit (modalOrderNewSelect) {
6931  const top = modalOrderNewSelect.querySelector('.modal-order-new__select-top')
6932  const placeholder = modalOrderNewSelect.querySelector('.modal-order-new__select-placeholder')
6933  const inputs = modalOrderNewSelect.querySelectorAll('.modal-order-new__select-input')
6934
6935  for (let i = 0; i < inputs.length; i++) {
6936    inputs[i].addEventListener('change', setValue)
6937  }
6938
6939  top.addEventListener('click', openSelect)
6940  window.addEventListener('click', closeSelect)
6941
6942  function openSelect (e) {
6943    e.stopPropagation()
6944    top.classList.toggle('active')
6945  }
6946
6947  function closeSelect () {
6948    top.classList.remove('active')
6949  }
6950
6951  function setValue () {
6952    placeholder.innerHTML = this.parentElement.querySelector('.modal-order-new__select-view').innerHTML
6953  }
6954}
6955
6956const nav = document.querySelector('.header .nav')
6957 
6958 if (nav) navInit()
6959 
6960 function navInit () {
6961   const buttons = nav.querySelectorAll('button.nav__box-link')
6962   const headerArea = document.querySelector('.header__area')
6963   const navBackButtons = nav.querySelectorAll('.nav__back')
6964   const navScrollers = nav.querySelectorAll('.nav__scroller')
6965   const navLeftScroller = nav.querySelector('.nav__left-scroller')
6966   let timeout
6967 
6968   for (let i = 0; i < buttons.length; i++) {
6969     buttons[i].addEventListener('click', toggleArea)
6970     buttons[i].addEventListener('mouseenter', toggleArea)
6971   }
6972 
6973   for (let i = 0; i < navBackButtons.length; i++) {
6974     navBackButtons[i].addEventListener('click', backArea)
6975   }
6976 
6977   function backArea () {
6978     const activeArea = nav.querySelector('.nav__area.active-mob')
6979     if (activeArea) activeArea.classList.remove('active-mob')
6980     headerArea.classList.remove('hide')
6981   }
6982 
6983   function toggleArea () {
6984     clearTimeout(timeout)
6985     timeout = setTimeout(() => toggle(this),50)
6986 
6987     function toggle (that) {
6988       if (!that.closest('.nav__left').querySelector('.nav__box-link:hover')) return
6989       const id = that.getAttribute('data-nav-id')
6990       const oldArea = nav.querySelector('.nav__area.active')
6991       if (oldArea) oldArea.classList.remove('active')
6992       if (oldArea) oldArea.classList.remove('active-mob')
6993       const oldButton = nav.querySelector('button.nav__box-link.active')
6994       if (oldButton) oldButton.classList.remove('active')
6995       const area = nav.querySelector("[data-nav-area='" + id + "']")
6996       if (area) area.classList.add('active')
6997       if (area) area.classList.add('active-mob')
6998       headerArea.classList.add('hide')
6999       that.classList.add('active')
7000     }
7001   }
7002   initSimpleBar()
7003
7004      function initSimpleBar () {
7005        if (window.innerWidth >= 744) {
7006          for (let i = 0; i < navScrollers.length; i++) {
7007            new SimpleBar(navScrollers[i])
7008          }
7009          new SimpleBar(navLeftScroller)
7010        }
7011      }
7012 }
7013 
7014// const enrichTile = document.getElementById("enrich-tile")
7015
7016// if (enrichTile) enrichTileInit()
7017
7018// function enrichTileInit () {
7019//   if (window.location.href.includes('#enrich-tile')) {
7020//     window.addEventListener('load', function() {
7021//       let offset
7022//       if (window.innerWidth < 744) {
7023//         offset = 60
7024//       } else if (window.innerWidth < 1200) {
7025//         offset = 80
7026//       } else {
7027//         offset = 80
7028//       }
7029//       window.scrollTo({
7030//         top: enrichTile.getBoundingClientRect().top + window.scrollY - offset,
7031//         behavior: 'smooth'
7032//       })
7033//     }, { once: true })
7034//   }
7035
7036//   const enrichTileFilterTops = enrichTile.querySelectorAll(".offer-tile__filter-top")
7037//   const filterSubject = enrichTile.querySelector(".offer-tile__filter_subject")
7038//   const filterClass = enrichTile.querySelector(".offer-tile__filter_class")
7039//   const stickyHeader = document.querySelector('.sticky-header')
7040//   const body = document.querySelector('body')
7041//   const filterSumr = enrichTile.querySelector('[data-role="filter-sumr"]')
7042//   const filterNewy = enrichTile.querySelector('[data-role="filter-newy"]')
7043
7044//   filterSumr?.addEventListener('change', updateFilter)
7045//   filterNewy?.addEventListener('change', updateFilter)
7046
7047
7048//   enrichTileFilterTops[0].addEventListener("click", (e)=> openFilter(enrichTileFilterTops[0], e))
7049//   enrichTileFilterTops[1].addEventListener("click", (e)=> openFilter(enrichTileFilterTops[1], e))
7050
7051//   document.addEventListener('click', function () {
7052//     enrichTileFilterTops[0].classList.remove('active')
7053//     enrichTileFilterTops[1].classList.remove('active')
7054//     showHeader()
7055//   })
7056
7057//   function openFilter (opener, e) {
7058//     e.stopPropagation()
7059//     if (!opener.classList.contains('active')) {
7060//       const oldActive = enrichTile.querySelector('.offer-tile__filter-top.active')
7061//       if (oldActive) oldActive.classList.remove('active')
7062//       const oldActiveFilter = enrichTile.querySelector('.offer-tile__filter.active')
7063//       if (oldActiveFilter) oldActiveFilter.classList.remove('active')
7064//       closeSelectFilter()
7065//     }
7066//     if (opener.classList.contains('active')) {
7067//       opener.classList.remove('active')
7068//       showHeader()
7069//       opener.parentElement.classList.remove('active')
7070//     } else {
7071//       opener.classList.add('active')
7072//       opener.parentElement.classList.add('active')
7073//       hideHeader()
7074//     }
7075//   }
7076
7077//   function closeSelectFilter () {
7078//     const oldSelectFilterOpen = document.querySelector(".select-filter.active")
7079//     if (oldSelectFilterOpen) {
7080//       oldSelectFilterOpen.classList.remove('active')
7081//       oldSelectFilterOpen.querySelector('.select-filter__top').classList.remove('active')
7082//     }
7083//   }
7084
7085//   function showHeader () {
7086//     stickyHeader.classList.remove('hide')
7087//     body.classList.remove('no-scroll')
7088//   }
7089
7090//   function hideHeader () {
7091//     if (window.innerWidth < 744) {
7092//       stickyHeader.classList.add('hide')
7093//       body.classList.add('no-scroll')
7094//     }
7095//   }
7096
7097//   const config = { attributes: true, childList: true, characterData: true, subtree: true }
7098//   const tile = enrichTile.querySelector('.all-courses__tile')
7099//   const classInputs = enrichTile.querySelectorAll('.offer-tile__filter-input_class')
7100//   const classInputText = enrichTile.querySelector('.offer-tile__filter_class .offer-tile__filter-top-text')
7101//   const subjectInputs = enrichTile.querySelectorAll('.offer-tile__filter-input_subject')
7102//   const subjectInputText = enrichTile.querySelector('.offer-tile__filter_subject .offer-tile__filter-top-text')
7103
7104//   const observer = new MutationObserver(function observerCallback(mutations) {
7105//     mutations.forEach(
7106//       (mutation) => {
7107//         if (mutation.addedNodes.length) {
7108//           mutation.addedNodes.forEach((node) => {
7109//             if (node?.classList?.contains('all-courses__item')) {
7110//               dataHrefLinksInit(node)
7111//               togglePrice(node)
7112//               fancyboxAjaxCardsReInit(node)
7113//               initCommonAnalytics(node)
7114//             }
7115//           })
7116//         }
7117//       })
7118
7119//     moreBtnInit()
7120//   })
7121
7122//   if (tile) togglePrice()
7123
7124//   function togglePrice (node) {
7125//     if (node) {
7126//       togglePriceHandler(node)
7127//     } else {
7128//       const items = tile?.querySelectorAll(".all-courses__item")
7129//       items.forEach((item) => {
7130//         togglePriceHandler(item)
7131//       })
7132//     }
7133//     function togglePriceHandler (item) {
7134//       const toggle = item.querySelectorAll('.all-courses__radio-input')
7135//       if (!toggle.length) return
7136//       const boxes = item.querySelectorAll('.all-courses__box')
7137//       const textReplace = item.querySelector('.all-courses__info.text-replace')
7138//       let texts
7139//       if (textReplace) {
7140//         texts = textReplace.querySelectorAll('.all-courses__info-span')
7141//       }
7142//       for (let i = 0; i < toggle.length; i++) {
7143//         toggle[i].addEventListener('change', toggleBoxes)
7144//         if (texts) toggle[i].addEventListener('change', toggleTexts)
7145//       }
7146
7147//       function toggleBoxes () {
7148//         for (let i = 0; i < boxes.length; i++) {
7149//           if (boxes[i].classList.contains('hide')) {
7150//             boxes[i].classList.remove('hide')
7151//           } else {
7152//             boxes[i].classList.add('hide')
7153//           }
7154//         }
7155//       }
7156
7157//       function toggleTexts () {
7158//         for (let i = 0; i < texts.length; i++) {
7159//           if (texts[i].classList.contains('hide')) {
7160//             texts[i].classList.remove('hide')
7161//           } else {
7162//             texts[i].classList.add('hide')
7163//           }
7164//         }
7165//       }
7166//     }
7167//   }
7168
7169
7170  
7171
7172
7173//   if (tile) observer.observe(tile, config)
7174
7175//   const reset = enrichTile.querySelector('.offer-tile__reset-filter')
7176//   if (reset) reset.addEventListener('click', resetFilters)
7177
7178//   function resetFilters () {
7179//     const items = enrichTile.querySelectorAll("input")
7180//     items.forEach((item) => {
7181//       if (item.hasAttribute('data-default-garde') || item.hasAttribute('data-default-subject')) {
7182//         item.checked = true
7183//       }else{
7184//         item.checked = false
7185//       }
7186//     })
7187//     reset.style.display = 'none'
7188//     classInputText.innerHTML = "Все классы"
7189//     subjectInputText.innerHTML = "Все предметы"
7190//     makeFiltration();
7191//   }
7192
7193//   for (let i = 0; i < classInputs.length; i++) {
7194//     classInputs[i].addEventListener('change', updateFilter)
7195//     classInputs[i].addEventListener('change', changeClassInputText)
7196//   }
7197
7198//   function changeClassInputText () {
7199//     classInputText.innerHTML = this.getAttribute('data-text')
7200//   }
7201
7202//   for (let i = 0; i < subjectInputs.length; i++) {
7203//     subjectInputs[i].addEventListener('change', updateFilter)
7204//     subjectInputs[i].addEventListener('change', changeSubjectInputText)
7205//   }
7206
7207//   function changeSubjectInputText () {
7208//     subjectInputText.innerHTML = this.getAttribute('data-text')
7209//   }
7210
7211//   moreBtnInit()
7212
7213//   function moreBtnInit () {
7214//     const moreBtn = enrichTile.querySelector('.all-courses__more-button')
7215//     if (moreBtn) {
7216//       const newBtn = replaceBtn(moreBtn)
7217//       newBtn.addEventListener('click', () => makeFiltration(newBtn.getAttribute('data-v')))
7218//     }
7219//   }
7220
7221//   function replaceBtn (oldElement) {
7222//     const newElement = oldElement.cloneNode(true)
7223//     oldElement.parentNode.replaceChild(newElement, oldElement)
7224//     return newElement
7225//   }
7226
7227
7228//   function updateFilter () {
7229//     const itemsAll = enrichTile.querySelectorAll(["input:checked"])
7230//     if (itemsAll.length) {
7231//       if (reset) reset.style.display = 'flex'
7232//     } else {
7233//       if (reset) reset.style.display = 'none'
7234//     }
7235//     makeFiltration()
7236//   }
7237
7238//   function makeFiltration (p_paginate = 1) {
7239//     const grades_items = enrichTile.querySelectorAll('.offer-tile__filter-input_class:checked')
7240//     let grades_result = ''
7241//     let grade_first = 0
7242//     grades_items.forEach((item, i) => {
7243//       if (i > 0) grades_result += '|'
7244//       if (grade_first == 0) grade_first = item.value
7245//       grades_result += item.value
7246//     })
7247//     let subjects_result = ''
7248//     try{
7249//       const subjects_items = enrichTile.querySelectorAll('.offer-tile__filter-input_subject:checked')
7250//       subjects_items.forEach((item, i) => {
7251//         if (i > 0) subjects_result += '|'
7252//         subjects_result += item.value
7253//       })
7254//     }catch(e){}
7255
7256//     let utm_f = tile.getAttribute('data-utm');
7257//     let promo_f = tile.getAttribute('data-promo');
7258//     // let oge_ege_type = tile.getAttribute('data-oge-ege');
7259
7260//     if(p_paginate === 1 ){
7261//       $('.filtered_elements').html("<div class='tile-loader'></div>");
7262//       $('.more_b').html("");
7263//     }
7264
7265    
7266//     var obData = {
7267//       'grade': grades_result,
7268//       'subject': subjects_result,
7269//       'utm_t': utm_f,
7270//       'promo': promo_f,
7271//       'pagePaginate': p_paginate,
7272//       'summerny': getSummerny(),
7273//     };
7274//     $.request('DirectionFunctions::onPaginateAllCourses', {
7275//       data: obData
7276//     })
7277//     // if (grade_first > 0){
7278//     //   let url = new URL(window.location.href)
7279//     //   url.searchParams.set('gr', grade_first);
7280//     //   history.replaceState(null, "", url.toString())
7281//     // }
7282//     // }
7283//   }
7284//   function getSummerny () {
7285//     let summerny = ''
7286//     if (filterSumr?.checked) {
7287//       summerny = filterSumr.getAttribute('data-value')
7288//     } else if (filterNewy?.checked) {
7289//       summerny = filterNewy.getAttribute('data-value')
7290//     }
7291//     return summerny
7292//   }
7293
7294
7295//   initTabs()
7296
7297//   function initTabs () {
7298//     const tabsParent = filterSubject.querySelector('.offer-tile__filter-tabs')
7299//     const tabs = filterSubject.querySelectorAll('.offer-tile__filter-tab')
7300//     const subjects = filterSubject.querySelectorAll('.offer-tile__filter-item')
7301
7302//     if (!tabs.length || !subjects.length) return
7303
7304//     tabs.forEach((tab) => {
7305//       tab.addEventListener('click', changeTab)
7306
7307//       function changeTab (e) {
7308//         e.stopPropagation()
7309//         const oldTab = filterSubject.querySelector('.offer-tile__filter-tab.active')
7310//         if (oldTab) oldTab.classList.remove('active')
7311
7312//         this.classList.add('active')
7313
7314//         subjects.forEach((subject) => {
7315//           subject.classList.add('hide')
7316//         })
7317
7318//         const index = this.getAttribute('data-index')
7319//         const activeSubjects = filterSubject.querySelectorAll('[data-index="' + index + '"]')
7320//         activeSubjects.forEach((subject) => {
7321//           subject.classList.remove('hide')
7322//         })
7323
7324//         tabsParent.scrollLeft = this.offsetLeft - tabsParent.clientWidth/2 + this.clientWidth/2
7325//       }
7326//     })
7327
7328//     tabs[0].click()
7329//   }
7330  
7331// }
7332
7333// const offerTile = document.getElementById("offer-tile")
7334
7335// if (offerTile) offerTileInit()
7336
7337// function offerTileInit () {
7338//   if (window.location.href.includes('#offer-tile')) {
7339//     window.addEventListener('load', function() {
7340//       let offset
7341//       if (window.innerWidth < 744) {
7342//         offset = 60
7343//       } else if (window.innerWidth < 1200) {
7344//         offset = 80
7345//       } else {
7346//         offset = 80
7347//       }
7348//       window.scrollTo({
7349//         top: offerTile.getBoundingClientRect().top + window.scrollY - offset,
7350//         behavior: 'smooth'
7351//       })
7352//     }, { once: true })
7353//   }
7354
7355//   const offerTileFilterTops = offerTile.querySelectorAll(".offer-tile__filter-top")
7356//   const filterSubject = offerTile.querySelector(".offer-tile__filter_subject")
7357//   const filterClass = offerTile.querySelector(".offer-tile__filter_class")
7358//   const stickyHeader = document.querySelector('.sticky-header')
7359//   const body = document.querySelector('body')
7360//   const isSumPage = offerTile.classList.contains('offer-tile_sum')
7361//   const requestFunction = offerTile.getAttribute('data-request-function')
7362//   const openers = offerTile.querySelectorAll(".offer-tile__filter-top")
7363//   const config = { attributes: true, childList: true, characterData: true, subtree: true }
7364//   const tile = offerTile.querySelector('.offer-tile__tile')
7365//   const classInputs = offerTile.querySelectorAll('.offer-tile__filter-input_class')
7366//   const classInputText = offerTile.querySelector('.offer-tile__filter_class .offer-tile__filter-top-text')
7367//   const subjectInputs = offerTile.querySelectorAll('.offer-tile__filter-input_subject')
7368//   const subjectInputText = offerTile.querySelector('.offer-tile__filter_subject .offer-tile__filter-top-text')
7369
7370
7371
7372//   offerTileFilterTops[0].addEventListener("click", (e)=> openFilter(offerTileFilterTops[0], e))
7373//   offerTileFilterTops[1].addEventListener("click", (e)=> openFilter(offerTileFilterTops[1], e))
7374
7375//   document.addEventListener('click', function () {
7376//     offerTileFilterTops[0].classList.remove('active')
7377//     offerTileFilterTops[1].classList.remove('active')
7378//     showHeader()
7379//   })
7380
7381//   function openFilter (opener, e) {
7382//     e.stopPropagation()
7383//     if (opener.getAttribute('data-ftype') === 'class_subjects' && !selectedClass() && isSumPage) {
7384//       setError()
7385//       return
7386//     } else {
7387//       resetError()
7388//     }
7389//     if (!opener.classList.contains('active')) {
7390//       const oldActive = offerTile.querySelector('.offer-tile__filter-top.active')
7391//       if (oldActive) oldActive.classList.remove('active')
7392//       const oldActiveFilter = offerTile.querySelector('.offer-tile__filter.active')
7393//       if (oldActiveFilter) oldActiveFilter.classList.remove('active')
7394//     }
7395//     if (opener.classList.contains('active')) {
7396//       opener.classList.remove('active')
7397//       showHeader()
7398//       opener.parentElement.classList.remove('active')
7399//     } else {
7400//       opener.classList.add('active')
7401//       opener.parentElement.classList.add('active')
7402//       hideHeader()
7403//     }
7404//   }
7405
7406//   function showHeader () {
7407//     stickyHeader.classList.remove('hide')
7408//     body.classList.remove('no-scroll')
7409//   }
7410
7411//   function hideHeader () {
7412//     if (window.innerWidth < 744) {
7413//       stickyHeader.classList.add('hide')
7414//       body.classList.add('no-scroll')
7415//     }
7416//   }
7417
7418  
7419
7420//   const observer = new MutationObserver(function observerCallback(mutations) {
7421//     mutations.forEach(
7422//       (mutation) => {
7423//         if (mutation.addedNodes.length) {
7424//           mutation.addedNodes.forEach((node) => {
7425//             if (node?.classList?.contains('offer-tile__item')) {
7426//               dataHrefLinksInit(node)
7427//               fancyboxAjaxCardsReInit(node)
7428//               initCommonAnalytics(node)
7429//             }
7430//           })
7431//         }
7432//       })
7433//     moreBtnInit()
7434//   })
7435
7436//   if (tile) observer.observe(tile, config)
7437
7438//   const reset = offerTile.querySelector('.offer-tile__reset-filter')
7439//   if (reset) reset.addEventListener('click', resetFilters)
7440
7441//   function resetFilters () {
7442//     const items = offerTile.querySelectorAll("input")
7443//     items.forEach((item) => {
7444//       if (item.hasAttribute('data-default-garde') || item.hasAttribute('data-default-subject')) {
7445//         item.checked = true
7446//       }else{
7447//         item.checked = false
7448//       }
7449//     })
7450//     reset.style.display = 'none'
7451//     classInputText.innerHTML = "Все классы"
7452//     subjectInputText.innerHTML = "Все предметы"
7453//     resetSortSubjects()
7454//     makeFiltration()
7455//   }
7456
7457//   for (let i = 0; i < classInputs.length; i++) {
7458//     classInputs[i].addEventListener('change', () => updateFilter(true))
7459//     classInputs[i].addEventListener('change', changeClassInputText)
7460//   }
7461
7462//   function sortSubjectsInit () {
7463//     resetSortSubjects()
7464//     const subjectsArray = selectedClass()?.getAttribute('data-subjects')
7465//     if (subjectsArray) {
7466//       hideAllSubjects()
7467//       sortSubjects(subjectsArray)
7468//     }
7469//   }
7470
7471//   sortSubjectsInit()
7472
7473//   function selectedClass () {
7474//     return filterClass.querySelector(["input:checked"])
7475//   }
7476
7477
7478
7479//   function sortSubjects (subjectsJSON) {
7480//     const subjectsParsed = JSON.parse(subjectsJSON)
7481//     if (!subjectsParsed) return
7482//     let isTabActiveSet = false
7483//     subjectInputs.forEach((subject) => {
7484//       if (subjectsParsed.includes(+subject.value)) {
7485//         const label = subject.closest('.offer-tile__filter-item')
7486//         if (label) {
7487//           label.style.display = 'block'
7488//           const index = label.getAttribute('data-index')
7489//           const tab = document.querySelector('.offer-tile__filter-tab[data-index="' + index + '"]')
7490//           if (tab) {
7491//             tab.classList.remove('hide')
7492//             if (!isTabActiveSet) {
7493//               tab.click()
7494//               isTabActiveSet = true
7495//             }
7496//           }
7497//         }
7498//       }
7499//     })
7500//   }
7501
7502//   function hideAllSubjects () {
7503//     const tabs = document.querySelectorAll('.offer-tile__filter-tab')
7504//     for (let i = 0; i < tabs.length; i++) {
7505//       tabs[i].classList.add('hide')
7506//     }
7507//     const activeTab = document.querySelector('.offer-tile__filter-tab.active')
7508//     if (activeTab) activeTab.classList.remove('active')
7509//     const subjectLabels = filterSubject.querySelectorAll('.offer-tile__filter-item')
7510//     for (let i = 0; i < subjectLabels.length; i++) {
7511//       subjectLabels[i].style.display = 'none'
7512//     }
7513//   }
7514
7515//   function resetSortSubjects () {
7516//     const tabs = document.querySelectorAll('.offer-tile__filter-tab')
7517//     for (let i = 0; i < tabs.length; i++) {
7518//       tabs[i].classList.remove('hide')
7519//     }
7520//     const activeTab = document.querySelector('.offer-tile__filter-tab.active')
7521//     if (activeTab) activeTab.classList.remove('active')
7522//     if (tabs[0]) tabs[0].click()
7523//     const subjectLabels = filterSubject.querySelectorAll('.offer-tile__filter-item')
7524//     for (let i = 0; i < subjectLabels.length; i++) {
7525//       subjectLabels[i].style.display = 'block'
7526//     }
7527//     const activeSubject = filterSubject.querySelector(["input:checked"])
7528//     if (activeSubject) activeSubject.checked = false
7529//     subjectInputText.innerHTML = "Все предметы"
7530//   }
7531
7532//   function setError () {
7533//     openers[0].parentElement.classList.add('offer-tile__filter_error')
7534//     openers[1].parentElement.classList.add('offer-tile__filter_error')
7535//   }
7536
7537//   function resetError () {
7538//     openers[0].parentElement.classList.remove('offer-tile__filter_error')
7539//     openers[1].parentElement.classList.remove('offer-tile__filter_error')
7540//   }
7541
7542
7543//   function changeClassInputText () {
7544//     classInputText.innerHTML = this.getAttribute('data-text')
7545//   }
7546
7547//   for (let i = 0; i < subjectInputs.length; i++) {
7548//     subjectInputs[i].addEventListener('change', () => updateFilter(false))
7549//     subjectInputs[i].addEventListener('change', changeSubjectInputText)
7550//   }
7551
7552//   function changeSubjectInputText () {
7553//     subjectInputText.innerHTML = this.getAttribute('data-text')
7554//   }
7555
7556//   moreBtnInit()
7557
7558//   function moreBtnInit () {
7559//     const moreBtn = offerTile.querySelector('.all-courses__more-button')
7560//     if (moreBtn) {
7561//       const newBtn = replaceBtn(moreBtn)
7562//       newBtn.addEventListener('click', () => makeFiltration(newBtn.getAttribute('data-v')))
7563//     }
7564//   }
7565
7566//   function replaceBtn (oldElement) {
7567//     const newElement = oldElement.cloneNode(true)
7568//     oldElement.parentNode.replaceChild(newElement, oldElement)
7569//     return newElement
7570//   }
7571
7572
7573//   function updateFilter (isClassUpdated) {
7574//     if (isClassUpdated && isSumPage) sortSubjectsInit()
7575//     const itemsAll = offerTile.querySelectorAll(["input:checked"])
7576//     if (itemsAll.length) {
7577//       if (reset) reset.style.display = 'flex'
7578//     } else {
7579//       if (reset) reset.style.display = 'none'
7580//     }
7581//     makeFiltration()
7582//   }
7583
7584//   function makeFiltration (p_paginate = 1) {
7585//     const grades_items = offerTile.querySelectorAll('.offer-tile__filter-input_class:checked')
7586//     let grades_result = ''
7587//     let grade_first = 0
7588//     grades_items.forEach((item, i) => {
7589//       if (i > 0) grades_result += '|'
7590//       if (grade_first == 0) grade_first = item.value
7591//       grades_result += item.value
7592//     })
7593//     let subjects_result = ''
7594//     try{
7595//       const subjects_items = offerTile.querySelectorAll('.offer-tile__filter-input_subject:checked')
7596//       subjects_items.forEach((item, i) => {
7597//         if (i > 0) subjects_result += '|'
7598//         subjects_result += item.value
7599//       })
7600//     }catch(e){}
7601
7602//     let utm_f = tile.getAttribute('data-utm');
7603//     let promo_f = tile.getAttribute('data-promo');
7604
7605//     if(p_paginate === 1 ){
7606//       $('.filtered_elements').html("<div class='tile-loader'></div>");
7607//       $('.more_b').html("");
7608//     }
7609
7610//     var obData = {
7611//       'grade': grades_result,
7612//       'subject': subjects_result,
7613//       'utm_t': utm_f,
7614//       'promo': promo_f,
7615//       'pagePaginate': p_paginate,
7616//     };
7617//     // console.log(obData)
7618//     $.request(requestFunction, {
7619//       data: obData
7620//     })
7621//     // if (grade_first > 0){
7622//     //   let url = new URL(window.location.href)
7623//     //   url.searchParams.set('gr', grade_first);
7624//     //   history.replaceState(null, "", url.toString())
7625//     // }
7626//     // }
7627//     if (grade_first > 0 && isSumPage) {
7628//       let url = new URL(window.location.href)
7629//       url.searchParams.set('gr', grade_first);
7630//       history.replaceState(null, "", url.toString())
7631//     }
7632
7633//   }
7634
7635//   initTabs()
7636
7637//   function initTabs () {
7638//     const tabsParent = filterSubject.querySelector('.offer-tile__filter-tabs')
7639//     const tabs = filterSubject.querySelectorAll('.offer-tile__filter-tab')
7640//     const subjects = filterSubject.querySelectorAll('.offer-tile__filter-item')
7641
7642//     if (!tabs.length || !subjects.length) return
7643
7644//     tabs.forEach((tab) => {
7645//       tab.addEventListener('click', changeTab)
7646
7647//       function changeTab (e) {
7648//         e.stopPropagation()
7649//         const oldTab = filterSubject.querySelector('.offer-tile__filter-tab.active')
7650//         if (oldTab) oldTab.classList.remove('active')
7651
7652//         this.classList.add('active')
7653
7654//         subjects.forEach((subject) => {
7655//           subject.classList.add('hide')
7656//         })
7657
7658//         const index = this.getAttribute('data-index')
7659//         const activeSubjects = filterSubject.querySelectorAll('[data-index="' + index + '"]')
7660//         activeSubjects.forEach((subject) => {
7661//           subject.classList.remove('hide')
7662//         })
7663
7664//         tabsParent.scrollLeft = this.offsetLeft - tabsParent.clientWidth/2 + this.clientWidth/2
7665//       }
7666//     })
7667
7668//     tabs[0].click()
7669//   }
7670  
7671// }
7672
7673const offerTimers = document.querySelectorAll('.offer-timer')
7674 
7675 if (offerTimers.length) offerTimersInit()
7676 
7677 function offerTimersInit () {
7678   for (let i = 0; i < offerTimers.length; i++) {
7679     offerTimerInit(offerTimers[i])
7680   }
7681 }
7682 
7683 function offerTimerInit (timer) {
7684   const date = timer.getAttribute('date-end')
7685   const countDownDate = new Date(date).getTime()
7686 
7687   const nodes = timer.querySelectorAll('.offer-timer__number')
7688 
7689   const interval = setInterval(updateTimer, 1000)
7690 
7691   function updateTimer () {
7692     const now = new Date().getTime();
7693     const distance = countDownDate - now;
7694 
7695     const days = Math.floor(distance / (1000 * 60 * 60 * 24))
7696     const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
7697     const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))
7698     const seconds = Math.floor((distance % (1000 * 60)) / 1000)
7699 
7700     nodes[0].innerHTML = days
7701     nodes[1].innerHTML = hours
7702     nodes[2].innerHTML = minutes
7703     nodes[3].innerHTML = seconds
7704 
7705     if (distance < 0) {
7706       clearInterval(interval);
7707       nodes[0].innerHTML = "0"
7708       nodes[1].innerHTML = "0"
7709       nodes[2].innerHTML = "0"
7710       nodes[3].innerHTML = "0"
7711     }
7712   }
7713 }
7714
7715const preAboutVideo = document.querySelector("[data-element='pre-about-video']")
7716
7717if (preAboutVideo) preAboutVideoInit()
7718
7719function preAboutVideoInit () {
7720  const videoWrap = document.querySelector("[data-element='pre-about-video-wrap']")
7721  const timeNode = document.querySelector("[data-element='pre-about-time']")
7722  const soundBtn = document.querySelector(".pre-about__sound")
7723
7724  preAboutVideo.addEventListener("timeupdate", timeupdateHandler)
7725
7726  function timeupdateHandler () {
7727    const date = new Date(null)
7728    date.setSeconds(Math.round(preAboutVideo.currentTime))
7729    timeNode.innerHTML = date.toISOString().slice(14, 19)
7730  }
7731
7732  videoWrap.addEventListener('click', playVideo)
7733
7734  function playVideo (e) {
7735    e.stopPropagation()
7736    if (preAboutVideo.muted) {
7737      preAboutVideo.muted = false
7738      preAboutVideo.loop = false
7739      preAboutVideo.currentTime = 0
7740      preAboutVideo.play()
7741      soundBtn.classList.add('active')
7742    } else {
7743      preAboutVideo.muted = true
7744      soundBtn.classList.remove('active')
7745    }
7746  }
7747}
7748
7749const preFaqItems = document.querySelectorAll("[data-element='pre-faq-item']")
7750
7751for (let i = 0; i < preFaqItems.length; i++) {
7752  preFaqItems[i].addEventListener("click", toggleFaqItem)
7753
7754  function toggleFaqItem () {
7755    this.classList.toggle('active')
7756  }
7757}
7758
7759
7760
7761const preReviewsSlider = document.querySelector('[data-element="pre-reviews-slider"]')
7762
7763if (preReviewsSlider) preReviewsSliderInit()
7764
7765function preReviewsSliderInit () {
7766  const preReviewsSliderSwiper = new Swiper(preReviewsSlider, {
7767    mousewheel: { forceToAxis: true },
7768    slidesPerView: 'auto',
7769    spaceBetween: 25,
7770    a11y: false,
7771    navigation: {
7772      nextEl: '.pre-reviews__nav-btn_right',
7773      prevEl: '.pre-reviews__nav-btn_left',
7774    },
7775    scrollbar: {
7776      el: '.pre-reviews__scrollbar',
7777      draggable: true,
7778    },
7779    breakpoints: {
7780      1440: {
7781        spaceBetween: 30,
7782      }
7783    }
7784  })
7785}
7786
7787const preReviewsVideoWraps = document.querySelectorAll("[data-element='pre-reviews-video-wrap']")
7788
7789if (preReviewsVideoWraps.length) preReviewsVideoWrapsInit()
7790
7791function preReviewsVideoWrapsInit () {
7792  for (let i = 0; i < preReviewsVideoWraps.length; i++) {
7793    videoInit(preReviewsVideoWraps[i])
7794    const video = preReviewsVideoWraps[i].querySelector("[data-element='pre-reviews-video']")
7795    video.addEventListener('play', stopOtherVideo)
7796  }
7797
7798  function stopOtherVideo () {
7799    const index = this.getAttribute('data-index')
7800    for (let i = 0; i < preReviewsVideoWraps.length; i++) {
7801      if (index != i) {
7802        let videoOther = preReviewsVideoWraps[i].querySelector("[data-element='pre-reviews-video']")
7803        videoOther.pause()
7804      }
7805    }
7806  }
7807
7808  function videoInit (wrap) {
7809    const video = wrap.querySelector("[data-element='pre-reviews-video']")
7810    wrap.addEventListener('click', playVideo, {once: true})
7811
7812    function playVideo () {
7813      wrap.classList.add('active')
7814      video.controls = true
7815      setTimeout(() => video.play(), 100)
7816    }
7817  }
7818}
7819
7820const preStudySlider = document.querySelector('[data-element="pre-study-slider"]')
7821
7822if (preStudySlider) {
7823  var preStudySliderSwiper
7824  var animationPlayed = false
7825  const wrapper = preStudySlider.querySelector('.pre-study__wrapper')
7826  window.addEventListener('resize', watchSlider, {passive: true})
7827  window.addEventListener('scroll', animateSlider, {passive: true})
7828  watchSlider()
7829
7830  function initSlider () {
7831    preStudySliderSwiper = new Swiper(preStudySlider, {
7832      mousewheel: { forceToAxis: true },
7833      slidesPerView: 'auto',
7834      spaceBetween: 25,
7835      loop: true,
7836      pagination: {
7837        el: ".pre-study__pagination",
7838      },
7839    })
7840  }
7841
7842  function watchSlider () {
7843    if (window.innerWidth < 1440) {
7844      preStudySliderSwiper?.destroy()
7845      initSlider()
7846    } else {
7847      preStudySliderSwiper?.destroy()
7848    }
7849  }
7850
7851  function animateSlider () {
7852    if (preStudySlider.getBoundingClientRect().top < window.innerHeight/2 && !animationPlayed && window.innerWidth < 992) {
7853      animationPlayed = true
7854      wrapper.style.transitionDuration = '0.5s'
7855      wrapper.style.transform = 'translate3d(-160px, 0, 0)'
7856      setTimeout(function () {
7857        wrapper.style.transform = 'translate3d(0, 0, 0)'
7858      }, 500)
7859    }
7860  }
7861}
7862
7863const preThanks = document.querySelector('.pre-thanks')
7864
7865if (preThanks) preThanksInit()
7866
7867function preThanksInit () {
7868  const url = new URL(window.location.href)
7869  //url.searchParams.delete('email')
7870//   url.searchParams.delete('cemail')
7871//   history.replaceState(null, "", url.toString())
7872}
7873
7874const preWaysSlideArray = document.querySelectorAll('[data-element="pre-ways-slide"]')
7875
7876if (preWaysSlideArray.length) preWaysSlideArrayInit()
7877
7878function preWaysSlideArrayInit () {
7879  for (let i = 0; i < preWaysSlideArray.length; i++) {
7880    preWaysSlideInit(preWaysSlideArray[i])
7881  }
7882
7883  function preWaysSlideInit (slide) {
7884    const list = slide.querySelector('[data-element="pre-ways-list"]')
7885    const btn = slide.querySelector('[data-element="pre-ways-more"]')
7886
7887    if (window.innerWidth >= 1200 ? list?.clientHeight > 140 : list?.clientHeight > 70) {
7888      btn.classList.add('show')
7889      btn.addEventListener('click', toggleList)
7890      slide.classList.add('hide')
7891    }
7892
7893    function toggleList () {
7894      if (slide.classList.contains('hide')) {
7895        slide.classList.remove('hide')
7896        btn.textContent = 'Свернуть'
7897      } else {
7898        slide.classList.add('hide')
7899        btn.textContent = 'Показать все предметы'
7900      }
7901    }
7902  }
7903}
7904
7905const preWaysSlider = document.querySelector('[data-element="pre-ways__slider"]')
7906
7907if (preWaysSlider) preWaysSliderInit()
7908
7909function preWaysSliderInit () {
7910  let preWaysSliderSwiper
7911  window.addEventListener('resize', watchSlider, {passive: true})
7912  watchSlider()
7913
7914  function watchSlider () {
7915    if (window.innerWidth < 1200) {
7916      preWaysSliderSwiper?.destroy()
7917    } else {
7918      preWaysSliderSwiper?.destroy()
7919      initSlider()
7920    }
7921  }
7922
7923  function initSlider () {
7924    preWaysSliderSwiper = new Swiper(preWaysSlider, {
7925      mousewheel: { forceToAxis: true },
7926      slidesPerView: 'auto',
7927      spaceBetween: 25,
7928      pagination: {
7929        el: ".pre-ways__pagination",
7930      },
7931      navigation: {
7932        nextEl: '.pre-ways__nav-btn_right',
7933        prevEl: '.pre-ways__nav-btn_left',
7934      },
7935      scrollbar: {
7936        el: '.pre-ways__scrollbar',
7937        draggable: true,
7938      },
7939      breakpoints: {
7940        1440: {
7941          spaceBetween: 30,
7942        }
7943      }
7944    })
7945  }
7946}
7947
7948const predzapsNewWaysInners = document.querySelectorAll('.predzaps-new-ways__inner')
7949
7950let predzapsNewWaysInnerTimer
7951for (let i = 0; i < predzapsNewWaysInners.length; i++) {
7952  predzapsNewWaysInnerInit(predzapsNewWaysInners[i])
7953}
7954
7955function predzapsNewWaysInnerInit (inner) {
7956  const tags = inner.querySelectorAll('.predzaps-new-ways__tag')
7957
7958  const toggle = inner.querySelector('.predzaps-new-ways__toggle')
7959  if (toggle) toggle.addEventListener('click', toggleTags)
7960
7961  if (getCountOfHiddenTags() === 0) {
7962    toggle.style.display = 'none'
7963  } else {
7964    toggle.innerHTML = `Показать ещё +${getCountOfHiddenTags()}`
7965  }
7966
7967  function toggleTags () {
7968    if (inner.classList.contains('active')) {
7969      inner.classList.remove('active')
7970      toggle.innerHTML = `Показать ещё +${getCountOfHiddenTags()}`
7971      if (predzapsNewWaysInnerTimer) clearInterval(predzapsNewWaysInnerTimer)
7972    } else {
7973      const oldActiveInner = document.querySelector('.predzaps-new-ways__inner.active')
7974      if (oldActiveInner) {
7975        oldActiveInner.classList.remove('active')
7976        const oldToggle = oldActiveInner.querySelector('.predzaps-new-ways__toggle')
7977        oldToggle.innerHTML = `Показать ещё +${getCountOfHiddenTags()}`
7978      }
7979      inner.classList.add('active')
7980      toggle.innerHTML = 'Свернуть'
7981      toggleTimer()
7982    }
7983  }
7984
7985  function toggleTimer () {
7986    if (predzapsNewWaysInnerTimer) clearInterval(predzapsNewWaysInnerTimer)
7987
7988    predzapsNewWaysInnerTimer = setInterval(() => {
7989      const oldActiveInner = document.querySelector('.predzaps-new-ways__inner.active')
7990      if (oldActiveInner) {
7991        oldActiveInner.classList.remove('active')
7992        const oldToggle = oldActiveInner.querySelector('.predzaps-new-ways__toggle')
7993        oldToggle.innerHTML = `Показать ещё +${getCountOfHiddenTags()}`
7994      }
7995    }, 10000)
7996  }
7997
7998  function getCountOfHiddenTags () {
7999    const height = inner.querySelector('.predzaps-new-ways__tags').clientHeight
8000    let counter = 0
8001    for (let i = 0; i < tags.length; i++) {
8002      if (tags[i].getBoundingClientRect().top - inner.getBoundingClientRect().top >= height) {
8003        counter += 1
8004      }
8005    }
8006    return counter
8007  }
8008}
8009
8010const predzapsThanks = document.querySelector('.predzaps-thanks')
8011
8012if (predzapsThanks) predzapsThanksInit()
8013
8014function predzapsThanksInit () {
8015//   const isSubjectSort = false
8016  const isSubjectSort = true
8017  const form = predzapsThanks.querySelector('.predzaps-thanks__slide_form')
8018  const tgSlide = predzapsThanks.querySelector('.predzaps-thanks__slide_tg')
8019  const stickyHeader = document.querySelector('.sticky-header')
8020  const body = document.querySelector('body')
8021  const addButton = predzapsThanks.querySelector(".predzaps-thanks__form-add")
8022  const btnSubmit = predzapsThanks.querySelector(".predzaps-thanks__form-submit")
8023  const inners = predzapsThanks.querySelectorAll('.predzaps-thanks__form-line-inner')
8024  const lines = predzapsThanks.querySelector(".predzaps-thanks__form-lines")
8025  const innerCleanCopy = inners[inners.length - 1].cloneNode(true)
8026  let counter = inners.length
8027
8028  function initOpeners (inner) {
8029    const openers = inner.querySelectorAll("[data-element='all-courses-filter-opener']")
8030    for (let i = 0; i < openers.length; i++) {
8031      openers[i].addEventListener("click", (e)=> openFilter(openers[i], e))
8032
8033      const wrap = openers[i].nextElementSibling
8034
8035      const closeBtn = wrap.querySelector('.all-courses__filter-close')
8036      if (closeBtn) closeBtn.addEventListener('click', () => closeFilter(openers[i]))
8037
8038      const items = wrap.querySelectorAll("[data-element='all-courses-filter-input']")
8039      const subjectSelect = wrap.closest('.predzaps-thanks__form-line-inner')?.querySelector('.all-courses__filter_subject')
8040      items.forEach((item) => {
8041        item.addEventListener('change', function () {
8042          updateFilter(openers[i], wrap)
8043          const isClass = !this.closest('.all-courses__filter-list').parentElement.classList.contains('class_subjects')
8044          if (this.hasAttribute('data-disable-subject') && isClass) {
8045            subjectSelect?.classList.add('all-courses__filter_college')
8046            if (subjectSelect) resetSubjects(subjectSelect, "Выберите направление")
8047          } else if (isClass) {
8048            subjectSelect?.classList.remove('all-courses__filter_college')
8049            if (subjectSelect) resetSubjects(subjectSelect)
8050          }
8051        })
8052
8053      })
8054
8055      const confirm = wrap.querySelector('.all-courses__confirm')
8056      if (confirm) confirm.addEventListener('click', () => closeFilter(openers[i]))
8057    }
8058  }
8059
8060  function resetSubjects (subjectSelect, textDefault='Выберите предмет') {
8061    const checkedSubjects = subjectSelect.querySelectorAll('.all-courses__filter-input:checked')
8062    checkedSubjects.forEach((subject) => {
8063      subject.checked = false
8064    })
8065    const text = subjectSelect.querySelector('.all-courses__filter-top-text')
8066    text.style.color = 'rgba(0,0,0,.62)'
8067    const headline = subjectSelect.querySelector('.all-courses__filter-headline')
8068    text.innerHTML = textDefault
8069    headline.innerHTML = textDefault
8070  }
8071  function subjectsSort (subjectSelect, subjectsList) {
8072    const subjects = subjectSelect.querySelectorAll('.all-courses__filter-input')
8073    subjects.forEach((subject) => {
8074      if (subjectsList.includes(+subject.value)) {
8075        subject.closest('.all-courses__filter-item').style.display = 'block'
8076      } else {
8077        subject.closest('.all-courses__filter-item').style.display = 'none'
8078      }
8079    })
8080    const line = subjectSelect.closest('.predzaps-thanks__form-line')
8081    const boxes = line.querySelectorAll('.all-courses__filter-box')
8082    let isTabNotSet = false
8083    boxes.forEach((box) => {
8084      const subjects = box.querySelectorAll('.all-courses__filter-input')
8085      let isEmpty = true
8086      subjects.forEach((subject) => {
8087        if (subject.closest('.all-courses__filter-item').style.display === 'block') isEmpty = false
8088      })
8089      const index = box.getAttribute('data-index')
8090      if (isEmpty && index) {
8091        const tab = line.querySelector(".all-courses__filter-tab[data-index='" + index + "']")
8092        tab.style.display = 'none'
8093        const box = line.querySelector(".all-courses__filter-box[data-index='" + index + "']")
8094        box.classList.add('all-courses__filter-box_hide-sort')
8095        box.previousElementSibling.classList.add('hide')
8096      } else if (index && !isTabNotSet) {
8097        isTabNotSet = true
8098        line.querySelector('.all-courses__filter-tab.active')?.classList.remove('active')
8099        const newTab = line.querySelector(".all-courses__filter-tab[data-index='" + index + "']")
8100        if (newTab) newTab.click()
8101      }
8102    })
8103  }
8104
8105  function showAllSubjects (subjectSelect) {
8106    const subjects = subjectSelect.querySelectorAll('.all-courses__filter-input')
8107    subjects.forEach((subject) => {
8108      subject.closest('.all-courses__filter-item').style.display = 'block'
8109    })
8110    const tabs = subjectSelect.querySelectorAll('.all-courses__filter-tab')
8111    tabs[0]?.click()
8112    tabs.forEach((tab) => {
8113      tab.style.display = 'flex'
8114    })
8115    const line = subjectSelect.closest('.predzaps-thanks__form-line')
8116    const boxes = line.querySelectorAll('.all-courses__filter-box')
8117    const tempBoxes = Array.from(boxes).filter(box => !box.classList.contains('all-courses__filter-box_college'))
8118    tempBoxes.forEach((box, index) => {
8119      box.classList.remove('all-courses__filter-box_hide-sort')
8120      box.previousElementSibling.classList.remove('hide')
8121    })
8122  }
8123
8124
8125  function removeInputNameError (inner) {
8126    const input = inner.querySelector('.predzaps-thanks__form-input')
8127    input.addEventListener('input', () => input.classList.remove('error-input'))
8128  }
8129
8130  inners.forEach(inner => {
8131    removeInputNameError(inner)
8132    initTabs(inner)
8133    initOpeners(inner)
8134    initDeleteButton(inner)
8135  })
8136
8137  function initDeleteButton (inner) {
8138    const buttonDelete = inner.querySelector('.predzaps-thanks__form-delete')
8139    buttonDelete.addEventListener('click', () => {
8140      const dataCounter = buttonDelete.getAttribute('data-counter')
8141      inner.remove()
8142      counter -= 1
8143      updateCounter(dataCounter)
8144      if (counter < 7) addButton.disabled = false
8145    })
8146  }
8147
8148  function updateCounter (dataCounter) {
8149    const inners = document.querySelectorAll('.predzaps-thanks__form-line-inner')
8150    for (let i = dataCounter - 1; i < inners.length; i++) {
8151      const lineName = inners[i].querySelector('.predzaps-thanks__form-line-name')
8152      if (lineName) lineName.innerHTML = `Ребёнок ${i+1}`
8153      const inputName = inners[i].querySelector('.predzaps-thanks__form-input')
8154      if (inputName) inputName.setAttribute('name', `name${i+1}`)
8155      const classInputs = inners[i].querySelectorAll('.all-courses__filter_class input')
8156      classInputs.forEach((input) => {
8157        input.setAttribute('name', `grade${i+1}`)
8158      })
8159      const subjectInputs = inners[i].querySelectorAll('.all-courses__filter_subject input')
8160      subjectInputs.forEach((input) => {
8161        input.setAttribute('name', `subject${i+1}`)
8162      })
8163      const deleteButton = inners[i].querySelector('.predzaps-thanks__form-delete')
8164      if (deleteButton) deleteButton.setAttribute('data-counter', i+1)
8165    }
8166  }
8167
8168
8169  function initTabs (inner) {
8170    const filterSubjectWrap = inner.querySelector('.all-courses__filter-wrap_subject')
8171    const list = filterSubjectWrap.querySelector('.all-courses__filter-list')
8172    const tabsParent = filterSubjectWrap.querySelector('.all-courses__filter-tabs')
8173    const tabs = filterSubjectWrap.querySelectorAll('.all-courses__filter-tab')
8174    const subjectsBoxes = filterSubjectWrap.querySelectorAll('.all-courses__filter-box')
8175
8176    if (!tabs.length || !subjectsBoxes.length) return
8177
8178    filterSubjectWrap.addEventListener('scroll', wrapScrollHandler, { passive: true })
8179
8180    function wrapScrollHandler () {
8181      subjectsBoxes.forEach((subjectBox) => {
8182        if (filterSubjectWrap.scrollTop >= subjectBox.offsetTop - 90 - 65) {
8183          const oldTab = filterSubjectWrap.querySelector('.all-courses__filter-tab.active')
8184          if (oldTab) oldTab.classList.remove('active')
8185          const index = subjectBox.getAttribute('data-index')
8186          const tab = filterSubjectWrap.querySelector('[data-index="' + index + '"]')
8187          if (tab) {
8188            tabsParent.scrollLeft = tab.offsetLeft - tabsParent.clientWidth/2 + tab.clientWidth/2
8189            tab.classList.add('active')
8190          }
8191        }
8192      })
8193    }
8194
8195    tabs.forEach((tab) => {
8196      tab.addEventListener('click', changeTab)
8197
8198      function changeTab (e) {
8199        e.stopPropagation()
8200        filterSubjectWrap.removeEventListener('scroll', wrapScrollHandler, { passive: true })
8201        const oldTab = filterSubjectWrap.querySelector('.all-courses__filter-tab.active')
8202        if (oldTab) oldTab.classList.remove('active')
8203
8204        this.classList.add('active')
8205
8206        subjectsBoxes.forEach((subjectsBox) => {
8207          subjectsBox.classList.add('hide')
8208        })
8209
8210        const index = this.getAttribute('data-index')
8211        const activeSubjectsBox = list.querySelector('[data-index="' + index + '"]')
8212        activeSubjectsBox.classList.remove('hide')
8213
8214        filterSubjectWrap.scrollTop = activeSubjectsBox.offsetTop - 90 - 60
8215
8216        tabsParent.scrollLeft = this.offsetLeft - tabsParent.clientWidth/2 + this.clientWidth/2
8217        setTimeout(() => filterSubjectWrap.addEventListener('scroll', wrapScrollHandler, { passive: true }), 1000)
8218      }
8219    })
8220
8221    tabs[0].click()
8222  }
8223
8224  function updateFilter(opener, wrap) {
8225    opener.classList.remove('error-input')
8226    if (opener.getAttribute('data-ftype') === 'class_select') {
8227      let subjectsList
8228      try {
8229        subjectsList = JSON.parse(wrap.querySelector('.all-courses__filter-input:checked').getAttribute('data-subjects'))
8230      } catch (e) {
8231        console.log(e)
8232      }
8233      const subjectSelect = wrap.closest('.predzaps-thanks__form-line-inner')?.querySelector('.all-courses__filter_subject')
8234      showAllSubjects(subjectSelect)
8235      subjectSelect.classList.remove('all-courses__filter_disabled')
8236      if (subjectsList && subjectSelect && isSubjectSort) subjectsSort(subjectSelect, subjectsList)
8237      const text = opener.querySelector('.all-courses__filter-top-text')
8238      text.style.color = '#000'
8239      text.innerHTML = wrap.querySelector('.all-courses__filter-input:checked').nextElementSibling.textContent
8240      closeFilter(opener, wrap)
8241    }
8242    if (opener.getAttribute('data-ftype') === 'class_subjects') {
8243      const isCollege = opener.closest('.all-courses__filter').classList.contains('all-courses__filter_college')
8244      const headline = wrap.querySelector('.all-courses__filter-headline')
8245      const text = opener.querySelector('.all-courses__filter-top-text')
8246      text.style.color = '#000'
8247      if (!isCollege) {
8248        headline.innerHTML = `Выбрано предметов: ${wrap.querySelectorAll('.all-courses__filter-input:checked').length}`
8249        text.innerHTML = `Выбрано предметов: ${wrap.querySelectorAll('.all-courses__filter-input:checked').length}`
8250      } else {
8251        text.innerHTML = wrap.querySelector('.all-courses__filter-input:checked').getAttribute('data-text')
8252        closeFilter(opener, wrap)
8253      }
8254    }
8255  }
8256
8257  function openFilter (opener, e) {
8258    e.stopPropagation()
8259    if (opener.classList.contains('active')) {
8260      closeFilter(opener)
8261    } else {
8262      const oldOpen = predzapsThanks.querySelector(".all-courses__filter-top.active")
8263      if (oldOpen) oldOpen.classList.remove('active')
8264      opener.classList.add('active')
8265
8266      const filter = opener.parentElement
8267      const oldFilter = predzapsThanks.querySelector(".all-courses__filter.open")
8268      if (oldFilter) oldFilter.classList.remove('open')
8269      if (filter) filter.classList.add('open')
8270    }
8271    hideHeader()
8272  }
8273
8274  function closeFilter (opener) {
8275    opener.classList.remove('active')
8276    const filter = opener.parentElement
8277    if (filter) filter.classList.remove('open')
8278    showHeader()
8279  }
8280
8281  function showHeader () {
8282    stickyHeader.classList.remove('hide')
8283    body.classList.remove('no-scroll')
8284  }
8285  function hideHeader () {
8286    if (window.innerWidth < 744) {
8287      stickyHeader.classList.add('hide')
8288      body.classList.add('no-scroll')
8289    }
8290  }
8291
8292
8293
8294  form.addEventListener('submit', submitForm)
8295
8296  function createSendData () {
8297    const names = []
8298    const nameInputs = form.querySelectorAll('.predzaps-thanks__form-input')
8299    nameInputs.forEach(nameInput => {
8300      names.push(nameInput.value)
8301    })
8302    const classes = []
8303    const classes_ids = []
8304    const classInputs = form.querySelectorAll('.all-courses__filter_class input:checked')
8305    classInputs.forEach(classInput => {
8306      classes.push(classInput.dataset.text)
8307      classes_ids.push(classInput.value)
8308    })
8309    const subjects = []
8310    const subjects_ids = []
8311    const inners = form.querySelectorAll('.predzaps-thanks__form-line-inner')
8312
8313    inners.forEach(inner => {
8314      const temp = []
8315      const temp_ids = []
8316      const subjectsOneChild = inner.querySelectorAll('.all-courses__filter_subject input:checked')
8317      subjectsOneChild.forEach(subject => {
8318        temp.push(subject.dataset.text)
8319        temp_ids.push(subject.value)
8320      })
8321      subjects.push(temp)
8322      subjects_ids.push(temp_ids)
8323    })
8324
8325    const summer_answers = []
8326    const checkboxes = form.querySelectorAll('.predzaps-thanks__summer-input')
8327    checkboxes.forEach(checkbox => {
8328      summer_answers.push(checkbox.checked ? 'да' : 'нет')
8329    })
8330
8331    const formData = new FormData(form);
8332    const formObject = {};
8333    const childrenFieldNames = new Set();
8334
8335      nameInputs.forEach(input => childrenFieldNames.add(input.name));
8336      classInputs.forEach(input => childrenFieldNames.add(input.name));
8337      inners.forEach(inner => {
8338        inner.querySelectorAll('.all-courses__filter_subject input').forEach(input => {
8339          childrenFieldNames.add(input.name);
8340        });
8341      });
8342
8343    formData.forEach((value, key) => {
8344        if (!childrenFieldNames.has(key)) {
8345          if (key in formObject) {
8346            if (Array.isArray(formObject[key])) {
8347              formObject[key].push(value);
8348            } else {
8349              formObject[key] = [formObject[key], value];
8350            }
8351          } else {
8352            formObject[key] = value;
8353          }
8354        }
8355      });
8356    const children = [];
8357    const children_ids = [];
8358      const maxLen = Math.max(names.length, classes.length, subjects.length, summer_answers.length);
8359
8360      for (let i = 0; i < maxLen; i++) {
8361        children.push({
8362          name: names[i] ?? null,
8363          class: classes[i] ?? null,
8364          subjects: subjects[i] ?? [],
8365          summer_answer: summer_answers[i] ?? null,
8366        });
8367        children_ids.push({
8368          name: names[i] ?? null,
8369          class: classes_ids[i] ?? null,
8370          subjects: subjects_ids[i] ?? [],
8371          summer_answer: summer_answers[i] ?? null,
8372        });
8373      }
8374
8375      formObject.children = children;
8376      formObject.children_ids = children_ids;
8377
8378    return formObject;
8379  }
8380
8381  function submitForm (e) {
8382    e.preventDefault()
8383    e.stopPropagation()
8384    if (validate()) {
8385      btnSubmit.disabled = true
8386      btnSubmit.classList.add('loading')
8387      const data = createSendData()
8388      console.log(data)
8389      const dataRequest = form.getAttribute('data-request');
8390      $.request('MainFunctions::' + dataRequest, {
8391        data: data,
8392        success: function(response) {
8393            // console.log('Ответ:', response);
8394            let hasErrors = false;
8395
8396            for (let key in response) {
8397              if (key.startsWith('.')) {
8398                const className = key.substring(1);
8399                const element = document.querySelector('.' + className);
8400
8401                if (element) {
8402                  element.innerHTML = response[key];
8403                  hasErrors = true;
8404                  btnSubmit.disabled = false
8405                  btnSubmit.classList.remove('loading')
8406                }
8407              }
8408            }
8409
8410            
8411
8412            if (hasErrors) {
8413            //   isSubmitting = false;
8414              return;
8415            }
8416          removeParameterFromUrl('cemail')
8417          form.classList.remove('active')
8418          tgSlide.classList.add('active')
8419          window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
8420        },
8421        error: function (error) {
8422          // console.error('❌ Ошибка отправки:', error);
8423        }
8424      });
8425    }
8426  }
8427
8428  function removeParameterFromUrl (keyToRemove) {
8429    const url = new URL(window.location.href)
8430    const params = url.searchParams
8431    params.delete(keyToRemove)
8432    window.history.replaceState({}, document.title, url.toString())
8433  }
8434
8435
8436  addButton.addEventListener('click', addLine)
8437
8438  function addLine () {
8439    if (validate()) {
8440      counter += 1
8441      lines.append(innerCleanCopy.cloneNode(true))
8442      const inners = predzapsThanks.querySelectorAll('.predzaps-thanks__form-line-inner')
8443      const inner = inners[inners.length - 1]
8444      removeInputNameError(inner)
8445      updateNames(inner)
8446      initTabs(inner)
8447      initOpeners(inner)
8448      initDeleteButton(inner)
8449      if (window.innerHeight - inner.getBoundingClientRect().bottom < 0) {
8450        inner.scrollIntoView({
8451          behavior: 'smooth',
8452          block: 'end'
8453        })
8454      }
8455      if (counter >= 7) addButton.disabled = true
8456    }
8457  }
8458
8459  function updateNames (inner) {
8460    const lineName = inner.querySelector('.predzaps-thanks__form-line-name')
8461    lineName.innerHTML = `Ребенок ${counter}`
8462    const inputs = inner.querySelectorAll('input')
8463    for (let i = 0; i < inputs.length; i++) {
8464      inputs[i].name = `${inputs[i].name}${counter}`
8465    }
8466    const deleteButton = inner.querySelector('.predzaps-thanks__form-delete')
8467    if (deleteButton) deleteButton.setAttribute('data-counter', counter)
8468  }
8469
8470  function validate () {
8471    const inners = predzapsThanks.querySelectorAll('.predzaps-thanks__form-line-inner')
8472    for (let i = 0; i < inners.length; i++) {
8473      const isValid = checkInputs(inners[i])
8474      if (!isValid) return false
8475    }
8476    function checkInputs(inner) {
8477      const nameInput = inner.querySelector(".predzaps-thanks__form-input")
8478      if (!nameInput.value) {
8479        nameInput.classList.add('error-input')
8480        return false
8481      }
8482      const classInput = inner.querySelector(".all-courses__filter_class input:checked")
8483      if (!classInput) {
8484        const top = inner.querySelector(".all-courses__filter_class .all-courses__filter-top")
8485        top.classList.add('error-input')
8486        return false
8487      }
8488      const isCollege = inner.querySelector('.all-courses__filter_subject.all-courses__filter_disabled')
8489      if (!isCollege) {
8490        const subjectInput = inner.querySelector(".all-courses__filter_subject input
8490:checked")
8491        if (!subjectInput) {
8492          const top = inner.querySelector(".all-courses__filter_subject .all-courses__filter-top")
8493          top.classList.add('error-input')
8494          return false
8495        }
8496      }
8497      return true
8498    }
8499    return true
8500  }
8501}
8502
8503
8504 
8505const teacherCostArray = document.querySelectorAll('.teacher-cost .cost__area')
8506 
8507if (teacherCostArray.length) teacherCostArrayInit()
8508 
8509 function teacherCostArrayInit () {
8510   for (let i = 0; i < teacherCostArray.length; i++) {
8511     teacherCostInit(teacherCostArray[i])
8512   }
8513 }
8514 
8515 function teacherCostInit(node) {
8516   const btn = node.querySelector('.cost__button')
8517   const checkbox = node.querySelector('.cost__teacher-checkbox')
8518   const price = node.querySelector('.cost__price-current')
8519 
8520 
8521   checkbox.addEventListener('change', checkboxChangeHandler)
8522 
8523   function checkboxChangeHandler () {
8524     const newPrice = checkbox.getAttribute('new-price')
8525     const oldPrice = btn.getAttribute('old-price')
8526 
8527     const newHref = checkbox.getAttribute('new-href')
8528     const oldHref = btn.getAttribute('old-href')
8529 
8530     if (checkbox.checked) {
8531       price.textContent = newPrice
8532       btn.href = newHref
8533     } else {
8534       price.textContent = oldPrice
8535       btn.href = oldHref
8536     }
8537   }
8538 }
8539
8540 const profStockAboutShow = document.querySelector('.prof-stock-about__show')
8541
8542if (profStockAboutShow) profStockAboutShow.addEventListener('click',
8543  () => profStockAboutShow.classList.toggle('active')
8544)
8545
8546const profStockTimers = document.querySelectorAll('[data-element="prof-stock-timer"]')
8547
8548if (profStockTimers.length > 0) {
8549  if (getCookie('prof_stock_expired') !== 'true') {
8550    profStockTimers.forEach(timer => {
8551      timer.classList.add('active')
8552    })
8553    if (getCookie('prof_stock_shown') !== 'true') {
8554      const date = new Date()
8555      date.setHours(date.getHours() + 24)
8556      document.cookie = `user_prof_stock_date_end=${date.toISOString().replace(/T(\d)(?=:)/, 'T0$1')}; max-age=31536000;`;
8557    }
8558    document.cookie = `prof_stock_shown=true; max-age=31536000;`;
8559    profStockTimers.forEach(timer => {
8560      initProfStockTimer(timer)
8561    })
8562  }
8563}
8564
8565function initProfStockTimer (timer) {
8566  let date = new Date(getCookie('user_prof_stock_date_end'))
8567  if (!(date instanceof Date && !isNaN(date.getTime()))) {
8568    date = new Date()
8569    date.setHours(date.getHours() + 24)
8570  }
8571  const countDownDate = date.getTime()
8572
8573  const nodes = timer.querySelectorAll('[data-element="prof-stock-timer-number"]')
8574
8575  const interval = setInterval(updateTimer, 1000)
8576
8577  function updateTimer () {
8578    const now = new Date().getTime();
8579    const distance = countDownDate - now;
8580
8581    const days = Math.floor(distance / (1000 * 60 * 60 * 24))
8582    const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
8583    const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))
8584    const seconds = Math.floor((distance % (1000 * 60)) / 1000)
8585
8586    if (nodes.length < 4) {
8587      nodes[0].innerHTML = String(hours).padStart(2, '0')
8588      nodes[1].innerHTML = String(minutes).padStart(2, '0')
8589      nodes[2].innerHTML = String(seconds).padStart(2, '0')
8590    } else {
8591      nodes[0].innerHTML = days
8592      nodes[1].innerHTML = hours
8593      nodes[2].innerHTML = minutes
8594      nodes[3].innerHTML = seconds
8595    }
8596    // console.log(distance)
8597    if (distance < 0) {
8598      clearInterval(interval);
8599      nodes[0].innerHTML = "0"
8600      nodes[1].innerHTML = "0"
8601      nodes[2].innerHTML = "0"
8602      document.cookie = `prof_stock_expired=true; max-age=31536000;`
8603      profStockTimers.forEach(timer => {
8604        timer.classList.remove('active')
8605      })
8606      if (nodes[3]) nodes[3].innerHTML = "0"
8607    }
8608  }
8609}
8610
8611    const profStockBar = document.querySelector('.prof-stock-bar')
8612
8613    if (profStockBar) profStockBarInit()
8614
8615    function profStockBarInit () {
8616      const cake = document.querySelector('.cake')
8617      if (cake) cake.classList.add('cake_prof-stock-bar')
8618
8619      const order = document.querySelector('.prof-stock-order');
8620      const footer = document.querySelector('.footer-quiz');
8621
8622      const observer = new IntersectionObserver((entries) => {
8623        entries.forEach(entry => {
8624          if (entry.isIntersecting) {
8625            profStockBar.style.display = 'none'
8626            if (cake) cake.classList.remove('cake_prof-stock-bar')
8627          } else {
8628            profStockBar.style.display = 'block'
8629            if (cake) cake.classList.add('cake_prof-stock-bar')
8630          }
8631        })
8632      }, {
8633        threshold: 0
8634      })
8635
8636      if (order) observer.observe(order)
8637      if (footer) observer.observe(footer)
8638    }
8639
8640
8641 const programBoxes = document.querySelectorAll('.program__box')
8642 
8643 if (programBoxes.length) programBoxesInit()
8644 
8645 function programBoxesInit () {
8646   for (let i = 0; i < programBoxes.length; i++) {
8647     programBoxInit(programBoxes[i])
8648   }
8649 
8650   function programBoxInit (box) {
8651     const items = box.querySelectorAll('.program__item')
8652     let span
8653 
8654     if (window.innerWidth >= 1440 && items.length > 12 || window.innerWidth >= 744  && items.length > 10 || window.innerWidth < 744 && items.length > 6) {
8655       box.classList.add('hide')
8656       const btn = box.querySelector('.program__more')
8657       btn.addEventListener('click', toogleBox)
8658       span = btn.querySelector('span')
8659     }
8660 
8661     function toogleBox () {
8662       if (box.classList.contains('active')) {
8663         box.classList.remove('active')
8664         span.innerHTML = 'Показать полностью'
8665         box.scrollIntoView()
8666       } else {
8667         box.classList.add('active')
8668         span.innerHTML = 'Скрыть список'
8669       }
8670     }
8671   }
8672 }
8673 
8674 
8675const promo = document.querySelector('.promo')
8676 
8677 if (promo) promoInit()
8678 
8679 function promoInit () {
8680   const closeBtn = promo.querySelector('.promo__close')
8681   const promoView = promo.querySelector('.promo__view')
8682   const cake = document.querySelector('.cake.cake_active')
8683   const footer = document.querySelector('footer')
8684 
8685   promoView.addEventListener('click', switchPromo)
8686   closeBtn.addEventListener('click', closePromo)
8687 
8688   if (footer) window.addEventListener('scroll', togglePromo, { passive: true })
8689   window.addEventListener('click', closePromo)
8690
8691   function switchPromo (e) {
8692     e.stopPropagation()
8693     promo.classList.toggle('active')
8694   }
8695 
8696   function closePromo () {
8697     promo.classList.remove('active')
8698   }
8699
8700   function togglePromo () {
8701    const scrollHeight = document.documentElement.scrollHeight
8702    const currentScroll = window.scrollY
8703    const clientHeight = document.documentElement.clientHeight
8704
8705    const distanceToBottom = scrollHeight - (currentScroll + clientHeight);
8706    if (distanceToBottom < footer.clientHeight) {
8707      promo.classList.add('hide')
8708    } else {
8709      promo.classList.remove('hide')
8710    }
8711  }
8712
8713
8714   if (cake) promo.classList.add('transition-with-cake')
8715 }
8716
8717const quizNew = document.querySelector('[data-element="quiz-new"]')
8718
8719if (quizNew) quizSoInit()
8720
8721function quizSoInit () {
8722  let index = 0
8723  const slides = quizNew.querySelectorAll('[data-element="quiz-so-slide"]')
8724  const buttonsNext = quizNew.querySelectorAll('[data-element="quiz-so-slide-next"]')
8725  const buttonsBack = quizNew.querySelectorAll('[data-element="quiz-so-slide-back"]')
8726  const btnSubmit = quizNew.querySelector('.btn-warning')
8727  const input = quizNew.querySelector("[data-element='input-phone-intl']")
8728  const inputName = quizNew.querySelector(".quiz-so-slide__form-input_name")
8729  const inputHidden = quizNew.querySelector("[data-element='input-phone-hidden']")
8730//   const inputsAll = quizNew.querySelectorAll('input');
8731  const policyCheckboxes = quizNew.querySelectorAll('.quiz-so-slide__checkbox-input')
8732  const linkTo = quizNew.getAttribute("data-docex")
8733  const utm_input = quizNew.querySelector('[name="utm"]')
8734  const inputsRadio = quizNew.querySelectorAll('.quiz-so-slide__input[type="radio"]')
8735
8736  buttonsNext.forEach(button => {
8737    button.addEventListener('click', nextSlide)
8738  })
8739
8740  window.addEventListener('resize', () => {
8741    quizNew.style.height = `${slides[index].clientHeight}px`
8742  }, { passive: true })
8743
8744  function nextSlide () {
8745    if (slides[index].querySelector('.quiz-so-slide__input') && !slides[index].querySelector('.quiz-so-slide__input
8745:checked')) {
8746      const inputs = slides[index].querySelectorAll('.quiz-so-slide__input')
8747      inputs.forEach(input => {
8748        input.classList.add('error')
8749        input.addEventListener('change', resetError, { once: true })
8750      })
8751      function resetError () {
8752        inputs.forEach(input => {
8753          input.classList.remove('error')
8754        })
8755      }
8756    } else if (index === slides.length - 1) {
8757
8758    } else {
8759      slides[index].classList.remove('active')
8760      index += 1
8761      slides[index].classList.add('active')
8762      quizNew.style.height = `${slides[index].clientHeight}px`
8763    }
8764  }
8765
8766  policyCheckboxes.forEach(policyCheckbox => {
8767    policyCheckbox.addEventListener('change', () => {
8768      policyCheckbox.parentNode.classList.remove('error')
8769    })
8770  })
8771
8772  if (inputName) inputName.addEventListener('input', () => {
8773    inputName.classList.remove('error')
8774  })
8775
8776  buttonsBack.forEach(button => {
8777    button.addEventListener('click', prevSlide)
8778  })
8779
8780  function prevSlide () {
8781    if (index === 0) return
8782    slides[index].classList.remove('active')
8783    index -= 1
8784    slides[index].classList.add('active')
8785    quizNew.style.height = `${slides[index].clientHeight}px`
8786  }
8787
8788  initLoaders()
8789
8790  function initLoaders () {
8791    slides.forEach((slide, index) => {
8792      const quizSoSlideLoaderFill = slide.querySelector('.quiz-so-slide__loader-fill')
8793      if (quizSoSlideLoaderFill) quizSoSlideLoaderFill.style.width = `${100 * index / slides.length}%`
8794      const quizSoSlideLoaderMobValue = slide.querySelector('.quiz-so-slide__loader-mob-value')
8795      if (quizSoSlideLoaderMobValue) quizSoSlideLoaderMobValue.innerHTML = Math.round(`${100 * index / slides.length}`) + '%'
8796      const quizSoSlideLoaderMobProgress = slide.querySelector('.quiz-so-slide__loader-mob-progress')
8797      if (quizSoSlideLoaderMobProgress) quizSoSlideLoaderMobProgress.style.strokeDashoffset = 250 - (140 * `${index / slides.length}`)
8798    })
8799  }
8800
8801  if (input && inputHidden) {
8802    iti = window.intlTelInput(input, {
8803      utilsScript: "../libs/intlTelInputWithUtils.min",
8804      initialCountry: 'ru',
8805      separateDialCode: true,
8806      strictMode: true
8807    })
8808
8809    input.addEventListener('input', function () {
8810      input.classList.remove('error')
8811      let tempValue = input.value
8812      inputHidden.value = input.value
8813      const cleanNumber = tempValue.replace(/[^+\d]/g, '')
8814      if (iti.selectedCountryData.dialCode === "7" && cleanNumber.length > 10) {
8815        inputHidden.value = cleanNumber.substring(cleanNumber.length - 10)
8816      }
8817      inputHidden.value = iti.selectedCountryData.dialCode + ' ' + inputHidden.value
8818    })
8819  }
8820  quizNew.addEventListener('submit', async (e) => {
8821    e.preventDefault()
8822    let isValid = true
8823    if (input && !input?.value?.trim() || !iti?.isValidNumber()) {
8824        input.classList.add("error")
8825        isValid = false
8826    }
8827    if (!inputName.value) {
8828        inputName.classList.add("error")
8829        isValid = false
8830    }
8831    if (!policyCheckboxes[0].checked) {
8832        policyCheckboxes[0].parentNode.classList.add("error")
8833        isValid = false
8834    }
8835    if (!policyCheckboxes[1].checked) {
8836        policyCheckboxes[1].parentNode.classList.add("error")
8837        isValid = false
8838    }
8839
8840    if (!isValid) {
8841        return false;
8842    }
8843        let linkTo_ = linkTo;
8844        if (utm_input) {
8845            utm_f = utm_input.value;
8846            if(utm_f != null && utm_f != '' && utm_f != undefined){
8847            }else{
8848                utm_f = ''
8849            }
8850            if (utm_f.length > 0) {
8851                linkTo_ = linkTo_ + utm_f;
8852            }
8853        }
8854        btnSubmit.disabled = true;
8855        //quizNew.submit()
8856        // var obData = {};
8857        // const whitelist = [
8858        //     'tel',
8859        //     'name',
8860        //     'policy',
8861        //     'news',
8862        //     'page_name',
8863        //     'utm',
8864        //     'class',
8865        //     'current-education-plan',
8866        //     'has-troubles',
8867        //     'school-position',
8868        //     'family-education-plan',
8869        //     'study-format',
8870        //     'need-help',
8871        //     'pay-format'];
8872
8873        // inputsAll.forEach(input => {
8874        //   if (input.name && whitelist.includes(input.name)) {
8875        //     if (input.type === 'radio') {
8876        //       if (input.checked) {
8877        //         obData[input.name] = input.value;
8878        //       }
8879        //     }else {
8880        //       obData[input.name] = input.value;
8881        //     }
8882        //   }
8883        // });
8884        
8885        // $.request('MainFunctions::onSendQuizSo', {
8886        //   data: obData,
8887        //     // success: function(data) {
8888        //     //     console.log(linkTo)
8889        //     //     //location.assign(linkTo)
8890        //     // },
8891        // })
8892        
8893        setTimeout(() => {
8894          location.assign(linkTo_)
8895        }, 100)
8896
8897  })
8898
8899  slides.forEach(slide => {
8900    const hidden = slide.querySelector('.quiz-so-slide__hidden-checkbox')
8901    if (!hidden) return
8902    const inputs = slide.querySelectorAll('.quiz-so-slide__input')
8903    for (let i = 0; i < inputs.length; i++) {
8904      inputs[i].addEventListener('input', function () {
8905        if (inputs[i].hasAttribute('data-single-check')) {
8906          const checked = slide.querySelectorAll("input:checked")
8907          for (let j = 0; j < checked.length; j++) {
8908            checked[j].checked = false
8909          }
8910          inputs[i].checked = true
8911          hidden.value = inputs[i].value
8912        } else {
8913          const inputSingleCheck = slide.querySelector("[data-single-check]")
8914          if (inputSingleCheck) inputSingleCheck.checked = false
8915          const checked = slide.querySelectorAll("input:checked")
8916          let temp = ''
8917          for (let j = 0; j < checked.length; j++) {
8918            temp += checked[j].value
8919            if (j !== checked.length - 1) temp += ', '
8920          }
8921          hidden.value = temp
8922        }
8923      })
8924    }
8925  })
8926  inputsRadio.forEach(input => {
8927    const link = input.getAttribute('data-redirect-quiz')
8928    if (link) {
8929      input.addEventListener('click', function () {
8930        let link_tr = link;
8931        if (utm_input) {
8932            utm_paramsToInsert = utm_input.value
8933            if(utm_paramsToInsert != null && utm_paramsToInsert != '' && utm_paramsToInsert != undefined){
8934            }else{
8935                utm_paramsToInsert = ''
8936            }
8937            if (utm_paramsToInsert.length > 0) {
8938                const link_parts = link_tr.split('#')
8939                if (link_parts.length === 1) {
8940                   link_tr += utm_paramsToInsert
8941                }else{
8942                   link_tr = `${link_parts[0]}${utm_paramsToInsert}#${link_parts[1]}`;
8943                }
8944            }
8945        }
8946        
8947        location.replace(link_tr)
8948      })
8949    } else {
8950      input.addEventListener('change', nextSlide)
8951    }
8952  })
8953}
8954
8955
8956const quiz = document.querySelector('[data-element="quiz"]')
8957
8958if (quiz) quizInit()
8959
8960function quizInit () {
8961  const generateData = {
8962    list_4: [
8963      ['Математика','Русский язык','Литературное чтение','Английский язык','Не планирую'],
8964      ['Математика','Русский язык','Окружающий мир','Литературное чтение','Английский язык','Музыка','Физическая культура','ИЗО и технология','Не планирую'],
8965      ['Математика','Русский язык','Окружающий мир','Литературное чтение','Английский язык','Музыка','Физическая культура','ИЗО и технология','Не планирую'],
8966      ['Математика','Русский язык','Окружающий мир','Литературное чтение','Английский язык','Музыка','Физическая культура','ИЗО и технология','Не планирую'],
8967      ['Математика','Русский язык','Окружающий мир','Литературное чтение','Английский язык','Музыка','Физическая культура','ИЗО и технология','Не планирую'],
8968      ['Математика','Русский язык','Литература','Биология','История','География','Английский язык','Музыка','Физическая культура','ИЗО и технология','Не планирую'],
8969      ['Математика','Русский язык','Литература','Биология','История','География','Английский язык','Музыка','Физическая культура','ИЗО и технология','Обществознание','Не планирую'],
8970      ['Математика','Русский язык','Литература','Биология','История','География','Английский язык','Музыка',
8971        'Физическая культура','ИЗО и технология','Обществознание','Физика','Химия','Информатика','Не планирую'],
8972      ['Математика','Русский язык','Литература','Биология','История','География','Английский язык','Музыка',
8973        'Физическая культура','ИЗО и технология','Обществознание','Физика','Химия','Информатика','Не планирую'],
8974      ['Русский язык','Литература','Английский язык','Математика','Информатика','Физика','Общество','История','География',
8975        'Биология','Химия','Физическая культура','Технология','ОБЗР','Не планирую'],
8976      ['Русский язык','Литература','Английский язык','Математика','Информатика','Физика','Общество','История','География',
8977        'Биология','Химия','Физическая культура','ОБЗР','Не планирую'],
8978      ['Русский язык','Литература','Английский язык','Математика','Информатика','Физика','Общество','История','География',
8979        'Биология','Химия','Физическая культура','ОБЗР','Не планирую'],
8980    ],
8981     list_5: [
8982      [],
8983      ['Китайский язык','Французский язык','Компьютерная грамотность','Программирование в Minecraft','Программирование в Scratch',
8984        'Шахматы','Блогинг','Испанский язык','Немецкий язык','Олимпиадный русский язык','Не планирую'],
8985      ['Китайский язык','Французский язык','Математика и логика. Первые шаги в олимпиадах','Компьютерная грамотность',
8986        'Программирование в Minecraft','Программирование в Scratch','Шахматы','Блогинг','Испанский язык','Немецкий язык',
8987        'Олимпиадный русский язык','Не планирую'],
8988      ['Китайский язык','Французский язык','Математика и логика. Первые шаги в олимпиадах','Компьютерная грамотность',
8989        'Программирование в Minecraft','Программирование в Scratch','Курс по разработке игр в Roblox','Ораторское мастерство',
8990        'Финансовая грамотность','Эмоциональный интеллект','Шахматы','Блогинг','Испанский язык','Немецкий язык',
8991        'Олимпиадный русский язык','Не планирую'],
8992      ['Китайский язык','Французский язык','Математика и логика. Первые шаги в олимпиадах','Компьютерная грамотность',
8993        'Программирование в Minecraft','Программирование в Scratch','Курс по разработке игр в Roblox','Ораторское мастерство',
8994        'Финансовая грамотность','Эмоциональный интеллект','Шахматы','Блогинг','Испанский язык','Немецкий язык',
8995        'Олимпиадный русский язык','Не планирую'],
8996      ['Китайский язык','Французский язык','Математика и логика. Первые шаги в олимпиадах','Программирование на Python',
8997        'Создание сайтов','Компьютерная грамотность','Программирование в Minecraft','Программирование в Scratch',
8998        'Курс по разработке игр в Roblox','Графический дизайн в Figma','Ораторское мастерство','Финансовая грамотность',
8999        'Эмоциональный интеллект','Шахматы','Блогинг','Испанский язык','Немецкий язык',
9000        'Олимпиадный русский язык','Не планирую'],
9001      ['Китайский язык','Французский язык','Математика и логика. Первые шаги в олимпиадах','Программирование на Python',
9002        'Создание сайтов','Компьютерная грамотность','Программирование в Minecraft','Программирование в Scratch',
9003        'Курс по разработке игр в Roblox','Графический дизайн в Figma','Ораторское мастерство','Финансовая грамотность',
9004        'Эмоциональный интеллект','Шахматы','Блогинг','Испанский язык','Немецкий язык',
9005        'Олимпиадный русский язык','Не планирую'],
9006      ['Китайский язык','Французский язык','Математика и логика. Первые шаги в олимпиадах','Программирование на Python',
9007        'Создание сайтов','Компьютерная грамотность','Курс по разработке игр в Roblox','Графический дизайн в Figma',
9008        'Ораторское мастерство','Финансовая грамотность','Эмоциональный интеллект','Шахматы','Блогинг','Испанский язык',
9009        'Немецкий язык','Олимпиадный русский язык','Не планирую'],
9010      ['Китайский язык','Французский язык','Математика и логика. Первые шаги в олимпиадах','Программирование на Python',
9011        'Создание сайтов','Компьютерная грамотность','Курс по разработке игр в Roblox','Графический дизайн в Figma',
9012        'Ораторское мастерство','Финансовая грамотность','Эмоциональный интеллект','Шахматы','Блогинг','Испанский язык',
9013        'Немецкий язык','Олимпиадный русский язык','Не планирую'],
9014      ['Подготовка к ОГЭ по математике','Подготовка к ОГЭ по русскому языку','Подготовка к ОГЭ по биологии','Подготовка к ОГЭ по истории',
9015        'Подготовка к ОГЭ по английскому языку','Подготовка к ОГЭ по обществознанию','Подготовка к ОГЭ по физике','Подготовка к ОГЭ по химии',
9016        'Подготовка к ОГЭ по информатике','Подготовка к ОГЭ по географии','Подготовка к ОГЭ по литературе',
9017        'Китайский язык','Французский язык','Программирование на Python','Создание сайтов','Компьютерная грамотность',
9018        'Курс по разработке игр в Roblox','Графический дизайн в Figma','Ораторское мастерство','Финансовая грамотность',
9019        'Эмоциональный интеллект','Шахматы','Блогинг','Цифровые профессии','Испанский язык','Немецкий язык',
9020        'Подготовка к перечневым олимпиадам по математике','Олимпиадный русский язык','Не планирую'],
9021      ['Подготовка к ЕГЭ по математике','Подготовка к ЕГЭ по русскому языку','Подготовка к ЕГЭ по биологии','Подготовка к ЕГЭ по истории',
9022        'Подготовка к ЕГЭ по английскому языку','Подготовка к ЕГЭ по обществознанию','Подготовка к ЕГЭ по физике','Подготовка к ЕГЭ по химии',
9023        'Подготовка к ЕГЭ по информатике','Подготовка к ЕГЭ по географии','Подготовка к ЕГЭ по литературе',
9024        'Китайский язык','Французский язык','Программирование на Python','Создание сайтов','Графический дизайн в Figma',
9025        'Ораторское мастерство','Финансовая грамотность','Эмоциональный интеллект','Шахматы','Блогинг','Цифровые профессии',
9026        'Испанский язык','Немецкий язык','Подготовка к перечневым олимпиадам по математике','Олимпиадный русский язык','Не планирую'
9027      ],
9028      ['Подготовка к ЕГЭ по профильной математике','Подготовка к ЕГЭ по базовой математике','Подготовка к ЕГЭ по русскому языку',
9029        'Подготовка к ЕГЭ по биологии','Подготовка к ЕГЭ по истории',
9030        'Подготовка к ЕГЭ по английскому языку','Подготовка к ЕГЭ по обществознанию','Подготовка к ЕГЭ по физике','Подготовка к ЕГЭ по химии',
9031        'Подготовка к ЕГЭ по информатике','Подготовка к ЕГЭ по географии','Подготовка к ЕГЭ по литературе',
9032        'Китайский язык','Французский язык','Программирование на Python','Создание сайтов','Графический дизайн в Figma',
9033        'Ораторское мастерство','Финансовая грамотность','Эмоциональный интеллект','Шахматы','Блогинг','Цифровые профессии',
9034        'Испанский язык','Немецкий язык','Подготовка к перечневым олимпиадам по математике','Олимпиадный русский язык',
9035        'Не планирую']
9036    ]
9037  }
9038
9039  let currentSlide = 0
9040  let classChosen
9041  const nextBtns = quiz.querySelectorAll('[data-element="quiz-next"]')
9042  const prevBtns = quiz.querySelectorAll('[data-element="quiz-prev"]')
9043  const slides = quiz.querySelectorAll('[data-element="quiz-inner"]')
9044  const form = quiz.querySelector('[data-element="quiz-form"]')
9045  const linkTo = form.getAttribute("data-docex")
9046  const wrap = quiz.querySelector('.quiz__wrap')
9047  const progress = quiz.querySelector('[data-element="quiz-progress"]')
9048  const progressFill = quiz.querySelector('[data-element="quiz-progress-bar-fill"]')
9049
9050  function initValidate () {
9051    const button = slides[currentSlide].querySelector("[data-element='quiz-next']")
9052    const input = slides[currentSlide].querySelectorAll('.quiz__input')
9053    if (input[0].type === 'text') {
9054      for (let i = 0; i < input.length; i++) {
9055        input[i].addEventListener('input', function () {
9056          button.disabled = !input[0].value || !input[1].value
9057        })
9058      }
9059    } else if (input[0].type === 'radio') {
9060      for (let i = 0; i < input.length; i++) 
9060{
9061        input[i].addEventListener('input', function () {
9062          const checked = slides[currentSlide].querySelector("input:checked")
9063          button.disabled = !checked
9064        })
9065      }
9066    } else {
9067      const hidden = slides[currentSlide].querySelector('.quiz__hidden-checkbox')
9068      for (let i = 0; i < input.length; i++) {
9069        input[i].addEventListener('input', function () {
9070          const checked = slides[currentSlide].querySelectorAll("input:checked")
9071          button.disabled = !checked.length
9072          let temp = ''
9073          for (let j = 0; j < checked.length; j++) {
9074            temp += checked[j].value
9075            if (j !== checked.length - 1) temp += ', '
9076          }
9077          hidden.value = temp
9078        })
9079      }
9080    }
9081  }
9082
9083  function initValidateLastSlide () {
9084    const inputs = slides[currentSlide].querySelectorAll('input')
9085
9086    for (let i = 0; i < inputs.length; i++) {
9087      inputs[i].addEventListener('change', validate)
9088    }
9089    function validate () {
9090      if (inputs[inputs.length - 1].checked) {
9091        for (let i = 0; i < inputs.length - 1; i++) {
9092          if (inputs[i].getAttribute('type') != 'hidden') {
9093            inputs[i].disabled = true
9094            inputs[i].closest('.quiz__label')?.classList?.add('disable')
9095          }
9096        }
9097      } else {
9098        for (let i = 0; i < inputs.length - 1; i++) {
9099          inputs[i].disabled = false
9100          inputs[i].closest('.quiz__label')?.classList?.remove('disable')
9101        }
9102      }
9103      let disableLastInput = false
9104      for (let i = 0; i < inputs.length - 1; i++) {
9105        if (inputs[i].checked) {
9106          inputs[inputs.length - 1].disabled = true
9107          inputs[inputs.length - 1].closest('.quiz__label').classList.add('disable')
9108          disableLastInput = true
9109        }
9110      }
9111      if (!disableLastInput) {
9112        inputs[inputs.length - 1].disabled = false
9113        inputs[inputs.length - 1].closest('.quiz__label').classList.remove('disable')
9114      }
9115    }
9116  }
9117
9118  for (let i = 0; i < nextBtns.length; i++) {
9119    nextBtns[i].addEventListener('click', nextSlide)
9120  }
9121
9122  for (let i = 0; i < prevBtns.length; i++) {
9123    prevBtns[i].addEventListener('click', prevSlide)
9124  }
9125
9126  initValidate()
9127
9128  function nextSlide () {
9129    window.scrollTo({ top: 0, behavior: 'smooth' })
9130    if (currentSlide === 0) {
9131      progress.classList.remove('hide')
9132      wrap.classList.remove('quiz__wrap_first-slide')
9133    }
9134    if (currentSlide === 1) {
9135      classChosen = slides[currentSlide].querySelector('input:checked').value
9136      const button = slides[currentSlide + 2].querySelector('.quiz__button')
9137      if (classChosen === "0") {
9138        currentSlide += 1
9139        button.type = 'submit'
9140        button.textContent = 'Отправить ответы'
9141        button.disabled = true
9142      } else {
9143        button.type = 'button'
9144        button.textContent = 'Дальше'
9145        button.disabled = true
9146      }
9147    } else if (currentSlide === 2) {
9148      if (slides[currentSlide].querySelector('input:checked').value === "Да") {
9149        currentSlide += 1
9150      }
9151    } else if (currentSlide === 3 && classChosen === "0") {
9152      sendData()
9153    }
9154
9155    if (currentSlide < slides.length - 1) {
9156      const generateListNode = slides[currentSlide + 1].querySelector('[data-element="quiz-generate"]')
9157      if (generateListNode) generateList(generateListNode)
9158
9159      const oldActiveSlide = quiz.querySelector('.quiz__inner.active')
9160      oldActiveSlide.classList.remove('active')
9161      currentSlide += 1
9162      slides[currentSlide].classList.add('active')
9163      initValidate()
9164      if (currentSlide === slides.length - 1 || generateListNode) initValidateLastSlide()
9165    } else {
9166      sendData()
9167    }
9168    progressFill.style.width = Math.round(currentSlide/(slides.length - 1) * 100) + '%'
9169  }
9170
9171  function prevSlide () {
9172    if (currentSlide > 0) {
9173      if (currentSlide === 1) {
9174        progress.classList.add('hide')
9175        wrap.classList.add('quiz__wrap_first-slide')
9176      }
9177
9178      if (currentSlide === 4 && slides[2].querySelector('input:checked').value === "Да") {
9179        currentSlide -= 1
9180      } else if (currentSlide === 3 && classChosen === "0") {
9181        currentSlide -= 1
9182      }
9183
9184      const oldActiveSlide = quiz.querySelector('.quiz__inner.active')
9185      oldActiveSlide.classList.remove('active')
9186      currentSlide -= 1
9187      slides[currentSlide].classList.add('active')
9188
9189      progressFill.style.width = Math.round(currentSlide/(slides.length - 1) * 100) + '%'
9190    }
9191  }
9192
9193  function sendData () {
9194    if (checkHoneypot()) return
9195    form.submit()
9196    setTimeout(() => {
9197      location.assign(linkTo)
9198    }, 100)
9199  }
9200
9201  function checkHoneypot() {
9202    const honeypots = form.querySelector('.modal-exter__input')
9203    return honeypots && honeypots?.value
9204  }
9205
9206
9207  function generateList (list) {
9208    const type = list.getAttribute('data-type')
9209    const name = list.getAttribute('data-name')
9210    const array = (generateData[list.getAttribute('data-list')])[classChosen]
9211    list.innerHTML = ''
9212    for (let i = 0; i < array.length; i++) {
9213      const nameInput = type === "radio" ? name : false
9214      let item
9215      if (nameInput) {
9216        item = `<label class="quiz__label">
9217        <input class="quiz__input" type="${type}" name="${nameInput}" value="${array[i]}">
9218        <div class="${'quiz__input-view quiz__input-view_' + type}"></div>
9219        <div class="quiz__input-text">${array[i]}</div>
9220      </label>`
9221      } else {
9222        item = `<label class="quiz__label">
9223        <input class="quiz__input" type="${type}" value="${array[i]}">
9224        <div class="${'quiz__input-view quiz__input-view_' + type}"></div>
9225        <div class="quiz__input-text">${array[i]}</div>
9226      </label>`
9227      }
9228
9229      list.innerHTML += item
9230    }
9231  }
9232}
9233
9234const reasons = document.querySelector('.reasons')
9235
9236if (reasons) reasonsInit()
9237
9238function reasonsInit () {
9239  window.scrollTo(0, 0)
9240  const body = document.querySelector('body')
9241  body.classList.add('no-scroll')
9242  const area = reasons.querySelector('.reasons__area')
9243  const circles = reasons.querySelectorAll('.reasons__circle')
9244  const caption = reasons.querySelector('.reasons__caption')
9245  const image = reasons.querySelector('.reasons__image')
9246
9247  const step = 300
9248  let index = -1
9249  let touchstartY = 0
9250  let touchendY = 0
9251  const swipeThreshold = 50
9252
9253  function throttle(func, delay) {
9254    let inThrottle
9255    let lastFn
9256    let lastTime
9257
9258    return function() {
9259      const context = this
9260      const args = arguments
9261
9262      if (!inThrottle) {
9263        func.apply(context, args)
9264        lastTime = Date.now()
9265        inThrottle = true
9266      } else {
9267        clearTimeout(lastFn)
9268        lastFn = setTimeout(function() {
9269          if (Date.now() - lastTime >= delay) {
9270            func.apply(context, args)
9271            lastTime = Date.now()
9272          }
9273        }, Math.max(delay - (Date.now() - lastTime), 0))
9274      }
9275    }
9276  }
9277
9278  let lock = false
9279
9280  function update (e) {
9281    if (lock) return
9282    if (e.deltaY < 0) {
9283      prevSlide()
9284    } else if (e.deltaY > 0) {
9285      nextSlide()
9286    }
9287    lock = true
9288    setTimeout(() => {lock = false}, 600)
9289  }
9290
9291  window.addEventListener('touchstart', e => {
9292    touchstartY = e.touches[0].clientY
9293  })
9294
9295  window.addEventListener('touchend', e => {
9296    touchendY = e.changedTouches[0].clientY
9297    handleGesture()
9298  })
9299
9300  function handleGesture() {
9301    if (touchendY < touchstartY - swipeThreshold) {
9302      nextSlide()
9303    }
9304
9305    if (touchendY > touchstartY + swipeThreshold) {
9306      prevSlide()
9307    }
9308  }
9309
9310  window.addEventListener('wheel', update, { passive: true })
9311
9312  function prevSlide () {
9313    if (index > -1 && window.scrollY === 0) {
9314      body.classList.add('no-scroll')
9315      if (area) area.classList.remove('end')
9316      hideOldSlide()
9317      index--
9318      showNewSlide()
9319      animateBg()
9320      if (index === -1) {
9321        caption.classList.remove('animate')
9322        image.classList.remove('animate')
9323        area.classList.remove('animate')
9324        circles[0].classList.remove('animate-end')
9325      }
9326    }
9327  }
9328  
9329  function nextSlide () {
9330    if (index < circles.length - 1) {
9331      hideOldSlide()
9332      index++
9333      showNewSlide()
9334      animateBg()
9335      if (index === 0) {
9336        caption.classList.add('animate')
9337        image.classList.add('animate')
9338        area.classList.add('animate')
9339        circles[0].classList.add('animate-end')
9340      }
9341      if (index === circles.length - 1) {
9342        area.classList.add('end')
9343        body.classList.remove('no-scroll')
9344      }
9345    }
9346  }
9347
9348  function hideOldSlide () {
9349    if (circles[index]) circles[index].classList.remove('animate')
9350  }
9351
9352  function showNewSlide () {
9353    if (circles[index]) circles[index].classList.add('animate')
9354  }
9355
9356  function animateBg () {
9357    reasons.style.backgroundPositionY = `${step * (index+1)}px`
9358  }
9359}
9360
9361const reviewDetailVideoBox = document.querySelector('.review-detail__video-box')
9362
9363if (reviewDetailVideoBox) {
9364  const video = reviewDetailVideoBox.querySelector('.review-detail__video')
9365
9366  reviewDetailVideoBox.addEventListener('click', function () {
9367    playVideo()
9368  }, {once: true})
9369
9370
9371  function playVideo () {
9372    video.play()
9373    reviewDetailVideoBox.classList.add('active')
9374  }
9375
9376}
9377
9378
9379const review = document.querySelector('.review')
9380
9381if (review) reviewInit()
9382
9383function reviewInit() {
9384  const textReplace = {
9385    parent: [
9386      { selector: '.review__caption_thanks-1', text: 'Спасибо, что поделились опытом!' },
9387      { selector: '.review__caption_thanks-2', text: 'Спасибо за ваш отзыв!' },
9388      { selector: '.review__headline-thanks-1', text: 'Дайте вашему мнению реальную силу' },
9389      { selector: '.review__thanks-title', text: 'Ваш отзыв — ориентир для других родителей.' },
9390      { selector: '.review__thanks-text_1', text: 'Многие родители сейчас ищут честные отзывы, чтобы сделать выбор для своего ребенка.' },
9391    //   { selector: '.review__thanks-text_2', text: 'Ваш отзыв на <a href="https://www.rbc.ru/courses/school-reviews/tocka-znanii" data-redirect>
9391РБК</a> станет для них весомым аргументом, который сэкономит время, деньги и нервы.' },
9392      { selector: '.review__thanks-text_2', text: 'Ваш отзыв на Отзовике станет для них весомым аргументом, который сэкономит время, деньги и нервы.' },
9393    //   { selector: '.review__thanks-headline_1', text: 'Пожалуйста, скопируйте свой отзыв и добавьте на РБК.' },
9394      { selector: '.review__thanks-headline_1', text: 'Пожалуйста, скопируйте свой отзыв и добавьте на Отзовик.' },
9395      { selector: '.review__thanks-headline_2', text: 'Это займёт 2 минуты. Пусть ваш голос поможет с выбором и станет ориентиром.' },
9396      { selector: '.review__thanks-headline_3', text: 'Оставьте отзыв и помогите другим родителям!' },
9397      { selector: '.review__thanks-2-title', text: 'Если вы хотите оставить отзыв на других учителей или тьюторов, нажмите на кнопки ниже' },
9398    ],
9399    student: [
9400      { selector: '.review__caption_thanks-1', text: 'Спасибо, что делишься опытом!' },
9401      { selector: '.review__caption_thanks-2', text: 'Спасибо за твой отзыв!' },
9402      { selector: '.review__headline-thanks-1', text: 'Дайте своему мнению реальную силу' },
9403      { selector: '.review__thanks-title', text: 'Твой отзыв — ориентир для других учеников.' },
9404      { selector: '.review__thanks-text_1', text: 'Новичкам онлайн-обучения тоже бывает трудно: кто-то боится непонятных тем, сложной домашки или остаться без поддержки учителей.' },
9405      { selector: '.review__thanks-text_2', text: 'Твой отзыв поможет им понять, что трудности решаемы и  поддержка рядом. Благодаря тебе другие ребята смогут сделать уверенный выбор' },
9406    //   { selector: '.review__thanks-headline_1', text: 'Пожалуйста, скопируй свой отзыв и добавь на РБК.' },
9407      { selector: '.review__thanks-headline_1', text: 'Пожалуйста, скопируй свой отзыв и добавь на Отзовик.' },
9408      { selector: '.review__thanks-headline_2', text: 'Это займёт 2 минуты.' },
9409      { selector: '.review__thanks-headline_3', text: 'Оставь отзыв и помоги другим школьникам!' },
9410      { selector: '.review__thanks-2-title', text: 'Если ты хочешь оставить отзыв на других учителей или тьюторов, нажми на кнопки ниже' },
9411    ]
9412  }
9413
9414  const selectTops = review.querySelectorAll('.review__select-top')
9415  const body = document.querySelector('body')
9416  const copy = review.querySelector('.review__thanks-copy')
9417  const textarea = review.querySelector('.review__textarea')
9418  const buttonNext = review.querySelector('.review__button')
9419  const buttonBack = review.querySelector('.review__back')
9420  const buttonMobBack = review.querySelector('.review__mob-back')
9421  const slides = review.querySelectorAll('.review__slide')
9422  const steps = review.querySelectorAll('.review__step')
9423  const form = review.querySelector('.review__form')
9424  const inputRate = review.querySelector('.review__rate-hidden')
9425  const inputRateDesktop = review.querySelectorAll('.review__rate-desktop-input')
9426  const selectSearchArray = review.querySelectorAll('.review__select-search')
9427  const simpleBars = review.querySelectorAll('[data-role="review-simplebar"]')
9428  const btnSubmit = form.querySelector('.review__submit')
9429  const role = review.querySelector('.review__role')
9430  const roleInputs = review.querySelectorAll('.review__role-input')
9431  const nameInput = review.querySelector("[name='st_name']")
9432  const surnameInput = review.querySelector("[name='st_surname']")
9433  const emailInput = review.querySelector("[name='email']")
9434  const selectClass = review.querySelector(".review__select_class")
9435  const selectClassInputs = selectClass.querySelectorAll(".review__select-input")
9436  const rateDesktop = review.querySelector(".review__rate-desktop")
9437  const selectsOnSecondSlide = slides[1].querySelectorAll('.review__select')
9438  const selectTopCloseArray = slides[1].querySelectorAll('.review__select-top-close')
9439  const subjectItems = document.querySelectorAll('.review__select_subject .review__select-item')
9440  const boxSubject = document.querySelector('.review__box_subject')
9441  const closeArrows = document.querySelectorAll('.review__select-top-close-arrow')
9442  const selectTeacherOrTutor = document.querySelector('.review__select_teacher') || document.querySelector('.review__select_tutor')
9443  const head_1 = review.querySelector('.review__thanks-headline_1')
9444  const head_2 = review.querySelector('.review__thanks-headline_2')
9445  const copyBox = review.querySelector('.review__thanks-copy-box')
9446
9447
9448  for (let i = 0; i < closeArrows.length; i++) {
9449    closeArrows[i].addEventListener('click', function (e) {
9450      e.stopPropagation()
9451      closeSelect(closeArrows[i].closest('.review__select-top'))
9452    })
9453  }
9454
9455  for (let i = 0; i < selectsOnSecondSlide.length; i++) {
9456    const inputs = selectsOnSecondSlide[i].querySelectorAll('.review__select-input')
9457    for (let j = 0; j < inputs.length; j++) {
9458      inputs[j].addEventListener('change', () => {
9459        selectsOnSecondSlide[i].classList.remove('review-error')
9460      })
9461    }
9462  }
9463
9464  for (let i = 0; i < selectClassInputs.length; i++) {
9465    const selectSearch = selectTeacherOrTutor.querySelector('.review__select-search')
9466    selectClassInputs[i].addEventListener('change', function () {
9467      selectClass.classList.remove('review-error')
9468      resetTeachersSort()
9469      resetSubjectCheckedInput(true)
9470      resetSearchCheckedInput()
9471      selectSort(selectSearch)
9472      clearSelectText(selectTeacherOrTutor)
9473      teachersSort(this.value)
9474    })
9475  }
9476
9477  function teachersSort (selectedClass) {
9478    const searchLabels = selectTeacherOrTutor.querySelectorAll('.review__select-item')
9479    searchLabels.forEach(label => {
9480      const input = label.querySelector('.review__select-input')
9481      const dataGrades = input.getAttribute('data-grades')
9482      if (!dataGrades) return
9483      const dataGradesParsed = JSON.parse(dataGrades)
9484      if (!(dataGradesParsed.find((data) => data == selectedClass))) label.classList.add('review__select-item_hide')
9485    })
9486  }
9487
9488  function resetTeachersSort () {
9489    const searchLabels = selectTeacherOrTutor.querySelectorAll('.review__select-item')
9490    searchLabels.forEach(label => {
9491      label.classList.remove('review__select-item_hide')
9492    })
9493  }
9494
9495  for (let i = 0; i < roleInputs.length; i++) {
9496    roleInputs[i].addEventListener('change', () => {
9497      role.classList.remove('review-error')
9498      const value = review.querySelector('.review__role-input:checked')?.value
9499      replaceTexts(value)
9500    })
9501  }
9502
9503  function replaceTexts(value) {
9504    if (value === 'student') {
9505      review.classList.add('review_student')
9506    } else {
9507      review.classList.remove('review_student')
9508    }
9509    textReplace[value].forEach((item) => {
9510      const node = review.querySelector(item.selector)
9511      node.innerHTML = item.text
9512      const dataRedirectLinks = node.querySelectorAll('[data-redirect]')
9513      for (let i = 0; i < dataRedirectLinks.length; i++) {
9514        dataRedirectLinks[i].addEventListener('click', dataRedirect)
9515      }
9516    })
9517
9518  }
9519
9520  nameInput.addEventListener('input', () => nameInput.classList.remove('review-error'))
9521  surnameInput.addEventListener('input', () => surnameInput.classList.remove('review-error'))
9522  emailInput.addEventListener('input', () => emailInput.classList.remove('review-error'))
9523
9524  function validateEmail (email) {
9525    if (/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(email.value)) {
9526      email.classList.remove('review-error')
9527      return true
9528    } else {
9529      email.classList.add('review-error')
9530      return false
9531    }
9532  }
9533
9534  for (let i = 0; i < simpleBars.length; i++) {
9535    new SimpleBar(simpleBars[i])
9536  }
9537
9538  selectTopCloseArray.forEach((topClose) => {
9539    topClose.addEventListener('click', function () {
9540      const select = this.closest('.review__select')
9541      const selectTop = this.closest('.review__select-top')
9542      const selectSearch = selectTop.querySelector('.review__select-search')
9543      selectSearch.value = ''
9544      selectSort(selectSearch)
9545      closeSelect(selectTop)
9546      if (select.classList.contains('review__select_teacher') || select.classList.contains('review__select_tutor')) {
9547        resetSearchCheckedInput(selectSearch)
9548        resetSubjectCheckedInput(true)
9549      } else {
9550        resetSubjectCheckedInput(false)
9551      }
9552      const selectTopText = selectTop?.querySelector('.review__select-top-text')
9553      if (selectTopText) {
9554        selectTopText.classList.remove('active')
9555        selectTopText.innerHTML = selectTopText.getAttribute('data-default-text')
9556      }
9557    })
9558  })
9559  
9560
9561  selectSearchArray.forEach((selectSearch) => {
9562    const select = selectSearch.closest('.review__select')
9563    selectSearch.addEventListener('input', () => selectSort(selectSearch))
9564    selectSearch.addEventListener('input', () => resetSearchCheckedInput(selectSearch))
9565    if (select.classList.contains('review__select_teacher') || select.classList.contains('review__select_tutor')) {
9566      selectSearch.addEventListener('input', () => resetSubjectCheckedInput(true))
9567      selectSearch.addEventListener('input', () => subjectsFilter(selectSearch))
9568    }
9569    const reviewSearchMob = select.querySelector('.review__search-mob')
9570    if (reviewSearchMob) {
9571      reviewSearchMob.addEventListener('input', () => selectSort(reviewSearchMob))
9572    }
9573  })
9574
9575  function resetSearchCheckedInput (selectSearch) {
9576    const checkedInput = selectSearch?.closest('.review__select')?.querySelector('.review__select-input:checked')
9577    if (checkedInput) checkedInput.checked = false
9578  }
9579
9580  function resetSubjectCheckedInput (disabled) {
9581    const select = document.querySelector('.review__select_subject')
9582    clearSelectText(select)
9583    if (disabled) {
9584      boxSubject.classList.add('review__box_disabled')
9585      const search = select.querySelector('.review__select-search')
9586      selectSort(search)
9587    }
9588  }
9589
9590  function clearSelectText (select) {
9591    const checkedInput = select.querySelector('.review__select-input:checked')
9592    if (checkedInput) checkedInput.checked = false
9593    const text = select.querySelector('.review__select-top-text')
9594    if (text) text.innerHTML = 'Не выбрано'
9595    const search = select.querySelector('.review__select-search')
9596    if (search) search.value = ''
9597    const searchMob = select.querySelector('.review__search-mob')
9598    if (searchMob) searchMob.value = ''
9599  }
9600
9601  function subjectsFilter (selectSearch) {
9602    const checkedInput = selectSearch.closest('.review__select')?.querySelector('.review__select-input:checked')
9603    if (checkedInput) {
9604      const dataSubjects = checkedInput.getAttribute('data-subjects')
9605      if (!dataSubjects) return
9606      const dataSubjectsParsed = JSON.parse(dataSubjects)
9607      hideAllSubjects()
9608      for (let i = 0; i < dataSubjectsParsed.length; i++) {
9609        const subject = document.querySelector(`[data-subject="${dataSubjectsParsed[i]}"]`)
9610        if (subject) subject.closest('.review__select-item').classList.remove('review__select-item_hide')
9611      }
9612    } else {
9613      showAllSubjects()
9614    }
9615  }
9616
9617  function hideAllSubjects () {
9618    for (let i = 0; i < subjectItems.length; i++) {
9619      subjectItems[i].classList.add('review__select-item_hide')
9620    }
9621  }
9622
9623  function showAllSubjects () {
9624    for (let i = 0; i < subjectItems.length; i++) {
9625      subjectItems[i].classList.remove('review__select-item_hide')
9626    }
9627  }
9628
9629
9630  function selectSort (search) {
9631    const select = search.closest('.review__select')
9632    const searchLabels = select.querySelectorAll('.review__select-item')
9633    const reviewSearchMob = select.querySelector('.review__search-mob')
9634    if (search.classList.contains('review__select-search')) {
9635      reviewSearchMob.value = search.value
9636    } else {
9637      search.value = reviewSearchMob.value
9638    }
9639    const searchString = search.value.toLowerCase()
9640    const searchSelect = search.closest('.review__select')
9641    if (searchString) {
9642      searchSelect.classList.add('review__select_not-empty')
9643    } else {
9644      searchSelect.classList.remove('review__select_not-empty')
9645    }
9646    for (let i = 0; i < searchLabels.length; i++) {
9647      const text = searchLabels[i].querySelector('.review__select-input').getAttribute('data-text').toLowerCase()
9648      if (text.startsWith(searchString) || text === searchString) {
9649        searchLabels[i].style.display = 'block'
9650      } else {
9651        searchLabels[i].style.display = 'none'
9652      }
9653    }
9654  }
9655
9656  copy.addEventListener('click', copyReview)
9657
9658  function copyReview () {
9659    steps[2].classList.add('done')
9660    navigator.clipboard.writeText(textarea.value)
9661    copy.textContent = 'Скопировано'
9662    copy.classList.add('done')
9663    setTimeout(() => {
9664      copy.textContent = 'Скопировать отзыв'
9665      copy.classList.remove('done')
9666    }, 2000)
9667  }
9668
9669  for (let i = 0; i < inputRateDesktop.length; i++) {
9670    inputRateDesktop[i].addEventListener('change', setRateInputValue)
9671  }
9672
9673  function setRateInputValue () {
9674    inputRate.value = review.querySelector('.review__rate-desktop-input:checked').value
9675    rateDesktop.classList.remove('review-error')
9676  }
9677
9678  buttonNext.addEventListener('click', nextSlide)
9679  buttonBack.addEventListener('click', prevSlide)
9680  buttonMobBack.addEventListener('click', prevSlide)
9681  let isSubmitting = false;
9682  form.addEventListener('submit', submitForm)
9683
9684  function afterSuccessSubmit () {
9685    const oldSlide = review.querySelector('.review__slide.active')
9686    if (oldSlide) oldSlide.classList.remove('active')
9687    if (inputRate.value > 8) {
9688      slides[2].classList.add('active')
9689      review.classList.add('review_thanks-1')
9690      if (!textarea.value) {
9691        head_1.style.display = 'none'
9692        head_2.style.display = 'none'
9693        copyBox.style.display = 'none'
9694      } else {
9695        head_1.style.display = 'block'
9696        head_2.style.display = 'block'
9697        copyBox.style.display = 'flex'
9698      }
9699
9700    } else {
9701      slides[3].classList.add('active')
9702      steps[2].classList.add('done')
9703      review.classList.add('review_thanks-2')
9704    }
9705    steps[1].classList.add('done')
9706    steps[2].classList.add('active')
9707    window.scrollTo(0, 0)
9708  }
9709
9710  async function submitForm (e) {
9711    e.preventDefault()
9712    if (!validateSecondSlide()) return
9713    const email = form.querySelector('[name="email"]')
9714    if (email) {
9715      email_value = email.value;
9716    }
9717
9718    btnSubmit.disabled = true;
9719
9720    if (checkHoneypot()) return
9721
9722    try {
9723      e.stopPropagation();
9724      console.log('isSubmitting:', isSubmitting);
9725      if (isSubmitting) return false;
9726
9727    //   if (!captchaPassed) {
9728    //     // console.log('🔄 Вызов execute...');
9729        captchaToken = null;
9730    //     window.smartCaptcha.execute(window.captchaWidget);
9731
9732    //     await new Promise((resolve, reject) => {
9733    //       const checkToken = setInterval(() => {
9734    //         if (captchaToken) {
9735    //           clearInterval(checkToken);
9736    //           resolve();
9737    //         }
9738    //       }, 100);
9739
9740    //       setTimeout(() => {
9741    //         clearInterval(checkToken);
9742    //         reject(new Error('Таймаут капчи'));
9743    //       }, 100000);
9744    //     });
9745
9746    //     // console.log('✅ Токен получен:', captchaToken);
9747    //   } else {
9748    //     // console.log('✅ Капча уже пройдена, пропускаем проверку');
9749    //   }
9750
9751
9752    //   if (captchaToken) {
9753
9754
9755        // console.log(globalForm);
9756        isSubmitting = true;
9757        //   console.log('Отправка формы:', review);
9758
9759        const dataRequest = form.getAttribute('data-request');
9760        const formData = new FormData(form);
9761        const formObject = {};
9762        formData.forEach((value, key) => {
9763          formObject[key] = value;
9764        });
9765        formObject['smart-token'] = captchaToken;
9766
9767        //formObject.captcha_token = captchaToken;
9768
9769        $.request('MainFunctions::' + dataRequest, {
9770          data: formObject,
9771          success: function(response) {
9772            // console.log('Ответ:', response);
9773            let hasErrors = false;
9774
9775            for (let key in response) {
9776              if (key.startsWith('.')) {
9777                const className = key.substring(1);
9778                const element = document.querySelector('.' + className);
9779
9780                if (element) {
9781                  element.innerHTML = response[key];
9782                  hasErrors = true;
9783                  btnSubmit.disabled = false;
9784                }
9785              }
9786            }
9787
9788            if (hasErrors) {
9789              isSubmitting = false;
9790              return;
9791            } else {
9792              afterSuccessSubmit()
9793            }
9794          },
9795          error: function(error) {
9796            // console.error('❌ Ошибка отправки:', error);
9797            isSubmitting = false;
9798          }
9799        });
9800
9801        return false;
9802    //   }else{
9803    //     return false;
9804    //   }
9805
9806    } catch (error) {
9807      // console.error('❌ Ошибка:', error);
9808      // alert('Ошибка проверки капчи');
9809      return false;
9810    }
9811
9812    function checkHoneypot() {
9813      const honeypots = form.querySelector('.modal-exter__input')
9814      return honeypots && honeypots?.value
9815    }
9816  }
9817
9818  function validateFirstSlide () {
9819    let valid = true
9820    const roleInputActive = slides[0].querySelector('.review__role-input:checked')
9821    if (!roleInputActive) {
9822      valid = false
9823      role.classList.add('review-error')
9824    }
9825    if (!nameInput.value) {
9826      nameInput.classList.add('review-error')
9827      valid = false
9828    }
9829    if (!surnameInput.value) {
9830      surnameInput.classList.add('review-error')
9831      valid = false
9832    }
9833    if (!validateEmail(emailInput)) {
9834      valid = false
9835    }
9836    const selectClassValue = slides[0].querySelector('.review__select-input:checked')
9837    if (!selectClassValue) {
9838      valid = false
9839      selectClass.classList.add('review-error')
9840    }
9841    return valid
9842  }
9843
9844  function validateSecondSlide () {
9845    let valid = true
9846    if (!inputRate.value) {
9847      valid = false
9848      rateDesktop.classList.add('review-error')
9849    }
9850    for (let i = 0; i < selectsOnSecondSlide.length; i++) {
9851      const input = selectsOnSecondSlide[i].querySelector('.review__select-input:checked')
9852      if (!input) {
9853        valid = false
9854        selectsOnSecondSlide[i].classList.add('review-error')
9855      }
9856    }
9857    return valid
9858  }
9859
9860  function nextSlide () {
9861    if (!validateFirstSlide()) return
9862    steps[1].classList.add('active')
9863    steps[0].classList.add('done')
9864    const oldSlide = review.querySelector('.review__slide.active')
9865    if (oldSlide) oldSlide.classList.remove('active')
9866    slides[1].classList.add('active')
9867    window.scrollTo(0, 0)
9868  }
9869
9870  function prevSlide () {
9871    steps[1].classList.remove('active')
9872    steps[0].classList.remove('done')
9873    const oldSlide = review.querySelector('.review__slide.active')
9874    if (oldSlide) oldSlide.classList.remove('active')
9875    slides[0].classList.add('active')
9876    window.scrollTo(0, 0)
9877  }
9878
9879  for (let i = 0; i < selectTops.length; i += 1) {
9880    selectTops[i].addEventListener('click', () => openSelect(selectTops[i]))
9881    const inputs = selectTops[i].parentElement.querySelectorAll('.review__select-input')
9882    inputs.forEach(input => {
9883      input.addEventListener('change', () => setSelectValue(selectTops[i]))
9884    })
9885    const selectClose = selectTops[i].parentElement.querySelector('.review__select-close')
9886    selectClose.addEventListener('click', () => closeSelect(selectTops[i]))
9887  }
9888
9889  window.addEventListener('click', function (e) {
9890    if (e.target.closest('.review__select')) return
9891    const activeSelect = review.querySelector('.review__select.active')
9892    if (activeSelect) activeSelect.classList.remove('active')
9893    const activeSelectTop = review.querySelector('.review__select-top.active')
9894    if (activeSelectTop) activeSelectTop.classList.remove('active')
9895    body.classList.remove('no-scroll-mob')
9896  })
9897
9898  function openSelect(that) {
9899    if (!that.classList.contains('active')) {
9900      const activeSelect = review.querySelector('.review__select.active')
9901      if (activeSelect) activeSelect.classList.remove('active')
9902      const activeSelectTop = review.querySelector('.review__select-top.active')
9903      if (activeSelectTop) activeSelectTop.classList.remove('active')
9904    }
9905
9906    if (that.parentElement.classList.contains('review__select_tutor') || that.parentElement.classList.contains('review__select_teacher')) {
9907      that.classList.add('active')
9908      that.parentElement.classList.add('active')
9909    } else {
9910      that.classList.toggle('active')
9911      that.parentElement.classList.toggle('active')
9912    }
9913    body.classList.add('no-scroll-mob')
9914  }
9915
9916  function closeSelect(selectTop) {
9917    selectTop.classList.remove('active')
9918    selectTop.parentElement.classList.remove('active')
9919    body.classList.remove('no-scroll-mob')
9920  }
9921
9922  function setSelectValue (selectTop) {
9923    closeSelect(selectTop)
9924    const selectText = selectTop.querySelector('.review__select-top-text')
9925    selectText.classList.add('active')
9926    const text = selectTop.parentElement.querySelector('input:checked').getAttribute('data-text')
9927    if (selectText) selectText.innerHTML = text
9928    const selectSearch = selectTop.querySelector('.review__select-search')
9929    if (selectSearch) {
9930      selectSearch.value = text
9931      const reviewSearchMob = selectTop.closest('.review__select').querySelector('.review__search-mob')
9932      if (reviewSearchMob) reviewSearchMob.value = text
9933      selectSort(selectSearch)
9934      subjectsFilter(selectSearch)
9935      boxSubject.classList.remove('review__box_disabled')
9936    }
9937    if (selectTop.parentElement.classList.contains('review__select_teacher')) {
9938      const name = review.querySelector('.review__sidebar-teacher-name')
9939      if (name) name.innerHTML = text
9940      const image = review.querySelector('.review__sidebar-teacher-image')
9941      const imageSrc = selectTop.parentElement.querySelector('input:checked').getAttribute('data-image')
9942      if (image && imageSrc) image.src = imageSrc
9943      const sidebarTeacher = review.querySelector('.review__sidebar-teacher')
9944      if (sidebarTeacher) {
9945        const sidebar = sidebarTeacher.parentElement.querySelector('.review__sidebar')
9946        if (sidebar) {
9947          sidebar.classList.add('hide')
9948          sidebarTeacher.classList.add('active')
9949        }
9950      }
9951    }
9952  }
9953}
9954
9955
9956const reviewsTile = document.querySelector('.reviews-tile')
9957
9958if (reviewsTile) reviewsTileInit()
9959
9960function reviewsTileInit () {
9961  const config = { attributes: false, childList: true, characterData: true, subtree: false }
9962  const body = document.querySelector('body')
9963  const sidebar = reviewsTile.querySelector('.reviews-tile__sidebar')
9964  const openFilterBtn = reviewsTile.querySelector('.reviews-tile__filter')
9965  const closeFilterBtn = reviewsTile.querySelector('.reviews-tile__close')
9966  const inputs = reviewsTile.querySelectorAll('.reviews-tile__input')
9967  const filterNote = reviewsTile.querySelector('.reviews-tile__filter-note')
9968  const scrollTopBtn = document.querySelector('.reviews-tile__scroll-top')
9969  const reviewsTileCards = document.querySelector('.reviews-tile__cards')
9970
9971  openFilterBtn.addEventListener('click', openFilters)
9972  closeFilterBtn.addEventListener('click', closeFilters)
9973
9974  function openFilters () {
9975    sidebar.classList.add('active')
9976    body.classList.add('no-scroll')
9977  }
9978
9979  function closeFilters () {
9980    sidebar.classList.remove('active')
9981    body.classList.remove('no-scroll')
9982  }
9983
9984  function textsInit (node) {
9985    let texts
9986    if (node) {
9987      texts = node.querySelectorAll('.reviews-tile__text')
9988    } else {
9989      texts = document.querySelectorAll('.reviews-tile__text')
9990    }
9991
9992
9993    for (let i = 0; i < texts.length; i++) {
9994      const toggle = texts[i].parentElement.querySelector('.reviews-tile__toggle')
9995      if ((texts[i].clientHeight - 230) > 40 && window.innerWidth >= 1440 || (texts[i].clientHeight - 190) > 40 && window.innerWidth >= 744 && window.innerWidth < 1440 || (texts[i].clientHeight - 350) > 40 && window.innerWidth < 744) {
9996        texts[i].classList.add('hide')
9997        toggle.addEventListener('click', () => toggleText(texts[i]))
9998      } else {
9999        toggle.style.display = 'none'
10000      }
10001    }
10002
10003    function toggleText (text) {
10004      const toggle = text.parentElement.querySelector('.reviews-tile__toggle')
10005      if (text.classList.contains('hide')) {
10006        text.classList.remove('hide')
10007        toggle.innerHTML = 'Скрыть'
10008      } else {
10009        text.classList.add('hide')
10010        toggle.innerHTML = 'Показать полностью'
10011      }
10012    }
10013  }
10014
10015  for (let i = 0; i < inputs.length; i++) {
10016    inputs[i].addEventListener('change', sort)
10017    inputs[i].addEventListener('change', (e) => sort(e))
10018  }
10019
10020  async function makeFiltration (attr_type = '', attr_utm = '',p_paginate = 1) {
10021        if (typeof attr_type !== 'undefined' && attr_type !== false &&
10022            typeof attr_utm !== 'undefined' && attr_utm !== false) {
10023          if (typeof p_paginate == 'undefined' || p_paginate == false || p_paginate == null){
10024            p_paginate = 1;
10025          }
10026          console.log(attr_type);
10027            console.log(attr_utm);
10028            console.log(p_paginate);
10029          $.request('ModelUrl::onPaginateR', {
10030                data: {
10031                    'pagePaginate': p_paginate,
10032                    'utm_t': attr_utm,
10033                    'type': attr_type,
10034                }
10035            });
10036        }
10037  }
10038
10039  function sort (e, isMoreBtn) {
10040    closeFilters()
10041    if (!isMoreBtn) {
10042      window.scrollTo({ top: window.scrollY + reviewsTile.getBoundingClientRect().top - 180, behavior: 'smooth' })
10043      filterNote.innerHTML = e.currentTarget.value
10044    }
10045    let utm_f = reviewsTile.getAttribute('data-utm');
10046    let attr_type = e.currentTarget.getAttribute('data-value');
10047    let p_paginate = e.currentTarget.getAttribute('data-v');
10048    if(p_paginate > 1){
10049        $('.review___more_pagi').html("<div class='tile-loader'></div>");
10050    }else{
10051        $('.review___catalog_pagi').html("<div class='tile-loader'></div>");
10052        $('.review___more_pagi').html("");
10053    }
10054    makeFiltration (attr_type, utm_f, p_paginate);
10055    
10056  }
10057
10058  function moreBtnInit () {
10059    const moreBtn = reviewsTile.querySelector('.reviews-tile__more')
10060    if (moreBtn) {
10061      const newBtn = replaceBtn(moreBtn)
10062      newBtn.addEventListener('click', (e) => sort(e, true))
10063    }
10064  }
10065
10066  function replaceBtn (oldElement) {
10067    const newElement = oldElement.cloneNode(true)
10068    oldElement.parentNode.replaceChild(newElement, oldElement)
10069    return newElement
10070  }
10071
10072
10073  videoInit()
10074  textsInit()
10075  moreBtnInit()
10076
10077  const observer = new MutationObserver(function observerCallback(mutations) {
10078    mutations.forEach(
10079      (mutation) => {
10080        if (mutation.addedNodes.length) {
10081          mutation.addedNodes.forEach((node) => {
10082            if (node?.classList?.contains('reviews-tile__card')) {
10083              videoInit(node)
10084              textsInit(node)
10085              fancyboxAjaxCardsReInit(node)
10086              initCommonAnalytics(node)
10087
10088            }
10089          })
10090        }
10091      })
10092    moreBtnInit()
10093  })
10094
10095  observer.observe(reviewsTileCards, config)
10096
10097  function videoInit (node) {
10098    let videoBoxes
10099    if (node) {
10100      videoBoxes = node.querySelectorAll('.reviews-tile__video-box')
10101    } else {
10102      videoBoxes = reviewsTile.querySelectorAll('.reviews-tile__video-box')
10103    }
10104
10105
10106    for (let i = 0; i < videoBoxes.length; i++) {
10107      videoBoxes[i].addEventListener('click', playVideo)
10108    }
10109
10110    function playVideo () {
10111        const oldActive = reviewsTile.querySelector('.reviews-tile__video-box.active')
10112        if (oldActive) {
10113          const video = oldActive.parentElement.querySelector('video')
10114          oldActive.classList.remove('active')
10115          video.pause()
10116        }
10117        this.classList.add('active')
10118        const video = this.parentElement.querySelector('video')
10119        if (video) {
10120            video.play()
10121        }
10122    }
10123  }
10124
10125  if (scrollTopBtn) {
10126    scrollTopBtn.addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' }))
10127    window.addEventListener('scroll', toggleAllCoursesTop, { passive: true })
10128
10129    function toggleAllCoursesTop () {
10130      if (window.scrollY > 0) {
10131        scrollTopBtn.classList.add('active')
10132      } else {
10133        scrollTopBtn.classList.remove('active')
10134      }
10135    }
10136  }
10137}
10138
10139const reviewsSlider = document.querySelector('.reviews__slider')
10140
10141if (reviewsSlider) reviewsSliderInit()
10142
10143function reviewsSliderInit () {
10144  const body = document.querySelector('body')
10145
10146  const videos = reviewsSlider.querySelectorAll('.reviews__video')
10147
10148  for (let i = 0; i < videos.length; i++) {
10149    initVideo(videos[i])
10150  }
10151
10152  window.addEventListener('resize', resizeHandler)
10153
10154  function resizeHandler () {
10155    if (window.innerWidth >= 1359) {
10156      for (let i = 0; i < videos.length; i++) {
10157        videos[i].pause()
10158      }
10159    }
10160  }
10161
10162  function initVideo (video) {
10163    const box = video.closest('.reviews__video-box')
10164    box.addEventListener('click', videoHandler)
10165
10166    const videoSrc = box.getAttribute('data-src')
10167    const videoHtml =
10168      '<video class="fancybox-video" controls autoplay playsinline ' +
10169      'webkit-playsinline disablePictureInPicture controlsList="nofullscreen">' +
10170      '<source src="' + videoSrc + '" type="video/mp4" />' +
10171      'Ваш браузер не поддерживает встроенное видео.' +
10172      '</video>';
10173
10174    function videoHandler (e) {
10175      if (window.innerWidth >= 1359) {
10176        $.fancybox.open({
10177          src: videoHtml,
10178          type: 'html',
10179          scrolling: 'no',
10180          touch: false,
10181          autoSize: false,
10182          smallBtn: false,
10183          toolbar: true,
10184          buttons: ['close'],
10185        })
10186      } else {
10187        e.preventDefault()
10188        e.stopPropagation()
10189        e.stopImmediatePropagation()
10190        playVideo()
10191      }
10192    }
10193
10194    function playVideo () {
10195      const oldBox = reviewsSlider.querySelector('.reviews__video-box.active')
10196      if (oldBox) {
10197        const oldVideo = oldBox.querySelector('.reviews__video')
10198        if (oldVideo) oldVideo.pause()
10199        oldBox.classList.remove('active')
10200      }
10201      video.play()
10202      box.classList.add('active')
10203    }
10204  }
10205
10206
10207  const inners = reviewsSlider.querySelectorAll('.reviews__slide')
10208
10209  for (let i = 0; i < inners.length; i++) {
10210    initInner(inners[i])
10211  }
10212
10213  function initInner (inner) {
10214    const btn = inner.querySelector('.reviews__toggle')
10215
10216    if (inner.clientHeight > 285 && window.innerWidth >= 1359 || inner.clientHeight > 232 && window.innerWidth < 1440) {
10217      inner.classList.add('hide')
10218      btn?.addEventListener('click', toggle)
10219    } else {
10220      btn?.remove()
10221    }
10222
10223    function toggle () {
10224      if (inner.classList.contains('hide')) {
10225        inner.classList.remove('hide')
10226        btn.innerHTML = 'Скрыть'
10227        inner.classList.add('show')
10228        if (window.innerWidth >= 744) createModal(inner, btn)
10229      } else {
10230        inner.classList.add('hide')
10231        btn.innerHTML = 'Читать весь отзыв'
10232        inner.classList.remove('show')
10233      }
10234    }
10235
10236    function createModal(innerOld) {
10237      const slide = innerOld.closest('.reviews__slide')
10238      const imageOld = slide.querySelector('.reviews__image')
10239      const textOld = slide.querySelector('.reviews__text')
10240      const nameOld = slide.querySelector('.reviews__name')
10241      const noteOld = slide.querySelector('.reviews__note')
10242      const starsOld = slide.querySelector('.reviews__stars')
10243
10244      const modal = document.createElement('div')
10245      modal.classList.add('review-modal')
10246
10247      const layer = document.createElement('div')
10248      layer.classList.add('review-modal__layer')
10249
10250      const inner = document.createElement('div')
10251      inner.classList.add('review-modal__inner')
10252
10253      const close = document.createElement('button')
10254      close.classList.add('review-modal__close')
10255
10256      const left = document.createElement('div')
10257      left.classList.add('review-modal__left')
10258
10259      const box = document.createElement('div')
10260      box.classList.add('review-modal__box')
10261
10262      const image = document.createElement('img')
10263      image.classList.add('review-modal__image')
10264
10265      const name = document.createElement('div')
10266      name.classList.add('review-modal__name')
10267
10268      const note = document.createElement('div')
10269      note.classList.add('review-modal__note')
10270
10271      const right = document.createElement('div')
10272      right.classList.add('review-modal__right')
10273
10274      const text = document.createElement('div')
10275      text.classList.add('review-modal__text')
10276
10277      const stars = document.createElement('div')
10278      stars.classList.add('reviews__stars')
10279
10280      image.src = imageOld.src
10281
10282      box.append(name)
10283      box.append(note)
10284      box.append(stars)
10285      name.innerHTML = nameOld.innerHTML
10286      note.innerHTML = noteOld.innerHTML
10287      stars.innerHTML = starsOld.innerHTML
10288      left.append(image)
10289      left.append(box)
10290      text.innerHTML = textOld.innerHTML
10291      right.append(text)
10292      inner.append(close)
10293      inner.append(left)
10294      inner.append(right)
10295      modal.append(layer)
10296      modal.append(inner)
10297
10298      layer.addEventListener('click', closeModal)
10299      close.addEventListener('click', closeModal)
10300
10301      const main = document.querySelector('main')
10302      main.append(modal)
10303
10304      body.classList.add('no-scroll-desktop')
10305
10306      function closeModal () {
10307        modal.remove()
10308        innerOld.classList.add('hide')
10309        btn.innerHTML = 'Читать весь отзыв'
10310        innerOld.classList.remove('show')
10311        body.classList.remove('no-scroll-desktop')
10312      }
10313    }
10314  }
10315
10316}
10317
10318
10319const reviewSo2026 = document.querySelector('.review_so-2026')
10320
10321if (reviewSo2026) reviewSo2026Init()
10322
10323function reviewSo2026Init () {
10324  const textReplace = {
10325    parent: [
10326      { selector: '.review__caption_thanks-1', text: 'Спасибо, что поделились опытом!' },
10327      { selector: '.review__caption_thanks-2', text: 'Спасибо за ваш отзыв!' },
10328      { selector: '.review__headline-thanks-1', text: 'Дайте вашему мнению реальную силу' },
10329      { selector: '.review__thanks-title', text: 'Ваш отзыв — ориентир для других родителей.' },
10330      { selector: '.review__thanks-text_1', text: 'Многие родители сейчас ищут честные отзывы, чтобы сделать выбор для своего ребенка.' },
10331    //   { selector: '.review__thanks-text_2', text: 'Ваш отзыв на <a href="https://www.rbc.ru/courses/school-reviews/tocka-znanii" data-redirect>
10331РБК</a> станет для них весомым аргументом, который сэкономит время, деньги и нервы.' },
10332      { selector: '.review__thanks-text_2', text: 'Ваш отзыв на Отзовике станет для них весомым аргументом, который сэкономит время, деньги и нервы.' },
10333    //   { selector: '.review__thanks-headline_1', text: 'Пожалуйста, добавьте свой отзыв на РБК.' },
10334      { selector: '.review__thanks-headline_1', text: 'Пожалуйста, добавьте свой отзыв на Отзовик.' },
10335      { selector: '.review__thanks-headline_2', text: 'Это займёт 2 минуты. Пусть ваш голос поможет с выбором и станет ориентиром.' },
10336      { selector: '.review__thanks-headline_3', text: 'Оставьте отзыв и помогите другим родителям!' },
10337      { selector: '.review__thanks-2-title', text: 'Если вы хотите оставить отзыв на других учителей или тьюторов, нажмите на кнопки ниже' },
10338    ],
10339    student: [
10340      { selector: '.review__caption_thanks-1', text: 'Спасибо, что делишься опытом!' },
10341      { selector: '.review__caption_thanks-2', text: 'Спасибо за твой отзыв!' },
10342      { selector: '.review__headline-thanks-1', text: 'Дайте своему мнению реальную силу' },
10343      { selector: '.review__thanks-title', text: 'Твой отзыв — ориентир для других учеников.' },
10344      { selector: '.review__thanks-text_1', text: 'Новичкам онлайн-обучения тоже бывает трудно: кто-то боится непонятных тем, сложной домашки или остаться без поддержки учителей.' },
10345      { selector: '.review__thanks-text_2', text: 'Твой отзыв поможет им понять, что трудности решаемы и  поддержка рядом. Благодаря тебе другие ребята смогут сделать уверенный выбор' },
10346    //   { selector: '.review__thanks-headline_1', text: 'Пожалуйста, добавь свой отзыв на РБК.' },
10347      { selector: '.review__thanks-headline_1', text: 'Пожалуйста, добавь свой отзыв на Отзовик.' },
10348      { selector: '.review__thanks-headline_2', text: 'Это займёт 2 минуты.' },
10349      { selector: '.review__thanks-headline_3', text: 'Оставь отзыв и помоги другим школьникам!' },
10350      { selector: '.review__thanks-2-title', text: 'Если ты хочешь оставить отзыв на других учителей или тьюторов, нажми на кнопки ниже' },
10351    ]
10352  }
10353
10354  const form = reviewSo2026.querySelector('.review__form')
10355  const slides = reviewSo2026.querySelectorAll('.review__slide')
10356  const steps = reviewSo2026.querySelectorAll('.review__step')
10357  const buttonsNext = reviewSo2026.querySelectorAll('.review__button')
10358  const buttonsBack = reviewSo2026.querySelectorAll('.review__back')
10359  const buttonsMobBack = reviewSo2026.querySelectorAll('.review__mob-back')
10360  const nameInput = reviewSo2026.querySelector("[name='st_name']")
10361  const surnameInput = reviewSo2026.querySelector("[name='st_surname']")
10362  const emailInput = reviewSo2026.querySelector("[name='email']")
10363  const btnSubmit = form.querySelector('.review__submit')
10364  const role = reviewSo2026.querySelector('.review__role')
10365  const roleInputs = reviewSo2026.querySelectorAll('.review__role-input')
10366  const head_1 = reviewSo2026.querySelector('.review__thanks-headline_1')
10367  const head_2 = reviewSo2026.querySelector('.review__thanks-headline_2')
10368  const textarea = reviewSo2026.querySelector('.review__textarea')
10369  const siteButton = reviewSo2026.querySelector('.review__thanks-site-button')
10370  const selectClass = reviewSo2026.querySelector(".review__select_class")
10371  const selectTops = reviewSo2026.querySelectorAll('.review__select-top')
10372  const body = document.querySelector('body')
10373  const selectClassInputs = selectClass.querySelectorAll(".review__select-input")
10374  const rateInputs = reviewSo2026.querySelectorAll(".review__rate-desktop-input")
10375
10376  let currentSlide = 0
10377  let isSubmitting = false;
10378
10379  for (let i = 0; i < selectClassInputs.length; i++) {
10380    selectClassInputs[i].addEventListener('change', function () {
10381      selectClass.classList.remove('review-error')
10382    })
10383  }
10384
10385  rateInputs.forEach( rateInput => {
10386    rateInput.addEventListener('change', function () {
10387      this.closest('.review__rate-so')?.classList.remove('review__rate-so_error')
10388    })
10389  })
10390
10391
10392  nameInput.addEventListener('input', () => nameInput.classList.remove('review-error'))
10393  surnameInput.addEventListener('input', () => surnameInput.classList.remove('review-error'))
10394  emailInput.addEventListener('input', () => emailInput.classList.remove('review-error'))
10395
10396  form.addEventListener('submit', submitForm)
10397
10398  buttonsNext.forEach(buttonNext => {
10399    buttonNext.addEventListener('click', nextSlide)
10400  })
10401  buttonsBack.forEach(buttonBack => {
10402    buttonBack.addEventListener('click', prevSlide)
10403  })
10404  buttonsMobBack.forEach(buttonMobBack => {
10405    buttonMobBack.addEventListener('click', prevSlide)
10406  })
10407
10408  siteButton.addEventListener('click', showLastSlideThanks)
10409
10410  for (let i = 0; i < roleInputs.length; i++) {
10411    roleInputs[i].addEventListener('change', () => {
10412      role.classList.remove('review-error')
10413      const value = reviewSo2026.querySelector('.review__role-input:checked')?.value
10414      replaceTexts(value)
10415    })
10416  }
10417
10418  function replaceTexts(value) {
10419    if (value === 'student') {
10420      reviewSo2026.classList.add('review_student')
10421    } else {
10422      reviewSo2026.classList.remove('review_student')
10423    }
10424    textReplace[value].forEach((item) => {
10425      const node = reviewSo2026.querySelector(item.selector)
10426      node.innerHTML = item.text
10427      const dataRedirectLinks = node.querySelectorAll('[data-redirect]')
10428      for (let i = 0; i < dataRedirectLinks.length; i++) {
10429        dataRedirectLinks[i].addEventListener('click', dataRedirect)
10430      }
10431    })
10432  }
10433
10434  function validateFirstSlide () {
10435    let valid = true
10436    const roleInputActive = slides[0].querySelector('.review__role-input:checked')
10437    if (!roleInputActive) {
10438      valid = false
10439      role.classList.add('review-error')
10440    }
10441    if (!nameInput.value) {
10442      nameInput.classList.add('review-error')
10443      valid = false
10444    }
10445    if (!surnameInput.value) {
10446      surnameInput.classList.add('review-error')
10447      valid = false
10448    }
10449    if (!validateEmail(emailInput)) {
10450      valid = false
10451    }
10452    const selectClassValue = slides[0].querySelector('.review__select-input:checked')
10453    if (!selectClassValue) {
10454      valid = false
10455      selectClass.classList.add('review-error')
10456    }
10457    return valid
10458  }
10459
10460  function validateEmail (email) {
10461    if (/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(email.value)) {
10462      email.classList.remove('review-error')
10463      return true
10464    } else {
10465      email.classList.add('review-error')
10466      return false
10467    }
10468  }
10469
10470  function nextSlide () {
10471    if (!validateFirstSlide()) return
10472    if (currentSlide > 0 && !slides[currentSlide].querySelector('input:checked')) {
10473      slides[currentSlide].querySelector('.review__rate-so')?.classList.add('review__rate-so_error')
10474      return
10475    }
10476    currentSlide += 1
10477    steps[currentSlide].classList.add('active')
10478    steps[currentSlide-1].classList.add('done')
10479    const oldSlide = reviewSo2026.querySelector('.review__slide.active')
10480    if (oldSlide) oldSlide.classList.remove('active')
10481    slides[currentSlide].classList.add('active')
10482    window.scrollTo(0, 0)
10483  }
10484
10485  function prevSlide () {
10486    currentSlide -= 1
10487    steps[currentSlide+1].classList.remove('active')
10488    steps[currentSlide].classList.remove('done')
10489    const oldSlide = reviewSo2026.querySelector('.review__slide.active')
10490    if (oldSlide) oldSlide.classList.remove('active')
10491    slides[currentSlide].classList.add('active')
10492    window.scrollTo(0, 0)
10493  }
10494
10495  async function submitForm (e) {
10496    e.preventDefault()
10497    const email = form.querySelector('[name="email"]')
10498    if (email) {
10499      email_value = email.value;
10500    }
10501
10502    btnSubmit.disabled = true;
10503
10504    if (checkHoneypot()) return
10505
10506    try {
10507      e.stopPropagation();
10508      console.log('isSubmitting:', isSubmitting);
10509      if (isSubmitting) return false;
10510
10511      //   if (!captchaPassed) {
10512      //     // console.log('🔄 Вызов execute...');
10513      captchaToken = null;
10514      //     window.smartCaptcha.execute(window.captchaWidget);
10515
10516      //     await new Promise((resolve, reject) => {
10517      //       const checkToken = setInterval(() => {
10518      //         if (captchaToken) {
10519      //           clearInterval(checkToken);
10520      //           resolve();
10521      //         }
10522      //       }, 100);
10523
10524      //       setTimeout(() => {
10525      //         clearInterval(checkToken);
10526      //         reject(new Error('Таймаут капчи'));
10527      //       }, 100000);
10528      //     });
10529
10530      //     // console.log('✅ Токен получен:', captchaToken);
10531      //   } else {
10532      //     // console.log('✅ Капча уже пройдена, пропускаем проверку');
10533      //   }
10534
10535
10536      //   if (captchaToken) {
10537
10538
10539      // console.log(globalForm);
10540      isSubmitting = true;
10541      //   console.log('Отправка формы:', review);
10542
10543      const dataRequest = form.getAttribute('data-request');
10544      const formData = new FormData(form);
10545      const formObject = {};
10546      formData.forEach((value, key) => {
10547        formObject[key] = value;
10548      });
10549      formObject['smart-token'] = captchaToken;
10550
10551      //formObject.captcha_token = captchaToken;
10552
10553      $.request('MainFunctions::' + dataRequest, {
10554        data: formObject,
10555        success: function(response) {
10556          // console.log('Ответ:', response);
10557          let hasErrors = false;
10558
10559          for (let key in response) {
10560            if (key.startsWith('.')) {
10561              const className = key.substring(1);
10562              const element = document.querySelector('.' + className);
10563
10564              if (element) {
10565                element.innerHTML = response[key];
10566                hasErrors = true;
10567                btnSubmit.disabled = false;
10568              }
10569            }
10570          }
10571
10572          if (hasErrors) {
10573            isSubmitting = false;
10574            return;
10575          } else {
10576            afterSuccessSubmit()
10577          }
10578        },
10579        error: function(error) {
10580          // console.error('❌ Ошибка отправки:', error);
10581          isSubmitting = false;
10582        }
10583      });
10584
10585      return false;
10586      //   }else{
10587      //     return false;
10588      //   }
10589
10590    } catch (error) {
10591      // console.error('❌ Ошибка:', error);
10592      // alert('Ошибка проверки капчи');
10593      return false;
10594    }
10595
10596    function checkHoneypot() {
10597      const honeypots = form.querySelector('.modal-exter__input')
10598      return honeypots && honeypots?.value
10599    }
10600  }
10601
10602  function afterSuccessSubmit () {
10603    const oldSlide = reviewSo2026.querySelector('.review__slide.active')
10604    if (oldSlide) oldSlide.classList.remove('active')
10605    if (role.querySelector('input:checked')?.value === 'parent') {
10606      slides[6].classList.add('active')
10607      reviewSo2026.classList.add('review_thanks-1')
10608      if (!textarea.value) {
10609        head_1.style.display = 'none'
10610        head_2.style.display = 'none'
10611      } else {
10612        head_1.style.display = 'block'
10613        head_2.style.display = 'block'
10614      }
10615    } else {
10616      slides[6].classList.add('active')
10617      steps[5].classList.add('done')
10618      reviewSo2026.classList.add('review_thanks-2')
10619    }
10620    steps[5].classList.add('done')
10621    steps[6].classList.add('active')
10622    window.scrollTo(0, 0)
10623    if (!isRateGood()) showLastSlideThanks()
10624  }
10625
10626  function isRateGood () {
10627    const rateChecked = reviewSo2026.querySelectorAll(".review__rate-desktop-input:checked")
10628    let result = true
10629    rateChecked.forEach(rate => {
10630      if (rate.value < 9) {
10631        result = false
10632      }
10633    })
10634    return result
10635  }
10636
10637
10638  function showLastSlideThanks () {
10639    steps[6].classList.add('done')
10640    window.scrollTo(0, 0)
10641    const oldSlide = reviewSo2026.querySelector('.review__slide.active')
10642    if (oldSlide) oldSlide.classList.remove('active')
10643    const title = reviewSo2026.querySelector('.review__thanks-2-title')
10644    const headline_thanks_1 = reviewSo2026.querySelector('.review__headline-thanks-1')
10645    const caption_thanks_1 = reviewSo2026.querySelector('.review__caption_thanks-1')
10646    const caption_thanks_2 = reviewSo2026.querySelector('.review__caption_thanks-2')
10647    slides[7].classList.add('active')
10648    if (role.querySelector('input:checked')?.value === 'parent') {
10649      title.innerHTML = 'Если вы хотите оставить отзыв на других учителей или тьюторов, нажмите на&nbsp;кнопки ниже'
10650      headline_thanks_1.innerHTML = '<span>Каждое мнение дает нам стимул двигаться дальше и развиваться.</span> <span>Мы будем продолжать работать над качеством наших курсов!</span>'
10651    } else {
10652      title.innerHTML = 'Если ты хочешь оставить отзыв на учителей или тьюторов, нажми на&nbsp;кнопки ниже'
10653      headline_thanks_1.innerHTML = '<span>Каждое мнение дает нам стимул двигаться дальше и развиваться.</span> <span>Мы будем продолжать работать над качеством наших курсов!</span>'
10654    }
10655    caption_thanks_1.innerHTML = 'Спасибо за ваш отзыв!'
10656    caption_thanks_2.innerHTML = 'Спасибо за твой отзыв! '
10657  }
10658
10659  window.addEventListener('click', function (e) {
10660    if (e.target.closest('.review__select')) return
10661    const activeSelect = reviewSo2026.querySelector('.review__select.active')
10662    if (activeSelect) activeSelect.classList.remove('active')
10663    const activeSelectTop = reviewSo2026.querySelector('.review__select-top.active')
10664    if (activeSelectTop) activeSelectTop.classList.remove('active')
10665    body.classList.remove('no-scroll-mob')
10666  })
10667
10668  for (let i = 0; i < selectTops.length; i += 1) {
10669    selectTops[i].addEventListener('click', () => openSelect(selectTops[i]))
10670    const inputs = selectTops[i].parentElement.querySelectorAll('.review__select-input')
10671    inputs.forEach(input => {
10672      input.addEventListener('change', () => setSelectValue(selectTops[i]))
10673    })
10674    const selectClose = selectTops[i].parentElement.querySelector('.review__select-close')
10675    selectClose.addEventListener('click', () => closeSelect(selectTops[i]))
10676  }
10677
10678  function openSelect(that) {
10679    if (!that.classList.contains('active')) {
10680      const activeSelect = reviewSo2026.querySelector('.review__select.active')
10681      if (activeSelect) activeSelect.classList.remove('active')
10682      const activeSelectTop = reviewSo2026.querySelector('.review__select-top.active')
10683      if (activeSelectTop) activeSelectTop.classList.remove('active')
10684    }
10685
10686    if (that.parentElement.classList.contains('review__select_tutor') || that.parentElement.classList.contains('review__select_teacher')) {
10687      that.classList.add('active')
10688      that.parentElement.classList.add('active')
10689    } else {
10690      that.classList.toggle('active')
10691      that.parentElement.classList.toggle('active')
10692    }
10693    body.classList.add('no-scroll-mob')
10694  }
10695
10696  function closeSelect(selectTop) {
10697    selectTop.classList.remove('active')
10698    selectTop.parentElement.classList.remove('active')
10699    body.classList.remove('no-scroll-mob')
10700  }
10701
10702  function setSelectValue (selectTop) {
10703    closeSelect(selectTop)
10704    const selectText = selectTop.querySelector('.review__select-top-text')
10705    selectText.classList.add('active')
10706    const text = selectTop.parentElement.querySelector('input:checked').getAttribute('data-text')
10707    if (selectText) selectText.innerHTML = text
10708  }
10709}
10710
10711
10712if (document.querySelector('[data-role="scroll-to-anchor"]')) initScrollToAnchor()
10713
10714function initScrollToAnchor () {
10715  const anchorElements = document.querySelectorAll('[data-role="scroll-to-anchor"]')
10716
10717  for (let i = 0, len = anchorElements.length; i < len; i++) _loopAddEventScrollToAnchor(anchorElements[i])
10718
10719  function _loopAddEventScrollToAnchor (node) {
10720    node.addEventListener('click', clickOnTheScrollElement)
10721  }
10722}
10723
10724function clickOnTheScrollElement (event) {
10725  event.preventDefault()
10726  let elementId
10727  if (this.hash) elementId = this.hash.substr(1)
10728  else elementId = this.getAttribute('scroll-to-anchor-id')?.substr(1)
10729  const element = document.getElementById(elementId)
10730  const offset = this.getAttribute('scroll-offset')
10731  if (element) animateScrollToAnchor(element, offset)
10732  const duration = this.getAttribute('scroll-duration')
10733  if (element) animateScrollToAnchor(element, offset, duration)
10734}
10735
10736function animateScrollToAnchor (theElement, offset, duration) {
10737  if (!offset) {
10738    const banner = document.querySelector('.discount')
10739    const bannerHeight = banner ? banner.clientHeight : 0
10740    if (window.innerWidth < 744) {
10741      offset = 84 + bannerHeight
10742    } else if (window.innerWidth < 1200) {
10743      offset = 102 + bannerHeight
10744    } else {
10745      offset = 120 + bannerHeight
10746    }
10747  }
10748  const positionNow = window.pageYOffset
10749  const positionElement = theElement.getBoundingClientRect().top + scrollY - offset
10750  if (duration === 'instant') {
10751    window.scrollTo({left: 0, top: positionElement, behavior: 'instant'})
10752  } else {
10753    duration = 200
10754    const step = positionElement - positionNow
10755    const start = performance.now()
10756
10757    requestAnimationFrame(function animate (time) {
10758      const timePassed = time - start
10759
10760        if (timePassed > duration) {
10761        window.scrollTo(0, positionElement)
10762      } else {
10763        window.scrollTo(0, positionNow + step * (timePassed / duration))
10764        requestAnimationFrame(animate)
10765      }
10766    })
10767  }
10768}
10769
10770const selectFilter = document.querySelectorAll('.select-filter')
10771const stickyHeader = document.querySelector('.sticky-header')
10772const body = document.querySelector('body')
10773
10774for (let i = 0; i < selectFilter.length; i++) {
10775  selectFilterInit(selectFilter[i])
10776}
10777
10778function selectFilterInit (select) {
10779  document.addEventListener('click', function (e) {
10780    if (e.target.classList.contains('select-filter__close') || e.target.closest('.select-filter__item') || !e.target.closest('.select-filter')) {
10781      filterTop.classList.remove('active')
10782      select.classList.remove('active')
10783      showHeader()
10784    }
10785  })
10786
10787  const text = select.querySelector(".select-filter__top-text")
10788  const filterTop = select.querySelector(".select-filter__top")
10789  filterTop.addEventListener("click", (e)=> openFilter(filterTop, e))
10790
10791  const inputs = select.querySelectorAll(".select-filter__input")
10792  for (let i = 0; i < inputs.length; i++) {
10793    inputs[i].addEventListener('change', function () {
10794      if (inputs[i].hasAttribute('data-summer')) {
10795        body.classList.add('summer-filter-active')
10796        text.innerHTML = inputs[i].parentElement.querySelector('.select-filter__view').innerHTML
10797      } else {
10798        body.classList.remove('summer-filter-active')
10799        text.innerHTML = inputs[i].getAttribute('data-text')
10800      }
10801    })
10802  }
10803
10804  function openFilter (opener, e) {
10805    e.stopPropagation()
10806    if (!opener.classList.contains('active')) {
10807      const oldActive = document.querySelector('.select-filter__top.active')
10808      if (oldActive) oldActive.classList.remove('active')
10809      const oldActiveFilter = document.querySelector('.select-filter.active')
10810      if (oldActiveFilter) oldActiveFilter.classList.remove('active')
10811    }
10812    if (opener.classList.contains('active')) {
10813      opener.classList.remove('active')
10814      showHeader()
10815      select.classList.remove('active')
10816    } else {
10817      opener.classList.add('active')
10818      select.classList.add('active')
10819      hideHeader()
10820      const oldOpen = document.querySelector(".all-courses__filter-top.active, .ege-tile__filter-top.active, .offer-tile__filter-top.active")
10821      if (oldOpen) oldOpen.classList.remove('active')
10822    }
10823  }
10824
10825  function showHeader () {
10826    stickyHeader.classList.remove('hide')
10827    body.classList.remove('no-scroll')
10828  }
10829
10830  function hideHeader () {
10831    if (window.innerWidth < 744) {
10832      stickyHeader.classList.add('hide')
10833      body.classList.add('no-scroll')
10834    }
10835  }
10836}
10837
10838
10839const stageToggles = document.querySelectorAll('.header__stages-button')
10840 
10841 if (stageToggles.length) stageTogglesInit()
10842 
10843 function stageTogglesInit () {
10844   for (let i = 0; i < stageToggles.length; i++) {
10845     stageToggles[i].addEventListener('click', toggleStage)
10846   }
10847 
10848   function toggleStage () {
10849     const id = this.getAttribute('data-stage-id')
10850     const blocks = document.querySelectorAll("[data-stage-number='" + id + "']")
10851 
10852     for (let i = 0; i < blocks.length; i++) {
10853       blocks[i].classList.remove('stage-block-hide')
10854     }
10855 
10856     const oldToggle = document.querySelector('.header__stages-button.active')
10857     let oldId = ''
10858     if (oldToggle) {
10859      oldId = oldToggle.getAttribute('data-stage-id')
10860      oldToggle.classList.remove('active')
10861     }
10862     const oldBlocks = document.querySelectorAll("[data-stage-number='" + oldId + "']")
10863
10864     const oldCourseAbout = document.querySelector(".course-about[data-stage-number='" + oldId + "']")
10865     if (oldCourseAbout) {
10866      const oldVideoWrap = oldCourseAbout.querySelector("[data-element='course-about-video-wrap']")
10867      if (oldVideoWrap) {
10868        const courseAboutVideo = oldVideoWrap.querySelector("[data-element='course-about-video']")
10869        if (courseAboutVideo) {
10870          if (!courseAboutVideo.muted) oldVideoWrap.click()
10871        }
10872      }
10873     }
10874 
10875     for (let i = 0; i < oldBlocks.length; i++) {
10876       oldBlocks[i].classList.add('stage-block-hide')
10877     }
10878 
10879     this.classList.add('active')
10880   }
10881 }
10882
10883const stretchBottom = document.querySelector('[data-role="stretch-bottom"]')
10884
10885if (stretchBottom) stretchBottomInit()
10886
10887function stretchBottomInit () {
10888  const close = stretchBottom.querySelector('[data-role="stretch-bottom-close"]')
10889  if (close) close.addEventListener('click', removeStretchBottom)
10890  const promo = document.querySelector('.promo')
10891  if (promo) promo.classList.add('with-stretch-bottom')
10892
10893  function removeStretchBottom (e) {
10894    e.preventDefault()
10895    stretchBottom.remove()
10896    if (promo) promo.classList.remove('with-stretch-bottom')
10897  }
10898}
10899
10900
10901const stretch = document.querySelector('[data-role="stretch"]')
10902
10903if (stretch) stretchInit()
10904
10905function stretchInit () {
10906  const stickyHeader = document.querySelector('.sticky-header')
10907  const close = stretch.querySelector('[data-role="stretch-close"]')
10908  if (close) close.addEventListener('click', removeStretch)
10909  const eye = document.querySelector('.eye')
10910
10911  function removeStretch (e) {
10912    e.preventDefault()
10913    stretch.remove()
10914    window.removeEventListener('scroll', checkScroll)
10915    stickyHeader.classList.remove('predzaps-top-hide-no-transition')
10916    stickyHeader.classList.remove('predzaps-top-hide')
10917    if (eye) eye.classList.remove('translate')
10918  }
10919
10920  window.addEventListener('scroll', checkScroll, { passive: true })
10921  checkScroll()
10922
10923  function checkScroll () {
10924    if (window.scrollY > 100) {
10925      stickyHeader.classList.add('predzaps-top-hide')
10926      setTimeout(() => stickyHeader.classList.add('predzaps-top-hide-no-transition'), 300)
10927      if (eye) eye.classList.remove('translate')
10928    } else if (window.scrollY <= 20) {
10929      stickyHeader.classList.remove('predzaps-top-hide-no-transition')
10930      setTimeout(() => stickyHeader.classList.remove('predzaps-top-hide'), 100)
10931      if (eye) eye.classList.add('translate')
10932    }
10933  }
10934}
10935
10936const tenorSidebarDesk = document.querySelector('.tenor-sidebar_desk')
10937const tenorSidebarMob = document.querySelector('.tenor-sidebar_mob')
10938
10939if (tenorSidebarDesk && tenorSidebarMob) articleSidebarDescInit()
10940
10941function articleSidebarDescInit () {
10942  const articleLinkArray = tenorSidebarDesk.querySelectorAll('.tenor-sidebar__link')
10943  const articleTitleArray = document.querySelectorAll('[data-element="tenor-sidebar-title"]')
10944  const articleLinkArrayMob = tenorSidebarMob.querySelectorAll('.tenor-sidebar__link')
10945  const name = tenorSidebarMob.querySelector('.tenor-sidebar__name')
10946  const layer = tenorSidebarMob.querySelector('.tenor-sidebar__layer')
10947  const body = document.querySelector('body')
10948  new SimpleBar(tenorSidebarDesk.querySelector('.tenor-sidebar__area'))
10949
10950  let scrollDown = true
10951  let lastScrollTop = 0
10952
10953
10954  window.addEventListener('scroll', checkScroll, { passive: true })
10955
10956  name.addEventListener('click', toggleSidebar)
10957  layer.addEventListener('click', closeSidebar)
10958
10959  window.addEventListener('scroll', checkScrollDirection, { passive: true })
10960
10961  for (let i = 0; i < articleLinkArrayMob.length; i++) {
10962    articleLinkArrayMob[i].addEventListener('click', toggleLinkActive)
10963  }
10964
10965  function checkScroll () {
10966    for (let i = 0; i < articleTitleArray.length; i++) {
10967      if (articleTitleArray[i].getBoundingClientRect().top < 300 || articleTitleArray[i].getBoundingClientRect().bottom - window.innerHeight < 0) {
10968        removeOldLinkActive()
10969        articleLinkArray[i].classList.add('active')
10970        articleLinkArrayMob[i].classList.add('active')
10971      } else {
10972        articleLinkArray[i].classList.remove('active')
10973        articleLinkArrayMob[i].classList.remove('active')
10974      }
10975    }
10976  }
10977
10978  function removeOldLinkActive () {
10979    const oldActive = tenorSidebarDesk.querySelector('.tenor-sidebar__link.active')
10980    if (oldActive) oldActive.classList.remove('active')
10981    const oldActiveMob = tenorSidebarMob.querySelector('.tenor-sidebar__link.active')
10982    if (oldActiveMob) oldActiveMob.classList.remove('active')
10983
10984  }
10985
10986  function checkScrollDirection () {
10987    const st = window.scrollY
10988    if (st - lastScrollTop > 7) {
10989      scrollDown = true
10990    } else if (st - lastScrollTop < -7) {
10991      scrollDown = false
10992    }
10993    lastScrollTop = st <= 0 ? 0 : st
10994    if (scrollDown && (name.getBoundingClientRect().top < 120)) {
10995      tenorSidebarMob.classList.remove('fixed')
10996    } else {
10997      tenorSidebarMob.classList.add('fixed')
10998    }
10999  }
11000
11001  function toggleSidebar () {
11002    if (name.classList.contains('active')) {
11003      closeSidebar()
11004    } else {
11005      body.classList.add('no-scroll-md')
11006      window.removeEventListener('scroll', checkScrollDirection)
11007      name.classList.add('active')
11008      name.textContent = 'Закрыть содержание'
11009      tenorSidebarMob.classList.add('active')
11010    }
11011  }
11012
11013  function closeSidebar () {
11014    body.classList.remove('no-scroll-md')
11015    tenorSidebarMob.classList.remove('active')
11016    name.classList.remove('active')
11017    name.textContent = name.getAttribute('data-default-text')
11018    window.addEventListener('scroll', checkScrollDirection, {passive: true})
11019  }
11020
11021  function toggleLinkActive () {
11022    const oldActive = tenorSidebarMob.querySelector('.tenor-sidebar__link.active')
11023    if (oldActive) oldActive.classList.remove('active')
11024    this.classList.add('active')
11025    closeSidebar()
11026  }
11027}
11028
11029const tileSumrNewy = document.querySelector('.tile-sumr-newy')
11030
11031if (tileSumrNewy) tileSumrNewyInit()
11032
11033function tileSumrNewyInit () {
11034  const inputs = tileSumrNewy.querySelectorAll('.tile-sumr-newy__input')
11035  inputs.forEach(input => {
11036    input.addEventListener('change', () => {
11037      if (input.hasAttribute('data-summer')) {
11038        body.classList.add('summer-filter-active')
11039      } else {
11040        body.classList.remove('summer-filter-active')
11041      }
11042    })
11043  })
11044}
11045
11046const timers = document.querySelectorAll('[data-element="timer"]')
11047
11048for (let i = 0; i < timers.length; i++) {
11049  timersInit(timers[i])
11050}
11051
11052function timersInit (timer) {
11053  const date = timer.getAttribute('date-end')
11054  const countDownDate = new Date(date).getTime()
11055
11056  const nodes = timer.querySelectorAll('[data-element="timer-number"]')
11057
11058  const interval = setInterval(updateTimer, 1000)
11059
11060  function updateTimer () {
11061    const now = new Date().getTime();
11062    const distance = countDownDate - now;
11063
11064    const days = Math.floor(distance / (1000 * 60 * 60 * 24))
11065    const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
11066    const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))
11067    const seconds = Math.floor((distance % (1000 * 60)) / 1000)
11068
11069    if (nodes.length < 4) {
11070      nodes[0].innerHTML = hours
11071      nodes[1].innerHTML = minutes
11072      nodes[2].innerHTML = seconds
11073    } else {
11074      nodes[0].innerHTML = days
11075      nodes[1].innerHTML = hours
11076      nodes[2].innerHTML = minutes
11077      nodes[3].innerHTML = seconds
11078    }
11079
11080    if (distance < 0) {
11081      clearInterval(interval);
11082      nodes[0].innerHTML = "0"
11083      nodes[1].innerHTML = "0"
11084      nodes[2].innerHTML = "0"
11085      if (nodes[3]) nodes[3].innerHTML = "0"
11086    }
11087  }
11088}
11089
11090
11091const trialFamilyStart = document.querySelector('#trial-family-start')
11092 
11093 if (trialFamilyStart) trialFamilyStartInit()
11094 
11095 function trialFamilyStartInit () {
11096   const opener = trialFamilyStart.querySelector("[data-element='trial-family-start-filter-opener']")
11097   const inputs = trialFamilyStart.querySelectorAll("[data-element='trial-family-start-filter-input']")
11098   const text = trialFamilyStart.querySelector(".trial-family-start__filter-top-text")
11099   const number = trialFamilyStart.querySelector(".trial-family-start__number")
11100   const button = trialFamilyStart.querySelector(".trial-family-start__button")
11101 
11102   opener.addEventListener('click', toggleSelect)
11103 
11104   function toggleSelect() {
11105     if (opener.classList.contains('active')) {
11106       opener.classList.remove('active')
11107     } else {
11108       const oldOpen = trialFamilyStart.querySelector(".trial-family-start__filter-top.active")
11109       if (oldOpen) oldOpen.classList.remove('active')
11110       opener.classList.add('active')
11111     }
11112   }
11113 
11114   for (let i = 0; i < inputs.length; i++) {
11115     inputs[i].addEventListener('change', setValue)
11116   }
11117 
11118   function setValue () {
11119     opener.classList.remove('active')
11120     text.innerHTML = this.getAttribute('data-number')
11121     number.innerHTML = this.getAttribute('data-number')
11122     button.href = this.value+this.getAttribute('data-utm');
11123   }
11124 }
11125
11126const trialTile = document.getElementById("trial-tile")
11127
11128if (trialTile) trialTileInit()
11129
11130function trialTileInit () {
11131  const config = { attributes: true, childList: true, characterData: true, subtree: true }
11132  const openers = trialTile.querySelectorAll("[data-element='trial-tile-filter-opener']")
11133  const grades = trialTile.querySelector("[data-ftype='class_select']")
11134  const subjects = trialTile.querySelector("[data-ftype='class_subjects']")
11135
11136  const observer = new MutationObserver(function() {
11137    const wrap = openers[1].nextElementSibling
11138    const items = wrap.querySelectorAll("[data-element='trial-tile-filter-input']")
11139    items.forEach((item) => {
11140      item.addEventListener('change', () => updateFilter(openers[1], wrap))
11141    })
11142  })
11143
11144  const reset = trialTile.querySelector("[data-element='trial-tile-filter-reset']")
11145  if (reset) reset.addEventListener('click', resetFilters)
11146
11147  function resetFilters () {
11148    for (let i = 0; i < openers.length; i++) {
11149      const wrap = openers[i].nextElementSibling
11150      const items = wrap.querySelectorAll("[data-element='trial-tile-filter-input']")
11151      items.forEach((item) => {
11152        item.checked = false
11153      })
11154      updateFilter(openers[i], wrap)
11155    }
11156    makeFiltration();
11157  }
11158
11159  for (let i = 0; i < openers.length; i++) {
11160    openers[i].addEventListener("click", ()=> openFilter(openers[i]))
11161    const wrap = openers[i].nextElementSibling
11162    const button = wrap.querySelector("[data-element='trial-tile-filter-save']")
11163    // button.addEventListener("click", ()=> closeFilter(openers[i], wrap))
11164    if (button) button.addEventListener("click", ()=> closeFilter(openers[i], wrap))
11165    const items = wrap.querySelectorAll("[data-element='trial-tile-filter-input']")
11166    items.forEach((item) => {
11167      item.addEventListener('change', () => updateFilter(openers[i], wrap))
11168      if (!button) item.addEventListener('change', () => closeFilter(openers[i], wrap))
11169    })
11170    if (i === 1) {
11171      window.onload = function() {
11172        observer.observe(wrap, config)
11173      }
11174    }
11175  }
11176
11177  function updateFilter (opener, wrap) {
11178    opener.innerHTML = opener.getAttribute('data-default-text')
11179    const items = wrap.querySelectorAll(["input:checked"])
11180    if (items.length) {
11181      opener.innerHTML = 'Выбрано: '
11182      items.forEach((item) => {
11183        const span = document.createElement("span")
11184        span.innerHTML = item.nextElementSibling.innerHTML
11185        span.classList.add('span')
11186        opener.append(span)
11187      })
11188    }
11189    const itemsAll = trialTile.querySelectorAll(["input:checked"])
11190    if (itemsAll.length) {
11191      if (reset) reset.style.display = 'flex'
11192    } else {
11193       if (reset) reset.style.display = 'none'
11194    }
11195    // makeFiltration();
11196  }
11197
11198  function openFilter (opener) {
11199    if (opener.classList.contains('active')) {
11200      closeFilter(opener)
11201    } else {
11202      const oldOpen = trialTile.querySelector(".trial-tile__filter-top.active")
11203      if (oldOpen) oldOpen.classList.remove('active')
11204      opener.classList.add('active')
11205
11206      const filter = opener.parentElement
11207       const oldFilter = trialTile.querySelector(".trial-tile__filter.open")
11208       if (oldFilter) oldFilter.classList.remove('open')
11209       if (filter) filter.classList.add('open')
11210    }
11211  }
11212
11213  function closeFilter (opener) {
11214    opener.classList.remove('active')
11215    const filter = opener.parentElement
11216     if (filter) filter.classList.remove('open')
11217    makeFiltration();
11218  }
11219  function makeFiltration () {
11220      const grades_wrap = grades.nextElementSibling
11221      const grades_items = grades_wrap.querySelectorAll(["input:checked"])
11222      let grades_result = ''
11223      let grade_first = 0
11224      grades_items.forEach((item, i) => {
11225        if (i > 0) grades_result += '|'
11226        if (grade_first == 0) grade_first = item.value
11227        grades_result += item.value
11228      })
11229      let subjects_result = ''
11230    try{
11231      const subjects_wrap = subjects.nextElementSibling
11232      const subjects_items = subjects_wrap.querySelectorAll(["input:checked"])
11233      subjects_items.forEach((item, i) => {
11234        if (i > 0) subjects_result += '|'
11235        subjects_result += item.value
11236      })
11237    }catch(e){}
11238    //   let promo_f = trialTile.getAttribute('data-promo');
11239      //console.log(grades_result)
11240      //console.log(subjects_result)
11241      let utm_f = trialTile.getAttribute('data-utm');
11242      $('.filtered_elements').html("<div class='tile-loader'></div>");
11243        // if(promo_f != null && promo_f != '' && promo_f != undefined){
11244        //     $.request('AllCourseFunctions::onPaginateAllCourses', {
11245        //             data: {
11246        //               'grade': grades_result,
11247        //               'subject': subjects_result,
11248        //               'promo': promo_f,
11249        //             }
11250        //         })
11251        // }else{
11252            $.request('TrialCourseFunctions::onPaginateAllCourses', {
11253                    data: {
11254                      'grade': grades_result,
11255                      'subject': subjects_result,
11256                      'utm_t': utm_f
11257                    }
11258                })
11259                if (grade_first > 0){
11260                    let url = new URL(window.location.href)
11261                    url.searchParams.set('gr', grade_first);
11262                    history.replaceState(null, "", url.toString())
11263                }
11264        // }
11265
11266  }
11267}
11268
11269/* ==========================================================================
11270   popups.js — открытие/закрытие модалок, блокировка скролла, фокус-трап
11271   Разметка управляется атрибутами:
11272     data-popup-open="<id>"  — открыть попап с этим id
11273     data-popup-close        — закрыть текущий попап
11274   ========================================================================== */
11275(function () {
11276  'use strict';
11277
11278  var root = document.querySelector('.tf');
11279  if (!root) return;
11280
11281  var openStack = [];
11282  var lastFocused = null;
11283
11284  var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), ' +
11285                  'select:not([disabled]), textarea:not([disabled]), [tabindex]:not
11285([tabindex="-1"])';
11286
11287  function lockScroll() {
11288    var sw = window.innerWidth - document.documentElement.clientWidth;
11289    document.body.style.overflow = 'hidden';
11290    if (sw > 0) document.body.style.paddingRight = sw + 'px';
11291  }
11292  function unlockScroll() {
11293    document.body.style.overflow = '';
11294    document.body.style.paddingRight = '';
11295  }
11296
11297  function open(id) {
11298    var popup = document.getElementById(id);
11299    if (!popup) return;
11300
11301    if (!openStack.length) {
11302      lastFocused = document.activeElement;
11303      lockScroll();
11304    } else {
11305      // Переход между попапами: предыдущий прячем.
11306      openStack[openStack.length - 1].hidden = true;
11307    }
11308
11309    popup.hidden = false;
11310    openStack.push(popup);
11311
11312    if (id === 'exitOverlay') {
11313      document.removeEventListener('mouseleave', mouseLeaveHandler)
11314    }
11315
11316    var first = popup.querySelector(FOCUSABLE);
11317    if (first) first.focus();
11318  }
11319
11320  function close() {
11321    var popup = openStack.pop();
11322    if (!popup) return;
11323    popup.hidden = true;
11324
11325    if (popup.id === 'exitOverlay') {
11326      popup.classList.remove('popup_no-social')
11327    }
11328
11329    if (openStack.length) {
11330      openStack[openStack.length - 1].hidden = false;
11331    } else {
11332      unlockScroll();
11333      if (lastFocused && lastFocused.focus) lastFocused.focus();
11334      lastFocused = null;
11335    }
11336  }
11337
11338  function closeAll() { while (openStack.length) close(); }
11339
11340  // --- Делегирование кликов -------------------------------------------------
11341  root.addEventListener('click', function (e) {
11342    var opener = e.target.closest('[data-popup-open]');
11343    if (opener) {
11344      e.preventDefault();
11345      open(opener.getAttribute('data-popup-open'));
11346      return;
11347    }
11348    if (e.target.closest('[data-popup-close]')) {
11349      e.preventDefault();
11350      close();
11351      return;
11352    }
11353    // Клик по подложке закрывает только на десктопе, где попап — модалка.
11354    var popup = e.target.closest('.popup');
11355    if (popup && e.target === popup && window.matchMedia('(min-width: 1280px)').matches) {
11356      close();
11357    }
11358  });
11359
11360  // --- Клавиатура ------------------------------------------------------------
11361  document.addEventListener('keydown', function (e) {
11362    if (!openStack.length) return;
11363    var popup = openStack[openStack.length - 1];
11364
11365    if (e.key === 'Escape') { e.preventDefault(); close(); return; }
11366
11367    if (e.key === 'Tab') {
11368      var items = Array.prototype.filter.call(
11369        popup.querySelectorAll(FOCUSABLE),
11370        function (el) { return el.offsetParent !== null; }
11371      );
11372      if (!items.length) return;
11373      var first = items[0], last = items[items.length - 1];
11374      if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
11375      else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
11376    }
11377  });
11378
11379  // --- Выбор варианта в попапе оплаты ---------------------------------------
11380  // Подсветка карточки. :has() ещё не везде, поэтому классом.
11381  root.addEventListener('change', function (e) {
11382    if (!e.target.classList.contains('radio')) return;
11383    var group = e.target.closest('.opt-group__options');
11384    if (!group) return;
11385    Array.prototype.forEach.call(group.querySelectorAll('.option'), function (opt) {
11386      var input = opt.querySelector('.radio');
11387      opt.classList.toggle('is-selected', !!input && input.checked);
11388    });
11389  });
11390
11391  const formatGroup = document.querySelector('.opt-group-format')
11392  const paymodeGroups = document.querySelectorAll('.opt-group-paymode')
11393  const optResults = document.querySelectorAll('.opt-result')
11394
11395  function updateResult (input) {
11396    optResults.forEach(result => {
11397      result.classList.toggle(
11398        'active',
11399        result.dataset.result === input.dataset.result
11400      )
11401    })
11402  }
11403
11404  if (formatGroup) {
11405    const formatInputs = formatGroup.querySelectorAll('input')
11406
11407    formatInputs.forEach(formatInput => {
11408      formatInput.addEventListener('change', () => {
11409
11410        const currentPayMode = document.querySelector(
11411          '.opt-group-paymode.active input:checked'
11412        )
11413
11414        const currentPayModeValue = currentPayMode?.value
11415
11416        const newPayModeGroup = document.querySelector(
11417          `.opt-group-paymode[data-format="${formatInput.value}"]`
11418        )
11419
11420        paymodeGroups.forEach(group => {
11421          group.classList.remove('active')
11422        })
11423
11424        if (!newPayModeGroup) return
11425
11426        newPayModeGroup.classList.add('active')
11427
11428        const newPayModeInputs = newPayModeGroup.querySelectorAll('input')
11429
11430        let newPayModeInput = Array.from(newPayModeInputs).find(
11431          input => input.value === currentPayModeValue
11432        )
11433
11434        if (!newPayModeInput) {
11435          newPayModeInput = newPayModeInputs[0]
11436        }
11437
11438        if (!newPayModeInput) return
11439
11440        newPayModeInput.checked = true
11441        newPayModeInput.dispatchEvent(
11442          new Event('change', { bubbles: true })
11443        )
11444      })
11445    })
11446  }
11447
11448  paymodeGroups.forEach(paymodeGroup => {
11449    paymodeGroup.querySelectorAll('input').forEach(input => {
11450      input.addEventListener('change', () => {
11451        updateResult(input)
11452      })
11453    })
11454  })
11455
11456  document.addEventListener('mouseleave', mouseLeaveHandler)
11457
11458  function mouseLeaveHandler(event) {
11459    if (event.clientY < 0 && !openStack.length) {
11460      const exitOverlay = document.querySelector('#exitOverlay')
11461      if (exitOverlay) exitOverlay.classList.add('popup_no-social')
11462      open('exitOverlay')
11463      document.removeEventListener('mouseleave', mouseLeaveHandler)
11464    }
11465  }
11466
11467
11468  // Наружу — на случай, если понадобится дёрнуть из кода проекта.
11469  window.tfPopups = { open: open, close: close, closeAll: closeAll };
11470})();
11471
11472/* ==========================================================================
11473   sticky.js — показ липкой панели и обратный отсчёт в оффере
11474   ========================================================================== */
11475(function () {
11476  'use strict';
11477
11478  // --- Липкая панель ---------------------------------------------------------
11479  // Появляется, когда пользователь ушёл ниже первого экрана, и прячется,
11480  // когда виден сам блок оффера — там уже есть своя кнопка.
11481  var sticky = document.getElementById('stickyCta');
11482  var offer = document.querySelector('.section--offer');
11483
11484  if (sticky) {
11485    var offerVisible = false;
11486
11487    if (offer && 'IntersectionObserver' in window) {
11488      new IntersectionObserver(function (entries) {
11489        offerVisible = entries[0].isIntersecting;
11490        update();
11491      }, { threshold: 0.2 }).observe(offer);
11492    }
11493
11494    var update = function () {
11495      sticky.classList.toggle('is-visible', !offerVisible);
11496    };
11497
11498    var ticking = false;
11499    window.addEventListener('scroll', function () {
11500      if (ticking) return;
11501      ticking = true;
11502      window.requestAnimationFrame(function () { update(); ticking = false; });
11503    }, { passive: true });
11504
11505    update();
11506  }
11507
11508  // --- Таймер оффера ---------------------------------------------------------
11509  // Дедлайн берётся из data-deadline-minutes. На бою заменить на время с сервера.
11510  var timer = document.querySelector('[data-element="try-free-timer"]')
11511  if (!timer) return
11512
11513  var dateEndStr = timer.getAttribute('date-end')
11514  if (!dateEndStr) return
11515
11516  var deadline = Date.parse(dateEndStr)
11517  if (isNaN(deadline)) return
11518
11519  var slots = {
11520    hours: timer.querySelector('[data-timer="hours"]'),
11521    minutes: timer.querySelector('[data-timer="minutes"]'),
11522    seconds: timer.querySelector('[data-timer="seconds"]')
11523  };
11524
11525  function pad(n) { return n < 10 ? '0' + n : String(n); }
11526
11527  function tick() {
11528    var left = Math.max(0, deadline - Date.now());
11529    var total = Math.floor(left / 1000);
11530
11531    if (slots.hours)   slots.hours.textContent   = pad(Math.floor(total / 3600));
11532    if (slots.minutes) slots.minutes.textContent = pad(Math.floor(total % 3600 / 60));
11533    if (slots.seconds) slots.seconds.textContent = pad(total % 60);
11534
11535    if (left > 0) {
11536      window.setTimeout(tick, 1000);
11537    } else {
11538      const title = document.querySelector('.offer__actions-title')
11539      if (title) title.remove()
11540      timer.remove()
11541    }
11542  }
11543  tick();
11544
11545})();
11546
11547
11548const vacanciesEndSlider = document.querySelector('.vacancies-end__slider')
11549
11550if (vacanciesEndSlider) vacanciesEndSliderInit()
11551
11552function vacanciesEndSliderInit () {
11553  let sliderSwiper
11554
11555  function initSlider () {
11556    sliderSwiper = new Swiper(vacanciesEndSlider, {
11557      mousewheel: { forceToAxis: true },
11558      slidesPerView: 'auto',
11559      spaceBetween: 15,
11560      a11y: false,
11561      grid: {
11562        rows: 2,
11563        fill: 'row',
11564      },
11565    })
11566  }
11567
11568  window.addEventListener('resize', checkSlider)
11569
11570  checkSlider()
11571
11572  function checkSlider () {
11573    if (window.innerWidth < 1360) {
11574      if (!sliderSwiper || sliderSwiper.destroyed) {
11575        initSlider()
11576      }
11577    } else {
11578      if (sliderSwiper && !sliderSwiper.destroyed) {
11579        sliderSwiper.destroy(true, true)
11580        sliderSwiper = null
11581      }
11582    }
11583  }
11584}
11585
11586const vacanciesStories = document.querySelector('.vacancies-stories')
11587
11588if (vacanciesStories) vacanciesStoriesInit()
11589
11590function vacanciesStoriesInit () {
11591  const body = document.querySelector('body')
11592
11593  const inners = vacanciesStories.querySelectorAll('.vacancies-stories__item')
11594
11595  for (let i = 0; i < inners.length; i++) {
11596    initInner(inners[i])
11597  }
11598
11599  function initInner (inner) {
11600    const btn = inner.querySelector('.vacancies-stories__more')
11601    btn.addEventListener('click', toggle)
11602
11603    function toggle () {
11604      if (inner.classList.contains('show')) {
11605        btn.innerHTML = 'Читать историю полностью'
11606        inner.classList.remove('show')
11607      } else {
11608        btn.innerHTML = 'Скрыть'
11609        inner.classList.add('show')
11610        if (window.innerWidth >= 744) createModal(inner, btn)
11611      }
11612    }
11613
11614    function createModal(innerOld) {
11615      const slide = innerOld.closest('.vacancies-stories__item')
11616      const imageOld = slide.querySelector('.vacancies-stories__image')
11617      const textOld = slide.querySelector('.vacancies-stories__content')
11618      const nameOld = slide.querySelector('.vacancies-stories__name')
11619      const noteOld = slide.querySelector('.vacancies-stories__role')
11620
11621      const modal = document.createElement('div')
11622      modal.classList.add('review-modal','review-modal_vacancies-stories')
11623      modal.setAttribute('data-block', 'modal_story')
11624
11625      const layer = document.createElement('div')
11626      layer.classList.add('review-modal__layer')
11627      layer.setAttribute('data-action', 'modal_close')
11628
11629      const inner = document.createElement('div')
11630      inner.classList.add('review-modal__inner')
11631
11632      const close = document.createElement('button')
11633      close.classList.add('review-modal__close')
11634      close.setAttribute('data-action', 'modal_close')
11635
11636      const left = document.createElement('div')
11637      left.classList.add('review-modal__left')
11638
11639      const box = document.createElement('div')
11640      box.classList.add('review-modal__box')
11641
11642      const image = document.createElement('img')
11643      image.classList.add('review-modal__image')
11644
11645      const name = document.createElement('div')
11646      name.classList.add('review-modal__name')
11647
11648      const note = document.createElement('div')
11649      note.classList.add('review-modal__note')
11650
11651      const right = document.createElement('div')
11652      right.classList.add('review-modal__right')
11653
11654      const text = document.createElement('div')
11655      text.classList.add('review-modal__text')
11656
11657      image.src = imageOld.src
11658
11659      box.append(name)
11660      box.append(note)
11661      name.innerHTML = nameOld.innerHTML
11662      note.innerHTML = noteOld.innerHTML
11663      left.append(image)
11664      left.append(box)
11665      text.innerHTML = textOld.innerHTML
11666      right.append(text)
11667      inner.append(close)
11668      inner.append(left)
11669      inner.append(right)
11670      modal.append(layer)
11671      modal.append(inner)
11672
11673      layer.addEventListener('click', () => setTimeout(closeModal, 100))
11674      close.addEventListener('click', () => setTimeout(closeModal, 100))
11675
11676      const main = document.querySelector('main')
11677      main.append(modal)
11678
11679      body.classList.add('no-scroll-desktop')
11680
11681      initCommonAnalytics(modal)
11682
11683      function closeModal () {
11684        modal.remove()
11685        innerOld.classList.remove('show')
11686        btn.innerHTML = 'Читать историю полностью'
11687        body.classList.remove('no-scroll-desktop')
11688      }
11689    }
11690  }
11691
11692}
11693
11694
11695const vacanciesTile = document.querySelector('.vacancies-tile')
11696
11697if (vacanciesTile) vacanciesTileInit()
11698
11699function vacanciesTileInit () {
11700  const inputs = vacanciesTile.querySelectorAll('.vacancies-tile__input')
11701  const cards = vacanciesTile.querySelectorAll('.vacancies-tile__card')
11702  const buttonPaginate = vacanciesTile.querySelector('.vacancies-tile__more')
11703  let paginateCounter = 1
11704  let paginatePerPage = 6
11705  let currentCards = []
11706
11707  buttonPaginate.addEventListener('click', paginate)
11708
11709  inputs.forEach(input => {
11710    input.addEventListener('change', updateTile)
11711  })
11712
11713  updateTile(true)
11714
11715  function updateTile (noRedirect) {
11716    currentCards = []
11717    paginateCounter = 1
11718    const currentCategory = this?.value || "0"
11719
11720    cards.forEach(card => {
11721      card.classList.add('hide')
11722      if (card.getAttribute('data-category') === currentCategory || currentCategory === "0") {
11723        currentCards.push(card)
11724      }
11725    })
11726
11727    paginate()
11728
11729    if (!noRedirect) {
11730      vacanciesTile.scrollIntoView({
11731        behavior: 'smooth'
11732      })
11733    }
11734  }
11735
11736  function paginate () {
11737    currentCards.forEach((card, index) => {
11738      if (index < paginateCounter * paginatePerPage) {
11739        card.classList.remove('hide')
11740      }
11741    })
11742    if (currentCards.length <= paginateCounter * paginatePerPage) {
11743      buttonPaginate.style.display = 'none'
11744    } else {
11745      buttonPaginate.style.display = 'inline-flex'
11746    }
11747    paginateCounter += 1
11748  }
11749}
11750
11751
11752const webinarRecordVideoBoxes = document.querySelectorAll('.webinar-record__video-box_poster')
11753
11754webinarRecordVideoBoxes.forEach(videoBox => {
11755  videoBox.addEventListener('click', () => {
11756    videoBox.classList.add('active')
11757  }, {once: true})
11758})
11759
11760if (webinarRecordVideoBoxes.length > 0) {
11761  window.addEventListener('blur', function() {
11762    const activeElement = document.activeElement
11763
11764    if (activeElement && activeElement.tagName === 'IFRAME') {
11765      const container = activeElement.closest('.webinar-record__video-box_poster')
11766      if (container) {
11767        container.classList.add('active')
11768      }
11769    }
11770  })
11771}
11772

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.