A second primary pointer pressing mid-drag replaced the drag record, so
neither release cleared the first pointer's transform and the card stayed
displaced. A press while a drag is in progress is now ignored, and a new
top card ends a drag left on the old one so it cannot block the next.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Track the pointerup position before choosing Try it, Pass or snap-back,
so the outcome follows where the card was let go (SQ-107-01).
- Keep the snap-back animation and cancel it when a new drag or a
decision starts (SQ-107-02).
- Treat losing pointer capture before the release as a cancel, springing
the card back and resetting its stamps (SQ-107-03).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The top card follows a pointer drag per handoff Motion §4: captured with
setPointerCapture under touch-action none, it moves to translate(dx, dy*0.3)
rotate(dx/18 deg) with the "Try it!" and "Pass" stamps at clamp(±dx/100).
A release past 110 px right throws it from where it was let go (340 ms, no
wiggle); past 110 px left folds it from the drag transform; anything shorter
springs back over 420 ms and resets the stamps. Swipe decisions go through
the same decide handler as the buttons and ← / → keys, so the busy lock and
reduced-motion fade apply unchanged; only the top card is draggable and
input is ignored while busy.
motion.ts gains dragTransform, follow, unfollow and snapBack beside the
exits; DeckCard marks its Pass stamp as a part.
Maestro task 54c12e9e-5f36-4595-babb-e54107bb473b.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>