    (function() {
        // Auto-submit helper for pickers created with $autosubmit (they carry
        // data-pp-autosubmit on the real input). Called only once the file is
        // final, AFTER compression has swapped in the resized image, so the
        // upload never races the resize. It clicks the form's own submit
        // button (rather than form.submit()) so the button's name reaches
        // $_POST, which every upload handler here keys off (e.g.
        // paintops_upload_before_photo). Guarded so it fires once per form.
        window.paintopsPhotoMaybeAutoSubmit = window.paintopsPhotoMaybeAutoSubmit || function(input) {
            if (!input || !input.getAttribute || input.getAttribute('data-pp-autosubmit') !== '1') return;
            var form = input.form || (input.closest ? input.closest('form') : null);
            if (!form || form.getAttribute('data-pp-submitting') === '1') return;
            form.setAttribute('data-pp-submitting', '1');
            var btn = form.querySelector('button[type="submit"], input[type="submit"]');
            if (btn) { btn.click(); } else { form.submit(); }
        };

        if (typeof DataTransfer === 'undefined' || typeof FileReader === 'undefined') return;

        document.addEventListener('change', function(e) {
            var input = e.target;
            if (!input.matches || !input.matches('input[type="file"].paintops-photo-input')) return;

            var file = input.files && input.files[0];
            if (!file) return;

            // Fires when the file is ready to upload (compressed if it could
            // be, original otherwise). Auto-submit hangs off this, never off
            // the raw pick, so it can never beat the resize to the server.
            function finish() { window.paintopsPhotoMaybeAutoSubmit(input); }

            if (!file.type || file.type.indexOf('image/') !== 0) { finish(); return; }

            var reader = new FileReader();
            reader.onload = function(ev) {
                var img = new Image();
                img.onload = function() {
                    var maxDim = 1600;
                    var w = img.width, h = img.height;
                    if (w > maxDim || h > maxDim) {
                        if (w >= h) { h = Math.round(h * (maxDim / w)); w = maxDim; }
                        else { w = Math.round(w * (maxDim / h)); h = maxDim; }
                    }
                    var canvas = document.createElement('canvas');
                    canvas.width = w;
                    canvas.height = h;
                    var ctx = canvas.getContext('2d');
                    if (!ctx) { finish(); return; }
                    ctx.drawImage(img, 0, 0, w, h);
                    canvas.toBlob(function(blob) {
                        if (blob) {
                            try {
                                var newName = file.name.replace(/\.[^.]+$/, '') + '.jpg';
                                var newFile = new File([blob], newName, { type: 'image/jpeg' });
                                var dt = new DataTransfer();
                                dt.items.add(newFile);
                                input.files = dt.files;
                            } catch (err) {
                                // Keep the original file if this browser can't
                                // construct File/DataTransfer objects.
                            }
                        }
                        finish();
                    }, 'image/jpeg', 0.82);
                };
                img.onerror = function() { finish(); };
                img.src = ev.target.result;
            };
            reader.onerror = function() { finish(); };
            reader.readAsDataURL(file);
        });
    })();
