/*
 * Zelda64Jewel GIF Manager - Version 1.3 PRODUCTION
 * Copyright (c) 2025 TheRND2
 * For Waveshare ESP32-S3-LCD-1.69 Rev2
 * No emoji or extended characters - plain ASCII only
 * Production ready - clean interface with hidden secret system
 */

#ifndef WEBPAGE_H
#define WEBPAGE_H

const char PAGE_HTML[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Zelda64Jewel GIF Manager - v1.3 PRODUCTION</title>
    <style>
        body {
            font-family: 'Courier New', monospace;
            margin: 0;
            padding: 20px;
            background: linear-gradient(135deg, #0f2027 0%, #203a43 25%, #2c5364 100%);
            color: #ffd700;
            min-height: 100vh;
            line-height: 1.4;
        }
        .container {
            max-width: 1000px;
            margin: 0 auto;
            background: rgba(0,0,0,0.4);
            padding: 30px;
            border-radius: 15px;
            box-shadow: 0 8px 32px rgba(0,0,0,0.5);
            border: 2px solid rgba(255,215,0,0.3);
        }
        .loading-indicator {
            display: none;
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(255,215,0,0.9);
            color: #000;
            padding: 10px 20px;
            border-radius: 20px;
            font-weight: bold;
            z-index: 1000;
            animation: pulse 1s infinite;
        }
        @keyframes pulse {
            0% { opacity: 0.8; }
            50% { opacity: 1; }
            100% { opacity: 0.8; }
        }
        .triforce-icon {
            width: 0;
            height: 0;
            border-left: 25px solid transparent;
            border-right: 25px solid transparent;
            border-bottom: 43px solid #ffd700;
            margin: 20px auto;
            position: relative;
            filter: drop-shadow(0 0 10px rgba(255,215,0,0.5));
        }
        .triforce-icon::before {
            content: '';
            position: absolute;
            left: -12.5px;
            top: 15px;
            width: 0;
            height: 0;
            border-left: 12.5px solid transparent;
            border-right: 12.5px solid transparent;
            border-bottom: 21px solid #2c5364;
        }
        h1 {
            text-align: center;
            color: #ffd700;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.8), 0 0 10px rgba(255,215,0,0.5);
            margin-bottom: 10px;
            font-family: 'Courier New', monospace;
            font-size: 24px;
            letter-spacing: 2px;
        }
        h2 {
            color: #87ceeb;
            border-bottom: 2px solid #ffd700;
            padding-bottom: 10px;
            font-family: 'Courier New', monospace;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
        }
        .status-section {
            background: linear-gradient(45deg, rgba(255,215,0,0.1), rgba(255,215,0,0.05));
            padding: 20px;
            border-radius: 10px;
            margin-bottom: 20px;
            border: 2px solid #ffd700;
            box-shadow: inset 0 0 10px rgba(255,215,0,0.2);
        }
        .secret-status {
            background: linear-gradient(45deg, rgba(148,0,211,0.2), rgba(75,0,130,0.1));
            padding: 20px;
            border-radius: 10px;
            margin-bottom: 20px;
            border: 2px solid #9370db;
            box-shadow: inset 0 0 10px rgba(147,112,219,0.3);
        }
        .secret-unlocked {
            background: linear-gradient(45deg, rgba(255,215,0,0.3), rgba(255,165,0,0.2));
            border-color: #ffd700;
            animation: secretGlow 2s ease-in-out infinite alternate;
        }
        @keyframes secretGlow {
            from { box-shadow: inset 0 0 10px rgba(255,215,0,0.3); }
            to { box-shadow: inset 0 0 20px rgba(255,215,0,0.6); }
        }
        .dev-warning {
            background: rgba(255,69,0,0.3);
            border: 2px solid #ff8c00;
            color: #ffb347;
            padding: 15px;
            border-radius: 10px;
            margin-bottom: 20px;
            text-align: center;
            font-weight: bold;
            animation: devWarningPulse 2s ease-in-out infinite alternate;
        }
        @keyframes devWarningPulse {
            from { box-shadow: 0 0 5px rgba(255,140,0,0.3); }
            to { box-shadow: 0 0 15px rgba(255,140,0,0.6); }
        }
        .storage-meter {
            margin: 20px 0;
            background: rgba(0,0,0,0.5);
            border-radius: 10px;
            padding: 15px;
            border: 1px solid #ffd700;
        }
        .storage-bar {
            height: 30px;
            background: #333;
            border-radius: 15px;
            overflow: hidden;
            position: relative;
            margin: 10px 0;
            border: 2px solid #666;
        }
        .storage-fill {
            height: 100%;
            background: linear-gradient(90deg, #22c55e, #16a34a);
            transition: width 0.3s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 14px;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
        }
        .storage-info {
            display: flex;
            justify-content: space-between;
            margin-top: 10px;
            font-size: 12px;
            color: #aaa;
        }
        .upload-progress {
            display: none;
            margin: 20px 0;
            background: rgba(0,0,0,0.5);
            border-radius: 10px;
            padding: 15px;
            border: 1px solid #4169e1;
        }
        .progress-bar {
            height: 25px;
            background: #333;
            border-radius: 15px;
            overflow: hidden;
            position: relative;
            margin: 10px 0;
            border: 2px solid #4169e1;
        }
        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #4169e1, #1e90ff);
            transition: width 0.3s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 12px;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
        }
        .navigation-controls {
            display: flex;
            justify-content: center;
            gap: 15px;
            margin: 20px 0;
            flex-wrap: wrap;
        }
        .nav-btn, .default-btn {
            background: linear-gradient(45deg, #228b22, #32cd32);
            color: white;
            border: none;
            padding: 15px 25px;
            border-radius: 25px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            transition: all 0.3s ease;
            box-shadow: 0 4px 15px rgba(0,0,0,0.3);
            font-family: 'Courier New', monospace;
            text-transform: uppercase;
            min-width: 120px;
        }
        .nav-btn:hover:not(:disabled), .default-btn:hover:not(:disabled) {
            transform: translateY(-3px);
            box-shadow: 0 6px 20px rgba(50,205,50,0.4);
            background: linear-gradient(45deg, #32cd32, #00ff00);
        }
        .nav-btn:disabled {
            background: #666;
            cursor: not-allowed;
            transform: none;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
        }
        .default-btn {
            background: linear-gradient(45deg, #9370db, #8a2be2);
        }
        .default-btn:hover:not(:disabled) {
            background: linear-gradient(45deg, #ba55d3, #9370db);
            box-shadow: 0 6px 20px rgba(147,112,219,0.4);
        }
        .upload-section {
            background: linear-gradient(45deg, rgba(0,100,0,0.2), rgba(0,150,0,0.1));
            padding: 25px;
            border-radius: 15px;
            margin-bottom: 25px;
            border: 2px solid #32cd32;
            box-shadow: 0 0 15px rgba(50,205,50,0.2);
        }
        .file-input {
            margin: 15px 0;
            padding: 15px;
            border: 3px dashed #ffd700;
            border-radius: 10px;
            background: rgba(255,255,255,0.05);
            width: 100%;
            color: #ffd700;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            box-sizing: border-box;
        }
        .upload-btn {
            background: linear-gradient(45deg, #ff6347, #ff4500);
            color: white;
            border: none;
            padding: 15px 35px;
            border-radius: 25px;
            cursor: pointer;
            font-size: 16px;
            font-weight: bold;
            margin-top: 15px;
            transition: all 0.3s ease;
            font-family: 'Courier New', monospace;
            text-transform: uppercase;
            box-shadow: 0 4px 15px rgba(255,69,0,0.3);
        }
        .upload-btn:hover:not(:disabled) {
            transform: scale(1.05);
            box-shadow: 0 6px 20px rgba(255,69,0,0.5);
        }
        .upload-btn:disabled {
            background: #666;
            cursor: not-allowed;
            transform: none;
        }
        .file-table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
            background: rgba(0,0,0,0.3);
            border-radius: 15px;
            overflow: hidden;
            font-family: 'Courier New', monospace;
            border: 2px solid rgba(255,215,0,0.3);
        }
        .file-table th {
            background: linear-gradient(45deg, #1a1a2e, #16213e);
            color: #ffd700;
            padding: 18px;
            text-align: left;
            font-weight: bold;
            text-transform: uppercase;
            letter-spacing: 1px;
            border-bottom: 2px solid #ffd700;
        }
        .file-table td {
            padding: 15px 18px;
            border-bottom: 1px solid rgba(255,215,0,0.2);
            color: #e0e0e0;
        }
        .file-table tr:hover {
            background: rgba(255,215,0,0.1);
        }
        .current-gif {
            background: rgba(255,215,0,0.3) !important;
            border-left: 5px solid #ffd700;
            box-shadow: inset 0 0 10px rgba(255,215,0,0.2);
        }
        .secret-gif {
            background: rgba(148,0,211,0.3) !important;
            border-left: 5px solid #9370db;
            box-shadow: inset 0 0 10px rgba(147,112,219,0.3);
            animation: secretRowGlow 3s ease-in-out infinite alternate;
        }
        @keyframes secretRowGlow {
            from { box-shadow: inset 0 0 10px rgba(147,112,219,0.3); }
            to { box-shadow: inset 0 0 15px rgba(147,112,219,0.6); }
        }
        .valid-gif {
            color: #90ee90;
            font-weight: bold;
        }
        .invalid-gif {
            color: #ff6b6b;
            font-weight: bold;
        }
        .delete-btn {
            background: linear-gradient(45deg, #dc143c, #b22222);
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 15px;
            cursor: pointer;
            font-size: 12px;
            transition: all 0.3s ease;
            font-family: 'Courier New', monospace;
            text-transform: uppercase;
            margin-left: 5px;
        }
        .delete-btn:hover:not(:disabled) {
            background: linear-gradient(45deg, #ff1744, #dc143c);
            transform: scale(1.05);
        }
        .delete-btn:disabled {
            background: #666;
            cursor: not-allowed;
            transform: none;
        }
        .preview-btn {
            background: linear-gradient(45deg, #4169e1, #0000cd);
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 15px;
            cursor: pointer;
            font-size: 12px;
            transition: all 0.3s ease;
            font-family: 'Courier New', monospace;
            text-transform: uppercase;
        }
        .preview-btn:hover:not(:disabled) {
            background: linear-gradient(45deg, #6495ed, #4169e1);
            transform: scale(1.05);
        }
        .preview-btn:disabled {
            background: #666;
            cursor: not-allowed;
            transform: none;
        }
        .make-default-btn {
            background: linear-gradient(45deg, #9370db, #8a2be2);
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 15px;
            cursor: pointer;
            font-size: 12px;
            transition: all 0.3s ease;
            font-family: 'Courier New', monospace;
            text-transform: uppercase;
            margin-left: 5px;
        }
        .make-default-btn:hover:not(:disabled) {
            background: linear-gradient(45deg, #ba55d3, #9370db);
            transform: scale(1.05);
        }
        .make-default-btn:disabled {
            background: #666;
            cursor: not-allowed;
            transform: none;
        }
        .status-message {
            padding: 15px;
            border-radius: 10px;
            margin: 15px 0;
            text-align: center;
            font-weight: bold;
            font-family: 'Courier New', monospace;
            text-transform: uppercase;
            letter-spacing: 1px;
        }
        .success { 
            background: linear-gradient(45deg, rgba(0,128,0,0.3), rgba(50,205,50,0.2)); 
            border: 2px solid #32cd32; 
            color: #90ee90;
        }
        .error { 
            background: linear-gradient(45deg, rgba(255,0,0,0.3), rgba(255,69,0,0.2)); 
            border: 2px solid #ff6b6b; 
            color: #ff9999;
        }
        .info { 
            background: linear-gradient(45deg, rgba(0,191,255,0.3), rgba(135,206,235,0.2)); 
            border: 2px solid #87ceeb; 
            color: #add8e6;
        }
        .gif-preview {
            width: 100px;
            height: 100px;
            border: 3px solid #ffd700;
            border-radius: 8px;
            margin: 5px;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 0 10px rgba(255,215,0,0.3);
            background: #333;
            object-fit: contain;
        }
        .gif-preview.loading {
            background: linear-gradient(45deg, #333 25%, #444 50%, #333 75%);
            background-size: 400% 400%;
            animation: loadingGradient 1.5s ease infinite;
        }
        @keyframes loadingGradient {
            0% { background-position: 0% 50%; }
            50% { background-position: 100% 50%; }
            100% { background-position: 0% 50%; }
        }
        .gif-preview:hover {
            transform: scale(1.1);
            box-shadow: 0 0 20px rgba(255,215,0,0.6);
        }
        .preview-placeholder {
            width: 100px;
            height: 100px;
            border: 3px solid #666;
            border-radius: 8px;
            margin: 5px;
            background: #222;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #666;
            font-size: 12px;
        }
        .modal {
            display: none;
            position: fixed;
            z-index: 1000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.9);
            justify-content: center;
            align-items: center;
        }
        .modal-content {
            background: linear-gradient(45deg, #1a1a2e, #16213e);
            padding: 30px;
            border-radius: 15px;
            text-align: center;
            max-width: 90%;
            max-height: 90%;
            border: 3px solid #ffd700;
            color: #ffd700;
            overflow-y: auto;
        }
        .close-modal {
            float: right;
            font-size: 28px;
            font-weight: bold;
            cursor: pointer;
            color: #ffd700;
            text-shadow: 0 0 5px rgba(255,215,0,0.5);
            margin-left: 20px;
        }
        .legend-text {
            color: #87ceeb;
            font-size: 12px;
            text-align: center;
            margin: 15px 0;
            font-style: italic;
        }
        .copyright {
            color: #666;
            font-size: 10px;
            text-align: center;
            margin-top: 30px;
            border-top: 1px solid #333;
            padding-top: 15px;
        }
        .version-notice {
            background: rgba(148,0,211,0.3);
            border: 2px solid #9370db;
            color: #dda0dd;
            padding: 15px;
            border-radius: 10px;
            margin-bottom: 20px;
            text-align: center;
            font-weight: bold;
        }
        
        /* Custom slider styling */
        input[type="range"] {
            -webkit-appearance: none;
            appearance: none;
            height: 8px;
            border-radius: 5px;
            background: linear-gradient(90deg, #333, #666);
            outline: none;
            border: 2px solid #ffd700;
        }
        
        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: linear-gradient(45deg, #ffd700, #ffed4e);
            cursor: pointer;
            border: 2px solid #fff;
            box-shadow: 0 0 10px rgba(255,215,0,0.5);
        }
        
        input[type="range"]::-moz-range-thumb {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: linear-gradient(45deg, #ffd700, #ffed4e);
            cursor: pointer;
            border: 2px solid #fff;
            box-shadow: 0 0 10px rgba(255,215,0,0.5);
        }
        
        .status-dot {
            display: inline-block;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            margin-right: 5px;
        }
        .status-on { background-color: #90ee90; }
        .status-off { background-color: #ff6b6b; }
        
        @media (max-width: 768px) {
            body {
                padding: 10px;
                font-size: 14px;
            }
            .container { 
                padding: 15px; 
                margin: 0 5px;
            }
            .navigation-controls { 
                flex-direction: column; 
                gap: 10px;
            }
            .nav-btn, .default-btn { 
                margin: 5px 0; 
                width: 100%;
                padding: 12px 20px;
            }
            .file-table { 
                font-size: 11px; 
                display: block;
                overflow-x: auto;
                white-space: nowrap;
            }
            .file-table th,
            .file-table td {
                padding: 10px 8px;
                min-width: 80px;
            }
            h1 { 
                font-size: 18px; 
                letter-spacing: 1px;
            }
            .gif-preview,
            .preview-placeholder {
                width: 80px;
                height: 80px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>ZELDA64JEWEL GIF MANAGER</h1>
        <div class="version-notice">
            VERSION 1.3 PRODUCTION - Ready for end users with hidden secret system
        </div>
        
        <div class="triforce-icon"></div>
        <div class="legend-text">THE POWER OF DIGITAL COURAGE</div>
        
        <div class="loading-indicator" id="loadingIndicator">LOADING...</div>
        
        <div class="status-section">
            <h2>CURRENT STATUS</h2>
            <div id="currentStatus">Loading...</div>
        </div>

        <div class="secret-status" id="secretStatus" style="display: none;">
            <h2>SECRET SYSTEM</h2>
            <div id="secretStatusContent">
                <strong>SECRET STATUS:</strong> <span id="secretState">UNLOCKED!</span><br>
                <strong>UNLOCK METHOD:</strong> 1/15 chance on startup (6.67%)<br>
                <strong>UNLOCKS:</strong> Hidden GIF file 2716057.gif<br>
                <strong>AUDIO CUE:</strong> Secret Found jingle instead of Triforce<br>
                <div style="margin-top: 10px; font-size: 12px; color: #dda0dd;">
                    The secret sound replaces the normal Triforce startup melody when triggered.
                    Once unlocked, the hidden GIF remains available permanently.
                </div>
            </div>
        </div>

        <div class="status-section">
            <h2>MOTION CONTROLS</h2>
            <div style="display: flex; flex-wrap: wrap; gap: 20px; align-items: center;">
                <div style="flex: 1; min-width: 200px;">
                    <label for="motionToggle" style="color: #ffd700; font-weight: bold;">Motion Detection:</label>
                    <button id="motionToggle" class="nav-btn" onclick="toggleMotion()" style="margin-left: 10px;">Loading...</button>
                </div>
                <div style="flex: 1; min-width: 250px;">
                    <label for="sensitivitySlider" style="color: #ffd700; font-weight: bold;">Sensitivity:</label>
                    <div style="display: flex; align-items: center; gap: 10px; margin-top: 5px;">
                        <span style="color: #87ceeb;">Less</span>
                        <input type="range" id="sensitivitySlider" min="0.1" max="3.0" step="0.1" value="2.0" 
                               style="flex: 1;" onchange="updateSensitivity(this.value)">
                        <span style="color: #87ceeb;">More</span>
                        <span id="sensitivityValue" style="color: #ffd700; font-weight: bold; min-width: 30px;">2.0</span>
                    </div>
                    <div style="color: #87ceeb; font-size: 11px; margin-top: 5px; text-align: center;">
                        Higher values = less sensitive to motion
                    </div>
                </div>
            </div>
            <div style="margin-top: 15px;">
                <button class="preview-btn" onclick="testBuzzer()" style="background: linear-gradient(45deg, #ff6347, #ff4500);">
                    Test Buzzer
                </button>
            </div>
        </div>

        <div class="storage-meter">
            <h3 style="color: #ffd700; margin: 0 0 10px 0;">STORAGE SPACE</h3>
            <div class="storage-bar">
                <div class="storage-fill" id="storageFill" style="width: 0%">0%</div>
            </div>
            <div class="storage-info">
                <span id="storageUsed">Used: 0 KB</span>
                <span id="storageFree">Free: 0 KB</span>
                <span id="storageTotal">Total: 0 KB</span>
            </div>
        </div>

        <div class="upload-progress" id="uploadProgress">
            <h3 style="color: #4169e1; margin: 0 0 10px 0;">UPLOAD PROGRESS</h3>
            <div class="progress-bar">
                <div class="progress-fill" id="progressFill" style="width: 0%">0%</div>
            </div>
            <div style="text-align: center; margin-top: 10px;">
                <span id="uploadFileName" style="color: #aaa;">Uploading...</span>
            </div>
        </div>

        <div class="navigation-controls">
            <button class="nav-btn" id="prevBtn" onclick="navigateGif('prev')">Previous</button>
            <button class="nav-btn" id="nextBtn" onclick="navigateGif('next')">Next</button>
            <button class="default-btn" id="makeDefaultBtn" onclick="makeCurrentDefault()">Set as Default</button>
        </div>

        <div class="legend-text" id="normalLegend">
            <strong>VERSION 1.3 FEATURES:</strong><br>
            Enhanced audio system | 3x faster startup melody<br>
            Silent GIF switching | Optimized performance<br>
            Motion controls with adjustable sensitivity<br>
            Production ready with hidden secret system
        </div>

        <div class="legend-text" id="secretLegend" style="display: none;">
            <strong>SECRET SYSTEM FEATURES:</strong><br>
            1/15 startup chance for secret unlock | Silent GIF switching<br>
            Permanent secret file unlock | Triforce vs Secret Found audio<br>
            Hidden easter egg discovery system
        </div>

        <div class="upload-section">
            <h2>UPLOAD NEW GIF</h2>
            <p><strong>Requirements:</strong> Maximum size 280x240 pixels. Only .gif files supported.</p>
            <p id="secretTip" style="display: none;"><strong>Secret Tip:</strong> Upload 2716057.gif - it may become special when the secret unlocks!</p>
            <form id="uploadForm">
                <input type="file" id="fileInput" accept=".gif" class="file-input">
                <div id="uploadPreview"></div>
                <button type="submit" class="upload-btn" id="uploadBtn">Upload GIF</button>
            </form>
            <div id="uploadStatus"></div>
        </div>

        <h2>GIF LIBRARY</h2>
        <table class="file-table">
            <thead>
                <tr>
                    <th>Preview</th>
                    <th>Filename</th>
                    <th>Size</th>
                    <th>Status</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody id="fileTableBody"></tbody>
        </table>

        <div class="legend-text" id="normalAudioInfo">
            <strong>Audio Information:</strong><br>
            Startup: Enhanced Triforce melody (3x faster)<br>
            GIF switching: Silent operation (no audio on motion or web navigation)<br>
            Buzzer test: Demonstrates device audio capabilities<br><br>
            <strong>MAY THE TRIFORCE BE WITH YOU</strong>
        </div>

        <div class="legend-text" id="secretAudioInfo" style="display: none;">
            <strong>Audio Information:</strong><br>
            Normal startup: Triforce melody | Secret startup: Secret Found jingle<br>
            GIF switching: Silent operation (no audio on motion or web navigation)<br>
            Buzzer test: Demonstrates both Triforce and Secret Found sounds<br><br>
            <strong>MAY THE TRIFORCE BE WITH YOU</strong>
        </div>

        <div class="copyright">
            Zelda64Jewel Version 1.3 PRODUCTION | Copyright (c) 2025 TheRND2<br>
            Motion-controlled GIF display with hidden secret system<br>
            Waveshare ESP32-S3-LCD-1.69 Rev2
        </div>
    </div>

    <!-- Preview Modal -->
    <div id="previewModal" class="modal">
        <div class="modal-content">
            <span class="close-modal" onclick="closePreview()">X</span>
            <div id="previewContainer"></div>
        </div>
    </div>

    <script>
        let currentFiles = [];
        let currentGif = '';
        let isOperationInProgress = false;
        let previewQueue = [];
        let isProcessingQueue = false;
        let statusUpdateInterval = null;
        let secretUnlocked = false;

        function showLoading(show) {
            document.getElementById('loadingIndicator').style.display = show ? 'block' : 'none';
        }

        function setOperationInProgress(inProgress) {
            isOperationInProgress = inProgress;
            showLoading(inProgress);
            
            // Disable all buttons during operations
            const buttons = document.querySelectorAll('button');
            buttons.forEach(btn => {
                if (inProgress) {
                    btn.dataset.wasDisabled = btn.disabled;
                    btn.disabled = true;
                } else {
                    btn.disabled = btn.dataset.wasDisabled === 'true';
                }
            });
        }

        function showMessage(message, type = 'info') {
            const statusDiv = document.getElementById('uploadStatus');
            statusDiv.innerHTML = '<div class="status-message ' + type + '">' + message + '</div>';
            setTimeout(() => statusDiv.innerHTML = '', 5000);
        }

        function updateSecretStatus(unlocked) {
            secretUnlocked = unlocked;
            const secretStatus = document.getElementById('secretStatus');
            const secretState = document.getElementById('secretState');
            const normalLegend = document.getElementById('normalLegend');
            const secretLegend = document.getElementById('secretLegend');
            const secretTip = document.getElementById('secretTip');
            const normalAudioInfo = document.getElementById('normalAudioInfo');
            const secretAudioInfo = document.getElementById('secretAudioInfo');
            
            if (unlocked) {
                secretStatus.style.display = 'block';
                secretStatus.classList.add('secret-unlocked');
                secretState.innerHTML = '<span style="color: #ffd700; font-weight: bold;">UNLOCKED!</span> Hidden content available';
                normalLegend.style.display = 'none';
                secretLegend.style.display = 'block';
                secretTip.style.display = 'block';
                normalAudioInfo.style.display = 'none';
                secretAudioInfo.style.display = 'block';
            } else {
                secretStatus.style.display = 'none';
                secretStatus.classList.remove('secret-unlocked');
                normalLegend.style.display = 'block';
                secretLegend.style.display = 'none';
                secretTip.style.display = 'none';
                normalAudioInfo.style.display = 'block';
                secretAudioInfo.style.display = 'none';
            }
        }

        async function updateStorageStatus() {
            try {
                const response = await fetch('/status');
                if (!response.ok) return;
                
                const status = await response.json();
                
                // Update secret status
                updateSecretStatus(status.secretUnlocked || false);
                
                // Update storage meter
                const usedSpace = status.totalSpace - status.freeSpace;
                const usedPercent = Math.round((usedSpace / status.totalSpace) * 100);
                const storageFill = document.getElementById('storageFill');
                storageFill.style.width = usedPercent + '%';
                storageFill.textContent = usedPercent + '%';
                
                // Update color based on usage
                if (usedPercent > 90) {
                    storageFill.style.background = 'linear-gradient(90deg, #dc2626, #ef4444)';
                } else if (usedPercent > 75) {
                    storageFill.style.background = 'linear-gradient(90deg, #f59e0b, #f97316)';
                } else {
                    storageFill.style.background = 'linear-gradient(90deg, #22c55e, #16a34a)';
                }
                
                document.getElementById('storageUsed').textContent = 'Used: ' + formatFileSize(usedSpace);
                document.getElementById('storageFree').textContent = 'Free: ' + formatFileSize(status.freeSpace);
                document.getElementById('storageTotal').textContent = 'Total: ' + formatFileSize(status.totalSpace);
                
                // Update upload progress if in progress
                if (status.uploadInProgress) {
                    document.getElementById('uploadProgress').style.display = 'block';
                    document.getElementById('progressFill').style.width = status.uploadProgress + '%';
                    document.getElementById('progressFill').textContent = status.uploadProgress + '%';
                    document.getElementById('uploadFileName').textContent = 'Uploading: ' + status.uploadFilename;
                } else {
                    document.getElementById('uploadProgress').style.display = 'none';
                }
                
                // Update motion controls
                const motionToggle = document.getElementById('motionToggle');
                const sensitivitySlider = document.getElementById('sensitivitySlider');
                const sensitivityValue = document.getElementById('sensitivityValue');
                
                if (motionToggle) {
                    motionToggle.textContent = status.motionEnabled ? 'ON' : 'OFF';
                    motionToggle.style.background = status.motionEnabled ? 
                        'linear-gradient(45deg, #228b22, #32cd32)' : 
                        'linear-gradient(45deg, #dc143c, #b22222)';
                }
                
                if (sensitivitySlider && sensitivityValue) {
                    sensitivitySlider.value = status.motionSensitivity || 2.0;
                    sensitivityValue.textContent = (status.motionSensitivity || 2.0).toFixed(1);
                }
            } catch (err) {
                console.error('Error updating storage status:', err);
            }
        }

        async function safeApiCall(url, options = {}) {
            if (isOperationInProgress && !url.includes('/status')) {
                showMessage('Another operation is in progress. Please wait...', 'info');
                return null;
            }

            if (!url.includes('/status')) {
                setOperationInProgress(true);
            }
            
            try {
                const response = await fetch(url, options);
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                return response;
            } catch (error) {
                console.error('API call failed:', error);
                showMessage('Operation failed: ' + error.message, 'error');
                return null;
            } finally {
                if (!url.includes('/status')) {
                    setOperationInProgress(false);
                }
            }
        }

        async function updateStatus() {
            const response = await safeApiCall('/list');
            if (!response) return;

            try {
                const files = await response.json();
                currentFiles = files;
                const validGifs = files.filter(f => f.valid);
                const currentFile = files.find(f => f.current);
                currentGif = currentFile ? currentFile.name : '';
                
                document.getElementById('currentStatus').innerHTML = 
                    '<strong>DEVICE STATISTICS</strong><br>' +
                    '- Total files: ' + files.length + '<br>' +
                    '- Valid GIFs: ' + validGifs.length + '<br>' +
                    '- Currently playing: ' + (currentGif || 'None') + '<br>' +
                    '- Device: Zelda64Jewel v1.3 PRODUCTION<br>' +
                    '- Board: Waveshare ESP32-S3-LCD-1.69 Rev2<br>' +
                    '- Motion: Silent switching (no audio)<br>' +
                    (secretUnlocked ? 
                        '- Secret: <span style="color: #ffd700;">UNLOCKED</span><br>' : '') +
                    '- Status: ' + (validGifs.length > 0 ? 
                        '<span class="status-dot status-on"></span><span style="color: #90ee90;">[READY FOR ADVENTURE]</span>' : 
                        '<span class="status-dot status-off"></span><span style="color: #ff9999;">[NO GIFS - UPLOAD SOME!]</span>');
                
                // Update navigation buttons
                const hasMultipleGifs = validGifs.length > 1;
                document.getElementById('prevBtn').disabled = !hasMultipleGifs;
                document.getElementById('nextBtn').disabled = !hasMultipleGifs;
                
                // Update make default button
                const makeDefaultBtn = document.getElementById('makeDefaultBtn');
                if (currentGif) {
                    makeDefaultBtn.disabled = false;
                    makeDefaultBtn.innerHTML = 'Set "' + currentGif + '" as Default';
                } else {
                    makeDefaultBtn.disabled = true;
                    makeDefaultBtn.innerHTML = 'No GIF Playing';
                }
                
                loadFileTable();
                updateStorageStatus();
            } catch (err) {
                console.error('Error parsing status:', err);
                showMessage('Failed to parse device status', 'error');
            }
        }

        function loadFileTable() {
            const tbody = document.getElementById('fileTableBody');
            tbody.innerHTML = '';
            
            if (currentFiles.length === 0) {
                const row = document.createElement('tr');
                row.innerHTML = '<td colspan="5" style="text-align: center; color: #ffa500; padding: 30px;">No files found. Upload some GIFs to get started!</td>';
                tbody.appendChild(row);
                return;
            }
            
            currentFiles.forEach(file => {
                const row = document.createElement('tr');
                let rowClass = '';
                
                if (file.current) {
                    rowClass = 'current-gif';
                } else if (file.name === '2716057.gif') {
                    rowClass = 'secret-gif';
                }
                
                if (rowClass) row.className = rowClass;
                
                const statusClass = file.valid ? 'valid-gif' : 'invalid-gif';
                const statusText = file.valid ? 'VALID' : 'INVALID';
                let currentIndicator = '';
                
                if (file.current) {
                    currentIndicator = ' (PLAYING)';
                } else if (file.name === '2716057.gif') {
                    currentIndicator = ' (SECRET!)';
                }
                
                // Create preview cell with placeholder
                let previewHtml = '';
                if (file.valid) {
                    previewHtml = '<div class="preview-placeholder" id="preview-' + file.name + '">Click<br>Preview</div>';
                } else {
                    previewHtml = '<div style="color: #666; text-align: center;">X</div>';
                }
                
                row.innerHTML = 
                    '<td>' + previewHtml + '</td>' +
                    '<td><strong>' + file.name + '</strong>' + currentIndicator + '</td>' +
                    '<td>' + formatFileSize(file.size) + '</td>' +
                    '<td class="' + statusClass + '">' + statusText + '</td>' +
                    '<td>' +
                        (file.valid ? '<button class="preview-btn" onclick="loadPreview(\'' + file.name + '\')">Preview</button>' : '') +
                        (file.valid ? '<button class="make-default-btn" onclick="makeDefault(\'' + file.name + '\')">Default</button>' : '') +
                        '<button class="delete-btn" onclick="deleteFile(\'' + file.name + '\')">Delete</button>' +
                    '</td>';
                tbody.appendChild(row);
            });
        }

        function formatFileSize(bytes) {
            if (bytes < 1024) return bytes + ' B';
            if (bytes < 1024*1024) return Math.round(bytes/1024) + ' KB';
            return Math.round(bytes/(1024*1024)) + ' MB';
        }

        async function loadPreview(filename) {
            if (isOperationInProgress) {
                showMessage('Please wait for current operation to complete', 'info');
                return;
            }

            const placeholder = document.getElementById('preview-' + filename);
            if (!placeholder) return;

            // Check if already loaded
            if (placeholder.tagName === 'IMG') return;

            // Add to queue
            previewQueue.push(filename);
            processPreviewQueue();
        }

        async function processPreviewQueue() {
            if (isProcessingQueue || previewQueue.length === 0) return;
            
            isProcessingQueue = true;
            
            while (previewQueue.length > 0) {
                const filename = previewQueue.shift();
                const placeholder = document.getElementById('preview-' + filename);
                
                if (placeholder && placeholder.tagName !== 'IMG') {
                    placeholder.className = 'gif-preview loading';
                    placeholder.innerHTML = '';
                    
                    // Wait 300ms between each preview load
                    await new Promise(resolve => setTimeout(resolve, 300));
                    
                    const img = document.createElement('img');
                    img.className = 'gif-preview';
                    img.src = '/preview?file=' + encodeURIComponent(filename);
                    img.onclick = () => showPreview(filename);
                    img.onerror = () => {
                        placeholder.className = 'preview-placeholder';
                        placeholder.innerHTML = 'Error';
                    };
                    img.onload = () => {
                        placeholder.parentNode.replaceChild(img, placeholder);
                    };
                }
            }
            
            isProcessingQueue = false;
        }

        async function navigateGif(direction) {
            const endpoint = direction === 'next' ? '/next' : '/prev';
            const response = await safeApiCall(endpoint, { method: 'POST' });
            if (response) {
                const text = await response.text();
                showMessage(text, 'success');
                setTimeout(updateStatus, 1000);
            }
        }

        async function makeCurrentDefault() {
            if (!currentGif) {
                showMessage('No GIF currently playing', 'error');
                return;
            }
            makeDefault(currentGif);
        }

        async function makeDefault(filename) {
            const response = await safeApiCall('/make_current_default', {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: 'filename=' + encodeURIComponent(filename)
            });
            
            if (response) {
                const text = await response.text();
                showMessage(text, 'success');
            }
        }

        async function deleteFile(filename) {
            if (!confirm('Delete ' + filename + '?\n\nThis action cannot be undone!')) {
                return;
            }
            
            const response = await safeApiCall('/delete', {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: 'file=' + encodeURIComponent(filename)
            });
            
            if (response) {
                const text = await response.text();
                showMessage(text, 'success');
                setTimeout(updateStatus, 3000);
            }
        }

        function showPreview(filename) {
            const modal = document.getElementById('previewModal');
            const container = document.getElementById('previewContainer');
            container.innerHTML = 
                '<h3>PREVIEW: ' + filename + '</h3>' +
                '<img src="/preview?file=' + encodeURIComponent(filename) + '" style="max-width: 100%; max-height: 70vh; border: 3px solid #ffd700; border-radius: 10px;">' +
                '<p>This is how the GIF will appear on your Zelda64Jewel device.</p>';
            modal.style.display = 'flex';
        }

        function closePreview() {
            document.getElementById('previewModal').style.display = 'none';
        }

        document.getElementById('previewModal').onclick = function(event) {
            if (event.target === this) {
                closePreview();
            }
        };

        // Upload handling
        document.getElementById('fileInput').addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (!file) return;

            const previewDiv = document.getElementById('uploadPreview');
            
            if (!file.name.toLowerCase().endsWith('.gif')) {
                showMessage('Only .gif files are allowed!', 'error');
                previewDiv.innerHTML = '';
                return;
            }

            const reader = new FileReader();
            reader.onload = function(event) {
                let specialNote = '';
                if (file.name === '2716057.gif' && secretUnlocked) {
                    specialNote = '<div style="color: #9370db; font-weight: bold; margin-top: 10px;">Special file detected! This is the secret unlocked file.</div>';
                }
                
                previewDiv.innerHTML = 
                    '<div style="margin: 15px 0; border: 2px solid #ffd700; padding: 15px; border-radius: 10px; background: rgba(255,215,0,0.05);">' +
                    '<strong>SELECTED FILE: ' + file.name + '</strong><br>' +
                    '<strong>Size:</strong> ' + formatFileSize(file.size) + '<br>' +
                    '<img src="' + event.target.result + '" class="gif-preview" style="margin-top: 15px;">' +
                    specialNote +
                    '</div>';
                
                const img = new Image();
                img.onload = function() {
                    if (this.width > 280 || this.height > 240) {
                        showMessage('GIF too large! Max: 280x240, Got: ' + this.width + 'x' + this.height, 'error');
                    } else {
                        showMessage('GIF dimensions OK: ' + this.width + 'x' + this.height, 'success');
                    }
                };
                img.src = event.target.result;
            };
            reader.readAsDataURL(file);
        });

        document.getElementById('uploadForm').addEventListener('submit', async function(e) {
            e.preventDefault();
            
            if (isOperationInProgress) {
                showMessage('Please wait for current operation to complete', 'info');
                return;
            }
            
            const fileInput = document.getElementById('fileInput');
            const file = fileInput.files[0];
            if (!file) {
                showMessage('Please select a file first!', 'error');
                return;
            }

            // Check file size against available space first
            const statusResponse = await fetch('/status');
            if (statusResponse.ok) {
                const status = await statusResponse.json();
                if (file.size > status.freeSpace) {
                    showMessage('Insufficient storage space! Need ' + formatFileSize(file.size) + ', have ' + formatFileSize(status.freeSpace), 'error');
                    return;
                }
            }

            setOperationInProgress(true);
            showMessage('UPLOADING TO ZELDA64JEWEL...', 'info');

            // Start progress monitoring
            statusUpdateInterval = setInterval(updateStorageStatus, 500);

            const formData = new FormData();
            formData.append('data', file, file.name);

            try {
                const response = await fetch('/upload', { 
                    method: 'POST', 
                    body: formData 
                });
                
                if (response.ok) {
                    const text = await response.text();
                    showMessage('UPLOAD SUCCESSFUL! ' + text, 'success');
                    document.getElementById('uploadPreview').innerHTML = '';
                    fileInput.value = '';
                    setTimeout(updateStatus, 5000);
                } else if (response.status === 507) {
                    showMessage('Upload failed: Insufficient storage space', 'error');
                } else {
                    throw new Error('Upload failed');
                }
            } catch (err) {
                showMessage('Upload failed: ' + err.message, 'error');
            } finally {
                clearInterval(statusUpdateInterval);
                setOperationInProgress(false);
                updateStorageStatus();
            }
        });

        async function toggleMotion() {
            const currentStatus = document.getElementById('motionToggle').textContent === 'ON';
            const newStatus = !currentStatus;
            
            const response = await safeApiCall('/motion_toggle', {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: 'enabled=' + newStatus
            });
            
            if (response) {
                const text = await response.text();
                showMessage(text, 'success');
                updateStorageStatus();
            }
        }

        async function updateSensitivity(value) {
            document.getElementById('sensitivityValue').textContent = parseFloat(value).toFixed(1);
            
            const response = await safeApiCall('/motion_sensitivity', {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: 'sensitivity=' + value
            });
            
            if (response) {
                const text = await response.text();
                showMessage(text, 'info');
            }
        }

        async function testBuzzer() {
            const response = await safeApiCall('/test_buzzer', { method: 'POST' });
            if (response) {
                const text = await response.text();
                showMessage(text, 'info');
            }
        }

        // Update status every 30 seconds
        setInterval(() => {
            if (!isOperationInProgress) {
                updateStatus();
            }
        }, 30000);

        // Update storage status every 5 seconds
        setInterval(() => {
            if (!isOperationInProgress) {
                updateStorageStatus();
            }
        }, 5000);
        
        // Initial load with correct default sensitivity
        window.onload = () => {
            console.log('Zelda64Jewel Web Interface v1.3 PRODUCTION Loaded');
            document.getElementById('sensitivitySlider').value = '2.0';
            document.getElementById('sensitivityValue').textContent = '2.0';
            updateStatus();
            updateStorageStatus();
        };
    </script>
</body>
</html>
)=====";

#endif // WEBPAGE_H
