Montalcino demo story had end_date: 2025-09-06 matching its start date,
causing a '06 – 06 Sep' range display. Removed from both the live page
and the demo source.
Template: added guard so end_date equal to the start date never renders
as a range, even if it appears in frontmatter.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Blueprint: end_date format changed from 'Y-m-d H:i' to 'Y-m-d' — the
demo frontmatter stores dates without a time component so Admin was
failing to parse it and showing the field empty.
Template: three-case smart range formatting:
- Same month & year → 01 – 03 Sep 2025
- Same year only → 01 Jan – 03 Sep 2025
- Different years → 01 Jan 2025 – 03 Feb 2026
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Blueprint: renamed 'Date' to 'Start Date', added optional 'End Date'
field (header.end_date) so it's editable in Admin.
Template: single date → 'd M Y'; range → 'd M Y – d M Y' (full year
on both sides — the old format silently dropped the start year).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Card background was rgba(26,24,20,0.92) — identical to the page background
(--color-paper #1A1814), making cards invisible. Changed to --color-canvas
(#22201B) for a lifted surface. Added border-left: 3px solid --color-accent
as an editorial marker; other three sides keep the subtle --color-border.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Replaced IntersectionObserver (discrete threshold) with a scroll RAF loop
using getBoundingClientRect. Opacity is computed from the fraction of
.story-hero__content still visible above the viewport top — so the nav title
fades in gradually as the hero title slides off the top edge, reaching full
opacity only when the element is completely gone.
Removed CSS transition (no longer needed; per-frame JS update is smooth).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Was visible on load because story-hero__content starts below the
viewport fold (bottom:18% of 140vh hero) — IO fired immediately
as 'not intersecting'. Fixed with hasBeenVisible flag: nav title
only appears after the element has entered then exited the viewport.
Typography changed from DM Sans/500 to DM Serif Display/400 at
--text-lg (1.375rem) with -0.01em tracking — same face as the
hero title, scaled down for the 60px nav bar.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Nav title: absolutely centered in the site-header, fades in via
IntersectionObserver when .story-hero__content scrolls above the fold.
Hidden on mobile (< 640px) where there is no room.
Back-to-top: fixed bottom-right pill, appears after 80% of the hero
viewport is scrolled past, smooth-scrolls to top on click.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Overlay previously hard-hid with display:none when scrollY = 100vh, while
the title was still visible (it exits at ~115vh). Now fades in 0→0.65 over
the first 70vh then fades back out to 0 by 140vh (full hero height).
Scrolly caption changed from full-width to centered pill with
rgba(0,0,0,0.45) background — readable against any image regardless of tone.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Adds haversineKm, extractTrackpoints, isNearTrack, buildJourneySegments, and
addJourneySegments to the shared MapLibre GL IIFE. Updates MapUtils export to
expose the new functions. ES5-only; no arrow functions, const/let, or modules.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPJztrVGbwic2xTG7G9fjM
Both stats.html.twig and trip.html.twig previously flattened all GPX
trackpoints into a single masterPts array before computing haversine
distance, elevation, and moving time. This caused the junction between
file N's last point and file N+1's first point to be treated as a real
segment — e.g. Florence→coast (~79 km, ~42 h) for Italy's 3-file demo
data, overstating distance and moving time significantly.
Fix: compute all metrics within each file independently and sum the
results. fileResults collection and callback consumption are unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPJztrVGbwic2xTG7G9fjM
Pre-allocate fileResults[idx] slots so GPX files always concatenate in URL
order regardless of fetch arrival order (Bug 1). Both .then and .catch now
call computeDistance() after decrementing pending so a failed last fetch no
longer leaves the distance element permanently blank (Bug 2).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPJztrVGbwic2xTG7G9fjM
Adds Twig computation for days on road, countries visited, and GPS
points; an expandable stats panel (hidden by default) with haversine
distance calculation; and toggle JS that activates the Stats button.
Added JavaScript to the trip.html.twig template that:
- Adds event listeners to filter buttons (.trip-filter-btn)
- Shows/hides article cards based on data-type attribute (journal/story)
- Manages active state of filter buttons
- Displays empty state message when no results match the filter
- Uses ES5 syntax (no arrow functions, const/let, or template literals)
Also added hidden feed-filter-empty element to display appropriate
empty messages for each filter type.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RB86BaJBG3eGiMdfhmHRrQ
Replace the old trip-nav links with a new filter bar component featuring:
- Three pill buttons for filtering (All content, Journal, Stories)
- "All content" button active by default with teal accent styling
- Separate Stats button with matching pill styling
- CSS for buttons with hover and active states
- Responsive flexbox layout that wraps on narrow screens
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RB86BaJBG3eGiMdfhmHRrQ