PageSourceSearch

https://tehnokvarc.ru/wp-content/themes/kvarc/assets/scripts/script.js?ver=15

js tehnokvarc.ru collected 2026-10-07 15:40:22 UTC 89,619 bytes, 2,725 lines download raw bytes

1// Основной JavaScript файл
2document.addEventListener("DOMContentLoaded", function () {
3  // Улучшенный lazy loading для изображений
4  const lazyImages = document.querySelectorAll('img[loading="lazy"]');
5
6  const imageObserver = new IntersectionObserver(
7    (entries, observer) => {
8      entries.forEach((entry) => {
9        if (entry.isIntersecting) {
10          const img = entry.target;
11          img.addEventListener("load", () => {
12            img.classList.add("loaded");
13          });
14          observer.unobserve(img);
15        }
16      });
17    },
18    {
19      rootMargin: "50px 0px",
20      threshold: 0.1,
21    }
22  );
23
24  lazyImages.forEach((img) => {
25    imageObserver.observe(img);
26  });
27  const searchToggles = document.querySelectorAll(".search-toggle");
28  const mobileSearchToggle = document.querySelector(".mobile-search");
29  const searchBlock = document.querySelector(".search");
30  const searchClose = document.querySelector(".search__close");
31  const searchInput = document.querySelector(".search__input");
32  const searchSubmit = document.querySelector(".search__submit");
33  const mobileMenu = document.querySelector(".mobile-menu");
34  const mobileMenuClose = document.querySelector(".mobile-menu__close");
35  const mobileSearch = document.querySelector(".mobile-search-screen");
36  const mobileSearchBtn = document.querySelector(".mobile-menu__search-btn");
37  const mobileSearchBack = document.querySelector(".mobile-search__back");
38  const mobileSearchInput = document.querySelector(".mobile-search__input");
39  const mobileSearchSubmit = document.querySelector(".mobile-search__submit");
40  const mobileSearchResults = document.querySelector(".mobile-search__results");
41  const desktopCatalogBtn = document.querySelector(".desktop-catalog");
42  const catalogPanel = document.querySelector(".catalog-panel");
43  const catalogOverlay = document.querySelector(".catalog-overlay");
44  const catalogClose = document.querySelector(".catalog-panel__close");
45  const mobileCatalogScreen = document.querySelector(".mobile-catalog-screen");
46  const mobileCatalogBack = document.querySelector(".mobile-catalog__back");
47  if (searchToggles.length && searchBlock) {
48    const openSearch = () => {
49      searchBlock.classList.add("search--open");
50      searchBlock.setAttribute("aria-hidden", "false");
51      if (searchInput) setTimeout(() => searchInput.focus(), 200);
52    };
53    const closeSearch = () => {
54      searchBlock.classList.remove("search--open");
55      searchBlock.setAttribute("aria-hidden", "true");
56    };
57    searchToggles.forEach((btn) => {
58      btn.addEventListener("click", openSearch);
59    });
60    if (searchClose) searchClose.addEventListener("click", closeSearch);
61    document.addEventListener("keydown", (e) => {
62      if (e.key === "Escape") closeSearch();
63    });
64  }
65
66  if (searchInput && searchSubmit) {
67    let searchTimeout;
68
69    const performSearch = async (query) => {
70      if (query.length < 2) {
71        updateSearchResults([]);
72        return;
73      }
74
75      try {
76        const formData = new FormData();
77        formData.append("action", "kvarc_search");
78        formData.append("query", query);
79        formData.append("nonce", kvarc_ajax.nonce);
80
81        const response = await fetch(kvarc_ajax.ajax_url, {
82          method: "POST",
83          body: formData,
84        });
85
86        const data = await response.json();
87
88        if (data.success) {
89          updateSearchResults(data.data.results);
90        }
91      } catch (error) {
92        console.error("Ошибка поиска:", error);
93      }
94    };
95
96    const highlightText = (text, query) => {
97      if (!query || query.length < 2) return text;
98
99      const regex = new RegExp(
100        `(${query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`,
101        "gi"
102      );
103      return text.replace(regex, '<mark class="search-highlight">$1</mark>');
104    };
105
106    const updateSearchResults = (results) => {
107      const resultsContainer = document.querySelector(".search__results");
108      if (!resultsContainer) {
109        return;
110      }
111
112      if (results.length === 0) {
113        resultsContainer.style.display = "none";
114        return;
115      }
116
117      const query = searchInput.value.trim();
118
119      // Группируем результаты по типам
120      const products = results.filter((r) => r.type === "product");
121      const categories = results.filter((r) => r.type === "category");
122      const pages = results.filter((r) => r.type === "page");
123
124      let html = "";
125
126      // Товары
127      if (products.length > 0) {
128        html +=
129          '<div class="search__column"><div class="search__group"><ul class="search__list">';
130        products.forEach((product) => {
131          const highlightedTitle = highlightText(product.title, query);
132          html += `<li class="search__item"><a href="${product.url}">${highlightedTitle}</a></li>`;
133        });
134        html += "</ul></div></div>";
135      }
136
137      // Категории
138      if (categories.length > 0) {
139        html +=
140          '<div class="search__column"><div class="search__group"><ul class="search__list">';
141        categories.forEach((category) => {
142          const highlightedTitle = highlightText(category.title, query);
143          html += `<li class="search__item"><a href="${category.url}">${highlightedTitle}</a></li>`;
144        });
145        html += "</ul></div></div>";
146      }
147
148      // Страницы
149      if (pages.length > 0) {
150        html +=
151          '<div class="search__column"><div class="search__group"><ul class="search__list">';
152        pages.forEach((page) => {
153          const highlightedTitle = highlightText(page.title, query);
154          html += `<li class="search__item"><a href="${page.url}">${highlightedTitle}</a></li>`;
155        });
156        html += "</ul></div></div>";
157      }
158
159      resultsContainer.innerHTML = html;
160      resultsContainer.style.display = "grid";
161    };
162
163    const updateSearchButtonState = () => {
164      const hasValue = searchInput.value.trim().length > 0;
165      searchSubmit.disabled = !hasValue;
166
167      // Очищаем предыдущий таймаут
168      if (searchTimeout) {
169        clearTimeout(searchTimeout);
170      }
171
172      // Устанавливаем новый таймаут для поиска
173      searchTimeout = setTimeout(() => {
174        performSearch(searchInput.value.trim());
175      }, 300);
176    };
177
178    updateSearchButtonState();
179    searchInput.addEventListener("input", updateSearchButtonState);
180
181    // Обработка отправки формы
182    if (searchSubmit) {
183      searchSubmit.addEventListener("click", (e) => {
184        e.preventDefault();
185        const query = searchInput.value.trim();
186        if (query.length > 0) {
187          window.location.href = `${
188            window.location.origin
189          }/?s=${encodeURIComponent(query)}`;
190        }
191      });
192    }
193  }
194
195  const header = document.querySelector(".site-header");
196  const openMobileMenu = () => {
197    if (!mobileMenu) return;
198    mobileMenu.classList.add("is-open");
199    mobileMenu.setAttribute("aria-hidden", "false");
200    if (header) header.classList.add("menu-open");
201    document.body.style.overflow = "hidden";
202  };
203  const closeMobileMenu = () => {
204    if (!mobileMenu) return;
205    mobileMenu.classList.remove("is-open");
206    mobileMenu.setAttribute("aria-hidden", "true");
207    if (header) header.classList.remove("menu-open");
208    document.body.style.overflow = "";
209  };
210
211  const burgerButtons = document.querySelectorAll(".mobile-burger");
212  burgerButtons.forEach((btn) =>
213    btn.addEventListener("click", () => {
214      const willOpen = !(
215        mobileMenu && mobileMenu.classList.contains("is-open")
216      );
217      if (willOpen) {
218        btn.classList.add("active");
219        openMobileMenu();
220      } else {
221        btn.classList.remove("active");
222        closeMobileMenu();
223      }
224    })
225  );
226
227  if (mobileMenuClose)
228    mobileMenuClose.addEventListener("click", () => {
229      burgerButtons.forEach((btn) => btn.classList.remove("active"));
230      closeMobileMenu();
231    });
232  document.addEventListener("keydown", (e) => {
233    if (e.key === "Escape") closeMobileMenu();
234  });
235
236  const openMobileSearch = () => {
237    if (!mobileSearch) return;
238    mobileSearch.classList.add("is-open");
239    mobileSearch.setAttribute("aria-hidden", "false");
240    if (mobileSearchInput) setTimeout(() => mobileSearchInput.focus(), 150);
241  };
242  const closeMobileSearch = () => {
243    if (!mobileSearch) return;
244    mobileSearch.classList.remove("is-open");
245    mobileSearch.setAttribute("aria-hidden", "true");
246  };
247  if (mobileSearchBtn) {
248    mobileSearchBtn.addEventListener("click", openMobileSearch);
249  } else {
250    console.warn("[mobile-search] .mobile-menu__search-btn NOT FOUND at init");
251    // делегирование включаем ТОЛЬКО если кнопка не найдена при инициализации
252    document.addEventListener("click", (e) => {
253      const btn =
254        e.target.closest && e.target.closest(".mobile-menu__search-btn");
255      if (btn) {
256        openMobileSearch();
257      }
258    });
259  }
260  if (mobileSearchBack)
261    mobileSearchBack.addEventListener("click", () => {
262      if (mobileSearchInput) mobileSearchInput.value = "";
263      if (mobileSearchResults) mobileSearchResults.innerHTML = "";
264      if (mobileSearchSubmit) mobileSearchSubmit.disabled = true;
265
266      // Очищаем таймаут поиска
267      if (mobileSearchTimeout) {
268        clearTimeout(mobileSearchTimeout);
269      }
270
271      closeMobileSearch();
272    });
273  document.addEventListener("keydown", (e) => {
274    if (e.key === "Escape") closeMobileSearch();
275  });
276
277  let mobileSearchTimeout;
278
279  const performMobileSearch = async (query) => {
280    if (query.length < 2) {
281      renderMobileResults([]);
282      return;
283    }
284
285    try {
286      const formData = new FormData();
287      formData.append("action", "kvarc_search");
288      formData.append("query", query);
289      formData.append("nonce", kvarc_ajax.nonce);
290
291      const response = await fetch(kvarc_ajax.ajax_url, {
292        method: "POST",
293        body: formData,
294      });
295
296      const data = await response.json();
297
298      if (data.success) {
299        renderMobileResults(data.data.results);
300      }
301    } catch (error) {
302      console.error("Ошибка мобильного поиска:", error);
303    }
304  };
305
306  const renderMobileResults = (results) => {
307    if (!mobileSearchResults) return;
308
309    if (!results || results.length === 0) {
310      mobileSearchResults.innerHTML = "";
311      return;
312    }
313
314    const html = results
315      .map(
316        (result) =>
317          `<a href="${result.url}" class="mobile-search__result">
318                            <span class="mobile-search__result-title">${
319                              result.title
320                            }</span>
321                            ${
322                              result.price
323                                ? `<span class="mobile-search__result-desc">${result.price}</span>`
324                                : ""
325                            }
326                            ${
327                              result.excerpt
328                                ? `<span class="mobile-search__result-desc">${result.excerpt}</span>`
329                                : ""
330                            }
331                        </a>`
332      )
333      .join("");
334
335    mobileSearchResults.innerHTML = html;
336  };
337
338  const updateMobileSearchState = () => {
339    const hasValue =
340      !!mobileSearchInput && mobileSearchInput.value.trim().length > 0;
341    if (mobileSearchSubmit) mobileSearchSubmit.disabled = !hasValue;
342
343    // Очищаем предыдущий таймаут
344    if (mobileSearchTimeout) {
345      clearTimeout(mobileSearchTimeout);
346    }
347
348    // Устанавливаем новый таймаут для поиска
349    mobileSearchTimeout = setTimeout(() => {
350      performMobileSearch(mobileSearchInput.value.trim());
351    }, 300);
352  };
353
354  if (mobileSearchInput)
355    mobileSearchInput.addEventListener("input", () => {
356      updateMobileSearchState();
357    });
358  if (mobileSearchSubmit)
359    mobileSearchSubmit.addEventListener("click", (e) => {
360      e.preventDefault();
361      updateMobileSearchState();
362    });
363
364  const openCatalogPanel = () => {
365    if (!catalogPanel) return;
366    catalogPanel.classList.add("is-open");
367    if (catalogOverlay) catalogOverlay.classList.add("is-open");
368    if (header) header.classList.add("menu-open");
369    document.body.style.overflow = "hidden";
370  };
371  const closeCatalogPanel = () => {
372    if (!catalogPanel) return;
373    catalogPanel.classList.remove("is-open");
374    if (catalogOverlay) catalogOverlay.classList.remove("is-open");
375    if (header) header.classList.remove("menu-open");
376    document.body.style.overflow = "";
377  };
378  const mobileCatalogBtns = document.querySelectorAll(
379    ".mobile-catalog, .mobile-menu__catalog"
380  );
381
382  const openMobileCatalog = () => {
383    if (!mobileCatalogScreen) return;
384    mobileCatalogScreen.classList.add("is-open");
385    mobileCatalogScreen.setAttribute("aria-hidden", "false");
386    if (header) header.classList.add("menu-open");
387    document.body.style.overflow = "hidden";
388  };
389  const closeMobileCatalog = () => {
390    if (!mobileCatalogScreen) return;
391    mobileCatalogScreen.classList.remove("is-open");
392    mobileCatalogScreen.setAttribute("aria-hidden", "true");
393    if (header) header.classList.remove("menu-open");
394    document.body.style.overflow = "";
395  };
396
397  if (desktopCatalogBtn)
398    desktopCatalogBtn.addEventListener("click", openCatalogPanel);
399
400  mobileCatalogBtns.forEach((btn) => {
401    // Кнопки в mobile-actions всегда открывают десктопные версии
402    if (btn.closest(".mobile-actions")) {
403      btn.addEventListener("click", openCatalogPanel);
404    } else {
405      // Остальные мобильные кнопки работают по размеру экрана
406      btn.addEventListener("click", () => {
407        if (window.innerWidth <= 768) {
408          openMobileCatalog();
409        } else {
410          openCatalogPanel();
411        }
412      });
413    }
414  });
415
416  if (mobileCatalogBack)
417    mobileCatalogBack.addEventListener("click", closeMobileCatalog);
418  if (catalogClose) catalogClose.addEventListener("click", closeCatalogPanel);
419  if (catalogOverlay)
420    catalogOverlay.addEventListener("click", closeCatalogPanel);
421  document.addEventListener("keydown", (e) => {
422    if (e.key === "Escape") {
423      closeCatalogPanel();
424      closeMobileCatalog();
425    }
426  });
427
428  // Попапы
429  const popupOverlay = document.querySelector(".popup-overlay");
430  const popups = document.querySelectorAll(".popup");
431  const popupCloses = document.querySelectorAll(".popup__close");
432
433  window.openPopup = (popupClass) => {
434    const popup = document.querySelector(`.popup-${popupClass}`);
435    if (!popup) return;
436
437    const popupOverlay = document.querySelector(".popup-overlay");
438    popupOverlay.classList.add("is-open");
439    popup.classList.add("is-open");
440    document.body.style.overflow = "hidden";
441  };
442
443  window.closePopup = () => {
444    const popupOverlay = document.querySelector(".popup-overlay");
445    const popups = document.querySelectorAll(".popup");
446    popupOverlay.classList.remove("is-open");
447    popups.forEach((popup) => popup.classList.remove("is-open"));
448    document.body.style.overflow = "";
449  };
450
451  // Закрытие попапов
452  if (popupCloses.length > 0) {
453    popupCloses.forEach((btn) =>
454      btn.addEventListener("click", window.closePopup)
455    );
456  }
457  if (popupOverlay) {
458    popupOverlay.addEventListener("click", window.closePopup);
459  }
460  document.addEventListener("keydown", (e) => {
461    if (e.key === "Escape") window.closePopup();
462  });
463
464  // Логика города
465  const cityConfirm = document.querySelector(".popup-city-confirm");
466  const cityChange = document.querySelector(".popup-city-change");
467  const cityItems = document.querySelectorAll(".popup__city-item");
468  const locationBtn = document.querySelector(".location__btn");
469  const cityNameDisplay = document.querySelector(".popup__city-name");
470  const citySearchInput = document.querySelector(".popup__search-input");
471  const citiesList = document.querySelector(".popup__cities-list");
472
473  if (cityConfirm) {
474    cityConfirm.addEventListener("click", () => {
475      const currentCity = cityNameDisplay
476        ? cityNameDisplay.textContent
477        : "ВОРОНЕЖ";
478      localStorage.setItem("cityConfirmed", "true");
479      localStorage.setItem("userCity", currentCity.toLowerCase());
480      if (locationBtn) locationBtn.textContent = currentCity.toLowerCase();
481      window.closePopup();
482    });
483  }
484
485  cityItems.forEach((item) => {
486    item.addEventListener("click", (e) => {
487      // Если это ссылка на другой город, не перехватываем событие
488      if (item.tagName === "A" && item.href) {
489        // Очищаем localStorage перед переходом
490        localStorage.removeItem("city_popup_shown");
491        localStorage.removeItem("user_city_confirmed");
492        return; // Позволяем браузеру перейти по ссылке
493      }
494
495      // Для кнопок (старая логика)
496      const city = item.dataset.city;
497      localStorage.setItem("cityConfirmed", "true");
498      localStorage.setItem("userCity", city);
499      if (locationBtn) locationBtn.textContent = city;
500      if (cityNameDisplay) cityNameDisplay.textContent = city.toUpperCase();
501      window.closePopup();
502    });
503  });
504
505
506  // Поиск городов
507  if (citySearchInput && citiesList) {
508    const allCityItems = [...cityItems];
509
510    citySearchInput.addEventListener("input", (e) => {
511      const searchTerm = e.target.value.toLowerCase().trim();
512
513      allCityItems.forEach((item) => {
514        const cityName = item.textContent.toLowerCase();
515        const isVisible = cityName.includes(searchTerm);
516        item.style.display = isVisible ? "block" : "none";
517      });
518
519      // Показываем сообщение если ничего не найдено
520      const visibleItems = allCityItems.filter(
521        (item) => item.style.display !== "none"
522      );
523      if (visibleItems.length === 0 && searchTerm) {
524        if (!citiesList.querySelector(".popup__no-results")) {
525          const noResults = document.createElement("div");
526          noResults.className = "popup__no-results";
527          noResults.textContent = "Город не найден";
528          citiesList.appendChild(noResults);
529        }
530      } else {
531        const noResults = citiesList.querySelector(".popup__no-results");
532        if (noResults) noResults.remove();
533      }
534    });
535
536    // Очищаем поиск при открытии попапа городов
537    const citiesPopup = document.querySelector(".popup-cities");
538    if (citiesPopup) {
539      const observer = new MutationObserver((mutations) => {
540        mutations.forEach((mutation) => {
541          if (
542            mutation.type === "attributes" &&
543            mutation.attributeName === "class"
544          ) {
545            if (citiesPopup.classList.contains("is-open")) {
546              setTimeout(() => {
547                citySearchInput.value = "";
548                allCityItems.forEach((item) => (item.style.display = "block"));
549                const noResults =
550                  citiesList.querySelector(".popup__no-results");
551                if (noResults) noResults.remove();
552                citySearchInput.focus();
553              }, 100);
554            }
555          }
556        });
557      });
558      observer.observe(citiesPopup, { attributes: true });
559    }
560  }
561
562  // Кнопки открытия попапов
563  const authLinks = document.querySelectorAll('[href="#"]');
564  const orderBtn = document.querySelector(".hero__btn");
565
566  if (orderBtn) {
567    orderBtn.addEventListener("click", (e) => {
568      e.preventDefault();
569      openPopup("request");
570    });
571  }
572
573  // Авторизация
574  const authToggle = document.querySelector(".auth-toggle");
575  if (authToggle) {
576    authToggle.addEventListener("click", (e) => {
577      e.preventDefault();
578      openPopup("auth");
579    });
580  }
581
582  // Старая логика для обратной совместимости
583  authLinks.forEach((link) => {
584    if (link.closest(".icon-link") && link.querySelector('img[src*="exit"]')) {
585      link.addEventListener("click", (e) => {
586        e.preventDefault();
587        openPopup("auth");
588      });
589    }
590  });
591
592  // Табы авторизации
593  const authTabs = document.querySelectorAll(".popup__tab");
594  const authContents = document.querySelectorAll(".popup__tab-content");
595
596  authTabs.forEach((tab) => {
597    tab.addEventListener("click", () => {
598      const targetTab = tab.dataset.tab;
599
600      authTabs.forEach((t) => t.classList.remove("popup__tab--active"));
601      authContents.forEach((c) =>
602        c.classList.remove("popup__tab-content--active")
603      );
604
605      tab.classList.add("popup__tab--active");
606      document
607        .querySelector(`[data-content="${targetTab}"]`)
608        .classList.add("popup__tab-content--active");
609    });
610  });
611
612  // Валидация форм и управление кнопками
613  const forms = document.querySelectorAll(".popup__form");
614
615  const validateForm = (form) => {
616    const submitBtn = form.querySelector(".popup__submit");
617    const requiredInputs = form.querySelectorAll(
618      "input[required], textarea[required]"
619    );
620    const requiredCheckboxes = form.querySelectorAll(
621      'input[type="checkbox"][required]'
622    );
623
624    let isValid = true;
625
626    // Проверяем обязательные поля
627    requiredInputs.forEach((input) => {
628      if (!input.value.trim()) {
629        isValid = false;
630      }
631    });
632
633    // Проверяем обязательные чекбоксы
634    requiredCheckboxes.forEach((checkbox) => {
635      if (!checkbox.checked) {
636        isValid = false;
637      }
638    });
639
640    // Управляем состоянием кнопки
641    if (submitBtn) {
642      submitBtn.disabled = !isValid;
643      if (isValid) {
644        submitBtn.classList.remove("popup__submit--disabled");
645      } else {
646        submitBtn.classList.add("popup__submit--disabled");
647      }
648    }
649  };
650
651  forms.forEach((form) => {
652    const inputs = form.querySelectorAll("input, textarea");
653    const checkboxes = form.querySelectorAll('input[type="checkbox"]');
654
655    // Изначально валидируем форму
656    validateForm(form);
657
658    // Слушаем изменения в полях ввода
659    inputs.forEach((input) => {
660      input.addEventListener("input", () => validateForm(form));
661      input.addEventListener("change", () => validateForm(form));
662    });
663
664    // Слушаем изменения в чекбоксах
665    checkboxes.forEach((checkbox) => {
666      checkbox.addEventListener("change", () => validateForm(form));
667    });
668
669    // Обработка отправки
670    form.addEventListener("submit", (e) => {
671      e.preventDefault();
672      validateForm(form);
673
674      const submitBtn = form.querySelector(".popup__submit");
675      if (submitBtn && !submitBtn.disabled) {
676        // Здесь будет логика отправки
677        window.closePopup();
678      }
679    });
680  });
681
682  // Инициализация Swiper слайдера для категорий
683  if (document.querySelector(".categories__slider")) {
684    var swiper = new Swiper(".categories__slider", {
685      slidesPerView: 4,
686      slidesPerColumn: 2,
687      spaceBetween: 15,
688      slidesPerColumnFill: "row",
689      navigation: {
690        nextEl: ".categories__arrow--next",
691        prevEl: ".categories__arrow--prev",
692      },
693      scrollbar: {
694        el: ".categories__scrollbar",
695        draggable: true,
696      },
697    });
698  }
699
700  // Страница товара
701  const tabBtns = document.querySelectorAll(".tab-btn");
702  const tabContents = document.querySelectorAll(".tab-content");
703
704  tabBtns.forEach((btn) => {
705    btn.addEventListener("click", () => {
706      const targetTab = btn.dataset.tab;
707
708      tabBtns.forEach((b) => b.classList.remove("tab-btn--active"));
709      tabContents.forEach((c) => c.classList.remove("tab-content--active"));
710
711      btn.classList.add("tab-btn--active");
712      document.getElementById(targetTab).classList.add("tab-content--active");
713    });
714  });
715
716  const quantityBtns = document.querySelectorAll(".quantity-btn");
717  const quantityInput = document.querySelector(".quantity-input");
718
719  quantityBtns.forEach((btn) => {
720    btn.addEventListener("click", () => {
721      if (!quantityInput) return;
722
723      let value = parseInt(quantityInput.value) || 1;
724
725      if (btn.classList.contains("quantity-btn--minus")) {
726        value = Math.max(1, value - 1);
727      } else if (btn.classList.contains("quantity-btn--plus")) {
728        value = value + 1;
729      }
730
731      quantityInput.value = value;
732    });
733  });
734
735  const galleryMain = document.querySelector(".product-gallery__main");
736  const galleryThumbs = document.querySelector(".product-gallery__thumbs");
737
738  if (galleryMain && galleryThumbs) {
739    var thumbsSwiper = new Swiper(galleryThumbs, {
740      spaceBetween: 12,
741      slidesPerView: 3,
742      watchSlidesProgress: true,
743      breakpoints: {
744        320: {
745          slidesPerView: 2,
746          spaceBetween: 8,
747        },
748        768: {
749          slidesPerView: 3,
750          spaceBetween: 12,
751        },
752        1024: {
753          slidesPerView: 3,
754          spaceBetween: 12,
755        },
756      },
757    });
758
759    var mainSwiper = new Swiper(galleryMain, {
760      spaceBetween: 10,
761      slidesPerView: 1,
762      navigation: {
763        nextEl: ".swiper-button-next",
764        prevEl: ".swiper-button-prev",
765      },
766      scrollbar: {
767        el: ".swiper-scrollbar",
768        draggable: true,
769      },
770      thumbs: {
771        swiper: thumbsSwiper,
772      },
773    });
774
775    // Ручная привязка кликов по миниатюрам
776    galleryThumbs.querySelectorAll('.swiper-slide').forEach(function(thumb, index) {
777      thumb.style.cursor = 'pointer';
778      thumb.addEventListener('click', function() {
779        mainSwiper.slideTo(index);
780      });
781    });
782
783    // Подсветка активной миниатюры при смене слайда
784    mainSwiper.on('slideChange', function() {
785      var activeIndex = mainSwiper.activeIndex;
786      galleryThumbs.querySelectorAll('.swiper-slide').forEach(function(t, i) {
787        t.classList.toggle('swiper-slide-thumb-active', i === activeIndex);
788      });
789    });
790  }
791
792  // Слайдер лидеры продаж
793  const bestsellersSlider = document.querySelector(".bestsellers__slider");
794  if (bestsellersSlider) {
795    const bestsellersSwiper = new Swiper(bestsellersSlider, {
796      slidesPerView: 4,
797      spaceBetween: 24,
798      navigation: {
799        nextEl: ".bestsellers__arrow--next",
800        prevEl: ".bestsellers__arrow--prev",
801      },
802      scrollbar: {
803        el: ".bestsellers__slider .swiper-scrollbar",
804        draggable: true,
805      },
806      breakpoints: {
807        320: {
808          slidesPerView: 1.2,
809          spaceBetween: 16,
810        },
811        768: {
812          slidesPerView: 1.2,
813          spaceBetween: 20,
814        },
815        900: {
816          slidesPerView: 3,
817          spaceBetween: 24,
818        },
819        1200: {
820          slidesPerView: 4,
821          spaceBetween: 24,
822        },
823      },
824    });
825  }
826
827  // Липкая панель товара
828  const productSticky = document.getElementById("productSticky");
829  if (productSticky) {
830    let lastScrollY = 0;
831
832    const handleScroll = () => {
833      const scrollY = window.scrollY;
834      const productInfo = document.querySelector(".product-info");
835
836      if (productInfo) {
837        const productInfoBottom =
838          productInfo.offsetTop + productInfo.offsetHeight;
839
840        // Показываем панель когда прокрутили ниже основной информации о товаре
841        if (scrollY > productInfoBottom) {
842          productSticky.classList.add("show");
843        } else {
844          productSticky.classList.remove("show");
845        }
846      }
847
848      lastScrollY = scrollY;
849    };
850
851    window.addEventListener("scroll", handleScroll, { passive: true });
852
853    // Синхронизация количества с основной формой
854    const stickyQuantityBtns = productSticky.querySelectorAll(".quantity-btn");
855    const stickyQuantityInput = productSticky.querySelector(".quantity-input");
856    const mainQuantityInput = document.querySelector(
857      ".product-purchase .quantity-input"
858    );
859
860    stickyQuantityBtns.forEach((btn) => {
861      btn.addEventListener("click", () => {
862        if (!stickyQuantityInput) return;
863
864        let value = parseInt(stickyQuantityInput.value) || 1;
865
866        if (btn.classList.contains("quantity-btn--minus")) {
867          value = Math.max(1, value - 1);
868        } else if (btn.classList.contains("quantity-btn--plus")) {
869          value = value + 1;
870        }
871
872        stickyQuantityInput.value = value;
873        if (mainQuantityInput) mainQuantityInput.value = value;
874      });
875    });
876
877    // Синхронизация при изменении в основной форме
878    if (mainQuantityInput && stickyQuantityInput) {
879      mainQuantityInput.addEventListener("input", () => {
880        stickyQuantityInput.value = mainQuantityInput.value;
881      });
882    }
883  }
884
885  const favoriteBtn = document.querySelector(".product-info__favorite");
886  if (favoriteBtn) {
887    favoriteBtn.addEventListener("click", () => {
888      favoriteBtn.classList.toggle("product-info__favorite--active");
889    });
890  }
891
892  const addToCartBtn = document.querySelector(".btn--cart");
893  if (addToCartBtn) {
894    addToCartBtn.addEventListener("click", () => {
895      const quantity = quantityInput ? parseInt(quantityInput.value) || 1 : 1;
896    });
897  }
898
899
900
901
902
903
904
905  // Синхронизация с WooCommerce при загрузке страницы
906  const variationsForm = document.querySelector(".variations_form");
907  if (variationsForm) {
908    // Инициализируем WooCommerce вариации
909    if (typeof wc_add_to_cart_variation_params !== "undefined") {
910      // WooCommerce уже инициализирован
911    } else {
912      // Ждем инициализации WooCommerce
913      setTimeout(() => {
914        const event = new Event("wc_variation_form", { bubbles: true });
915        variationsForm.dispatchEvent(event);
916      }, 100);
917    }
918  }
919
920  // Video Swiper
921  const videoSwiper = new Swiper(".video-slider", {
922    slidesPerView: 1.2,
923    spaceBetween: 20,
924    navigation: {
925      nextEl: ".video-btn-next",
926      prevEl: ".video-btn-prev",
927    },
928    breakpoints: {
929      320: {
930        slidesPerView: 1,
931        spaceBetween: 16,
932      },
933      768: {
934        slidesPerView: 1,
935        spaceBetween: 10,
936      },
937      1024: {
938        spaceBetween: 20,
939        slidesPerView: 1.2,
940      },
941    },
942  });
943
944  // Production Slider
945  const productionSwiper = new Swiper(".production-slider", {
946    effect: "fade",
947    fadeEffect: {
948      crossFade: true,
949    },
950    slidesPerView: 1,
951
952    pagination: {
953      el: ".swiper-pagination",
954      clickable: true,
955    },
956    navigation: {
957      nextEl: ".swiper-button-next",
958      prevEl: ".swiper-button-prev",
959    },
960  });
961
962  // Якорная навигация для страницы О компании
963  const aboutNavLinks = document.querySelectorAll(".about-nav__link");
964  const aboutSections = document.querySelectorAll(".about-section");
965
966  if (aboutNavLinks.length > 0) {
967    // Smooth scroll для якорных ссылок
968    aboutNavLinks.forEach((link) => {
969      link.addEventListener("click", (e) => {
970        e.preventDefault();
971        const targetId = link.getAttribute("href").substring(1);
972        const targetSection = document.getElementById(targetId);
973
974        if (targetSection) {
975          targetSection.scrollIntoView({
976            behavior: "smooth",
977            block: "start",
978          });
979
980          // Обновляем активную ссылку
981          aboutNavLinks.forEach((l) => l.classList.remove("active"));
982          link.classList.add("active");
983        }
984      });
985    });
986
987    // Отслеживание скролла для активации ссылок
988    const handleAboutScroll = () => {
989      let current = "";
990
991      aboutSections.forEach((section) => {
992        const sectionTop = section.offsetTop - 120;
993        const sectionHeight = section.offsetHeight;
994
995        if (
996          window.scrollY >= sectionTop &&
997          window.scrollY < sectionTop + sectionHeight
998        ) {
999          current = section.getAttribute("id");
1000        }
1001      });
1002
1003      if (current) {
1004        aboutNavLinks.forEach((link) => {
1005          link.classList.remove("active");
1006          if (link.getAttribute("href") === `#${current}`) {
1007            link.classList.add("active");
1008          }
1009        });
1010      }
1011    };
1012
1013    window.addEventListener("scroll", handleAboutScroll, { passive: true });
1014  }
1015
1016  // Определение города пользователя
1017  function detectUserCity() {
1018    // Проверяем, показывали ли мы уже попап в этой сессии
1019    const cityPopupShown = localStorage.getItem("city_popup_shown");
1020    if (cityPopupShown) {
1021      return;
1022    }
1023
1024    if (typeof kvarc_ajax !== "undefined") {
1025      fetch(kvarc_ajax.ajax_url, {
1026        method: "POST",
1027        headers: {
1028          "Content-Type": "application/x-www-form-urlencoded",
1029        },
1030        body: "action=get_user_city&nonce=" + kvarc_ajax.nonce,
1031      })
1032        .then((response) => response.json())
1033        .then((data) => {
1034          if (data.success && data.data.show_popup) {
1035            showCityPopup(data.data.city);
1036            // Сохраняем, что попап уже показан
1037            localStorage.setItem("city_popup_shown", "true");
1038          }
1039        })
1040        .catch((error) => {});
1041    }
1042  }
1043
1044  // Маппинг английских названий городов на русские
1045  const cityMapping = {
1046    TOLYATTI: "ТОЛЬЯТТИ",
1047    MOSCOW: "МОСКВА",
1048    "SAINT PETERSBURG": "САНКТ-ПЕТЕРБУРГ",
1049    SPB: "САНКТ-ПЕТЕРБУРГ",
1050    NOVOSIBIRSK: "НОВОСИБИРСК",
1051    EKATERINBURG: "ЕКАТЕРИНБУРГ",
1052    KAZAN: "КАЗАНЬ",
1053    "NIZHNY NOVGOROD": "НИЖНИЙ НОВГОРОД",
1054    CHELYABINSK: "ЧЕЛЯБИНСК",
1055    SAMARA: "САМАРА",
1056    ROSTOV: "РОСТОВ-НА-ДОНУ",
1057    "ROSTOV-ON-DON": "РОСТОВ-НА-ДОНУ",
1058    UFA: "УФА",
1059    KRASNOYARSK: "КРАСНОЯРСК",
1060    PERM: "ПЕРМЬ",
1061    VORONEZH: "ВОРОНЕЖ",
1062    VOLGOGRAD: "ВОЛГОГРАД",
1063    KRASNODAR: "КРАСНОДАР",
1064    SARATOV: "САРАТОВ",
1065    TYUMEN: "ТЮМЕНЬ",
1066    IZHEVSK: "ИЖЕВСК",
1067    BARNAUL: "БАРНАУЛ",
1068    ULYANOVSK: "УЛЬЯНОВСК",
1069    IRKUTSK: "ИРКУТСК",
1070    KHABAROVSK: "ХАБАРОВСК",
1071    YAROSLAVL: "ЯРОСЛАВЛЬ",
1072    VLADIVOSTOK: "ВЛАДИВОСТОК",
1073    MAKHACHKALA: "МАХАЧКАЛА",
1074    TOMSK: "ТОМСК",
1075    ORENBURG: "ОРЕНБУРГ",
1076    KEMEROVO: "КЕМЕРОВО",
1077    RYAZAN: "РЯЗАНЬ",
1078    ASTRAKHAN: "АСТРАХАНЬ",
1079    "NABEREZHNYE CHELNY": "НАБЕРЕЖНЫЕ ЧЕЛНЫ",
1080    PENZA: "ПЕНЗА",
1081    LIPETSK: "ЛИПЕЦК",
1082    KIROV: "КИРОВ",
1083    CHEBOKSARY: "ЧЕБОКСАРЫ",
1084    TULA: "ТУЛА",
1085    KALININGRAD: "КАЛИНИНГРАД",
1086    BRYANSK: "БРЯНСК",
1087    IVANOVO: "ИВАНОВО",
1088    MAGNITOGORSK: "МАГНИТОГОРСК",
1089    KURSK: "КУРСК",
1090    ARKHANGELSK: "АРХАНГЕЛЬСК",
1091    TVER: "ТВЕРЬ",
1092    STAVROPOL: "СТАВРОПОЛЬ",
1093    SIMFEROPOL: "СИМФЕРОПОЛЬ",
1094    BELGOROD: "БЕЛГОРОД",
1095    SOCHI: "СОЧИ",
1096    VLADIMIR: "ВЛАДИМИР",
1097    CHITA: "ЧИТА",
1098    GROZNY: "ГРОЗНЫЙ",
1099    KALUGA: "КАЛУГА",
1100    SMOLENSK: "СМОЛЕНСК",
1101    VOLZHESK: "ВОЛЖСК",
1102    Cherepovets: "ЧЕРЕПОВЕЦ",
1103    Vladikavkaz: "ВЛАДИКАВКАЗ",
1104    Saransk: "САРАНСК",
1105    Yakutsk: "ЯКУТСК",
1106    Murmansk: "МУРМАНСК",
1107    Vladimir: "ВЛАДИМИР",
1108    Orenburg: "ОРЕНБУРГ",
1109    Novokuznetsk: "НОВОКУЗНЕЦК",
1110    Kirov: "КИРОВ",
1111    Cheboksary: "ЧЕБОКСАРЫ",
1112    Ivanovo: "ИВАНОВО",
1113    Magnitogorsk: "МАГНИТОГОРСК",
1114    Krasnodar: "КРАСНОДАР",
1115    Tula: "ТУЛА",
1116    Bryansk: "БРЯНСК",
1117    Sochi: "СОЧИ",
1118    Arkhangelsk: "АРХАНГЕЛЬСК",
1119    Stavropol: "СТАВРОПОЛЬ",
1120    Kaluga: "КАЛУГА",
1121    Smolensk: "СМОЛЕНСК",
1122    Volzhsk: "ВОЛЖСК",
1123    Vladikavkaz: "ВЛАДИКАВКАЗ",
1124    Saransk: "САРАНСК",
1125    Yakutsk: "ЯКУТСК",
1126    Murmansk: "МУРМАНСК",
1127    Novokuznetsk: "НОВОКУЗНЕЦК",
1128  };
1129
1130  function translateCityName(cityName) {
1131    const upperCity = cityName.toUpperCase();
1132    return cityMapping[upperCity] || cityName.toUpperCase();
1133  }
1134
1135  function showCityPopup(cityName) {
1136    const popupCity = document.querySelector(".popup-city");
1137    const popupOverlay = document.querySelector(".popup-overlay");
1138    const cityNameElement = document.querySelector(".popup__city-name");
1139    const confirmBtn = document.querySelector(".popup-city-confirm");
1140    const changeBtn = document.querySelector(".popup-city-change");
1141
1142    if (popupCity && popupOverlay && cityNameElement) {
1143      cityNameElement.textContent = translateCityName(cityName);
1144
1145      // Показываем попап
1146      popupCity.classList.add("is-open");
1147      popupOverlay.classList.add("is-open");
1148
1149      // Обработчик для кнопки "Да, спасибо"
1150      if (confirmBtn) {
1151        // Удаляем старые обработчики
1152        const newConfirmBtn = confirmBtn.cloneNode(true);
1153        confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);
1154
1155        newConfirmBtn.addEventListener("click", () => {
1156          // Сохраняем выбор пользователя
1157          localStorage.setItem("city_popup_shown", "true");
1158          localStorage.setItem("user_city_confirmed", cityName);
1159
1160          // Закрываем попап
1161          popupCity.classList.remove("is-open");
1162          popupOverlay.classList.remove("is-open");
1163        });
1164      }
1165
1166      // Обработчик для кнопки "Нет, другой"
1167      if (changeBtn) {
1168        // Удаляем старые обработчики
1169        const newChangeBtn = changeBtn.cloneNode(true);
1170        changeBtn.parentNode.replaceChild(newChangeBtn, changeBtn);
1171
1172        newChangeBtn.addEventListener("click", (e) => {
1173          e.preventDefault();
1174          popupCity.classList.remove("is-open");
1175
1176          // Очищаем сохраненный выбор, так как пользователь хочет выбрать другой город
1177          localStorage.removeItem("city_popup_shown");
1178          localStorage.removeItem("user_city_confirmed");
1179
1180        });
1181      }
1182    }
1183  }
1184
1185
1186  // Обработчики закрытия попапов
1187  const popupCloseButtons = document.querySelectorAll(".popup__close");
1188  popupCloseButtons.forEach((closeBtn) => {
1189    closeBtn.addEventListener("click", () => {
1190      const popup = closeBtn.closest(".popup");
1191      const overlay = document.querySelector(".popup-overlay");
1192
1193      if (popup) {
1194        popup.classList.remove("is-open");
1195      }
1196      if (overlay) {
1197        overlay.classList.remove("is-open");
1198      }
1199    });
1200  });
1201
1202  // Очищаем localStorage при выборе города из списка (переход на другой сайт)
1203  const cityLinks = document.querySelectorAll(
1204    ".footer__cities a, .popup__city-item[href]"
1205  );
1206  cityLinks.forEach((link) => {
1207    link.addEventListener("click", () => {
1208      localStorage.removeItem("city_popup_shown");
1209      localStorage.removeItem("user_city_confirmed");
1210    });
1211  });
1212
1213  // Управление состоянием кнопок CF7 форм
1214  const cf7Forms = document.querySelectorAll(".wpcf7-form");
1215
1216  cf7Forms.forEach((form) => {
1217    const submitBtn = form.querySelector(".wpcf7-submit");
1218
1219    const validateCF7Form = () => {
1220      let isValid = true;
1221
1222      // Проверяем обязательные поля ввода (исключая чекбоксы)
1223      const requiredInputs = form.querySelectorAll(
1224        ".wpcf7-validates-as-required:not(.wpcf7-checkbox)"
1225      );
1226      requiredInputs.forEach((input) => {
1227        if (!input.value.trim()) {
1228          isValid = false;
1229        }
1230      });
1231
1232      // Проверяем обязательные чекбоксы
1233      const requiredCheckboxes = form.querySelectorAll(
1234        'input[type="checkbox"][required]'
1235      );
1236      requiredCheckboxes.forEach((checkbox) => {
1237        if (!checkbox.checked) {
1238          isValid = false;
1239        }
1240      });
1241
1242      // Проверяем CF7 acceptance чекбоксы
1243      const acceptanceCheckboxes = form.querySelectorAll(
1244        '.wpcf7-acceptance input[type="checkbox"]'
1245      );
1246      acceptanceCheckboxes.forEach((checkbox) => {
1247        if (!checkbox.checked) {
1248          isValid = false;
1249        }
1250      });
1251
1252      // Управляем состоянием кнопки
1253      if (submitBtn) {
1254        submitBtn.disabled = !isValid;
1255        if (isValid) {
1256          submitBtn.classList.remove("disabled");
1257        } else {
1258          submitBtn.classList.add("disabled");
1259        }
1260      }
1261    };
1262
1263    // Изначально валидируем форму
1264    validateCF7Form();
1265
1266    // Слушаем изменения в полях ввода
1267    const textInputs = form.querySelectorAll(
1268      'input[type="text"], input[type="tel"], input[type="email"], textarea'
1269    );
1270    textInputs.forEach((input) => {
1271      input.addEventListener("input", validateCF7Form);
1272      input.addEventListener("change", validateCF7Form);
1273    });
1274
1275    // Слушаем изменения в чекбоксах
1276    const checkboxes = form.querySelectorAll('input[type="checkbox"]');
1277    checkboxes.forEach((checkbox) => {
1278      checkbox.addEventListener("change", validateCF7Form);
1279    });
1280
1281    // Слушаем изменения в CF7 acceptance чекбоксах
1282    const acceptanceCheckboxes = form.querySelectorAll(
1283      '.wpcf7-acceptance input[type="checkbox"]'
1284    );
1285    acceptanceCheckboxes.forEach((checkbox) => {
1286      checkbox.addEventListener("change", validateCF7Form);
1287    });
1288
1289    // Обработчик для кастомных чекбоксов
1290    const customCheckboxes = form.querySelectorAll(".popup__checkbox");
1291    customCheckboxes.forEach((customCheckbox) => {
1292      const checkbox = customCheckbox.querySelector('input[type="checkbox"]');
1293      if (checkbox) {
1294        // Слушаем изменения чекбокса
1295        checkbox.addEventListener("change", () => {
1296          // Добавляем/убираем класс для стилизации
1297          customCheckbox.classList.toggle(
1298            "popup__checkbox--checked",
1299            checkbox.checked
1300          );
1301          validateCF7Form();
1302        });
1303
1304        // Изначально устанавливаем стиль
1305        customCheckbox.classList.toggle(
1306          "popup__checkbox--checked",
1307          checkbox.checked
1308        );
1309      }
1310    });
1311  });
1312
1313  // AJAX логин и регистрация
1314  const loginForm = document.querySelector("#login-form");
1315  const registerForm = document.querySelector("#register-form");
1316  const logoutBtn = document.querySelector("#logout-btn");
1317
1318  if (loginForm) {
1319    loginForm.addEventListener("submit", function (e) {
1320      e.preventDefault();
1321
1322      const formData = new FormData();
1323      formData.append("action", "kvarc_login");
1324      formData.append("nonce", kvarc_ajax.nonce);
1325      formData.append(
1326        "username",
1327        this.querySelector('[name="username"]').value
1328      );
1329      formData.append(
1330        "password",
1331        this.querySelector('[name="password"]').value
1332      );
1333      formData.append(
1334        "remember",
1335        this.querySelector('[name="remember"]')
1336          ? this.querySelector('[name="remember"]').checked
1337          : false
1338      );
1339
1340      fetch(kvarc_ajax.ajax_url, {
1341        method: "POST",
1342        body: formData,
1343      })
1344        .then((response) => response.json())
1345        .then((data) => {
1346          if (data.success) {
1347            showToast("Успешный вход!", "success");
1348            setTimeout(() => {
1349              location.reload();
1350            }, 1000);
1351          } else {
1352            showToast(data.data || "Ошибка входа", "error");
1353          }
1354        })
1355        .catch((error) => {
1356          showToast("Ошибка соединения", "error");
1357        });
1358    });
1359  }
1360
1361  if (registerForm) {
1362    registerForm.addEventListener("submit", function (e) {
1363      e.preventDefault();
1364
1365      const password = this.querySelector('[name="password"]').value;
1366      const passwordConfirm = this.querySelector(
1367        '[name="password_confirm"]'
1368      ).value;
1369
1370      if (password !== passwordConfirm) {
1371        showToast("Пароли не совпадают", "error");
1372        return;
1373      }
1374
1375      if (password.length < 6) {
1376        showToast("Пароль должен содержать минимум 6 символов", "error");
1377        return;
1378      }
1379
1380      const formData = new FormData();
1381      formData.append("action", "kvarc_register");
1382      formData.append("nonce", kvarc_ajax.nonce);
1383      formData.append(
1384        "username",
1385        this.querySelector('[name="username"]').value
1386      );
1387      formData.append("email", this.querySelector('[name="email"]').value);
1388      formData.append("password", password);
1389
1390      fetch(kvarc_ajax.ajax_url, {
1391        method: "POST",
1392        body: formData,
1393      })
1394        .then((response) => response.json())
1395        .then((data) => {
1396          if (data.success) {
1397            showToast("Регистрация успешна!", "success");
1398            setTimeout(() => {
1399              location.reload();
1400            }, 1000);
1401          } else {
1402            showToast(data.data || "Ошибка регистрации", "error");
1403          }
1404        })
1405        .catch((error) => {
1406          showToast("Ошибка соединения", "error");
1407        });
1408    });
1409  }
1410
1411  if (logoutBtn) {
1412    logoutBtn.addEventListener("click", function (e) {
1413      e.preventDefault();
1414
1415      const formData = new FormData();
1416      formData.append("action", "kvarc_logout");
1417      formData.append("nonce", kvarc_ajax.nonce);
1418
1419      fetch(kvarc_ajax.ajax_url, {
1420        method: "POST",
1421        body: formData,
1422      })
1423        .then((response) => response.json())
1424        .then((data) => {
1425          if (data.success) {
1426            showToast("Выход выполнен!", "success");
1427            setTimeout(() => {
1428              location.reload();
1429            }, 1000);
1430          }
1431        })
1432        .catch((error) => {
1433          showToast("Ошибка соединения", "error");
1434        });
1435    });
1436  }
1437
1438  // Переинициализация при AJAX загрузке
1439  document.addEventListener('woocommerce_variations_loaded', function() {
1440    initVariationSwatches();
1441  });
1442
1443  // Логика для показа/скрытия списка вариантов
1444  function initVariationDropdowns() {
1445    const variationHeaders = document.querySelectorAll('.variations th.label');
1446    
1447    variationHeaders.forEach(header => {
1448      header.addEventListener('click', function() {
1449        const row = this.closest('tr');
1450        const variationList = row.querySelector('.single-product-variable-items');
1451        
1452        if (variationList) {
1453          // Закрываем все другие списки
1454          document.querySelectorAll('.single-product-variable-items').forEach(list => {
1455            if (list !== variationList) {
1456              list.classList.remove('active');
1457            }
1458          });
1459          
1460          // Переключаем текущий список
1461          variationList.classList.toggle('active');
1462        }
1463      });
1464    });
1465
1466    // Закрытие при клике вне списка
1467    document.addEventListener('click', function(e) {
1468      if (!e.target.closest('.variations')) {
1469        document.querySelectorAll('.single-product-variable-items').forEach(list => {
1470          list.classList.remove('active');
1471        });
1472      }
1473    });
1474  }
1475
1476  // Запускаем инициализацию dropdown'ов
1477  if (document.querySelector('.variations')) {
1478    initVariationDropdowns();
1479  }
1480});
1481
1482jQuery(document.body).on(
1483  "added_to_cart",
1484  function (event, fragments, cart_hash, button) {
1485    setTimeout(function () {
1486      jQuery(".added_to_cart").remove();
1487
1488      var addedButtons = jQuery(".product-card__cart-btn.added");
1489      addedButtons.each(function () {
1490        var $btn = jQuery(this);
1491        $btn.text("Добавлено").addClass("product-card__cart-btn--added");
1492
1493        $btn.addClass("animate__animated animate__pulse");
1494        setTimeout(function () {
1495          $btn.removeClass("animate__animated animate__pulse");
1496        }, 1000);
1497      });
1498
1499      showToast("Товар добавлен в корзину!", "success");
1500      updateCartCount();
1501    }, 100);
1502  }
1503);
1504
1505function updateCartCount() {
1506  var ajaxUrl = wc_add_to_cart_params.wc_ajax_url
1507    .toString()
1508    .replace("%%endpoint%%", "get_refreshed_fragments");
1509
1510  jQuery.ajax({
1511    url: ajaxUrl,
1512    type: "POST",
1513    success: function (data) {
1514      if (data && data.fragments) {
1515        jQuery.each(data.fragments, function (key, value) {
1516          var $element = jQuery(key);
1517          if ($element.length > 0) {
1518            $element.replaceWith(value);
1519          }
1520        });
1521      }
1522    },
1523  });
1524}
1525
1526function updateWishlistCount() {
1527  if (typeof yith_wcwl_l10n !== "undefined") {
1528    jQuery.ajax({
1529      url: yith_wcwl_l10n.ajax_url,
1530      type: "POST",
1531      data: {
1532        action: "yith_wcwl_update_wishlist_count",
1533      },
1534      success: function (response) {
1535        if (response.count !== undefined) {
1536          var count = response.count;
1537          var $countElements = jQuery(".wishlist-count");
1538
1539          if (count > 0) {
1540            if ($countElements.length > 0) {
1541              $countElements.text(count);
1542            } else {
1543              jQuery(
1544                '.icon-link:has(.icon-img[src*="favorite.svg"]), .mobile-menu__shortcut:has(img[src*="favorite.svg"])'
1545              ).each(function () {
1546                jQuery(this).append(
1547                  '<span class="wishlist-count">' + count + "</span>"
1548                );
1549              });
1550            }
1551          } else {
1552            $countElements.remove();
1553          }
1554        }
1555      },
1556    });
1557  }
1558}
1559
1560function showToast(message, type = "success") {
1561  var toast = jQuery(
1562    '<div class="toast toast--' + type + '">' + message + "</div>"
1563  );
1564  jQuery("body").append(toast);
1565
1566  setTimeout(function () {
1567    toast.addClass("toast--show");
1568  }, 100);
1569
1570  setTimeout(function () {
1571    toast.removeClass("toast--show");
1572    setTimeout(function () {
1573      toast.remove();
1574    }, 300);
1575  }, 3000);
1576}
1577
1578jQuery(document).ready(function ($) {
1579  // Обновление счетчика избранного при загрузке страницы
1580  updateWishlistCount();
1581
1582  // Обработчики событий YITH Wishlist
1583  $(document).on("yith_wcwl_reload_fragments", function () {
1584    updateWishlistCount();
1585  });
1586
1587  $(document).on("added_to_wishlist", function () {
1588    updateWishlistCount();
1589  });
1590
1591  $(document).on("removed_from_wishlist", function () {
1592    updateWishlistCount();
1593  });
1594
1595  // Принудительная инициализация BeRocket фильтров
1596  if (typeof berocket_aapf_widget_ready !== "undefined") {
1597    setTimeout(function () {
1598      berocket_aapf_widget_ready();
1599    }, 100);
1600  }
1601
1602  if (typeof berocket_aapf_widget_ready_ajax !== "undefined") {
1603    setTimeout(function () {
1604      berocket_aapf_widget_ready_ajax();
1605    }, 100);
1606  }
1607
1608  // Обработка клика по кнопке фильтрации
1609  $(".products-catalog__filter").on("click", function () {
1610    $(".mobile-filters-overlay").attr("aria-hidden", "false");
1611    $("body").css("overflow", "hidden");
1612  });
1613
1614  // Закрытие мобильных фильтров
1615  $(".mobile-filters__back").on("click", function () {
1616    $(".mobile-filters-overlay").attr("aria-hidden", "true");
1617    $("body").css("overflow", "");
1618  });
1619
1620  // Закрытие при клике вне панели
1621  $(".mobile-filters-overlay").on("click", function (e) {
1622    if (e.target === this) {
1623      $(this).attr("aria-hidden", "true");
1624      $("body").css("overflow", "");
1625    }
1626  });
1627
1628  // Кнопка "Применить"
1629  $(".mobile-filters__apply").on("click", function () {
1630    $(".mobile-filters-overlay").attr("aria-hidden", "true");
1631    $("body").css("overflow", "");
1632    // Здесь можно добавить логику применения фильтров
1633  });
1634
1635  // Скрываем стандартный select сортировки
1636  $(".woocommerce-ordering").hide();
1637
1638  // Показываем select при клике на кнопку Сортировка
1639  $(".products-catalog__sort").on("click", function () {
1640    if (window.innerWidth <= 768) {
1641      // Мобильная версия - показываем попап снизу
1642      $(".products-catalog__sort-dropdown").addClass("active");
1643      $("body").addClass("no-scroll");
1644    } else {
1645      // Десктопная версия - показываем дропдаун
1646      $(".woocommerce-ordering").toggle();
1647    }
1648  });
1649
1650  // Закрытие мобильного попапа сортировки
1651  $(document).on("click", ".products-catalog__sort-dropdown", function (e) {
1652    if (e.target === this) {
1653      $(".products-catalog__sort-dropdown").removeClass("active");
1654      $("body").removeClass("no-scroll");
1655    }
1656  });
1657
1658  // Скрываем select при клике вне его (десктоп)
1659  $(document).on("click", function (e) {
1660    if (window.innerWidth > 768) {
1661      if (
1662        !$(e.target).closest(".products-catalog__sort, .woocommerce-ordering")
1663          .length
1664      ) {
1665        $(".woocommerce-ordering").hide();
1666      }
1667    }
1668  });
1669
1670  // BeRocket фильтры дропдауны (делегирование событий)
1671  $(document).on("click", ".bapf_head", function () {
1672    var $filter = $(this).closest(".bapf_sfilter");
1673    var $otherFilters = $(".bapf_sfilter").not($filter);
1674
1675    // Закрываем другие дропдауны
1676    $otherFilters.removeClass("active");
1677
1678    // Переключаем текущий дропдаун
1679    $filter.toggleClass("active");
1680  });
1681
1682  // Закрываем дропдауны при клике вне их
1683  $(document).on("click", function (e) {
1684    if (!$(e.target).closest(".bapf_sfilter").length) {
1685      $(".bapf_sfilter").removeClass("active");
1686    }
1687  });
1688
1689  // Плавная прокрутка для навигации
1690  const aboutNavLinks = document.querySelectorAll(".about-nav__link");
1691
1692  aboutNavLinks.forEach((link) => {
1693    link.addEventListener("click", (e) => {
1694      e.preventDefault();
1695
1696      const targetId = link.getAttribute("href").substring(1);
1697      const targetSection = document.getElementById(targetId);
1698
1699      if (targetSection) {
1700        targetSection.scrollIntoView({
1701          behavior: "smooth",
1702          block: "start",
1703        });
1704
1705        // Обновляем активную ссылку
1706        aboutNavLinks.forEach((l) => l.classList.remove("active"));
1707        link.classList.add("active");
1708      }
1709    });
1710  });
1711
1712  // Обновление активной ссылки при прокрутке
1713  const aboutSections = document.querySelectorAll(".about-section");
1714
1715  function updateActiveNavLink() {
1716    const scrollPosition = window.scrollY + 100;
1717
1718    aboutSections.forEach((section) => {
1719      const sectionTop = section.offsetTop;
1720      const sectionHeight = section.offsetHeight;
1721      const sectionId = section.id;
1722
1723      if (
1724        scrollPosition >= sectionTop &&
1725        scrollPosition < sectionTop + sectionHeight
1726      ) {
1727        aboutNavLinks.forEach((link) => {
1728          link.classList.remove("active");
1729          if (link.getAttribute("href") === "#" + sectionId) {
1730            link.classList.add("active");
1731          }
1732        });
1733      }
1734    });
1735  }
1736
1737  window.addEventListener("scroll", updateActiveNavLink);
1738
1739  // Слайдер сертификатов
1740  if (document.querySelector(".certificates-swiper")) {
1741    const certificatesSwiper = new Swiper(".certificates-swiper", {
1742      slidesPerView: 2.8,
1743      spaceBetween: 10,
1744
1745
1746      breakpoints: {
1747        768: {
1748          slidesPerView: 2,
1749          spaceBetween: 10,
1750        },
1751        1024: {
1752          slidesPerView: 1,
1753          spaceBetween: 10,
1754        },
1755      },
1756    });
1757  }
1758
1759  // Инициализация Swiper для видео
1760  if (document.querySelector(".video-slider")) {
1761    const videoSwiper = new Swiper(".video-slider", {
1762      slidesPerView: 1.2,
1763      spaceBetween: 20,
1764      navigation: {
1765        nextEl: ".video-btn-next",
1766        prevEl: ".video-btn-prev",
1767      },
1768      breakpoints: {
1769        768: {
1770          slidesPerView: 1,
1771        },
1772        1024: {
1773          slidesPerView: 3,
1774        },
1775      },
1776    });
1777  }
1778
1779  // Обработка клика по видео
1780  const videoItems = document.querySelectorAll(".video-item");
1781
1782  videoItems.forEach((item) => {
1783    item.addEventListener("click", () => {
1784      // Здесь можно добавить логику для открытия видео
1785    });
1786  });
1787
1788  // Обработка кнопки обратного звонка
1789  const callbackBtns = document.querySelectorAll(".callback-widget__btn");
1790
1791  callbackBtns.forEach((btn) => {
1792    btn.addEventListener("click", () => {
1793      // Здесь можно добавить логику для открытия формы обратного звонка
1794    });
1795  });
1796
1797  // Обработка кнопки "Развернуть" в секции "О нас"
1798  const aboutExpandBtn = document.querySelector(".about__expand-btn");
1799  const aboutText = document.querySelector(".about__text");
1800
1801  if (aboutExpandBtn && aboutText) {
1802    // Получаем оригинальный текст кнопки из data атрибута или из span
1803    const originalBtnText = aboutExpandBtn.querySelector("span").textContent;
1804    const expandedBtnText = "Свернуть";
1805
1806    aboutExpandBtn.addEventListener("click", function () {
1807      const isExpanded = aboutText.classList.contains("about__text--expanded");
1808      const btnText = this.querySelector("span");
1809      const btnIcon = this.querySelector("svg");
1810
1811      if (isExpanded) {
1812        // Сворачиваем
1813        aboutText.classList.remove("about__text--expanded");
1814        btnText.textContent = originalBtnText;
1815        btnIcon.style.transform = "rotate(0deg)";
1816      } else {
1817        // Разворачиваем
1818        aboutText.classList.add("about__text--expanded");
1819        btnText.textContent = expandedBtnText;
1820        btnIcon.style.transform = "rotate(180deg)";
1821      }
1822    });
1823  }
1824
1825  // Инициализация Fancybox для сертификатов
1826  if (typeof $.fn.fancybox !== "undefined") {
1827    $('[data-fancybox="certificates"]').fancybox({
1828      buttons: ["zoom", "slideShow", "fullScreen", "thumbs", "close"],
1829      animationEffect: "fade",
1830      transitionEffect: "slide",
1831      thumbs: {
1832        autoStart: true,
1833      },
1834      touch: {
1835        vertical: true,
1836        momentum: true,
1837      },
1838      beforeShow: function () {
1839        console.log("Fancybox beforeShow");
1840      },
1841      afterShow: function () {
1842        console.log("Fancybox afterShow");
1843      },
1844      beforeClose: function () {
1845        console.log("Fancybox beforeClose");
1846      },
1847      afterClose: function () {
1848        console.log("Fancybox afterClose");
1849        // Восстанавливаем карту после закрытия
1850        if (
1851          window.footerMap &&
1852          typeof window.footerMap.container !== "undefined"
1853        ) {
1854          setTimeout(function () {
1855            window.footerMap.container.fitToViewport();
1856          }, 100);
1857        }
1858      },
1859    });
1860  }
1861
1862  // Обработка клика по чекбоксу в order-form
1863  $(".order-form .wpcf7-acceptance").on("click", function (e) {
1864    const checkbox = $(this).find('input[type="checkbox"]');
1865
1866    if (checkbox.length) {
1867      const newState = !checkbox.prop("checked");
1868
1869      checkbox.prop("checked", newState);
1870
1871      // Принудительно обновляем стили
1872      const listItem = $(this).find(".wpcf7-list-item");
1873      if (newState) {
1874        listItem.addClass("checked");
1875      } else {
1876        listItem.removeClass("checked");
1877      }
1878
1879      checkbox.trigger("change");
1880    }
1881  });
1882
1883  // Дополнительная обработка для отладки
1884  $(document).on(
1885    "change",
1886    '.order-form input[type="checkbox"]',
1887    function () {}
1888  );
1889
1890  // Проверка загрузки элементов
1891  $(document).ready(function () {
1892    // Автоматически отмечаем чекбокс
1893    $('.order-form input[type="checkbox"]').each(function () {
1894      $(this).prop("checked", true);
1895      $(this)
1896        .closest(".wpcf7-acceptance")
1897        .find(".wpcf7-list-item")
1898        .addClass("checked");
1899      $(this).trigger("change");
1900    });
1901
1902    // Инициализация маски для телефона
1903    if (typeof $.fn.mask !== "undefined") {
1904      $('input[type="tel"], input[name="your-phone"]').mask(
1905        "+7 (000) 000-00-00",
1906        {
1907          placeholder: "+7 (___) ___-__-__",
1908        }
1909      );
1910    }
1911  });
1912
1913  // Инициализация слайдера для страницы "Производство"
1914  if (document.querySelector(".production-slider")) {
1915    const productionSwiper = new Swiper(".production-slider", {
1916      slidesPerView: 1,
1917      spaceBetween: 0,
1918      loop: true,
1919      autoplay: {
1920        delay: 5000,
1921        disableOnInteraction: false,
1922      },
1923      pagination: {
1924        el: ".swiper-pagination",
1925        clickable: true,
1926      },
1927      navigation: {
1928        nextEl: ".swiper-button-next",
1929        prevEl: ".swiper-button-prev",
1930      },
1931      effect: "fade",
1932      fadeEffect: {
1933        crossFade: true,
1934      },
1935      speed: 800,
1936    });
1937  }
1938
1939  // Галерея
1940  if (document.querySelector(".gallery-slider")) {
1941    const gallerySwiper = new Swiper(".gallery-slider", {
1942      slidesPerView: 1,
1943      spaceBetween: 0,
1944      loop: true,
1945      autoplay: {
1946        delay: 4000,
1947        disableOnInteraction: false,
1948      },
1949      navigation: {
1950        nextEl: ".gallery__btn--next",
1951        prevEl: ".gallery__btn--prev",
1952      },
1953      pagination: {
1954        el: ".gallery__dots",
1955        clickable: true,
1956      },
1957      effect: "fade",
1958      fadeEffect: {
1959        crossFade: true,
1960      },
1961      speed: 600,
1962    });
1963  }
1964
1965  // Купить в один клик
1966  document.addEventListener("click", function (e) {
1967    if (
1968      e.target.classList.contains("product-card__buy-btn") ||
1969      e.target.classList.contains("product-single__buy-btn")
1970    ) {
1971      e.preventDefault();
1972
1973      const productId = e.target.dataset.productId;
1974      let productName = "";
1975
1976      // Для карточки товара
1977      if (e.target.classList.contains("product-card__buy-btn")) {
1978        productName =
1979          e.target
1980            .closest(".product-card")
1981            .querySelector(".product-card__title")?.textContent || "";
1982      }
1983      // Для страницы товара
1984      else if (e.target.classList.contains("product-single__buy-btn")) {
1985        productName =
1986          document.querySelector(".product-info__title")?.textContent ||
1987          document.querySelector(".entry-title")?.textContent ||
1988          document.querySelector("h1")?.textContent ||
1989          "";
1990      }
1991
1992      // Открываем попап с формой
1993      if (typeof openPopup === "function") {
1994        openPopup("buy-one-click");
1995
1996        // Передаем данные о товаре в форму
1997        setTimeout(() => {
1998          const form = document.querySelector(
1999            ".popup-buy-one-click .wpcf7-form"
2000          );
2001          if (form) {
2002            const productIdField = form.querySelector(
2003              'input[name="product-id"]'
2004            );
2005            const productNameField = form.querySelector(
2006              'input[name="product-name"]'
2007            );
2008
2009            if (productIdField) {
2010              productIdField.value = productId;
2011            }
2012            if (productNameField) {
2013              productNameField.value = productName;
2014            }
2015          } else {
2016          }
2017        }, 100);
2018      }
2019    }
2020  });
2021
2022  // FAQ функциональность для главной страницы
2023  function initFAQ() {
2024    const faqTabs = document.querySelectorAll(".faq__tab");
2025    const faqQuestions = document.querySelectorAll(".faq__question");
2026
2027    // Проверяем, не инициализированы ли уже элементы
2028    if (faqTabs.length > 0 && faqTabs[0].hasAttribute("data-initialized")) {
2029      console.log("FAQ already initialized, skipping...");
2030      return;
2031    }
2032
2033    // Инициализация: скрываем все вопросы, кроме активного таба
2034    const activeTab = document.querySelector(".faq__tab--active");
2035    if (activeTab) {
2036      const activeTabName = activeTab.dataset.tab;
2037      faqQuestions.forEach((question) => {
2038        const questionTab = question.dataset.tab;
2039        if (questionTab === activeTabName) {
2040          question.style.display = "block";
2041        } else {
2042          question.style.display = "none";
2043        }
2044      });
2045    }
2046
2047    // Переключение FAQ табов
2048    if (faqTabs.length > 0) {
2049      faqTabs.forEach((btn) => {
2050        btn.addEventListener("click", (e) => {
2051          e.preventDefault();
2052          e.stopPropagation();
2053
2054          const tab = btn.dataset.tab;
2055
2056          // Убираем активный класс со всех кнопок
2057          faqTabs.forEach((b) => b.classList.remove("faq__tab--active"));
2058          // Добавляем активный класс к нажатой кнопке
2059          btn.classList.add("faq__tab--active");
2060
2061          // Показываем/скрываем вопросы в зависимости от таба
2062          faqQuestions.forEach((question) => {
2063            const questionTab = question.dataset.tab;
2064            if (questionTab === tab) {
2065              question.style.display = "block";
2066            } else {
2067              question.style.display = "none";
2068              // Закрываем вопросы неактивных табов
2069              question.classList.remove("faq__question--active");
2070            }
2071          });
2072
2073          // Показываем первый активный вопрос нового таба
2074          const firstActiveQuestionOfTab = document.querySelector(
2075            `.faq__question[data-tab="${tab}"].faq__question--active`
2076          );
2077          if (firstActiveQuestionOfTab) {
2078            // Оставляем первый активный вопрос открытым
2079          } else {
2080            // Если нет активных вопросов, открываем первый
2081            const firstQuestionOfTab = document.querySelector(
2082              `.faq__question[data-tab="${tab}"]`
2083            );
2084            if (firstQuestionOfTab) {
2085              firstQuestionOfTab.classList.add("faq__question--active");
2086            }
2087          }
2088        });
2089      });
2090    }
2091
2092    // FAQ аккордеон
2093    if (faqQuestions.length > 0) {
2094      faqQuestions.forEach((item) => {
2095        const btn = item.querySelector(".faq__question-btn");
2096
2097        if (!btn) return;
2098
2099        const toggleItem = (e) => {
2100          e.preventDefault();
2101          e.stopPropagation();
2102
2103          const isActive = item.classList.contains("faq__question--active");
2104
2105          // Закрываем все остальные элементы в том же табе
2106          const currentTab = item.dataset.tab;
2107          const questionsInSameTab = document.querySelectorAll(
2108            `.faq__question[data-tab="${currentTab}"]`
2109          );
2110          questionsInSameTab.forEach((otherItem) => {
2111            if (otherItem !== item) {
2112              otherItem.classList.remove("faq__question--active");
2113            }
2114          });
2115
2116          // Переключаем текущий элемент
2117          if (isActive) {
2118            item.classList.remove("faq__question--active");
2119          } else {
2120            item.classList.add("faq__question--active");
2121          }
2122        };
2123
2124        btn.addEventListener("click", toggleItem);
2125      });
2126    }
2127  }
2128
2129  // FAQ функциональность для страницы FAQ
2130  function initFAQPage() {
2131    const faqNavBtns = document.querySelectorAll(".faq-nav__btn");
2132    const faqCategories = document.querySelectorAll(".faq-category");
2133    const faqItems = document.querySelectorAll(".faq-item");
2134
2135    console.log("FAQ Page Init - Found elements:", {
2136      navBtns: faqNavBtns.length,
2137      categories: faqCategories.length,
2138      items: faqItems.length,
2139    });
2140
2141    // Переключение FAQ категорий (табов)
2142    if (faqNavBtns.length > 0) {
2143      faqNavBtns.forEach((btn) => {
2144        btn.addEventListener("click", function () {
2145          const category = this.getAttribute("data-category");
2146          console.log("FAQ Tab clicked:", category);
2147
2148          // Убираем активный класс у всех кнопок
2149          faqNavBtns.forEach((b) => b.classList.remove("faq-nav__btn--active"));
2150
2151          // Добавляем активный класс к текущей кнопке
2152          btn.classList.add("faq-nav__btn--active");
2153
2154          // Скрываем все категории
2155          faqCategories.forEach((category) => {
2156            category.classList.remove("faq-category--active");
2157          });
2158
2159          // Показываем выбранную категорию
2160          const activeCategory = document.querySelector(
2161            `.faq-category[data-category="${category}"]`
2162          );
2163
2164          if (activeCategory) {
2165            activeCategory.classList.add("faq-category--active");
2166          }
2167        });
2168      });
2169    }
2170
2171    // FAQ аккордеон
2172    if (faqItems.length > 0) {
2173      faqItems.forEach((item, index) => {
2174        const toggleBtn = item.querySelector(".faq-item__toggle");
2175        const header = item.querySelector(".faq-item__header");
2176
2177        console.log(`FAQ Item ${index}:`, {
2178          hasToggleBtn: !!toggleBtn,
2179          hasHeader: !!header,
2180        });
2181
2182        // Добавляем обработчик на кнопку
2183        if (toggleBtn) {
2184          toggleBtn.addEventListener("click", function (e) {
2185            e.preventDefault();
2186            e.stopPropagation();
2187            console.log("FAQ Toggle clicked for item:", index);
2188
2189            const isActive = item.classList.contains("faq-item--active");
2190
2191            // Закрываем все другие вопросы
2192            faqItems.forEach((otherItem) => {
2193              if (otherItem !== item) {
2194                otherItem.classList.remove("faq-item--active");
2195              }
2196            });
2197
2198            // Переключаем текущий вопрос
2199            if (isActive) {
2200              item.classList.remove("faq-item--active");
2201            } else {
2202              item.classList.add("faq-item--active");
2203            }
2204          });
2205        }
2206
2207        // Добавляем обработчик на заголовок
2208        if (header) {
2209          header.addEventListener("click", function (e) {
2210            e.preventDefault();
2211            e.stopPropagation();
2212            console.log("FAQ Header clicked for item:", index);
2213
2214            const isActive = item.classList.contains("faq-item--active");
2215
2216            // Закрываем все другие вопросы
2217            faqItems.forEach((otherItem) => {
2218              if (otherItem !== item) {
2219                otherItem.classList.remove("faq-item--active");
2220              }
2221            });
2222
2223            // Переключаем текущий вопрос
2224            if (isActive) {
2225              item.classList.remove("faq-item--active");
2226            } else {
2227              item.classList.add("faq-item--active");
2228            }
2229          });
2230        }
2231      });
2232    }
2233  }
2234
2235  // Мобильная навигация для страниц
2236  const mobileNavToggle = document.getElementById("mobileNavToggle");
2237  const mobileNavOverlay = document.getElementById("mobileNavOverlay");
2238  const mobileNavClose = document.getElementById("mobileNavClose");
2239  const mobileNavLinks = document.querySelectorAll(".mobile-nav__link");
2240
2241  if (mobileNavToggle && mobileNavOverlay) {
2242    // Открытие мобильной навигации
2243    mobileNavToggle.addEventListener("click", () => {
2244      mobileNavToggle.classList.add("active");
2245      mobileNavOverlay.style.display = "block";
2246      setTimeout(() => {
2247        mobileNavOverlay.classList.add("active");
2248      }, 10);
2249      document.body.style.overflow = "hidden";
2250    });
2251
2252    // Закрытие мобильной навигации
2253    const closeMobileNav = () => {
2254      mobileNavToggle.classList.remove("active");
2255      mobileNavOverlay.classList.remove("active");
2256      setTimeout(() => {
2257        mobileNavOverlay.style.display = "none";
2258      }, 300);
2259      document.body.style.overflow = "";
2260    };
2261
2262    if (mobileNavClose) {
2263      mobileNavClose.addEventListener("click", closeMobileNav);
2264    }
2265
2266    // Закрытие при клике на оверлей
2267    mobileNavOverlay.addEventListener("click", (e) => {
2268      if (e.target === mobileNavOverlay) {
2269        closeMobileNav();
2270      }
2271    });
2272
2273    // Закрытие при клике на ссылку
2274    mobileNavLinks.forEach((link) => {
2275      link.addEventListener("click", () => {
2276        closeMobileNav();
2277      });
2278    });
2279
2280    // Закрытие при нажатии Escape
2281    document.addEventListener("keydown", (e) => {
2282      if (e.key === "Escape" && mobileNavOverlay.classList.contains("active")) {
2283        closeMobileNav();
2284      }
2285    });
2286  }
2287
2288  // About Certificates Swiper
2289  if (document.querySelector(".about-certificates-swiper")) {
2290    const aboutCertificatesSwiper = new Swiper(".about-certificates-swiper", {
2291      slidesPerView: 1.2,
2292      spaceBetween: 5,
2293      effect: "coverflow",
2294      grabCursor: true,
2295      centeredSlides: true,
2296      coverflowEffect: {
2297        rotate: 0,
2298        stretch: 0,
2299        depth: 100,
2300        modifier: 2,
2301        slideShadows: true,
2302      },
2303      navigation: {
2304        nextEl: ".certificates-btn-next",
2305        prevEl: ".certificates-btn-prev",
2306      },
2307      breakpoints: {
2308        480: {
2309          slidesPerView: 1.2,
2310          spaceBetween: 5,
2311          effect: "coverflow",
2312          centeredSlides: true,
2313        },
2314        768: {
2315          slidesPerView: 2,
2316          spaceBetween: 30,
2317          effect: "slide",
2318          centeredSlides: false,
2319        },
2320        1920: {
2321          slidesPerView: 3,
2322          spaceBetween: 40,
2323          effect: "slide",
2324          centeredSlides: false,
2325        },
2326      },
2327    });
2328  }
2329
2330  // Запускаем инициализацию FAQ
2331  let faqInitialized = false;
2332  let faqPageInitialized = false;
2333
2334  function initializeFAQOnce() {
2335    if (!faqInitialized) {
2336      initFAQ();
2337      faqInitialized = true;
2338    }
2339  }
2340
2341  function initializeFAQPageOnce() {
2342    if (!faqPageInitialized) {
2343      initFAQPage();
2344      faqPageInitialized = true;
2345    }
2346  }
2347
2348  // Инициализируем FAQ для главной страницы
2349  initializeFAQOnce();
2350
2351  // Инициализируем FAQ для страницы FAQ
2352  initializeFAQPageOnce();
2353
2354  // Дополнительная инициализация при загрузке DOM
2355  document.addEventListener("DOMContentLoaded", function () {
2356    console.log("DOM Content Loaded - Re-initializing FAQ Page");
2357    initializeFAQPageOnce();
2358  });
2359
2360  // Глобальная функция для переключения FAQ элементов
2361  window.toggleFAQItem = function (header) {
2362    const item = header.closest(".faq-item");
2363    if (!item) return;
2364
2365    console.log("Global toggleFAQItem called for:", item);
2366
2367    const isActive = item.classList.contains("faq-item--active");
2368
2369    // Закрываем все другие вопросы
2370    const allItems = document.querySelectorAll(".faq-item");
2371    allItems.forEach((otherItem) => {
2372      if (otherItem !== item) {
2373        otherItem.classList.remove("faq-item--active");
2374      }
2375    });
2376
2377    // Переключаем текущий вопрос
2378    if (isActive) {
2379      item.classList.remove("faq-item--active");
2380    } else {
2381      item.classList.add("faq-item--active");
2382    }
2383  };
2384
2385  // Рейтинг звездами
2386  $(document).on("click", ".stars a", function (e) {
2387    e.preventDefault();
2388    var rating = $(this).attr("class").replace("star-", "");
2389
2390    // Обновляем активные звезды
2391    $(".stars a").removeClass("active");
2392    $(".stars a").each(function (index) {
2393      if (index < rating) {
2394        $(this).addClass("active");
2395      }
2396    });
2397
2398    // Устанавливаем значение в скрытый select
2399    $("#rating").val(rating);
2400  });
2401
2402  // Hover эффект для звезд
2403  $(document).on("mouseenter", ".stars a", function () {
2404    var rating = $(this).attr("class").replace("star-", "");
2405    $(".stars a").removeClass("hover");
2406    $(".stars a").each(function (index) {
2407      if (index < rating) {
2408        $(this).addClass("hover");
2409      }
2410    });
2411  });
2412
2413  $(document).on("mouseleave", ".stars", function () {
2414    $(".stars a").removeClass("hover");
2415  });
2416
2417  // Раскрывающиеся блоки в футере для мобильной версии
2418  const footerColumnToggles = document.querySelectorAll(
2419    ".footer__column-toggle"
2420  );
2421
2422  footerColumnToggles.forEach((toggle) => {
2423    toggle.addEventListener("click", function () {
2424      const column = this.closest(".footer__column");
2425      const isActive = column.classList.contains("active");
2426
2427      // Закрываем все другие колонки
2428      document.querySelectorAll(".footer__column").forEach((col) => {
2429        col.classList.remove("active");
2430      });
2431
2432      // Открываем текущую колонку если она была закрыта
2433      if (!isActive) {
2434        column.classList.add("active");
2435      }
2436    });
2437  });
2438
2439  // Оверлей для вариаций товара
2440  let overlayObserver = null;
2441  let overlayInitialized = false;
2442  
2443  function initVariationOverlay() {
2444    if (overlayInitialized) {
2445      console.log('Оверлей уже инициализирован, пропускаем...');
2446      return;
2447    }
2448    
2449    console.log('Инициализация оверлея вариаций...');
2450    
2451    // Удаляем предыдущий observer если есть
2452    if (overlayObserver) {
2453      overlayObserver.disconnect();
2454    }
2455    
2456    // Наблюдаем за изменениями класса active
2457    overlayObserver = new MutationObserver(function(mutations) {
2458      mutations.forEach(function(mutation) {
2459        if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
2460          const target = mutation.target;
2461          if (target.classList.contains('active') && target.classList.contains('variable-items-wrapper')) {
2462            console.log('Найден активный wrapper:', target);
2463            const tr = target.closest('tr');
2464            if (tr) {
2465              const label = tr.querySelector('.label label');
2466              if (label) {
2467                const attributeLabel = label.textContent;
2468                showVariationOverlay(attributeLabel, target);
2469              }
2470            }
2471          }
2472        }
2473      });
2474    });
2475    
2476    // Наблюдаем за всеми wrapper'ами
2477    const wrappers = document.querySelectorAll('.variable-items-wrapper');
2478    console.log('Найдено wrapper\'ов:', wrappers.length);
2479    
2480    wrappers.forEach((wrapper, index) => {
2481      console.log(`Наблюдение за wrapper ${index + 1}:`, wrapper);
2482      overlayObserver.observe(wrapper, { attributes: true, attributeFilter: ['class'] });
2483      
2484      // Проверяем, есть ли уже класс active
2485      if (wrapper.classList.contains('active')) {
2486        console.log('Wrapper уже активен:', wrapper);
2487        const tr = wrapper.closest('tr');
2488        if (tr) {
2489          const label = tr.querySelector('.label label');
2490          if (label) {
2491            const attributeLabel = label.textContent;
2492            showVariationOverlay(attributeLabel, wrapper);
2493          }
2494        }
2495      }
2496    });
2497    
2498    overlayInitialized = true;
2499    console.log('Оверлей инициализирован успешно');
2500  }
2501
2502  function showVariationOverlay(attributeLabel, wrapper) {
2503    // Проверяем, нет ли уже открытого оверлея
2504    if (document.querySelector('.variation-overlay')) {
2505      console.log('Оверлей уже открыт, пропускаем');
2506      return;
2507    }
2508    
2509    // Проверяем, не закрывался ли оверлей недавно (защита от двойного клика)
2510    if (wrapper.dataset.overlayJustClosed) {
2511      console.log('Оверлей только что закрылся, пропускаем');
2512      return;
2513    }
2514    
2515    console.log('Создание оверлея для:', attributeLabel);
2516    const overlay = document.createElement('div');
2517    overlay.className = 'variation-overlay';
2518    overlay.innerHTML = `
2519      <div class="variation-overlay-content">
2520        <button class="variation-overlay-close">&times;</button>
2521        <h3 class="variation-overlay-title">Выберите ${attributeLabel}</h3>
2522        <div class="variation-overlay-variations"></div>
2523      </div>
2524    `;
2525    
2526    const variationsContainer = overlay.querySelector('.variation-overlay-variations');
2527    const clonedWrapper = wrapper.cloneNode(true);
2528    console.log('Клонированный wrapper:', clonedWrapper);
2529    variationsContainer.appendChild(clonedWrapper);
2530    
2531    document.body.appendChild(overlay);
2532    console.log('Оверлей добавлен в DOM');
2533    
2534    setTimeout(() => {
2535      overlay.classList.add('active');
2536      console.log('Оверлей активирован');
2537    }, 10);
2538    
2539    const closeBtn = overlay.querySelector('.variation-overlay-close');
2540    
2541    function closeOverlay() {
2542      overlay.classList.remove('active');
2543      
2544      // Устанавливаем флаг о закрытии оверлея
2545      wrapper.dataset.overlayJustClosed = 'true';
2546      setTimeout(() => {
2547        delete wrapper.dataset.overlayJustClosed;
2548      }, 500);
2549      
2550      setTimeout(() => {
2551        if (document.body.contains(overlay)) {
2552          document.body.removeChild(overlay);
2553        }
2554      }, 300);
2555    }
2556    
2557    closeBtn.addEventListener('click', closeOverlay);
2558    
2559    overlay.addEventListener('click', function(e) {
2560      if (e.target === overlay) {
2561        closeOverlay();
2562      }
2563    });
2564    
2565    document.addEventListener('keydown', function closeOnEscape(e) {
2566      if (e.key === 'Escape') {
2567        closeOverlay();
2568        document.removeEventListener('keydown', closeOnEscape);
2569      }
2570    });
2571    
2572    // Используем делегирование событий для более надежной работы
2573    clonedWrapper.addEventListener('click', function(e) {
2574      const item = e.target.closest('.variable-item');
2575      if (!item) {
2576        console.log('Клик не по элементу вариации');
2577        return;
2578      }
2579      
2580      e.preventDefault();
2581      e.stopPropagation();
2582      console.log('Клик по клонированному элементу:', item);
2583      
2584      const value = item.getAttribute('data-value');
2585      console.log('Значение элемента:', value);
2586      
2587      if (value) {
2588        // Ищем оригинальный элемент по data-value
2589        const originalItem = wrapper.querySelector(`[data-value="${value}"]`);
2590        console.log('Найден оригинальный элемент:', originalItem);
2591        
2592        if (originalItem) {
2593          console.log('Триггерим клик по оригинальному элементу');
2594          
2595          // Просто триггерим клик по оригинальному элементу
2596          // Это позволит оригинальному скрипту WooCommerce обработать выбор
2597          originalItem.click();
2598          
2599          console.log('Закрытие оверлея');
2600          closeOverlay();
2601        } else {
2602          console.log('Оригинальный элемент не найден!');
2603        }
2604      } else {
2605        console.log('Значение data-value не найдено!');
2606      }
2607    });
2608    
2609    // Добавляем стили для кликабельности всем элементам
2610    const clonedItems = clonedWrapper.querySelectorAll('.variable-item');
2611    console.log('Клонированные элементы:', clonedItems.length);
2612    
2613    clonedItems.forEach((item, index) => {
2614      console.log(`Обработка клонированного элемента ${index + 1}:`, item);
2615      item.style.cursor = 'pointer';
2616      item.style.pointerEvents = 'auto';
2617    });
2618  }
2619
2620  // Инициализация после загрузки DOM
2621  document.addEventListener('DOMContentLoaded', function() {
2622    console.log('DOM загружен, инициализация оверлея...');
2623    initVariationOverlay();
2624  });
2625
2626  // Повторная инициализация для динамически загруженного контента
2627  setTimeout(() => {
2628    console.log('Повторная инициализация оверлея через 1 секунду...');
2629    initVariationOverlay();
2630  }, 1000);
2631
2632  // Дополнительная инициализация через 3 секунды
2633  setTimeout(() => {
2634    console.log('Дополнительная инициализация оверлея через 3 секунды...');
2635    initVariationOverlay();
2636  }, 3000);
2637});
2638
2639
2640document.querySelector('.open_cities_popup').addEventListener('click', function(e) {
2641    e.preventDefault();
2642    document.querySelector('a.geolocation__link').click();
2643});
2644
2645
2646jQuery(document).ready(function() {
2647
2648    function scrollToCity(targetId) {
2649        var target = jQuery('#id-' + targetId);
2650
2651        if (!target.length) return;
2652
2653        var windowWidth = jQuery(window).width();
2654        var headerHeight = windowWidth <= 767 ? 60 : 120;
2655        var offset = 20;
2656
2657        jQuery('html, body').animate({
2658            scrollTop: target.offset().top - headerHeight - offset
2659        }, 800);
2660    }
2661
2662    // Клик по ссылке на странице контактов
2663    jQuery('.city-anchor a').on('click', function(e) {
2664        var cityId = jQuery(this).data('city');
2665
2666        if (cityId) {
2667            e.preventDefault();
2668            scrollToCity(cityId);
2669        }
2670    });
2671
2672    // Обработка GET-параметра city (переход с FAQ)
2673    var urlParams = new URLSearchParams(window.location.search);
2674    var cityId = urlParams.get('city');
2675
2676    if (cityId) {
2677        setTimeout(function() {
2678            scrollToCity(cityId);
2679        }, 300);
2680    }
2681});
2682
2683// автозаполнение города в формах
2684document.addEventListener('DOMContentLoaded', function() {
2685  const buttons = document.querySelectorAll('.btn');
2686
2687  buttons.forEach(function(btn) {
2688    btn.addEventListener('click', function() {
2689      const citySpan = document.querySelector('.geolocation__value');
2690      if (!citySpan) return;
2691
2692      const city = citySpan.textContent.trim();
2693      if (city === 'Определение...' || city === '') return;
2694
2695      document.querySelectorAll('.your-city-auto').forEach(function(input) {
2696        input.value = city;
2697      });
2698    });
2699  });
2700});
2701
2702document.addEventListener('DOMContentLoaded', function() {
2703  document.querySelectorAll('.popup__form').forEach(function(form) {
2704    const submitBtns = form.querySelectorAll('.popup__submit');
2705    if (submitBtns.length < 2) return;
2706
2707    const first = submitBtns[0];
2708    const second = submitBtns[1];
2709
2710    // Клик по второй → имитация клика по первой
2711    second.addEventListener('click', function(e) {
2712      e.preventDefault();
2713      first.click();
2714    });
2715
2716    // Синхронизация состояния
2717    new MutationObserver(function() {
2718      second.disabled = first.disabled;
2719      second.classList.toggle('popup__submit--disabled', first.classList.contains('popup__submit--disabled'));
2720    }).observe(first, { attributes: true, attributeFilter: ['disabled', 'class'] });
2721
2722    second.disabled = first.disabled;
2723    second.classList.toggle('popup__submit--disabled', first.classList.contains('popup__submit--disabled'));
2724  });
2725});

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.