<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="return-url" content="/blog/feed/">
    <title data-i18n="title">Security Check</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: #ffffff;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            color: #222c65;
        }

        .header {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            background: #222c65;
            padding: 15px 30px;
            display: flex;
            align-items: center;
        }

        .header .logo {
            height: 32px;
            width: auto;
        }

        .container {
            background: #ffffff;
            border-radius: 8px;
            padding: 40px;
            max-width: 500px;
            width: 90%;
            text-align: center;
            border: 1px solid #e0e0e0;
            box-shadow: 0 2px 12px rgba(34, 44, 101, 0.08);
        }

        .shield-icon {
            width: 64px;
            height: 64px;
            margin-bottom: 20px;
            color: #222c65;
        }

        h1 {
            font-size: 1.5rem;
            margin-bottom: 10px;
            font-weight: 600;
            color: #222c65;
        }

        p {
            color: #666666;
            margin-bottom: 30px;
            font-size: 0.95rem;
            line-height: 1.5;
        }

        .progress-container {
            background: #f0f0f0;
            border-radius: 8px;
            height: 8px;
            overflow: hidden;
            margin-bottom: 15px;
        }

        .progress-bar {
            height: 100%;
            background: #222c65;
            width: 0%;
            transition: width 0.3s ease;
        }

        .status {
            font-size: 0.9rem;
            color: #666666;
            min-height: 24px;
        }

        .status.success {
            color: #222c65;
            font-weight: 500;
        }

        .status.error {
            color: #cc3333;
        }

        .stats {
            display: flex;
            justify-content: space-around;
            margin-top: 25px;
            padding-top: 20px;
            border-top: 1px solid #e0e0e0;
        }

        .stat {
            font-size: 0.8rem;
            color: #888888;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .stat-value {
            font-size: 1.3rem;
            color: #222c65;
            display: block;
            margin-top: 8px;
            font-weight: 500;
            font-variant-numeric: tabular-nums;
        }

        noscript {
            display: block;
            margin-top: 20px;
            padding: 15px;
            background: rgba(204, 51, 51, 0.1);
            border-radius: 8px;
            color: #cc3333;
        }

        .error-container {
            display: none;
            margin-top: 20px;
            padding: 15px;
            background: rgba(204, 51, 51, 0.1);
            border-radius: 8px;
        }

        .error-message {
            color: #cc3333;
            font-size: 0.9rem;
            margin-bottom: 15px;
        }

        .retry-button {
            background: #222c65;
            border: none;
            padding: 12px 24px;
            border-radius: 8px;
            color: #fff;
            font-size: 0.9rem;
            cursor: pointer;
            transition: background 0.2s ease;
        }

        .retry-button:hover {
            background: #1a2250;
        }

        .footer {
            position: absolute;
            bottom: 20px;
            font-size: 0.75rem;
            color: #999999;
        }
    </style>
</head>
<body>
    <div class="header">
        <svg class="logo" data-name="Ebene 1" version="1.1" viewBox="0 0 277.56 45.35" xmlns="http://www.w3.org/2000/svg">
            <path fill="#ffffff" transform="translate(-3.06 -2.83)" d="M274.39,23.24A2.32,2.32,0,0,1,277,20.83a3.76,3.76,0,0,1,3.15,1.61V20a23.88,23.88,0,0,0-3.22-.56c-2.76,0-4.34,1.68-4.34,3.89,0,4.62,6.27,4.51,6.27,8.22a2.59,2.59,0,0,1-2.8,2.63A4.43,4.43,0,0,1,272.15,32v2.73a13.32,13.32,0,0,0,4,.91c2.69,0,4.48-1.72,4.48-4.13,0-4.94-6.23-4.73-6.23-8.23m-6.34-10.11c0-1.16,0-2.8.11-3.64H265.6a5.12,5.12,0,0,1-.87,1.15h1.57v20.9c0,1.19,0,2.83-.1,3.64h2c-.07-.81-.11-2.35-.11-3.64ZM252,31.05c0-1.72,1.33-3.15,3.78-3.15,2.07,0,3.75,1.43,3.75,3.15a3.49,3.49,0,0,1-3.75,3.18c-2.45,0-3.78-1.4-3.78-3.18M255.1,20.9c3.26,0,4.27,2.31,4.27,5.11v2.38a4.57,4.57,0,0,0-3.92-1.79c-3.39,0-5.28,2-5.28,4.52s1.89,4.44,5.21,4.44a4.87,4.87,0,0,0,4.06-1.89c.07,1.37.84,1.89,1.68,1.89a2.6,2.6,0,0,0,1.54-.42V34a1.55,1.55,0,0,1-.73.18c-.49,0-.88-.25-.88-1.3V26.25c0-4.72-1.92-6.79-5.67-6.79a12.44,12.44,0,0,0-4.13,1v2a5,5,0,0,1,3.85-1.57m-10,5.07V31.5c0,1,0,2.63-.14,3.68h2c-.1-1-.14-2.66-.14-3.68V26c0-4.24-2.1-6.58-5.28-6.58a5.2,5.2,0,0,0-4.76,2.87V19.71h-2.42a7.1,7.1,0,0,1-.91,1.19H235V31.5c0,1,0,2.63-.11,3.68h2c-.07-1-.1-2.66-.1-3.68V25.76c0-2.94,1.82-4.86,4.2-4.86,2.1,0,4.13,1.5,4.13,5.07m-27.83,1.47a6.17,6.17,0,1,1,6.13,6.44,6.27,6.27,0,0,1-6.13-6.44m-1.71,0a7.88,7.88,0,1,0,7.84-8,7.92,7.92,0,0,0-7.84,8M209.88,15a1.14,1.14,0,0,0,2.28,0,1.14,1.14,0,1,0-2.28,0M212,23.35c0-1.3,0-2.84.1-3.64h-2.52a5.08,5.08,0,0,1-.91,1.19h1.58V31.5c0,1.26,0,2.91-.11,3.68h2c-.07-.7-.1-2.35-.1-3.68Zm-12.39-.11a2.32,2.32,0,0,1,2.62-2.41,3.76,3.76,0,0,1,3.15,1.61V20a23.88,23.88,0,0,0-3.22-.56c-2.76,0-4.34,1.68-4.34,3.89,0,4.62,6.27,4.51,6.27,8.22a2.59,2.59,0,0,1-2.8,2.63A4.43,4.43,0,0,1,197.32,32v2.73a13.32,13.32,0,0,0,4,.91c2.69,0,4.48-1.72,4.48-4.13,0-4.94-6.23-4.73-6.23-8.23m-11.87,0a2.32,2.32,0,0,1,2.63-2.41,3.77,3.77,0,0,1,3.15,1.61V20a24.17,24.17,0,0,0-3.22-.56c-2.77,0-4.34,1.68-4.34,3.89,0,4.62,6.26,4.51,6.26,8.22a2.59,2.59,0,0,1-2.8,2.63A4.46,4.46,0,0,1,185.45,32v2.73a13.39,13.39,0,0,0,4,.91c2.7,0,4.48-1.72,4.48-4.13,0-4.94-6.23-4.73-6.23-8.23M176,20.86A5.28,5.28,0,0,1,181,25.48H170.72c.63-2.55,2.62-4.62,5.25-4.62m7,5.95c0-.07,0-.21,0-.35,0-2.31-2.1-7-7-7-4,0-7.21,3.29-7.21,8a7.64,7.64,0,0,0,7.66,8c3.12,0,4.06-.81,5.25-1v-2a7.67,7.67,0,0,1-5,1.44c-3.81,0-6.37-3.5-6-7.18ZM159.8,21.18h2.55V31.54c0,1.15-.07,2.8-.1,3.64h2c-.07-.84-.11-2.49-.11-3.64V21.18h3.33V19.71H164.1v-4.1c0-3.08,1.23-4.86,3.4-4.86a3.06,3.06,0,0,1,2.34.8v-2a20.8,20.8,0,0,0-2.62-.31c-3,0-4.87,2.34-4.87,6.4v4H159.8ZM144,27.44a6.17,6.17,0,1,1,6.12,6.44A6.27,6.27,0,0,1,144,27.44m-1.72,0a7.88,7.88,0,1,0,7.84-8,7.93,7.93,0,0,0-7.84,8m-2.1-8c-1.75,0-3.53,1.47-4.13,3.82V19.71h-2.31a5.39,5.39,0,0,1-.84,1.19h1.51V31.54c0,1.19,0,2.41-.11,3.64h2c-.11-1.23-.14-2.45-.14-3.64V26.29c0-2.77,1.92-5.22,3.85-5.22a3.94,3.94,0,0,1,2.2.6v-2c-.52,0-1-.18-2-.18m-23.41,8a6.25,6.25,0,0,1,6-6.47,6.34,6.34,0,0,1,6.16,6.51,6.07,6.07,0,1,1-12.11,0M115.1,40.5c0,1,0,2.59-.14,3.64h2c-.1-1-.14-2.66-.14-3.64V31.64A6.48,6.48,0,0,0,123,35.42a7.77,7.77,0,0,0,7.66-8,7.82,7.82,0,0,0-7.66-8,6.83,6.83,0,0,0-6.13,4V19.71h-2.41a7.68,7.68,0,0,1-.91,1.19h1.57Z"/>
            <rect fill="#ffffff" x="100.84" width="1.4" height="45.35"/>
            <path fill="#ffffff" transform="translate(-3.06 -2.83)" d="M87.66,21.74a3.59,3.59,0,0,1,3.47,3.19H84a3.9,3.9,0,0,1,3.67-3.19m7.49,5.88a5.46,5.46,0,0,0,.07-.94c0-3.5-2.69-7.81-7.52-7.81-4.34,0-7.7,3.57-7.7,8.37a8.11,8.11,0,0,0,8.36,8.22c2.84,0,4.06-.73,5.22-.84V31.19A7.51,7.51,0,0,1,89,32.35a4.93,4.93,0,0,1-5-4.73ZM65.79,39.35C65.79,38,67.64,37,69.88,37c2.49,0,4.45,1.08,4.45,2.45s-1.86,2.41-4.27,2.41-4.27-1.08-4.27-2.48M67,25.21a3.15,3.15,0,1,1,6.3,0,3.15,3.15,0,1,1-6.3,0m7.91-6.06a1.66,1.66,0,0,1-.45,1.12,7.13,7.13,0,0,0-4.31-1.43c-4,0-7.1,2.87-7.1,6.37a6,6,0,0,0,2.13,4.58,3.3,3.3,0,0,0-2.52,3.12,3,3,0,0,0,1.72,2.76,4.24,4.24,0,0,0-2.56,3.68c0,3,3.68,5.14,8.23,5.14s8.36-2.31,8.36-5.25c0-3.43-3.85-5.49-8.33-5.49-1,0-1.85.24-2.31.24a1.47,1.47,0,0,1-1.47-1.43c0-.88.53-1.44,1.12-1.44a27.4,27.4,0,0,0,2.73.49c4,0,7.14-2.9,7.14-6.4a5.55,5.55,0,0,0-.87-3,3.49,3.49,0,0,0,1.71-3.05ZM49.13,30.67a2.32,2.32,0,0,1,2.62-2.21,2.48,2.48,0,0,1,2.63,2.21,2.47,2.47,0,0,1-2.63,2.27,2.32,2.32,0,0,1-2.62-2.27M50.53,22a3.46,3.46,0,0,1,3.78,3.78V27.2a4.7,4.7,0,0,0-3.47-1.33c-3.6,0-5.6,2.28-5.6,5s2.07,4.72,5.36,4.72a4.89,4.89,0,0,0,3.92-1.82,2.39,2.39,0,0,0,2.55,1.82,4,4,0,0,0,2.66-.84V32.38a1.44,1.44,0,0,1-.8.18c-.53,0-1-.28-1-1.47v-5c0-4.73-2-7.21-6.47-7.21-2.63,0-4,.94-5,1.12v3.6A5.5,5.5,0,0,1,50.53,22M28.16,35.18h4.17c-.07-1-.11-2.27-.11-3.6V25.8c0-2.41,1.3-3.78,2.84-3.78,1.78,0,2.76,1.19,2.76,4v5.6c0,.91,0,2.55-.1,3.6h4.16c-.1-1-.14-2.31-.14-3.6V25.45c0-4.3-2.13-6.58-5.49-6.58a4.82,4.82,0,0,0-4.69,2.84,4.25,4.25,0,0,0-4.41-2.84,4.9,4.9,0,0,0-4.48,2.52V19.15H18.12A12.56,12.56,0,0,1,17,21.46h1.68V31.58c0,1.15,0,2.8-.07,3.6h4.13c-.07-.8-.1-2.45-.1-3.6V25.8c0-2.45,1.26-3.78,2.83-3.78,1.93,0,2.77,1.4,2.77,3.68v5.88c0,1.33,0,2.55-.11,3.6M13,22.72c0-1.26,0-2.76.11-3.57H8.46a9.92,9.92,0,0,1-1.12,2.31H9V31.58c0,1.22,0,2.87-.11,3.6h4.17c-.07-.66-.11-2.31-.11-3.6Z"/>
            <path fill="#ffffff" transform="translate(-3.06 -2.83)" d="M10.26,9.36c-3.4.93-7.84,6.2-7.12,8.25.22.65,2.38-5,7.31-5S15.68,17,18,13c2.43-4.28-4.41-4.51-7.72-3.6"/>
        </svg>
    </div>

    <div class="container">
        <svg class="shield-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
            <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
            <path d="M9 12l2 2 4-4"/>
        </svg>

        <h1 data-i18n="heading">Security Check</h1>
        <p data-i18n="description">Please wait while we verify your connection. This only takes a few seconds.</p>

        <div class="progress-container">
            <div class="progress-bar" id="progress"></div>
        </div>

        <div class="status" id="status" data-i18n="initializing">Initializing...</div>

        <div class="stats">
            <div class="stat">
                <span data-i18n="attempts">Attempts</span>
                <span class="stat-value" id="attempts">0</span>
            </div>
            <div class="stat">
                <span data-i18n="hashRate">Hash Rate</span>
                <span class="stat-value" id="hashrate">0 H/s</span>
            </div>
            <div class="stat">
                <span data-i18n="time">Time</span>
                <span class="stat-value" id="time">0.0s</span>
            </div>
        </div>

        <div class="error-container" id="errorContainer">
            <div class="error-message" id="errorMessage"></div>
            <button class="retry-button" id="retryButton" data-i18n="retry">Retry</button>
        </div>

        <noscript>
            <strong data-i18n="jsRequired">JavaScript Required</strong><br>
            <span data-i18n="enableJs">Please enable JavaScript in your browser to continue.</span>
        </noscript>
    </div>

    <script>
        // Internationalization (i18n)
        const translations = {
            en: {
                title: 'Security Check',
                heading: 'Security Check',
                description: 'Please wait while we verify your connection. This only takes a few seconds.',
                initializing: 'Initializing...',
                attempts: 'Attempts',
                hashRate: 'Hash Rate',
                time: 'Time',
                retry: 'Retry',
                jsRequired: 'JavaScript Required',
                enableJs: 'Please enable JavaScript in your browser to continue.',
                loadingChallenge: 'Loading challenge...',
                computing: 'Computing...',
                verifying: 'Verifying...',
                success: 'Verification successful. You will now be redirected automatically.',
                successLinkText: 'If the redirection does not work, please click here:',
                validationFailed: 'Validation failed',
                challengeLoadError: 'Could not load challenge',
                submitError: 'Could not submit solution',
                errorOccurred: 'An error occurred'
            },
            de: {
                title: 'Sicherheitsprüfung',
                heading: 'Sicherheitsprüfung',
                description: 'Bitte warten Sie, während wir Ihre Verbindung verifizieren. Dies dauert nur wenige Sekunden.',
                initializing: 'Initialisiere...',
                attempts: 'Versuche',
                hashRate: 'Hash-Rate',
                time: 'Zeit',
                retry: 'Erneut versuchen',
                jsRequired: 'JavaScript erforderlich',
                enableJs: 'Bitte aktivieren Sie JavaScript in Ihrem Browser, um fortzufahren.',
                loadingChallenge: 'Challenge wird geladen...',
                computing: 'Berechnung läuft...',
                verifying: 'Verifizierung...',
                success: 'Die Prüfung war erfolgreich. Sie werden jetzt automatisch weitergeleitet.',
                successLinkText: 'Falls die Weiterleitung nicht funktioniert, klicken Sie bitte hier:',
                validationFailed: 'Validierung fehlgeschlagen',
                challengeLoadError: 'Challenge konnte nicht geladen werden',
                submitError: 'Lösung konnte nicht übermittelt werden',
                errorOccurred: 'Fehler aufgetreten'
            },
            fr: {
                title: 'Vérification de sécurité',
                heading: 'Vérification de sécurité',
                description: 'Veuillez patienter pendant que nous vérifions votre connexion. Cela ne prend que quelques secondes.',
                initializing: 'Initialisation...',
                attempts: 'Tentatives',
                hashRate: 'Taux de hachage',
                time: 'Temps',
                retry: 'Réessayer',
                jsRequired: 'JavaScript requis',
                enableJs: 'Veuillez activer JavaScript dans votre navigateur pour continuer.',
                loadingChallenge: 'Chargement du défi...',
                computing: 'Calcul en cours...',
                verifying: 'Vérification...',
                success: 'Vérification réussie. Vous allez maintenant être redirigé automatiquement.',
                successLinkText: 'Si la redirection ne fonctionne pas, veuillez cliquer ici:',
                validationFailed: 'Échec de la validation',
                challengeLoadError: 'Impossible de charger le défi',
                submitError: 'Impossible de soumettre la solution',
                errorOccurred: 'Une erreur est survenue'
            },
            pl: {
                title: 'Weryfikacja bezpieczeństwa',
                heading: 'Weryfikacja bezpieczeństwa',
                description: 'Proszę czekać, trwa weryfikacja połączenia. To zajmie tylko kilka sekund.',
                initializing: 'Inicjalizacja...',
                attempts: 'Próby',
                hashRate: 'Szybkość hashowania',
                time: 'Czas',
                retry: 'Spróbuj ponownie',
                jsRequired: 'Wymagany JavaScript',
                enableJs: 'Proszę włączyć JavaScript w przeglądarce, aby kontynuować.',
                loadingChallenge: 'Ładowanie wyzwania...',
                computing: 'Obliczanie...',
                verifying: 'Weryfikacja...',
                success: 'Weryfikacja zakończona pomyślnie. Zostaniesz automatycznie przekierowany.',
                successLinkText: 'Jeśli przekierowanie nie działa, kliknij tutaj:',
                validationFailed: 'Weryfikacja nie powiodła się',
                challengeLoadError: 'Nie udało się załadować wyzwania',
                submitError: 'Nie udało się przesłać rozwiązania',
                errorOccurred: 'Wystąpił błąd'
            },
            it: {
                title: 'Controllo di sicurezza',
                heading: 'Controllo di sicurezza',
                description: 'Attendere mentre verifichiamo la connessione. Ci vorranno solo pochi secondi.',
                initializing: 'Inizializzazione...',
                attempts: 'Tentativi',
                hashRate: 'Velocità hash',
                time: 'Tempo',
                retry: 'Riprova',
                jsRequired: 'JavaScript richiesto',
                enableJs: 'Attivare JavaScript nel browser per continuare.',
                loadingChallenge: 'Caricamento sfida...',
                computing: 'Calcolo in corso...',
                verifying: 'Verifica...',
                success: 'Verifica completata con successo. Verrai reindirizzato automaticamente.',
                successLinkText: 'Se il reindirizzamento non funziona, clicca qui:',
                validationFailed: 'Validazione fallita',
                challengeLoadError: 'Impossibile caricare la sfida',
                submitError: 'Impossibile inviare la soluzione',
                errorOccurred: 'Si è verificato un errore'
            },
            es: {
                title: 'Verificación de seguridad',
                heading: 'Verificación de seguridad',
                description: 'Por favor espere mientras verificamos su conexión. Esto solo tomará unos segundos.',
                initializing: 'Inicializando...',
                attempts: 'Intentos',
                hashRate: 'Tasa de hash',
                time: 'Tiempo',
                retry: 'Reintentar',
                jsRequired: 'JavaScript requerido',
                enableJs: 'Por favor active JavaScript en su navegador para continuar.',
                loadingChallenge: 'Cargando desafío...',
                computing: 'Calculando...',
                verifying: 'Verificando...',
                success: 'Verificación exitosa. Será redirigido automáticamente.',
                successLinkText: 'Si la redirección no funciona, haga clic aquí:',
                validationFailed: 'Validación fallida',
                challengeLoadError: 'No se pudo cargar el desafío',
                submitError: 'No se pudo enviar la solución',
                errorOccurred: 'Se produjo un error'
            }
        };

        // Detect browser language and get supported language code
        function detectLanguage() {
            const supportedLanguages = ['en', 'de', 'fr', 'pl', 'it', 'es'];
            const browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage];
            
            for (const lang of browserLanguages) {
                // Extract primary language code (e.g., 'de' from 'de-DE')
                const primaryLang = lang.split('-')[0].toLowerCase();
                if (supportedLanguages.includes(primaryLang)) {
                    return primaryLang;
                }
            }
            
            return 'en'; // Fallback to English
        }

        // Get translation for a key
        const currentLanguage = detectLanguage();
        function t(key) {
            return translations[currentLanguage][key] || translations['en'][key] || key;
        }

        // Apply translations to all elements with data-i18n attribute
        function applyTranslations() {
            document.documentElement.lang = currentLanguage;
            document.querySelectorAll('[data-i18n]').forEach(el => {
                const key = el.getAttribute('data-i18n');
                el.textContent = t(key);
            });
        }

        // Apply translations immediately for static content
        applyTranslations();

        class PowSolver {
            constructor() {
                this.statusEl = document.getElementById('status');
                this.progressEl = document.getElementById('progress');
                this.attemptsEl = document.getElementById('attempts');
                this.hashrateEl = document.getElementById('hashrate');
                this.timeEl = document.getElementById('time');
                this.errorContainer = document.getElementById('errorContainer');
                this.errorMessage = document.getElementById('errorMessage');
                this.retryButton = document.getElementById('retryButton');

                this.attempts = 0;
                this.startTime = null;
                this.challenge = null;
                this.worker = null;
                this.statsInterval = null;

                this.retryButton.addEventListener('click', () => this.start());
            }

            async start() {
                this.reset();
                this.returnUrl = this.getReturnUrl();

                try {
                    this.updateStatus(t('loadingChallenge'));
                    this.challenge = await this.fetchChallenge();

                    this.updateStatus(t('computing'));
                    this.startTime = Date.now();
                    this.startStatsUpdate();

                    const solution = await this.solve();

                    this.stopStatsUpdate();
                    this.updateStats(); // Final stats update
                    this.updateStatus(t('verifying'), 90);

                    const result = await this.submitSolution(solution);

                    if (result.success) {
                        // Use return URL from server (stored during fetchChallenge)
                        // This is secure because the URL comes from HAProxy via X-Return-URL header
                        const returnUrl = this.returnUrl || '/';
                        
                        // Build absolute URL if relative
                        const absoluteUrl = returnUrl.startsWith('http') 
                            ? returnUrl 
                            : window.location.origin + (returnUrl.startsWith('/') ? returnUrl : '/' + returnUrl);
                        
                        // Update status with success message
                        this.updateStatus(t('success'), 100, 'success');
                        
                        // Add clickable link below status with proper HTML escaping
                        const linkDiv = document.createElement('div');
                        linkDiv.style.marginTop = '20px';
                        linkDiv.style.padding = '15px';
                        linkDiv.style.backgroundColor = '#d4edda';
                        linkDiv.style.border = '2px solid #28a745';
                        linkDiv.style.borderRadius = '8px';
                        linkDiv.style.fontSize = '1rem';
                        linkDiv.style.textAlign = 'center';
                        
                        const linkText = document.createTextNode(t('successLinkText') + ' ');
                        linkDiv.appendChild(linkText);
                        
                        const link = document.createElement('a');
                        link.href = absoluteUrl;
                        link.style.color = '#222c65';
                        link.style.fontWeight = '700';
                        link.style.textDecoration = 'underline';
                        link.style.fontSize = '1.1rem';
                        link.textContent = absoluteUrl;
                        linkDiv.appendChild(link);
                        
                        this.statusEl.insertAdjacentElement('afterend', linkDiv);
                        
                        setTimeout(() => {
                            window.location.href = returnUrl;
                        }, 1000);
                    } else {
                        throw new Error(result.error || t('validationFailed'));
                    }
                } catch (error) {
                    this.stopStatsUpdate();
                    this.showError(error.message);
                    console.error('PoW Error:', error);
                }
            }

            reset() {
                this.attempts = 0;
                this.startTime = null;
                this.challenge = null;
                this.returnUrl = null;
                this.errorContainer.style.display = 'none';
                this.progressEl.style.width = '0%';
                this.attemptsEl.textContent = '0';
                this.hashrateEl.textContent = '0 H/s';
                this.timeEl.textContent = '0.0s';

                if (this.worker) {
                    this.worker.terminate();
                    this.worker = null;
                }
            }

            async fetchChallenge() {
                const response = await fetch('/challenge/generate', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' }
                });

                if (!response.ok) {
                    throw new Error(`${t('challengeLoadError')} (${response.status})`);
                }

                return response.json();
            }

            /**
             * Reads the return URL from the <meta name="return-url"> tag.
             * The URL has already been validated and sanitized server-side by the ChallengeController
             * to prevent Open Redirect attacks.
             */
            getReturnUrl() {
                const meta = document.querySelector('meta[name="return-url"]');
                return (meta && meta.content) || '/';
            }

            async solve() {
                const { challengeId, prefix, difficulty } = this.challenge;

                // Use Web Worker for better performance
                if (window.Worker && window.crypto && window.crypto.subtle) {
                    return this.solveWithWorker(prefix, difficulty, challengeId);
                }

                // Fallback to main thread
                return this.solveInMainThread(prefix, difficulty, challengeId);
            }

            async solveInMainThread(prefix, difficulty, challengeId) {
                let nonce = 0;
                const batchSize = 1000;

                while (true) {
                    for (let i = 0; i < batchSize; i++) {
                        const testNonce = (nonce + i).toString(16).padStart(16, '0');
                        const input = prefix + testNonce;
                        const hash = await this.sha256(input);

                        this.attempts++;

                        if (this.meetsTarget(hash, difficulty)) {
                            return { challengeId, nonce: testNonce, hash };
                        }
                    }

                    nonce += batchSize;

                    // Allow UI updates
                    await new Promise(resolve => setTimeout(resolve, 0));
                }
            }

            async solveWithWorker(prefix, difficulty, challengeId) {
                return new Promise((resolve, reject) => {
                    const workerCode = `
                        async function sha256(message) {
                            const msgBuffer = new TextEncoder().encode(message);
                            const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
                            const hashArray = Array.from(new Uint8Array(hashBuffer));
                            return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
                        }

                        function meetsTarget(hash, difficultyBits) {
                            // Calculate required zero nibbles (4 bits per hex character)
                            const requiredZeroNibbles = Math.floor(difficultyBits / 4);
                            const remainingBits = difficultyBits % 4;

                            // Check full zero nibbles
                            for (let i = 0; i < requiredZeroNibbles && i < hash.length; i++) {
                                if (hash[i] !== '0') return false;
                            }

                            // Check remaining bits if any
                            if (remainingBits > 0 && requiredZeroNibbles < hash.length) {
                                const nibble = parseInt(hash[requiredZeroNibbles], 16);
                                const maxValue = 1 << (4 - remainingBits);
                                if (nibble >= maxValue) return false;
                            }

                            return true;
                        }

                        self.onmessage = async function(e) {
                            const { prefix, difficulty, challengeId, startNonce } = e.data;
                            let nonce = startNonce;
                            const batchSize = 1000;
                            const reportInterval = 1000;

                            while (true) {
                                for (let i = 0; i < batchSize; i++) {
                                    const currentAttempt = nonce + i;
                                    const testNonce = currentAttempt.toString(16).padStart(16, '0');
                                    const input = prefix + testNonce;
                                    const hash = await sha256(input);

                                    // Send progress update every reportInterval attempts
                                    if ((currentAttempt + 1) % reportInterval === 0) {
                                        self.postMessage({ type: 'progress', attempts: currentAttempt + 1 });
                                    }

                                    if (meetsTarget(hash, difficulty)) {
                                        self.postMessage({
                                            type: 'solved',
                                            challengeId,
                                            nonce: testNonce,
                                            hash,
                                            attempts: currentAttempt + 1
                                        });
                                        return;
                                    }
                                }

                                nonce += batchSize;
                            }
                        };
                    `;

                    const blob = new Blob([workerCode], { type: 'application/javascript' });
                    this.worker = new Worker(URL.createObjectURL(blob));

                    this.worker.onmessage = (e) => {
                        if (e.data.type === 'solved') {
                            this.worker.terminate();
                            this.worker = null;
                            this.attempts = e.data.attempts;
                            resolve(e.data);
                        } else if (e.data.type === 'progress') {
                            this.attempts = e.data.attempts;
                        }
                    };

                    this.worker.onerror = (error) => {
                        this.worker.terminate();
                        this.worker = null;
                        reject(new Error('Worker error: ' + error.message));
                    };

                    this.worker.postMessage({
                        prefix,
                        difficulty,
                        challengeId,
                        startNonce: 0
                    });
                });
            }

            async sha256(message) {
                const msgBuffer = new TextEncoder().encode(message);
                const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
                const hashArray = Array.from(new Uint8Array(hashBuffer));
                return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
            }

            meetsTarget(hash, difficultyBits) {
                // Calculate required zero nibbles (4 bits per hex character)
                const requiredZeroNibbles = Math.floor(difficultyBits / 4);
                const remainingBits = difficultyBits % 4;

                // Check full zero nibbles
                for (let i = 0; i < requiredZeroNibbles && i < hash.length; i++) {
                    if (hash[i] !== '0') return false;
                }

                // Check remaining bits if any
                if (remainingBits > 0 && requiredZeroNibbles < hash.length) {
                    const nibble = parseInt(hash[requiredZeroNibbles], 16);
                    const maxValue = 1 << (4 - remainingBits);
                    if (nibble >= maxValue) return false;
                }

                return true;
            }

            async submitSolution(solution) {
                const response = await fetch('/challenge/solve', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        challengeId: solution.challengeId,
                        nonce: solution.nonce,
                        hash: solution.hash
                    })
                });

                if (!response.ok) {
                    throw new Error(`${t('submitError')} (${response.status})`);
                }

                return response.json();
            }

            updateStatus(text, progress = null, className = '') {
                this.statusEl.textContent = text;
                this.statusEl.className = 'status ' + className;

                if (progress !== null) {
                    this.progressEl.style.width = progress + '%';
                }
            }

            startStatsUpdate() {
                this.statsInterval = setInterval(() => this.updateStats(), 100);
            }

            stopStatsUpdate() {
                if (this.statsInterval) {
                    clearInterval(this.statsInterval);
                    this.statsInterval = null;
                }
            }

            updateStats() {
                if (!this.startTime) return;

                const elapsed = (Date.now() - this.startTime) / 1000;
                const hashrate = elapsed > 0 ? Math.round(this.attempts / elapsed) : 0;

                // Estimate progress based on expected difficulty
                const expectedAttempts = Math.pow(2, this.challenge.difficulty);
                const progress = Math.min(85, (this.attempts / expectedAttempts) * 100);

                this.progressEl.style.width = progress + '%';
                this.attemptsEl.textContent = this.formatNumber(this.attempts);
                this.hashrateEl.textContent = this.formatNumber(hashrate) + ' H/s';
                this.timeEl.textContent = elapsed.toFixed(1) + 's';
            }

            formatNumber(num) {
                if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
                if (num >= 1000) return (num / 1000).toFixed(1) + 'K';
                return num.toString();
            }

            showError(message) {
                this.updateStatus(t('errorOccurred'), 0, 'error');
                this.errorMessage.textContent = message;
                this.errorContainer.style.display = 'block';
            }
        }

        // Start solver when DOM is ready
        document.addEventListener('DOMContentLoaded', () => {
            const solver = new PowSolver();
            solver.start();
        });
    </script>
</body>
</html>
