Editing an event's start now shifts the end by the same amount, preserving the
current duration (end - start). Moving the start forward never leaves the end
before it, and moving it either way never silently changes the length. Guards
against an already-negative-duration state.
Extracted a pure `shiftedEnd(oldStart, oldEnd, newStart)` for the start
date/time onChange handlers. +7 unit tests. tsc + eslint clean.