// Analytics load only after consent: Metrika, GTM and direct GA4. // GA4 is configured here; do not configure the same GA4 tag/events again in GTM. (function() { const key = 'olyapka_analytics_v2'; const banner = document.getElementById('cookieBanner'); let choice = null; try { choice = localStorage.getItem(key); } catch (err) { /* storage may be blocked */ } window.analyticsAllowed = choice === 'accepted'; function loadAnalytics() { if (!window.analyticsAllowed || window.analyticsLoaded) return; window.analyticsLoaded = true; window.ym = window.ym || function() { (window.ym.a = window.ym.a || []).push(arguments); }; window.ym.l = Date.now(); const metrika = document.createElement('script'); metrika.async = true; metrika.src = 'https://mc.yandex.ru/metrika/tag.js'; document.head.append(metrika); window.ym(110606131, 'init', {clickmap: true, trackLinks: true, accurateTrackBounce: true, webvisor: true}); window.dataLayer = window.dataLayer || []; window.gtag = window.gtag || function() { window.dataLayer.push(arguments); }; window.gtag('js', new Date()); window.gtag('config', 'G-T6084CKB81'); const ga = document.createElement('script'); ga.async = true; ga.src = 'https://www.googletagmanager.com/gtag/js?id=G-T6084CKB81'; document.head.append(ga); window.dataLayer.push({'gtm.start': Date.now(), event: 'gtm.js'}); const gtm = document.createElement('script'); gtm.async = true; gtm.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-M5HGH586'; document.head.append(gtm); } function choose(value) { const wasAllowed = window.analyticsAllowed; try { localStorage.setItem(key, value); } catch (err) { /* session-only choice */ } window.analyticsAllowed = value === 'accepted'; banner.hidden = true; banner.classList.remove('show'); if (wasAllowed && !window.analyticsAllowed) { location.reload(); return; } loadAnalytics(); } if (banner) { if (!choice) { banner.hidden = false; banner.classList.add('show'); } document.getElementById('cookieAccept').addEventListener('click', () => choose('accepted')); document.getElementById('cookieDecline').addEventListener('click', () => choose('declined')); document.getElementById('cookieSettings').addEventListener('click', () => { banner.hidden = false; banner.classList.add('show'); document.getElementById('cookieAccept').focus(); }); } loadAnalytics(); })(); // Accessible mobile navigation, including Escape and focus return. (function() { const burger = document.getElementById('burger'); const nav = document.getElementById('nav'); if (!burger || !nav) return; document.documentElement.classList.add('js-menu'); function setOpen(open) { burger.classList.toggle('open', open); nav.classList.toggle('open', open); burger.setAttribute('aria-expanded', String(open)); burger.setAttribute('aria-label', open ? 'Закрыть меню' : 'Открыть меню'); } burger.addEventListener('click', () => setOpen(burger.getAttribute('aria-expanded') !== 'true')); nav.addEventListener('click', e => { if (e.target.closest('a')) setOpen(false); }); document.addEventListener('keydown', e => { if (e.key === 'Escape' && nav.classList.contains('open')) { setOpen(false); burger.focus(); } }); document.addEventListener('click', e => { if (!nav.contains(e.target) && !burger.contains(e.target)) setOpen(false); }); matchMedia('(max-width: 768px)').addEventListener('change', () => setOpen(false)); })(); // ===== Goal Tracking (Yandex.Metrika + GA) ===== (function() { document.addEventListener('click', function(e) { const target = e.target.closest('[data-goal]'); if (!target) return; const goal = target.getAttribute('data-goal'); if (!goal) return; // Yandex.Metrika if (window.analyticsAllowed && typeof ym !== 'undefined') { try { ym(110606131, 'reachGoal', goal); } catch(err) {} } // Send existing button goals directly to GA4. if (window.analyticsAllowed && typeof window.gtag === 'function') { window.gtag('event', goal, {send_to: 'G-T6084CKB81'}); } // Keep custom events available to the existing GTM container. if (window.analyticsAllowed && window.dataLayer) window.dataLayer.push({event: goal}); }); })(); // Native anchor navigation preserves URL fragments and keyboard focus. // ===== Portfolio Video Lightbox ===== (function() { const modal = document.getElementById('videoModal'); const player = document.getElementById('videoModalPlayer'); const title = document.getElementById('videoModalTitle'); const fsBtn = document.getElementById('videoModalFullscreen'); const triggers = document.querySelectorAll('.work-video[data-video]'); if (!modal || !player || !triggers.length) return; let lastFocus = null; const background = Array.from(document.body.children).filter(el => el !== modal && el.tagName !== 'SCRIPT'); let inertStates = []; modal.setAttribute('inert', ''); function open(src, label) { lastFocus = document.activeElement; modal.removeAttribute('inert'); inertStates = background.map(el => el.inert); background.forEach(el => { el.inert = true; }); title.textContent = label || ''; player.src = src; modal.classList.add('open'); modal.setAttribute('aria-hidden', 'false'); document.body.classList.add('video-modal-open'); const p = player.play(); if (p && typeof p.catch === 'function') p.catch(() => {}); player.focus({ preventScroll: true }); } function close() { if (document.fullscreenElement) { document.exitFullscreen().catch(() => {}); } player.pause(); modal.classList.remove('open'); modal.setAttribute('aria-hidden', 'true'); modal.setAttribute('inert', ''); background.forEach((el, i) => { el.inert = inertStates[i]; }); document.body.classList.remove('video-modal-open'); setTimeout(() => { if (!modal.classList.contains('open')) { player.removeAttribute('src'); player.load(); } }, 300); if (lastFocus && typeof lastFocus.focus === 'function') lastFocus.focus({ preventScroll: true }); } function toggleFullscreen() { if (document.fullscreenElement) { document.exitFullscreen().catch(() => {}); return; } if (player.requestFullscreen) { player.requestFullscreen().catch(() => {}); } else if (player.webkitEnterFullscreen) { player.webkitEnterFullscreen(); // iOS Safari } } triggers.forEach(btn => { btn.addEventListener('click', function(e) { e.preventDefault(); open(btn.getAttribute('data-video'), btn.getAttribute('data-title')); }); }); modal.querySelectorAll('[data-video-close]').forEach(el => { el.addEventListener('click', close); }); // Клик по тёмной области вокруг плеера тоже закрывает окно modal.querySelectorAll('.video-modal-dialog, .video-modal-stage, .video-modal-bar').forEach(el => { el.addEventListener('click', function(e) { if (e.target === el) close(); }); }); if (fsBtn) fsBtn.addEventListener('click', toggleFullscreen); player.addEventListener('dblclick', toggleFullscreen); document.addEventListener('keydown', function(e) { if (!modal.classList.contains('open')) return; if (e.key === 'Escape') { close(); return; } if (e.key === 'Tab') { const stops = Array.from(modal.querySelectorAll('button, video[controls]')); const first = stops[0], last = stops[stops.length - 1]; if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); } } if (e.key === ' ' && document.activeElement === player) return; // native handling if ((e.key === 'f' || e.key === 'F') && document.activeElement === player) toggleFullscreen(); }); })();