booked_slots previously recorded only (date, time), so availability
checking excluded an exact time match but not a real overlap — a
4-hour service booked at 9:00 AM didn't block 11:00 AM or 1:00 PM.
Add duration_minutes to booked_slots (populated by sync_booked_slot()
from the booked service's own duration) and switch client-side
computeAvailableSlots to a half-open-interval overlap check, also
rejecting candidates that wouldn't finish before closing time.
Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH