# Stats Redesign — Implementation Plan
*Derived from spec: docs/working/specs/2026-06-19-stats-redesign.md*
> **For agentic workers:** Use superpowers:subagent-driven-development to execute this plan task-by-task.
**Status:** ✅ Complete (2026-06-20)
**Goal:** Expand trip statistics from 4 to 6 stats (add cities visited + temperature range), add smart distance labelling (Mode A: GPX-based "km cycled" vs Mode B: entry-lat/lng "km roamed"), and add a collapsible cycling panel (only when GPX files are present) with 7 cycling-specific stats derived from GPX track data.
**Architecture:** Twig server-side computation for new stats (cities, temp range, GPX detection, date_end-aware days-on-road). Client-side JS for: distance computation in both modes, GPX parsing, cycling panel population. No new pages, no Grav config changes.
**Tech Stack:** Twig (Grav 2.0), vanilla JS (ES5), CSS custom properties
---
## Global Constraints
- **ES5 JS only** — no `const`/`let`, no arrow functions `() =>`, no template literals `` ` `` — all scripts are inline Twig and run as plain `
```
### CSS change in style.css
Update `.stats-grid` from 2 to 3 columns:
```css
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-4);
margin-bottom: var(--space-8);
}
```
Keep the mobile breakpoint if one exists; add one if not:
```css
@media (max-width: 600px) {
.stats-grid { grid-template-columns: repeat(2, 1fr); }
}
```
### Commit
```bash
cd user && git add themes/intotheeast/templates/stats.html.twig themes/intotheeast/css/style.css
git commit -m "feat: expand stats page to 6 stats — cities, temp range, distance mode detection"
```
---
## Task 2: Update `trip.html.twig` — inline stats + cycling panel
**Files:**
- Modify: `user/themes/intotheeast/templates/trip.html.twig`
- Modify: `user/themes/intotheeast/css/style.css`
**What to build:**
### Twig changes in trip.html.twig
Add after the existing `{% set story_count %}` line (line ~19), mirroring Task 1's logic but using `page` directly (not `page.parent()`):
**1. Date-end-aware days on road** — replace the existing `days_on_road` block:
```twig
{% set days_on_road = 0 %}
{% if page.header.date_end is not empty %}
{% set start_ts = page.header.date_start|date('U') %}
{% set end_ts = page.header.date_end|date('U') %}
{% set days_on_road = ((end_ts - start_ts) / 86400)|round(0, 'ceil') %}
{% else %}
{% set first_ts = null %}
{% for entry in journal_entries %}
{% set ts = entry.date|date('U') %}
{% if first_ts is null or ts < first_ts %}{% set first_ts = ts %}{% endif %}
{% endfor %}
{% if first_ts is not null %}
{% set diff_seconds = "now"|date('U') - first_ts %}
{% set days_raw = (diff_seconds / 86400)|round(0, 'floor') %}
{% set days_on_road = days_raw < 1 ? 1 : days_raw %}
{% endif %}
{% endif %}
```
**2. Cities dedup** (add after country dedup block):
```twig
{% set seen_city_lower = [] %}
{% set city_display = [] %}
{% for entry in journal_entries %}
{% if entry.header.location_city is not empty %}
{% set lower = entry.header.location_city|trim|lower %}
{% if lower not in seen_city_lower %}
{% set seen_city_lower = seen_city_lower|merge([lower]) %}
{% set city_display = city_display|merge([entry.header.location_city|trim]) %}
{% endif %}
{% endif %}
{% endfor %}
```
**3. Temperature range** (add after cities block):
```twig
{% set temp_min = null %}
{% set temp_max = null %}
{% for entry in journal_entries %}
{% if entry.header.weather_temp_c is defined and entry.header.weather_temp_c is not empty %}
{% set t = entry.header.weather_temp_c %}
{% if temp_min is null or t < temp_min %}{% set temp_min = t %}{% endif %}
{% if temp_max is null or t > temp_max %}{% set temp_max = t %}{% endif %}
{% endif %}
{% endfor %}
```
**4. GPX detection** — `gpx_urls` already computed in trip.html.twig; add:
```twig
{% set has_gpx = gpx_urls|length > 0 %}
```
### HTML changes in trip.html.twig
**A. Update filter bar** — add Cycling button next to Stats button (hidden if no GPX):
Find the current filter bar:
```twig
```
Replace with:
```twig
{% if has_gpx %}
{% endif %}
```
**B. Update inline stats block** — expand from 4 to 6 stats (same order as Task 1):
Replace the current `.trip-stats-grid` content with:
```twig
{{ days_on_road }}{{ days_on_road == 1 ? 'day' : 'days' }} on the road