1<!DOCTYPE html><!-- Last Published: Thu Sep 24 2026 18:04:18 GMT+0000 (Coordinated Universal Time) --><html data-wf-domain="postmodern-jukebox.webflow.io" data-wf-page="69c3fc5ac9f60b8eed4e5e64" data-wf-site="69c2b9815263da6a49ccf592" lang="en"><head><meta charset="utf-8"/><link href="https://cdn.prod.website-files.com" rel="preconnect" crossorigin="anonymous"/><title>Terms of Use</title><meta content="Terms of Use" property="og:title"/><meta content="Terms of Use" name="twitter:title"/><meta content="width=device-width, initial-scale=1" name="viewport"/><link href="https://cdn.prod.website-files.com/69c2b9815263da6a49ccf592/css/postmodern-jukebox.webflow.shared.5669ecd2b.css" rel="stylesheet" type="text/css" integrity="sha384-Vmns0rW0m3JUhKEfg3bD7rsUjxrSgSYEfn42Ps7rweANzNKAHZlOahx0wcMLZtnm" crossorigin="anonymous"/><link href="https://fonts.googleapis.com" rel="preconnect"/><link href="https://fonts.gstatic.com" rel="preconnect" crossorigin="anonymous"/>
1<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js" type="text/javascript"></script>
1<script type="text/javascript">WebFont.load({ google: { families: ["Inter:300,400,500,600,700"] }});</script>
1<script src="https://use.typekit.net/guh4etq.js" type="text/javascript"></script>
1<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
1<script type="text/javascript">!function(o,c){var n=c.documentElement,t=" w-mod-";n.className+=t+"js",("ontouchstart"in o||o.DocumentTouch&&c instanceof DocumentTouch)&&(n.className+=t+"touch")}(window,document);</script>
1<link href="https://cdn.prod.website-files.com/69c2b9815263da6a49ccf592/69cae9a5001740fc8d4dc547_fav_circle_32.png" rel="icon" type="image/png" sizes="32x32" media="(prefers-color-scheme: light)"/><link href="https://cdn.prod.website-files.com/69c2b9815263da6a49ccf592/69cae9a5001740fc8d4dc547_fav_circle_32.png" rel="icon" type="image/png" sizes="32x32" media="(prefers-color-scheme: dark)"/><link href="https://cdn.prod.website-files.com/69c2b9815263da6a49ccf592/69cae9b1f0926144d376145c_fav_circle_256.png" rel="apple-touch-icon"/>
1<script>(function(w,i,g){w[g]=w[g]||[];if(typeof w[g].push=='function')w[g].push.apply(w[g],Array.isArray(i)?i:[i]);})(window,['G-8JM48JCNFN'],'google_tags_first_party');</script>
1<script async="" src="/haqt6iy0yx2eNjljMmI5ODE1MjYzZGE2YTQ5Y2NmNTky/swoU_Bl-mHSmbWuqdd1JbfE8ew4"></script>
1<script type="text/javascript">window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag('set', 'developer_id.dZGVlNj', true);gtag('set', 'developer_id.dYWYxNW', true);gtag('js', new Date());gtag('config', 'G-8JM48JCNFN');</script>
1<!-- Meta Pixel Code -->
2<script>
vendor: 399 bytes, lines 2-11
2 3!function(f,b,e,v,n,t,s) 4{if(f.fbq)return;n=f.fbq=function(){n.callMethod? 5n.callMethod.apply(n,arguments):n.queue.push(arguments)}; 6if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; 7n.queue=[];t=b.createElement(e);t.async=!0; 8t.src=v;s=b.getElementsByTagName(e)[0]; 9s.parentNode.insertBefore(t,s)}(window, document,'script', 10'https://connect.facebook.net/en_US/fbevents.js'); 11fbq('init', '
111008267602569190
vendor: 30 bytes, lines 11-12
11'); 12fbq('track', 'PageView');
13</script>
13 14<noscript><img height="1" width="1" style="display:none" 15src="https://www.facebook.com/tr?id=1008267602569190&ev=PageView&noscript=1" 16/></noscript> 17<!-- End Meta Pixel Code --> 18 19<!-- Google Analytics --> <!-- UNUSED IN FAVOR OF Apps & Integrations --> 20<!-- Google Tag Manager --> <!-- Tag manager currently appears to be empty --> 21<!--
21<script>
vendor: 328 bytes, lines 21-26
21 22(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 23new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 24j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 25'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 26})(window,document,'script','dataLayer','
26GTM-TLGB2WN
vendor: 4 bytes, line 26
26');
27</script>
27 --> 28<!-- End Google Tag Manager --> 29 30<!-- Enzuzo --> 31<!--
31<script src="https://app.enzuzo.com/scripts/cookiebar/6495237a-3374-11f1-b383-0bc89965430d"></script>
31 --> 32 33<!-- Global Styles --> 34<style> 35 input::placeholder { 36 color: inherit !important; 37 opacity: 0.5; 38 } 39 40 .iti { 41 --iti-border-color: var(--pmj-gold); 42 --iti-dropdown-bg: var(--pmj-blue); 43 --iti-icon-color: var(--pmj-gold); 44 --iti-hover-color: var(--pmj-lighter-blue); 45 46 width: 100%; 47 margin-bottom: 10px; 48 49 & input[type="search"] { 50 background-color: var(--pmj-blue); 51 } 52 } 53</style></head><body class="body-standard"><div class="header"><div id="mobile-nav" class="mobile-nav hidden"><div class="mobile-nav-scripts w-embed w-script">
53<script> 54 document.addEventListener('DOMContentLoaded', () => { 55 const hamburger = document.getElementById('hamburger') 56 const mobileNav = document.getElementById('mobile-nav') 57 58 if (!hamburger || !mobileNav) { 59 console.warn('Missing required mobile nav element.') 60 return 61 } 62 63 const mobileNavLinks = mobileNav.querySelectorAll('a') 64 65 mobileNavLinks.forEach((link) => { 66 link.addEventListener('click', () => { 67 hideMobileNav() 68 }) 69 }) 70 71 function hideMobileNav () { 72 mobileNav.classList.add('hidden') 73 hamburger.classList.remove('close') 74 } 75 76 hamburger.addEventListener('click', () => { 77 if (mobileNav.classList.contains('hidden')) { 78 mobileNav.classList.remove('hidden') 79 hamburger.classList.add('close') 80 } else { 81 hideMobileNav() 82 } 83 }) 84 }) 85</script>
85</div><div class="mobile-nav-styling w-embed"><style> 86 .mobile-nav .nav-tickets-wrap { 87 display: flex !important; 88 flex-direction: column; 89 } 90 .mobile-nav .nav-list { 91 flex-direction: column; 92 align-items: center; 93 } 94</style></div><div class="nav-tickets-wrap header-nav"><ul role="list" class="nav-list"><li><a href="/">Home</a></li><li><a href="/tour-dates">Tour Dates</a></li><li><a href="/#featured-videos">Videos</a></li><li class="hidden-link"><a href="https://postmodernjukebox.myshopify.com/">Store</a></li><li><a href="/#about">About</a></li><li><a data-open-contact="" href="#">Contact</a></li></ul><a href="/tour-dates" class="tickets-button w-button">Tickets</a></div></div><div class="header-styles w-embed"><style> 95 .header .nav-list a { 96 text-decoration: none; 97 } 98 99 .hamburger.close .bar.t { 100 top: 43%; 101 transform: rotateZ(-45deg); 102 } 103 .hamburger.close .bar.m { 104 opacity: 0; 105 } 106 .hamburger.close .bar.b { 107 bottom: 43%; 108 transform: rotateZ(45deg); 109 } 110</style></div><a href="/" class="link-block w-inline-block"><img loading="lazy" src="https://cdn.prod.website-files.com/69c2b9815263da6a49ccf592/69c2dcadf485bf6a30da92cb_pmj_header_logotype.svg" alt="" class="header-logotype"/></a><div class="nav-tickets-wrap header-nav"><ul role="list" class="nav-list"><li><a href="/">Home</a></li><li><a href="/tour-dates">Tour Dates</a></li><li><a href="/#featured-videos">Videos</a></li><li class="hidden-link"><a href="https://postmodernjukebox.myshopify.com/">Store</a></li><li><a href="/#about">About</a></li><li><a data-open-contact="" href="#">Contact</a></li></ul><a href="/tour-dates" class="tickets-button w-button">Tickets</a></div><div id="hamburger" class="hamburger"><div class="bars-wrapper"><div class="bar t"></div><div class="bar m"></div><div class="bar b"></div></div></div></div><div class="text-page-content"><h1 class="page-title">Terms of Service</h1><div class="rich-text w-richtext"><p><strong>Last updated: March 31, 2026</strong></p><p>â</p><p>Welcome to <strong>Postmodern Jukebox</strong> (âwe,â âus,â or âourâ). These Terms of Service (âTermsâ) govern your use of our website located at <strong>[yourdomain.com]</strong> (the âSiteâ).</p><p>By accessing or using the Site, you agree to be bound by these Terms.</p><p>â</p><h2>Use of the Site</h2><p>You agree to use this Site only for lawful purposes and in accordance with these Terms.</p><p>You agree not to:</p><ul role="list"><li>Use the Site in any way that violates applicable laws or regulations</li><li>Attempt to gain unauthorized access to any part of the Site</li><li>Interfere with or disrupt the Site or its servers</li><li>Use the Site to transmit any harmful or malicious code</li></ul><p>â</p><h2>Intellectual Property</h2><p>All content on this Site, including text, images, graphics, logos, and design, is owned by or licensed to <strong>[Your Company]</strong> and is protected by intellectual property laws.</p><p>You may not reproduce, distribute, modify, or create derivative works without our prior written consent.</p><p>â</p><h2>User Submissions</h2><p>If you submit any information through the Site (e.g., forms, messages, or uploads), you:</p><ul role="list"><li>Grant us the right to use, reproduce, and process that information as necessary to operate the Site and provide services</li><li>Represent that you have the right to submit such information</li></ul><p>We reserve the right to remove or refuse any submissions at our discretion.</p><p>â</p><h2>Third-Party Links</h2><p>Our Site may contain links to third-party websites or services. We are not responsible for the content, policies, or practices of those third parties.</p><p>Use of third-party sites is at your own risk.</p><p>â</p><h2>Disclaimer of Warranties</h2><p>The Site is provided on an âas isâ and âas availableâ basis.</p><p>We make no warranties, express or implied, regarding:</p><ul role="list"><li>The operation or availability of the Site</li><li>The accuracy or completeness of content</li><li>The absence of errors or interruptions</li></ul><p>â</p><h2>Limitation of Liability</h2><p>To the fullest extent permitted by law, <strong>[Your Company]</strong> shall not be liable for any indirect, incidental, special, or consequential damages arising out of or related to your use of the Site.</p><p>â</p><h2>Indemnification</h2><p>You agree to indemnify and hold harmless <strong>[Your Company]</strong> from any claims, damages, or expenses arising from:</p><ul role="list"><li>Your use of the Site</li><li>Your violation of these Terms</li></ul><p>â</p><h2>Termination</h2><p>We reserve the right to suspend or terminate your access to the Site at any time, without notice, for conduct that we believe violates these Terms or is otherwise harmful.</p><p>â</p><h2>Governing Law</h2><p>These Terms are governed by and construed in accordance with the laws of the State of <strong>[Your State]</strong>, without regard to its conflict of law principles.</p><p>â</p><h2>Changes to These Terms</h2><p>We may update these Terms from time to time. Updates will be posted on this page with a revised âLast updatedâ date.</p><p>Your continued use of the Site after changes are posted constitutes your acceptance of the updated Terms.</p><p>â</p><h2>Contact Information</h2><p>If you have any questions about these Terms, please contact us:</p><p><strong>[Company Name]</strong><br/><strong>[Email Address]</strong><br/><strong>[Mailing Address (optional)]</strong></p><p>â</p></div></div><div class="footer"><div id="subscribe-modal" class="modal hidden"><div class="modal__hitbox"></div><div class="modal__inner"><div class="modal__close"><p class="close-x">Ã</p></div><div data-listid="27" class="subscribe-form w-form"><form id="wf-form-Modal-Subscribe-Form" name="wf-form-Modal-Subscribe-Form" data-name="Modal Subscribe Form" method="get" data-wf-page-id="69c3fc5ac9f60b8eed4e5e64" data-wf-element-id="189f57b2-242a-d2db-1253-57904bd611d3" data-turnstile-sitekey="0x4AAAAAAAQTptj2So4dx43e"><div class="form-header"><h2 class="form__title">Stay Updated</h2><h3 class="form__subtitle">Hear the latest on tour dates and new releases.</h3></div><div class="input-wrapper name first"><div class="input-single-wrapper"><label for="first-name" class="standard-label">First Name</label><input class="standard-input w-input" maxlength="256" name="first-name" data-name="first-name" placeholder="" type="text"/></div><div class="input-single-wrapper"><label for="last-name" class="standard-label">Last Name</label><input class="standard-input w-input" maxlength="256" name="last-name" data-name="last-name" placeholder="" type="text" id="last-name"/></div></div><label for="City" class="standard-label">Your City</label><input class="standard-input w-input" maxlength="256" name="City" data-name="City" placeholder="" type="text" id="City" required=""/><label for="Email" class="standard-label">Email Address</label><input class="standard-input w-input" maxlength="256" name="Email" data-name="Email" placeholder="" type="email" id="Email" required=""/><label for="subscribe-phone" class="standard-label">Phone Number (Optional)</label><input class="standard-input intl-phone w-input" maxlength="256" name="field" data-name="Field" placeholder="" type="text" id="subscribe-phone"/>
110<p class="sms-disclaimer">By entering your phone number and pressing "Submit"Â below you confirm that you are 13 years old or older and meet the minimum age requirements to use this service. You agree to Community's Terms of Service and Privacy Policy and consent to receive recurring messages at the number above (which may be marketing and/or automated) from or on behalf of Postmodern Jukebox via Community. Consent is not a condition of purchase. Message &Â data rates may apply. Message HELPÂ for help, STOPÂ to cancel.</p><input type="submit" data-wait="Please wait..." class="btn w-button" value="Submit"/></form><div class="success-message w-form-done"><div>Thank you! Your submission has been received!</div></div><div class="w-form-fail"><div>Oops! Something went wrong while submitting the form.</div></div></div></div></div><div id="contact-modal" class="modal hidden"><div class="modal__hitbox"></div><div class="modal__inner"><div class="modal__close"><p class="close-x">Ã</p></div><div data-listid="27" class="contact-form w-form"><form id="email-form" name="email-form" data-name="Email Form" method="get" data-wf-page-id="69c3fc5ac9f60b8eed4e5e64" data-wf-element-id="ee3635b7-d4b4-29e4-68d1-fff7f7e074f4" data-turnstile-sitekey="0x4AAAAAAAQTptj2So4dx43e"><div class="form-header"><h2 class="form__title">Got a question?</h2><h3 class="form__subtitle">Send us a message and we'll get back to you as soon as possible.</h3></div><div class="input-wrapper name"><div class="input-single-wrapper"><label for="contact-first-name" class="standard-label">First Name</label><input class="standard-input w-input" maxlength="256" name="first-name" data-name="first-name" placeholder="" type="text" id="contact-first-name"/></div><div class="input-single-wrapper"><label for="contact-last-name" class="standard-label">Last Name</label><input class="standard-input w-input" maxlength="256" name="last-name" data-name="last-name" placeholder="" type="text" id="contact-last-name"/></div></div><label for="email" class="standard-label">Email Address</label><input class="standard-input w-input" maxlength="256" name="email" data-name="Email" placeholder="" type="email" id="email" required=""/><label for="email-reason" class="standard-label">Reason for Contacting</label><select id="email-reason" name="Reason" data-name="Reason" required="" class="standard-input w-select"><option value="">Select one...</option><option value="Europe Tickets / VIP">Europe Tickets / VIP</option><option value="North America Tickets / VIP">North America Tickets / VIP</option><option value="Booking">Booking</option><option value="All other inquiries">All other inquiries</option></select><label for="email-subject" class="standard-label">Subject</label><input class="standard-input w-input" maxlength="256" name="Email-Subject" data-name="Email Subject" placeholder="" type="text" id="email-subject" required=""/><label for="email-message" class="standard-label">Message</label><textarea id="email-message" name="Message" maxlength="5000" data-name="Message" placeholder="" class="standard-input w-input"></textarea><label class="w-checkbox standard-checkbox"><input type="checkbox" id="Subscribe" name="Subscribe" data-name="Subscribe" data-subscribe="" class="w-checkbox-input checkbox"/><span class="standard-label check w-form-label" for="Subscribe">Subscribe to Mailing List?</span></label><label for="contact-phone" class="standard-label">Phone Number (Optional)</label><input class="standard-input intl-phone w-input" maxlength="256" name="field" data-name="Field" placeholder="" type="text" id="contact-phone"/><p class="sms-disclaimer">By entering your phone number and pressing "Submit"Â below you confirm that you are 13 years old or older and meet the minimum age requirements to use this service. You agree to Community's Terms of Service and Privacy Policy and consent to receive recurring messages at the number above (which may be marketing and/or automated) from or on behalf of Postmodern Jukebox via Community. Consent is not a condition of purchase. Message &Â data rates may apply. Message HELPÂ for help, STOPÂ to cancel.</p><input type="submit" data-wait="Please wait..." class="btn w-button" value="Submit"/></form><div class="success-message w-form-done"><div>Thank you! Your submission has been received!</div></div><div class="form-error w-form-fail"><div>Oops! Something went wrong while submitting the form.</div></div></div></div></div><div class="footer-styles w-embed"><style>
111 .footer .nav-list a { 112 text-decoration: none; 113 } 114</style></div><div class="footer__subscribe"><div class="news-headline-wrapper"><div class="code-embed w-embed"><?xml version="1.0" encoding="UTF-8"?> 115<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49.26 44.56"> 116 <defs> 117 <style> 118 .cls-1 { 119 fill: currentColor; 120 } 121 </style> 122 </defs> 123 <g id="FONTS_AND_LAYOUT" data-name="FONTS AND LAYOUT"> 124 <g> 125 <path class="cls-1" d="M28.59,22.39l3.74,2.38-15.52,8.33c-2.8,1.5-5.43,4.51-3.49,8.08.98,1.8,2.57,3.16,4.29,3.37.05,0,.1,0,.16.01.63-1.01,1.37-1.95,2.13-2.88.19-.23.39-.46.58-.69-.58-.43-1.07-.94-1.38-1.67-1.13-2.62,6.14-6.69,8-7.83l8.01-4.95,6.03,3.78,8.13-8.13-8.15-8.14-6.35,3.85-8.24-5.09c-1.82-1.12-9.04-5.2-7.85-7.81.21-.47.5-.85.83-1.18-1.18-1.12-2.2-2.43-3.1-3.82-1.39.46-2.65,1.61-3.46,3.05-2.02,3.6.51,6.62,3.34,8.14l15.65,8.41-3.64,2.26C19.65,20.55,8.65,19.33,0,18.51c0,.93.37,5.73.48,7.19,8.58-.86,19.51-2,28.11-3.32Z"/> 126 <path class="cls-1" d="M9.75,9.76c-.18-.1-.37-.
12618-.56-.26-1.16,1.73-2.43,3.39-3.59,5.13-.26.39-.55.73-.87,1.03,7.94,1.8,15.64,3.63,24.13,4.92-6.13-4.26-12.56-7.33-19.11-10.82Z"/> 127 <path class="cls-1" d="M5.53,28.63c.87.43,1.61,1.09,2.06,1.94.59,1.12,1.17,2.23,1.91,3.26.2.27.35.58.45.9.03-.02.07-.03.1-.04,6.48-3.43,12.86-6.54,19.24-10.86-8.26,1.16-15.93,3.03-23.77,4.8Z"/> 128 </g> 129 </g> 130</svg></div><h1 class="headline">News &Â Updates Here</h1></div><div class="arrow-wrap"><div class="arrow-line"></div><div class="arrow-head w-embed"><svg width="8" height="10" viewBox="0 0 8 10" fill="none" xmlns="http://www.w3.org/2000/svg"> 131 <path d="M1 1L7 5L1 9" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> 132</svg></div></div><div data-listid="27" class="subscribe-form-block w-form"><form id="footer-subscribe" name="wf-form-" data-name="Footer Subscribe" method="get" data-wf-page-id="69c3fc5ac9f60b8eed4e5e64" data-wf-element-id="82ea620f-13a0-06ed-ead9-9bb7519967d7" data-turnstile-sitekey="0x4AAAAAAAQTptj2So4dx43e"><div class="input-wrapper"><input class="subscribe-input w-input" maxlength="256" name="email" data-name="Email" placeholder="Enter your email" type="email" id="footer-subscribe-email" required=""/><input type="submit" data-wait="Please wait..." id="footer-subscribe-submit" class="btn w-button" value="Submit"/></div></form><div class="success-message w-form-done"><div>Thank you! Your submission has been received!</div></div><div class="w-form-fail"><div>Sorry, something went wrong. Please try again later.</div></div></div></div><img loading="lazy" src="https://cdn.prod.website-files.com/69c2b9815263da6a49ccf592/69c3fae7636e6830966d10e3_footer_logo.svg" alt="" class="footer__logo"/><div class="footer__nav"><div class="footer__nav__socials"><ul role="list" class="nav-list condensed"><li><a href="https://www.facebook.com/postmodernjukebox/" target="_blank">ï</a></li><li><a href="https://x.com/PMJofficial" target="_blank">î</a></li><li><a href="https://www.instagram.com/pmjofficial/" target="_blank">ï </a></li><li><a href="https://www.youtube.com/channel/UCORIeT1hk6tYBuntEXsguLg" target="_blank">ï §</a></li><li><a href="https://open.spotify.com/artist/5HYNPEO2NNBONQkp3Mvwvc" target="_blank">ï¼</a></li></ul></div><div class="nav-tickets-wrap"><ul role="list" class="nav-list footer-nav"><li><a href="/terms" aria-current="page" class="w--current">Terms of Service</a></li><li><a href="/privacy-policy">Privacy Policy</a></li><li><a href="#manage_cookies">Cookies</a></li><li><a data-open-contact="" href="#">Contact</a></li></ul><a href="/tour-dates" class="tickets-button w-button">Tickets</a></div></div></div>
132<script src="https://d3e54v103j8qbb.cloudfront.net/js/jquery-3.5.1.min.dc5e7f18c8.js?site=69c2b9815263da6a49ccf592" type="text/javascript" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
132<script src="https://cdn.prod.website-files.com/69c2b9815263da6a49ccf592/js/webflow.schunk.1398ace9ffbb200a.js" type="text/javascript" integrity="sha384-EVP6t2U07qoLfhZHt+I2uUY5DBG5cLU1LidMdpFA0l5xbMsorberyNhh8TZYB7b1" crossorigin="anonymous"></script>
132<script src="https://cdn.prod.website-files.com/69c2b9815263da6a49ccf592/js/webflow.a0aa6ca1.2628b82da48d0a28.js" type="text/javascript" integrity="sha384-HdQOnR91f9MludhV34T3CDlKHN4sJtqw3YFQ/owDbEaj0SKsRf7UZHGJ0RF9Sa78" crossorigin="anonymous"></script>
132<!-- International Telephone Input --> 133<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/build/css/intlTelInput.css">
134<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/js/intlTelInput.min.js"></script>
vendor: 1 bytes, line 134
134
135<script> 136 const phoneInputs = document.querySelectorAll(".intl-phone"); 137 if (phoneInputs && phoneInputs.length) { 138 console.log('Initializing international phone number inputs...') 139 phoneInputs.forEach((input) => { 140 window.intlTelInput(input, { 141 loadUtils: () => import("https://cdn.jsdelivr.net/npm/[email protected]/build/js/utils.js"), 142 hiddenInput: (telInputName) => ({ 143 phone: "phone_full", 144 country: "country_code" 145 }), 146 }); 147 }) 148 } else { 149 console.warn('No .intl-phone inputs found.') 150 } 151</script>
151 152
153<script> 154 // Modal Scripts 155 const subscribeModal = document.getElementById('subscribe-modal') 156 const subscribeModalOpeners = document.querySelectorAll('[data-open-subscribe]') 157 158 function showModal(modal) { 159 if (modal) modal.classList.remove('hidden') 160 } 161 162 if (subscribeModal) { 163 subscribeModalOpeners.forEach((opener) => { 164 opener.addEventListener('click', (e) => { 165 e.preventDefault() 166 showModal(subscribeModal) 167 }) 168 }) 169 } 170 171 const contactModal = document.getElementById('contact-modal') 172 const contactModalOpeners = document.querySelectorAll('[data-open-contact]') 173 174 if (contactModal) { 175 contactModalOpeners.forEach((opener) => { 176 opener.addEventListener('click', (e) => { 177 showModal(contactModal) 178 }) 179 }) 180 } 181 182 const modals = document.querySelectorAll('.modal'); 183 console.log('Modals', modals) 184 if (modals && modals.length) { 185 modals.forEach((modal) => { 186 const close = modal.querySelector('.modal__close') 187 const hitbox = modal.querySelector('.modal__hitbox') 188 189 close.addEventListener('click', () => { 190 modal.classList.add('hidden') 191 }) 192 hitbox.addEventListener('click', () => { 193 modal.classList.add('hidden') 194 }) 195 }) 196 } 197 198 const params = new URLSearchParams(window.location.search); 199 if (params.has('subscribe')) showModal(subscribeModal); 200 if (params.has('contact')) showModal(contactModal); 201 202/** 203 * Site-wide: POST /app/api/leads for forms in [data-listid]. 204 * 205 * - `[data-listid]` and **no** `[data-subscribe]` (legacy): Community (if phone) â POST `/leads` â .w-form-done / .w-form-fail. 206 * - `[data-listid]` + `[data-subscribe]` **checked**: Community (if phone) â `/leads` â native Webflow submit. 207 * - `[data-listid]` + `[data-subscribe]` **unchecked**: Community (if phone) only â **no** `/leads` (email opt-out) â Webflow submit. 208 * - `data-subscribe` gates **email list** only, not Community SMS. 209 * - No `[data-listid]`: default Webflow only. 210 * 211 * Submit button: while the leads request runs (and before Webflowâs second submit), label comes from 212 * `data-wait` on the button (Webflow default), or âPlease wait...â. 213 * 214 * Uses stopPropagation on intercept paths so Webflow doesnât race the leads call. 215 * Webflow handoff uses `setTimeout(0)` before `requestSubmit()` so it runs outside the capturing submit 216 * stack (fixes first-click no-op on WebKit/Webflow); `checkValidity()` runs first so HTML5 errors surface. 217 * 218 * Mount: one global Code Embed (e.g. site footer or Project-wide custom code before </body>). 219 * API: POST /app/api/leads; optional POST /app/api/community-subscribe when `phone_full` is present 220 * (runs before leads + Webflow). Community Invite/Update Member accepts `given_name`, `surname`, 221 * `city`, and `email` per https://developer.community.com/reference/upsert-member â proxied as-is. 222 * Form fields may still use Webflow names like `firstName` / âFirst Nameâ; the embed maps those to `given_name`/`surname` for `/community-subscribe` only (`/leads` keeps `firstName`/`lastName` as today). 223 * 224 * intl-tel-input: Webflow often uses `type="text"` + `.iti__tel-input` (not `type="tel"`). We resolve the 225 * plugin element via `[data-intl-tel-input-id]`, `.iti__tel-input`, or `.iti` + text input, then 226 * `intlTelInput.getInstance(input)` â `await iti.promise` â `isValidNumber()` / `getNumber()` for E.164. 227 * Do not rely on a `phone_full` hidden field being populated before submit. 228 * 229 * **Country code in Webflow / intl-tel-input (site script, not this file):** use plugin options such as 230 * `initialCountry: "us"` (or `"auto"` with `geoIpLookup`), `nationalMode: false` for full international 231 * format, and `strictMode: true` if you want stricter typing. This embed blocks submit when the ITI field 232 * has text but `isValidNumber()` is false (incomplete / wrong country). 233 */ 234(function () { 235 var LEADS_URL = "/app/api/leads"; 236 var COMMUNITY_URL = "/app/api/community-subscribe"; 237 var LOG = "[form-leads]"; 238 /** Set on the form while re-dispatching so we donât intercept the Webflow submit. */ 239 var SKIP_FLAG = "__formLeadsSkipIntercept"; 240 241 /** Console-safe hint for phone values (last 4 digits only). */ 242 function maskPhoneForLog(value) { 243 if (value == null || String(value).trim() === "") return "(empty)"; 244 var d = String(value).replace(/\D/g, ""); 245 if (d.length <= 4) return "(short)"; 246 return "â¦" + d.slice(-4); 247 } 248 /** Original submit label while showing data-wait / Please wait... */ 249 var SUBMIT_LABEL_BACKUP = "__formLeadsSubmitLabelBackup"; 250 251 function log() { 252 var a = [LOG]; 253 for (var i = 0; i < arguments.length; i++) a.push(arguments[i]); 254 console.log.apply(console, a); 255 } 256 257 function warn() { 258 var a = [LOG]; 259 for (var i = 0; i < arguments.length; i++) a.push(arguments[i]); 260 console.warn.apply(console, a); 261 } 262 263 function getListSource(form) { 264 if (!(form instanceof HTMLFormElement)) return null; 265 if (form.hasAttribute("data-listid")) return form; 266 return form.closest("[data-listid]"); 267 } 268 269 function getSubscribeCheckbox(form) { 270 if (!(form instanceof HTMLFormElement)) return null; 271 return form.querySelector('input[type="checkbox"][data-subscribe]'); 272 } 273 274 function getFormWrapper(form) { 275 return form.closest(".w-form") || form.parentElement; 276 } 277
278 function getMessageElements(form) { 279 var wrap = getFormWrapper(form); 280 if (!wrap) return { success: null, fail: null }; 281 return { 282 success: wrap.querySelector(".w-form-done, .wf-form-done"), 283 fail: wrap.querySelector(".w-form-fail, .wf-form-fail"), 284 }; 285 } 286 287 function pickField(fd, names) { 288 var i; 289 var k; 290 var v; 291 for (i = 0; i < names.length; i++) { 292 v = fd.get(names[i]); 293 if (v != null && String(v).trim()) return String(v).trim(); 294 } 295 for (var pair of fd.entries()) { 296 k = pair[0]; 297 v = pair[1]; 298 if ( 299 v != null && 300 String(v).trim() && 301 names.some(function (n) { 302 return n.toLowerCase() === k.toLowerCase(); 303 }) 304 ) { 305 return String(v).trim(); 306 } 307 } 308 return ""; 309 } 310 311 /** Webflow inputs often use `data-name="First Name"` while `name` is generic; match label loosely. */ 312 function findInputValueByDataName(form, re) { 313 if (!(form instanceof HTMLFormElement)) return ""; 314 var els = form.querySelectorAll("[data-name]"); 315 var i; 316 var el; 317 var dn; 318 var v; 319 for (i = 0; i < els.length; i++) { 320 el = els[i]; 321 dn = el.getAttribute("data-name"); 322 if (!dn || !re.test(String(dn).trim())) continue; 323 if ("value" in el && el.value != null) { 324 v = String(el.value).trim(); 325 if (v) return v; 326 } 327 } 328 return ""; 329 } 330 331 function findEmail(form, fd) { 332 var el = form.querySelector( 333 'input[type="email"], input[name="email"], input[name="Email"]' 334 ); 335 if (el && el.value && String(el.value).trim()) return String(el.value).trim(); 336 var v = fd.get("email") || fd.get("Email") || fd.get("EMAIL"); 337 if (v && String(v).trim()) return String(v).trim(); 338 for (var pair of fd.entries()) { 339 if (/email/i.test(pair[0]) && pair[1] && String(pair[1]).trim()) { 340 return String(pair[1]).trim(); 341 } 342 } 343 return ""; 344 } 345 346 function collectPayload(form, listSource) { 347 var fd = new FormData(form); 348 var raw = listSource.getAttribute("data-listid"); 349 var listId; 350 if (raw != null && String(raw).trim() !== "") { 351 var n = parseInt(String(raw).trim(), 10); 352 if (Number.isFinite(n)) listId = n; 353 } 354 355 var firstName = 356 pickField(fd, [ 357 "firstName", 358 "first-name", 359 "First-Name", 360 "fname", 361 "FirstName", 362 "given_name", 363 "given-name", 364 ]) || 365 findInputValueByDataName(form, /^first\s*name$/i) || 366 findInputValueByDataName(form, /^firstname$/i) || 367 findInputValueByDataName(form, /^given\s*name$/i); 368 var lastName = 369 pickField(fd, [ 370 "lastName", 371 "last-name", 372 "Last-Name", 373 "lname", 374 "LastName", 375 "surname", 376 ]) || 377 findInputValueByDataName(form, /^last\s*name$/i) || 378 findInputValueByDataName(form, /^lastname$/i) || 379 findInputValueByDataName(form, /^surname$/i); 380 var city = 381 pickField(fd, [ 382 "city", 383 "City", 384 "town", 385 "Town", 386 "hometown", 387 "HomeTown", 388 ]) || 389 findInputValueByDataName(form, /^city$/i) || 390 findInputValueByDataName(form, /^town$/i) || 391 findInputValueByDataName(form, /^hometown$/i); 392 393 return { 394 email: findEmail(form, fd), 395 firstName: firstName, 396 lastName: lastName, 397 city: city, 398 phone: pickField(fd, ["phone", "Phone", "tel", "telephone"]), 399 phoneFull: pickField(fd, [ 400 "phone_full", 401 "phone-full", 402 "Phone_Full", 403 "Phone_full", 404 ]), 405 listId: listId, 406 }; 407 } 408 409 /** 410 * The input element intl-tel-input was bound to. Webflow uses `type="text"` + `iti__tel-input`, not 411 * always `type="tel"`. 412 */ 413 function findIntlTelInput(form) { 414 if (!(form instanceof HTMLFormElement)) return null; 415 var byPluginAttr = form.querySelector("input[data-intl-tel-input-id]"); 416 if (byPluginAttr) return byPluginAttr; 417 var byClass = form.querySelector( 418 "input.iti__tel-input, input.intl-tel-input, input.intl-phone" 419 ); 420 if (byClass) return byClass; 421 var wrap = form.querySelector(".iti"); 422 if (wrap) { 423 var tel = wrap.querySelector('input[type="tel"]'); 424 if (tel) return tel; 425 var itiText = wrap.querySelector( 426 "input.iti__tel-input, input.intl-tel-input, input.intl-phone" 427 ); 428 if (itiText) return itiText; 429 var textTel = wrap.querySelector('input[type="text"][inputmode="tel"]'); 430 if (textTel) return textTel; 431 } 432 return form.querySelector('input[type="tel"]'); 433 } 434 435 function getIntlTelInstance(input) { 436 if (!input || typeof window.intlTelInput === "undefined") return null; 437 var g = window.intlTelInput; 438 if (typeof g.getInstance !== "function") return null; 439 try { 440 return g.getInstance(input); 441 } catch (e) { 442 return null; 443 } 444 } 445 446 /** 447 * Fills `payload.phoneFull` from intl-tel-input when present (requires utils: `iti.promise` first). 448 * If the instance exists but `isValidNumber()` is false, clears `phone_full` for Community. 449 * Sets `payload._intlTelMeta` when ITI is present: `{ hasInstance, isEmpty, isValid }` for submit validation. 450 */ 451 async function mergePhoneFullFromIntlTel(form, payload) { 452 log("intl-tel: mergePhoneFullFromIntlTel start"); 453 var input = findIntlTelInput(form); 454 if (!input) { 455 log("intl-tel: no intl-tel input found â using FormData phone_full only"); 456 return; 457 } 458 if (typeof window.intlTelInput === "undefined") { 459 log("intl-tel: window.intlTelInput missing â skip plugin merge"); 460 return; 461 } 462 var iti = getIntlTelInstance(input); 463 if (!iti) { 464 log("intl-tel: getInstance returned null â using FormData phone_full only"); 465 return; 466 } 467 468 try { 469 if (iti.promise && typeof iti.promise.then === "function") { 470 log("intl-tel: awaiting iti.promise (utils)"); 471 await iti.promise; 472 log("intl-tel: utils ready"); 473 } 474 } catch (e) { 475 warn("intl-tel: utils failed to load", e); 476 return; 477 } 478 479 var rawVal = String(input.value || "").trim(); 480 var isEmpty = rawVal === ""; 481 var countryData = 482 typeof iti.getSelectedCountryData === "function" 483 ? iti.getSelectedCountryData() 484 : null; 485 if (!isEmpty && !countryData) { 486 payload._intlTelMeta = { 487 hasInstance: true, 488 isEmpty: false, 489 isValid: false, 490 }; 491 log("intl-tel: digits entered but no country â clear phone_full, will validate"); 492 payload.phoneFull = ""; 493 return; 494 } 495 496 try { 497 if (typeof iti.isValidNumber !== "function" || typeof iti.getNumber !== "function") { 498 log("intl-tel: isValidNumber/getNumber not available â skip"); 499 payload._intlTelMeta = { 500 hasInstance: true, 501 isEmpty: isEmpty, 502 isValid: false, 503 }; 504 return; 505 } 506 if (!iti.isValidNumber()) { 507 payload._intlTelMeta = { 508 hasInstance: true, 509 isEmpty: isEmpty, 510 isValid: false, 511 };
512 log("intl-tel: not valid â clear phone_full for Community", { 513 masked: maskPhoneForLog(payload.phoneFull), 514 isEmpty: isEmpty, 515 }); 516 payload.phoneFull = ""; 517 return; 518 } 519 var num = iti.getNumber(); 520 if (num && String(num).trim()) { 521 payload.phoneFull = String(num).trim(); 522 log("intl-tel: phone_full set from getNumber", maskPhoneForLog(payload.phoneFull)); 523 if (!payload.phone || !String(payload.phone).trim()) { 524 payload.phone = payload.phoneFull; 525 } 526 } 527 payload._intlTelMeta = { 528 hasInstance: true, 529 isEmpty: isEmpty, 530 isValid: true, 531 }; 532 } catch (e) { 533 warn("intl-tel: isValidNumber/getNumber failed", e); 534 payload._intlTelMeta = { 535 hasInstance: true, 536 isEmpty: isEmpty, 537 isValid: false, 538 }; 539 } 540 } 541 542 /** True when ITI is present, user typed something, and the number is not valid (incomplete / wrong country). */ 543 function shouldAbortForInvalidIntlPhone(payload) { 544 var m = payload._intlTelMeta; 545 return !!(m && m.hasInstance && !m.isEmpty && !m.isValid); 546 } 547 548 /** Focus phone, optional country dropdown, and native validation message. */ 549 function flagInvalidIntlPhone(form) { 550 var input = findIntlTelInput(form); 551 if (!input) return; 552 input.focus(); 553 var iti = getIntlTelInstance(input); 554 if (iti && typeof iti.openDropdown === "function") { 555 try { 556 iti.openDropdown(); 557 } catch (e) { 558 /* ignore */ 559 } 560 } 561 var msg = 562 "Enter a valid phone number including country code (or clear the field)."; 563 if (typeof input.setCustomValidity === "function") { 564 input.setCustomValidity(msg); 565 input.reportValidity(); 566 var clear = function () { 567 input.setCustomValidity(""); 568 input.removeEventListener("input", clear); 569 input.removeEventListener("change", clear); 570 }; 571 input.addEventListener("input", clear); 572 input.addEventListener("change", clear); 573 } 574 } 575 576 function hasCommunityPhone(payload) { 577 return ( 578 payload.phoneFull != null && 579 String(payload.phoneFull).trim() !== "" 580 ); 581 } 582 583 /** Best-effort; failures are logged and the rest of the flow continues. */ 584 async function postCommunitySubscribe(payload) { 585 log("community: POST start", COMMUNITY_URL, { 586 phone: maskPhoneForLog(payload.phoneFull), 587 hasEmail: !!payload.email, 588 hasGivenName: !!payload.firstName, 589 hasSurname: !!payload.lastName, 590 hasCity: !!payload.city, 591 }); 592 try { 593 var body = { 594 phone_full: String(payload.phoneFull).trim(), 595 }; 596 var em = payload.email != null && String(payload.email).trim(); 597 if (em) body.email = String(em); 598 var gn = payload.firstName != null && String(payload.firstName).trim(); 599 if (gn) body.given_name = String(gn); 600 var sn = payload.lastName != null && String(payload.lastName).trim(); 601 if (sn) body.surname = String(sn); 602 var ct = payload.city != null && String(payload.city).trim(); 603 if (ct) body.city = String(ct); 604 605 var res = await fetch(COMMUNITY_URL, { 606 method: "POST", 607 headers: { 608 "Content-Type": "application/json", 609 Accept: "application/json", 610 }, 611 body: JSON.stringify(body), 612 }); 613 var ctext = await res.text(); 614 log("community: response", res.status, res.statusText, "bodyLen", ctext.length); 615 if (!res.ok) { 616 warn("community: error (continuing flow)", ctext.slice(0, 800)); 617 } else if (ctext) { 618 log("community: body preview", ctext.slice(0, 500)); 619 } else { 620 log("community: ok, empty body"); 621 } 622 } catch (err) { 623 warn("community: fetch failed (continuing flow)", err); 624 } 625 } 626 627 function getWaitText(submitBtn) { 628 if (!submitBtn) return "Please wait..."; 629 var w = submitBtn.getAttribute("data-wait"); 630 if (w != null && String(w).trim() !== "") return String(w).trim(); 631 return "Please wait..."; 632 } 633 634 function isInputSubmit(el) { 635 return el.tagName === "INPUT" && el.type === "submit"; 636 } 637 638 function getSubmitLabel(submitBtn) { 639 if (isInputSubmit(submitBtn)) return submitBtn.value; 640 return submitBtn.textContent || ""; 641 } 642 643 function setSubmitLabel(submitBtn, text) { 644 if (isInputSubmit(submitBtn)) submitBtn.value = text; 645 else submitBtn.textContent = text; 646 } 647 648 /** Webflow-style: show data-wait (or âPlease wait...â) and disable while our work runs. */ 649 function applySubmitWaitState(submitBtn) { 650 if (!submitBtn) { 651 log("ui: applySubmitWaitState â no submit button"); 652 return; 653 } 654 log("ui: submit wait state (data-wait / Please waitâ¦)"); 655 submitBtn[SUBMIT_LABEL_BACKUP] = getSubmitLabel(submitBtn); 656 setSubmitLabel(submitBtn, getWaitText(submitBtn)); 657 submitBtn.disabled = true; 658 } 659 660 function restoreSubmitButton(submitBtn) { 661 if (!submitBtn) return; 662 log("ui: restore submit button"); 663 if (submitBtn[SUBMIT_LABEL_BACKUP] !== undefined) { 664 setSubmitLabel(submitBtn, submitBtn[SUBMIT_LABEL_BACKUP]); 665 delete submitBtn[SUBMIT_LABEL_BACKUP]; 666 } 667 submitBtn.disabled = false;
668 } 669 670 /** Restore label + enable, then native submit on the next macrotask (outside submit-handler stack). */ 671 function handOffToWebflowSubmit(form, submitBtn) { 672 log("flow: schedule native Webflow submit (next task)"); 673 submitBtn = 674 submitBtn || 675 form.querySelector( 676 'input[type="submit"], button[type="submit"], button:not([type])' 677 ); 678 setTimeout(function () { 679 if (submitBtn) { 680 restoreSubmitButton(submitBtn); 681 } 682 if (!form.checkValidity()) { 683 warn( 684 "webflow: handoff aborted â HTML5 validation failed (fix highlighted fields and retry)" 685 ); 686 form.reportValidity(); 687 return; 688 } 689 submitWebflowNative(form, submitBtn); 690 }, 0); 691 } 692 693 function showFormState(form, state) { 694 var messages = getMessageElements(form); 695 var success = messages.success; 696 var fail = messages.fail; 697 698 log("UI state:", state, { 699 hasSuccessEl: !!success, 700 hasFailEl: !!fail, 701 }); 702 703 if (state === "success") { 704 form.style.display = "none"; 705 } else { 706 form.style.display = ""; 707 } 708 709 if (success) { 710 success.style.display = state === "success" ? "block" : "none"; 711 success.hidden = state !== "success"; 712 } 713 if (fail) { 714 fail.style.display = state === "error" ? "block" : "none"; 715 fail.hidden = state !== "error"; 716 } 717 } 718 719 /** 720 * Second-phase submit after handoff. `requestSubmit` throws if HTML5 validation fails â clear SKIP_FLAG 721 * and restore the button so the user is not stuck on âPlease waitâ¦â. 722 */ 723 function submitWebflowNative(form, submitBtn) { 724 submitBtn = 725 submitBtn || 726 form.querySelector( 727 'input[type="submit"], button[type="submit"], button:not([type])' 728 ); 729 form[SKIP_FLAG] = true; 730 try { 731 if (typeof form.requestSubmit === "function") { 732 log("webflow: requestSubmit()"); 733 form.requestSubmit(submitBtn || undefined); 734 } else { 735 log("webflow: form.submit() fallback"); 736 form.submit(); 737 } 738 } catch (err) { 739 delete form[SKIP_FLAG]; 740 warn( 741 "webflow: requestSubmit did not run (validation or browser) â restored submit", 742 err 743 ); 744 if (submitBtn) { 745 restoreSubmitButton(submitBtn); 746 } 747 } 748 } 749 750 async function handleSubmit(e) { 751 var form = e.target; 752 if (!(form instanceof HTMLFormElement)) { 753 return; 754 } 755 756 if (form[SKIP_FLAG]) { 757 log("event: skip intercept â second pass after handoff (Webflow native)"); 758 delete form[SKIP_FLAG]; 759 return; 760 } 761 762 log("event: submit", { formId: form.id || "(no id)" }); 763 764 var subscribeCb = getSubscribeCheckbox(form); 765 var hasSubscribeCheckbox = !!subscribeCb; 766 var subscribeChecked = !!(subscribeCb && subscribeCb.checked); 767 /** After our work, use native Webflow submit + Webflow UI (any form with data-subscribe). */ 768 var useWebflowHandoff = hasSubscribeCheckbox; 769 /** POST /leads only when there is no email opt-out checkbox, or it is checked. */ 770 var shouldPostLeads = !hasSubscribeCheckbox || subscribeChecked; 771 772 var listSource = getListSource(form); 773 if (!listSource) { 774 log("decision: no [data-listid] â pass through to Webflow only"); 775 return; 776 } 777 778 e.preventDefault(); 779 e.stopPropagation(); 780 e.stopImmediatePropagation(); 781 782 log("intercept", { 783 mode: useWebflowHandoff ? "Webflow handoff" : "leads + embedded success UI", 784 formAction: form.getAttribute("action"), 785 formId: form.id || "(no id)", 786 dataListid: listSource.getAttribute("data-listid"), 787 hasSubscribeCheckbox: hasSubscribeCheckbox, 788 subscribeChecked: hasSubscribeCheckbox ? subscribeChecked : "(n/a)", 789 shouldPostLeads: shouldPostLeads, 790 }); 791 792 var payload = collectPayload(form, listSource); 793 await mergePhoneFullFromIntlTel(form, payload); 794 log("payload after intl merge", { 795 email: payload.email ? "(present)" : "(missing)", 796 listId: payload.listId, 797 phone: maskPhoneForLog(payload.phone), 798 phoneFull: maskPhoneForLog(payload.phoneFull), 799 intlTelMeta: payload._intlTelMeta || "(none)", 800 }); 801 802 if (shouldAbortForInvalidIntlPhone(payload)) { 803 warn("validation: phone incomplete or invalid â fix or clear before submit"); 804 flagInvalidIntlPhone(form); 805 showFormState(form, "error"); 806 return; 807 } 808 809 var submitBtn = form.querySelector( 810 'input[type="submit"], button[type="submit"], button:not([type])' 811 ); 812 813 applySubmitWaitState(submitBtn); 814 815 try { 816 if (hasCommunityPhone(payload)) { 817 log("step: Community (phone_full present)"); 818 await postCommunitySubscribe(payload); 819 } else { 820 log("step: skip Community â no phone_full"); 821 } 822 823 if (!payload.email) { 824 warn("validation: no email"); 825 if (useWebflowHandoff) { 826 log("flow: no email â skip leads, Webflow only"); 827 handOffToWebflowSubmit(form, submitBtn); 828 } else { 829 log("flow: no email â show error (leads only)"); 830 showFormState(form, "error"); 831 } 832 return; 833 } 834 835 if (!shouldPostLeads) { 836 log("flow: email list opt-out â skip /leads, Webflow only"); 837 handOffToWebflowSubmit(form, submitBtn); 838 return; 839 } 840 841 log("step: ActiveCampaign /leads"); 842 var body = { email: payload.email }; 843 if (payload.firstName) body.firstName = payload.firstName; 844 if (payload.lastName) body.lastName = payload.lastName; 845 if (payload.phone) body.phone = payload.phone; 846 if (payload.city) body.city = payload.city; 847 if (payload.listId !== undefined) body.listId = payload.listId; 848 849 log("leads: POST", LEADS_URL, { 850 hasListId: body.listId !== undefined, 851 hasPhone: !!body.phone, 852 hasCity: !!body.city, 853 }); 854 855 var res = await fetch(LEADS_URL, { 856 method: "POST", 857 headers: { 858 "Content-Type": "application/json", 859 Accept: "application/json", 860 }, 861 body: JSON.stringify(body), 862 }); 863 864 log("leads: response", res.status, res.statusText, res.url); 865 866 if (useWebflowHandoff) { 867 if (res.ok) { 868 log("leads: ok â then Webflow"); 869 try { 870 var okJson = await res.json(); 871 if (okJson) log("leads: body", okJson); 872 } catch (ignore) {} 873 } else { 874 var errTextWf = await res.text(); 875 warn("leads: error (Webflow will still submit)", errTextWf.slice(0, 800)); 876 } 877 handOffToWebflowSubmit(form, submitBtn); 878 } else { 879 if (res.ok) { 880 try { 881 var okJson2 = await res.json(); 882 if (okJson2) log("leads: body", okJson2); 883 } catch (ignore) {} 884 log("flow: leads success â showFormState success"); 885 showFormState(form, "success"); 886 } else { 887 var errText = await res.text(); 888 warn("leads: error body", errText.slice(0, 800)); 889 log("flow: leads error â showFormState error"); 890 showFormState(form, "error"); 891 } 892 } 893 } catch (err) { 894 warn("leads: fetch threw", err); 895 if (useWebflowHandoff) { 896 log("flow: after leads throw â hand off to Webflow"); 897 handOffToWebflowSubmit(form, submitBtn); 898 } else { 899 log("flow: after leads throw â showFormState error"); 900 showFormState(form, "error"); 901 } 902 } finally { 903 if (submitBtn && !useWebflowHandoff) { 904 log("finally: restore submit (legacy leads-only path)"); 905 restoreSubmitButton(submitBtn); 906 } 907 } 908 } 909 910 log( 911 "initialized â [data-listid]: Community if phone; /leads when email opt-in; data-subscribe = email only" 912 ); 913 document.addEventListener("submit", handleSubmit, true); 914})(); 915</script>
915</body></html>
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.