{"id":478,"date":"2025-12-11T18:39:36","date_gmt":"2025-12-11T18:39:36","guid":{"rendered":"https:\/\/staging.buddyupgo.com\/?page_id=478"},"modified":"2025-12-11T18:39:36","modified_gmt":"2025-12-11T18:39:36","slug":"subscription-tiers","status":"publish","type":"page","link":"https:\/\/staging.buddyupgo.com\/subscription-tiers\/","title":{"rendered":"Subscription Tiers"},"content":{"rendered":"<div class=\"buddyUpPjaxContainer\" data-buddyup-pjax-container=\"1\"><style>#subscriptionTiers,section#tiersOverview,section#tiersFootNotes{width:90%;max-width:1200px;margin:0 auto;padding:0 15px}#subscriptionTiers{display:flex;flex-direction:column}section#subscriptionTiers{background-image:url(\/wp-content\/uploads\/interests-bg.jpg);background-position:center;background-repeat:no-repeat;background-size:cover;border-radius:var(--buddyup-panel-radius);padding:clamp(20px,5vw,40px)}section#tiersOverview{border-radius:var(--buddyup-panel-radius);padding:clamp(20px,5vw,40px);margin:clamp(20px,5vw,40px) auto;text-align:center}section#tiersFootNotes{margin:0 auto 40px;font-size:clamp(.75rem,1.5vw,.9rem);color:#555}.centeredHeader{text-align:center;padding:20px 0}.centeredHeader h1{font-style:italic;font-weight:600;font-size:clamp(1.5rem,5vw,2.5rem);margin-bottom:.5rem}.tiercardContainer{display:flex;justify-content:center;gap:clamp(20px,4vw,30px);flex-wrap:wrap;margin:0 auto;flex-direction:row}.tierCard{display:flex;flex-direction:column;align-items:center;border:1px solid #ccc;border-radius:var(--buddyup-panel-radius);padding:clamp(15px,4vw,20px);text-align:center;background-color:var(--buddyup-background);width:350px;transition:transform .3s ease}.tierCard:hover{transform:scale(1.05)}.tierCard h2{font-weight:600;font-size:clamp(1.2rem,3vw,1.5rem);margin:0;padding:0}.tierCard h3{font-style:italic;font-size:clamp(.9rem,2vw,1.1rem);margin:5px 0 10px;padding:0}.tierCard ul.featuresList{font-size:clamp(.85rem,2vw,1rem);padding-top:unset;justify-self:center}.tierCard ul.featuresList li{text-align:left;list-style:disc;padding:0}.tierCard ul.featuresList li:before{content:\"\"}.buttonContainer{margin:0 auto!important}.subscribeButton{background-color:var(--primary-color);color:#fff;border:none;border-radius:999px;padding:10px 20px;font-size:clamp(.9rem,2vw,1rem);cursor:pointer;transition:background-color .3s ease}section#tiersOverview table{margin:0 auto;width:100%;border-collapse:collapse;border-radius:var(--buddyup-control-radius);font-size:clamp(.85rem,2vw,1rem)}section#tiersOverview td,section#tiersOverview th{padding:clamp(8px,2vw,12px);text-align:center;vertical-align:top;line-height:1.4}.buddyUpSubscriptionNativeNotice{background:#eef7fb;border:1px solid #bad8e5;border-radius:12px;color:#12345a;line-height:1.5;margin:0 0 20px;padding:14px 16px;text-align:center;width:100%}section#tiersOverview tbody th{width:16%;color:var(--buddyup-ink);text-align:left;font-weight:800}section#tiersOverview tbody tr:nth-child(2n){background:var(--buddyup-surface-soft)}section#tiersOverview table#desktopViewTable thead,section#tiersOverview .tierCardsOverview thead.tierNameTableMobile{background-color:var(--buddyup-background);color:#000}section#tiersOverview .tierCardsOverview tbody.featureNameTableMobile{background-color:#fff;color:#000}section#tiersOverview .tierCardsOverview{display:none}@media (max-width: 870px){section#tiersOverview,section#subscriptionTiers .tierCard{width:300px;align-items:unset}section#tiersOverview{padding:0}section#tiersOverview table#desktopViewTable{display:none}section#tiersOverview .tierCardsOverview{display:grid;grid-template-columns:1fr;gap:15px}.tiercardContainer{grid-template-columns:1fr;margin:0 auto}}@media (max-width: 480px){#subscriptionTiers,section#tiersOverview,section#tiersFootNotes{padding:10px}.tierCard{padding:15px}}@media (max-width: 355px){section#subscriptionTiers .tierCard{width:100%}}section#subscriptionTiers{width:100%;max-width:var(--buddyup-page-width)!important;border-radius:0;background-image:none}#subscriptionTiers .buddyUpPageHeader{width:100%}\n<\/style>\n<script>\n    \/\/ Prime state from cached login data, but keep UI in loading mode until account-get confirms.\n    (function() {\n        function normalizeTier(t) {\n            t = parseInt(t);\n            if (isNaN(t)) t = 0;\n            if (![0, 1, 2].includes(t)) t = 0;\n            return t;\n        }\n\n        function normalizeResubscribeFlag(value) {\n            if (value === true || value === 1 || value === '1') return 1;\n            var raw = String(value || '').toLowerCase().trim();\n            return ['true', 'yes', 'on'].includes(raw) ? 1 : 0;\n        }\n\n        document.documentElement.setAttribute('data-buddyup-sub-ui', 'loading');\n\n        try {\n            const raw = window.localStorage ? localStorage.getItem('buddyup_user') : null;\n            if (!raw) return;\n            const user = JSON.parse(raw);\n\n            let tier = (typeof user.user_subscription !== 'undefined' ? user.user_subscription : null);\n            tier = tier === null && typeof user.subscription !== 'undefined' ? user.subscription : tier;\n            tier = tier === null && typeof user.subscription_tier !== 'undefined' ? user.subscription_tier : tier;\n            tier = tier === null && typeof user.tier !== 'undefined' ? user.tier : tier;\n\n            document.documentElement.setAttribute('data-buddyup-tier', String(normalizeTier(tier)));\n\n            var canResubscribe = 0;\n            if (typeof user.subscription_can_resubscribe !== 'undefined') {\n                canResubscribe = normalizeResubscribeFlag(user.subscription_can_resubscribe);\n            } else {\n                var status = String(user.subscription_status || '').toLowerCase().trim();\n                if (['closed', 'cancelled', 'canceled', 'inactive', 'ended', 'expired', 'refunded'].includes(status)) {\n                    canResubscribe = 1;\n                }\n            }\n            document.documentElement.setAttribute('data-buddyup-can-resubscribe', String(canResubscribe));\n        } catch (e) {\n            \/\/ no-op\n        }\n    })();\n<\/script>\n\n<style>\n    #buddyUpSubscriptionCards {\n        display: grid;\n        grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));\n        gap: 20px;\n        width: 100%;\n        margin: 0 0 20px;\n    }\n\n    .buddyUpTierCard {\n        background: #fff;\n        border: 1px solid var(--buddyup-outline);\n        border-radius: 20px;\n        padding: clamp(1.25rem, 3vw, 1.75rem);\n        box-shadow: var(--buddyup-shadow-sm);\n        display: flex;\n        flex-direction: column;\n    }\n\n    .buddyUpTierCard h3 {\n        margin: 0 0 10px;\n        color: var(--buddyup-ink);\n        font-size: 1.5rem;\n    }\n\n    .buddyUpTierPrice {\n        min-height: 2.4rem;\n        margin: -.15rem 0 1rem;\n        color: var(--buddyup-ink);\n        font-size: 1.55rem;\n        font-weight: 850;\n        line-height: 1.2;\n    }\n\n    .buddyUpTierPrice small {\n        color: var(--buddyup-muted);\n        font-size: .82rem;\n        font-weight: 700;\n    }\n\n    .buddyUpTierInlinePrice {\n        display: block;\n        margin-top: .25rem;\n        color: var(--buddyup-muted);\n        font-size: .82rem;\n        font-weight: 700;\n        line-height: 1.3;\n    }\n\n    .buddyUpTierCard ul {\n        flex: 1;\n        margin: 0 0 1rem;\n        padding: 0;\n        display: grid;\n        gap: .65rem;\n        list-style: none;\n    }\n\n    .buddyUpTierCard li {\n        position: relative;\n        padding-left: 1.55rem;\n        color: var(--buddyup-text);\n        line-height: 1.45;\n    }\n\n    .buddyUpTierCard li::before {\n        content: \"\u2713\";\n        position: absolute;\n        left: 0;\n        color: var(--tertiary-color);\n        font-weight: 900;\n    }\n\n    .buddyUpTierCard .buddyUpButton1 {\n        display: inline-block;\n        text-decoration: none;\n        cursor: pointer;\n        width: 100%;\n        margin-top: auto;\n    }\n\n    #subscriptionTiers {\n        padding-block: clamp(1rem, 3vw, 2rem) 5rem;\n        background: transparent;\n    }\n\n    #buddyUpCardEnthusiast {\n        border-color: rgba(217, 63, 12, .28);\n        background: linear-gradient(160deg, #fff 0%, #fff8f4 100%);\n        box-shadow: var(--buddyup-shadow-md);\n    }\n\n    .buddyUpTierKicker {\n        display: inline-flex;\n        align-self: flex-start;\n        margin-bottom: .65rem;\n        padding: .25rem .55rem;\n        border-radius: 999px;\n        background: var(--buddyup-surface-soft);\n        color: var(--buddyup-muted);\n        font-size: .74rem;\n        font-weight: 800;\n        letter-spacing: .08em;\n        text-transform: uppercase;\n    }\n\n    #buddyUpCardEnthusiast .buddyUpTierKicker {\n        background: rgba(217, 63, 12, .1);\n        color: #a5320c;\n    }\n\n    #buddyUpTier2Already {\n        display: none;\n        padding: 18px;\n        border-radius: 12px;\n        border: 1px solid rgba(0,0,0,0.08);\n        background: #f8f9fb;\n        width: 100%;\n        text-align: center;\n        margin: 0 0 20px;\n    }\n\n    \/* Hide cards based on tier unless this user is eligible to resubscribe now. *\/\n    html[data-buddyup-tier=\"1\"]:not([data-buddyup-can-resubscribe=\"1\"]) #buddyUpCardAdventurer { display: none; }\n    html[data-buddyup-tier=\"2\"]:not([data-buddyup-can-resubscribe=\"1\"]) #buddyUpSubscriptionCards { display: none; }\n    html[data-buddyup-tier=\"2\"]:not([data-buddyup-can-resubscribe=\"1\"]) #buddyUpTier2Already { display: block; }\n\n    \/* Prevent stale-state flash: keep cards\/message hidden until first live account check settles. *\/\n    #buddyUpSubscriptionLoading {\n        display: none;\n        width: 100%;\n        text-align: center;\n        margin: 0 0 20px;\n        padding: 14px 16px;\n        border: 1px dashed rgba(0,0,0,0.18);\n        border-radius: 12px;\n        background: #f8f9fb;\n        color: #444;\n        font-size: 0.95rem;\n    }\n\n    html[data-buddyup-sub-ui=\"loading\"] #buddyUpSubscriptionCards,\n    html[data-buddyup-sub-ui=\"loading\"] #buddyUpTier2Already {\n        display: none;\n    }\n\n    html[data-buddyup-sub-ui=\"loading\"] #buddyUpSubscriptionLoading {\n        display: block;\n    }\n\n    \/* Checkout modal styles *\/\n    #buddyUpCheckoutOverlay {\n        position: fixed;\n        top: 0; left: 0; right: 0; bottom: 0;\n        background: rgba(0,0,0,0.5);\n        z-index: 99999;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n    }\n    #buddyUpCheckoutModal {\n        background: #fff;\n        border-radius: 14px;\n        width: 95vw;\n        max-width: 520px;\n        height: auto;\n        max-height: min(85vh, 760px);\n        display: flex;\n        flex-direction: column;\n        overflow: hidden;\n        box-shadow: 0 12px 40px rgba(0,0,0,0.18);\n    }\n    #buddyUpCheckoutHeader {\n        display: flex;\n        justify-content: space-between;\n        align-items: center;\n        padding: 14px 18px;\n        border-bottom: 1px solid #eee;\n    }\n    #buddyUpCheckoutHeader h3 { margin: 0; font-size: 16px; }\n    #buddyUpCheckoutClose {\n        background: none; border: none; font-size: 22px; cursor: pointer; color: #888; padding: 0 4px;\n    }\n    #buddyUpCheckoutClose:hover { color: #333; }\n    #buddyUpCheckoutBody {\n        flex: 0 1 auto;\n        overflow-y: auto;\n        overflow-x: hidden;\n        position: relative;\n        max-height: calc(min(85vh, 760px) - 55px);\n    }\n    #buddyUpCheckoutBody iframe {\n        width: 100%;\n        height: 100%;\n        min-height: 620px;\n        border: none;\n        display: block;\n    }\n\n    #buddyUpSubscriptionStatusNotice {\n        display: none;\n        width: 100%;\n        margin: 0 0 20px;\n        padding: 12px 16px;\n        border: 1px solid rgba(31, 77, 101, .2);\n        border-radius: 12px;\n        background: #f4f9fb;\n        color: var(--buddyup-text);\n        line-height: 1.45;\n    }\n\n    #buddyUpSubscriptionStatusNotice.isVisible {\n        display: block;\n    }\n    #buddyUpStripeCheckoutForm {\n        margin: 0;\n    }\n\n    #buddyUpStripePaymentElement {\n        padding: 18px 18px 10px;\n    }\n\n    #buddyUpStripePaymentMessage {\n        padding: 0 18px 10px;\n        color: #b00020;\n        display: none;\n    }\n\n    .buddyUpStripeCheckoutActions {\n        padding: 0 18px 18px;\n        display: flex;\n        gap: .6rem;\n        align-items: center;\n        justify-content: flex-end;\n    }\n    #buddyUpCheckoutLoading {\n        position: absolute;\n        top: 0; left: 0; right: 0; bottom: 0;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        background: #fff;\n        font-size: 15px;\n        color: #666;\n    }\n    #buddyUpCheckoutProcessing {\n        position: absolute;\n        top: 0; left: 0; right: 0; bottom: 0;\n        display: none;\n        align-items: center;\n        justify-content: center;\n        background: rgba(255,255,255,0.94);\n        text-align: center;\n        z-index: 2;\n        padding: 20px;\n    }\n    .buddyUpCheckoutProcessingInner {\n        max-width: 340px;\n    }\n    .buddyUpCheckoutSpinner {\n        width: 34px;\n        height: 34px;\n        border-radius: 50%;\n        border: 3px solid #d9d9d9;\n        border-top-color: #3d7ef0;\n        margin: 0 auto 12px;\n        animation: buddyUpCheckoutSpin 0.9s linear infinite;\n    }\n    @keyframes buddyUpCheckoutSpin {\n        to { transform: rotate(360deg); }\n    }\n    #buddyUpCheckoutSuccess {\n        display: none;\n        text-align: center;\n        padding: 40px 24px;\n    }\n    #buddyUpCheckoutSuccess i { font-size: 48px; color: #34a853; margin-bottom: 14px; }\n\n    #buddyUpCheckoutProfileModal .buddyUpModalContent,\n    #buddyUpCheckoutProfileModal .buddyUpModalInner {\n        max-width: 760px;\n    }\n\n    #buddyUpCheckoutProfileForm {\n        --checkout-soft-bg: rgba(67, 126, 146, 0.08);\n        --checkout-border: rgba(0, 0, 0, 0.09);\n        --checkout-focus: rgba(67, 126, 146, 0.35);\n        max-width: 720px;\n        margin: 0 auto;\n        padding: 4px 2px 0;\n    }\n\n    .buddyUpCheckoutProfileIntro {\n        margin: 0 0 1rem;\n        padding: .85rem 1rem;\n        border-radius: 14px;\n        border: 1px solid rgba(67, 126, 146, 0.18);\n        background: linear-gradient(135deg, rgba(67,126,146,.12), rgba(217,63,12,.06));\n        color: #263238;\n        line-height: 1.42;\n        text-align: left;\n    }\n\n    .buddyUpCheckoutProfileGrid {\n        display: grid;\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n        gap: 14px 16px;\n        align-items: start;\n    }\n\n    .buddyUpCheckoutProfileGrid .buddyUpInputWrapper {\n        margin: 0;\n        padding: 0;\n        display: grid;\n        gap: .4rem;\n    }\n\n    .buddyUpCheckoutProfileGrid label {\n        margin: 0;\n        color: #2f3437;\n        font-size: .92rem;\n        font-weight: 700;\n        line-height: 1.2;\n        text-align: left;\n    }\n\n    .buddyUpCheckoutProfileGrid input[type=\"text\"],\n    .buddyUpCheckoutProfileGrid input[type=\"tel\"] {\n        width: 100%;\n        min-height: 44px;\n        border-radius: 12px;\n        border: 1px solid var(--buddyup-control-border, rgba(0,0,0,.16));\n        background: var(--buddyup-control-bg, #fff);\n        box-shadow: 0 1px 0 rgba(0,0,0,.03);\n        padding: .65rem .8rem;\n        font: inherit;\n        transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;\n    }\n\n    .buddyUpCheckoutProfileGrid input[type=\"text\"]:focus,\n    .buddyUpCheckoutProfileGrid input[type=\"tel\"]:focus {\n        outline: none;\n        border-color: var(--buddyup-control-border-focus, rgba(67,126,146,.55));\n        box-shadow: 0 0 0 4px var(--checkout-focus);\n        background: #fff;\n    }\n\n    .buddyUpCheckoutProfileGrid .fullWidth {\n        grid-column: 1 \/ -1;\n    }\n    #checkoutBillingAddressFields {\n        display: grid;\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n        gap: 14px 16px;\n        padding: 1rem;\n        border-radius: 14px;\n        border: 1px dashed rgba(67, 126, 146, 0.35);\n        background: rgba(67, 126, 146, 0.045);\n    }\n\n    #checkoutBillingAddressFields.hidden {\n        display: none;\n    }\n\n    #buddyUpCheckoutProfileError {\n        margin-top: .9rem;\n        padding: .7rem .85rem;\n        border-radius: 12px;\n        background: rgba(173, 2, 16, .08);\n        color: var(--buddyup-red);\n        text-align: center;\n    }\n\n    #buddyUpCheckoutProfileError.hidden {\n        display: none;\n    }\n\n    .buddyUpCheckoutProfileActions {\n        display: flex;\n        flex-wrap: wrap;\n        gap: .65rem;\n        justify-content: flex-end;\n        align-items: center;\n        margin-top: 1.2rem;\n        padding-top: 1rem;\n        border-top: 1px solid rgba(0,0,0,.08);\n    }\n\n    .buddyUpCheckoutProfileActions [class*=\"buddyUpButton\"] {\n        margin-top: 0;\n    }\n\n    @media (max-width: 700px) {\n        .buddyUpCheckoutProfileGrid,\n            #checkoutBillingAddressFields {\n            grid-template-columns: 1fr;\n        }\n\n        .buddyUpCheckoutProfileActions {\n            justify-content: stretch;\n        }\n\n        .buddyUpCheckoutProfileActions button {\n            flex: 1 1 140px;\n        }\n    }\n    @media (max-width: 600px) {\n        #buddyUpCheckoutModal { width: 100vw; max-width: 100vw; height: var(--buddyup-mobile-usable-vh, 100dvh); max-height: var(--buddyup-mobile-usable-vh, 100dvh); border-radius: 0; }\n        #buddyUpCheckoutBody { flex: 1 1 auto; max-height: none; min-height: calc(var(--buddyup-mobile-usable-vh, 100dvh) - 60px); }\n    }\n<\/style>\n\n<section id=\"subscriptionTiers\" class=\"flexWrapper buddyUpContainer\"\n         data-subscription-terms-url=\"https:\/\/staging.buddyupgo.com\/mobile-application-and-website-end-user-license-agreement\/\"\n         data-privacy-url=\"https:\/\/staging.buddyupgo.com\/privacy-policy\/\"\n         data-subscription-terms-version=\"pre-aws-2026-08-27\">\n\n    <div class=\"buddyUpPageHeader\">\n        <div>\n            <span class=\"buddyUpPageEyebrow\">Choose how you adventure<\/span>\n            <h1 class=\"textH1\">Membership<\/h1>\n            <p class=\"buddyUpPageLead\">Unlock more connections, creation tools, and privacy controls as your BuddyUp community grows.<\/p>\n        <\/div>\n    <\/div>\n\n    <div id=\"buddyUpSubscriptionLoading\">Checking your subscription status...<\/div>\n\n    <div id=\"buddyUpSubscriptionStatusNotice\" role=\"status\" aria-live=\"polite\"><\/div>\n\n    \n            <fieldset id=\"buddyUpBillingPeriod\" style=\"border:0;margin:1rem auto;padding:0;text-align:center;\">\n            <legend style=\"font-weight:700;margin-bottom:.5rem;\">Billing period<\/legend>\n            <label style=\"margin-right:1rem;\"><input type=\"radio\" name=\"buddyup_billing_interval\" value=\"month\" checked \/> Monthly<\/label>\n            <label><input type=\"radio\" name=\"buddyup_billing_interval\" value=\"year\" \/> Annual<\/label>\n            <p class=\"textSmall\" style=\"margin:.5rem 0 0;\">Paid plans renew automatically until canceled. Cancel at least 24 hours before renewal.<\/p>\n        <\/fieldset>\n    \n    <div id=\"buddyUpTier2Already\">\n        <h3>You are already subscribed (Enthusiast).<\/h3>\n        <p>No upgrades are available at this time.<\/p>\n    <\/div>\n\n    <div id=\"buddyUpSubscriptionCards\">\n        <div class=\"buddyUpTierCard\" id=\"buddyUpCardAdventurer\">\n            <span class=\"buddyUpTierKicker\">More ways to connect<\/span>\n            <h3>Adventurer<\/h3>\n            <p class=\"buddyUpTierPrice\" data-stripe-price=\"adventurer\" aria-live=\"polite\"><small>Loading current price\u2026<\/small><\/p>\n            <ul>\n                                    <li>Unlimited right-swipes and messaging<\/li>\n                                    <li>Create up to 3 premium groups and 4 events per month<\/li>\n                                    <li>Up to 75 buddies<\/li>\n                                    <li>Up to 3 profile videos<\/li>\n                                    <li>Enhanced event comments (up to 3 media items)<\/li>\n                                    <li>Planned: advanced planning\/filter tools<\/li>\n                            <\/ul>\n                            <button class=\"buddyUpButton1\" data-tier=\"1\" data-product=\"adventurer\" onclick=\"buddyUpStartCheckout(this)\">Purchase Adventurer<\/button>\n                    <\/div>\n\n        <div class=\"buddyUpTierCard\" id=\"buddyUpCardEnthusiast\">\n            <span class=\"buddyUpTierKicker\">Most flexibility<\/span>\n            <h3>Enthusiast<\/h3>\n            <p class=\"buddyUpTierPrice\" data-stripe-price=\"enthusiast\" aria-live=\"polite\"><small>Loading current price\u2026<\/small><\/p>\n            <ul>\n                                    <li>See who swiped right on you<\/li>\n                                    <li>Ad-free experience<\/li>\n                                    <li>Create up to 15 premium groups + unlimited events<\/li>\n                                    <li>Up to 1,500 buddies<\/li>\n                                    <li>Comprehensive privacy controls<\/li>\n                                    <li>Profile videos up to 10 uploads and richer media limits<\/li>\n                                    <li>Planned: premium spotlight placement in Explore\/BuddyUp<\/li>\n                                    <li>Everything in Adventurer<\/li>\n                            <\/ul>\n                            <button class=\"buddyUpButton1\" data-tier=\"2\" data-product=\"enthusiast\" onclick=\"buddyUpStartCheckout(this)\">Purchase Enthusiast<\/button>\n                    <\/div>\n    <\/div>\n<\/section>\n\n<script>\n    (function() {\n        function formatStripePrice(price) {\n            if (!price || !Number.isFinite(Number(price.unit_amount)) || !price.currency) return '';\n            var amount = Number(price.unit_amount) \/ 100;\n            var currency = String(price.currency).toUpperCase();\n            var formatted;\n            try {\n                formatted = new Intl.NumberFormat(undefined, { style: 'currency', currency: currency }).format(amount);\n            } catch (e) {\n                formatted = currency + ' ' + amount.toFixed(2);\n            }\n            var interval = String(price.interval || '').toLowerCase();\n            var intervalCount = Math.max(1, Number(price.interval_count || 1));\n            if (!interval) return formatted;\n            return formatted + '<small> \/ ' + (intervalCount > 1 ? intervalCount + ' ' : '') + interval + (intervalCount > 1 ? 's' : '') + '<\/small>';\n        }\n\n        function selectedBillingInterval() {\n            var selected = document.querySelector('input[name=\"buddyup_billing_interval\"]:checked');\n            return selected && selected.value === 'year' ? 'year' : 'month';\n        }\n\n        function renderStripePrices(response) {\n            var priceEls = document.querySelectorAll('[data-stripe-price]');\n            var legacyPrices = response && response.prices && typeof response.prices === 'object' ? response.prices : {};\n            var billingPrices = response && response.billing_prices && typeof response.billing_prices === 'object' ? response.billing_prices : {};\n            var interval = selectedBillingInterval();\n            window.buddyUpSelectedBillingInterval = interval;\n            priceEls.forEach(function(el) {\n                var key = el.getAttribute('data-stripe-price');\n                var variants = billingPrices[key] && typeof billingPrices[key] === 'object' ? billingPrices[key] : {};\n                var selectedPrice = variants[interval] || (interval === 'month' ? legacyPrices[key] : null);\n                var display = formatStripePrice(selectedPrice);\n                el.innerHTML = display || '<small>' + (interval === 'year' ? 'Annual price is not configured yet' : 'Current price shown securely at checkout') + '<\/small>';\n            });\n        }\n\n        async function loadStripePrices() {\n            var priceEls = document.querySelectorAll('[data-stripe-price]');\n            if (!priceEls.length || !window.BUDDYUP || typeof BUDDYUP.apiRequest !== 'function') return;\n            try {\n                var response = await BUDDYUP.apiRequest('stripe-config', {});\n                window.buddyUpSubscriptionPricing = response || {};\n                var root = document.getElementById('subscriptionTiers');\n                if (root && response && response.subscription_terms_version) {\n                    root.setAttribute('data-subscription-terms-version', String(response.subscription_terms_version));\n                }\n                renderStripePrices(response || {});\n            } catch (e) {\n                priceEls.forEach(function(el) {\n                    el.innerHTML = '<small>Current price shown securely at checkout<\/small>';\n                });\n            }\n        }\n\n        document.querySelectorAll('input[name=\"buddyup_billing_interval\"]').forEach(function(input) {\n            input.addEventListener('change', function() {\n                renderStripePrices(window.buddyUpSubscriptionPricing || {});\n            });\n        });\n        loadStripePrices();\n    })();\n<\/script>\n\n<script>\n(function() {\n    'use strict';\n\n    var _subscriptionUiHydrated = false;\n\n    function markSubscriptionUiReady() {\n        document.documentElement.setAttribute('data-buddyup-sub-ui', 'ready');\n        _subscriptionUiHydrated = true;\n    }\n\n    function parseBoolish(value) {\n        if (value === true || value === 1 || value === '1') return true;\n        var raw = String(value || '').toLowerCase().trim();\n        return ['true', 'yes', 'on'].includes(raw);\n    }\n\n    function parseCanResubscribeFromSource(src) {\n        if (!src || typeof src !== 'object') return null;\n\n        var explicit = src.subscription_can_resubscribe;\n        if (typeof explicit !== 'undefined') return parseBoolish(explicit);\n\n        explicit = src.can_resubscribe;\n        if (typeof explicit !== 'undefined') return parseBoolish(explicit);\n\n        explicit = src.subscription_is_closed;\n        if (typeof explicit !== 'undefined') return parseBoolish(explicit);\n\n        var status = String(src.subscription_status || '').toLowerCase().trim();\n        if (status === '') return null;\n\n        if (['closed', 'cancelled', 'canceled', 'inactive', 'ended', 'expired', 'refunded'].includes(status)) {\n            return true;\n        }\n\n        return false;\n    }\n\n    function parseCanResubscribeFromAccount(res) {\n        var sources = [\n            res,\n            res && res.data,\n            res && res.user,\n            res && res.data && res.data.user\n        ];\n\n        for (var i = 0; i < sources.length; i++) {\n            var parsed = parseCanResubscribeFromSource(sources[i]);\n            if (parsed !== null) return parsed;\n        }\n\n        return false;\n    }\n\n    function applySubscriptionUiState(tier, canResubscribe) {\n        var normalizedTier = normalizeTier(tier);\n        document.documentElement.setAttribute('data-buddyup-tier', String(normalizedTier));\n        document.documentElement.setAttribute('data-buddyup-can-resubscribe', canResubscribe ? '1' : '0');\n        markSubscriptionUiReady();\n    }\n\n    function setSubscriptionStatusNotice(message) {\n        var notice = document.getElementById('buddyUpSubscriptionStatusNotice');\n        if (!notice) return;\n        notice.textContent = String(message || '');\n        notice.classList.toggle('isVisible', String(message || '').trim() !== '');\n    }\n\n    function refreshSubscriptionUiState(forceSync) {\n        if (typeof BUDDYUP === 'undefined' || !BUDDYUP.apiRequest) {\n            if (!_subscriptionUiHydrated) {\n                var currentTier = document.documentElement.getAttribute('data-buddyup-tier') || '0';\n                var currentResubscribe = document.documentElement.getAttribute('data-buddyup-can-resubscribe') === '1';\n                applySubscriptionUiState(currentTier, currentResubscribe);\n            }\n            return;\n        }\n\n        \/\/ This is a public comparison page. Requesting account-get as a guest\n        \/\/ returns an auth error and invokes the global expired-session redirect.\n        if (!BUDDYUP.hasAuthenticatedUser(BUDDYUP.getCurrentUser())) {\n            applySubscriptionUiState(0, false);\n            setSubscriptionStatusNotice('');\n            return;\n        }\n\n        function applyFallbackSubscriptionUiState() {\n            if (_subscriptionUiHydrated) return;\n            \/\/ Never let stale browser storage claim that someone is already subscribed.\n            \/\/ Show the comparison safely; checkout performs another live account check.\n            applySubscriptionUiState(0, false);\n            setSubscriptionStatusNotice('We could not confirm your current membership yet. Prices are still shown below, and we will verify your account again before checkout.');\n        }\n\n        var accountRequest = BUDDYUP.apiRequest('account-get', {\n            _force: !!forceSync,\n            _cb: Date.now()\n        });\n        var timeoutFallback = new Promise(function(resolve) {\n            setTimeout(function() { resolve(null); }, 3500);\n        });\n\n        Promise.race([accountRequest, timeoutFallback]).then(function(res) {\n            if (!res) {\n                applyFallbackSubscriptionUiState();\n                return;\n            }\n            setSubscriptionStatusNotice('');\n            applySubscriptionUiState(parseTierFromAccount(res), parseCanResubscribeFromAccount(res));\n        }).catch(function(){\n            applyFallbackSubscriptionUiState();\n        });\n    }\n\n    \/\/ Single source of truth on this page: account-get result controls subscription UI.\n    refreshSubscriptionUiState(true);\n\n    window.addEventListener('focus', function() {\n        refreshSubscriptionUiState(false);\n    });\n\n    document.addEventListener('visibilitychange', function() {\n        if (document.visibilityState === 'visible') {\n            refreshSubscriptionUiState(false);\n        }\n    });\n\n    \/\/ Avoid noisy periodic polling on this page; rely on focus\/visibility and explicit checkout events.\n\n    \/\/ Checkout flow: create a Stripe Checkout Session and mount Stripe's Payment Element on-site.\n\n    let _checkoutToken = null;\n    let _checkoutPollTimer = null;\n    let _checkoutPollInFlight = false;\n    let _checkoutPollAttempts = 0;\n    let _checkoutComplete = false;\n    let _checkoutStartedAt = null;\n    let _checkoutTargetTier = 0;\n    let _checkoutIframeLoadCount = 0;\n    let _checkoutLastIframeLoadAt = 0;\n    let _checkoutSubmitLikely = false;\n    let _checkoutSubmitLikelyReason = null;\n    let _checkoutProcessingVisible = false;\n    let _checkoutInteractionCount = 0;\n    let _checkoutLastInteractionAt = 0;\n    let _checkoutTraceId = null;\n    let _checkoutTrace = [];\n    let _checkoutCleanupFns = [];\n    let _checkoutActiveLink = null;\n    let _checkoutTraceLastPersistAt = 0;\n    let _checkoutIframeFocusedSince = 0; \/\/ timestamp when focus first entered iframe\n    let _checkoutRunPoll = null;\n    let _checkoutVerifyUserId = 0;\n    let _checkoutVerifyUserToken = '';\n    let _checkoutLastVerifyAt = 0;\n    let _checkoutMaxVerifyAttempts = 3;\n\n    function checkoutLog(label, data) {\n        var safeData = null;\n        if (typeof data !== 'undefined') {\n            try {\n                safeData = JSON.parse(JSON.stringify(data));\n            } catch (e) {\n                safeData = String(data);\n            }\n        }\n\n        try {\n            const entry = {\n                ts: Date.now(),\n                iso: new Date().toISOString(),\n                label: String(label || ''),\n                data: safeData,\n            };\n            _checkoutTrace.push(entry);\n            if (_checkoutTrace.length > 400) {\n                _checkoutTrace = _checkoutTrace.slice(-400);\n            }\n\n            if (_checkoutTraceId && window.sessionStorage) {\n                var nowMs = Date.now();\n                var labelStr = String(label || '');\n                var importantPersist = \/checkout\\.success|checkout\\.error|reconcile\\.poll\\.maxAttempts|checkout\\.submit_likely|postMessage\\.received|reconcile\\.poll\\.applied_detected|modal\\.close\/.test(labelStr);\n                if ((nowMs - _checkoutTraceLastPersistAt) >= 2500 || importantPersist) {\n                    const payload = {\n                        trace_id: _checkoutTraceId,\n                        updated_at: entry.iso,\n                        events: _checkoutTrace,\n                    };\n                    sessionStorage.setItem('buddyup_checkout_trace_active', JSON.stringify(payload));\n                    sessionStorage.setItem('buddyup_checkout_trace_last', JSON.stringify(payload));\n                    _checkoutTraceLastPersistAt = nowMs;\n                }\n            }\n        } catch (e) {}\n\n        try {\n            if (window.BUDDYUP_CHECKOUT_DEBUG === true) {\n                if (typeof data !== 'undefined') console.log('[BuddyUpCheckout]', label, data);\n                else console.log('[BuddyUpCheckout]', label);\n            }\n        } catch (e) {}\n    }\n\n    function beginCheckoutTrace(context) {\n        _checkoutTraceId = 'chk_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 8);\n        _checkoutTrace = [];\n        _checkoutTraceLastPersistAt = 0;\n        try {\n            window.__buddyUpCheckoutTraceId = _checkoutTraceId;\n            window.__buddyUpCheckoutGetTrace = function() {\n                return {\n                    trace_id: _checkoutTraceId,\n                    events: _checkoutTrace.slice(0),\n                };\n            };\n        } catch (e) {}\n        checkoutLog('trace.begin', context || {});\n    }\n\n    function markCheckoutSubmitLikely(reason, meta) {\n        if (_checkoutComplete || _checkoutSubmitLikely) return;\n\n        _checkoutSubmitLikely = true;\n        _checkoutSubmitLikelyReason = reason || 'unknown';\n        showCheckoutProcessing('Payment submitted. Finalizing your subscription...');\n        checkoutLog('checkout.submit_likely', {\n            reason: _checkoutSubmitLikelyReason,\n            meta: meta || null,\n        });\n\n        \/\/ Submit-like signals are strong; trigger a near-immediate verification pass.\n        scheduleCheckoutVerificationSoon(350, 'submit_likely');\n    }\n\n    function scheduleCheckoutVerificationSoon(delayMs, reason) {\n        if (_checkoutComplete || typeof _checkoutRunPoll !== 'function') return;\n\n        var ms = parseInt(delayMs, 10);\n        if (!Number.isFinite(ms) || ms < 0) ms = 0;\n\n        if (_checkoutPollTimer) {\n            clearTimeout(_checkoutPollTimer);\n            _checkoutPollTimer = null;\n        }\n\n        _checkoutPollTimer = setTimeout(function() {\n            if (typeof _checkoutRunPoll === 'function') {\n                _checkoutRunPoll(reason || 'scheduled');\n            }\n        }, ms);\n    }\n\n    function summarizeMessagePayload(payload) {\n        if (payload === null || typeof payload === 'undefined') return { kind: String(payload) };\n        if (typeof payload === 'string') {\n            return {\n                kind: 'string',\n                length: payload.length,\n                preview: payload.slice(0, 180),\n            };\n        }\n        if (typeof payload === 'number' || typeof payload === 'boolean') {\n            return { kind: typeof payload, value: payload };\n        }\n        if (Array.isArray(payload)) {\n            return { kind: 'array', length: payload.length };\n        }\n        if (typeof payload === 'object') {\n            const keys = Object.keys(payload).slice(0, 12);\n            const out = { kind: 'object', keys: keys };\n            if (Object.prototype.hasOwnProperty.call(payload, 'status')) out.status = payload.status;\n            if (Object.prototype.hasOwnProperty.call(payload, 'event')) out.event = payload.event;\n            if (Object.prototype.hasOwnProperty.call(payload, 'type')) out.type = payload.type;\n            return out;\n        }\n        return { kind: typeof payload };\n    }\n\n    function canInferSubmitNow() {\n        if (_checkoutComplete) return false;\n        if (_checkoutIframeLoadCount < 1) return false;\n        if (_checkoutInteractionCount < 1) return false;\n        if (!_checkoutLastIframeLoadAt) return false;\n\n        \/\/ Allow iframe scripts to finish booting before interpreting message noise.\n        return (Date.now() - _checkoutLastIframeLoadAt) >= 1200;\n    }\n\n    function installCheckoutObservers(iframe) {\n        if (!iframe) return;\n\n        const overlay = document.getElementById('buddyUpCheckoutOverlay');\n        if (!overlay) return;\n\n        const onPointerDown = function(evt) {\n            if (_checkoutComplete) return;\n            try {\n                const rect = iframe.getBoundingClientRect();\n                const cx = typeof evt.clientX === 'number' ? evt.clientX : -1;\n                const cy = typeof evt.clientY === 'number' ? evt.clientY : -1;\n                const inside = cx >= rect.left && cx <= rect.right && cy >= rect.top && cy <= rect.bottom;\n                if (!inside) return;\n\n                _checkoutInteractionCount += 1;\n                _checkoutLastInteractionAt = Date.now();\n                checkoutLog('checkout.iframe.interaction', {\n                    count: _checkoutInteractionCount,\n                    x: cx,\n                    y: cy,\n                });\n            } catch (e) {}\n        };\n\n        const onWindowBlur = function() {\n            if (_checkoutComplete) return;\n            const now = Date.now();\n            const prevInteractionAt = _checkoutLastInteractionAt;\n            const sinceInteraction = prevInteractionAt ? (now - prevInteractionAt) : null;\n            var activeIsCheckoutIframe = false;\n            try {\n                activeIsCheckoutIframe = document.activeElement === iframe;\n            } catch (e) {}\n\n            if (_checkoutIframeLoadCount >= 1 && activeIsCheckoutIframe) {\n                                \/\/ Track when the user first focused into the iframe (form engagement start).\n                                if (!_checkoutIframeFocusedSince) _checkoutIframeFocusedSince = now;\n                \/\/ Cross-origin iframe clicks do not bubble into parent; infer interaction from focus transfer.\n                if (!prevInteractionAt || (now - prevInteractionAt) > 450) {\n                    _checkoutInteractionCount += 1;\n                    _checkoutLastInteractionAt = now;\n                    checkoutLog('checkout.iframe.focus_interaction', {\n                        count: _checkoutInteractionCount,\n                        source: 'window.blur.activeElement',\n                    });\n                }\n            }\n\n            checkoutLog('checkout.window.blur', {\n                sinceInteractionMs: sinceInteraction,\n                interactionCount: _checkoutInteractionCount,\n                activeIsCheckoutIframe: activeIsCheckoutIframe,\n            });\n\n            \/\/ Strong signal for submit\/challenge transitions: quick blur after meaningful iframe interaction.\n            \/\/ After 5s of iframe focus (user was filling the form) 1 interaction is enough.\n            \/\/ Otherwise require 3 to avoid false positives from an opening click.\n            var blurInteractionThreshold = (_checkoutIframeFocusedSince > 0 && (now - _checkoutIframeFocusedSince) >= 5000) ? 1 : 3;\n            if (_checkoutIframeLoadCount >= 1 && _checkoutInteractionCount >= blurInteractionThreshold && sinceInteraction !== null && sinceInteraction >= 250 && sinceInteraction <= 1600) {\n                markCheckoutSubmitLikely('window_blur_after_iframe_interaction', {\n                    sinceInteractionMs: sinceInteraction,\n                    interactionCount: _checkoutInteractionCount,\n                });\n            }\n        };\n\n        const onWindowFocus = function() {\n            if (_checkoutComplete) return;\n            checkoutLog('checkout.window.focus', {\n                interactionCount: _checkoutInteractionCount,\n                submitLikely: _checkoutSubmitLikely,\n            });\n\n            if (_checkoutSubmitLikely) {\n                scheduleCheckoutVerificationSoon(250, 'window_focus');\n            }\n        };\n\n        const onVisibilityChange = function() {\n            if (_checkoutComplete) return;\n            const state = document.visibilityState;\n            checkoutLog('checkout.visibility', { state: state });\n            if (_checkoutIframeLoadCount >= 1 && state === 'hidden' && _checkoutInteractionCount > 0) {\n                markCheckoutSubmitLikely('document_hidden_after_interaction', {\n                    interactionCount: _checkoutInteractionCount,\n                });\n            }\n            if (state === 'visible' && _checkoutSubmitLikely) {\n                scheduleCheckoutVerificationSoon(200, 'visibility_visible');\n            }\n        };\n\n        overlay.addEventListener('pointerdown', onPointerDown, true);\n        window.addEventListener('blur', onWindowBlur);\n        window.addEventListener('focus', onWindowFocus);\n        document.addEventListener('visibilitychange', onVisibilityChange);\n\n        _checkoutCleanupFns.push(function() {\n            try { overlay.removeEventListener('pointerdown', onPointerDown, true); } catch (e) {}\n            try { window.removeEventListener('blur', onWindowBlur); } catch (e) {}\n            try { window.removeEventListener('focus', onWindowFocus); } catch (e) {}\n            try { document.removeEventListener('visibilitychange', onVisibilityChange); } catch (e) {}\n        });\n\n        checkoutLog('checkout.observers.installed', { traceId: _checkoutTraceId });\n    }\n\n    function getCurrentUser() {\n        try {\n            const raw = window.localStorage ? localStorage.getItem('buddyup_user') : null;\n            return raw ? JSON.parse(raw) : null;\n        } catch(e) { return null; }\n    }\n\n    function normalizeTier(value) {\n        value = parseInt(value);\n        if (isNaN(value)) value = 0;\n        if (![0, 1, 2].includes(value)) value = 0;\n        return value;\n    }\n\n    function accountDataFromResponse(res) {\n        if (!res) return null;\n        if (res && res.data && typeof res.data === 'object') return res.data;\n        if (res && res.user && typeof res.user === 'object') return res.user;\n        if (res && typeof res === 'object') return res;\n        return null;\n    }\n\n    function readFirstString(source, keys) {\n        if (!source || typeof source !== 'object') return '';\n        for (var i = 0; i < keys.length; i++) {\n            var val = source[keys[i]];\n            if (typeof val === 'string' && val.trim() !== '') return val.trim();\n        }\n        return '';\n    }\n\n    function hasEverSubscribed(accountRes, currentTier, user) {\n        if (normalizeTier(currentTier) > 0) return true;\n\n        var account = accountDataFromResponse(accountRes);\n        var candidates = [];\n\n        if (account) {\n            candidates.push(account.payment_ref);\n            candidates.push(account.subscription_started_at);\n            candidates.push(account.subscription_expires_at);\n            candidates.push(account.confirmation_number);\n        }\n\n        if (user && typeof user === 'object') {\n            candidates.push(user.payment_ref);\n            candidates.push(user.subscription_started_at);\n            candidates.push(user.subscription_expires_at);\n            candidates.push(user.confirmation_number);\n        }\n\n        for (var i = 0; i < candidates.length; i++) {\n            if (typeof candidates[i] === 'string' && candidates[i].trim() !== '') return true;\n        }\n\n        return false;\n    }\n    function hasCompleteBillingAddress(accountRes, user) {\n        var account = accountDataFromResponse(accountRes) || {};\n        var fallback = user && typeof user === 'object' ? user : {};\n        var line1 = readFirstString(account, ['billing_address_line_1', 'address_line_1']) || readFirstString(fallback, ['billing_address_line_1', 'address_line_1']);\n        var city = readFirstString(account, ['billing_city', 'city']) || readFirstString(fallback, ['billing_city', 'city']);\n        var state = readFirstString(account, ['billing_state', 'state']) || readFirstString(fallback, ['billing_state', 'state']);\n        var postal = readFirstString(account, ['billing_postal_code', 'postal_code']) || readFirstString(fallback, ['billing_postal_code', 'postal_code']);\n        return !!(line1 && city && state && postal);\n    }\n\n    function seedCheckoutCompletion(accountRes, user) {\n        var account = accountDataFromResponse(accountRes) || {};\n        var fallback = user && typeof user === 'object' ? user : {};\n\n        var seed = {};\n        seed.first_name = readFirstString(account, ['first_name']) || readFirstString(fallback, ['first_name']) || '';\n        seed.last_name = readFirstString(account, ['last_name']) || readFirstString(fallback, ['last_name']) || '';\n        seed.mobile_phone = readFirstString(account, ['billing_phone', 'mobile_phone']) || readFirstString(fallback, ['billing_phone', 'mobile_phone']) || '';\n        seed.address_line_1 = readFirstString(account, ['billing_address_line_1', 'address_line_1']) || readFirstString(fallback, ['billing_address_line_1', 'address_line_1']) || '';\n        seed.address_line_2 = readFirstString(account, ['billing_address_line_2', 'address_line_2']) || readFirstString(fallback, ['billing_address_line_2', 'address_line_2']) || '';\n        seed.city = readFirstString(account, ['billing_city', 'city']) || readFirstString(fallback, ['billing_city', 'city']) || '';\n        seed.state = readFirstString(account, ['billing_state', 'state']) || readFirstString(fallback, ['billing_state', 'state']) || '';\n        seed.postal_code = readFirstString(account, ['billing_postal_code', 'postal_code']) || readFirstString(fallback, ['billing_postal_code', 'postal_code']) || '';\n        seed.about_me = readFirstString(account, ['about_me']) || '';\n        seed.email = readFirstString(account, ['email_address', 'email']) || readFirstString(fallback, ['email_address', 'email']) || '';\n        return seed;\n    }\n\n    function buildCheckoutCustomerPayload(user, accountRes, completionData) {\n        var account = accountDataFromResponse(accountRes) || {};\n        var completion = completionData && typeof completionData === 'object' ? completionData : {};\n        var fallback = user && typeof user === 'object' ? user : {};\n\n        var payload = {\n            external_id: String(fallback.id || account.id || ''),\n            first_name: completion.first_name || readFirstString(account, ['first_name']) || readFirstString(fallback, ['first_name']) || readFirstString(fallback, ['full_name']) || 'User',\n            last_name: completion.last_name || readFirstString(account, ['last_name']) || readFirstString(fallback, ['last_name']) || '',\n            email: completion.email || readFirstString(account, ['email_address', 'email']) || readFirstString(fallback, ['email_address', 'email']) || '',\n            mobile_phone: completion.mobile_phone || readFirstString(account, ['mobile_phone']) || readFirstString(fallback, ['mobile_phone']) || '',\n            address_line_1: completion.address_line_1 || readFirstString(account, ['billing_address_line_1', 'address_line_1']) || readFirstString(fallback, ['billing_address_line_1', 'address_line_1']) || '',\n            address_line_2: completion.address_line_2 || readFirstString(account, ['billing_address_line_2', 'address_line_2']) || readFirstString(fallback, ['billing_address_line_2', 'address_line_2']) || '',\n            city: completion.city || readFirstString(account, ['billing_city', 'city']) || readFirstString(fallback, ['billing_city', 'city']) || '',\n            state: completion.state || readFirstString(account, ['billing_state', 'state']) || readFirstString(fallback, ['billing_state', 'state']) || '',\n            postal_code: completion.postal_code || readFirstString(account, ['billing_postal_code', 'postal_code']) || readFirstString(fallback, ['billing_postal_code', 'postal_code']) || '',\n            billing_address_different: 0,\n            active: true,\n        };\n\n        payload.account_name = (payload.first_name + ' ' + payload.last_name).trim();\n        if (payload.account_name === '') {\n            payload.account_name = 'BuddyUp User ' + String(fallback.id || account.id || '');\n        }\n\n        return payload;\n    }\n\n    async function requestCheckoutBillingDetails(accountRes, user, tier) {\n        if (typeof BUDDYUP === 'undefined' || typeof BUDDYUP.openModal !== 'function') {\n            return null;\n        }\n\n        var seed = seedCheckoutCompletion(accountRes, user);\n\n        return await new Promise(function(resolve) {\n            var settled = false;\n            var finish = function(value) {\n                if (settled) return;\n                settled = true;\n                resolve(value);\n            };\n\n            var body = '' +\n                '<form id=\"buddyUpCheckoutProfileForm\">' +\n                    '<p class=\"buddyUpCheckoutProfileIntro\">Confirm your billing details for this subscription. These details are used for Stripe billing and receipts; they will not update your public BuddyUp profile.<\/p>' +\n                    '<div class=\"buddyUpCheckoutProfileGrid\">' +\n                        '<div class=\"buddyUpInputWrapper\">' +\n                            '<label for=\"checkoutFirstName\">Billing First Name <span class=\"requiredMessage\">*<\/span><\/label>' +\n                            '<input type=\"text\" id=\"checkoutFirstName\" value=\"' + BUDDYUP.escapeHtml(seed.first_name) + '\" required \/>' +\n                        '<\/div>' +\n                        '<div class=\"buddyUpInputWrapper\">' +\n                            '<label for=\"checkoutLastName\">Billing Last Name <span class=\"requiredMessage\">*<\/span><\/label>' +\n                            '<input type=\"text\" id=\"checkoutLastName\" value=\"' + BUDDYUP.escapeHtml(seed.last_name) + '\" required \/>' +\n                        '<\/div>' +\n                        '<div class=\"buddyUpInputWrapper\">' +\n                            '<label for=\"checkoutPhone\">Billing Phone Number <span class=\"requiredMessage\">*<\/span><\/label>' +\n                            '<input type=\"tel\" id=\"checkoutPhone\" value=\"' + BUDDYUP.escapeHtml(seed.mobile_phone) + '\" required \/>' +\n                        '<\/div>' +\n                        '<div class=\"buddyUpInputWrapper\">' +\n                            '<label for=\"checkoutZip\">Billing Zip Code <span class=\"requiredMessage\">*<\/span><\/label>' +\n                            '<input type=\"text\" id=\"checkoutZip\" value=\"' + BUDDYUP.escapeHtml(seed.postal_code) + '\" required \/>' +\n                        '<\/div>' +\n                        '<div id=\"checkoutBillingAddressFields\" class=\"fullWidth\">' +\n                            '<div class=\"buddyUpInputWrapper fullWidth\">' +\n                                '<label for=\"checkoutAddress1\">Billing Street Address <span class=\"requiredMessage\">*<\/span><\/label>' +\n                                '<input type=\"text\" id=\"checkoutAddress1\" value=\"' + BUDDYUP.escapeHtml(seed.address_line_1) + '\" required \/>' +\n                            '<\/div>' +\n                            '<div class=\"buddyUpInputWrapper fullWidth\">' +\n                                '<label for=\"checkoutAddress2\">Billing Address Line 2<\/label>' +\n                                '<input type=\"text\" id=\"checkoutAddress2\" value=\"' + BUDDYUP.escapeHtml(seed.address_line_2) + '\" \/>' +\n                            '<\/div>' +\n                        '<\/div>' +\n                        '<div class=\"buddyUpInputWrapper\">' +\n                            '<label for=\"checkoutCity\">Billing City <span class=\"requiredMessage\">*<\/span><\/label>' +\n                            '<input type=\"text\" id=\"checkoutCity\" value=\"' + BUDDYUP.escapeHtml(seed.city) + '\" required \/>' +\n                        '<\/div>' +\n                        '<div class=\"buddyUpInputWrapper\">' +\n                            '<label for=\"checkoutState\">Billing State <span class=\"requiredMessage\">*<\/span><\/label>' +\n                            '<input type=\"text\" id=\"checkoutState\" value=\"' + BUDDYUP.escapeHtml(seed.state) + '\" required \/>' +\n                        '<\/div>' +\n                    '<\/div>' +\n                    '<div id=\"buddyUpCheckoutProfileError\" class=\"buddyUpErrorMessage hidden\"><\/div>' +\n                    '<div class=\"buddyUpCheckoutProfileActions\">' +\n                        '<button type=\"button\" id=\"buddyUpCheckoutProfileCancel\" class=\"buddyUpButton3\">Cancel<\/button>' +\n                        '<button type=\"submit\" id=\"buddyUpCheckoutProfileSubmit\" class=\"buddyUpButton1\">Checkout<\/button>' +\n                    '<\/div>' +\n                '<\/form>';\n\n            BUDDYUP.openModal(body, 'Billing Details', 'buddyUpCheckoutProfileModal');\n\n            var closeBtn = document.getElementById('buddyUpCloseModalButton');\n            if (closeBtn) {\n                closeBtn.addEventListener('click', function() { finish(null); }, { once: true });\n            }\n\n            var overlay = document.querySelector('#buddyUpModalWrapper .buddyUpModalOverlay');\n            if (overlay) {\n                overlay.addEventListener('click', function() { finish(null); }, { once: true });\n            }\n\n            var form = document.getElementById('buddyUpCheckoutProfileForm');\n            var cancelBtn = document.getElementById('buddyUpCheckoutProfileCancel');\n            var saveBtn = document.getElementById('buddyUpCheckoutProfileSubmit');\n            var errEl = document.getElementById('buddyUpCheckoutProfileError');\n\n            if (cancelBtn) {\n                cancelBtn.addEventListener('click', function() {\n                    BUDDYUP.closeModal();\n                    finish(null);\n                });\n            }\n\n            if (!form || !saveBtn || !errEl) {\n                finish(null);\n                return;\n            }\n\n\n            form.addEventListener('submit', function(e) {\n                e.preventDefault();\n                var payload = {\n                    first_name: String((document.getElementById('checkoutFirstName') || {}).value || '').trim(),\n                    last_name: String((document.getElementById('checkoutLastName') || {}).value || '').trim(),\n                    mobile_phone: String((document.getElementById('checkoutPhone') || {}).value || '').trim(),\n                    postal_code: String((document.getElementById('checkoutZip') || {}).value || '').trim(),\n                    address_line_1: String((document.getElementById('checkoutAddress1') || {}).value || '').trim(),\n                    address_line_2: String((document.getElementById('checkoutAddress2') || {}).value || '').trim(),\n                    city: String((document.getElementById('checkoutCity') || {}).value || '').trim(),\n                    state: String((document.getElementById('checkoutState') || {}).value || '').trim(),\n                    email: seed.email || readFirstString(user || {}, ['email_address', 'email']),\n                    billing_address_different: 0\n                };\n\n                if (!payload.first_name || !payload.last_name || !payload.mobile_phone || !payload.address_line_1 || !payload.postal_code || !payload.city || !payload.state) {\n                    errEl.textContent = 'Please complete all required billing fields before checkout.';\n                    errEl.classList.remove('hidden');\n                    return;\n                }\n\n                errEl.classList.add('hidden');\n                BUDDYUP.closeModal();\n                finish(payload);\n            });\n        });\n    }\n    function selectedCheckoutInterval() {\n        var selected = document.querySelector('input[name=\"buddyup_billing_interval\"]:checked');\n        return selected && selected.value === 'year' ? 'year' : 'month';\n    }\n\n    function selectedCheckoutPrice(productId, interval) {\n        var config = window.buddyUpSubscriptionPricing || {};\n        var variants = config.billing_prices && config.billing_prices[productId]\n            ? config.billing_prices[productId]\n            : {};\n        return variants && variants[interval] ? variants[interval] : null;\n    }\n\n    function formatCheckoutOfferPrice(price) {\n        if (!price || !Number.isFinite(Number(price.unit_amount)) || !price.currency) return '';\n        var amount = Number(price.unit_amount) \/ 100;\n        try {\n            return new Intl.NumberFormat(undefined, {\n                style: 'currency',\n                currency: String(price.currency).toUpperCase()\n            }).format(amount);\n        } catch (e) {\n            return String(price.currency).toUpperCase() + ' ' + amount.toFixed(2);\n        }\n    }\n\n    function requestSubscriptionConsent(tierName, productId, interval) {\n        return new Promise(function(resolve) {\n            var root = document.getElementById('subscriptionTiers');\n            var termsUrl = root ? String(root.getAttribute('data-subscription-terms-url') || '') : '';\n            var privacyUrl = root ? String(root.getAttribute('data-privacy-url') || '') : '';\n            var termsVersion = root ? String(root.getAttribute('data-subscription-terms-version') || '') : '';\n            var price = selectedCheckoutPrice(productId, interval);\n            var priceLabel = formatCheckoutOfferPrice(price);\n            var cadenceLabel = interval === 'year' ? 'year' : 'month';\n            var overlay = document.createElement('div');\n            overlay.id = 'buddyUpSubscriptionConsentOverlay';\n            overlay.style.cssText = 'position:fixed;inset:0;z-index:100000;background:rgba(0,0,0,.62);display:flex;align-items:center;justify-content:center;padding:1rem;';\n            overlay.innerHTML =\n                '<div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"buddyUpSubscriptionConsentTitle\" style=\"background:#fff;color:#222;max-width:560px;width:100%;padding:1.25rem;border-radius:12px;box-shadow:0 20px 60px rgba(0,0,0,.35);\">' +\n                    '<h3 id=\"buddyUpSubscriptionConsentTitle\" style=\"margin-top:0;\">Confirm recurring subscription<\/h3>' +\n                    '<p><strong>' + BUDDYUP.escapeHtml(tierName) + '<\/strong> costs <strong>' + BUDDYUP.escapeHtml(priceLabel) + ' per ' + cadenceLabel + '<\/strong>.<\/p>' +\n                    '<p>It renews automatically at the then-current price until canceled. Cancel at least 24 hours before renewal to avoid the next charge.<\/p>' +\n                    (interval === 'year' ? '<p>You will receive the annual renewal notices described in the Subscription Terms.<\/p>' : '') +\n                    '<label style=\"display:flex;gap:.65rem;align-items:flex-start;margin:1rem 0;\">' +\n                        '<input type=\"checkbox\" id=\"buddyUpRecurringConsentCheck\" style=\"margin-top:.25rem;\" \/>' +\n                        '<span>I expressly consent to automatic renewal and authorize recurring charges. I have reviewed the <a href=\"' + BUDDYUP.escapeHtml(termsUrl) + '\" target=\"_blank\" rel=\"noopener noreferrer\">Terms<\/a> and <a href=\"' + BUDDYUP.escapeHtml(privacyUrl) + '\" target=\"_blank\" rel=\"noopener noreferrer\">Privacy Policy<\/a>.<\/span>' +\n                    '<\/label>' +\n                    '<p id=\"buddyUpRecurringConsentError\" class=\"buddyUpErrorMessage hidden\">Check the consent box to continue.<\/p>' +\n                    '<div style=\"display:flex;gap:.75rem;justify-content:flex-end;flex-wrap:wrap;\">' +\n                        '<button type=\"button\" id=\"buddyUpRecurringConsentCancel\" class=\"buddyUpButton3\">Cancel<\/button>' +\n                        '<button type=\"button\" id=\"buddyUpRecurringConsentContinue\" class=\"buddyUpButton1\">Continue to secure payment<\/button>' +\n                    '<\/div>' +\n                '<\/div>';\n            document.body.appendChild(overlay);\n\n            var finish = function(result) {\n                if (overlay.parentNode) overlay.parentNode.removeChild(overlay);\n                resolve(result);\n            };\n            overlay.querySelector('#buddyUpRecurringConsentCancel').addEventListener('click', function() { finish(null); });\n            overlay.addEventListener('click', function(e) { if (e.target === overlay) finish(null); });\n            overlay.querySelector('#buddyUpRecurringConsentContinue').addEventListener('click', function() {\n                var checkbox = overlay.querySelector('#buddyUpRecurringConsentCheck');\n                if (!checkbox || !checkbox.checked) {\n                    overlay.querySelector('#buddyUpRecurringConsentError').classList.remove('hidden');\n                    return;\n                }\n                finish({ accepted: true, terms_version: termsVersion, method: 'checkbox' });\n            });\n        });\n    }\n\n    function persistCheckoutTierHint(tierHint, accountRes) {\n        try {\n            var tier = normalizeTier(tierHint);\n            if (tier <= 0) return;\n\n            var user = (typeof BUDDYUP !== 'undefined' && typeof BUDDYUP.getCurrentUser === 'function')\n                ? BUDDYUP.getCurrentUser()\n                : getCurrentUser();\n            if (!user || typeof user !== 'object') return;\n\n            var existing = normalizeTier(\n                user.user_subscription ?? user.subscription ?? user.subscription_tier ?? user.tier ?? 0\n            );\n            var nextTier = Math.max(existing, tier);\n\n            user.user_subscription = nextTier;\n            user.subscription = nextTier;\n            user.subscription_tier = nextTier;\n            user.tier = nextTier;\n\n            if (accountRes && (accountRes.subscription_expires_at || accountRes.expires_at)) {\n                user.subscription_expires_at = accountRes.subscription_expires_at || accountRes.expires_at;\n            }\n\n            if (typeof BUDDYUP !== 'undefined' && typeof BUDDYUP.setUser === 'function') {\n                BUDDYUP.setUser(user);\n            } else if (window.localStorage) {\n                localStorage.setItem('buddyup_user', JSON.stringify(user));\n            }\n        } catch (e) {}\n    }\n\n    function showCheckoutProcessing(message) {\n        var processing = document.getElementById('buddyUpCheckoutProcessing');\n        var messageEl = document.getElementById('buddyUpCheckoutProcessingMessage');\n        if (!processing) return;\n\n        if (messageEl && message) messageEl.textContent = message;\n        processing.style.display = 'flex';\n        _checkoutProcessingVisible = true;\n        checkoutLog('checkout.processing.show', { message: message || null });\n    }\n\n    function hideCheckoutProcessing() {\n        var processing = document.getElementById('buddyUpCheckoutProcessing');\n        if (!processing) return;\n        processing.style.display = 'none';\n        _checkoutProcessingVisible = false;\n    }\n\n    function closeCheckoutModal() {\n        checkoutLog('modal.close');\n        const overlay = document.getElementById('buddyUpCheckoutOverlay');\n        if (overlay) overlay.remove();\n\n        if (_checkoutCleanupFns.length > 0) {\n            _checkoutCleanupFns.forEach(function(fn) {\n                try { fn(); } catch (e) {}\n            });\n            _checkoutCleanupFns = [];\n        }\n\n        document.querySelector('html').style.overflow = '';\n        if (_checkoutPollTimer) {\n            clearTimeout(_checkoutPollTimer);\n            _checkoutPollTimer = null;\n        }\n        _checkoutPollInFlight = false;\n        _checkoutPollAttempts = 0;\n        _checkoutToken = null;\n        _checkoutTargetTier = 0;\n        _checkoutIframeLoadCount = 0;\n        _checkoutLastIframeLoadAt = 0;\n        _checkoutSubmitLikely = false;\n        _checkoutSubmitLikelyReason = null;\n        _checkoutProcessingVisible = false;\n        _checkoutInteractionCount = 0;\n        _checkoutLastInteractionAt = 0;\n        _checkoutIframeFocusedSince = 0;\n        _checkoutActiveLink = null;\n        _checkoutTraceLastPersistAt = 0;\n        _checkoutLastVerifyAt = 0;\n        _checkoutVerifyUserId = 0;\n        _checkoutVerifyUserToken = '';\n        _checkoutRunPoll = null;\n    }\n\n    function showCheckoutError(msg) {\n        checkoutLog('checkout.error', { message: msg });\n        closeCheckoutModal();\n        if (typeof BUDDYUP !== 'undefined' && BUDDYUP.openModal) {\n            BUDDYUP.openModal('<p>' + msg + '<\/p>', 'Checkout Error', 'buddyUpCheckoutErrorModal');\n        } else {\n            alert(msg);\n        }\n    }\n\n    function showCheckoutSuccess(tierHint) {\n        if (_checkoutComplete) return;\n        _checkoutComplete = true;\n        tierHint = normalizeTier(typeof tierHint === 'undefined' ? _checkoutTargetTier : tierHint);\n        checkoutLog('checkout.success');\n\n        if (_checkoutPollTimer) {\n            clearTimeout(_checkoutPollTimer);\n            _checkoutPollTimer = null;\n        }\n\n        hideCheckoutProcessing();\n        persistCheckoutTierHint(tierHint);\n\n        const body = document.getElementById('buddyUpCheckoutBody');\n        const success = document.getElementById('buddyUpCheckoutSuccess');\n        if (body) body.style.display = 'none';\n        if (success) success.style.display = 'block';\n\n        \/\/ Refresh subscription data so the page reflects the new tier\n        if (typeof BUDDYUP !== 'undefined' && BUDDYUP.apiRequest) {\n            var currentUser = getCurrentUser();\n            var userId = currentUser && currentUser.id ? parseInt(currentUser.id, 10) : 0;\n            var userToken = currentUser && currentUser.user_token ? String(currentUser.user_token) : '';\n            BUDDYUP.apiRequest('account-get', { id: userId, user_token: userToken, _force: true, _cb: Date.now() }).then(function(res) {\n                var confirmedTier = parseTierFromAccount(res);\n                if (confirmedTier > 0 || tierHint > 0) {\n                    persistCheckoutTierHint(Math.max(confirmedTier, tierHint), res);\n                }\n                if (res && typeof BUDDYUP.resolveSubscriptionTier === 'function') {\n                    BUDDYUP.resolveSubscriptionTier(true);\n                }\n            }).catch(function(){});\n        }\n\n        var accountLink = (typeof buddyUpVariables !== 'undefined' && buddyUpVariables.account_link)\n            ? String(buddyUpVariables.account_link)\n            : '\/buddyup\/account';\n        var redirectUrl = accountLink + (accountLink.indexOf('?') === -1 ? '?' : '&') + 'subscription_success=1';\n        if (tierHint > 0) {\n            redirectUrl += '&subscription_tier=' + encodeURIComponent(String(tierHint));\n        }\n\n        var continueBtn = document.getElementById('buddyUpCheckoutSuccessContinue');\n        if (continueBtn) {\n            continueBtn.setAttribute('href', redirectUrl);\n        }\n\n        \/\/ Auto-redirect to account so users are not stranded on iframe receipt screens.\n        setTimeout(function() {\n            window.location.href = redirectUrl;\n        }, 900);\n    }\n\n    function parseTierFromAccount(res) {\n        var sources = [\n            res,\n            res && res.data,\n            res && res.user,\n            res && res.data && res.data.user\n        ];\n\n        for (var i = 0; i < sources.length; i++) {\n            var src = sources[i];\n            if (!src || typeof src !== 'object') continue;\n            var raw = src.user_subscription;\n            if (typeof raw === 'undefined') raw = src.subscription;\n            if (typeof raw === 'undefined') raw = src.subscription_tier;\n            if (typeof raw === 'undefined') raw = src.tier;\n            if (typeof raw === 'undefined') continue;\n\n            var parsed = parseInt(raw);\n            if (!isNaN(parsed) && [0, 1, 2].includes(parsed)) {\n                return parsed;\n            }\n        }\n\n        return 0;\n    }\n    function loadStripeJs() {\n        if (window.Stripe) return Promise.resolve(window.Stripe);\n        return new Promise(function(resolve, reject) {\n            var existing = document.querySelector('script[src=\"https:\/\/js.stripe.com\/dahlia\/stripe.js\"]');\n            if (existing) {\n                existing.addEventListener('load', function() { resolve(window.Stripe); });\n                existing.addEventListener('error', function() { reject(new Error('Could not load Stripe.js.')); });\n                return;\n            }\n            var script = document.createElement('script');\n            script.src = 'https:\/\/js.stripe.com\/dahlia\/stripe.js';\n            script.async = true;\n            script.onload = function() { resolve(window.Stripe); };\n            script.onerror = function() { reject(new Error('Could not load Stripe.js.')); };\n            document.head.appendChild(script);\n        });\n    }\n\n    async function verifyStripeCheckoutSession(sessionId, tier) {\n        if (!sessionId) return null;\n        var res = await BUDDYUP.apiRequest('stripe-session-status', {\n            session_id: sessionId,\n            expected_tier: tier,\n            _force: true\n        });\n        checkoutLog('stripe.session.status', res || {});\n        return res;\n    }\n\n    async function pollStripeCheckoutSession(sessionId, tier) {\n        var maxAttempts = 10;\n        var delayMs = 1200;\n        for (var attempt = 1; attempt <= maxAttempts; attempt++) {\n            var res = await verifyStripeCheckoutSession(sessionId, tier);\n            if (res && res.status === 'success') {\n                var appliedTier = Number(res.applied && res.applied.tier ? res.applied.tier : 0);\n                var appliedOk = !!(res.applied && res.applied.ok);\n                if (appliedOk && appliedTier >= tier) {\n                    return res;\n                }\n            }\n            await new Promise(function(resolve) { setTimeout(resolve, delayMs); });\n            delayMs = Math.min(delayMs + 500, 3500);\n        }\n        return null;\n    }\n\n    window.buddyUpStartCheckout = async function(btn) {\n        var user = getCurrentUser();\n        var productId = btn.getAttribute('data-product');\n        var tier = parseInt(btn.getAttribute('data-tier')) || 1;\n        var billingInterval = selectedCheckoutInterval();\n        var configuredPrice = selectedCheckoutPrice(productId, billingInterval);\n\n        if (!configuredPrice || !configuredPrice.price_id) {\n            showCheckoutError('That billing period is not available yet. Please choose another option or contact support.');\n            return;\n        }\n\n        beginCheckoutTrace({\n            productId: productId,\n            tier: tier,\n            userId: user && user.id ? user.id : null,\n        });\n\n        _checkoutComplete = false;\n        _checkoutTargetTier = normalizeTier(tier);\n        _checkoutSubmitLikely = false;\n        _checkoutSubmitLikelyReason = null;\n        _checkoutProcessingVisible = false;\n        _checkoutStartedAt = new Date(Date.now() - (2 * 60 * 1000)).toISOString();\n        checkoutLog('checkout.start', { userId: user && user.id, productId: productId, tier: tier, startedAt: _checkoutStartedAt, provider: 'stripe' });\n\n        if (!user || !user.id) {\n            if (typeof BUDDYUP !== 'undefined' && BUDDYUP.openModal) {\n                var loginLink = (typeof buddyUpVariables !== 'undefined' && buddyUpVariables.login_link) ? buddyUpVariables.login_link : '\/login';\n                BUDDYUP.openModal(\n                    '<div style=\"max-width:350px;margin:0 auto;\"><p>Please log in to purchase a subscription.<\/p><a href=\"' + loginLink + '\" class=\"buddyUpButton1\">Log In<\/a><\/div>',\n                    'Log In Required',\n                    'buddyUpLoginRequiredModal'\n                );\n            } else {\n                alert('Please log in to purchase a subscription.');\n            }\n            return;\n        }\n\n        var accountRes = null;\n        var currentTier = 0;\n\n        try {\n            accountRes = await BUDDYUP.apiRequest('account-get', { id: user.id, _force: true });\n            if (!accountRes || accountRes.status !== 'success') {\n                throw new Error((accountRes && (accountRes.message || accountRes.data)) ? (accountRes.message || accountRes.data) : 'We could not verify your current membership.');\n            }\n            currentTier = parseTierFromAccount(accountRes);\n            if (currentTier > 0) {\n                checkoutLog('checkout.portal.mode', { fromTier: currentTier, requestedTier: tier, requestedInterval: billingInterval });\n                var portalReturn = new URL(window.location.href);\n                portalReturn.searchParams.delete('stripe_return');\n                portalReturn.searchParams.delete('subscription_success');\n                var portalRes = await BUDDYUP.apiRequest('stripe-portal-session', {\n                    user_id: user.id,\n                    user_token: user.user_token || '',\n                    return_url: portalReturn.toString(),\n                    _force: true\n                });\n                if (!portalRes || portalRes.status !== 'success' || !portalRes.url) {\n                    throw new Error((portalRes && (portalRes.message || portalRes.data)) ? (portalRes.message || portalRes.data) : 'Could not open subscription management. Please try again.');\n                }\n                window.location.href = portalRes.url;\n                return;\n            }\n        } catch (preflightErr) {\n            checkoutLog('checkout.preflight.error', { message: preflightErr && preflightErr.message ? preflightErr.message : String(preflightErr) });\n            showCheckoutError(preflightErr && preflightErr.message ? preflightErr.message : 'We could not verify your current membership. Please try again.');\n            return;\n        }\n\n        var billingDetails = null;\n        var skipCompletion = hasEverSubscribed(accountRes, currentTier, user) && hasCompleteBillingAddress(accountRes, user);\n        if (!skipCompletion) {\n            billingDetails = await requestCheckoutBillingDetails(accountRes, user, tier);\n            if (!billingDetails) {\n                checkoutLog('checkout.profile_completion.cancelled', { tier: tier });\n                return;\n            }\n            try {\n                accountRes = await BUDDYUP.apiRequest('account-get', { id: user.id, _force: true });\n            } catch (refreshErr) {\n                checkoutLog('checkout.profile_completion.refresh_error', { message: refreshErr && refreshErr.message ? refreshErr.message : String(refreshErr) });\n            }\n        } else {\n            checkoutLog('checkout.profile_completion.skipped', { reason: 'prior_subscription_history' });\n        }\n\n        var tierName = tier === 2 ? 'Enthusiast' : 'Adventurer';\n        var subscriptionConsent = await requestSubscriptionConsent(tierName, productId, billingInterval);\n        if (!subscriptionConsent || !subscriptionConsent.accepted) {\n            checkoutLog('checkout.subscription_consent.cancelled', { tier: tier, interval: billingInterval });\n            return;\n        }\n\n        document.querySelector('html').style.overflow = 'hidden';\n        var modalHtml = '<div id=\"buddyUpCheckoutOverlay\">' +\n            '<div id=\"buddyUpCheckoutModal\">' +\n                '<div id=\"buddyUpCheckoutHeader\">' +\n                    '<h3>Subscribe \u2014 ' + tierName + ' (' + (billingInterval === 'year' ? 'Annual' : 'Monthly') + ')<\/h3>' +\n                    '<button id=\"buddyUpCheckoutClose\" aria-label=\"Close checkout\">&times;<\/button>' +\n                '<\/div>' +\n                '<div id=\"buddyUpCheckoutBody\">' +\n                    '<div id=\"buddyUpCheckoutLoading\">Preparing checkout&hellip;<\/div>' +\n                    '<div id=\"buddyUpCheckoutProcessing\">' +\n                        '<div class=\"buddyUpCheckoutProcessingInner\">' +\n                            '<div class=\"buddyUpCheckoutSpinner\"><\/div>' +\n                            '<p id=\"buddyUpCheckoutProcessingMessage\" style=\"margin:0 0 8px 0; font-weight:600;\">Processing payment...<\/p>' +\n                            '<p class=\"textSmall\" style=\"margin:0; opacity:.85;\">Please keep this window open while we activate your subscription.<\/p>' +\n                        '<\/div>' +\n                    '<\/div>' +\n                '<\/div>' +\n                '<div id=\"buddyUpCheckoutSuccess\">' +\n                    '<i class=\"fas fa-check-circle\"><\/i>' +\n                    '<h3>Payment Received!<\/h3>' +\n                    '<p>Your subscription is active. Redirecting you to your account now.<\/p>' +\n                    '<p style=\"margin-top:12px;\"><a id=\"buddyUpCheckoutSuccessContinue\" class=\"buddyUpButton1\" href=\"#\">Go to Account<\/a><\/p>' +\n                '<\/div>' +\n            '<\/div>' +\n        '<\/div>';\n        document.body.insertAdjacentHTML('beforeend', modalHtml);\n        document.getElementById('buddyUpCheckoutClose').addEventListener('click', closeCheckoutModal);\n        document.getElementById('buddyUpCheckoutOverlay').addEventListener('click', function(e) {\n            if (e.target === this) closeCheckoutModal();\n        });\n\n        try {\n            var customerPayload = buildCheckoutCustomerPayload(user, accountRes, billingDetails);\n            var loading = document.getElementById('buddyUpCheckoutLoading');\n            if (loading) loading.innerHTML = 'Loading secure payment form&hellip;';\n\n            var accountReturnLink = (typeof buddyUpVariables !== 'undefined' && buddyUpVariables.account_link)\n                ? String(buddyUpVariables.account_link)\n                : '\/buddyup\/account';\n            var accountReturnUrl = new URL(accountReturnLink, window.location.origin);\n            accountReturnUrl.searchParams.set('stripe_return', '1');\n            accountReturnUrl.searchParams.set('subscription_success', '1');\n            accountReturnUrl.searchParams.set('subscription_tier', String(tier));\n            accountReturnUrl.searchParams.set('billing_interval', billingInterval);\n            accountReturnUrl.searchParams.set('session_id', '{CHECKOUT_SESSION_ID}');\n            var returnUrl = accountReturnUrl.toString().replace('%7BCHECKOUT_SESSION_ID%7D', '{CHECKOUT_SESSION_ID}');\n            var sessionRes = await BUDDYUP.apiRequest('stripe-create-checkout-session', {\n                tier: tier,\n                product_id: productId,\n                billing_interval: billingInterval,\n                subscription_consent: true,\n                subscription_consent_method: subscriptionConsent.method,\n                subscription_terms_version: subscriptionConsent.terms_version,\n                customer: customerPayload,\n                user_id: user.id,\n                user_token: user.user_token || '',\n                return_url: returnUrl,\n                _force: true\n            });\n\n            if (!sessionRes || sessionRes.status === 'error' || !sessionRes.client_secret || !sessionRes.publishable_key) {\n                throw new Error((sessionRes && (sessionRes.message || sessionRes.data)) ? (sessionRes.message || sessionRes.data) : 'Could not initialize Stripe Checkout. Please try again.');\n            }\n\n            checkoutLog('stripe.checkout.session.ready', {\n                session_id: sessionRes.session_id || null,\n                has_client_secret: !!sessionRes.client_secret\n            });\n\n            var body = document.getElementById('buddyUpCheckoutBody');\n            if (loading) loading.remove();\n            var form = document.createElement('form');\n            form.id = 'buddyUpStripeCheckoutForm';\n            form.innerHTML =\n                '<div id=\"buddyUpStripePaymentElement\"><\/div>' +\n                '<div id=\"buddyUpStripePaymentMessage\" class=\"textSmall\"><\/div>' +\n                '<div class=\"buddyUpStripeCheckoutActions\">' +\n                    '<button type=\"submit\" id=\"buddyUpStripePayButton\" class=\"buddyUpButton1\">Subscribe securely<\/button>' +\n                '<\/div>';\n            body.appendChild(form);\n\n            var StripeCtor = await loadStripeJs();\n            var stripe = StripeCtor(sessionRes.publishable_key);\n            if (!stripe || typeof stripe.initCheckoutElementsSdk !== 'function') {\n                throw new Error('This Stripe.js version does not support custom Checkout Elements.');\n            }\n\n            var checkout = stripe.initCheckoutElementsSdk({\n                clientSecret: Promise.resolve(sessionRes.client_secret)\n            });\n            var paymentElement = checkout.createPaymentElement();\n            paymentElement.mount('#buddyUpStripePaymentElement');\n\n            form.addEventListener('submit', async function(e) {\n                e.preventDefault();\n                var payBtn = document.getElementById('buddyUpStripePayButton');\n                var msgEl = document.getElementById('buddyUpStripePaymentMessage');\n                if (payBtn) payBtn.setAttribute('disabled', 'disabled');\n                if (msgEl) {\n                    msgEl.style.display = 'none';\n                    msgEl.textContent = '';\n                }\n\n                try {\n                    showCheckoutProcessing('Payment submitted. Finalizing your subscription...');\n                    var loadActionsResult = await checkout.loadActions();\n                    var actions = loadActionsResult && loadActionsResult.actions;\n                    if (!actions || typeof actions.confirm !== 'function') {\n                        throw new Error('Stripe checkout actions are not available. Please refresh and try again.');\n                    }\n                    var confirmResult = await actions.confirm();\n                    if (confirmResult && confirmResult.error) {\n                        throw new Error(confirmResult.error.message || 'Payment could not be completed.');\n                    }\n\n                    var settled = await pollStripeCheckoutSession(sessionRes.session_id, tier);\n                    if (settled) {\n                        showCheckoutSuccess(tier);\n                        return;\n                    }\n                    showCheckoutProcessing('Payment submitted. Waiting for Stripe confirmation...');\n                } catch (payErr) {\n                    var message = payErr && payErr.message ? payErr.message : 'Payment could not be completed. Please try again.';\n                    checkoutLog('stripe.checkout.confirm.error', { message: message });\n                    var processing = document.getElementById('buddyUpCheckoutProcessing');\n                    if (processing) processing.style.display = 'none';\n                    if (msgEl) {\n                        msgEl.textContent = message;\n                        msgEl.style.display = 'block';\n                    } else {\n                        showCheckoutError(message);\n                    }\n                    if (payBtn) payBtn.removeAttribute('disabled');\n                }\n            });\n\n        } catch(err) {\n            showCheckoutError(err.message || 'An error occurred starting checkout. Please try again.');\n        }\n    };\n})();\n<\/script>\n\n<section id=\"tiersOverview\">\n    <h2>Overview of Subscription Tiers<\/h2>\n    <table id=\"desktopViewTable\">\n        <thead>\n            <tr>\n                <td>\n                    <strong>Features<\/strong>\n                <\/td>\n                                    <td>\n                        <strong>Explorer(Free)<\/strong>\n                                                    <span class=\"buddyUpTierInlinePrice\">Free<\/span>\n                                            <\/td>\n                                    <td>\n                        <strong>Adventurer<\/strong>\n                                                    <span class=\"buddyUpTierInlinePrice\" data-stripe-price=\"adventurer\" aria-live=\"polite\">Loading current price\u2026<\/span>\n                                            <\/td>\n                                    <td>\n                        <strong>Enthusiast<\/strong>\n                                                    <span class=\"buddyUpTierInlinePrice\" data-stripe-price=\"enthusiast\" aria-live=\"polite\">Loading current price\u2026<\/span>\n                                            <\/td>\n                            <\/tr>\n        <\/thead>\n        <tbody>\n            \n                            <tr>\n                    <th scope=\"row\">BuddyUp<\/th>\n                                            <td>10 right-swipes\/day and 3 reveals\/week<\/td>\n                                            <td>Unlimited right-swipes; see matches<\/td>\n                                            <td>Unlimited right-swipes; see who liked you<\/td>\n                                    <\/tr>\n                            <tr>\n                    <th scope=\"row\">Groups<\/th>\n                                            <td>Join and create up to 2 groups<\/td>\n                                            <td>Full interaction; create up to 3 premium groups<\/td>\n                                            <td>Full interaction; create up to 15 premium groups<\/td>\n                                    <\/tr>\n                            <tr>\n                    <th scope=\"row\">Events<\/th>\n                                            <td>Join and create up to 3\/month<\/td>\n                                            <td>Create up to 4\/month<\/td>\n                                            <td>Create unlimited events<\/td>\n                                    <\/tr>\n                            <tr>\n                    <th scope=\"row\">Event comments<\/th>\n                                            <td>1 image or video<\/td>\n                                            <td>Up to 3 media items<\/td>\n                                            <td>Up to 8 media items<\/td>\n                                    <\/tr>\n                            <tr>\n                    <th scope=\"row\">Buddies<\/th>\n                                            <td>Up to 25<\/td>\n                                            <td>Up to 75<\/td>\n                                            <td>Up to 1,500<\/td>\n                                    <\/tr>\n                            <tr>\n                    <th scope=\"row\">Messaging<\/th>\n                                            <td>5 messages\/day<\/td>\n                                            <td>Unlimited<\/td>\n                                            <td>Unlimited<\/td>\n                                    <\/tr>\n                            <tr>\n                    <th scope=\"row\">Profile media<\/th>\n                                            <td>Upload your own photo; no videos<\/td>\n                                            <td>Upload your own photo; up to 3 videos<\/td>\n                                            <td>Upload your own photo; up to 10 videos<\/td>\n                                    <\/tr>\n                            <tr>\n                    <th scope=\"row\">Privacy<\/th>\n                                            <td>Whole-profile privacy<\/td>\n                                            <td>Whole-profile privacy<\/td>\n                                            <td>Field-by-field controls<\/td>\n                                    <\/tr>\n                            <tr>\n                    <th scope=\"row\">Ads<\/th>\n                                            <td>Display ads<\/td>\n                                            <td>Display ads<\/td>\n                                            <td>Ad-free<\/td>\n                                    <\/tr>\n                    <\/tbody>\n    <\/table>\n    <div class=\"tierCardsOverview\">\n                    <table id=\"explorer(free)_overview_table\">\n                <thead class=\"tierNameTableMobile\">\n                    <tr>\n                        <td>\n                            Explorer(Free)                                                            <span class=\"buddyUpTierInlinePrice\">Free<\/span>\n                                                    <\/td>\n                    <\/tr>\n                <\/thead>\n                <tbody class=\"featureNameTableMobile\">\n                                        <tr>\n                        <td>BuddyUp: 10 right-swipes per day, limited info on matches, 3 reveals per week<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Groups: Can join but can't interact, create up to 2 free groups<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Events: Can view and join, create 3 free events per month (up to 25 attendees per event)<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Event Comments: Can comment with 1 image\/video<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Buddies: Up to 25<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Messaging: 5 messages per day<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Profile Videos: No videos<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Profile Image: Upload your own profile photo<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Privacy: All or nothing<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Ads: Display ads<\/td>\n                    <\/tr>\n                                    <\/tbody>\n            <\/table>\n                    <table id=\"adventurer_overview_table\">\n                <thead class=\"tierNameTableMobile\">\n                    <tr>\n                        <td>\n                            Adventurer                                                            <span class=\"buddyUpTierInlinePrice\" data-stripe-price=\"adventurer\" aria-live=\"polite\">Loading current price\u2026<\/span>\n                                                    <\/td>\n                    <\/tr>\n                <\/thead>\n                <tbody class=\"featureNameTableMobile\">\n                                        <tr>\n                        <td>BuddyUp: Unlimited right-swipes, see matches but not who swiped right<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Groups: Can fully interact, create up to 3 premium groups<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Events: Create up to 4 events per month<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Event Comments: Can comment with up to 3 images\/videos<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Buddies: Up to 75<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Messaging: Unlimited<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Profile Videos: 3 videos (30 sec total)<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Profile Image: Upload your own profile photo<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Privacy: All or nothing<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Ads: Display ads<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Planned perks: advanced planning\/filter tools<\/td>\n                    <\/tr>\n                                    <\/tbody>\n            <\/table>\n                    <table id=\"enthusiast_overview_table\">\n                <thead class=\"tierNameTableMobile\">\n                    <tr>\n                        <td>\n                            Enthusiast                                                            <span class=\"buddyUpTierInlinePrice\" data-stripe-price=\"enthusiast\" aria-live=\"polite\">Loading current price\u2026<\/span>\n                                                    <\/td>\n                    <\/tr>\n                <\/thead>\n                <tbody class=\"featureNameTableMobile\">\n                                        <tr>\n                        <td>BuddyUp: Unlimited right-swipes, see who swiped right<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Groups: Can fully interact, create up to 15 premium groups<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Events: Unlimited events<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Event Comments: Can comment with up to 8 images\/videos<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Buddies: Up to 1,500<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Messaging: Unlimited<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Profile Videos: 10 videos<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Profile Image: Upload your own profile photo<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Privacy: Granular control<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Ads: Ad free<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Planned perks: premium spotlight placement in Explore\/BuddyUp<\/td>\n                    <\/tr>\n                                    <\/tbody>\n            <\/table>\n            <\/div>\n<\/section>\n\n<section id=\"tiersFootNotes\">\n    <span>\n        Explorer: 10 right swipes per day, 3 reveals per week, up to 5 messages per day, up to 2 groups, and up to 3 events per month.\n        Adventurer: unlimited swipes and messaging, up to 3 premium groups, and up to 4 events per month.\n        Enthusiast: unlimited swipes, reveals, messaging, and events, plus up to 15 premium groups.\n    <\/span>\n<\/section>\n\n\n\n\n\n<\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"templates\/full-width-no-header.php","meta":{"footnotes":""},"class_list":["post-478","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/staging.buddyupgo.com\/api\/wp\/v2\/pages\/478","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/staging.buddyupgo.com\/api\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/staging.buddyupgo.com\/api\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/staging.buddyupgo.com\/api\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/staging.buddyupgo.com\/api\/wp\/v2\/comments?post=478"}],"version-history":[{"count":1,"href":"https:\/\/staging.buddyupgo.com\/api\/wp\/v2\/pages\/478\/revisions"}],"predecessor-version":[{"id":479,"href":"https:\/\/staging.buddyupgo.com\/api\/wp\/v2\/pages\/478\/revisions\/479"}],"wp:attachment":[{"href":"https:\/\/staging.buddyupgo.com\/api\/wp\/v2\/media?parent=478"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}