On real Android touchscreens, a horizontal drag on content with nothing
left to scroll horizontally gets claimed by Chrome's native
swipe-to-go-back/forward gesture before our own touchend listener
(article-view swipe navigation) ever sees it — silently, with no
touchend firing at all. Synthetic touch testing (mouse-drag emulation
in devtools) doesn't go through that gesture recognizer, so it worked
there while doing nothing on an actual phone.
Fix: overscroll-behavior-x: contain on body stops Chrome from claiming
the gesture for its own navigation, letting our touchend fire normally.
Also drops the overflow-x: hidden added to .article-single for the
slide transition — body already has it (for the same full-bleed-image
reason), so it was redundant.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Swiping left/right in the single-article view now pages to the
next/previous article, same as the up/down nav buttons. Touch handlers
live on .article-single: a swipe needs >=50px horizontal travel and
<=75px vertical travel to count (so scrolling/diagonal drags don't
trigger it), and multi-touch or swipes starting inside a horizontally
scrollable <pre> block are ignored so code blocks keep their own
scroll behavior.
Also adds a direction-aware slide/fade transition (via Vue's
<Transition>, keyed on currentIndex) when paging between articles,
triggered by both the swipe gesture and the nav buttons.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>