- Replace native date inputs with always-open custom calendar; return
journeys show two months side-by-side with Airbnb-style range selection
- Add min-connection filter (30/40/50/60 min) for the inbound leg of
return journeys, separate from the outbound connection filter
- Fix total journey time: naive datetime subtraction across CET/BST was
1 h too long outbound and 1 h too short inbound
- Filter inbound circle line suggestions when connection ≥ 40 min: only
show services arriving ≥ 5 min before GWR departure at Paddington
- Add Std / SP labels to Eurostar fare lines so users can distinguish
Standard from Standard Premier
- Row selection with a fixed summary bar showing NR + Eurostar + circle
totals; selection is preserved in the URL
- Load walk-on fares sequentially, outbound section first
- Mobile: card-grid table layout, hide headcode/platform on small screens
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Disable the return date input until Return journey type is selected.
Clicking anywhere in the return date group auto-selects Return and
enables the field. The return date min is kept in sync with the
outbound date, bumping the value forward if it would otherwise fall
before the outbound date.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
For return journeys, replace the single combined date navigation row with two
separate rows so outbound and return dates can be adjusted independently.
For inbound underground options, show one service before the earliest catchable
(as an "aim for this" option) rather than the next service after it, which
often arrived too late to connect with the GWR train.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Eurostar scraper now fetches both Standard and Plus (PLUS class code)
prices/seats in a single API call; each service dict gains plus_price
and plus_seats fields
- GWR fares scraper gains fetch_advance() which makes two sets of
paginated calls (standard advance + first-class advance) and returns
cheapest per departure; shared _run_pages() generator reduces
duplication in fetch()
- New /api/advance_fares/<station_crs>/<travel_date> endpoint returns
advance fares as JSON, cached for 24 hours
- Results page gains NR ticket selector (Walk-on / Std Advance / 1st
Advance) and Eurostar selector (Standard / Plus); total column is
JS-computed from the selected combination with cheapest/priciest
highlighting
- Load advance prices button fetches the API lazily; if advance fares
are already cached they are embedded in the page and applied on load
so the button is hidden automatically
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Redesign results table from 8 columns to 4 (National Rail, Transfer,
Eurostar, Total), making GWR and Eurostar legs consistent with each other
- Move CET label next to Paris arrival time; show duration · train number
on one line below
- Move "Too early" label into the National Rail column for unreachable rows
- Remove horizontal scrollbar (drop card-scroll / overflow-x: auto)
- Add DEFAULT_MIN_CONNECTION / DEFAULT_MAX_CONNECTION to config/default.py
(70 / 150 min); remove all hardcoded fallback values from app.py and
templates
- Redirect to clean URL when both connection params equal their defaults;
omit params from all generated links when at default values
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Support any station with direct trains to Paddington; station CRS code
is now part of the URL (/results/<crs>/<slug>/<date>)
- Load station list from data/direct_to_paddington.tsv; show dropdown on
index page; 404 for unknown station codes
- Fetch live GWR walk-on fares via api.gwr.com for all stations (SSS/SVS/SDS
with restrictions already applied per train); cache 30 days
- Scrape Paddington arrival platform numbers from RTT
- Show unreachable morning Eurostars (before first reachable service only)
- Circle line: show actual KX St Pancras arrival times (not check-in estimate)
and add a second backup service in the transfer column
- Widen page max-width to 1100px for longer station names
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract repeated inline styles from templates into named CSS classes in
base.html: layout helpers, buttons, form groups, alert boxes, results table
rules, row highlight classes, typography utilities, and empty-state styles.
Remove the per-page <style> block from results.html.
Update README to reflect current destinations, GraphQL data source, Circle
Line timetable, configurable connection range, and GWR fare table.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>