Swipe left for older, right for newer, matching the existing arrow keys.
The image tracks the finger and slides out on commit; the exit animation
covers the page load, so this stays plain static-site navigation.
The keyboard handler moves out of the template into static/photo-nav.js,
which the existing //go:embed of static/ picks up with no generator
changes.
Swipes starting within 24px of a screen edge are left alone — that strip
is the browser's own back-gesture. Only touch pointers are handled, so
desktop drag-to-save still works, and the axis locks after 10px so
vertical drags stay scrolls. With no neighbour that way the image
rubber-bands instead of navigating.
Also prefetch the neighbour medium JPEGs, not just their HTML, or the
next page still blocks on a fresh image request.
The keyboard handler now bails on modifier keys; it previously hijacked
Alt+ArrowLeft, which is browser-back on Linux and Windows.
Move the Newer and Older links to a right-aligned group joined by a
slash so they stop crowding the Back link, and drop the aqua accent so
every link in the row shares the muted serif tone.
Replace the standalone Back link with a three-cell nav row so each
photo page links to its neighbours in the timeline. Prefetch the
neighbouring pages and bind the arrow keys for keyboard navigation.
Emit /page/N/ pages alongside index.html and render a pager at the
bottom of each page. Ships as a plain link that navigates without JS,
and an IntersectionObserver enhancement that fetches the next page and
appends tiles for an infinite-scroll feel.
Vollkorn read as too chunky next to the Malayalam bio in Manjari.
Crimson Pro is a calmer book-face serif that pairs more evenly.
Renames the CSS variable from --vk to --serif to reflect that the
value is no longer Vollkorn-specific, and bumps .ml to 17px/1.5
so the Malayalam subtitle sits at a comfortable reading size.
Photo detail page previously showed a square crop of the source image. Now
generate an aspect-preserved medium JPEG (longest side 1600, quality 88)
and display that on the detail page instead. The original file is linked
from a click-through on the image and from a sidebar 'Full size' download
link.
Also skip regeneration of images/thumbs/medium when the destination is
already at least as new as the source, so a rebuild triggered by editing
one sidecar (or restarting the service) no longer redecodes and rescales
every photo.