(function () { var HOME_TITLE = 'Canadian firearms, read straight.'; var HOME_BODY = 'Precision, gear, handloading, and the policy file that actually affects licensed owners. The Dispatch is one email a week. Evidence over outrage, sent only when there is something worth sending.'; var HOME_BUTTON = 'Subscribe to The Dispatch'; var APP_STORE_URL = 'https://apps.apple.com/ca/app/holdover-tools/id6772333585'; var APP_BADGE_URL = 'https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg'; var waitingSignup = null; var sentSignup = false; function onReady(fn) { if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); else fn(); } function plausible(name, props) { if (typeof window.plausible !== 'function') return; window.plausible(name, props ? { props: props } : undefined); } function pagePath() { return location.pathname || '/'; } function campaignFromTarget(target) { var holder = target && target.closest ? target.closest('a[href],button,[data-members-form],.gh-cta,.ho-lead-magnet') : null; var href = holder && holder.getAttribute ? (holder.getAttribute('href') || holder.href || '') : ''; try { var url = href ? new URL(href, location.origin) : null; var campaign = url && url.searchParams.get('utm_campaign'); if (campaign) return campaign; } catch (error) {} if (holder && holder.getAttribute && holder.getAttribute('data-ho-campaign')) return holder.getAttribute('data-ho-campaign'); if (pagePath() === '/') return 'homepage-dispatch'; return 'dispatch'; } function leadTarget(target) { var el = target && target.closest ? target.closest('a[href],button,.gh-button') : null; if (!el) return null; var href = el.getAttribute ? (el.getAttribute('href') || el.href || '') : ''; if (/\/dispatch\/|\butm_medium=lead-magnet\b/i.test(href)) return el; if (el.closest && el.closest('.ho-lead-magnet,.gh-cta')) return el; return null; } function fireLeadClick(target) { var campaign = campaignFromTarget(target); try { sessionStorage.setItem('hoLeadCampaign', campaign); } catch (error) {} plausible('Lead Magnet CTA: Click', { page: pagePath(), campaign: campaign }); } function startSignup(target) { waitingSignup = { page: pagePath(), campaign: campaignFromTarget(target) || readLastCampaign() }; } function readLastCampaign() { try { return sessionStorage.getItem('hoLeadCampaign') || 'dispatch'; } catch (error) { return 'dispatch'; } } function completeSignup() { if (!waitingSignup || sentSignup) return; sentSignup = true; plausible('Dispatch Signup: Complete', { page: waitingSignup.page || pagePath(), campaign: waitingSignup.campaign || readLastCampaign() }); } function formLooksSuccessful(form) { if (!form) return false; var state = String(form.getAttribute('data-members-form') || form.className || ''); if (/success/i.test(state)) return true; var successNode = form.querySelector('[data-members-success],.gh-form-success,.success'); if (!successNode) return false; return successNode.offsetParent !== null || successNode.getAttribute('aria-hidden') !== 'true'; } function watchMemberForms() { document.addEventListener('click', function (event) { var appTarget = appCtaTarget(event.target); if (appTarget) { plausible('App Store CTA: Click', { page: pagePath(), placement: appTarget.getAttribute('data-ho-app-placement') || 'unknown' }); return; } var target = leadTarget(event.target); if (target) fireLeadClick(target); }, true); document.addEventListener('submit', function (event) { if (event.target && event.target.matches && event.target.matches('[data-members-form]')) { startSignup(event.target); } }, true); if (!window.MutationObserver) return; var observer = new MutationObserver(function () { if (!waitingSignup) return; document.querySelectorAll('[data-members-form]').forEach(function (form) { if (formLooksSuccessful(form)) completeSignup(); }); }); observer.observe(document.documentElement, { attributes: true, childList: true, subtree: true }); } function patchNetworkCompletion() { if (window.fetch) { var originalFetch = window.fetch; window.fetch = function () { var request = arguments[0]; var requestUrl = typeof request === 'string' ? request : (request && request.url) || ''; return originalFetch.apply(this, arguments).then(function (response) { if (waitingSignup && response && response.ok && /\/members\/api\//.test(requestUrl)) completeSignup(); return response; }); }; } if (window.XMLHttpRequest && XMLHttpRequest.prototype.open && XMLHttpRequest.prototype.send) { var originalOpen = XMLHttpRequest.prototype.open; var originalSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function (method, url) { this.hoGrowthUrl = String(url || ''); return originalOpen.apply(this, arguments); }; XMLHttpRequest.prototype.send = function () { this.addEventListener('load', function () { if (waitingSignup && /\/members\/api\//.test(this.hoGrowthUrl || '') && this.status >= 200 && this.status < 400) completeSignup(); }); return originalSend.apply(this, arguments); }; } } function applyHomepageCapture() { if (pagePath() !== '/') return; var title = document.querySelector('.gh-cta-title'); var body = document.querySelector('.gh-cta-description'); var button = document.querySelector('.gh-cta .gh-button span span'); if (title) title.textContent = HOME_TITLE; if (body) body.textContent = HOME_BODY; if (button) button.textContent = HOME_BUTTON; } function appStoreHref(placement) { var url = new URL(APP_STORE_URL); url.searchParams.set('utm_source', 'holdover'); url.searchParams.set('utm_medium', 'site'); url.searchParams.set('utm_campaign', 'holdover-tools-ios'); url.searchParams.set('utm_content', placement); return url.toString(); } function appCtaTarget(target) { return target && target.closest ? target.closest('[data-ho-app-cta]') : null; } function injectAppDownloadStyle() { if (document.getElementById('ho-app-download-style')) return; var style = document.createElement('style'); style.id = 'ho-app-download-style'; style.textContent = [ '.ho-app-download,.ho-app-download *{box-sizing:border-box}', '.ho-app-download{--ho-bg:var(--bg,#faf6ec);--ho-card:var(--bg-card,#fffdfa);--ho-dark:var(--ink,#15171a);--ho-muted:var(--ink-dim,#444);--ho-faint:var(--ink-faint,#777);--ho-rule:var(--rule,#d8d2c7);--ho-red:var(--red,#d8272e);background:var(--ho-bg);color:var(--ho-dark);font-family:var(--serif,Georgia,serif);margin:0 calc(50% - 50vw);width:100vw}', '.ho-app-download a{border:0!important;text-decoration:none!important}', '.ho-app-download-inner{display:grid;gap:26px;grid-template-columns:minmax(0,.82fr) minmax(0,1.35fr) auto;margin:0 auto;max-width:1480px;padding:34px 40px;position:relative}', '.ho-app-download-inner::before{background:var(--ho-red);content:"";height:12px;left:40px;position:absolute;top:34px;width:12px}', '.ho-app-download-kicker{color:var(--ho-muted);font-family:var(--mono,ui-monospace,monospace);font-size:10.5px;font-weight:700;letter-spacing:2px;line-height:1;margin:4px 0 14px 24px;text-transform:uppercase}', '.ho-app-download-title{color:var(--ho-dark)!important;font-family:var(--serif,Georgia,serif)!important;font-size:clamp(31px,3vw,48px)!important;font-weight:400!important;letter-spacing:0!important;line-height:1.04!important;margin:0!important;max-width:13ch;text-wrap:balance}', '.ho-app-download-copy{align-self:end;border-left:1px solid var(--ho-rule);padding-left:24px}', '.ho-app-download-copy p{color:var(--ho-muted);font-family:var(--serif,Georgia,serif);font-size:17px;line-height:1.48;margin:0;max-width:48ch}', '.ho-app-download-meta{color:var(--ho-faint);font-family:var(--mono,ui-monospace,monospace);font-size:10px;font-weight:700;letter-spacing:1.7px;line-height:1.5;margin-top:13px;text-transform:uppercase}', '.ho-app-download-actions{align-self:end;display:grid;gap:10px;justify-items:end}', '.ho-app-download-badge{display:block;line-height:0;transition:filter 140ms ease,transform 140ms ease}', '.ho-app-download-badge img{display:block;height:auto!important;max-width:156px!important;width:156px!important}', '.ho-app-download-badge:hover,.ho-app-download-badge:focus-visible{filter:brightness(1.08);outline:0;transform:translateY(-1px)}', '.ho-app-download-note{color:var(--ho-faint);font-family:var(--mono,ui-monospace,monospace);font-size:9.5px;font-weight:700;letter-spacing:1.4px;line-height:1.35;text-align:right;text-transform:uppercase}', '.ho-app-download.is-home{border-bottom:2px solid var(--ho-dark);border-top:1px solid var(--ho-rule)}', '.ho-app-download.is-footer{background:var(--ho-dark);color:var(--ho-bg);margin-top:0}', '.ho-app-download.is-footer .ho-app-download-inner{grid-template-columns:minmax(0,.95fr) minmax(0,1.25fr) auto;padding-bottom:30px;padding-top:30px}', '.ho-app-download.is-footer .ho-app-download-inner::before{top:30px}', '.ho-app-download.is-footer .ho-app-download-title{color:var(--ho-bg)!important;font-size:clamp(27px,2.2vw,38px)!important;max-width:16ch}', '.ho-app-download.is-footer .ho-app-download-kicker,.ho-app-download.is-footer .ho-app-download-copy p,.ho-app-download.is-footer .ho-app-download-meta,.ho-app-download.is-footer .ho-app-download-note{color:rgba(250,246,236,.68)}', '.ho-app-download.is-footer .ho-app-download-copy{border-left-color:rgba(250,246,236,.18)}', '@media (max-width:900px){.ho-app-download-inner,.ho-app-download.is-footer .ho-app-download-inner{grid-template-columns:1fr;gap:18px;padding:30px 20px}.ho-app-download-inner::before,.ho-app-download.is-footer .ho-app-download-inner::before{left:20px;top:30px}.ho-app-download-title{max-width:18ch}.ho-app-download-copy{border-left:0;border-top:1px solid var(--ho-rule);padding-left:0;padding-top:18px}.ho-app-download.is-footer .ho-app-download-copy{border-top-color:rgba(250,246,236,.18)}.ho-app-download-actions{justify-items:start}.ho-app-download-note{text-align:left}}', '@media (max-width:520px){.ho-app-download-title{font-size:32px!important}.ho-app-download-copy p{font-size:16px}.ho-app-download-badge img{max-width:150px!important;width:150px!important}}' ].join(''); document.head.appendChild(style); } function buildAppDownloadCta(options) { var placement = options.placement; var section = document.createElement('section'); section.className = 'ho-app-download ' + options.className; section.setAttribute('aria-labelledby', options.headingId); section.innerHTML = [ '
' + options.copy + '
', '', '