    (function() {
        if (window.paintopsPhotoPickerWired) return;
        window.paintopsPhotoPickerWired = true;

        document.addEventListener('click', function(e) {
            var camBtn = e.target.closest ? e.target.closest('.pp-camera-btn') : null;
            var libBtn = e.target.closest ? e.target.closest('.pp-library-btn') : null;
            if (!camBtn && !libBtn) return;
            e.preventDefault();
            var picker = (camBtn || libBtn).closest('.paintops-photo-picker');
            if (!picker) return;
            var target = picker.querySelector(camBtn ? '.pp-camera-input' : '.pp-library-input');
            if (target) target.click();
        });

        document.addEventListener('change', function(e) {
            var input = e.target;
            if (!input.classList || (!input.classList.contains('pp-camera-input') && !input.classList.contains('pp-library-input'))) return;
            if (!input.files || !input.files[0]) return;

            var picker = input.closest('.paintops-photo-picker');
            if (!picker) return;
            var realInput = picker.querySelector('.pp-real-input');
            if (!realInput || typeof DataTransfer === 'undefined') return;

            var dt = new DataTransfer();
            dt.items.add(input.files[0]);
            realInput.files = dt.files;

            var nameEl = picker.querySelector('.pp-filename');
            if (nameEl) nameEl.textContent = input.files[0].name;

            // Setting .files programmatically doesn't fire a native change
            // event, dispatch one so anything already listening on the
            // real input (e.g. the compression script above, or the AI
            // Photo Estimate analyze button) reacts the same as if the
            // user had picked this file directly.
            realInput.dispatchEvent(new Event('change', { bubbles: true }));
        });
    })();
