Checked on the latest main. The automated check is office/layout.test.mjs. It passed with no remaining issues.
/admin/login and /admin/register, plus the owner token screen after generating a token.position: fixed inside a sticky header, so opening it left the links invisible or stuck at visibility: hidden / opacity: 0. Opening the menu now takes the header out of sticky positioning and paints a full-screen menu. The close button stays above the menu.No overlapping text, no horizontal page scroll, no clipped text, no broken images, and no console errors remained after those fixes.
Full-page screenshots are in /opt/cursor/artifacts/qa/.
webkit_390_<page>.pngchromium_1440_<page>.pngwebkit_390_login.png, chromium_1440_login.pngwebkit_390_register.png, chromium_1440_register.pngwebkit_390_token.png, chromium_1440_token.pngDone. Every public image slot is editable from Site Photos (/admin/photos) by the owner only. The nav entry is hidden from admins. GET, upload/replace, and reset under /admin/photos return 403 for an admin session and for an anonymous visitor, including when the admin posts a valid CSRF token. The owner can open the page and save a change.
The inventory is linkPhotoSlots() in office/photos.test.mjs (“every public image slot maps to an editable setting”). It walks every public template for <img>, {% photo %}, and CSS url() backgrounds, and it fails if a slot has no default image. The current inventory is 131 slots, 0 unmapped. Pages: Brand (logo, favicon, share image), Home (hero, inset, features, letters, closing backdrop), Weddings, Parties, Corporate, Packages, service cards, Portfolio (including the gallery contact sheet and stories), About (including the team portrait), Journal (cards, lead, covers, share images, inline images), Contact, testimonials, case study, thank-you, 404, privacy, terms, and photo credits.
Each slot has a preview, alt text, a focal-point crop (center, edges, and corners), a JPG/PNG/WebP upload under 8 MB, replace, and reset to the built-in photograph. Uploads are sniffed, resized with sharp, and stored on the disk at /var/data/uploads/site (beside OFFICE_DB). The public page picks up the replacement on the next request.
Empty frames fall back to an existing stock photograph (florals, a reception table, or evening lights) instead of rendering a blank box. The about-page team portrait keeps the garden ceremony as its stand-in and says so in the caption.
office/photos.test.mjs passed: 4 tests. The owner-only check is in that file. The photo editor screenshots below are Chromium at 1440px. The lean layout pass also opened /admin/photos as the owner.
d-photo-editor.pngd-photo-hero-slot.pngd-photo-hero-replaced.pngd-home-before.png (chapel ceremony)d-home-after.png (birthday balloons, new alt text, served from /uploads/site/home-hero.webp)