<!DOCTYPE html>
<html lang="en" class="boot-screen-active">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
    <title>Pick the Cure, Steer Clear of Risk</title>
    <meta name="theme-color" content="#ffffff">
    <!-- Favicon -->
    <link rel="icon" type="image/svg+xml" href="/favicon.svg">
    <!-- PWA: manifest.webmanifest 由 vite-plugin-pwa 在 build 时自动注入 link，dev 也通过插件接管 -->
    <!-- iOS PWA: Safari 不读 manifest 的 icons 与 display，必须显式声明以下 4 项 -->
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="apple-mobile-web-app-title" content="Pickcure">
    <link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png?v=2">
    <!-- 避免首屏依赖海外字体 CDN，防止在受限网络下阻塞主模块执行 -->
    <style>
        html.boot-screen-active,
        html.boot-screen-active body {
            background: #ffffff;
        }

        body {
            font-family: "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
                "Noto Sans SC", "Helvetica Neue", Arial, sans-serif;
            scroll-behavior: smooth;
        }

        #loading-state {
            position: fixed;
            inset: 0;
            background: #ffffff;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 9000;
            transition: opacity 0.5s ease-out;
        }

        /* PMQR Icon Animations - 只保留透明度变化，移除所有 transform */
        @keyframes pmqr-synaptic-breathe {

            0%,
            100% {
                opacity: 0.9;
            }

            50% {
                opacity: 1;
            }
        }

        @keyframes pmqr-orbital-scan {

            0%,
            100% {
                opacity: 1;
            }
        }

        @keyframes pmqr-axis-rotate {
            from {
                transform: rotate(0deg);
            }

            to {
                transform: rotate(360deg);
            }
        }

        /* Keep the wordmark visually connected to, but not touching, the icon. */
        @keyframes text-bounce {

            0%,
            100% {
                transform: translateY(3px);
            }

            50% {
                transform: translateY(-3px);
            }
        }

        @keyframes pmqr-sclera-pulse {

            0%,
            100% {
                transform: scale(0.95);
                opacity: 0.3;
            }

            50% {
                transform: scale(1.05);
                opacity: 0.6;
            }
        }

        @keyframes pmqr-data-flow {
            0% {
                transform: translateY(45px);
                opacity: 0;
            }

            20% {
                opacity: 0.8;
            }

            80% {
                opacity: 0.8;
            }

            100% {
                transform: translateY(0px);
                opacity: 0;
            }
        }

        .pmqr-loader-svg {
            width: 120px;
            height: 120px;
            filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1));
        }

        .pmqr-iris-group {
            transform-origin: center;
            animation: pmqr-synaptic-breathe 4s ease-in-out infinite;
        }

        .pmqr-pupil-group {
            transform-origin: center;
            animation: pmqr-orbital-scan 8s ease-in-out infinite;
        }

        .pmqr-axes-container {
            transform-origin: center;
            animation: pmqr-axis-rotate 30s linear infinite;
        }

        .pmqr-sclera-beam {
            transform-origin: center;
            animation: pmqr-sclera-pulse 5s ease-in-out infinite;
        }

        .pmqr-data-particle {
            fill: #fbbf24;
            animation: pmqr-data-flow 2s linear infinite;
        }

        /* Keep the boot wordmark in sync with components/BrandWordmark.tsx. */
        .loading-title {
            margin-top: 0.4rem;
            font-size: 1.125rem;
            line-height: 1;
            font-weight: 700;
            letter-spacing: normal;
            color: #020617;
            text-align: center;
            animation: text-bounce 1.5s ease-in-out infinite;
        }

        .loading-title-cure {
            color: #1e6fd9;
        }

        #error-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(255, 255, 255, 0.98);
            z-index: 9999;
            padding: 2rem;
            color: #ef4444;
            overflow: auto;
        }
    </style>



    <script src="/boot-i18n.js"></script>
    <script>
        // Minimal Localization for Boot: prefer saved app language, then browser
        let savedLang = null;
        try {
            savedLang = typeof localStorage !== 'undefined' ? localStorage.getItem('pickcure_lang') : null;
        } catch (e) {
            savedLang = null;
        }
        const validLangs = ['en', 'zh', 'fr', 'ru', 'ar', 'es', 'id', 'th', 'fa'];
        let langCode = (savedLang && validLangs.indexOf(savedLang) !== -1) ? savedLang : 'en';
        if (langCode === 'en') {
            const userLang = navigator.language || 'en';
            if (userLang.startsWith('zh')) langCode = 'zh';
            else if (userLang.startsWith('fr')) langCode = 'fr';
            else if (userLang.startsWith('ru')) langCode = 'ru';
            else if (userLang.startsWith('ar')) langCode = 'ar';
            else if (userLang.startsWith('es')) langCode = 'es';
            else if (userLang.startsWith('id')) langCode = 'id';
            else if (userLang.startsWith('th')) langCode = 'th';
            else if (userLang.startsWith('fa')) langCode = 'fa';
        }
        const LANG = langCode;

        const BOOT_I18N = window.__PICKCURE_BOOT_I18N__ || {};
        const FALLBACK_BOOT_EN = {
            boot_loading: "Pick the cure, steer clear of Risk",
            boot_timeout_msg: "The application failed to initialize within 30 seconds.\nPossible causes:\n1. JS resources are blocked by CDN or firewall\n2. Javascript execution froze due to version conflicts\n3. Try enabling VPN or switching network",
            boot_err_title: "Startup Failed",
            boot_err_desc: "Please check the console for details or try reloading.",
            boot_retry: "Retry",
            boot_net_check: "Detect",
            boot_runtime_error_prefix: "Runtime Error: ",
            boot_network_hint: "\nHint: This might be caused by network instability. Please check your connection or wait a moment before retrying."
        };
        const t = BOOT_I18N[LANG] || BOOT_I18N.en || FALLBACK_BOOT_EN;
        const bootErrorLines = new Set();
        window.appLoaded = false;
        window.appVisualReady = false;
        window.bootTerminalShown = false;

        function showBootOverlay(titleText) {
            const loader = document.getElementById('loading-state');
            const overlay = document.getElementById('error-overlay');
            const title = document.getElementById('error-title');
            const desc = document.getElementById('error-desc');
            const btn = document.getElementById('retry-btn');
            const networkBtn = document.getElementById('network-help-btn');

            if (loader) loader.style.display = 'none';
            document.documentElement.classList.remove('boot-screen-active');
            if (overlay) {
                overlay.style.display = 'block';
                window.bootTerminalShown = true;
            }
            if (title && titleText) title.textContent = titleText;
            if (desc) desc.textContent = t.boot_err_desc;
            if (btn) btn.textContent = t.boot_retry;
            if (networkBtn) networkBtn.textContent = t.boot_net_check || (LANG === 'zh' ? '网络' : 'Detect');
            const detailsToggle = document.getElementById('error-details-toggle');
            if (detailsToggle) detailsToggle.textContent = t.boot_show_details || 'Show technical details';
        }

        function setBootErrorMessage(message) {
            const txt = document.getElementById('error-message');
            if (!txt) return;
            txt.textContent = String(message || '');
        }

        function appendBootErrorLine(message) {
            const line = String(message || '').trim();
            const txt = document.getElementById('error-message');
            if (!line || !txt || bootErrorLines.has(line)) return;
            bootErrorLines.add(line);
            txt.textContent += (txt.textContent ? "\n" : "") + line;
        }

        function formatBootDiagnosticLine(bootDiag) {
            if (!bootDiag) return '';
            const prefix = t.boot_diagnostic_prefix || 'Startup diagnostic: ';
            const message = t.boot_diag_mismatch || 'A JS resource returned invalid content.';
            return `${prefix}${message}`;
        }

        function openUnavailablePage() {
            try {
                const current = new URL(window.location.href);
                const helpUrl = new URL('/pwa-unavailable.html', window.location.origin);
                helpUrl.searchParams.set('target', current.pathname + current.search + current.hash);
                window.location.href = helpUrl.toString();
                return;
            } catch (err) {
                // ignore and fallback below
            }
            window.location.href = '/pwa-unavailable.html';
        }

        function isSilentIndexedDbDisconnectMessage(rawMessage) {
            const message = String(rawMessage || '').toLowerCase();
            if (!message) return false;
            return message.includes('connection to indexeddatabase server lost')
                || message.includes('connection to indexeddb server lost')
                || message.includes('connection to indexed database server lost')
                || message.includes('connection to indexeddatabase')
                || message.includes('connection to indexeddb')
                || message.includes('connection to indexed database')
                || message.includes('indexed database server lost')
                || message.includes('database connection is closing');
        }

        // Tier 1 silent filter: transient/benign errors that should NOT show the boot
        // overlay. Covers AbortController cancellations (React 18 StrictMode + nav teardown),
        // Safari/Firefox fetch teardown noise, ResizeObserver benign loops, CORS-stripped
        // cross-origin "Script error.", and browser extension stack frames.
        // Tracked separately from the IDB filter so console.warn output can distinguish causes.
        function isTransientSilentError(rawMessage, errorObj) {
            const message = String(rawMessage || '').toLowerCase().trim();
            const errName = (errorObj && errorObj.name) ? String(errorObj.name) : '';

            if (looksLikeModuleChunkFailure(rawMessage, errorObj)) return false;

            // 1. AbortController cancellations
            if (errName === 'AbortError') return true;
            if (message.includes('the operation was aborted')) return true;
            if (message.includes('the user aborted a request')) return true;
            if (message === 'cancelled' || message === 'canceled') return true;
            if (message.endsWith(': cancelled') || message.endsWith(': canceled')) return true;

            // 2. Safari/Firefox transient fetch failures during page teardown
            //    (Safari "Load failed" is the iOS-PWA equivalent of the IDB disconnect noise)
            if (message === 'load failed') return true;
            if (message.endsWith(': load failed')) return true;
            if (message.includes('networkerror when attempting to fetch resource')) return true;

            // 3. ResizeObserver benign loops (no actual user-visible problem)
            if (message.includes('resizeobserver loop')) return true;

            // 4. Cross-origin script error stripped by CORS (no actionable info)
            if (message === 'script error.' || message === 'script error') return true;

            // 5. Browser extension noise (not our code)
            const stackRaw = (errorObj && (errorObj.stack || errorObj.fileName || errorObj.filename)) || '';
            const stack = String(stackRaw).toLowerCase();
            if (stack.includes('chrome-extension://')) return true;
            if (stack.includes('moz-extension://')) return true;
            if (stack.includes('safari-web-extension://')) return true;
            if (stack.includes('safari-extension://')) return true;

            // 6. Firebase Auth redirect errors (storage-partitioned PWA / cleared sessionStorage).
            //    These are non-fatal: AuthModal.handleError already handles them in-app.
            //    Suppress here to prevent the boot overlay from killing the UI before React can
            //    render the graceful in-modal error message.
            if (message.includes('pending promise was never set')) return true;
            if (message.includes('missing initial state')) return true;
            if (message.includes('sessionstorage is inaccessible')) return true;
            if (message.includes('storage-partitioned browser environment')) return true;

            return false;
        }

        function attemptSingleRecoveryReload(reason, detail) {
            console.warn(reason, detail);
            var forceRecovery = detail && detail.force === true;
            if (window.appLoaded && !forceRecovery) return false; // 已经进入应用后不再强制刷新，关键 CSS 恢复除外
            var marker = detail && detail.marker
                ? String(detail.marker)
                : (forceRecovery ? 'reloaded-after-runtime-chunk-error' : 'reloaded-after-error');
            if (window.name.includes(marker)) return false;
            // 全局恢复次数上限：同一会话内最多自动恢复 2 次，超过后直接展示错误页
            // 防止 CDN 故障/文件丢失场景下的无限刷新循环，耗尽移动设备电量
            var recoveryCount = 0;
            try {
                recoveryCount = parseInt(sessionStorage.getItem('pickcure_recovery_count') || '0', 10) || 0;
            } catch (_ignored) {}
            if (recoveryCount >= 2) {
                console.error('[boot] Recovery limit reached, stopping automatic reloads.');
                return false;
            }
            try {
                sessionStorage.setItem('pickcure_recovery_count', String(recoveryCount + 1));
            } catch (_ignored2) {}
            window.name += ';' + marker;

            var navigationStarted = false;
            function doReload() {
                if (navigationStarted) return;
                navigationStarted = true;
                try {
                    var url = new URL(window.location.href);
                    url.searchParams.set('pv', String(Date.now()));
                    window.location.replace(url.pathname + url.search + url.hash);
                } catch (_e) {
                    window.location.reload();
                }
            }

            function activateWaitingWorker(registration, waiting) {
                var settled = false;
                var timer = null;

                function finish() {
                    if (settled) return;
                    settled = true;
                    if (timer !== null) window.clearTimeout(timer);
                    navigator.serviceWorker.removeEventListener('controllerchange', finish);
                    waiting.removeEventListener('statechange', onStateChange);
                    doReload();
                }

                function onStateChange() {
                    if (waiting.state === 'activated' || waiting.state === 'redundant') finish();
                }

                navigator.serviceWorker.addEventListener('controllerchange', finish);
                waiting.addEventListener('statechange', onStateChange);
                timer = window.setTimeout(finish, 8000);
                try {
                    waiting.postMessage({ type: 'SKIP_WAITING' });
                    onStateChange();
                } catch (_e) {
                    finish();
                }
            }

            function inspectUpdateBeforeReload(registration) {
                if (registration.waiting) {
                    activateWaitingWorker(registration, registration.waiting);
                    return;
                }

                // `update()` only starts the browser's update check. Poll because the
                // installing/waiting transition happens asynchronously on Safari/iOS.
                try {
                    var updatePromise = registration.update();
                    if (updatePromise && typeof updatePromise.catch === 'function') {
                        updatePromise.catch(function () { /* offline: keep the old worker */ });
                    }
                } catch (_e) {
                    // Keep the old, still usable worker and fall through to one reload.
                }

                var deadline = Date.now() + 8000;
                var poll = window.setInterval(function () {
                    if (registration.waiting) {
                        window.clearInterval(poll);
                        activateWaitingWorker(registration, registration.waiting);
                        return;
                    }
                    if (Date.now() >= deadline) {
                        window.clearInterval(poll);
                        doReload();
                    }
                }, 200);
            }

            // Recovery is state-aware: hand a fully installed waiting worker control
            // before navigating. Never unregister or purge caches automatically; the
            // explicit Retry button remains the only destructive repair path.
            if ('serviceWorker' in navigator) {
                navigator.serviceWorker.getRegistration()
                    .then(function (registration) {
                        if (!registration) {
                            doReload();
                            return;
                        }
                        inspectUpdateBeforeReload(registration);
                    })
                    .catch(doReload);
            } else {
                doReload();
            }
            return true;
        }

        function clearBootRecoveryMarker() {
            try {
                window.name = window.name
                    .split(';')
                    .filter(function (part) {
                        return part
                            && part !== 'reloaded-after-error'
                            && part !== 'reloaded-after-runtime-chunk-error'
                            && part !== 'reloaded-after-boot-timeout';
                    })
                    .join(';');
            } catch {
                // ignore
            }
        }

        function retryBootLoad() {
            clearBootRecoveryMarker();

            function doRetry() {
                try {
                    const url = new URL(window.location.href);
                    url.searchParams.set('pv', String(Date.now()));
                    window.location.replace(`${url.pathname}${url.search}${url.hash}`);
                } catch {
                    window.location.reload();
                }
            }

            // Explicit user repair: clear stale SW/cache only after automatic recovery failed.
            function purgeRetry() {
                if (typeof caches === 'undefined') return Promise.resolve();
                return caches.keys().then(function (keys) {
                    return Promise.all(keys.map(function (k) { return caches.delete(k).catch(function () { }); }));
                }).catch(function () { });
            }
            if (navigator.serviceWorker && navigator.serviceWorker.getRegistrations) {
                var fallbackTimer = setTimeout(doRetry, 2000);
                Promise.all([
                    navigator.serviceWorker.getRegistrations().then(function (regs) {
                        return Promise.all(regs.map(function (r) { return r.unregister(); }));
                    }),
                    purgeRetry()
                ]).then(function () {
                    clearTimeout(fallbackTimer);
                    doRetry();
                }).catch(function () {
                    clearTimeout(fallbackTimer);
                    doRetry();
                });
            } else {
                purgeRetry().then(doRetry).catch(doRetry);
            }
        }

        function shouldRecoverByReloadForStaleChunk(rawMessage, errorObj) {
            if (looksLikeModuleChunkFailure(rawMessage, errorObj)) return true;

            const message = String(rawMessage || '');
            const lowerMessage = message.toLowerCase();
            const stackRaw = (errorObj && (errorObj.stack || errorObj.fileName || errorObj.filename)) || '';
            const stack = String(stackRaw || '');
            const lowerStack = stack.toLowerCase();
            const assetLike =
                lowerStack.includes('/assets/') ||
                lowerStack.includes('\\assets\\') ||
                lowerStack.includes('.js') ||
                lowerStack.includes('.mjs');

            if (lowerMessage.includes('importing a module script failed')) return true;
            if (lowerMessage.includes('failed to fetch dynamically imported module')) return true;

            // PWA/background-resume stale chunk case:
            // the browser asked for an old hashed JS chunk, but received index.html or another
            // HTML fallback page instead, which surfaces as SyntaxError: Unexpected token '<'.
            if (message.includes("Unexpected token '<'") || lowerMessage.includes('unexpected token <') || lowerMessage.includes("got '<'")) {
                return true;
            }

            return false;
        }

        function looksLikeModuleChunkFailure(rawMessage, errorObj) {
            const message = String(rawMessage || '');
            const lowerMessage = message.toLowerCase();
            const stackRaw = (errorObj && (errorObj.stack || errorObj.fileName || errorObj.filename)) || '';
            const stack = String(stackRaw || '');
            const lowerStack = stack.toLowerCase();

            if (
                lowerMessage.includes('failed to fetch dynamically imported module') ||
                lowerMessage.includes('importing a module script failed') ||
                lowerMessage.includes('error loading dynamically imported module') ||
                lowerMessage.includes('unable to preload css') ||
                lowerMessage.includes('unable to preload') ||
                lowerMessage.includes('loading chunk') ||
                lowerMessage.includes('loading css chunk')
            ) {
                return true;
            }

            const mentionsAsset =
                lowerMessage.includes('/assets/') ||
                lowerStack.includes('/assets/') ||
                lowerStack.includes('\\assets\\') ||
                /\/assets\/[^ "'<>]+\.m?js/i.test(message) ||
                /\/assets\/[^ "'<>]+\.css/i.test(message) ||
                /\/assets\/[^ "'<>]+\.m?js/i.test(stack) ||
                /\/assets\/[^ "'<>]+\.css/i.test(stack);

            if ((lowerMessage === 'load failed' || lowerMessage.endsWith(': load failed')) && mentionsAsset) {
                return true;
            }

            return false;
        }

        function recordBootRequestDiagnostic(entry) {
            try {
                var diag = window.__BOOT_DIAG__;
                if (!diag) return;
                if (!Array.isArray(diag.requests)) diag.requests = [];
                diag.requests.push(entry);
                if (diag.requests.length > 20) {
                    diag.requests = diag.requests.slice(diag.requests.length - 20);
                }
            } catch {
                // ignore
            }
        }

        function classifyBootDiagnostic(rawMessage, errorObj) {
            var message = String(rawMessage || '');
            var lowerMessage = message.toLowerCase();
            var stackRaw = (errorObj && (errorObj.stack || errorObj.fileName || errorObj.filename)) || '';
            var stack = String(stackRaw || '');
            var lowerStack = stack.toLowerCase();
            var diag = window.__BOOT_DIAG__ || {};
            var requests = Array.isArray(diag.requests) ? diag.requests : [];
            var recentHtmlAsset = requests.slice().reverse().find(function (item) {
                return item && item.kind === 'asset_html_response';
            });
            var recentHtmlApi = requests.slice().reverse().find(function (item) {
                return item && item.kind === 'api_html_response';
            });

            if (shouldRecoverByReloadForStaleChunk(message, errorObj)) {
                return {
                    kind: 'stale_chunk_html_or_module_mismatch',
                    summary: 'Likely stale JS chunk or HTML fallback returned for module asset.',
                    detail: recentHtmlAsset || null
                };
            }

            if ((message.includes("Unexpected token '<'") || lowerMessage.includes('unexpected token <')) && recentHtmlApi) {
                return {
                    kind: 'api_returned_html_instead_of_json',
                    summary: 'API likely returned HTML instead of JSON.',
                    detail: recentHtmlApi
                };
            }

            if (recentHtmlAsset && (lowerStack.includes('/assets/') || lowerStack.includes('.js') || lowerStack.includes('.mjs'))) {
                return {
                    kind: 'asset_html_response_near_failure',
                    summary: 'A JS asset request recently returned HTML near the failure window.',
                    detail: recentHtmlAsset
                };
            }

            if (recentHtmlApi && (lowerMessage.includes('json') || lowerMessage.includes('fetch'))) {
                return {
                    kind: 'api_html_response_near_failure',
                    summary: 'An API request recently returned HTML near the failure window.',
                    detail: recentHtmlApi
                };
            }

            return null;
        }

        // Global Timeout Safety Net
        window.appLoaded = false;
        window.__BOOT_DIAG__ = { start: Date.now(), chunks: {}, requests: [] };

        function isCriticalCssAssetUrl(urlLike) {
            try {
                var url = new URL(urlLike, window.location.href);
                return url.pathname.startsWith('/assets/') && /\/index-[\w-]+\.css$/i.test(url.pathname);
            } catch {
                return false;
            }
        }

        function getCriticalCssLinks() {
            return Array.from(document.querySelectorAll('link[rel="stylesheet"][href]'))
                .filter(function (link) { return isCriticalCssAssetUrl(link.href); });
        }

        function isViteDevEntryPresent() {
            return Array.from(document.querySelectorAll('script[type="module"][src]'))
                .some(function (script) {
                    try {
                        var url = new URL(script.src, window.location.href);
                        return url.pathname === '/index.tsx';
                    } catch {
                        return false;
                    }
                });
        }

        function isCriticalCssReady() {
            try {
                if (getComputedStyle(document.documentElement)
                    .getPropertyValue('--pickcure-app-css-ready').trim() === '1') {
                    return true;
                }
            } catch {
                // Fall back to stylesheet inspection below.
            }
            var links = getCriticalCssLinks();
            if (links.length === 0) return isViteDevEntryPresent();
            return links.some(function (link) {
                try {
                    if (link.dataset && link.dataset.pickcureCssLoaded === '1') return true;
                    if (!link.sheet) return false;
                    void link.sheet.cssRules;
                    return true;
                } catch {
                    return !!link.sheet;
                }
            });
        }

        function waitForCriticalCss(timeoutMs) {
            timeoutMs = typeof timeoutMs === 'number' ? timeoutMs : 3500;
            if (isCriticalCssReady()) return Promise.resolve(true);
            return new Promise(function (resolve) {
                var settled = false;
                var observer = null;
                var timer = null;

                function finish(ok) {
                    if (settled) return;
                    settled = true;
                    if (observer) observer.disconnect();
                    if (timer) clearTimeout(timer);
                    resolve(ok);
                }

                function attach(link) {
                    if (!link || link.dataset.pickcureCssWatched === '1') return;
                    link.dataset.pickcureCssWatched = '1';
                    link.addEventListener('load', function () {
                        link.dataset.pickcureCssLoaded = '1';
                        finish(true);
                    }, { once: true });
                    link.addEventListener('error', function () {
                        try {
                            var failedUrl = new URL(link.href, window.location.href);
                            recordBootRequestDiagnostic({
                                kind: 'css_load_failed',
                                url: failedUrl.pathname + failedUrl.search,
                                at: Date.now()
                            });
                        } catch {
                            // ignore
                        }
                        attemptSingleRecoveryReload('Critical CSS failed to load, attempting cache-busting recovery reload...', {
                            url: link.href,
                            force: true
                        });
                        finish(false);
                    }, { once: true });
                }

                getCriticalCssLinks().forEach(attach);
                observer = new MutationObserver(function () {
                    if (isCriticalCssReady()) {
                        finish(true);
                        return;
                    }
                    getCriticalCssLinks().forEach(attach);
                });
                observer.observe(document.documentElement, { childList: true, subtree: true });

                timer = setTimeout(function () {
                    if (isCriticalCssReady()) {
                        finish(true);
                        return;
                    }
                    recordBootRequestDiagnostic({
                        kind: 'critical_css_timeout',
                        url: getCriticalCssLinks().map(function (link) { return link.href; }).join(',') || 'missing',
                        at: Date.now()
                    });
                    attemptSingleRecoveryReload('Critical CSS did not become ready, attempting cache-busting recovery reload...', {
                        links: getCriticalCssLinks().map(function (link) { return link.href; }),
                        force: true
                    });
                    finish(false);
                }, timeoutMs);

                setTimeout(function () {
                    if (isCriticalCssReady()) finish(true);
                }, 0);
            });
        }

        window.__PICKCURE_CRITICAL_CSS__ = {
            isReady: isCriticalCssReady,
            whenReady: waitForCriticalCss,
            showFailure: function () {
                showBootOverlay(t.boot_err_title);
                setBootErrorMessage(t.boot_network_hint || t.boot_timeout_msg);
            }
        };

        if (typeof window.fetch === 'function') {
            var originalFetch = window.fetch.bind(window);
            window.fetch = function () {
                var fetchArgs = arguments;
                var rawTarget = fetchArgs[0];
                var url = '';
                try {
                    if (typeof rawTarget === 'string') url = rawTarget;
                    else if (rawTarget && typeof rawTarget.url === 'string') url = rawTarget.url;
                } catch {
                    url = '';
                }

                return originalFetch.apply(window, fetchArgs).then(function (response) {
                    try {
                        var absoluteUrl = new URL(url || response.url || '', window.location.href);
                        var contentType = String(response.headers && response.headers.get && response.headers.get('content-type') || '').toLowerCase();
                        var isHtml = contentType.includes('text/html');
                        if (isHtml) {
                            if (absoluteUrl.pathname.startsWith('/assets/') || /\.(js|mjs|css)$/i.test(absoluteUrl.pathname)) {
                                recordBootRequestDiagnostic({
                                    kind: 'asset_html_response',
                                    url: absoluteUrl.pathname + absoluteUrl.search,
                                    status: response.status,
                                    contentType: contentType,
                                    at: Date.now()
                                });
                                // Early recovery: a JS/CSS asset got HTML back → stale chunk / SPA fallback.
                                // Trigger reload NOW instead of waiting for the parser to throw.
                                attemptSingleRecoveryReload('Fetch intercepted HTML response for asset, triggering early recovery...', {
                                    url: absoluteUrl.pathname,
                                    status: response.status
                                });
                            } else if (absoluteUrl.pathname.startsWith('/api/')) {
                                recordBootRequestDiagnostic({
                                    kind: 'api_html_response',
                                    url: absoluteUrl.pathname + absoluteUrl.search,
                                    status: response.status,
                                    contentType: contentType,
                                    at: Date.now()
                                });
                            }
                        }
                    } catch {
                        // ignore
                    }
                    return response;
                });
            };
        }

        document.addEventListener('load', function (e) {
            var el = e.target;
            if (el && el.src && typeof el.src === 'string') {
                window.__BOOT_DIAG__.chunks[el.src] = { ok: true, at: Date.now() };
            }
            if (el && el.href && typeof el.href === 'string' && isCriticalCssAssetUrl(el.href)) {
                el.dataset.pickcureCssLoaded = '1';
                window.__BOOT_DIAG__.chunks[el.href] = { ok: true, at: Date.now() };
            }
        }, true);
        document.addEventListener('error', function (e) {
            var el = e.target;
            if (el && el.src && typeof el.src === 'string') {
                window.__BOOT_DIAG__.chunks[el.src] = { ok: false, at: Date.now() };
                try {
                    var failedUrl = new URL(el.src, window.location.href);
                    var isScriptAsset = failedUrl.pathname.startsWith('/assets/') || /\.(js|mjs)$/i.test(failedUrl.pathname);
                    if (isScriptAsset) {
                        recordBootRequestDiagnostic({
                            kind: 'script_load_failed',
                            url: failedUrl.pathname + failedUrl.search,
                            at: Date.now()
                        });
                        attemptSingleRecoveryReload('Script asset failed to load, attempting cache-busting recovery reload...', {
                            url: failedUrl.pathname + failedUrl.search
                        });
                    }
                } catch {
                    // ignore
                }
            }
            if (el && el.href && typeof el.href === 'string' && isCriticalCssAssetUrl(el.href)) {
                window.__BOOT_DIAG__.chunks[el.href] = { ok: false, at: Date.now() };
                try {
                    var failedCssUrl = new URL(el.href, window.location.href);
                    recordBootRequestDiagnostic({
                        kind: 'css_load_failed',
                        url: failedCssUrl.pathname + failedCssUrl.search,
                        at: Date.now()
                    });
                    attemptSingleRecoveryReload('Critical CSS asset failed to load, attempting cache-busting recovery reload...', {
                        url: failedCssUrl.pathname + failedCssUrl.search,
                        force: true
                    });
                } catch {
                    // ignore
                }
            }
        }, true);
        setTimeout(() => {
            if (!window.appLoaded || !window.appVisualReady) {
                if (window.bootTerminalShown) return;
                // If an explicit error is already shown (e.g. bootErrorLines contains errors),
                // do not override it with a generic timeout overlay.
                if (typeof bootErrorLines !== 'undefined' && bootErrorLines.size > 0) return;

                var diag = window.__BOOT_DIAG__;
                var appRendered = !!window.appLoaded;
                var appVisualReady = !!window.appVisualReady;
                var pending = Object.keys(diag.chunks).filter(function (k) { return diag.chunks[k].ok; });
                var failed = Object.keys(diag.chunks).filter(function (k) { return !diag.chunks[k].ok; });
                var scripts = Array.from(document.querySelectorAll('script[src]')).map(function (s) { return s.src; });
                var notStarted = scripts.filter(function (s) { return !diag.chunks[s]; });
                console.error("App load timeout triggered.", JSON.stringify({
                    elapsed: Date.now() - diag.start,
                    appRendered: appRendered,
                    appVisualReady: appVisualReady,
                    loaded: pending,
                    failed: failed,
                    notStarted: notStarted
                }));
                if (attemptSingleRecoveryReload('App boot timeout, preserving cache and retrying once...', {
                    force: true,
                    marker: 'reloaded-after-boot-timeout',
                    elapsed: Date.now() - diag.start,
                    appRendered: appRendered,
                    appVisualReady: appVisualReady,
                    loaded: pending,
                    failed: failed,
                    notStarted: notStarted
                })) {
                    return;
                }
                showBootOverlay(t.boot_timeout_title);
                setBootErrorMessage(t.boot_timeout_msg);
            }
        }, 30000);

        // Automatic Recovery for Module Load Failures
        // Do NOT reload or preventDefault here — lazyWithRetry handles retry + fallback
        // for lazy-loaded components. Only record diagnostics for debugging.
        window.addEventListener('vite:preloadError', (event) => {
            recordBootRequestDiagnostic({
                kind: 'vite_preload_error',
                url: (event.payload && event.payload.message) || 'unknown',
                at: Date.now()
            });
            if (event && typeof event.preventDefault === 'function') {
                event.preventDefault();
            }
        });

        window.addEventListener('error', function (e) {
            const errMessage = e && (e.message || (e.error && e.error.message));
            const errObj = (e && e.error) || { stack: '', filename: e && e.filename };

            // Silent IDB disconnect (logged with dedicated tag for diagnostics)
            if (isSilentIndexedDbDisconnectMessage(errMessage)) {
                console.warn('Silent IndexedDB disconnect during boot/runtime:', e.error || e.message);
                return;
            }

            // Generic transient/benign noise (AbortError, Load failed, ResizeObserver, etc.)
            if (isTransientSilentError(errMessage, errObj)) {
                console.warn('Silent transient error swallowed:', e.error || e.message);
                return;
            }

            if (shouldRecoverByReloadForStaleChunk(errMessage, errObj)) {
                // React 已经启动后，路由 chunk 由 lazyWithRetry 统一负责版本握手与恢复。
                // 这里不能再发起第二条 SW/reload 链，否则会与按钮加载竞态。
                if (window.appLoaded) {
                    console.warn('Runtime module error delegated to lazyWithRetry:', errObj || errMessage);
                    return;
                }
                if (attemptSingleRecoveryReload('Module/stale-chunk error detected, attempting recovery reload...', {
                    message: errMessage,
                    error: errObj,
                    force: false
                })) {
                    return;
                }
                return;
            }

            // Only show boot overlay during initial load
            if (!window.appLoaded) {
                var bootDiag = classifyBootDiagnostic(errMessage, errObj);
                console.error("Global Error:", e.error || e.message, bootDiag ? { bootDiag: bootDiag } : undefined);

                showBootOverlay(t.boot_err_title);
                appendBootErrorLine((t.boot_runtime_error_prefix || "Runtime Error: ") + (e.error ? e.error.message : e.message));
                appendBootErrorLine(formatBootDiagnosticLine(bootDiag));
                if (e.message && (e.message.includes('failed') || e.message.includes('fetch'))) {
                    appendBootErrorLine(t.boot_network_hint || "Hint: This might be caused by network instability. Please check your connection or wait a moment before retrying.");
                }
            }
        });

        window.addEventListener('unhandledrejection', function (e) {
            try {
                const reason = e && (e.reason || (e.detail && e.detail.reason));
                const message = reason && (reason.message || String(reason));

                if (isSilentIndexedDbDisconnectMessage(message)) {
                    console.warn('Silent IndexedDB disconnect promise rejection:', reason || message);
                    if (e && typeof e.preventDefault === 'function') {
                        e.preventDefault();
                    }
                    return;
                }

                if (isTransientSilentError(message, reason)) {
                    console.warn('Silent transient promise rejection swallowed:', reason || message);
                    if (e && typeof e.preventDefault === 'function') {
                        e.preventDefault();
                    }
                    return;
                }

                if (shouldRecoverByReloadForStaleChunk(message, reason)) {
                    if (e && typeof e.preventDefault === 'function') {
                        e.preventDefault();
                    }
                    if (window.appLoaded) {
                        console.warn('Runtime module rejection delegated to lazyWithRetry:', reason || message);
                        return;
                    }
                    if (attemptSingleRecoveryReload('Unhandled module/stale-chunk rejection detected, attempting recovery reload...', {
                        message: message,
                        error: reason,
                        force: false
                    })) {
                        return;
                    }
                    return;
                }

                // Only show boot overlay if app hasn't loaded yet
                if (!window.appLoaded) {
                    var bootDiag = classifyBootDiagnostic(message, reason);
                    if (bootDiag) {
                        console.error('Unhandled rejection boot diagnostic:', bootDiag);
                    }
                    showBootOverlay(t.boot_err_title);
                    appendBootErrorLine((t.boot_runtime_error_prefix || "Runtime Error: ") + (message || 'Unhandled Promise Rejection'));
                    appendBootErrorLine(formatBootDiagnosticLine(bootDiag));
                }
            } catch (err) {
                console.error('unhandledrejection handler failed', err);
            }
        });

        // Immediate DOM Update
        document.addEventListener("DOMContentLoaded", () => {
            const title = document.getElementById('error-title');
            const desc = document.getElementById('error-desc');
            const btn = document.getElementById('retry-btn');
            const networkBtn = document.getElementById('network-help-btn');
            if (title) title.textContent = t.boot_err_title;
            if (desc) desc.textContent = t.boot_err_desc;
            if (btn) btn.textContent = t.boot_retry;
            if (networkBtn) networkBtn.textContent = t.boot_net_check || (LANG === 'zh' ? networkBtn.textContent : 'Detect');
        });
    </script>

<script>!function(w,d,s,u,n,a,b){if(w[n])return;a=w[n]={q:[],t:+new Date,s:[],o:u,track:function(){a.q.push([+new Date].concat([].slice.call(arguments)))},setScope:function(){a.s=[].slice.call(arguments).filter(function(x){return typeof x==="string"});a.q.push([+new Date,"setScope"].concat(a.s))},scope:function(){var c=[].slice.call(arguments);return{track:function(){a.q.push([+new Date].concat([].slice.call(arguments)).concat([{__scope:c}]))}}}};b=d.createElement(s);b.async=1;b.src=u+"/s.js";d.getElementsByTagName(s)[0].parentNode.insertBefore(b,d.getElementsByTagName(s)[0])}(window,document,"script","https://t.whop.tw","whop");whop.setScope("biz_gXCWfy4sPejM0v");whop.track("page");</script>  <script type="module" crossorigin src="/assets/index-CrhXG9q2.js" fetchpriority="high"></script>
  <link rel="stylesheet" crossorigin href="/assets/index-RcsUmpgB.css">
<link rel="manifest" href="/manifest.webmanifest"></head>

<body class="bg-white text-[#2E2E2E]">
    <div id="loading-state">
        <!-- PMQR Icon SVG (Inline for immediate render) -->
        <svg class="pmqr-loader-svg" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
            <defs>
                <radialGradient id="iris-grad" cx="50%" cy="50%" r="50%">
                    <stop offset="0%" stop-color="#3b82f6" stop-opacity="0.9"></stop>
                    <stop offset="100%" stop-color="#1d4ed8" stop-opacity="0.4"></stop>
                </radialGradient>
                <radialGradient id="pupil-grad" cx="50%" cy="50%" r="50%">
                    <stop offset="0%" stop-color="#1e3a8a" stop-opacity="1"></stop>
                    <stop offset="100%" stop-color="#0f172a" stop-opacity="1"></stop>
                </radialGradient>
                <linearGradient id="axis-grad" x1="0%" y1="100%" x2="0%" y2="0%">
                    <stop offset="0%" stop-color="#60a5fa" stop-opacity="0.6"></stop>
                    <stop offset="100%" stop-color="#60a5fa" stop-opacity="0"></stop>
                </linearGradient>
                <radialGradient id="sclera-beam-grad" cx="50%" cy="50%" r="50%">
                    <stop offset="20%" stop-color="white" stop-opacity="0.1"></stop>
                    <stop offset="100%" stop-color="white" stop-opacity="0.01"></stop>
                </radialGradient>
            </defs>

            <!-- Outer Sclera -->
            <circle cx="50" cy="50" r="48" fill="#60a5fa" fill-opacity="0.028" stroke="#60a5fa" stroke-opacity="0.3"
                stroke-width="0.55"></circle>

            <!-- Rotating Axes & Beams -->
            <g class="pmqr-axes-container">
                <g transform="rotate(0 50 50)">
                    <path class="pmqr-sclera-beam" d="M50 50 L47 15 L50 5 L53 15 Z" fill="url(#sclera-beam-grad)"
                        style="animation-delay: 0s"></path>
                    <line x1="50" y1="50" x2="50" y2="5" stroke="url(#axis-grad)" stroke-width="0.3" opacity="0.3">
                    </line>
                    <circle class="pmqr-data-particle" cx="50" cy="5" r="0.6" style="animation-delay: 0s"></circle>
                </g>
                <g transform="rotate(45 50 50)">
                    <path class="pmqr-sclera-beam" d="M50 50 L47 15 L50 5 L53 15 Z" fill="url(#sclera-beam-grad)"
                        style="animation-delay: 0.1s"></path>
                    <line x1="50" y1="50" x2="50" y2="5" stroke="url(#axis-grad)" stroke-width="0.3" opacity="0.3">
                    </line>
                    <circle class="pmqr-data-particle" cx="50" cy="5" r="0.6" style="animation-delay: 0.1s"></circle>
                </g>
                <g transform="rotate(90 50 50)">
                    <path class="pmqr-sclera-beam" d="M50 50 L47 15 L50 5 L53 15 Z" fill="url(#sclera-beam-grad)"
                        style="animation-delay: 0.2s"></path>
                    <line x1="50" y1="50" x2="50" y2="5" stroke="url(#axis-grad)" stroke-width="0.3" opacity="0.3">
                    </line>
                </g>
                <g transform="rotate(135 50 50)">
                    <path class="pmqr-sclera-beam" d="M50 50 L47 15 L50 5 L53 15 Z" fill="url(#sclera-beam-grad)"
                        style="animation-delay: 0.3s"></path>
                    <line x1="50" y1="50" x2="50" y2="5" stroke="url(#axis-grad)" stroke-width="0.3" opacity="0.3">
                    </line>
                </g>
                <g transform="rotate(180 50 50)">
                    <path class="pmqr-sclera-beam" d="M50 50 L47 15 L50 5 L53 15 Z" fill="url(#sclera-beam-grad)"
                        style="animation-delay: 0.4s"></path>
                    <line x1="50" y1="50" x2="50" y2="5" stroke="url(#axis-grad)" stroke-width="0.3" opacity="0.3">
                    </line>
                </g>
                <g transform="rotate(225 50 50)">
                    <path class="pmqr-sclera-beam" d="M50 50 L47 15 L50 5 L53 15 Z" fill="url(#sclera-beam-grad)"
                        style="animation-delay: 0.5s"></path>
                    <line x1="50" y1="50" x2="50" y2="5" stroke="url(#axis-grad)" stroke-width="0.3" opacity="0.3">
                    </line>
                </g>
                <g transform="rotate(270 50 50)">
                    <path class="pmqr-sclera-beam" d="M50 50 L47 15 L50 5 L53 15 Z" fill="url(#sclera-beam-grad)"
                        style="animation-delay: 0.6s"></path>
                    <line x1="50" y1="50" x2="50" y2="5" stroke="url(#axis-grad)" stroke-width="0.3" opacity="0.3">
                    </line>
                </g>
                <g transform="rotate(315 50 50)">
                    <path class="pmqr-sclera-beam" d="M50 50 L47 15 L50 5 L53 15 Z" fill="url(#sclera-beam-grad)"
                        style="animation-delay: 0.7s"></path>
                    <line x1="50" y1="50" x2="50" y2="5" stroke="url(#axis-grad)" stroke-width="0.3" opacity="0.3">
                    </line>
                </g>
            </g>

            <!-- Iris -->
            <g class="pmqr-iris-group">
                <path d="M50 15 L74 25 L85 50 L74 75 L50 85 L26 75 L15 50 L26 25 Z" fill="url(#iris-grad)"
                    stroke="#60a5fa" stroke-width="1.35" stroke-linejoin="round" opacity="0.97"></path>

                <!-- Pupil -->
                <g class="pmqr-pupil-group">
                    <path d="M50 34 L62 39.5 L66 50 L62 60.5 L50 66 L38 60.5 L34 50 L38 39.5 Z" fill="url(#pupil-grad)">
                    </path>
                    <circle cx="46" cy="44" r="2.2" fill="white" fill-opacity="0.3"></circle>
                    <circle cx="44" cy="42" r="0.8" fill="white" fill-opacity="0.5"></circle>
                </g>
            </g>

            <!-- Nodes -->
            <circle cx="50" cy="15" r="1.45" fill="#fbbf24"></circle>
            <circle cx="85" cy="50" r="1.45" fill="#fbbf24" style="animation-delay: 1s"></circle>
            <circle cx="50" cy="85" r="1.45" fill="#fbbf24" style="animation-delay: 2s"></circle>
            <circle cx="15" cy="50" r="1.45" fill="#fbbf24" style="animation-delay: 3s"></circle>
        </svg>

        <h2 class="loading-title" aria-label="PickCure"><span>Pick</span><span class="loading-title-cure">Cure</span></h2>
        <p id="slogan-text"
            style="font-size: 0.9rem; color: #64748b; margin-top: 0.5rem; height: 1.5em; transition: opacity 0.5s; opacity: 0;">
        </p>
        <script>
            // 1. Title "PICKCURE" is static (Universal)
            // 2. Slogan is localized and appears after 600ms
            if (typeof t !== 'undefined' && t.boot_loading) {
                setTimeout(() => {
                    const el = document.getElementById('slogan-text');
                    if (el) {
                        el.textContent = t.boot_loading;
                        el.style.opacity = '1';
                    }
                }, 500);
            }
        </script>
    </div>

    <div id="root"></div>

    <div id="error-overlay">
        <div
            style="max-width: 600px; margin: 10% auto; background: #fff1f2; border: 1px solid #fecaca; padding: 20px; border-radius: 6px;">
            <h2 id="error-title" class="text-xl font-bold mb-2 text-red-700">Startup Failed</h2>
            <p id="error-desc" class="text-sm text-gray-600 mb-2">Please check the console for details or try reloading.
            </p>
            <pre id="error-message" style="display: none;"
                class="font-mono text-xs whitespace-pre-wrap bg-white p-4 rounded border border-red-100"></pre>
            <div id="error-details-toggle"
                onclick="document.getElementById('error-message').style.display='block'; this.style.display='none';"
                style="font-size: 11px; color: #b91c1c; cursor: pointer; text-decoration: underline; margin-top: 8px;">
                Show technical details</div>
            <div style="display:flex; flex-wrap:wrap; gap:12px; margin-top:16px;">
                <button id="retry-btn" onclick="retryBootLoad()"
                    class="px-4 py-2 bg-red-600 text-white rounded text-sm font-bold">Retry</button>
                <button id="network-help-btn" onclick="openUnavailablePage()"
                    class="px-4 py-2 bg-white text-red-700 rounded text-sm font-bold border border-red-200">Network</button>
            </div>
        </div>
    </div>

<!-- Cloudflare Pages Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "bfa9c2f66e4f4420ba15ab3ccc600e8c"}'></script><!-- Cloudflare Pages Analytics --></body>

</html><!-- force rebuild 20260219001 -->
