- KnowledgeView: IntersectionObserver was watching the viewport instead
of the card-grid scroll container, causing infinite scroll to stop
loading after only ~29 items. Pass card-grid element as `root`.
- CalendarView: listen for 'fable:calendar-changed' custom event and
call refetchEvents() so tool-created events appear without navigation.
- ChatPanel: dispatch 'fable:calendar-changed' when create_event,
update_event, or delete_event tool calls succeed.
- tools.py: normalize naive datetimes to UTC before storing events so
timezone comparisons in list_events queries are always consistent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>