Performance:
- Add loading="lazy" decoding="async" to product card images
- Preconnect to Square S3 image CDN and fonts.googleapis.com in layout
- Cache-Control headers on catalog (20s), inventory (10s), occasions/categories (5min)
Scroll lock:
- Update useLockBodyScroll to use position:fixed + scroll-restore for iOS Safari
- Apply same fix to CartDrawer's inline scroll lock
Color names:
- Remove word-break:break-word so single words never split across lines;
multi-word names still wrap at spaces
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Balloon mask and color images correctly live at /color/images/ (served by
main site via nginx). Only the shine image path was wrong — it's at
/color/shine.svg, not /color/images/shine.svg. That missing file was the
actual cause of Safari showing ? placeholders. Previous commit incorrectly
moved everything to /color-picker/ which broke the CSS mask-image.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix vinyl add-on checkout: product line item was dropped when vinyl selected; entryUnitPrice also excluded base product price
- Store vinyl per-letter price on cart entry so CartDrawer charges the config price, not hardcoded 65¢
- Fix two bare modifiers.find() calls (use optional chaining) to prevent checkout crash on bad data
- Validate deliveryCents (must be non-negative integer) and customer name fields (no control chars) in checkout API
- Validate rateOverride values are non-negative numbers in delivery-quote API
- Add RFC 5545 iCalendar escaping to SUMMARY/LOCATION/DESCRIPTION fields to prevent calendar injection
- Add public /api/hours route; pickup and delivery calendars now fetch admin-saved hours and pre-grey closed days
- Reset delivery quote and slot when high-rate item is removed from cart
- Change delivery window copy from 2 hours to 1 hour (DeliveryDatePicker + terms page)
- Fix SVG paths: /color/images/ → /color-picker/images/ (balloon mask, shine, color backgrounds); was causing Safari ? placeholders
- Enlarge padlock icon in PaymentForm from 11px to 14px for better alignment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ColorPicker.tsx was constructing image URLs with the old /color-picker/
prefix. globals.css had the same for the balloon-mask.svg SVG mask.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>