touch-action: none stops panning and zooming but not Chromium's
long-press gesture. It fires at ~500ms, just after ARM_MS, raises the
context menu and cancels the pointer stream — so the hold armed the drag
and the OS stole it back a frame later, leaving the page's own long-press
UI on screen and the tab where it was.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pointercancel fires when the OS claims the gesture mid-drag — likely on
the screen edge where the widened hit strip lives, which is also where
Android's swipe-back gesture starts. Bare reset() left the tab stranded
wherever the finger last was, unsnapped and unsaved, until a resize or
reload. Share the pointerup snap block with pointercancel.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
touch-action is resolved at gesture start, so the strip cannot be both
browser-scrolled and script-dragged. Own the gesture and split by intent:
a swipe from the strip scrolls the page, a ~400ms hold arms a reposition
drag, and the visible sliver still drags with no hold. Adds the missing
pointercancel reset.
The 7px sliver is well below a usable touch target on a phone. An
invisible #hit child extends the hit area inward while the visible tab
stays exactly 7x44. Drops overflow:hidden (it would clip #hit) and moves
the corner clip onto #fill via border-radius: inherit.