1(function () { 2 'use strict'; 3 4 var reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; 5 6 document.addEventListener('DOMContentLoaded', function () { 7 8 /* ---- Scroll progress bar ------------------------------------- */ 9 var bar = document.createElement('div'); 10 bar.className = 'vargo-progress'; 11 document.body.appendChild(bar); 12 var onProgress = function () { 13 var d = document.documentElement; 14 var max = d.scrollHeight - d.clientHeight; 15 bar.style.transform = 'scaleX(' + (max > 0 ? d.scrollTop / max : 0) + ')'; 16 }; 17 onProgress(); 18 window.addEventListener('scroll', onProgress, { passive: true }); 19 20 /* ---- Mobile drawer ----------------------------------------- */ 21 var menuTrigger = document.getElementById('vargo-menu-trigger'); 22 var menuOverlay = document.getElementById('vargo-menu-overlay'); 23 var menuClose = document.getElementById('vargo-menu-close'); 24 var menuBackdrop = document.getElementById('vargo-menu-backdrop'); 25 function openMenu() { 26 menuOverlay.hidden = false; 27 if (menuBackdrop) menuBackdrop.hidden = false; 28 requestAnimationFrame(function () { 29 menuOverlay.classList.add('is-open'); 30 if (menuBackdrop) menuBackdrop.classList.add('is-open'); 31 }); 32 menuTrigger.setAttribute('aria-expanded', 'true'); 33 document.body.classList.add('vargo-menu-is-open'); 34 } 35 function closeMenu() { 36 menuOverlay.classList.remove('is-open'); 37 if (menuBackdrop) menuBackdrop.classList.remove('is-open'); 38 menuTrigger.setAttribute('aria-expanded', 'false'); 39 document.body.classList.remove('vargo-menu-is-open'); 40 setTimeout(function () { 41 menuOverlay.hidden = true; 42 if (menuBackdrop) menuBackdrop.hidden = true; 43 }, 400); 44 } 45 if (menuTrigger && menuOverlay) { 46 menuTrigger.addEventListener('click', function () { 47 menuOverlay.classList.contains('is-open') ? closeMenu() : openMenu(); 48 }); 49 if (menuClose) menuClose.addEventListener('click', closeMenu); 50 if (menuBackdrop) menuBackdrop.addEventListener('click', closeMenu); 51 menuOverlay.querySelectorAll('.vargo-menu-overlay__list a').forEach(function (l) { 52 l.addEventListener('click', closeMenu); 53 }); 54 document.addEventListener('keydown', function (e) { 55 if (e.key === 'Escape' && menuOverlay.classList.contains('is-open')) closeMenu(); 56 }); 57 } 58 59 /* ---- Header shadow on scroll ------------------------------ */ 60 var header = document.getElementById('masthead'); 61 if (header) { 62 var hs = function () { header.classList.toggle('is-scrolled', window.scrollY > 12); }; 63 hs(); 64 window.addEventListener('scroll', hs, { passive: true }); 65 } 66 67 /* ---- Chat triggers -------------------------------------- */ 68 document.addEventListener('click', function (e) { 69 var t = e.target && e.target.closest && e.target.closest('.vargo-open-chat, #vargo-open-chat-btn'); 70 if (!t) return; 71 var homeChat = document.getElementById('vargo-agent-chat'); 72 if (homeChat) { 73 e.preventDefault(); 74 homeChat.scrollIntoView({ behavior: 'smooth', block: 'center' }); 75 if (window.vargoAgentFocusChat) setTimeout(window.vargoAgentFocusChat, 350); 76 } else if (window.vargoAgentOpen) { 77 e.preventDefault(); 78 window.vargoAgentOpen(); 79 } 80 }); 81 82 /* ---- Anchor scrolling with sticky-header offset -------- 83 Works for same-page links AND for landing on /page/#section 84 from another page (menu items). scrollIntoView / native hash 85 jumps ignore the sticky header, so we compute the offset. */ 86 var headerEl = document.getElementById('masthead'); 87 var scrollToEl = function (el, smooth) { 88 if (!el) return; 89 var offset = (headerEl ? headerEl.getBoundingClientRect().height : 72) + 18; 90 var y = el.getBoundingClientRect().top + window.pageYOffset - offset; 91 window.scrollTo({ top: Math.max(0, y), behavior: smooth ? 'smooth' : 'auto' }); 92 }; 93 var elForHash = function (hash) { 94 if (!hash || hash.length < 2) return null; 95 try { return document.querySelector(hash); } catch (e) { return null; } 96 }; 97 98 // After clicking an item inside a hover mega-menu, force it closed 99 // (otherwise, since we preventDefault the navigation, the pointer is 100 // still over it / focus is retained and it stays open on the same page). 101 var dismissDropdown = function (link) { 102 var item = link.closest('.vargo-nav__item'); 103 if (!item) return; 104 item.classList.add('is-dismissed'); 105 try { link.blur(); } catch (e) {} 106 if (document.activeElement && document.activeElement.blur) document.activeElement.blur(); 107 var reopen = function () { item.classList.remove('is-dismissed');
107 item.removeEventListener('mouseleave', reopen); }; 108 item.addEventListener('mouseleave', reopen); 109 setTimeout(reopen, 2500); 110 }; 111 112 document.querySelectorAll('a[href*="#"]').forEach(function (link) { 113 link.addEventListener('click', function (e) { 114 var raw = link.getAttribute('href') || ''; 115 if (raw.indexOf('#') === -1) return; 116 var u; 117 try { u = new URL(raw, location.href); } catch (err) { return; } 118 var hash = u.hash; 119 if (!hash || hash === '#') return; 120 var inDropdown = !!link.closest('.vargo-dropdown'); 121 // same page only when origin + path match exactly 122 var samePage = u.origin === location.origin && u.pathname === location.pathname; 123 if (!samePage) { 124 if (inDropdown) dismissDropdown(link); // will close on navigate anyway; harmless 125 return; 126 } 127 // Tab links: let the tabs' own hashchange handler switch + scroll. 128 if (/^#tab-/.test(hash)) { 129 e.preventDefault(); 130 if (location.hash === hash) { 131 window.dispatchEvent(new Event('hashchange')); 132 } else { 133 location.hash = hash; 134 } 135 if (inDropdown) dismissDropdown(link); 136 return; 137 } 138 var el = elForHash(hash); 139 if (el) { 140 e.preventDefault(); 141 if (history.replaceState) { history.replaceState(null, '', hash); } 142 scrollToEl(el, true); 143 if (inDropdown) dismissDropdown(link); 144 } 145 }); 146 }); 147 148 // Landed with a hash (e.g. from the menu): re-align after layout settles 149 // â Elementor content + images shift the page height after the browser's 150 // initial jump, which is why "it stays at the top". 151 if (location.hash && location.hash.length > 1) { 152 var target = elForHash(location.hash); 153 if (target) { 154 var realign = function () { scrollToEl(elForHash(location.hash), false); }; 155 requestAnimationFrame(realign); 156 setTimeout(realign, 250); 157 setTimeout(realign, 700); 158 window.addEventListener('load', function () { setTimeout(realign, 120); }); 159 } 160 } 161 162 /* Logo carousel (client list) and the stat counters are now real 163 * Elementor widgets ("Image Carousel" / "Counter") â their autoplay 164 * and count-up animation are handled by Elementor's own frontend.js, 165 * no custom code needed here any more. */ 166 167 /* ---- Pricing monthly / annual toggle ----------------- */ 168 var toggle = document.querySelector('.vargo-price-toggle'); 169 var sw = toggle && toggle.querySelector('.vargo-sw, .sw, button'); 170 if (toggle && sw) { 171 if (!sw.querySelector('.vargo-sw__dot')) { 172 var dot = document.createElement('span'); 173 dot.className = 'vargo-sw__dot'; 174 sw.appendChild(dot); 175 } 176 var labels = toggle.querySelectorAll('span[data-t]'); 177 var apply = function (annual) { 178 toggle.classList.toggle('is-annual', annual); 179 sw.setAttribute('aria-checked', annual ? 'true' : 'false'); 180 labels.forEach(function (s) { s.classList.toggle('on', s.dataset.t === (annual ? 'a' : 'm')); }); 181 document.querySelectorAll('.vargo-plan__price[data-m]').forEach(function (p) { 182 p.querySelector('.amt').textContent = annual ? p.dataset.a : p.dataset.m; 183 var per = p.querySelector('.per'); 184 if (per) per.textContent = annual ? (p.dataset.perA || '/ año') : (p.dataset.perM || '/ mes'); 185 }); 186 document.querySelectorAll('.vargo-plan__bill[data-bill-m]').forEach(function (b) { 187 b.textContent = annual ? b.dataset.billA : b.dataset.billM; 188 }); 189 }; 190 sw.addEventListener('click', function () { apply(!toggle.classList.contains('is-annual')); }); 191 apply(false); 192 } 193 194 /* ---- Tabs (Plataforma) â native Elementor "Tabs" widget, kept 195 * deep-linkable via #tab-<slug> (mega-menu + home bento links to it). 196 * Order here must match the $groups order in vargo_demo_page_plataforma(). 197 * Elementor renders a desktop AND a mobile title per tab (both share 198 * the .elementor-tab-title class + a 1-indexed data-tab), so matching 199 * is done by data-tab value, picking whichever copy is visible. */ 200 var VARGO_TAB_SLUGS = ['ventas', 'operacion', 'finanzas', 'comunicacion', 'automatizacion']; 201 document.querySelectorAll('.vargo-tabs').forEach(function (tabs) { 202 var allTitles = Array.prototype.slice.call(tabs.querySelectorAll('.elementor-tab-title[data-tab]')); 203 if (!allTitles.length) return; 204
205 allTitles.forEach(function (t) { 206 t.addEventListener('click', function () { 207 var slug = VARGO_TAB_SLUGS[parseInt(t.getAttribute('data-tab'), 10) - 1]; 208 if (slug && history.replaceState) history.replaceState(null, '', '#tab-' + slug); 209 }); 210 }); 211 212 var fromHash = function (scroll) { 213 var m = (location.hash || '').match(/^#tab-([a-z-]+)$/); 214 if (!m) return; 215 var idx = VARGO_TAB_SLUGS.indexOf(m[1]); 216 if (idx < 0) return; 217 var candidates = allTitles.filter(function (t) { return t.getAttribute('data-tab') === String(idx + 1); }); 218 var target = candidates.filter(function (t) { return t.offsetParent !== null; })[0] || candidates[0]; 219 if (target && !target.classList.contains('elementor-active')) target.click(); 220 if (scroll) tabs.scrollIntoView({ behavior: 'smooth', block: 'center' }); 221 }; 222 // Elementor's own tabs.js binds its click handler after its frontend 223 // init cycle, which may run after this script â retry the initial 224 // hash check a few times instead of a single early call. 225 fromHash(true); 226 [60, 200, 500, 1000].forEach(function (ms) { setTimeout(function () { fromHash(true); }, ms); }); 227 window.addEventListener('hashchange', function () { fromHash(true); }); 228 }); 229 230 /* ---- Blog: copy-link share button ------------------- */ 231 document.querySelectorAll('.vargo-share__copy').forEach(function (btn) { 232 btn.addEventListener('click', function () { 233 var wrap = btn.closest('.vargo-share'); 234 var url = (wrap && wrap.getAttribute('data-url')) || location.href; 235 var done = function () { 236 btn.classList.add('is-done'); 237 setTimeout(function () { btn.classList.remove('is-done'); }, 1800); 238 }; 239 if (navigator.clipboard && navigator.clipboard.writeText) { 240 navigator.clipboard.writeText(url).then(done, done); 241 } else { 242 var t = document.createElement('textarea'); 243 t.value = url; document.body.appendChild(t); t.select(); 244 try { document.execCommand('copy'); } catch (e) {} 245 document.body.removeChild(t); done(); 246 } 247 }); 248 }); 249 250 /* ---- Sticky sub-nav scroll-spy ---------------------- */ 251 var subnav = document.querySelector('.vargo-subnav'); 252 if (subnav && 'IntersectionObserver' in window) { 253 var links = Array.prototype.slice.call(subnav.querySelectorAll('a')); 254 var targets = links.map(function (a) { return document.querySelector(a.getAttribute('href')); }).filter(Boolean); 255 var so = new IntersectionObserver(function (es) { 256 es.forEach(function (e) { 257 if (e.isIntersecting) { 258 links.forEach(function (l) { l.classList.remove('is-active'); }); 259 var m = links.filter(function (l) { return l.getAttribute('href') === '#' + e.target.id; })[0]; 260 if (m) m.classList.add('is-active'); 261 } 262 }); 263 }, { rootMargin: '-45% 0px -50% 0px' }); 264 targets.forEach(function (t) { so.observe(t); }); 265 } 266 267 /* ---- Scroll-reveal (progressive, with failsafe) ----- */ 268 if (!reduceMotion && 'IntersectionObserver' in window) { 269 var rt = Array.prototype.slice.call(document.querySelectorAll( 270 '.elementor-widget-icon-box, .elementor-widget-image-box, .elementor-widget-testimonial, .elementor-accordion, .elementor-widget-counter, .vargo-post-card, .vargo-contact-form-wrap, .vargo-hero__media, .vargo-split__media .elementor-widget-image, .vargo-plan__card, .vargo-tabs__card' 271 )); 272 var reveal = function (n) { n.classList.add('is-visible'); }; 273 var ro = new IntersectionObserver(function (es) { 274 es.forEach(function (e) { if (e.isIntersecting) { reveal(e.target); ro.unobserve(e.target); } }); 275 }, { threshold: 0.08, rootMargin: '0px 0px -40px 0px' }); 276 var vh = window.innerHeight || 800; 277 rt.forEach(function (n, i) { 278 if (n.getBoundingClientRect().top < vh - 40) { n.classList.add('vargo-reveal', 'is-visible'); return; } 279 n.classList.add('vargo-reveal'); 280 n.style.transitionDelay = (i % 3) * 70 + 'ms'; 281 ro.observe(n); 282 }); 283 setTimeout(function () { rt.forEach(reveal); }, 2600); 284 } 285 }); 286})();
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.