bottom edge of the content area (above the reserved footer)
full-page content area height (independent of the cursor's position) — already net of the reserved header/footer
top edge of the content area (below the reserved header) — the starting y on every page
remaining vertical space from the cursor to the bottom edge of the content area
moves to a new page if the remaining space is less than requiredHeight
true if a new page was started
a block taller than a full content area (e.g. a long table) won't break here — if the cursor is already at the top of a page, breaking wouldn't help, so the block must handle breaking internally
sync state to match the real doc after a block has paginated itself (e.g. AutoTable) doesn't fire onPageBreak — the page was already added by the block itself can't go backwards (pageIndex must be >= current) — rendering only ever moves forward
x/y tracking + page-break decisions — pure logic, doesn't touch jsPDF the engine connects to the doc only via onPageBreak → testable without mocking jsPDF