// Fake data layer — same shapes the real API will return. // Each stop: day, slot (mutual-exclusion group), state: planned | maybe | alt. // Only one `planned` stop per slot per day; `alt`/`maybe` don't count against // the day's time budget. // // Two demo cities: Florence (rich itinerary demo) and Boston (inside the // local OSRM extract, so legs are routed on the real road network — see // server.js /route proxy and app.js routeClient). ?city=florence|boston const FLORENCE = { trip: { id: 'trip-2026-09', version: 1, title: 'Florence 12–15 Sep', // stays, not a single hotel: {hotel, place, checkIn, checkOut, state}. // Days resolve their anchor per date; >1 candidate stay covering the // same nights → worst-case anchoring for those nights. // Multi-city trips = more stays, each anchoring its own dates. stays: [ { id: 'ST1', name: 'Hotel Palagio', at: [43.7684, 11.2566], place: 'Florence', checkIn: '2026-09-12', checkOut: '2026-09-15', state: 'booked', price: 180 }, ], places: [ { id: 'PL1', name: 'Florence', bbox: [43.73, 11.21, 43.80, 11.29], center: [43.769, 11.255], vibe: 'art + food, relaxed pace', dates: ['2026-09-12', '2026-09-15'] } ], bookings: [ { type: 'hotel', name: 'Hotel Palagio', ref: 'H-77821', dates: '12–15 Sep', where: [43.7684, 11.2566], status: 'booked', source: 'user_booking' }, { type: 'train', name: 'Frecciarossa 9512', ref: 'F-55812', from: 'Firenze SMN', to: 'Pisa Centrale', date: '2026-09-15', depart: '09:12', arrive: '09:58', status: 'booked', source: 'user_booking', stations: { from: [43.7726, 11.2597], to: [43.7157, 10.3922] } } ] }, days: [ { id: 'D1', date: '2026-09-12', label: 'Day 1 · Fri 12', startMin: 8 * 60, wakingHours: 11, base: { name: 'Hotel Palagio', at: [43.7684, 11.2566] }, legs: [], stops: [ { id: 'S1', name: 'Breakfast at the hotel', kind: 'meal', mealKind: 'breakfast', slot: 'breakfast', state: 'planned', at: [43.7684, 11.2566], dur: 30, durConf: 3, suggested: { value: 30, conf: 2, src: 'triptadvisor.com' } }, { id: 'S2', name: 'Palazzo Pitti', kind: 'visit', slot: 'visit', state: 'planned', url: 'https://www.palazzopittiturin.it', at: [43.7639, 11.2518], dur: 60, durConf: 5, // user override (sticky) suggested: { value: 150, conf: 2, src: 'wikivoyage.org' }, price: { amount: 14, cur: '€', conf: 2, src: 'uffizi.it' }, note: 'guides suggest 2–3 h', img: ['🏛️', 'Palazzo Pitti', 'linear-gradient(135deg,#b5533c,#7a3a2c)', 'https://thumb.wikimedia.org/wikipedia/commons/thumb/7/72/Palacio_Pitti%2C_Florencia%2C_Italia%2C_2022-09-18%2C_DD_197.jpg/1280px-Palacio_Pitti%2C_Florencia%2C_Italia%2C_2022-09-18%2C_DD_197.jpg'], detail: { summary: 'The Medici family’s riverside palazzo: the Galleria Palatina (Portraiture, the 500 Room) and the modern-art Galleria d’Arte Moderna. Rooms are small and crowded in peak season — the apartments alone run 1.5–2 h if you linger, ~1 h for the highlights. September afternoons are the sweet spot: light is good for photos and lines thin after 16:00.', links: [ { label: 'Official site', href: 'https://www.palazzopittiturin.it' }, { label: 'Tickets', href: 'https://www.uffizi.it/en/visit/tickets' }, { label: 'TripAdvisor', href: 'https://www.tripadvisor.com/Attraction_Review-g187791-d183726-Reviews-Palazzo_Pitti-Florence_Tuscany.html' }, { label: 'Reddit r/Florence', href: 'https://www.reddit.com/r/Florence/search/?q=palazzo+pitti&restrict_sr=1' } ] } }, { id: 'S4', name: 'Lunch — Trattoria Mario', kind: 'meal', mealKind: 'lunch', slot: 'lunch', state: 'planned', url: 'https://www.trattoriamario.it', at: [43.7667, 11.2544], dur: 45, durConf: 3, suggested: { value: 90, conf: 2, src: 'trattoriamario.it' }, price: { amount: 25, cur: '€', conf: 2, src: 'trattoriamario.it' }, img: ['🍝', 'Trattoria Mario', 'linear-gradient(135deg,#d08b3c,#9c5f1e)', 'https://upload.wikimedia.org/wikipedia/commons/1/12/Bistecca_alla_fiorentina-01.jpg'], detail: { summary: 'A no-frills Florentine kitchen on Via dei Neri, open since 1954. Counter seating, short menu (bistecca, lampredotto, tripe soup), and the queue is real — arriving as lunch opens (12:00) is the difference between 10 minutes and 40. Budget ~1 h including eating.', links: [ { label: 'Official site', href: 'https://www.trattoriamario.it' }, { label: 'Menu', href: 'https://www.trattoriamario.it/menu' }, { label: 'TripAdvisor', href: 'https://www.tripadvisor.com/Restaurant_Review-g187791-d310951-Reviews-Trattoria_Mario-Florence_Tuscany.html' }, { label: 'Reddit r/food', href: 'https://www.reddit.com/r/food/search/?q=trattoria+mario+florence&restrict_sr=1' } ] } }, { id: 'S5', name: 'Boboli Gardens', kind: 'visit', slot: 'visit', state: 'planned', url: 'https://www.boboli.it', at: [43.7579, 11.2463], dur: 120, durConf: 3, suggested: { value: 120, conf: 2, src: 'boboli.it' }, price: { amount: 10, cur: '€', conf: 2, src: 'uffizi.it' }, img: ['🌿', 'Boboli Gardens', 'linear-gradient(135deg,#4f9e63,#2c6b40)', 'https://thumb.wikimedia.org/wikipedia/commons/thumb/d/d2/Obelisco%2C_Boboli_Gardens%2C_Florence_%2826408174180%29.jpg/1280px-Obelisco%2C_Boboli_Gardens%2C_Florence_%2826408174180%29.jpg'], detail: { summary: 'The Medici’s formal garden behind Pitti — statues, the Apollo fountain, a hilltop view over the city. The full loop with the Accademia annex runs 2 h; the upper terraces alone are a fine 45-minute pace-break. Pairs naturally with Pitti: the entrance is the courtyard behind it.', links: [ { label: 'Official site', href: 'https://www.boboli.it' }, { label: 'Tickets', href: 'https://www.uffizi.it/en/visit/tickets' }, { label: 'TripAdvisor', href: 'https://www.tripadvisor.com/Attraction_Review-g187791-d183872-Reviews-Giardini_Di_Boboli-Florence_Tuscany.html' }, { label: 'Reddit r/Florence', href: 'https://www.reddit.com/r/Florence/search/?q=boboli&restrict_sr=1' } ] } }, { id: 'S6', name: 'Gelato — Vivoli', kind: 'meal', mealKind: 'snack', slot: 'snack', state: 'planned', at: [43.7680, 11.2537], dur: 20, durConf: 3, suggested: { value: 20, conf: 1, src: null }, price: null, img: ['🍦', 'Vivoli gelato', 'linear-gradient(135deg,#e0a5c0,#a56a92)'] }, { id: 'S7', name: 'Lunch — Ristorante Santini', kind: 'meal', mealKind: 'lunch', slot: 'lunch', state: 'alt', url: 'https://www.santini.it', at: [43.7646, 11.2528], dur: 75, durConf: 3, suggested: { value: 90, conf: 2, src: 'santini.it' }, price: { amount: 45, cur: '€', conf: 2, src: 'santini.it' }, img: ['🍷', 'Ristorante Santini', 'linear-gradient(135deg,#7a4a5c,#4c2b3a)', 'https://thumb.wikimedia.org/wikipedia/commons/thumb/c/c0/View_from_Giotto%27s_Bell_Tower_-_Florence.jpg/1280px-View_from_Giotto%27s_Bell_Tower_-_Florence.jpg'], detail: { summary: 'A classic Florentine restaurant in a 16th-century building on the Arno — the terrace looks across to Pitti. Set tables, longer menus, lunch from 12:30. The step-up option: worth holding if Mario’s queue looks long, or if the day goes well and you want to mark it.', links: [ { label: 'Official site', href: 'https://www.santini.it' }, { label: 'Menu', href: 'https://www.santini.it/en/menu' }, { label: 'TripAdvisor', href: 'https://www.tripadvisor.com/Restaurant_Review-g187791-d1442007-Reviews-Ristorante_Santini-Florence_Tuscany.html' }, { label: 'Reddit r/food', href: 'https://www.reddit.com/r/food/search/?q=santini+florence&restrict_sr=1' } ] } } ] }, { id: 'D2', date: '2026-09-13', label: 'Day 2 · Sat 13', startMin: 8 * 60 + 30, wakingHours: 11, base: { name: 'Hotel Palagio', at: [43.7684, 11.2566] }, legs: [], stops: [ { id: 'S8', name: 'Breakfast at the hotel', kind: 'meal', mealKind: 'breakfast', slot: 'breakfast', state: 'planned', at: [43.7684, 11.2566], dur: 30, durConf: 3, suggested: { value: 30, conf: 2, src: 'tripadvisor.com' } }, { id: 'S9', name: 'Galleria dell’Accademia (David)', kind: 'visit', slot: 'visit', state: 'planned', url: 'https://www.galleriaaccademia.firenze.it', at: [43.7734, 11.2628], dur: 90, durConf: 3, suggested: { value: 120, conf: 2, src: 'wikivoyage.org' }, price: { amount: 16, cur: '€', conf: 2, src: 'galleriaaccademia.firenze.it' }, img: ['🗿', 'Accademia', 'linear-gradient(135deg,#6b7280,#3f4650)'], detail: { summary: 'Home of the original David plus Donatello’s Prigione. Timed-entry tickets, and the David room moves in batches — a 09:30 slot is noticeably calmer than midday. Allow ~90 min; 2 h if you do the whole collection.', links: [ { label: 'Official site', href: 'https://www.galleriaaccademia.firenze.it' }, { label: 'Tickets', href: 'https://www.galleriaaccademia.firenze.it/en/tickets' }, { label: 'TripAdvisor', href: 'https://www.tripadvisor.com/Attraction_Review-g187791-d183692-Reviews-Galleria_dell_Accademia-Florence_Tuscany.html' }, { label: 'Reddit r/Florence', href: 'https://www.reddit.com/r/Florence/search/?q=accademia+david&restrict_sr=1' } ] } }, { id: 'S10', name: 'Lunch — Trattoria Sostanza', kind: 'meal', mealKind: 'lunch', slot: 'lunch', state: 'planned', url: 'https://www.sostanza.it', at: [43.7609, 11.2469], dur: 75, durConf: 3, suggested: { value: 90, conf: 2, src: 'tripadvisor.com' }, price: { amount: 35, cur: '€', conf: 2, src: 'tripadvisor.com' }, img: ['🍕', 'Trattoria Sostanza', 'linear-gradient(135deg,#b0563c,#7a3a2c)'], detail: { summary: 'Oltrarno kitchen a short walk across the Arno from the Accademia: Florentine classics, a proper wine list, and a roomy back — the kind of lunch that runs long. Reservations recommended on Saturdays.', links: [ { label: 'Official site', href: 'https://www.sostanza.it' }, { label: 'Menu', href: 'https://www.sostanza.it/menu' }, { label: 'TripAdvisor', href: 'https://www.tripadvisor.com/Restaurant_Review-g187791-d559983-Reviews-Trattoria_Sostanza-Florence_Tuscany.html' }, { label: 'Reddit r/food', href: 'https://www.reddit.com/r/food/search/?q=sostanza+florence&restrict_sr=1' } ] } }, { id: 'S11', name: 'Oltrarno stroll · San Niccolò', kind: 'visit', slot: 'visit', state: 'planned', at: [43.7613, 11.2497], dur: 60, durConf: 3, suggested: { value: 60, conf: 1, src: null }, price: null, img: ['⛪', 'Oltrarno', 'linear-gradient(135deg,#8f7a4f,#5c4d2e)'] } ] }, { id: 'D3', date: '2026-09-14', label: 'Day 3 · Sun 14', startMin: 9 * 60, wakingHours: 11, base: { name: 'Hotel Palagio', at: [43.7684, 11.2566] }, legs: [], stops: [ { id: 'S12', name: 'Breakfast at the hotel', kind: 'meal', mealKind: 'breakfast', slot: 'breakfast', state: 'planned', at: [43.7684, 11.2566], dur: 30, durConf: 3, suggested: { value: 30, conf: 2, src: 'tripadvisor.com' } }, { id: 'S13', name: 'San Marco & cloister', kind: 'visit', slot: 'visit', state: 'planned', at: [43.7723, 11.2597], dur: 45, durConf: 3, suggested: { value: 45, conf: 1, src: null }, price: { amount: 8, cur: '€', conf: 1, src: null }, img: ['🖼️', 'San Marco', 'linear-gradient(135deg,#7a6a4f,#4d422e)'] }, { id: 'S14', name: 'Aperitivo — Il Latte', kind: 'meal', mealKind: 'dinner', slot: 'dinner', state: 'maybe', url: 'https://www.illatte.it', at: [43.7700, 11.2560], dur: 60, durConf: 3, suggested: { value: 60, conf: 1, src: null }, price: { amount: 12, cur: '€', conf: 2, src: 'tripadvisor.com' }, img: ['🥂', 'Il Latte', 'linear-gradient(135deg,#c9a13c,#8f6f1e)'] } ] }, { id: 'D4', date: '2026-09-15', label: 'Day 4 · Mon 15', isDeparture: true, startMin: 8 * 60, wakingHours: 11, base: { name: 'Hotel Palagio', at: [43.7684, 11.2566] }, legs: [], stops: [ { id: 'S15', name: 'Breakfast & check-out', kind: 'meal', mealKind: 'breakfast', slot: 'breakfast', state: 'planned', at: [43.7684, 11.2566], dur: 30, durConf: 3, suggested: { value: 30, conf: 2, src: 'tripadvisor.com' } }, { id: 'S16', name: 'Train → Pisa Centrale', kind: 'transit', slot: 'transit', state: 'planned', at: [43.7726, 11.2597], dur: 30, durConf: 4, transit: { name: 'Frecciarossa 9512', ref: 'F-55812', from: 'Firenze SMN', to: 'Pisa Centrale', depart: '09:12', arrive: '09:58', arriveBy: '08:42', buffer: '30 min before departure' }, suggested: null, price: { amount: 45, cur: '€', conf: 4, src: 'booking' }, img: ['🚄', 'Frecciarossa 9512', 'linear-gradient(135deg,#274b8f,#16294d)'] } ] } ], // focus-mode candidate pools (what a slot search returns) candidates: { hotel: [ { id: 'H1', name: 'Hotel Palagio', at: [43.7684, 11.2566], price: 180, dur: null, tags: ['central', 'quiet', 'refundable'], pitch: 'Where you are now — refundable until the 8th.', url: null }, { id: 'H2', name: 'Hotel Savoy', at: [43.7726, 11.2565], price: 210, dur: null, tags: ['near SMN', 'grand', 'rooftop'], pitch: 'Grand hotel by the station — handy for the 15th, 10 min from the centre.', url: null }, { id: 'H3', name: 'Residenza Oltrarno', at: [43.7604, 11.2510], price: 140, dur: null, tags: ['oltrarno', 'small', 'value'], pitch: 'Six rooms above a bookshop — cheaper, and puts you on the south side.', url: null }, ], lunch: [ { id: 'C1', name: 'Trattoria Mario', at: [43.7667, 11.2544], price: 25, dur: 90, tags: ['counter', 'local', 'queue'], pitch: 'No-frills counter since 1954 — the queue is the point.', url: 'https://www.trattoriamario.it', img: ['🍝', 'Trattoria Mario', 'linear-gradient(135deg,#d08b3c,#9c5f1e)', 'https://upload.wikimedia.org/wikipedia/commons/1/12/Bistecca_alla_fiorentina-01.jpg'] }, { id: 'C2', name: 'Ristorante Santini', at: [43.7646, 11.2528], price: 45, dur: 90, tags: ['views', 'terrace', 'splurge'], pitch: '16th-century set tables on the Arno, terrace across from Pitti.', url: 'https://www.santini.it', img: ['🍷', 'Santini', 'linear-gradient(135deg,#7a4a5c,#4c2b3a)'] }, { id: 'C3', name: 'Trattoria Sostanza', at: [43.7609, 11.2469], price: 35, dur: 90, tags: ['oltrarno', 'roomy', 'wine'], pitch: 'Oltrarno kitchen, proper wine list, a roomy back — runs long.', url: 'https://www.sostanza.it', img: ['🍕', 'Sostanza', 'linear-gradient(135deg,#b0563c,#7a3a2c)'] }, { id: 'C4', name: 'Vendemmia', at: [43.7735, 11.2585], price: 30, dur: 75, tags: ['vegetarian', 'garden', 'near SMN'], pitch: 'Garden terrace by SMN, strong vegetarian menu, calmer pace.', url: 'https://www.vendemmia.it', img: ['🥗', 'Vendemmia', 'linear-gradient(135deg,#5f9e6b,#33613c)'] }, { id: 'C5', name: 'La Cantina di San Niccolò', at: [43.7615, 11.2490], price: 22, dur: 75, tags: ['cellar', 'cozy', 'oltrarno'], pitch: 'Stone cellar, candlelight, short honest menu — book ahead.', url: 'https://www.lacantina.it', img: ['🕯️', 'La Cantina', 'linear-gradient(135deg,#8f7a4f,#5c4d2e)'] }, { id: 'C6', name: 'Buonami Pizza', at: [43.7680, 11.2550], price: 15, dur: 45, tags: ['fast', 'casual', 'near hotel'], pitch: 'Two-stop, fast, good — the reset-button lunch.', url: 'https://www.buonami.it', img: ['🍕', 'Buonami', 'linear-gradient(135deg,#c98a2c,#8a5f1a)'] } ], visit: [ { id: 'V1', name: 'Piazzale Michelangelo', at: [43.7669, 11.2455], price: 0, dur: 60, tags: ['views', 'sunset', 'free'], pitch: 'The postcard view — best from 17:00 as the light warms.', url: 'https://en.wikipedia.org/wiki/Piazzale_Michelangelo', img: ['🌇', 'Piazzale Michelangelo', 'linear-gradient(135deg,#c97a3c,#8a4f1a)'] }, { id: 'V2', name: 'San Miniato al Monte', at: [43.7620, 11.2521], price: 4, dur: 60, tags: ['views', 'romanesque', 'calm'], pitch: 'Romanesque basilica on the hill — quiet, cool in the afternoon.', url: 'https://en.wikipedia.org/wiki/San_Miniato_al_Monte', img: ['⛪', 'San Miniato', 'linear-gradient(135deg,#8f9a7a,#5c644d)'] }, { id: 'V3', name: 'Santo Spirito square', at: [43.7603, 11.2496], price: 0, dur: 45, tags: ['square', 'lazier', 'market'], pitch: 'Oltrarno’s lazy square; Saturday’s market is the event.', url: 'https://en.wikipedia.org/wiki/Santo_Spirito,_Florence', img: ['☕', 'Santo Spirito', 'linear-gradient(135deg,#a58a6a,#6d5840)'] }, { id: 'V4', name: 'Terme di Caracalla (ruins)', at: [43.7589, 11.2707], price: 10, dur: 75, tags: ['ruins', 'open', 'afternoon'], pitch: 'Third-century baths in open fields — cool, empty, odd.', url: 'https://en.wikipedia.org/wiki/Baths_of_Caracalla', img: ['🏛️', 'Terme di Caracalla', 'linear-gradient(135deg,#b0a58a,#756a4f)'] } ] }, nudges: { D1: [ { id: 'N1', title: 'Lunch may be a little tight', body: '45 min at Trattoria Mario — a meal there usually runs ~90 min (web), and the local queue adds to that.', fix: { label: 'Extend to ~90 min', stop: 'S4', dur: 90, msg: 'Lunch extended to 90 min — everything after it slides later; the day still fits.' } }, { id: 'N2', title: 'Pitti: 1 h (you) vs ~2.5 h usually', body: 'Guides suggest 2–3 h for the full complex. We kept your 1 h — no need to change anything.', fix: { label: 'Keep as is' } } ], D2: [], D3: [ { id: 'N3', title: 'Dinner is still an idea', body: 'Il Latte is an option, not a plan — worth deciding by this evening so there’s a fallback if it’s full.', fix: { label: 'Keep as is' } } ] }, multimodal: [ { into: 'S5', dur: 18, sub: [{ mode: 'foot', dur: 6 }, { mode: 'tram', dur: 12 }] } ], vibes: [ { id: 'v1', label: 'art & food · relaxed pace' }, { id: 'v2', label: 'gardens & walking' }, { id: 'v3', label: 'day trip · Fiesole' }, { id: 'v4', label: 'views & aperitivo' } ], suggestions: [ { stop: 'S2', pitch: 'The Palazzo Medici’s private apartments — less crowded than the Uffizi, opens right at 9:30.', enrich: 'open 09:30–19:30 · skip-the-line available' }, { stop: 'S4', pitch: 'No-frills Florentine kitchen the locals queue for. Expect a wait without a reservation.', enrich: 'lunch 12:00–14:30 · dinner from 19:30 · ~1 h typically' }, { stop: 'S5', pitch: 'Renaissance gardens behind Pitti — a good pace-break in the heat; ~2 h is the sweet spot.', enrich: 'open 08:15–19:30 · last entry 18:15' }, { stop: 'S7', pitch: 'The step-up lunch: set tables on the Arno, terrace across from Pitti. Worth holding if Mario’s queue looks long.', enrich: 'lunch from 12:30 · book ahead in season' } ] }; // --------------------------------------------------------------------------- // Boston — same shapes, but INSIDE the local OSRM extract (NE-US), so the // routeClient upgrades legs to real road-network times + geometry. // --------------------------------------------------------------------------- const BOSTON = { trip: { id: 'trip-2026-09-b', version: 1, title: 'Boston 14–16 Sep', stays: [ { id: 'ST1', name: 'Hotel Commonwealth', at: [42.3495, -71.0960], place: 'Boston', checkIn: '2026-09-14', checkOut: '2026-09-16', state: 'booked', price: 165 }, ], places: [ { id: 'PL1', name: 'Boston', bbox: [42.33, -71.12, 42.375, -71.04], center: [42.357, -71.063], vibe: 'history + harbor, food-first', dates: ['2026-09-14', '2026-09-16'] } ], bookings: [ { type: 'hotel', name: 'Hotel Commonwealth', ref: 'H-55210', dates: '14–16 Sep', where: [42.3495, -71.0960], status: 'booked', source: 'user_booking' }, { type: 'train', name: 'Amtrak 700', ref: 'A-33421', from: 'Back Bay', to: 'Penn Station, NYC', date: '2026-09-16', depart: '17:00', arrive: '19:40', status: 'booked', source: 'user_booking', stations: { from: [42.3519, -71.0654], to: [40.7506, -73.9935] } } ] }, days: [ { id: 'D1', date: '2026-09-14', label: 'Day 1 · Mon 14', startMin: 8 * 60, wakingHours: 11, base: { name: 'Hotel Commonwealth', at: [42.3495, -71.0960] }, legs: [], stops: [ { id: 'S1', name: 'Breakfast at the hotel', kind: 'meal', mealKind: 'breakfast', slot: 'breakfast', state: 'planned', at: [42.3495, -71.0960], dur: 30, durConf: 3, suggested: { value: 30, conf: 2, src: 'tripadvisor.com' } }, { id: 'S2', name: 'Museum of Fine Arts', kind: 'visit', slot: 'visit', state: 'planned', url: 'https://www.mfa.org', at: [42.3394, -71.0949], dur: 120, durConf: 3, suggested: { value: 150, conf: 2, src: 'mfa.org' }, price: { amount: 25, cur: '$', conf: 2, src: 'mfa.org' }, img: ['🖼️', 'MFA Boston', 'linear-gradient(135deg,#7a4a5c,#4c2b3a)', 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/MFA%2C_Boston%2C_MA.jpg/1280px-MFA%2C_Boston%2C_MA.jpg'], detail: { summary: 'One of the largest art museums in the US, next to the hotel. The Impressionist wing and the Asian galleries are the anchors — allow 2 h for highlights, 3 h if you linger in the Japanese scroll wing. Thursday/Friday the light in the skylit atrium is the best.', links: [ { label: 'Official site', href: 'https://www.mfa.org' }, { label: 'Tickets', href: 'https://www.mfa.org/visit/tickets' }, { label: 'TripAdvisor', href: 'https://www.tripadvisor.com/Attraction_Review-g1146335-d183805-Reviews-Museum_of_Fine_Arts-Boston_MA.html' } ] } }, { id: 'S4', name: 'Lunch — State Street Fare', kind: 'meal', mealKind: 'lunch', slot: 'lunch', state: 'planned', url: 'https://www.statestreetfare.com', at: [42.3410, -71.0935], dur: 60, durConf: 3, suggested: { value: 75, conf: 2, src: 'statestreetfare.com' }, price: { amount: 30, cur: '$', conf: 2, src: 'statestreetfare.com' }, img: ['🍽️', 'State Street Fare', 'linear-gradient(135deg,#d08b3c,#9c5f1e)'], detail: { summary: 'The MFA’s own café with a garden terrace — New England seasonal plates. It’s the sensible choice after a museum morning; the terrace gets crowded by 13:00 on weekends.', links: [ { label: 'Official site', href: 'https://www.statestreetfare.com' }, { label: 'Menu', href: 'https://www.statestreetfare.com/menu' } ] } }, { id: 'S5', name: 'Boston Public Library (Coppa Wing)', kind: 'visit', slot: 'visit', state: 'planned', url: 'https://www.bpl.org', at: [42.3499, -71.0769], dur: 60, durConf: 3, suggested: { value: 60, conf: 2, src: 'bpl.org' }, price: { amount: 0, cur: '$', conf: 2, src: 'bpl.org' }, img: ['📚', 'BPL', 'linear-gradient(135deg,#5f7a4f,#3a4f2c)'], detail: { summary: 'The Beaux-Arts free reading room and the Domitian & Apollo statues in the courtyard. A good 45–60 min breather on the walk toward the North End — the architecture alone is worth it.', links: [ { label: 'Official site', href: 'https://www.bpl.org' } ] } }, { id: 'S6', name: 'Faneuil Hall & Quincy Market', kind: 'visit', slot: 'visit', state: 'planned', url: 'https://www.boston.gov/departments/parks/faneuil-hall', at: [42.3601, -71.0555], dur: 90, durConf: 3, suggested: { value: 90, conf: 2, src: 'boston.gov' }, price: null, img: ['🏛️', 'Faneuil Hall', 'linear-gradient(135deg,#b5533c,#7a3a2c)'], detail: { summary: 'The “Cradle of Liberty” and the covered food market. Best worked top-down: the market stalls first (clam chowder, lemonade), then the hall’s free exhibits. Weekends are busy — September afternoons are kinder.', links: [ { label: 'Official site', href: 'https://www.boston.gov/departments/parks/faneuil-hall' }, { label: 'Quincy Market', href: 'https://www.quincymarket.com' } ] } } ] }, { id: 'D2', date: '2026-09-15', label: 'Day 2 · Tue 15', startMin: 8 * 60 + 30, wakingHours: 11, base: { name: 'Hotel Commonwealth', at: [42.3495, -71.0960] }, legs: [], stops: [ { id: 'S8', name: 'Breakfast at the hotel', kind: 'meal', mealKind: 'breakfast', slot: 'breakfast', state: 'planned', at: [42.3495, -71.0960], dur: 30, durConf: 3, suggested: { value: 30, conf: 2, src: 'tripadvisor.com' } }, { id: 'S9', name: 'Paul Revere House', kind: 'visit', slot: 'visit', state: 'planned', url: 'https://www.boston.gov/departments/parks/paul-revere-house', at: [42.3616, -71.0631], dur: 45, durConf: 3, suggested: { value: 45, conf: 2, src: 'boston.gov' }, price: { amount: 10, cur: '$', conf: 2, src: 'boston.gov' }, img: ['🏠', 'Paul Revere House', 'linear-gradient(135deg,#8f7a4f,#5c4d2e)'], detail: { summary: 'The oldest house in Boston, a tight 30–45 min with the resident docent. Timed entry; the North End around it is the walk.', links: [ { label: 'Official site', href: 'https://www.boston.gov/departments/parks/paul-revere-house' } ] } }, { id: 'S10', name: 'Lunch — Union Oyster House', kind: 'meal', mealKind: 'lunch', slot: 'lunch', state: 'planned', url: 'https://www.unionoysterhouse.com', at: [42.3621, -71.0604], dur: 60, durConf: 3, suggested: { value: 75, conf: 2, src: 'unionoysterhouse.com' }, price: { amount: 40, cur: '$', conf: 2, src: 'unionoysterhouse.com' }, img: ['🦪', 'Union Oyster House', 'linear-gradient(135deg,#4f7a9e,#2c4f6b)'], detail: { summary: 'Claimed oldest restaurant in the US (1826). Clam chowder and a short, serious menu. Book ahead for the lunch hour — the room is small.', links: [ { label: 'Official site', href: 'https://www.unionoysterhouse.com' } ] } }, { id: 'S11', name: 'New England Aquarium', kind: 'visit', slot: 'visit', state: 'planned', url: 'https://neaq.org', at: [42.3598, -71.0483], dur: 120, durConf: 3, suggested: { value: 120, conf: 2, src: 'neaq.org' }, price: { amount: 35, cur: '$', conf: 2, src: 'neaq.org' }, img: ['🐋', 'NE Aquarium', 'linear-gradient(135deg,#2f6fd6,#1d4f9c)'], detail: { summary: 'The whale tank and the Harborwalk beyond it. September is a good time — the new whale migration is winding down but the penguin and jelly exhibits are year-round. Allow 2 h.', links: [ { label: 'Official site', href: 'https://neaq.org' } ] } } ] }, { id: 'D3', date: '2026-09-16', label: 'Day 3 · Wed 16', isDeparture: true, startMin: 8 * 60, wakingHours: 11, base: { name: 'Hotel Commonwealth', at: [42.3495, -71.0960] }, legs: [], stops: [ { id: 'S15', name: 'Breakfast & check-out', kind: 'meal', mealKind: 'breakfast', slot: 'breakfast', state: 'planned', at: [42.3495, -71.0960], dur: 30, durConf: 3, suggested: { value: 30, conf: 2, src: 'tripadvisor.com' } }, { id: 'S12', name: 'Boston Common & Public Garden', kind: 'visit', slot: 'visit', state: 'planned', at: [42.3547, -71.0717], dur: 45, durConf: 3, suggested: { value: 45, conf: 1, src: null }, price: null, img: ['🌳', 'Public Garden', 'linear-gradient(135deg,#4f9e63,#2c6b40)'] }, { id: 'S16', name: 'Train → Penn Station NYC', kind: 'transit', slot: 'transit', state: 'planned', at: [42.3519, -71.0654], dur: 30, durConf: 4, transit: { name: 'Amtrak 700', ref: 'A-33421', from: 'Back Bay', to: 'Penn Station, NYC', depart: '17:00', arrive: '19:40', arriveBy: '16:30', buffer: '30 min before departure' }, suggested: null, price: { amount: 65, cur: '$', conf: 4, src: 'booking' }, img: ['🚄', 'Amtrak 700', 'linear-gradient(135deg,#274b8f,#16294d)'] } ] } ], candidates: { hotel: [ { id: 'H1', name: 'Hotel Commonwealth', at: [42.3495, -71.0960], price: 165, dur: null, tags: ['by the mfa', 'quiet', 'refundable'], pitch: 'Where you are now — one block from the MFA, refundable until the 12th.', url: null }, { id: 'H2', name: 'The Liberty Hotel', at: [42.3580, -71.0530], price: 240, dur: null, tags: ['north end', 'rooftop', 'grand'], pitch: 'Rooftop bar over the North End — closer to the food, pricier.', url: null }, { id: 'H3', name: 'Haven Guest House', at: [42.3470, -71.0900], price: 120, dur: null, tags: ['value', 'small', 'near mfa'], pitch: 'Six rooms off the MFA’s garden — cheaper, a short walk to everything.', url: null } ], lunch: [ { id: 'C1', name: 'State Street Fare', at: [42.3410, -71.0935], price: 30, dur: 75, tags: ['by the mfa', 'garden', 'seasonal'], pitch: 'The MFA’s café — garden terrace, New England seasonal plates.', url: 'https://www.statestreetfare.com', img: ['🍽️', 'State Street Fare', 'linear-gradient(135deg,#d08b3c,#9c5f1e)'] }, { id: 'C2', name: 'Union Oyster House', at: [42.3621, -71.0604], price: 40, dur: 75, tags: ['historic', 'oysters', 'book ahead'], pitch: 'Claimed oldest restaurant in the US — clam chowder, a short serious menu.', url: 'https://www.unionoysterhouse.com', img: ['🦪', 'Union Oyster', 'linear-gradient(135deg,#4f7a9e,#2c4f6b)'] }, { id: 'C3', name: 'Eataly Boston', at: [42.3595, -71.0540], price: 35, dur: 60, tags: ['market', 'fast', 'central'], pitch: 'The food-hall option — a dozen kitchens, grab and go, by Quincy Market.', url: 'https://boston.eataly.net', img: ['🍕', 'Eataly', 'linear-gradient(135deg,#b0563c,#7a3a2c)'] }, { id: 'C4', name: 'Kazuo', at: [42.3540, -71.0620], price: 32, dur: 60, tags: ['japanese', 'counter', 'near the common'], pitch: 'Japanese counter near the Common — quiet, good, a little pricier.', url: 'https://kazooboston.com', img: ['🍣', 'Kazuo', 'linear-gradient(135deg,#5f6b7a,#3a434f)'] } ], visit: [ { id: 'V1', name: 'John F. Kennedy Presidential Library', at: [42.3599, -71.0590], price: 15, dur: 90, tags: ['history', 'harbor view', 'indoor'], pitch: 'The JFK archives with a harbor view — a good 90 min, indoor if it turns.', url: 'https://www.jfklibrary.org', img: ['🎙️', 'JFK Library', 'linear-gradient(135deg,#4a5a78,#2f3a50)'] }, { id: 'V2', name: 'Harborwalk', at: [42.3590, -71.0420], price: 0, dur: 60, tags: ['outdoor', 'harbor', 'walk'], pitch: 'The esplanade along the harbor — sunset is the point in September.', url: 'https://www.boston.gov/departments/parks/harborwalk', img: ['🌅', 'Harborwalk', 'linear-gradient(135deg,#c97a3c,#8a4f1a)'] }, { id: 'V3', name: 'T. F. Green Memorial', at: [42.3530, -71.0470], price: 0, dur: 45, tags: ['views', 'free', 'calm'], pitch: 'The memorial at the harbor’s edge — a quiet, photo-friendly 30–45 min.', url: 'https://www.boston.gov', img: ['⛵', 'T. F. Green', 'linear-gradient(135deg,#7a8a9e,#4f5a6b)'] }, { id: 'V4', name: 'Boston Tea Party Ships & Museum', at: [42.3555, -71.0535], price: 30, dur: 75, tags: ['history', 'interactive', 'harbor'], pitch: 'A 75-min interactive re-enactment on the harbor — fun, a little kitsch.', url: 'https://www.bostonteachallenge.org', img: ['🫖', 'Tea Party', 'linear-gradient(135deg,#8f4f4f,#5c2f2f)'] } ] }, nudges: { D1: [ { id: 'N1', title: 'Lunch may be a little tight', body: '60 min at State Street Fare — the terrace lunch usually runs ~75 min (web), and it crowds by 13:00.', fix: { label: 'Extend to ~75 min', stop: 'S4', dur: 75, msg: 'Lunch extended to 75 min — the afternoon slides a little later; the day still fits.' } }, { id: 'N2', title: 'MFA: 2 h (you) vs ~2.5 h usually', body: 'Guides suggest 2.5–3 h for the highlights. We kept your 2 h — the Impressionist wing alone runs that long.', fix: { label: 'Keep as is' } } ], D2: [ { id: 'N3', title: 'Union Oyster House at the lunch hour', body: 'The room is small and booked solid 12:00–13:30 — a 12:00 seat beats a 12:30 walk-in.', fix: { label: 'Keep as is' } } ], D3: [] }, multimodal: [], vibes: [ { id: 'v1', label: 'history & harbor · relaxed pace' }, { id: 'v2', label: 'museums & art' }, { id: 'v3', label: 'food-first, North End' }, { id: 'v4', label: 'views & sunset walk' } ], suggestions: [ { stop: 'S2', pitch: 'The MFA’s Impressionist wing and the Japanese scroll room — 2 h for highlights, 3 h if you linger.', enrich: 'open 10:00–17:00 · free first Thu 4–9 · one block from the hotel' }, { stop: 'S4', pitch: 'The MFA’s own café — the garden terrace gets crowded by 13:00 on weekends.', enrich: 'lunch 12:00–15:00 · ~1 h · terrace seats' }, { stop: 'S5', pitch: 'The Beaux-Arts free reading room and the courtyard’s Domitian & Apollo — a good breather toward the North End.', enrich: 'open 10:00–18:00 · free · ~45 min' }, { stop: 'S6', pitch: 'Work the market stalls first (chowder, lemonade), then the free hall exhibits — weekends are busy.', enrich: 'stalls 10:00–17:00 · hall free · ~90 min' } ] }; // pick the demo city from ?city= (default Florence) const _city = (new URLSearchParams(location.search).get('city') || 'florence').toLowerCase(); window.MOCK = _city === 'boston' ? BOSTON : FLORENCE; window.MOCK_CITY = _city;