{"id":16,"date":"2026-07-11T15:39:52","date_gmt":"2026-07-11T15:39:52","guid":{"rendered":"https:\/\/reduceimageresolution.com\/?page_id=16"},"modified":"2026-07-11T15:49:46","modified_gmt":"2026-07-11T15:49:46","slug":"home","status":"publish","type":"page","link":"https:\/\/reduceimageresolution.com\/?page_id=16","title":{"rendered":"HOME"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Reduce Image Resolution<\/title>\n    <link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.4.0\/css\/all.min.css\">\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jszip\/3.10.1\/jszip.min.js\">\n    <\/script>\n    <style>\n        \/* \u2500\u2500 root \u2500\u2500 *\/\n        :root {\n            --primary: #4a6fa5;\n            --primary-light: #6c8fc7;\n            --secondary: #5d8a82;\n            --secondary-light: #7faca2;\n            --accent: #a56f4a;\n            --light: #f8f9fa;\n            --light-gray: #e9ecef;\n            --medium-gray: #ced4da;\n            --dark-gray: #6c757d;\n            --dark: #343a40;\n            --danger: #e74c3c;\n            --warning: #f39c12;\n            --success: #28a745;\n            --info: #17a2b8;\n            --border-radius: 12px;\n            --card-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);\n            --transition: all 0.3s ease;\n        }\n\n        * {\n            margin: 0;\n            padding: 0;\n            box-sizing: border-box;\n            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n        }\n\n        body {\n            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\n            color: var(--dark);\n            min-height: 100vh;\n            padding: 15px;\n            line-height: 1.6;\n            display: flex;\n            flex-direction: column;\n        }\n\n        .container {\n            max-width: 1200px;\n            margin: 0 auto;\n            width: 100%;\n            flex: 1;\n            display: flex;\n            flex-direction: column;\n        }\n\n        \/* \u2500\u2500 header \u2500\u2500 *\/\n        header {\n            text-align: center;\n            margin-bottom: 25px;\n            padding: 25px 20px;\n            background: white;\n            border-radius: var(--border-radius);\n            box-shadow: var(--card-shadow);\n            position: relative;\n        }\n        header h1 {\n            font-size: 2.5rem;\n            margin-bottom: 12px;\n            color: var(--primary);\n            font-weight: 700;\n        }\n        header p {\n            font-size: 1.1rem;\n            color: var(--dark-gray);\n            max-width: 800px;\n            margin: 0 auto;\n            line-height: 1.6;\n        }\n\n        \/* \u2500\u2500 layout \u2500\u2500 *\/\n        .main-content {\n            display: flex;\n            flex-wrap: wrap;\n            gap: 25px;\n            margin-bottom: 25px;\n            flex: 1;\n        }\n        .card {\n            background: white;\n            border-radius: var(--border-radius);\n            padding: 25px;\n            box-shadow: var(--card-shadow);\n            transition: var(--transition);\n        }\n        .card:hover {\n            transform: translateY(-5px);\n            box-shadow: 0 12px 25px rgba(0, 0, 0, 0.1);\n        }\n        .upload-section {\n            flex: 1;\n            min-width: 300px;\n        }\n        .options-section {\n            flex: 1;\n            min-width: 300px;\n        }\n        .preview-section {\n            flex: 2;\n            min-width: 300px;\n            display: flex;\n            flex-direction: column;\n        }\n\n        .section-title {\n            font-size: 1.4rem;\n            margin-bottom: 20px;\n            color: var(--primary);\n            padding-bottom: 12px;\n            border-bottom: 2px solid var(--light-gray);\n            display: flex;\n            align-items: center;\n            gap: 10px;\n        }\n        .section-title i {\n            font-size: 1.2rem;\n        }\n\n        \/* \u2500\u2500 drop area \u2500\u2500 *\/\n        .drop-area {\n            border: 3px dashed var(--medium-gray);\n            border-radius: 8px;\n            padding: 35px 20px;\n            text-align: center;\n            cursor: pointer;\n            transition: var(--transition);\n            margin-bottom: 20px;\n            background-color: var(--light);\n            position: relative;\n        }\n        .drop-area:hover,\n        .drop-area.active {\n            border-color: var(--primary);\n            background-color: rgba(74, 111, 165, 0.05);\n        }\n        .drop-area i {\n            font-size: 3rem;\n            color: var(--primary-light);\n            margin-bottom: 15px;\n            display: block;\n        }\n        .drop-area p {\n            margin: 10px 0;\n            color: var(--dark-gray);\n        }\n        .batch-upload {\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            margin-top: 10px;\n            gap: 8px;\n        }\n\n        \/* \u2500\u2500 buttons \u2500\u2500 *\/\n        .btn {\n            display: inline-flex;\n            align-items: center;\n            justify-content: center;\n            gap: 8px;\n            padding: 12px 24px;\n            background: var(--primary);\n            color: white;\n            border: none;\n            border-radius: 8px;\n            cursor: pointer;\n            font-size: 1rem;\n            font-weight: 600;\n            transition: var(--transition);\n            text-align: center;\n        }\n        .btn:hover {\n            background: var(--primary-light);\n            transform: translateY(-2px);\n            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);\n        }\n        .btn-secondary {\n            background: var(--secondary);\n        }\n        .btn-secondary:hover {\n            background: var(--secondary-light);\n        }\n        .btn-danger {\n            background: var(--danger);\n        }\n        .btn-danger:hover {\n            background: #c0392b;\n        }\n        .btn-warning {\n            background: var(--warning);\n        }\n        .btn-warning:hover {\n            background: #e67e22;\n        }\n        .btn-success {\n            background: var(--success);\n        }\n        .btn-success:hover {\n            background: #218838;\n        }\n        .btn-info {\n            background: var(--info);\n        }\n        .btn-info:hover {\n            background: #138496;\n        }\n        .btn-sm {\n            padding: 8px 16px;\n            font-size: 0.9rem;\n        }\n\n        \/* \u2500\u2500 form \u2500\u2500 *\/\n        .form-group {\n            margin-bottom: 20px;\n        }\n        .form-group label {\n            display: block;\n            margin-bottom: 8px;\n            font-weight: 600;\n            color: var(--dark);\n            display: flex;\n            align-items: center;\n            gap: 8px;\n        }\n        .form-group label i {\n            color: var(--primary);\n            font-size: 1rem;\n        }\n        select,\n        input {\n            width: 100%;\n            padding: 12px;\n            border: 2px solid var(--light-gray);\n            border-radius: 8px;\n            font-size: 1rem;\n            transition: var(--transition);\n            background-color: var(--light);\n        }\n        select:focus,\n        input:focus {\n            border-color: var(--primary);\n            outline: none;\n            box-shadow: 0 0 0 3px rgba(74, 111, 165, 0.2);\n        }\n\n        \/* \u2500\u2500 preview \u2500\u2500 *\/\n        .preview-container {\n            display: flex;\n            flex-wrap: wrap;\n            gap: 20px;\n            margin-top: 20px;\n        }\n        .preview-box {\n            flex: 1;\n            min-width: 250px;\n            text-align: center;\n            background: var(--light);\n            padding: 18px;\n            border-radius: var(--border-radius);\n        }\n        .preview-title {\n            font-size: 1.1rem;\n            margin-bottom: 12px;\n            color: var(--dark);\n            font-weight: 600;\n        }\n        .image-preview {\n            max-width: 100%;\n            max-height: 280px;\n            border-radius: 8px;\n            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n            margin-bottom: 15px;\n            background: white;\n            padding: 8px;\n        }\n        .image-info {\n            background: var(--light-gray);\n            padding: 10px;\n            border-radius: 8px;\n            font-size: 0.9rem;\n            display: flex;\n            flex-direction: column;\n            gap: 5px;\n        }\n        .image-info span {\n            font-weight: 600;\n            color: var(--primary);\n        }\n\n        .action-buttons {\n            display: flex;\n            gap: 12px;\n            margin-top: 25px;\n            flex-wrap: wrap;\n        }\n\n        .compression-info {\n            background: var(--light);\n            padding: 18px;\n            border-radius: var(--border-radius);\n            margin-top: 20px;\n            text-align: center;\n            border-left: 4px solid var(--success);\n        }\n        .size-reduction {\n            font-weight: bold;\n            color: var(--success);\n            font-size: 1.2rem;\n        }\n\n        .dimension-inputs {\n            display: flex;\n            gap: 12px;\n            margin-top: 12px;\n        }\n        .dimension-inputs>div {\n            flex: 1;\n        }\n        .preserve-aspect {\n            display: flex;\n            align-items: center;\n            margin-top: 12px;\n            gap: 8px;\n            padding: 10px;\n            background: var(--light);\n            border-radius: 8px;\n        }\n\n        \/* \u2500\u2500 messages \u2500\u2500 *\/\n        .message {\n            padding: 12px;\n            margin-top: 12px;\n            border-radius: 8px;\n            display: none;\n            font-weight: 500;\n            display: flex;\n            align-items: center;\n            gap: 8px;\n        }\n        .error-message {\n            color: var(--danger);\n            background-color: rgba(231, 76, 60, 0.1);\n            border-left: 4px solid var(--danger);\n        }\n        .warning-message {\n            color: var(--warning);\n            background-color: rgba(243, 156, 18, 0.1);\n            border-left: 4px solid var(--warning);\n        }\n        .success-message {\n            color: var(--success);\n            background-color: rgba(40, 167, 69, 0.1);\n            border-left: 4px solid var(--success);\n        }\n\n        \/* \u2500\u2500 loading \u2500\u2500 *\/\n        .loading {\n            display: none;\n            text-align: center;\n            margin: 12px 0;\n        }\n        .loading-spinner {\n            border: 4px solid rgba(74, 111, 165, 0.2);\n            border-radius: 50%;\n            border-top: 4px solid var(--primary);\n            width: 35px;\n            height: 35px;\n            animation: spin 1s linear infinite;\n            margin: 0 auto 12px;\n        }\n        @keyframes spin {\n            0% {\n                transform: rotate(0deg);\n            }\n            100% {\n                transform: rotate(360deg);\n            }\n        }\n\n        \/* \u2500\u2500 misc \u2500\u2500 *\/\n        .dpi-settings {\n            background-color: var(--light);\n            padding: 12px;\n            border-radius: 8px;\n            margin-top: 12px;\n            border-left: 4px solid var(--primary);\n        }\n        .format-info {\n            font-size: 0.85rem;\n            color: var(--dark-gray);\n            margin-top: 6px;\n            padding: 6px 10px;\n            background: var(--light);\n            border-radius: 6px;\n        }\n        .privacy-notice {\n            background-color: var(--light);\n            padding: 12px;\n            border-radius: 8px;\n            margin-top: 15px;\n            border-left: 4px solid var(--success);\n            font-size: 0.85rem;\n            display: flex;\n            align-items: flex-start;\n            gap: 10px;\n        }\n        .privacy-notice i {\n            color: var(--success);\n            font-size: 1.1rem;\n        }\n        progress {\n            width: 100%;\n            height: 8px;\n            margin-top: 12px;\n            border-radius: 4px;\n            overflow: hidden;\n        }\n        progress::-webkit-progress-bar {\n            background-color: var(--light-gray);\n            border-radius: 4px;\n        }\n        progress::-webkit-progress-value {\n            background-color: var(--primary);\n            border-radius: 4px;\n        }\n        progress::-moz-progress-bar {\n            background-color: var(--primary);\n            border-radius: 4px;\n        }\n        .option-group {\n            background: var(--light);\n            padding: 18px;\n            border-radius: 10px;\n            margin-bottom: 20px;\n        }\n        .option-group-title {\n            font-size: 1rem;\n            margin-bottom: 12px;\n            color: var(--primary);\n            display: flex;\n            align-items: center;\n            gap: 8px;\n        }\n        .preset-buttons {\n            display: flex;\n            flex-wrap: wrap;\n            gap: 10px;\n            margin-top: 15px;\n        }\n\n        \/* \u2500\u2500 file list \u2500\u2500 *\/\n        .file-list-container {\n            margin-top: 15px;\n            max-height: 250px;\n            overflow-y: auto;\n            border: 1px solid var(--light-gray);\n            border-radius: 8px;\n            padding: 10px;\n        }\n        .file-item {\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n            padding: 8px;\n            background: var(--light);\n            border-radius: 8px;\n            margin-bottom: 8px;\n            font-size: 0.9rem;\n        }\n        .file-info {\n            display: flex;\n            align-items: center;\n            gap: 12px;\n            overflow: hidden;\n        }\n        .file-thumb {\n            width: 60px;\n            height: 60px;\n            object-fit: cover;\n            border-radius: 6px;\n            background: #ddd;\n        }\n        .file-name {\n            white-space: nowrap;\n            overflow: hidden;\n            text-overflow: ellipsis;\n            max-width: 180px;\n        }\n        .file-status {\n            font-size: 0.8rem;\n            padding: 4px 8px;\n            border-radius: 4px;\n            background: var(--light-gray);\n        }\n        .file-status.success {\n            background: var(--success);\n            color: white;\n        }\n        .file-status.error {\n            background: var(--danger);\n            color: white;\n        }\n\n        \/* \u2500\u2500 EXIF \/ history \u2500\u2500 *\/\n        .exif-data {\n            margin-top: 15px;\n            padding: 15px;\n            background: var(--light);\n            border-radius: 8px;\n            font-size: 0.85rem;\n            max-height: 150px;\n            overflow-y: auto;\n        }\n        .exif-data h4 {\n            margin-bottom: 10px;\n            color: var(--primary);\n        }\n        .exif-data table {\n            width: 100%;\n        }\n        .exif-data td {\n            padding: 4px 0;\n        }\n        .exif-data td:first-child {\n            font-weight: 600;\n            color: var(--dark);\n            width: 40%;\n        }\n\n        .history-panel {\n            margin-top: 20px;\n            padding: 15px;\n            background: var(--light);\n            border-radius: 8px;\n            max-height: 200px;\n            overflow-y: auto;\n        }\n        .history-item {\n            display: flex;\n            justify-content: space-between;\n            padding: 8px 0;\n            border-bottom: 1px solid var(--light-gray);\n            cursor: pointer;\n        }\n        .history-item:hover {\n            background: var(--light-gray);\n        }\n        .history-item:last-child {\n            border-bottom: none;\n        }\n        .history-info {\n            display: flex;\n            gap: 10px;\n            align-items: center;\n        }\n        .history-thumb {\n            width: 30px;\n            height: 30px;\n            object-fit: cover;\n            border-radius: 4px;\n        }\n\n        \/* \u2500\u2500 responsive \u2500\u2500 *\/\n        @media (max-width: 992px) {\n            .main-content {\n                flex-direction: column;\n            }\n            .preview-container {\n                flex-direction: column;\n            }\n        }\n        @media (max-width: 768px) {\n            body {\n                padding: 10px;\n            }\n            header {\n                padding: 20px 15px;\n                margin-bottom: 20px;\n            }\n            header h1 {\n                font-size: 2rem;\n            }\n            header p {\n                font-size: 1rem;\n            }\n            .card {\n                padding: 20px;\n            }\n            .action-buttons {\n                flex-direction: column;\n            }\n            .dimension-inputs {\n                flex-direction: column;\n                gap: 10px;\n            }\n            .btn {\n                width: 100%;\n                justify-content: center;\n            }\n            .drop-area {\n                padding: 25px 15px;\n            }\n            .drop-area i {\n                font-size: 2.5rem;\n            }\n            .file-thumb {\n                width: 50px;\n                height: 50px;\n            }\n        }\n\n        \/* \u2500\u2500 batch preview area (hidden by default) \u2500\u2500 *\/\n        #batchPreviewContent {\n            display: none;\n        }\n\n        \/* \u2500\u2500 mode indicator badge \u2500\u2500 *\/\n        .mode-badge {\n            display: inline-block;\n            padding: 4px 14px;\n            border-radius: 30px;\n            font-size: 0.75rem;\n            font-weight: 700;\n            text-transform: uppercase;\n            letter-spacing: 0.5px;\n            margin-left: 10px;\n        }\n        .mode-badge.single {\n            background: var(--primary);\n            color: white;\n        }\n        .mode-badge.batch {\n            background: var(--secondary);\n            color: white;\n        }\n\n        \/* batch status summary *\/\n        .batch-summary {\n            background: var(--light);\n            padding: 18px;\n            border-radius: var(--border-radius);\n            text-align: center;\n            margin: 10px 0 20px 0;\n        }\n        .batch-summary .count {\n            font-size: 2rem;\n            font-weight: 700;\n            color: var(--primary);\n        }\n\n        \/* \u2500\u2500 footer \u2500\u2500 *\/\n        footer {\n            text-align: center;\n            padding: 20px;\n            color: var(--dark-gray);\n            font-size: 0.9rem;\n            background: white;\n            border-radius: var(--border-radius);\n            box-shadow: var(--card-shadow);\n            margin-top: auto;\n            \/* ensure it's centered *\/\n            width: 100%;\n        }\n        footer p {\n            margin: 0;\n        }\n        footer p:last-child {\n            margin-top: 8px;\n            font-size: 0.85rem;\n        }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"container\">\n\n        <!-- HEADER -->\n        <header>\n            <h1><i class=\"fas fa-compress-alt\"><\/i> Reduce Image Resolution<\/h1>\n            <p>Compress and resize your images online without losing quality. Support for multiple output formats, batch processing, and advanced editing options.<\/p>\n        <\/header>\n\n        <!-- MAIN CONTENT -->\n        <div class=\"main-content\">\n\n            <!-- \u2500\u2500\u2500 LEFT COLUMN: UPLOAD \u2500\u2500\u2500 -->\n            <div class=\"card upload-section\">\n                <h2 class=\"section-title\"><i class=\"fas fa-upload\"><\/i> Upload Image<\/h2>\n\n                <div class=\"drop-area\" id=\"dropArea\" aria-labelledby=\"dropAreaLabel\">\n                    <i class=\"fas fa-cloud-upload-alt\"><\/i>\n                    <p id=\"dropAreaLabel\">Drag &#038; Drop your image here<\/p>\n                    <p>OR<\/p>\n                    <input type=\"file\" id=\"fileInput\" accept=\"image\/*\" hidden multiple>\n                    <button class=\"btn\" id=\"browseBtn\"><i class=\"fas fa-folder-open\"><\/i> Browse Files<\/button>\n                    <div class=\"batch-upload\">\n                        <input type=\"checkbox\" id=\"batchMode\" checked>\n                        <label for=\"batchMode\">Enable batch processing (up to 50 images) <span style=\"background:var(--primary); color:white; padding:2px 8px; border-radius:20px; font-size:0.8rem;\">BULK<\/span><\/label>\n                    <\/div>\n                <\/div>\n\n                <!-- Batch file list -->\n                <div class=\"file-list-container\" id=\"batchFilesContainer\" style=\"display: none;\">\n                    <h3>Selected Files (<span id=\"batchCount\">0<\/span>)<\/h3>\n                    <div id=\"batchFilesList\"><\/div>\n                <\/div>\n\n                <!-- Single file info -->\n                <div class=\"file-list-container\" id=\"singleFileContainer\" style=\"display: none;\">\n                    <h3>Selected File<\/h3>\n                    <div id=\"singleFileInfo\"><\/div>\n                <\/div>\n\n                <div class=\"error-message\" id=\"uploadError\" style=\"display: none;\"><i class=\"fas fa-exclamation-circle\"><\/i> <span><\/span><\/div>\n                <div class=\"warning-message\" id=\"uploadWarning\" style=\"display: none;\"><i class=\"fas fa-exclamation-triangle\"><\/i> <span><\/span><\/div>\n\n                <!-- Output Settings -->\n                <div class=\"option-group\">\n                    <div class=\"option-group-title\"><i class=\"fas fa-cog\"><\/i> Output Settings<\/div>\n                    <div class=\"form-group\">\n                        <label for=\"outputFormat\"><i class=\"fas fa-file-image\"><\/i> Output Format<\/label>\n                        <select id=\"outputFormat\">\n                            <option value=\"jpeg\">JPEG<\/option>\n                            <option value=\"png\">PNG<\/option>\n                            <option value=\"webp\">WEBP<\/option>\n                            <option value=\"bmp\">BMP<\/option>\n                            <option value=\"tiff\">TIFF<\/option>\n                        <\/select>\n                        <div class=\"format-info\" id=\"formatInfo\">\n                            <strong>JPEG<\/strong>: Best for photographs, smaller file size\n                        <\/div>\n                    <\/div>\n                    <div class=\"form-group\">\n                        <label><i class=\"fas fa-sliders-h\"><\/i> Quick Presets<\/label>\n                        <div class=\"preset-buttons\">\n                            <button class=\"btn btn-sm btn-info\" data-preset=\"web\">Web Optimized (72 DPI)<\/button>\n                            <button class=\"btn btn-sm btn-info\" data-preset=\"print\">Print Quality (300 DPI)<\/button>\n                            <button class=\"btn btn-sm btn-info\" data-preset=\"social\">Social Media<\/button>\n                            <button class=\"btn btn-sm btn-info\" data-preset=\"email\">Email Attachment<\/button>\n                        <\/div>\n                    <\/div>\n                <\/div>\n\n                <div class=\"privacy-notice\">\n                    <i class=\"fas fa-shield-alt\"><\/i>\n                    <div>Your images are processed entirely in your browser and never uploaded to any server. We respect your privacy.<\/div>\n                <\/div>\n            <\/div>\n\n            <!-- \u2500\u2500\u2500 MIDDLE COLUMN: COMPRESSION OPTIONS \u2500\u2500\u2500 -->\n            <div class=\"card options-section\">\n                <h2 class=\"section-title\"><i class=\"fas fa-sliders-h\"><\/i> Compression Options<\/h2>\n\n                <!-- Resize -->\n                <div class=\"option-group\">\n                    <div class=\"option-group-title\"><i class=\"fas fa-expand-alt\"><\/i> Resize Settings<\/div>\n                    <div class=\"form-group\">\n                        <label for=\"resizeType\"><i class=\"fas fa-ruler\"><\/i> Resize By<\/label>\n                        <select id=\"resizeType\">\n                            <option value=\"percentage\">Percentage<\/option>\n                            <option value=\"pixel\">Pixels<\/option>\n                            <option value=\"cm\">Centimeters<\/option>\n                            <option value=\"inches\">Inches<\/option>\n                        <\/select>\n                    <\/div>\n                    <div class=\"form-group\" id=\"percentageInput\">\n                        <label for=\"resizeValue\"><i class=\"fas fa-percentage\"><\/i> Scale Percentage (%)<\/label>\n                        <input type=\"number\" id=\"resizeValue\" value=\"50\" min=\"1\" max=\"100\">\n                    <\/div>\n                    <div class=\"form-group dimension-inputs\" id=\"pixelInputs\" style=\"display: none;\">\n                        <div>\n                            <label for=\"pixelWidth\"><i class=\"fas fa-arrows-alt-h\"><\/i> Width (px)<\/label>\n                            <input type=\"number\" id=\"pixelWidth\" min=\"1\" max=\"10000\" placeholder=\"Width\">\n                        <\/div>\n                        <div>\n                            <label for=\"pixelHeight\"><i class=\"fas fa-arrows-alt-v\"><\/i> Height (px)<\/label>\n                            <input type=\"number\" id=\"pixelHeight\" min=\"1\" max=\"10000\" placeholder=\"Height\">\n                        <\/div>\n                    <\/div>\n                    <div class=\"form-group dimension-inputs\" id=\"cmInputs\" style=\"display: none;\">\n                        <div>\n                            <label for=\"cmWidth\"><i class=\"fas fa-arrows-alt-h\"><\/i> Width (cm)<\/label>\n                            <input type=\"number\" id=\"cmWidth\" min=\"0.1\" step=\"0.1\" max=\"200\" placeholder=\"Width\">\n                        <\/div>\n                        <div>\n                            <label for=\"cmHeight\"><i class=\"fas fa-arrows-alt-v\"><\/i> Height (cm)<\/label>\n                            <input type=\"number\" id=\"cmHeight\" min=\"0.1\" step=\"0.1\" max=\"200\" placeholder=\"Height\">\n                        <\/div>\n                    <\/div>\n                    <div class=\"form-group dimension-inputs\" id=\"inchInputs\" style=\"display: none;\">\n                        <div>\n                            <label for=\"inchWidth\"><i class=\"fas fa-arrows-alt-h\"><\/i> Width (inches)<\/label>\n                            <input type=\"number\" id=\"inchWidth\" min=\"0.1\" step=\"0.1\" max=\"80\" placeholder=\"Width\">\n                        <\/div>\n                        <div>\n                            <label for=\"inchHeight\"><i class=\"fas fa-arrows-alt-v\"><\/i> Height (inches)<\/label>\n                            <input type=\"number\" id=\"inchHeight\" min=\"0.1\" step=\"0.1\" max=\"80\" placeholder=\"Height\">\n                        <\/div>\n                    <\/div>\n                    <div class=\"preserve-aspect\" id=\"aspectRatioContainer\" style=\"display: none;\">\n                        <input type=\"checkbox\" id=\"preserveAspect\" checked>\n                        <label for=\"preserveAspect\">Preserve Aspect Ratio<\/label>\n                    <\/div>\n                    <div class=\"dpi-settings\" id=\"dpiContainer\" style=\"display: none;\">\n                        <label for=\"dpiValue\"><i class=\"fas fa-tachometer-alt\"><\/i> DPI (Dots Per Inch)<\/label>\n                        <input type=\"number\" id=\"dpiValue\" value=\"96\" min=\"72\" max=\"600\">\n                        <div class=\"format-info\">Used for cm\/inches to pixels conversion. 96 DPI is standard for web.<\/div>\n                    <\/div>\n                <\/div>\n\n                <!-- Quality -->\n                <div class=\"option-group\">\n                    <div class=\"option-group-title\"><i class=\"fas fa-file-export\"><\/i> Output Quality<\/div>\n                    <div class=\"form-group\">\n                        <label for=\"quality\"><i class=\"fas fa-battery-three-quarters\"><\/i> Quality Level (0-100)<\/label>\n                        <input type=\"range\" id=\"quality\" min=\"0\" max=\"100\" value=\"80\">\n                        <div style=\"display: flex; justify-content: space-between; margin-top: 8px;\">\n                            <small>Lower Size<\/small>\n                            <span id=\"qualityValue\">80%<\/span>\n                            <small>Higher Quality<\/small>\n                        <\/div>\n                    <\/div>\n                    <div class=\"form-group\">\n                        <label for=\"exifHandling\"><i class=\"fas fa-camera\"><\/i> EXIF Data Handling<\/label>\n                        <select id=\"exifHandling\">\n                            <option value=\"keep\">Keep EXIF Data<\/option>\n                            <option value=\"remove\">Remove EXIF Data<\/option>\n                        <\/select>\n                        <div class=\"format-info\">EXIF data contains camera information and may affect privacy.<\/div>\n                    <\/div>\n                <\/div>\n\n                <!-- SINGLE MODE: Compress button (hidden in batch) -->\n                <button class=\"btn btn-success\" id=\"compressBtn\" disabled style=\"width:100%;\"><i class=\"fas fa-compress-arrows-alt\"><\/i> Compress Image<\/button>\n\n                <!-- loading indicators -->\n                <div class=\"loading\" id=\"compressionLoading\">\n                    <div class=\"loading-spinner\"><\/div>\n                    <p>Processing image&#8230; <span id=\"progressStep\">Initializing<\/span><\/p>\n                    <progress id=\"compressionProgress\" value=\"0\" max=\"100\"><\/progress>\n                <\/div>\n                <div class=\"loading\" id=\"batchLoading\" style=\"display: none;\">\n                    <div class=\"loading-spinner\"><\/div>\n                    <p>Batch processing <span id=\"batchProgressCurrent\">0<\/span>\/<span id=\"batchProgressTotal\">0<\/span> images&#8230;<\/p>\n                    <progress id=\"batchProgress\" value=\"0\" max=\"100\"><\/progress>\n                <\/div>\n\n                <div class=\"success-message\" id=\"compressionSuccess\" style=\"display: none;\"><i class=\"fas fa-check-circle\"><\/i> <span><\/span><\/div>\n                <div class=\"warning-message\" id=\"batchWarning\" style=\"display: none;\"><i class=\"fas fa-exclamation-triangle\"><\/i> <span><\/span><\/div>\n            <\/div>\n\n            <!-- \u2500\u2500\u2500 RIGHT COLUMN: PREVIEW \u2500\u2500\u2500 -->\n            <div class=\"card preview-section\">\n                <h2 class=\"section-title\">\n                    <i class=\"fas fa-eye\"><\/i> Preview\n                    <span class=\"mode-badge single\" id=\"modeBadge\">Single<\/span>\n                <\/h2>\n\n                <!-- ======== SINGLE MODE CONTENT ======== -->\n                <div id=\"singlePreviewContent\">\n                    <div class=\"preview-container\">\n                        <div class=\"preview-box\">\n                            <h3 class=\"preview-title\">Original Image<\/h3>\n                            <img decoding=\"async\" id=\"originalPreview\" class=\"image-preview\" src=\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='400' height='200' viewBox='0 0 400 200'%3E%3Crect width='400' height='200' fill='%23f8f9fa'\/%3E%3Cpath d='M150 100 L200 70 L250 100 L300 50' stroke='%234a6fa5' stroke-width='4' fill='none'\/%3E%3Ccircle cx='150' cy='100' r='10' fill='%235d8a82'\/%3E%3Ccircle cx='200' cy='70' r='10' fill='%235d8a82'\/%3E%3Ccircle cx='250' cy='100' r='10' fill='%235d8a82'\/%3E%3Ccircle cx='300' cy='50' r='10' fill='%235d8a82'\/%3E%3C\/svg%3E\" alt=\"Original Preview\">\n                            <div class=\"image-info\">\n                                <div>Size: <span id=\"originalSize\">0 KB<\/span><\/div>\n                                <div>Dimensions: <span id=\"originalDimensions\">0 x 0<\/span><\/div>\n                                <div>Type: <span id=\"originalType\">&#8211;<\/span><\/div>\n                            <\/div>\n                        <\/div>\n                        <div class=\"preview-box\">\n                            <h3 class=\"preview-title\">Compressed Image<\/h3>\n                            <img decoding=\"async\" id=\"compressedPreview\" class=\"image-preview\" src=\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='400' height='200' viewBox='0 0 400 200'%3E%3Crect width='400' height='200' fill='%23f8f9fa'\/%3E%3Cpath d='M150 100 L200 70 L250 100 L300 50' stroke='%234a6fa5' stroke-width='4' fill='none'\/%3E%3Ccircle cx='150' cy='100' r='10' fill='%235d8a82'\/%3E%3Ccircle cx='200' cy='70' r='10' fill='%235d8a82'\/%3E%3Ccircle cx='250' cy='100' r='10' fill='%235d8a82'\/%3E%3Ccircle cx='300' cy='50' r='10' fill='%235d8a82'\/%3E%3C\/svg%3E\" alt=\"Compressed Preview\">\n                            <div class=\"image-info\">\n                                <div>Size: <span id=\"compressedSize\">0 KB<\/span><\/div>\n                                <div>Dimensions: <span id=\"compressedDimensions\">0 x 0<\/span><\/div>\n                                <div>Type: <span id=\"compressedType\">&#8211;<\/span><\/div>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"compression-info\">\n                        <i class=\"fas fa-chart-line\"><\/i> Size Reduction: <span id=\"sizeReduction\" class=\"size-reduction\">0%<\/span>\n                    <\/div>\n\n                    <div class=\"exif-data\" id=\"exifContainer\" style=\"display: none;\">\n                        <h4>EXIF Data<\/h4>\n                        <table id=\"exifTable\"><\/table>\n                    <\/div>\n\n                    <!-- SINGLE MODE buttons -->\n                    <div class=\"action-buttons\">\n                        <button class=\"btn\" id=\"downloadBtn\" disabled><i class=\"fas fa-download\"><\/i> Download Compressed Image<\/button>\n                        <button class=\"btn btn-warning\" id=\"newImageBtn\"><i class=\"fas fa-plus-circle\"><\/i> Process New Image<\/button>\n                        <button class=\"btn btn-danger\" id=\"resetBtn\"><i class=\"fas fa-redo\"><\/i> Reset All<\/button>\n                    <\/div>\n                <\/div>\n\n                <!-- ======== BATCH MODE CONTENT ======== -->\n                <div id=\"batchPreviewContent\">\n                    <div class=\"batch-summary\">\n                        <div><i class=\"fas fa-images\" style=\"font-size:2rem; color:var(--primary);\"><\/i><\/div>\n                        <div class=\"count\" id=\"batchFileCountDisplay\">0<\/div>\n                        <div style=\"color:var(--dark-gray);\">images ready for batch compression<\/div>\n                    <\/div>\n\n                    <!-- BATCH MODE buttons -->\n                    <div class=\"action-buttons\">\n                        <button class=\"btn btn-info\" id=\"batchCompressBtn\" style=\"width:100%;\"><i class=\"fas fa-tasks\"><\/i> Compress All (ZIP)<\/button>\n                        <button class=\"btn btn-success\" id=\"downloadZipBtn\" style=\"display:none; width:100%;\"><i class=\"fas fa-file-archive\"><\/i> Download All as ZIP<\/button>\n                    <\/div>\n\n                    <!-- batch progress (shown inside batch preview) -->\n                    <div class=\"loading\" id=\"batchLoadingInline\" style=\"display: none;\">\n                        <div class=\"loading-spinner\"><\/div>\n                        <p>Batch processing <span id=\"batchProgressCurrentInline\">0<\/span>\/<span id=\"batchProgressTotalInline\">0<\/span> images&#8230;<\/p>\n                        <progress id=\"batchProgressInline\" value=\"0\" max=\"100\"><\/progress>\n                    <\/div>\n                    <div class=\"success-message\" id=\"batchSuccessInline\" style=\"display: none;\"><i class=\"fas fa-check-circle\"><\/i> <span><\/span><\/div>\n                    <div class=\"warning-message\" id=\"batchWarningInline\" style=\"display: none;\"><i class=\"fas fa-exclamation-triangle\"><\/i> <span><\/span><\/div>\n                <\/div>\n\n                <!-- History (shown in both modes) -->\n                <div class=\"history-panel\" id=\"historyPanel\" style=\"display: none;\">\n                    <h4>Recent Compressions<\/h4>\n                    <div id=\"historyList\"><\/div>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- FOOTER (centered) -->\n        <footer>\n            <p>\u00a9 <span id=\"currentYear\"><\/span> Reduce Image Resolution | All rights reserved<\/p>\n            <p>Designed with <i class=\"fas fa-heart\" style=\"color: #e74c3c;\"><\/i> for easy image compression<\/p>\n        <\/footer>\n    <\/div>\n\n    <script>\n        \/\/ ============================================================\n        \/\/  PIXLOP \u2014 FULL JAVASCRIPT ENGINE\n        \/\/ ============================================================\n\n        \/\/ \u2500\u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        function formatFileSize(bytes) {\n            if (bytes < 1024) return bytes + ' bytes';\n            if (bytes < 1048576) return (bytes \/ 1024).toFixed(2) + ' KB';\n            return (bytes \/ 1048576).toFixed(2) + ' MB';\n        }\n\n        function showMessage(el, msg) {\n            if (!el) return;\n            const span = el.querySelector('span');\n            if (span) span.textContent = msg;\n            el.style.display = 'flex';\n        }\n\n        function hideMessage(el) {\n            if (el) el.style.display = 'none';\n        }\n\n        function getSafeMimeType(fmt) {\n            const map = {\n                'jpeg': 'image\/jpeg',\n                'jpg': 'image\/jpeg',\n                'png': 'image\/png',\n                'webp': 'image\/webp',\n                'bmp': 'image\/png',\n                'tiff': 'image\/png'\n            };\n            return map[fmt.toLowerCase()] || 'image\/png';\n        }\n\n        \/\/ \u2500\u2500\u2500 DOM refs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        const fileInput = document.getElementById('fileInput');\n        const browseBtn = document.getElementById('browseBtn');\n        const dropArea = document.getElementById('dropArea');\n        const uploadError = document.getElementById('uploadError');\n        const uploadWarning = document.getElementById('uploadWarning');\n        const outputFormat = document.getElementById('outputFormat');\n        const formatInfo = document.getElementById('formatInfo');\n        const resizeType = document.getElementById('resizeType');\n        const resizeValue = document.getElementById('resizeValue');\n        const pixelWidth = document.getElementById('pixelWidth');\n        const pixelHeight = document.getElementById('pixelHeight');\n        const cmWidth = document.getElementById('cmWidth');\n        const cmHeight = document.getElementById('cmHeight');\n        const inchWidth = document.getElementById('inchWidth');\n        const inchHeight = document.getElementById('inchHeight');\n        const preserveAspect = document.getElementById('preserveAspect');\n        const dpiValue = document.getElementById('dpiValue');\n        const quality = document.getElementById('quality');\n        const qualityValue = document.getElementById('qualityValue');\n        const compressBtn = document.getElementById('compressBtn');\n        const compressionLoading = document.getElementById('compressionLoading');\n        const progressStep = document.getElementById('progressStep');\n        const compressionProgress = document.getElementById('compressionProgress');\n        const compressionSuccess = document.getElementById('compressionSuccess');\n        const originalPreview = document.getElementById('originalPreview');\n        const originalSize = document.getElementById('originalSize');\n        const originalDimensions = document.getElementById('originalDimensions');\n        const originalType = document.getElementById('originalType');\n        const compressedPreview = document.getElementById('compressedPreview');\n        const compressedSize = document.getElementById('compressedSize');\n        const compressedDimensions = document.getElementById('compressedDimensions');\n        const compressedType = document.getElementById('compressedType');\n        const sizeReduction = document.getElementById('sizeReduction');\n        const downloadBtn = document.getElementById('downloadBtn');\n        const newImageBtn = document.getElementById('newImageBtn');\n        const resetBtn = document.getElementById('resetBtn');\n        const batchMode = document.getElementById('batchMode');\n        const batchFilesContainer = document.getElementById('batchFilesContainer');\n        const batchFilesList = document.getElementById('batchFilesList');\n        const batchCount = document.getElementById('batchCount');\n        const singleFileContainer = document.getElementById('singleFileContainer');\n        const singleFileInfo = document.getElementById('singleFileInfo');\n        const presetButtons = document.querySelectorAll('[data-preset]');\n        const exifContainer = document.getElementById('exifContainer');\n        const exifTable = document.getElementById('exifTable');\n        const historyPanel = document.getElementById('historyPanel');\n        const historyList = document.getElementById('historyList');\n\n        \/\/ Batch mode elements (now in preview section)\n        const batchCompressBtn = document.getElementById('batchCompressBtn');\n        const downloadZipBtn = document.getElementById('downloadZipBtn');\n        const batchLoadingInline = document.getElementById('batchLoadingInline');\n        const batchProgressCurrentInline = document.getElementById('batchProgressCurrentInline');\n        const batchProgressTotalInline = document.getElementById('batchProgressTotalInline');\n        const batchProgressInline = document.getElementById('batchProgressInline');\n        const batchSuccessInline = document.getElementById('batchSuccessInline');\n        const batchWarningInline = document.getElementById('batchWarningInline');\n        const batchFileCountDisplay = document.getElementById('batchFileCountDisplay');\n        const modeBadge = document.getElementById('modeBadge');\n\n        \/\/ single \/ batch content containers\n        const singlePreviewContent = document.getElementById('singlePreviewContent');\n        const batchPreviewContent = document.getElementById('batchPreviewContent');\n\n        \/\/ \u2500\u2500\u2500 state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        let originalImage = null;\n        let compressedImageData = null;\n        let originalImageData = { width: 0, height: 0, size: 0, type: '', file: null };\n        let batchFiles = [];\n        let batchCompressedResults = [];\n        let compressionHistory = [];\n\n        \/\/ \u2500\u2500\u2500 core compression \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        function compressImageFromElement(img, settings, originalFilename = 'image') {\n            return new Promise((resolve, reject) => {\n                let newWidth, newHeight;\n                const type = settings.resizeType;\n\n                if (type === 'percentage') {\n                    const ratio = parseInt(settings.resizeValue) \/ 100;\n                    newWidth = Math.round(img.width * ratio);\n                    newHeight = Math.round(img.height * ratio);\n                } else if (type === 'pixel') {\n                    newWidth = parseInt(settings.pixelWidth) || img.width;\n                    newHeight = parseInt(settings.pixelHeight) || img.height;\n                    if (settings.preserveAspect) {\n                        const ratio = img.width \/ img.height;\n                        if (newWidth && !newHeight) newHeight = Math.round(newWidth \/ ratio);\n                        else if (!newWidth && newHeight) newWidth = Math.round(newHeight * ratio);\n                        else if (newWidth && newHeight) {\n                            const targetRatio = newWidth \/ newHeight;\n                            if (ratio > targetRatio) newHeight = Math.round(newWidth \/ ratio);\n                            else newWidth = Math.round(newHeight * ratio);\n                        }\n                    }\n                } else if (type === 'cm' || type === 'inches') {\n                    const dpi = parseInt(settings.dpiValue) || 96;\n                    let wInch = 0,\n                        hInch = 0;\n                    if (type === 'cm') {\n                        wInch = (parseFloat(settings.cmWidth) || 0) \/ 2.54;\n                        hInch = (parseFloat(settings.cmHeight) || 0) \/ 2.54;\n                    } else {\n                        wInch = parseFloat(settings.inchWidth) || 0;\n                        hInch = parseFloat(settings.inchHeight) || 0;\n                    }\n                    newWidth = Math.round(wInch * dpi);\n                    newHeight = Math.round(hInch * dpi);\n                    if (settings.preserveAspect && newWidth && newHeight) {\n                        const ratio = img.width \/ img.height;\n                        const targetRatio = newWidth \/ newHeight;\n                        if (ratio > targetRatio) newHeight = Math.round(newWidth \/ ratio);\n                        else newWidth = Math.round(newHeight * ratio);\n                    }\n                }\n\n                newWidth = Math.min(newWidth || img.width, 10000);\n                newHeight = Math.min(newHeight || img.height, 10000);\n                if (newWidth <= 0) newWidth = img.width;\n                if (newHeight <= 0) newHeight = img.height;\n\n                const canvas = document.createElement('canvas');\n                canvas.width = newWidth;\n                canvas.height = newHeight;\n                const ctx = canvas.getContext('2d');\n                ctx.drawImage(img, 0, 0, newWidth, newHeight);\n\n                const mime = getSafeMimeType(settings.outputFormat);\n                const ql = parseInt(settings.quality) \/ 100;\n\n                canvas.toBlob((blob) => {\n                    if (!blob) reject(new Error('Compression failed'));\n                    else resolve({ blob, filename: originalFilename, width: newWidth, height: newHeight,\n                        size: blob.size, type: settings.outputFormat });\n                }, mime, ql);\n            });\n        }\n\n        function compressImageFile(file, settings) {\n            return new Promise((resolve, reject) => {\n                const reader = new FileReader();\n                reader.onload = (e) => {\n                    const img = new Image();\n                    img.onload = () => {\n                        compressImageFromElement(img, settings, file.name).then(resolve).catch(reject);\n                    };\n                    img.onerror = () => reject(new Error('Failed to load image: ' + file.name));\n                    img.src = e.target.result;\n                };\n                reader.onerror = () => reject(new Error('Failed to read file: ' + file.name));\n                reader.readAsDataURL(file);\n            });\n        }\n\n        \/\/ \u2500\u2500\u2500 UI: file handling \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        function handleFileSelect() {\n            const files = fileInput.files;\n            if (!files.length) return;\n\n            if (batchMode.checked) {\n                processBatchFiles(Array.from(files).slice(0, 50));\n                if (files.length > 50) showMessage(uploadWarning, 'Only the first 50 images will be processed.');\n                singleFileContainer.style.display = 'none';\n            } else {\n                processSingleFile(files[0]);\n                batchFilesContainer.style.display = 'none';\n                batchCompressBtn.style.display = 'none';\n                compressBtn.style.display = 'block';\n                downloadZipBtn.style.display = 'none';\n            }\n            updateModeUI();\n        }\n\n        function processSingleFile(file) {\n            if (!file.type.match('image.*')) {\n                showMessage(uploadError, 'Please select an image file (JPEG, PNG, etc.)');\n                return;\n            }\n            if (file.size > 20 * 1024 * 1024) {\n                showMessage(uploadError, 'Image size should be less than 20MB');\n                return;\n            }\n            hideMessage(uploadError);\n            hideMessage(uploadWarning);\n\n            const reader = new FileReader();\n            reader.onload = (e) => {\n                const img = new Image();\n                img.onload = () => {\n                    originalImage = img;\n                    originalPreview.src = e.target.result;\n\n                    originalImageData.width = img.width;\n                    originalImageData.height = img.height;\n                    originalImageData.size = file.size;\n                    originalImageData.type = file.type.split('\/')[1].toUpperCase();\n                    originalImageData.file = file;\n\n                    originalDimensions.textContent = `${img.width} x ${img.height}`;\n                    originalSize.textContent = formatFileSize(file.size);\n                    originalType.textContent = originalImageData.type;\n\n                    if (resizeType.value === 'pixel') {\n                        pixelWidth.value = img.width;\n                        pixelHeight.value = img.height;\n                    }\n\n                    compressBtn.disabled = false;\n                    extractEXIFData(file);\n\n                    singleFileContainer.style.display = 'block';\n                    singleFileInfo.innerHTML = `\n                                <div class=\"file-item\">\n                                    <div class=\"file-info\">\n                                        <img decoding=\"async\" src=\"${e.target.result}\" class=\"file-thumb\" alt=\"${file.name}\">\n                                        <span class=\"file-name\" title=\"${file.name}\">${file.name}<\/span>\n                                    <\/div>\n                                    <div class=\"file-status\">Ready<\/div>\n                                <\/div>\n                            `;\n                    updateModeUI();\n                };\n                img.onerror = () => showMessage(uploadError, 'Failed to load the image.');\n                img.src = e.target.result;\n            };\n            reader.readAsDataURL(file);\n        }\n\n        function processBatchFiles(files) {\n            batchFiles = files;\n            batchFilesList.innerHTML = '';\n            batchCount.textContent = batchFiles.length;\n            batchFileCountDisplay.textContent = batchFiles.length;\n\n            files.forEach((file, index) => {\n                const reader = new FileReader();\n                reader.onload = (e) => {\n                    const fileItem = document.createElement('div');\n                    fileItem.className = 'file-item';\n                    fileItem.dataset.index = index;\n                    fileItem.innerHTML = `\n                                <div class=\"file-info\">\n                                    <img decoding=\"async\" src=\"${e.target.result}\" class=\"file-thumb\" alt=\"${file.name}\">\n                                    <span class=\"file-name\" title=\"${file.name}\">${file.name}<\/span>\n                                <\/div>\n                                <div class=\"file-status\" id=\"batch-status-${index}\">Pending<\/div>\n                            `;\n                    batchFilesList.appendChild(fileItem);\n                };\n                reader.readAsDataURL(file);\n            });\n\n            if (batchFiles.length > 0) {\n                batchFilesContainer.style.display = 'block';\n                batchCompressBtn.style.display = 'block';\n                compressBtn.style.display = 'none';\n                downloadZipBtn.style.display = 'none';\n                singleFileContainer.style.display = 'none';\n                batchFileCountDisplay.textContent = batchFiles.length;\n            } else {\n                batchFilesContainer.style.display = 'none';\n                batchCompressBtn.style.display = 'none';\n                compressBtn.style.display = 'block';\n            }\n            updateModeUI();\n        }\n\n        \/\/ \u2500\u2500\u2500 mode UI toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        function updateModeUI() {\n            const isBatch = batchMode.checked;\n            \/\/ toggle content\n            singlePreviewContent.style.display = isBatch ? 'none' : 'block';\n            batchPreviewContent.style.display = isBatch ? 'block' : 'none';\n\n            \/\/ badge\n            modeBadge.textContent = isBatch ? 'Batch' : 'Single';\n            modeBadge.className = 'mode-badge ' + (isBatch ? 'batch' : 'single');\n\n            \/\/ compress button in options\n            compressBtn.style.display = isBatch ? 'none' : 'block';\n\n            \/\/ batch compress button\n            batchCompressBtn.style.display = (isBatch && batchFiles.length > 0) ? 'block' : 'none';\n\n            \/\/ download zip button\n            if (!isBatch) downloadZipBtn.style.display = 'none';\n\n            \/\/ if batch has files, show count\n            if (isBatch && batchFiles.length > 0) {\n                batchFileCountDisplay.textContent = batchFiles.length;\n            } else if (isBatch) {\n                batchFileCountDisplay.textContent = '0';\n            }\n\n            \/\/ hide batch loading\/inline messages when switching\n            batchLoadingInline.style.display = 'none';\n            hideMessage(batchSuccessInline);\n            hideMessage(batchWarningInline);\n        }\n\n        \/\/ \u2500\u2500\u2500 toggle batch mode \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        function toggleBatchMode() {\n            if (batchMode.checked) {\n                fileInput.setAttribute('multiple', 'multiple');\n                \/\/ if we have single image loaded, clear it\n                if (originalImage && batchFiles.length === 0) {\n                    resetImage();\n                }\n                \/\/ show batch container if files exist\n                if (batchFiles.length > 0) {\n                    batchFilesContainer.style.display = 'block';\n                    batchCompressBtn.style.display = 'block';\n                    batchFileCountDisplay.textContent = batchFiles.length;\n                } else {\n                    batchFilesContainer.style.display = 'none';\n                    batchCompressBtn.style.display = 'none';\n                }\n                compressBtn.style.display = 'none';\n                downloadBtn.style.display = 'none';\n                downloadZipBtn.style.display = 'none';\n                singleFileContainer.style.display = 'none';\n            } else {\n                fileInput.removeAttribute('multiple');\n                batchFilesContainer.style.display = 'none';\n                batchCompressBtn.style.display = 'none';\n                compressBtn.style.display = 'block';\n                downloadBtn.style.display = 'inline-flex';\n                downloadZipBtn.style.display = 'none';\n                \/\/ if we have batch files, take first as single\n                if (batchFiles.length > 0) {\n                    processSingleFile(batchFiles[0]);\n                    batchFiles = [];\n                    batchCompressedResults = [];\n                    batchFilesList.innerHTML = '';\n                    batchCount.textContent = '0';\n                    batchFileCountDisplay.textContent = '0';\n                } else {\n                    resetImage();\n                }\n            }\n            updateModeUI();\n        }\n\n        \/\/ \u2500\u2500\u2500 reset \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        function resetImage() {\n            fileInput.value = '';\n            originalPreview.src =\n                'data:image\/svg+xml,%3Csvg xmlns=\\'http:\/\/www.w3.org\/2000\/svg\\' width=\\'400\\' height=\\'200\\' viewBox=\\'0 0 400 200\\'%3E%3Crect width=\\'400\\' height=\\'200\\' fill=\\'%23f8f9fa\\'\/%3E%3Cpath d=\\'M150 100 L200 70 L250 100 L300 50\\' stroke=\\'%234a6fa5\\' stroke-width=\\'4\\' fill=\\'none\\'\/%3E%3Ccircle cx=\\'150\\' cy=\\'100\\' r=\\'10\\' fill=\\'%235d8a82\\'\/%3E%3Ccircle cx=\\'200\\' cy=\\'70\\' r=\\'10\\' fill=\\'%235d8a82\\'\/%3E%3Ccircle cx=\\'250\\' cy=\\'100\\' r=\\'10\\' fill=\\'%235d8a82\\'\/%3E%3Ccircle cx=\\'300\\' cy=\\'50\\' r=\\'10\\' fill=\\'%235d8a82\\'\/%3E%3C\/svg%3E';\n            compressedPreview.src =\n                'data:image\/svg+xml,%3Csvg xmlns=\\'http:\/\/www.w3.org\/2000\/svg\\' width=\\'400\\' height=\\'200\\' viewBox=\\'0 0 400 200\\'%3E%3Crect width=\\'400\\' height=\\'200\\' fill=\\'%23f8f9fa\\'\/%3E%3Cpath d=\\'M150 100 L200 70 L250 100 L300 50\\' stroke=\\'%234a6fa5\\' stroke-width=\\'4\\' fill=\\'none\\'\/%3E%3Ccircle cx=\\'150\\' cy=\\'100\\' r=\\'10\\' fill=\\'%235d8a82\\'\/%3E%3Ccircle cx=\\'200\\' cy=\\'70\\' r=\\'10\\' fill=\\'%235d8a82\\'\/%3E%3Ccircle cx=\\'250\\' cy=\\'100\\' r=\\'10\\' fill=\\'%235d8a82\\'\/%3E%3Ccircle cx=\\'300\\' cy=\\'50\\' r=\\'10\\' fill=\\'%235d8a82\\'\/%3E%3C\/svg%3E';\n            originalSize.textContent = '0 KB';\n            originalDimensions.textContent = '0 x 0';\n            originalType.textContent = '-';\n            compressedSize.textContent = '0 KB';\n            compressedDimensions.textContent = '0 x 0';\n            compressedType.textContent = '-';\n            sizeReduction.textContent = '0%';\n            originalImage = null;\n            compressedImageData = null;\n            compressBtn.disabled = true;\n            downloadBtn.disabled = true;\n            hideMessage(uploadError);\n            hideMessage(uploadWarning);\n            hideMessage(compressionSuccess);\n            exifContainer.style.display = 'none';\n            singleFileContainer.style.display = 'none';\n            batchFilesContainer.style.display = 'none';\n            batchCompressBtn.style.display = 'none';\n            downloadZipBtn.style.display = 'none';\n            compressBtn.style.display = 'block';\n            batchFiles = [];\n            batchCompressedResults = [];\n            batchFilesList.innerHTML = '';\n            batchCount.textContent = '0';\n            batchFileCountDisplay.textContent = '0';\n            hideMessage(batchSuccessInline);\n            hideMessage(batchWarningInline);\n            batchLoadingInline.style.display = 'none';\n            updateModeUI();\n        }\n\n        function resetAll() {\n            resetImage();\n            outputFormat.value = 'jpeg';\n            updateFormatInfo();\n            resizeType.value = 'percentage';\n            handleResizeTypeChange();\n            resizeValue.value = '50';\n            pixelWidth.value = '';\n            pixelHeight.value = '';\n            cmWidth.value = '';\n            cmHeight.value = '';\n            inchWidth.value = '';\n            inchHeight.value = '';\n            preserveAspect.checked = true;\n            dpiValue.value = '96';\n            quality.value = '80';\n            updateQualityValue();\n            batchMode.checked = true;\n            toggleBatchMode();\n            batchFilesList.innerHTML = '';\n            batchFiles = [];\n            batchCompressedResults = [];\n            downloadZipBtn.style.display = 'none';\n            singleFileContainer.style.display = 'none';\n            batchFileCountDisplay.textContent = '0';\n            updateModeUI();\n        }\n\n        \/\/ \u2500\u2500\u2500 compress single \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        async function compressSingle() {\n            if (!originalImage) {\n                showMessage(uploadError, 'Please upload an image first');\n                return;\n            }\n            compressionLoading.style.display = 'block';\n            progressStep.textContent = 'Compressing...';\n            compressionProgress.value = 30;\n\n            const settings = {\n                resizeType: resizeType.value,\n                resizeValue: resizeValue.value,\n                pixelWidth: pixelWidth.value,\n                pixelHeight: pixelHeight.value,\n                cmWidth: cmWidth.value,\n                cmHeight: cmHeight.value,\n                inchWidth: inchWidth.value,\n                inchHeight: inchHeight.value,\n                preserveAspect: preserveAspect.checked,\n                dpiValue: dpiValue.value,\n                outputFormat: outputFormat.value,\n                quality: quality.value\n            };\n\n            try {\n                const result = await compressImageFromElement(originalImage, settings, 'image');\n                compressedImageData = result;\n                const url = URL.createObjectURL(result.blob);\n                compressedPreview.src = url;\n                compressedDimensions.textContent = `${result.width} x ${result.height}`;\n                compressedSize.textContent = formatFileSize(result.size);\n                compressedType.textContent = result.type.toUpperCase();\n                const reduction = Math.round((1 - (result.size \/ originalImageData.size)) * 100);\n                sizeReduction.textContent = `${reduction}%`;\n                downloadBtn.disabled = false;\n                showMessage(compressionSuccess, `Image compressed! Size reduced by ${reduction}%`);\n                compressionLoading.style.display = 'none';\n                compressionProgress.value = 100;\n                addToHistory(originalImageData, result);\n            } catch (error) {\n                console.error(error);\n                showMessage(uploadError, 'Compression failed: ' + error.message);\n                compressionLoading.style.display = 'none';\n            }\n        }\n\n        function downloadSingle() {\n            if (!compressedImageData) return;\n            const a = document.createElement('a');\n            a.href = URL.createObjectURL(compressedImageData.blob);\n            a.download = `compressed-image.${compressedImageData.type}`;\n            document.body.appendChild(a);\n            a.click();\n            document.body.removeChild(a);\n            URL.revokeObjectURL(a.href);\n        }\n\n        \/\/ \u2500\u2500\u2500 compress batch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        async function compressBatch() {\n            if (batchFiles.length === 0) {\n                showMessage(batchWarningInline, 'No images to process.');\n                return;\n            }\n\n            batchCompressBtn.disabled = true;\n            downloadZipBtn.style.display = 'none';\n            batchLoadingInline.style.display = 'block';\n            batchProgressTotalInline.textContent = batchFiles.length;\n            batchProgressCurrentInline.textContent = '0';\n            batchProgressInline.value = 0;\n            hideMessage(batchWarningInline);\n            hideMessage(batchSuccessInline);\n\n            const settings = {\n                resizeType: resizeType.value,\n                resizeValue: resizeValue.value,\n                pixelWidth: pixelWidth.value,\n                pixelHeight: pixelHeight.value,\n                cmWidth: cmWidth.value,\n                cmHeight: cmHeight.value,\n                inchWidth: inchWidth.value,\n                inchHeight: inchHeight.value,\n                preserveAspect: preserveAspect.checked,\n                dpiValue: dpiValue.value,\n                outputFormat: outputFormat.value,\n                quality: quality.value\n            };\n\n            batchCompressedResults = [];\n            let successCount = 0;\n\n            for (let i = 0; i < batchFiles.length; i++) {\n                const file = batchFiles[i];\n                const statusEl = document.getElementById(`batch-status-${i}`);\n                if (statusEl) statusEl.textContent = 'Processing';\n\n                try {\n                    const res = await compressImageFile(file, settings);\n                    batchCompressedResults.push(res);\n                    if (statusEl) {\n                        statusEl.textContent = 'Done';\n                        statusEl.classList.add('success');\n                    }\n                    successCount++;\n                } catch (err) {\n                    console.error(err);\n                    if (statusEl) {\n                        statusEl.textContent = 'Error';\n                        statusEl.classList.add('error');\n                    }\n                }\n                batchProgressCurrentInline.textContent = i + 1;\n                batchProgressInline.value = ((i + 1) \/ batchFiles.length) * 100;\n            }\n\n            batchLoadingInline.style.display = 'none';\n            batchCompressBtn.disabled = false;\n\n            if (batchCompressedResults.length > 0) {\n                downloadZipBtn.style.display = 'block';\n                showMessage(batchSuccessInline, `Compressed ${successCount} of ${batchFiles.length} images.`);\n            } else {\n                showMessage(batchWarningInline, 'No images could be compressed.');\n            }\n        }\n\n        function downloadZip() {\n            if (batchCompressedResults.length === 0) return;\n            const zip = new JSZip();\n            batchCompressedResults.forEach((item, idx) => {\n                const ext = outputFormat.value;\n                const base = item.filename.substring(0, item.filename.lastIndexOf('.')) || `image_${idx + 1}`;\n                zip.file(`${base}_compressed.${ext}`, item.blob);\n            });\n            zip.generateAsync({ type: 'blob' }).then(content => {\n                const a = document.createElement('a');\n                a.href = URL.createObjectURL(content);\n                a.download = `compressed_images_${Date.now()}.zip`;\n                document.body.appendChild(a);\n                a.click();\n                document.body.removeChild(a);\n                URL.revokeObjectURL(a.href);\n            });\n        }\n\n        \/\/ \u2500\u2500\u2500 history \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        function addToHistory(orig, comp) {\n            const item = {\n                original: { width: orig.width, height: orig.height, size: orig.size },\n                compressed: { width: comp.width, height: comp.height, size: comp.size },\n                timestamp: Date.now(),\n                reduction: Math.round((1 - comp.size \/ orig.size) * 100)\n            };\n            compressionHistory.unshift(item);\n            if (compressionHistory.length > 5) compressionHistory.pop();\n            localStorage.setItem('compressionHistory', JSON.stringify(compressionHistory));\n            updateHistoryDisplay();\n        }\n\n        function loadHistory() {\n            const saved = localStorage.getItem('compressionHistory');\n            if (saved) {\n                compressionHistory = JSON.parse(saved);\n                updateHistoryDisplay();\n            }\n        }\n\n        function updateHistoryDisplay() {\n            if (compressionHistory.length === 0) {\n                historyPanel.style.display = 'none';\n                return;\n            }\n            historyPanel.style.display = 'block';\n            historyList.innerHTML = '';\n            compressionHistory.forEach(item => {\n                const div = document.createElement('div');\n                div.className = 'history-item';\n                div.innerHTML = `\n                            <div class=\"history-info\">\n                                <img decoding=\"async\" src=\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='30' height='30' viewBox='0 0 30 30'%3E%3Crect width='30' height='30' fill='%23f8f9fa'\/%3E%3Cpath d='M10 15 L15 10 L20 15 L25 5' stroke='%234a6fa5' stroke-width='2' fill='none'\/%3E%3Ccircle cx='10' cy='15' r='2' fill='%235d8a82'\/%3E%3Ccircle cx='15' cy='10' r='2' fill='%235d8a82'\/%3E%3Ccircle cx='20' cy='15' r='2' fill='%235d8a82'\/%3E%3Ccircle cx='25' cy='5' r='2' fill='%235d8a82'\/%3E%3C\/svg%3E\" class=\"history-thumb\">\n                                <div>\n                                    <div>${item.original.width}x${item.original.height} \u2192 ${item.compressed.width}x${item.compressed.height}<\/div>\n                                    <div style=\"font-size:0.8rem;color:var(--success);\">${item.reduction}% reduction<\/div>\n                                <\/div>\n                            <\/div>\n                            <div style=\"font-size:0.8rem;\">${new Date(item.timestamp).toLocaleTimeString()}<\/div>\n                        `;\n                div.addEventListener('click', () => alert('History item clicked \u2013 would reload settings.'));\n                historyList.appendChild(div);\n            });\n        }\n\n        \/\/ \u2500\u2500\u2500 EXIF \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        function extractEXIFData(file) {\n            exifContainer.style.display = 'none';\n            exifTable.innerHTML = '';\n            const data = {\n                'Make': 'Camera Manufacturer',\n                'Model': 'Camera Model',\n                'Date': new Date(file.lastModified).toLocaleString(),\n                'Resolution': `${originalImageData.width} x ${originalImageData.height}`,\n                'File Size': formatFileSize(file.size)\n            };\n            exifContainer.style.display = 'block';\n            for (const key in data) {\n                const row = document.createElement('tr');\n                row.innerHTML = `<td>${key}<\/td><td>${data[key]}<\/td>`;\n                exifTable.appendChild(row);\n            }\n        }\n\n        \/\/ \u2500\u2500\u2500 UI helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        function handleResizeTypeChange() {\n            const type = resizeType.value;\n            document.getElementById('percentageInput').style.display = 'none';\n            document.getElementById('pixelInputs').style.display = 'none';\n            document.getElementById('cmInputs').style.display = 'none';\n            document.getElementById('inchInputs').style.display = 'none';\n            document.getElementById('aspectRatioContainer').style.display = 'none';\n            document.getElementById('dpiContainer').style.display = 'none';\n\n            if (type === 'percentage') document.getElementById('percentageInput').style.display = 'block';\n            else if (type === 'pixel') {\n                document.getElementById('pixelInputs').style.display = 'flex';\n                document.getElementById('aspectRatioContainer').style.display = 'flex';\n            } else if (type === 'cm' || type === 'inches') {\n                if (type === 'cm') document.getElementById('cmInputs').style.display = 'flex';\n                else document.getElementById('inchInputs').style.display = 'flex';\n                document.getElementById('aspectRatioContainer').style.display = 'flex';\n                document.getElementById('dpiContainer').style.display = 'block';\n            }\n        }\n\n        function updateFormatInfo() {\n            const f = outputFormat.value;\n            const map = {\n                'jpeg': '<strong>JPEG<\/strong>: Best for photographs, smaller file size',\n                'png': '<strong>PNG<\/strong>: Lossless format, supports transparency',\n                'webp': '<strong>WEBP<\/strong>: Modern format, excellent compression',\n                'bmp': '<strong>BMP<\/strong>: Uncompressed format (may fallback to PNG)',\n                'tiff': '<strong>TIFF<\/strong>: High quality (may fallback to PNG)'\n            };\n            formatInfo.innerHTML = map[f] || '';\n        }\n\n        function updateQualityValue() {\n            qualityValue.textContent = quality.value + '%';\n        }\n\n        function applyPreset(e) {\n            const p = e.target.dataset.preset;\n            if (p === 'web') { resizeType.value = 'pixel';\n                handleResizeTypeChange();\n                dpiValue.value = '72';\n                quality.value = '75';\n                updateQualityValue(); } else if (p === 'print') { resizeType.value = 'inches';\n                handleResizeTypeChange();\n                dpiValue.value = '300';\n                quality.value = '95';\n                updateQualityValue(); } else if (p === 'social') { resizeType.value = 'pixel';\n                handleResizeTypeChange();\n                pixelWidth.value = '1080';\n                preserveAspect.checked = true;\n                quality.value = '85';\n                updateQualityValue(); } else if (p === 'email') { resizeType.value = 'percentage';\n                handleResizeTypeChange();\n                resizeValue.value = '50';\n                quality.value = '70';\n                updateQualityValue(); }\n        }\n\n        function handleDimensionChange(type) {\n            if (!preserveAspect.checked || !originalImage) return;\n            const ratio = originalImage.width \/ originalImage.height;\n            let wInput, hInput;\n            if (type === 'pixel') { wInput = pixelWidth;\n                hInput = pixelHeight; } else if (type === 'cm') { wInput = cmWidth;\n                hInput = cmHeight; } else { wInput = inchWidth;\n                hInput = inchHeight; }\n            const active = document.activeElement;\n            if (active === wInput && wInput.value) {\n                if (type === 'pixel') hInput.value = Math.round(wInput.value \/ ratio);\n                else hInput.value = (wInput.value \/ ratio).toFixed(1);\n            } else if (active === hInput && hInput.value) {\n                if (type === 'pixel') wInput.value = Math.round(hInput.value * ratio);\n                else wInput.value = (hInput.value * ratio).toFixed(1);\n            }\n        }\n\n        \/\/ \u2500\u2500\u2500 drag & drop \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        function handleDragOver(e) { e.preventDefault();\n            dropArea.classList.add('active'); }\n\n        function handleDragLeave(e) { e.preventDefault();\n            dropArea.classList.remove('active'); }\n\n        function handleDrop(e) {\n            e.preventDefault();\n            dropArea.classList.remove('active');\n            if (e.dataTransfer.files.length) {\n                fileInput.files = e.dataTransfer.files;\n                handleFileSelect();\n            }\n        }\n\n        \/\/ \u2500\u2500\u2500 event binding \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        browseBtn.addEventListener('click', () => fileInput.click());\n        fileInput.addEventListener('change', handleFileSelect);\n        dropArea.addEventListener('dragover', handleDragOver);\n        dropArea.addEventListener('dragleave', handleDragLeave);\n        dropArea.addEventListener('drop', handleDrop);\n        outputFormat.addEventListener('change', updateFormatInfo);\n        resizeType.addEventListener('change', handleResizeTypeChange);\n        quality.addEventListener('input', updateQualityValue);\n        compressBtn.addEventListener('click', compressSingle);\n        downloadBtn.addEventListener('click', downloadSingle);\n        newImageBtn.addEventListener('click', resetImage);\n        resetBtn.addEventListener('click', resetAll);\n        batchMode.addEventListener('change', toggleBatchMode);\n        batchCompressBtn.addEventListener('click', compressBatch);\n        downloadZipBtn.addEventListener('click', downloadZip);\n        presetButtons.forEach(btn => btn.addEventListener('click', applyPreset));\n\n        pixelWidth.addEventListener('input', () => handleDimensionChange('pixel'));\n        pixelHeight.addEventListener('input', () => handleDimensionChange('pixel'));\n        cmWidth.addEventListener('input', () => handleDimensionChange('cm'));\n        cmHeight.addEventListener('input', () => handleDimensionChange('cm'));\n        inchWidth.addEventListener('input', () => handleDimensionChange('inches'));\n        inchHeight.addEventListener('input', () => handleDimensionChange('inches'));\n\n        \/\/ \u2500\u2500\u2500 init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n        document.getElementById('currentYear').textContent = new Date().getFullYear();\n        updateFormatInfo();\n        updateQualityValue();\n        handleResizeTypeChange();\n        loadHistory();\n\n        \/\/ default: batch mode ON\n        batchMode.checked = true;\n        toggleBatchMode();\n        updateModeUI();\n    <\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Reduce Image Resolution Reduce Image Resolution Compress and resize your images online without losing quality. Support for multiple output formats, batch processing, and advanced editing options. Upload Image Drag &#038; Drop your image here OR Browse Files Enable batch processing (up to 50 images) BULK Selected Files (0) Selected File Output Settings Output Format JPEGPNGWEBPBMPTIFF [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-16","page","type-page","status-publish","hentry"],"blocksy_meta":[],"_links":{"self":[{"href":"https:\/\/reduceimageresolution.com\/index.php?rest_route=\/wp\/v2\/pages\/16","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/reduceimageresolution.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/reduceimageresolution.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/reduceimageresolution.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/reduceimageresolution.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=16"}],"version-history":[{"count":2,"href":"https:\/\/reduceimageresolution.com\/index.php?rest_route=\/wp\/v2\/pages\/16\/revisions"}],"predecessor-version":[{"id":20,"href":"https:\/\/reduceimageresolution.com\/index.php?rest_route=\/wp\/v2\/pages\/16\/revisions\/20"}],"wp:attachment":[{"href":"https:\/\/reduceimageresolution.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=16"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}