Session-gated login (a shared client password), image.php streams only when unlocked with ?download=1 support, .htaccess blocks direct access to the raw image, and generated favicon/OG/Twitter assets live in a public/ folder so crawlers can read meta without auth. Auto-regenerated previews with PHP/GD plus a one-click revert script.
Root cause was off-canvas #mobileMenu (left:-100%) plus translateX reveal blocks inflating scroll area. Fixed with overflow-x:hidden/clip, 100dvh mobile menu height, and a dedicated 2:3 (800×1200) hero asset replacing the cropped landscape image.