No events on this day yet.
); } // Dynamic time range, clamped to 0–1440, min 8h window let rangeStart = 7 * 60; let rangeEnd = 22 * 60; if (timed.length > 0) { const starts = timed.map((e) => toMin(e.start_time!)); const ends = timed.map((e) => (e.end_time ? toMin(e.end_time) : toMin(e.start_time!) + 60)); rangeStart = Math.max(0, Math.floor(Math.min(...starts) / 60) * 60 - 60); rangeEnd = Math.min(24 * 60, Math.ceil(Math.max(...ends) / 60) * 60 + 60); if (rangeEnd - rangeStart < 8 * 60) rangeEnd = Math.min(24 * 60, rangeStart + 8 * 60); } const hours: number[] = []; for (let h = Math.ceil(rangeStart / 60); h <= Math.floor(rangeEnd / 60); h++) hours.push(h); const totalHeight = (rangeEnd - rangeStart) * PX_PER_MIN; const driveMap = new Map(driveSegments.map((s) => [s.fromId, s.text])); return ({e.title}
{height >= 44 && ({fmtTime(e.start_time)} {e.end_time ? ` – ${fmtTime(e.end_time)}` : ""} {isConflict ? " ⚠ conflict" : ""}
)} {height >= 60 && !e.location_inherited && e.location && ({e.location}
)} {height >= 60 && e.notes && ({e.notes}
)} {e.tags?.length > 0 && (Unscheduled
{untimed.map((e) => ({e.title}
{!e.location_inherited && e.location && ({e.location}
)} {e.notes &&{e.notes}
} {e.tags?.length > 0 && (Trip Assistant
Tell me what you want to do — I can search places and suggest events.
{children}
, ul: ({ children }) =>{s.title}
{fmtDate(s.date)} {s.start_time && ` · ${fmtTime(s.start_time)}`} {s.end_time && ` – ${fmtTime(s.end_time)}`}
)} {s.location &&{s.location}
} {s.notes &&{s.notes}
} {s.tags && s.tags.length > 0 && (Added to itinerary
)}Loading…
; if (!trip) returnTrip not found.
; const days = dateRange(trip.start_date, trip.end_date); const attendees = Object.values(trip.attendees ?? {}); const dayEvents = trip.events.filter((e) => e.date === selectedDay); const hasConflict = (day: string) => detectConflicts(trip.events.filter((e) => e.date === day)).size > 0; return ({fmtDayHeading(selectedDay)}