{"id":478,"date":"2025-12-11T18:39:36","date_gmt":"2025-12-11T18:39:36","guid":{"rendered":"https:\/\/buddyupapi-staging.us35.cdn-alpha.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:\/\/buddyupapi-staging.us35.cdn-alpha.com\/subscription-tiers\/","title":{"rendered":"Subscription Tiers"},"content":{"rendered":"<div class=\"buddyUpPjaxContainer\" data-buddyup-pjax-container=\"1\"><style>@import url('https:\/\/fonts.googleapis.com\/css2?family=Google+Sans+Code:ital,wght@0,300..800;1,300..800&family=Roboto:ital,wght@0,100..900;1,100..900&display=swap');\n\n\/* Layout *\/\n#subscriptionTiers,\nsection#tiersOverview,\nsection#tiersFootNotes {\n    width: 90%;\n    max-width: 1200px;\n    margin: 0 auto;\n    padding: 0 15px;\n}\n\n#subscriptionTiers {\n    display: flex;\n    flex-direction: column;\n}\n\nsection#subscriptionTiers {\n    background-image: url(https:\/\/www.buddyupgo.com\/wp-content\/uploads\/interests-bg.jpg);\n    background-position: center;\n    background-repeat: no-repeat;\n    background-size: cover;\n    border-radius: var(--buddyup-panel-radius);\n    padding: clamp(20px, 5vw, 40px);\n}\n\nsection#tiersOverview {\n    border-radius: var(--buddyup-panel-radius);\n    padding: clamp(20px, 5vw, 40px);\n    margin: clamp(20px, 5vw, 40px) auto;\n    text-align: center;\n}\n\nsection#tiersFootNotes {\n    margin: 0 auto 40px;\n    font-size: clamp(0.75rem, 1.5vw, 0.9rem);\n    color: #555;\n}\n\n\/* Header *\/\n.centeredHeader {\n    text-align: center;\n    padding: 20px 0;\n}\n\n.centeredHeader h1 {\n    font-family: 'Roboto', sans-serif;\n    font-style: italic;\n    font-weight: 600;\n    font-size: clamp(1.5rem, 5vw, 2.5rem);\n    margin-bottom: 0.5rem;\n}\n\n\/* Tier Cards *\/\n.tiercardContainer {\n    display: flex;\n    justify-content: center;\n    gap: clamp(20px, 4vw, 30px);\n    flex-wrap: wrap;\n    margin: 0 auto;\n    flex-direction: row;\n}\n\n.tierCard {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    border: 1px solid #ccc;\n    border-radius: var(--buddyup-panel-radius);\n    padding: clamp(15px, 4vw, 20px);\n    text-align: center;\n    background-color: var(--buddyup-background);\n    width: 350px;\n    transition: transform 0.3s ease;\n}\n\n.tierCard:hover {\n    transform: scale(1.05);\n}\n\n.tierCard h2 {\n    font-family: 'Roboto', sans-serif;\n    font-weight: 600;\n    font-size: clamp(1.2rem, 3vw, 1.5rem);\n    margin: 0;\n    padding: 0;\n}\n\n.tierCard h3 {\n    font-family: 'Roboto', sans-serif;\n    font-style: italic;\n    font-size: clamp(0.9rem, 2vw, 1.1rem);\n    margin: 5px 0 10px;\n    padding: 0;\n}\n\n.tierCard ul.featuresList {\n    font-size: clamp(0.85rem, 2vw, 1rem);\n    padding-top: unset;\n    justify-self: center;\n}\n\n.tierCard ul.featuresList li {\n    text-align: left;\n    list-style: disc;\n    padding: 0;\n}\n\n.tierCard ul.featuresList li::before {\n    content: \"\";\n}\n\n\/* Buttons *\/\n.buttonContainer {\n    margin: 0 auto !important;\n}\n\n.subscribeButton {\n    background-color: var(--primary-color);\n    color: white;\n    border: none;\n    border-radius: 999px;\n    padding: 10px 20px;\n    font-size: clamp(0.9rem, 2vw, 1rem);\n    cursor: pointer;\n    transition: background-color 0.3s ease;\n}\n\n\/* Table *\/\nsection#tiersOverview table {\n    margin: 0 auto;\n    width: 100%;\n    border-collapse: collapse;\n    border-radius: var(--buddyup-control-radius);\n    font-size: clamp(0.85rem, 2vw, 1rem);\n}\n\nsection#tiersOverview td {\n    padding: clamp(8px, 2vw, 12px);\n    text-align: center;\n}\n\nsection#tiersOverview table#desktopViewTable thead,\nsection#tiersOverview .tierCardsOverview thead.tierNameTableMobile {\n    background-color: var(--buddyup-background);\n    color: black;\n}\n\nsection#tiersOverview .tierCardsOverview tbody.featureNameTableMobile {\n    background-color: #FFFFFF;\n    color: black;\n}\n\nsection#tiersOverview .tierCardsOverview {\n    display: none;\n}\n\n\/* Mobile *\/\n@media (max-width: 870px) {\n    section#tiersOverview,\n    section#subscriptionTiers .tierCard {\n        width: 300px;\n        align-items: unset;\n    }\n\n    section#tiersOverview {\n        padding: 0;\n    }\n\n    section#tiersOverview table#desktopViewTable {\n        display: none;\n    }\n\n    section#tiersOverview .tierCardsOverview {\n        display: grid;\n        grid-template-columns: 1fr;\n        gap: 15px;\n    }\n\n    .tiercardContainer {\n        grid-template-columns: 1fr;\n        margin: 0 auto;\n    }\n}\n\n@media (max-width: 480px) {\n    #subscriptionTiers,\n    section#tiersOverview,\n    section#tiersFootNotes {\n        padding: 10px;\n    }\n\n    .tierCard {\n        padding: 15px;\n    }\n}\n\n@media (max-width: 355px) {\n    section#subscriptionTiers .tierCard {\n        width: 100%;\n    }\n}\n<\/style>\n<script>\n    \/\/ Set tier ASAP from cached login data, so CSS can hide cards immediately.\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        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        } 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: 18px;\n        width: 100%;\n        margin: 0 0 20px;\n    }\n\n    .buddyUpTierCard {\n        background: #fff;\n        border: 1px solid rgba(0,0,0,0.08);\n        border-radius: 12px;\n        padding: 18px;\n        box-shadow: 0 8px 20px rgba(0,0,0,0.06);\n    }\n\n    .buddyUpTierCard h3 {\n        margin: 0 0 10px;\n    }\n\n    .buddyUpTierCard ul {\n        margin: 0 0 14px;\n        padding-left: 18px;\n    }\n\n    .buddyUpTierCard .buddyUpButton1 {\n        display: inline-block;\n        text-decoration: none;\n        cursor: pointer;\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 (0: show both, 1: show only Tier 2 card, 2: show message) *\/\n    html[data-buddyup-tier=\"1\"] #buddyUpCardAdventurer { display: none; }\n    html[data-buddyup-tier=\"2\"] #buddyUpSubscriptionCards { display: none; }\n    html[data-buddyup-tier=\"2\"] #buddyUpTier2Already { display: block; }\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: 85vh;\n        max-height: 85vh;\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: 1;\n        overflow: hidden;\n        position: relative;\n        min-height: 400px;\n    }\n    #buddyUpCheckoutBody iframe {\n        width: 100%;\n        height: 100%;\n        border: none;\n        display: block;\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    #buddyUpCheckoutProfileForm {\n        max-width: 680px;\n        margin: 0 auto;\n    }\n\n    .buddyUpCheckoutProfileGrid {\n        display: grid;\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n        gap: 10px 14px;\n    }\n\n    .buddyUpCheckoutProfileGrid .buddyUpInputWrapper {\n        margin-bottom: 0;\n    }\n\n    .buddyUpCheckoutProfileGrid .fullWidth {\n        grid-column: 1 \/ -1;\n    }\n\n    #buddyUpCheckoutProfileError {\n        margin-top: .7rem;\n    }\n\n    .buddyUpCheckoutProfileActions {\n        display: flex;\n        gap: .6rem;\n        justify-content: flex-end;\n        margin-top: 1rem;\n    }\n\n    @media (max-width: 700px) {\n        .buddyUpCheckoutProfileGrid {\n            grid-template-columns: 1fr;\n        }\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 { min-height: calc(var(--buddyup-mobile-usable-vh, 100dvh) - 60px); }\n    }\n<\/style>\n\n<section id=\"subscriptionTiers\" class=\"flexWrapper buddyUpContainer\">\n\n    <div id=\"buddyUpTier2Already\">\n        <h3>You are already subscribed (Tier 2: 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            <h3>Tier 1 \u2014 Adventurer<\/h3>\n            <ul>\n                                    <li>Create Premium Groups<\/li>\n                                    <li>Unlimited Right Swipes<\/li>\n                                    <li>Can Message Buddies<\/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            <h3>Tier 2 \u2014 Enthusiast<\/h3>\n            <ul>\n                                    <li>Comprehensive Privacy Controls<\/li>\n                                    <li>See Who Swiped Right on You<\/li>\n                                    <li>Create Multiple Premium Groups<\/li>\n                                    <li>Ad Free Experience<\/li>\n                                    <li>Create As Many Events As You Like<\/li>\n                                    <li>And Everything in Adventurer Tier<\/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    'use strict';\n\n    \/\/ Refresh tier from API so stale localStorage doesn't hide wrong cards\n    if (typeof BUDDYUP !== 'undefined' && BUDDYUP.resolveSubscriptionTier) {\n        BUDDYUP.resolveSubscriptionTier(true);\n    } else if (typeof BUDDYUP !== 'undefined' && BUDDYUP.apiRequest) {\n        BUDDYUP.apiRequest('account-get', { _force: true }).then(function(res) {\n            if (!res) return;\n            var tier = res.user_subscription ?? res.subscription ?? res.subscription_tier ?? res.tier ?? 0;\n            tier = parseInt(tier);\n            if (isNaN(tier) || ![0, 1, 2].includes(tier)) tier = 0;\n            document.documentElement.setAttribute('data-buddyup-tier', String(tier));\n        }).catch(function(){});\n    }\n\n    \/\/Checkout flow: create Hyfin customer with user context, then open payment link in modal\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\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                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            }\n        } catch (e) {}\n\n        try {\n            if (typeof data !== 'undefined') console.log('[BuddyUpCheckout]', label, data);\n            else console.log('[BuddyUpCheckout]', label);\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        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\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, 'hyfin_return')) out.hyfin_return = payload.hyfin_return;\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                \/\/ 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 iframe interaction.\n            if (_checkoutIframeLoadCount >= 1 && _checkoutInteractionCount > 0 && 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\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        };\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.hyfin_customer_id);\n            candidates.push(account.hyfin_customer_external_id);\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.hyfin_customer_id);\n            candidates.push(user.hyfin_customer_external_id);\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\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, ['mobile_phone']) || readFirstString(fallback, ['mobile_phone']) || '';\n        seed.city = readFirstString(account, ['city']) || readFirstString(fallback, ['city']) || '';\n        seed.state = readFirstString(account, ['state']) || readFirstString(fallback, ['state']) || '';\n        seed.postal_code = readFirstString(account, ['postal_code']) || readFirstString(fallback, ['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 || '',\n            address_line_2: completion.address_line_2 || '',\n            city: completion.city || readFirstString(account, ['city']) || readFirstString(fallback, ['city']) || '',\n            state: completion.state || readFirstString(account, ['state']) || readFirstString(fallback, ['state']) || '',\n            postal_code: completion.postal_code || readFirstString(account, ['postal_code']) || readFirstString(fallback, ['postal_code']) || '',\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 requestCheckoutProfileCompletion(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 style=\"margin-top:0;\">Complete your profile details before checkout. Returning subscribers can skip this step automatically.<\/p>' +\n                    '<div class=\"buddyUpCheckoutProfileGrid\">' +\n                        '<div class=\"buddyUpInputWrapper\">' +\n                            '<label for=\"checkoutFirstName\">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\">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\">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\">Zip Code <span class=\"requiredMessage\">*<\/span><\/label>' +\n                            '<input type=\"text\" id=\"checkoutZip\" value=\"' + BUDDYUP.escapeHtml(seed.postal_code) + '\" required \/>' +\n                        '<\/div>' +\n                        '<div class=\"buddyUpInputWrapper fullWidth\">' +\n                            '<label for=\"checkoutAddress1\">Street Address <span class=\"requiredMessage\">*<\/span><\/label>' +\n                            '<input type=\"text\" id=\"checkoutAddress1\" required \/>' +\n                        '<\/div>' +\n                        '<div class=\"buddyUpInputWrapper fullWidth\">' +\n                            '<label for=\"checkoutAddress2\">Address Line 2<\/label>' +\n                            '<input type=\"text\" id=\"checkoutAddress2\" \/>' +\n                        '<\/div>' +\n                        '<div class=\"buddyUpInputWrapper\">' +\n                            '<label for=\"checkoutCity\">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\">State <span class=\"requiredMessage\">*<\/span><\/label>' +\n                            '<input type=\"text\" id=\"checkoutState\" value=\"' + BUDDYUP.escapeHtml(seed.state) + '\" required \/>' +\n                        '<\/div>' +\n                        '<div class=\"buddyUpInputWrapper fullWidth\">' +\n                            '<label for=\"checkoutAboutMe\">About Me<\/label>' +\n                            '<textarea id=\"checkoutAboutMe\" rows=\"3\" placeholder=\"Tell us a little about what you want to do on BuddyUpGo.\">' + BUDDYUP.escapeHtml(seed.about_me) + '<\/textarea>' +\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, 'Complete Your Subscription Profile', '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            form.addEventListener('submit', async function(e) {\n                e.preventDefault();\n\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                    about_me: String((document.getElementById('checkoutAboutMe') || {}).value || '').trim(),\n                    email: seed.email || readFirstString(user || {}, ['email_address', 'email'])\n                };\n\n                if (!payload.first_name || !payload.last_name || !payload.mobile_phone || !payload.postal_code || !payload.address_line_1 || !payload.city || !payload.state) {\n                    errEl.textContent = 'Please complete all required fields before checkout.';\n                    errEl.classList.remove('hidden');\n                    return;\n                }\n\n                errEl.classList.add('hidden');\n                saveBtn.setAttribute('disabled', 'disabled');\n                saveBtn.textContent = 'Saving...';\n\n                try {\n                    var editPayload = {\n                        id: user.id,\n                        user_token: user.user_token,\n                        first_name: payload.first_name,\n                        last_name: payload.last_name,\n                        mobile_phone: payload.mobile_phone,\n                        city: payload.city,\n                        state: payload.state,\n                        postal_code: payload.postal_code\n                    };\n                    if (payload.about_me) {\n                        editPayload.about_me = payload.about_me;\n                    }\n\n                    var editRes = await BUDDYUP.apiRequest('account-edit', editPayload);\n                    if (!editRes || editRes.status !== 'success') {\n                        var msg = (editRes && (editRes.message || editRes.data)) ? (editRes.message || editRes.data) : 'Could not save your profile details.';\n                        throw new Error(String(msg));\n                    }\n\n                    var updated = accountDataFromResponse(editRes);\n                    if (updated && typeof updated === 'object') {\n                        var mergedUser = Object.assign({}, user, updated);\n                        if (typeof BUDDYUP.setUser === 'function') {\n                            BUDDYUP.setUser(mergedUser);\n                        } else if (window.localStorage) {\n                            localStorage.setItem('buddyup_user', JSON.stringify(mergedUser));\n                        }\n                    }\n\n                    BUDDYUP.closeModal();\n                    finish(payload);\n                } catch (saveErr) {\n                    errEl.textContent = saveErr && saveErr.message ? saveErr.message : 'Could not save your profile details.';\n                    errEl.classList.remove('hidden');\n                    saveBtn.removeAttribute('disabled');\n                    saveBtn.textContent = 'Checkout';\n                }\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    }\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            BUDDYUP.apiRequest('account-get', { _force: true }).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\n    function extractRecordsArray(res) {\n        if (!res) return [];\n        if (Array.isArray(res)) return res;\n        if (Array.isArray(res.records)) return res.records;\n        if (res.data && Array.isArray(res.data.records)) return res.data.records;\n        if (res.result && Array.isArray(res.result.records)) return res.result.records;\n        return [];\n    }\n\n    function parseRecordTimestamp(rec) {\n        if (!rec || typeof rec !== 'object') return null;\n\n        var candidates = ['updated_on', 'updated_at', 'paid_on', 'created_on', 'created_at', 'date'];\n        for (var i = 0; i < candidates.length; i++) {\n            var raw = rec[candidates[i]];\n            if (!raw && rec.subscription && typeof rec.subscription === 'object') {\n                raw = rec.subscription[candidates[i]];\n            }\n            if (!raw) continue;\n\n            var ts = Date.parse(String(raw));\n            if (Number.isFinite(ts)) return ts;\n        }\n\n        return null;\n    }\n\n    function isSubscriptionRecordActive(rec) {\n        if (!rec || typeof rec !== 'object') return false;\n\n        if (typeof rec.active !== 'undefined') {\n            if (rec.active === true) return true;\n            if (typeof rec.active === 'string') {\n                var v = rec.active.toLowerCase().trim();\n                return v === 'true' || v === '1' || v === 'yes' || v === 'on';\n            }\n            return false;\n        }\n\n        var status = (typeof rec.status === 'string' ? rec.status : '').toLowerCase().trim();\n        if (!status) return true;\n        return ['closed', 'cancelled', 'canceled', 'inactive', 'expired', 'failed'].indexOf(status) === -1;\n    }\n\n    function doesSubscriptionRecordMatchUser(rec, userId) {\n        if (!rec || typeof rec !== 'object') return false;\n        var uid = String(userId || '').trim();\n        if (!uid) return false;\n\n        var candidates = [];\n        candidates.push(rec.customer_external_id);\n        candidates.push(rec.external_id);\n        if (rec.customer && typeof rec.customer === 'object') {\n            candidates.push(rec.customer.external_id);\n            candidates.push(rec.customer.reference_number);\n        }\n\n        for (var i = 0; i < candidates.length; i++) {\n            var raw = candidates[i];\n            if (raw === null || typeof raw === 'undefined') continue;\n            var s = String(raw).trim();\n            if (!s) continue;\n            if (s === uid) return true;\n            var m = s.match(\/\\d+\/);\n            if (m && m[0] === uid) return true;\n        }\n\n        return false;\n    }\n\n    function inferTierFromSubscriptionRecord(rec) {\n        if (!rec || typeof rec !== 'object') return 0;\n\n        var textBits = [];\n        if (typeof rec.product_external_id === 'string') textBits.push(rec.product_external_id);\n        if (typeof rec.external_id === 'string') textBits.push(rec.external_id);\n        if (typeof rec.description === 'string') textBits.push(rec.description);\n        if (rec.product && typeof rec.product === 'object') {\n            if (typeof rec.product.external_id === 'string') textBits.push(rec.product.external_id);\n            if (typeof rec.product.name === 'string') textBits.push(rec.product.name);\n        }\n        var text = textBits.join(' ').toLowerCase();\n        if (text.indexOf('enthusiast') !== -1) return 2;\n        if (text.indexOf('adventurer') !== -1) return 1;\n\n        var amount = parseFloat(rec.amount);\n        if (Number.isFinite(amount)) {\n            if (Math.abs(amount - 8.99) < 0.06) return 2;\n            if (Math.abs(amount - 6.99) < 0.06) return 1;\n        }\n\n        return 0;\n    }\n\n    function expectedAmountForTier(tier) {\n        var t = normalizeTier(tier);\n        if (t === 1) return 6.99;\n        if (t === 2) return 8.99;\n        return null;\n    }\n\n    function startCheckoutReconciliation(userId, targetTier) {\n        checkoutLog('reconcile.start', { userId: userId, targetTier: targetTier });\n        if (_checkoutPollTimer) {\n            clearTimeout(_checkoutPollTimer);\n            _checkoutPollTimer = null;\n        }\n        _checkoutPollAttempts = 0;\n        _checkoutPollInFlight = false;\n\n        var currentUser = getCurrentUser();\n        var userToken = currentUser && currentUser.user_token ? String(currentUser.user_token) : '';\n    var expectedAmount = expectedAmountForTier(targetTier);\n        checkoutLog('reconcile.identity', { userId: userId, hasUserToken: !!userToken });\n\n        var maxAttempts = 180;\n        var pollEveryMs = 8000;\n        var nextFetchAllowedAt = 0;\n        var fetchBackoffMs = 10000;\n\n        async function runPoll() {\n            if (_checkoutComplete) return;\n            if (_checkoutPollInFlight) {\n                _checkoutPollTimer = setTimeout(runPoll, pollEveryMs);\n                return;\n            }\n\n            _checkoutPollInFlight = true;\n            try {\n                _checkoutPollAttempts += 1;\n                var nowMs = Date.now();\n                if (_checkoutSubmitLikely && !_checkoutProcessingVisible) {\n                    showCheckoutProcessing('Payment submitted. Finalizing your subscription...');\n                }\n                checkoutLog('reconcile.poll.attempt', {\n                    attempt: _checkoutPollAttempts,\n                    nextFetchInMs: Math.max(0, nextFetchAllowedAt - nowMs)\n                });\n\n                \/\/ Once submit is likely, prioritize a remote reconcile immediately.\n                if (_checkoutSubmitLikely && nowMs < nextFetchAllowedAt) {\n                    nextFetchAllowedAt = nowMs;\n                }\n\n                \/\/ Reconcile against Hyfin on a backoff schedule to avoid throttling.\n                if (nowMs >= nextFetchAllowedAt) {\n                    var reqNonce = Date.now();\n                    var reconcileRes = await BUDDYUP.apiRequest('hyfin-fetch-payments', {\n                        apply_for_user: String(userId),\n                        updated_after: _checkoutStartedAt,\n                        checkout_started_at: _checkoutStartedAt,\n                        expected_tier: targetTier,\n                        expected_amount: expectedAmount,\n                        only_successful: true,\n                        force_remote: true,\n                        id: userId,\n                        user_token: userToken,\n                        _cb: reqNonce,\n                        _force: true\n                    });\n                    checkoutLog('reconcile.poll.fetchPayments', reconcileRes && reconcileRes.reconciled ? reconcileRes.reconciled : reconcileRes);\n\n                    var recMeta = reconcileRes && reconcileRes.reconciled\n                        ? reconcileRes.reconciled\n                        : (reconcileRes && reconcileRes.data && reconcileRes.data.reconciled ? reconcileRes.data.reconciled : null);\n                    var appliedCount = recMeta && !isNaN(parseInt(recMeta.applied, 10)) ? parseInt(recMeta.applied, 10) : 0;\n                    if (appliedCount > 0) {\n                        checkoutLog('reconcile.poll.applied_detected', recMeta);\n                        showCheckoutSuccess(targetTier);\n                        return;\n                    }\n\n                    var msg = String((reconcileRes && reconcileRes.message) || '').toLowerCase();\n                    var isErr = !!(reconcileRes && reconcileRes.status === 'error');\n                    var isThrottled = msg.indexOf('thrott') !== -1;\n\n                    if (isThrottled) {\n                        fetchBackoffMs = Math.min(Math.max(fetchBackoffMs, 60000) * 2, 180000);\n                        nextFetchAllowedAt = Date.now() + fetchBackoffMs;\n                        checkoutLog('reconcile.poll.fetchBackoff', { reason: 'throttled', waitMs: fetchBackoffMs });\n                    } else if (isErr) {\n                        fetchBackoffMs = Math.min(Math.round(fetchBackoffMs * 1.6), 120000);\n                        nextFetchAllowedAt = Date.now() + fetchBackoffMs;\n                        checkoutLog('reconcile.poll.fetchBackoff', { reason: 'error', waitMs: fetchBackoffMs });\n                    } else {\n                        fetchBackoffMs = 8000;\n                        nextFetchAllowedAt = Date.now() + fetchBackoffMs;\n                    }\n\n                    \/\/ Some Hyfin products can expose subscription activation before payment rows become queryable.\n                    if (appliedCount <= 0 && ((_checkoutPollAttempts % 2 === 0) || _checkoutSubmitLikely)) {\n                        var subsReqNonce = Date.now() + 1;\n                        var subRes = await BUDDYUP.apiRequest('hyfin-fetch-subscriptions', {\n                            updated_after: _checkoutStartedAt,\n                            checkout_started_at: _checkoutStartedAt,\n                            apply_for_user: String(userId),\n                            id: userId,\n                            user_token: userToken,\n                            _cb: subsReqNonce,\n                            _force: true\n                        });\n\n                        var subRecords = extractRecordsArray(subRes);\n                        var checkoutStartTs = _checkoutStartedAt ? Date.parse(String(_checkoutStartedAt)) : NaN;\n                        var matched = 0;\n                        var recentMatched = 0;\n                        var bestTier = 0;\n\n                        for (var s = 0; s < subRecords.length; s++) {\n                            var rec = subRecords[s];\n                            if (!isSubscriptionRecordActive(rec)) continue;\n                            if (!doesSubscriptionRecordMatchUser(rec, userId)) continue;\n\n                            matched += 1;\n                            bestTier = Math.max(bestTier, inferTierFromSubscriptionRecord(rec));\n\n                            var recTs = parseRecordTimestamp(rec);\n                            if (Number.isFinite(checkoutStartTs) && Number.isFinite(recTs) && recTs >= (checkoutStartTs - 5000)) {\n                                recentMatched += 1;\n                            }\n                        }\n\n                        checkoutLog('reconcile.poll.subscriptions', {\n                            count: subRecords.length,\n                            matched: matched,\n                            recentMatched: recentMatched,\n                            bestTier: bestTier,\n                            targetTier: targetTier,\n                        });\n\n                        var tierSatisfied = (bestTier === 0 || bestTier >= targetTier);\n                        if (recentMatched > 0 && tierSatisfied) {\n                            checkoutLog('reconcile.poll.subscription_detected', {\n                                matched: matched,\n                                recentMatched: recentMatched,\n                                bestTier: bestTier,\n                            });\n                            \/\/ Subscription visibility is only a signal; wait for payment apply\/account tier confirmation.\n                            fetchBackoffMs = Math.min(fetchBackoffMs, 3000);\n                            nextFetchAllowedAt = Date.now();\n                        }\n\n                        if (matched > 0 && _checkoutSubmitLikely && _checkoutPollAttempts >= 8 && tierSatisfied) {\n                            checkoutLog('reconcile.poll.subscription_detected_fallback', {\n                                matched: matched,\n                                bestTier: bestTier,\n                                attempts: _checkoutPollAttempts,\n                            });\n                            fetchBackoffMs = Math.min(fetchBackoffMs, 3000);\n                            nextFetchAllowedAt = Date.now();\n                        }\n                    }\n                } else {\n                    checkoutLog('reconcile.poll.fetchPayments.skipped', {\n                        waitMs: Math.max(0, nextFetchAllowedAt - nowMs)\n                    });\n                }\n\n                var acct = await BUDDYUP.apiRequest('account-get', {\n                    _force: true,\n                    _cb: Date.now()\n                });\n                var dbTier = parseTierFromAccount(acct);\n                checkoutLog('reconcile.poll.account', { dbTier: dbTier, targetTier: targetTier });\n                if (dbTier >= targetTier) {\n                    showCheckoutSuccess(targetTier);\n                    return;\n                }\n\n                if (_checkoutPollAttempts >= maxAttempts && !_checkoutComplete) {\n                    checkoutLog('reconcile.poll.maxAttempts', { attempts: _checkoutPollAttempts });\n                    if (_checkoutPollTimer) clearTimeout(_checkoutPollTimer);\n                    _checkoutPollTimer = null;\n                    return;\n                }\n            } catch (pollErr) {\n                console.warn('[BuddyUp] Checkout reconciliation poll failed:', pollErr);\n                fetchBackoffMs = Math.min(Math.round(fetchBackoffMs * 1.6), 120000);\n                nextFetchAllowedAt = Date.now() + fetchBackoffMs;\n                checkoutLog('reconcile.poll.fetchBackoff', { reason: 'exception', waitMs: fetchBackoffMs });\n            } finally {\n                _checkoutPollInFlight = false;\n                if (!_checkoutComplete && _checkoutPollAttempts < maxAttempts) {\n                    _checkoutPollTimer = setTimeout(runPoll, pollEveryMs);\n                }\n            }\n        }\n\n        _checkoutPollTimer = setTimeout(runPoll, 5000);\n    }\n\n    \/\/ Listen for postMessage from the Hyfin return endpoint (same-origin iframe)\n    window.addEventListener('message', function(event) {\n        const checkoutIframe = document.querySelector('#buddyUpCheckoutBody iframe');\n        const fromCheckoutIframe = !!(checkoutIframe && checkoutIframe.contentWindow && event.source === checkoutIframe.contentWindow);\n\n        if (fromCheckoutIframe) {\n            const summary = summarizeMessagePayload(event.data);\n            checkoutLog('checkout.postMessage.iframe', {\n                origin: event.origin || null,\n                payload: summary,\n            });\n\n            \/\/ Best-effort submit detection from partner message payload text.\n            if (!_checkoutSubmitLikely && !_checkoutComplete) {\n                if (!canInferSubmitNow()) {\n                    checkoutLog('checkout.postMessage.submit_inference.skipped', {\n                        reason: 'gating',\n                        iframeLoadCount: _checkoutIframeLoadCount,\n                        interactionCount: _checkoutInteractionCount,\n                        msSinceFirstLoad: _checkoutLastIframeLoadAt ? (Date.now() - _checkoutLastIframeLoadAt) : null,\n                    });\n                } else {\n                    let blob = '';\n                    try {\n                        blob = typeof event.data === 'string'\n                            ? event.data.toLowerCase()\n                            : JSON.stringify(event.data || {}).toLowerCase();\n                    } catch (e) {\n                        blob = '';\n                    }\n\n                    \/\/ Deliberately strict: avoid \"payment\"\/\"auth\" generic boot messages.\n                    if (blob && \/(submit|submitted|submitting|processing|processed|redirecting|redirected|3ds|challenge|authorize|authorizing|authorized|otp)\/.test(blob)) {\n                        markCheckoutSubmitLikely('postMessage_keyword', {\n                            origin: event.origin || null,\n                            interactionCount: _checkoutInteractionCount,\n                            iframeLoadCount: _checkoutIframeLoadCount,\n                        });\n                    }\n                }\n            }\n        }\n\n        if (!event.data || typeof event.data !== 'object') return;\n        if (!event.data.hyfin_return) return;\n\n        checkoutLog('postMessage.received', event.data);\n\n        if (event.data.hyfin_return === 'ok') {\n            markCheckoutSubmitLikely('return_postmessage', {\n                activated: !!event.data.activated,\n                foundCount: Array.isArray(event.data.found) ? event.data.found.length : 0,\n            });\n            showCheckoutProcessing('Payment submitted. Finalizing your subscription...');\n        } else {\n            \/\/ Error or unknown token - still close gracefully\n            showCheckoutError('Payment could not be confirmed. Please check your account or try again.');\n        }\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\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        _checkoutIframeLoadCount = 0;\n        _checkoutLastIframeLoadAt = 0;\n        _checkoutSubmitLikely = false;\n        _checkoutSubmitLikelyReason = null;\n        _checkoutProcessingVisible = false;\n        _checkoutInteractionCount = 0;\n        _checkoutLastInteractionAt = 0;\n        _checkoutStartedAt = new Date(Date.now() - (2 * 60 * 1000)).toISOString();\n        checkoutLog('checkout.start', { userId: user && user.id, productId: productId, tier: tier, startedAt: _checkoutStartedAt });\n\n        \/\/ 1. Must be logged in\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        \/\/ Preflight guard: never allow same-tier (or lower) checkout while paid tier is active.\n        try {\n            accountRes = await BUDDYUP.apiRequest('account-get', { id: user.id, _force: true });\n            currentTier = parseTierFromAccount(accountRes);\n            if (currentTier >= tier) {\n                var msg = currentTier > tier\n                    ? 'Your account already has a higher active tier. This checkout is disabled.'\n                    : 'You already have this subscription tier active. You cannot purchase the same tier again.';\n                showCheckoutError(msg);\n                return;\n            }\n            if (currentTier > 0 && currentTier < tier) {\n                checkoutLog('checkout.upgrade.mode', { fromTier: currentTier, toTier: tier });\n            }\n        } catch (preflightErr) {\n            checkoutLog('checkout.preflight.error', { message: preflightErr && preflightErr.message ? preflightErr.message : String(preflightErr) });\n        }\n\n        var completionData = null;\n        var skipCompletion = hasEverSubscribed(accountRes, currentTier, user);\n        if (!skipCompletion) {\n            completionData = await requestCheckoutProfileCompletion(accountRes, user, tier);\n            if (!completionData) {\n                checkoutLog('checkout.profile_completion.cancelled', { tier: tier });\n                return;\n            }\n\n            \/\/ Refresh account after completion save so subsequent checks use fresh values.\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        \/\/ 2. Build the checkout modal with loading state\n        document.querySelector('html').style.overflow = 'hidden';\n        var tierName = tier === 2 ? 'Enthusiast' : 'Adventurer';\n        var modalHtml = '<div id=\"buddyUpCheckoutOverlay\">' +\n            '<div id=\"buddyUpCheckoutModal\">' +\n                '<div id=\"buddyUpCheckoutHeader\">' +\n                    '<h3>Subscribe \u2014 ' + tierName + '<\/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            \/\/ 3. Build the customer payload from account data + completion form values.\n            var customerPayload = buildCheckoutCustomerPayload(user, accountRes, completionData);\n\n            \/\/ Do not pre-create customer via API here; Rapid Checkout will create\/update\n            \/\/ the payer customer and this avoids duplicate customer records.\n\n            \/\/ 4. Store tier mapping so webhook\/return can infer which tier the user is purchasing\n            try {\n                var mappingRes = await BUDDYUP.apiRequest('hyfin-add-subscription', {\n                    external_id: 'buddyup_' + user.id + '_' + productId + '_' + Date.now(),\n                    tier: tier,\n                    customer: { external_id: String(user.id) },\n                    _store_mapping_only: true\n                });\n                checkoutLog('checkout.mapping.saved', mappingRes);\n            } catch(mapErr) {\n                console.warn('[BuddyUp] Tier mapping store failed (non-fatal):', mapErr);\n            }\n\n            \/\/ 5. Fetch payment link with user context (backend creates a correlation token)\n            var linkRes = await BUDDYUP.apiRequest('hyfin-get-payment-link', {\n                product_id: productId,\n                customer: {\n                    external_id: String(user.id),\n                    first_name: customerPayload.first_name,\n                    last_name: customerPayload.last_name,\n                    email: customerPayload.email,\n                    mobile_phone: customerPayload.mobile_phone,\n                    address_line_1: customerPayload.address_line_1,\n                    address_line_2: customerPayload.address_line_2,\n                    city: customerPayload.city,\n                    state: customerPayload.state,\n                    postal_code: customerPayload.postal_code\n                },\n                user_wp_id: user.id,\n                tier: tier,\n                _force: true\n            });\n\n            if (!linkRes || linkRes.status === 'error' || !linkRes.link) {\n                throw new Error(linkRes && linkRes.message ? linkRes.message : 'Could not load payment link. Please try again.');\n            }\n\n            checkoutLog('checkout.link.ready', {\n                token: linkRes.token || null,\n                return_url: linkRes.return_url || null,\n                hasLink: !!linkRes.link\n            });\n\n            _checkoutToken = linkRes.token || null;\n\n            \/\/ 6. Load Hyfin Rapid Checkout in modal iframe\n            var loading = document.getElementById('buddyUpCheckoutLoading');\n            if (loading) loading.innerHTML = 'Loading secure checkout&hellip;';\n\n            var iframe = document.createElement('iframe');\n            iframe.src = linkRes.link;\n            iframe.title = tierName + ' checkout';\n            iframe.setAttribute('allow', 'payment');\n            iframe.addEventListener('load', function() {\n                _checkoutIframeLoadCount += 1;\n                _checkoutLastIframeLoadAt = Date.now();\n                checkoutLog('checkout.iframe.load', { src: iframe.src, count: _checkoutIframeLoadCount });\n\n                if (_checkoutIframeLoadCount === 1) {\n                    if (loading) loading.remove();\n                    return;\n                }\n\n                if (_checkoutIframeLoadCount >= 2 && !_checkoutSubmitLikely && !_checkoutComplete) {\n                    markCheckoutSubmitLikely('iframe_second_load', {\n                        count: _checkoutIframeLoadCount,\n                        msSinceLastInteraction: _checkoutLastInteractionAt ? (Date.now() - _checkoutLastInteractionAt) : null,\n                    });\n                    checkoutLog('checkout.iframe.submit_likely', {\n                        count: _checkoutIframeLoadCount,\n                        reason: _checkoutSubmitLikelyReason,\n                    });\n                }\n            });\n            document.getElementById('buddyUpCheckoutBody').appendChild(iframe);\n            installCheckoutObservers(iframe);\n\n            \/\/ Rapid checkout does not always redirect to return_url in iframe mode.\n            \/\/ Poll backend reconciliation so successful payment webhooks still activate DB subscription.\n            startCheckoutReconciliation(user.id, tier);\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                    <\/td>\n                                    <td>\n                        <strong>Adventurer<\/strong>\n                    <\/td>\n                                    <td>\n                        <strong>Enthusiast<\/strong>\n                    <\/td>\n                            <\/tr>\n        <\/thead>\n        <tbody>\n            \n                            <tr>\n                    <td>MatchUp: 5 right-swipes per day, limited info on matches<\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Groups: Can join but can't interact, create 1 free group (no discussions, photos, ratings)<\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Events: Can view and join, create 1 free event (10 people limit)<\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Event Comments: Can view only<\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Buddies: Up to 10<\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Messaging: 1 message per day<\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Profile Videos: No videos<\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Profile Images: BuddyUp stock images only<\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Privacy: All or nothing<\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Ads: Display ads<\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>MatchUp: Unlimited right-swipes, see matches but not who swiped right<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Groups: Can fully interact, create 1 premium group<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Events: Create 2 events per month<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Event Comments: Can comment with 1 image\/video<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Buddies: Up to 50<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Messaging: Unlimited<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Profile Videos: 3 videos (30 sec total)<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Profile Images: Custom uploads unlocked (up to 5 changes)<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>MatchUp: Unlimited right-swipes, see who swiped right<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Groups: Can fully interact, create up to 10 premium groups<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Events: Unlimited events<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Event Comments: Can comment with 5 images\/videos<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Buddies: Up to 1000<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Profile Videos: 10 videos<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Profile Images: Custom uploads unlocked (up to 10 changes)<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Privacy: Granular control<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/td>\n                                    <\/tr>\n                            <tr>\n                    <td>Ads: Ad free<\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u274c                        <\/td>\n                                            <td>\n                            \u2714\ufe0f                        <\/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>Explorer(Free)<\/td>\n                    <\/tr>\n                <\/thead>\n                <tbody class=\"featureNameTableMobile\">\n                                        <tr>\n                        <td>MatchUp: 5 right-swipes per day, limited info on matches<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Groups: Can join but can't interact, create 1 free group (no discussions, photos, ratings)<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Events: Can view and join, create 1 free event (10 people limit)<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Event Comments: Can view only<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Buddies: Up to 10<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Messaging: 1 message per day<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Profile Videos: No videos<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Profile Images: BuddyUp stock images only<\/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>Adventurer<\/td>\n                    <\/tr>\n                <\/thead>\n                <tbody class=\"featureNameTableMobile\">\n                                        <tr>\n                        <td>MatchUp: Unlimited right-swipes, see matches but not who swiped right<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Groups: Can fully interact, create 1 premium group<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Events: Create 2 events per month<\/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 50<\/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 Images: Custom uploads unlocked (up to 5 changes)<\/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=\"enthusiast_overview_table\">\n                <thead class=\"tierNameTableMobile\">\n                    <tr>\n                        <td>Enthusiast<\/td>\n                    <\/tr>\n                <\/thead>\n                <tbody class=\"featureNameTableMobile\">\n                                        <tr>\n                        <td>MatchUp: Unlimited right-swipes, see who swiped right<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Groups: Can fully interact, create up to 10 premium groups<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Events: Unlimited events<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Event Comments: Can comment with 5 images\/videos<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Buddies: Up to 1000<\/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 Images: Custom uploads unlocked (up to 10 changes)<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Privacy: Granular control<\/td>\n                    <\/tr>\n                                        <tr>\n                        <td>Ads: Ad free<\/td>\n                    <\/tr>\n                                    <\/tbody>\n            <\/table>\n            <\/div>\n<\/section>\n\n<section id=\"tiersFootNotes\">\n    <span>\n        MatchUp restrictions for Explorer Tier: 5 right swipes per day. Group restrictions for Explorer Tier: Can join, but not interact.\n         Group restrictions for Explorer Tier: Can create 1 group. Group restrictions for Adventurer Tier: Can create 1 premium group.\n         Group restrictions for Enthusiast Tier: Can create 10 premium groups.\n    <\/span>\n<\/section><\/div>","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:\/\/buddyupapi-staging.us35.cdn-alpha.com\/api\/wp\/v2\/pages\/478","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/buddyupapi-staging.us35.cdn-alpha.com\/api\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/buddyupapi-staging.us35.cdn-alpha.com\/api\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/buddyupapi-staging.us35.cdn-alpha.com\/api\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/buddyupapi-staging.us35.cdn-alpha.com\/api\/wp\/v2\/comments?post=478"}],"version-history":[{"count":1,"href":"https:\/\/buddyupapi-staging.us35.cdn-alpha.com\/api\/wp\/v2\/pages\/478\/revisions"}],"predecessor-version":[{"id":479,"href":"https:\/\/buddyupapi-staging.us35.cdn-alpha.com\/api\/wp\/v2\/pages\/478\/revisions\/479"}],"wp:attachment":[{"href":"https:\/\/buddyupapi-staging.us35.cdn-alpha.com\/api\/wp\/v2\/media?parent=478"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}