<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, max-age=0">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Expires" content="0">
    <title>Вход в управлялку vMix под ЖФЛ</title>
    <link rel="icon" href="/static/smith.ico" type="image/x-icon">
    <style>
        :root {
            --bg: #000000;
            --green: #00ff66;
            --green-soft: #00cc55;
            --green-dim: rgba(0, 255, 102, 0.7);
            --panel: rgba(0, 20, 0, 0.22);
            --border: rgba(0, 255, 102, 0.22);
            --danger: #ff5f56;
        }

        * {
            box-sizing: border-box;
        }

        html, body {
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
            background: var(--bg);
            color: var(--green);
            font-family: "Courier New", monospace;
        }

        body {
            position: relative;
        }

        #matrixCanvas {
            position: fixed;
            inset: 0;
            width: 100%;
            height: 100%;
            z-index: 0;
            opacity: 0.22;
        }

        .screen {
            position: relative;
            z-index: 1;
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 24px;
        }

        .terminal {
            width: min(900px, 100%);
            min-height: 420px;
            padding: 32px;
            border: 1px solid var(--border);
            background: linear-gradient(
                180deg,
                rgba(0, 18, 0, 0.35) 0%,
                rgba(0, 0, 0, 0.72) 100%
            );
            box-shadow:
                0 0 24px rgba(0, 255, 102, 0.08),
                inset 0 0 30px rgba(0, 255, 102, 0.04);
            backdrop-filter: blur(2px);
        }

        .terminal-header {
            display: flex;
            align-items: center;
            gap: 8px;
            margin-bottom: 24px;
        }

        .dot {
            width: 10px;
            height: 10px;
            border-radius: 999px;
            background: var(--green);
            box-shadow: 0 0 8px rgba(0, 255, 102, 0.5);
        }

        .terminal-title {
            margin-left: 8px;
            font-size: 13px;
            color: var(--green-dim);
            letter-spacing: 0.12em;
            text-transform: uppercase;
        }

.terminal-body {
    font-size: 28px;
    line-height: 1.8;
    text-shadow: 0 0 10px rgba(0, 255, 102, 0.18);
}

.term-line {
    display: block;
    min-height: 1.8em;
}

        .prompt-line {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
            gap: 6px;
        }

.prompt {
    color: var(--green);
}

        .input-wrap {
            position: relative;
            display: inline-flex;
            align-items: center;
            min-width: 220px;
        }

.fake-input {
    position: absolute;
    left: -9999px;
    opacity: 0;
    pointer-events: none;
}

.typed-value {
    color: var(--green);
}

.caret {
    display: inline;
    margin-left: -1px;  /* чуть прижать к тексту */
}

.hidden {
    display: none;
}

        .sys-message {
            margin-top: 18px;
            font-size: 16px;
            color: var(--green-dim);
            line-height: 1.5;
        }

        .sys-error {
            color: var(--danger);
            text-shadow: 0 0 8px rgba(255, 95, 86, 0.25);
        }

        .subtle {
            opacity: 0.8;
        }

        .scanline::before {
            content: "";
            position: fixed;
            inset: 0;
            pointer-events: none;
            z-index: 2;
            background: linear-gradient(
                to bottom,
                rgba(255, 255, 255, 0.02),
                rgba(255, 255, 255, 0.00) 3px
            );
            background-size: 100% 4px;
            opacity: 0.08;
        }

        @keyframes blink {
            0%, 49% { opacity: 1; }
            50%, 100% { opacity: 0; }
        }

        @media (max-width: 700px) {
            .terminal {
                padding: 22px;
                min-height: 360px;
            }

            .terminal-body {
                font-size: 20px;
                line-height: 1;
            }

            .sys-message {
                font-size: 14px;
            }
        }
    </style>
</head>
<body class="scanline">
    <canvas id="matrixCanvas"></canvas>

    <div class="screen">
        <div class="terminal">
            <div class="terminal-header">
                <span class="dot"></span>
                <span class="dot" style="opacity: 0.7;"></span>
                <span class="dot" style="opacity: 0.45;"></span>
                <div class="terminal-title">wfl access terminal</div>
            </div>

            <div class="terminal-body" id="terminalBody">
                <div class="term-line" id="welcomeLine"></div>

                <div class="term-line hidden" id="loginLine">
                    <span id="loginPrompt" class="prompt"></span>
                    <span id="usernameText" class="typed-value"></span><span id="usernameCaret" class="caret">█</span>
                    <input id="usernameInput" class="fake-input" type="text" autocomplete="username" spellcheck="false">
                </div>

                <div class="term-line hidden" id="passwordLine">
                    <span id="passwordPrompt" class="prompt"></span>
                    <span id="passwordText" class="typed-value"></span><span id="passwordCaret" class="caret hidden">█</span>
                    <input id="passwordInput" class="fake-input" type="password" autocomplete="current-password" spellcheck="false">
                </div>

                <div class="term-line hidden subtle" id="submitLine">
                    authorizing...
                </div>

                {% if message %}
                    <div class="sys-message">{{ message }}</div>
                {% endif %}

                {% if error %}
                    <div class="sys-message sys-error">{{ error }}</div>
                {% endif %}
            </div>
        </div>
    </div>

    <form id="realLoginForm" method="post" action="/login" class="hidden">
        <input type="hidden" name="username" id="realUsername">
        <input type="hidden" name="password" id="realPassword">
    </form>

<script>
(function () {
    const canvas = document.getElementById("matrixCanvas");
    const ctx = canvas ? canvas.getContext("2d") : null;

    let matrixAnimationId = null;
    let drops = [];
    const fontSize = 18;
    const chars = "アイウエオカキクケコサシスセソ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZЖФЛ<>+*#";
    let columns = 0;
    let lastTime = 0;
    const fps = 18;
    const interval = 1000 / fps;

    function resizeCanvas() {
        if (!canvas || !ctx) return;
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        columns = Math.floor(canvas.width / fontSize);
        drops = Array(columns).fill(1);
    }

    function drawMatrix(time = 0) {
        if (!canvas || !ctx) return;

        if (time - lastTime < interval) {
            matrixAnimationId = requestAnimationFrame(drawMatrix);
            return;
        }

        lastTime = time;

        ctx.fillStyle = "rgba(0, 0, 0, 0.12)";
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        ctx.fillStyle = "#00ff66";
        ctx.font = fontSize + "px monospace";

        for (let i = 0; i < drops.length; i++) {
            const text = chars[Math.floor(Math.random() * chars.length)];
            ctx.fillText(text, i * fontSize, drops[i] * fontSize);

            if (drops[i] * fontSize > canvas.height && Math.random() > 0.985) {
                drops[i] = 0;
            }

            drops[i] += 0.65;
        }

        matrixAnimationId = requestAnimationFrame(drawMatrix);
    }

    resizeCanvas();
    drawMatrix();
    window.addEventListener("resize", resizeCanvas);

    const welcomeText = "добро пожаловать в ЖФЛ";

    const welcomeLine = document.getElementById("welcomeLine");
    const loginLine = document.getElementById("loginLine");
    const passwordLine = document.getElementById("passwordLine");
    const submitLine = document.getElementById("submitLine");

    const loginPrompt = document.getElementById("loginPrompt");
    const passwordPrompt = document.getElementById("passwordPrompt");

    const usernameInput = document.getElementById("usernameInput");
    const passwordInput = document.getElementById("passwordInput");

    const usernameText = document.getElementById("usernameText");
    const passwordText = document.getElementById("passwordText");

    const usernameCaret = document.getElementById("usernameCaret");
    const passwordCaret = document.getElementById("passwordCaret");

    const realLoginForm = document.getElementById("realLoginForm");
    const realUsername = document.getElementById("realUsername");
    const realPassword = document.getElementById("realPassword");

    const hasServerError = !!document.querySelector(".sys-error");

    let phase = "waiting_start";
    let started = false;
    let audioCtx = null;

    function ensureAudioContext() {
        if (!audioCtx) {
            audioCtx = new (window.AudioContext || window.webkitAudioContext)();
        }

        if (audioCtx.state === "suspended") {
            audioCtx.resume();
        }

        return audioCtx;
    }

    function playKeySound() {
        const ctx = ensureAudioContext();

        const oscillator = ctx.createOscillator();
        const gainNode = ctx.createGain();

        oscillator.type = "square";
        oscillator.frequency.setValueAtTime(900, ctx.currentTime);

        gainNode.gain.setValueAtTime(0.012, ctx.currentTime);
        gainNode.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + 0.035);

        oscillator.connect(gainNode);
        gainNode.connect(ctx.destination);

        oscillator.start();
        oscillator.stop(ctx.currentTime + 0.035);
    }

    function typeText(target, text, speed = 60, callback, withSound = true) {
        let i = 0;

        function typing() {
            if (i < text.length) {
                target.textContent += text[i];
                if (withSound) playKeySound();
                i++;
                setTimeout(typing, speed);
            } else if (callback) {
                callback();
            }
        }

        typing();
    }

    function focusCurrentInput() {
        if (phase === "login") {
            usernameInput.focus();
        } else if (phase === "password") {
            passwordInput.focus();
        }
    }

    function showLoginStep(prefill = "") {
        phase = "typing_login";
        loginLine.classList.remove("hidden");
        usernameCaret.classList.add("hidden");
        passwordCaret.classList.add("hidden");
        loginPrompt.textContent = "";
        usernameText.textContent = "";
        usernameInput.value = "";

        typeText(loginPrompt, "login:", 60, () => {
            if (prefill) {
                usernameInput.value = prefill;
                usernameText.textContent = prefill;
            }

            phase = "login";
            usernameCaret.classList.remove("hidden");
            usernameInput.focus();
        });
    }

    function showPasswordStep(prefill = "") {
        phase = "typing_password";
        passwordLine.classList.remove("hidden");

        usernameCaret.classList.add("hidden");
        passwordCaret.classList.add("hidden");

        passwordPrompt.textContent = "";
        passwordText.textContent = "";
        passwordInput.value = "";

        typeText(passwordPrompt, "password:", 60, () => {
            if (prefill) {
                passwordInput.value = prefill;
                passwordText.textContent = "*".repeat(prefill.length);
            }

            phase = "password";
            passwordCaret.classList.remove("hidden");
            passwordInput.focus();
        });
    }

    function submitLogin() {
        phase = "submitting";
        usernameCaret.classList.add("hidden");
        passwordCaret.classList.add("hidden");
        submitLine.classList.remove("hidden");

        realUsername.value = usernameInput.value.trim();
        realPassword.value = passwordInput.value;

        setTimeout(() => {
            realLoginForm.submit();
        }, 350);
    }

    function startSequence(options = {}) {
        if (started) return;
        started = true;

        const skipWelcome = !!options.skipWelcome;
        const usernamePrefill = options.usernamePrefill || "";

        ensureAudioContext();

        phase = "typing_welcome";
        welcomeLine.textContent = "";
        loginPrompt.textContent = "";
        passwordPrompt.textContent = "";
        usernameText.textContent = "";
        passwordText.textContent = "";
        usernameInput.value = "";
        passwordInput.value = "";
        submitLine.classList.add("hidden");

        loginLine.classList.add("hidden");
        passwordLine.classList.add("hidden");

        usernameCaret.classList.add("hidden");
        passwordCaret.classList.add("hidden");

        if (skipWelcome) {
            welcomeLine.textContent = welcomeText;
            setTimeout(() => showLoginStep(usernamePrefill), 120);
            return;
        }

        typeText(welcomeLine, welcomeText, 75, () => {
            setTimeout(() => showLoginStep(usernamePrefill), 220);
        });
    }

    usernameInput.addEventListener("input", function () {
        usernameText.textContent = usernameInput.value;
        playKeySound();
    });

    passwordInput.addEventListener("input", function () {
        passwordText.textContent = "*".repeat(passwordInput.value.length);
        playKeySound();
    });

    usernameInput.addEventListener("keydown", function (event) {
        if (event.key === "Enter") {
            playKeySound();
            event.preventDefault();

            if (!usernameInput.value.trim()) {
                return;
            }

            usernameCaret.classList.add("hidden");
            showPasswordStep();
        }
    });

    passwordInput.addEventListener("keydown", function (event) {
        if (event.key === "Enter") {
            playKeySound();
            event.preventDefault();

            if (!usernameInput.value.trim() || !passwordInput.value) {
                return;
            }

            submitLogin();
        }
    });

    document.addEventListener("click", function () {
        if (!started) {
            startSequence();
            return;
        }
        focusCurrentInput();
    });

    document.addEventListener("keydown", function (event) {
        if (!started) {
            event.preventDefault();
            startSequence();
            return;
        }

        if (
            phase === "typing_welcome" ||
            phase === "typing_login" ||
            phase === "typing_password" ||
            phase === "submitting"
        ) {
            return;
        }

        if (document.activeElement === usernameInput || document.activeElement === passwordInput) {
            return;
        }

        if (event.key === "Tab") {
            event.preventDefault();
            focusCurrentInput();
            return;
        }

        if (event.key.length === 1 || event.key === "Backspace") {
            focusCurrentInput();
        }
    });

    if (hasServerError) {
        startSequence({ skipWelcome: true });
    }
})();
</script>

</body>
</html>