The chapters payload now carries resume_rewind_seconds (server-side
per-user setting); the player applies it at two events, each rewinding
once from where playback currently sits — never stacked:
- open-resume: restorePosition starts the rewind early from the saved
spot (percentage and chapter+offset branches, clamped at the book
start). Deep links (?loc=) stay exempt — an explicit jump is not a
resume.
- unpause: a genuine pause→play steps back again (the re-orientation
gap). Programmatic plays — post-restore autoplay and track-switch
autoplays — set a suppress flag: their play event is the session
start the open-rewind already positioned, not an unpause.
Math lives in audio-rewind.ts (pure, unit-tested) after the
audio-scrubber pattern; payload values gate through the 0/5/10
allow-list so stale or foreign servers degrade to exact resume.