# Milestone 2 Spec — Interactive Map **Goal:** A `/map` page shows all entries as markers on an interactive Leaflet.js map, connected by a chronological route line, with popups linking to entries. --- ## User Stories - As a reader, I want to see a world map showing where Mischa has been so I can understand the journey at a glance without reading every entry. - As a reader, I want to click a map marker and see the entry date, title, and a thumbnail — and be able to click through to the full entry. - As a reader on mobile, I want to pan and pinch-zoom the map with my fingers without the page scrolling underneath. - As a traveler (Mischa), I want the map to automatically include every entry that has lat/lng data — I should not need to do any manual map maintenance. - As a reader, I want the map to show the route line connecting stops in the order they were visited, so the journey makes narrative sense. --- ## Feature Details ### 2.1 — Map Page **Route:** `/map` **Template:** `map.html.twig` — extends `partials/base.html.twig` **Page file:** `user/pages/03.map/map.md` **Content:** - Full-viewport-height map container below the site header - Leaflet.js loaded from CDN (jsDelivr): `https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.min.js` - Leaflet CSS from same CDN - Tile layer: OpenStreetMap (free, no API key): `https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png` - Attribution: "© OpenStreetMap contributors" **Map initialization:** - Default zoom: auto-fit to bounds of all markers (use `map.fitBounds()`) - If no entries with GPS data: show world view, zoom 2, centered at 0,0 with a message "No locations yet" - Min zoom: 2, Max zoom: 18 --- ### 2.2 — Entry Data Serialization **How entries reach the map JS:** In `map.html.twig`, Grav's Twig will iterate all published entries under `/tracker` and serialize them to a JSON array embedded in a `