'use strict'; // Shared pure policy. No speed limit; credit only loaded pages actually observed, // not pages skipped between two scroll positions. Coordinates never leave reader. (function (root) { const IDLE_MS = 30000, EXPOSURE_MS = 100; function exposureTracker() { const seen = new Set(), exposures = new Map(); function update(pages, now, active) { const visible = new Set(active ? pages.filter(page => page.loaded).map(page => page.index) : []); for (const [page, entry] of exposures) { if (entry.visible) entry.ms += Math.max(0, now - entry.at); entry.at = now; entry.visible = visible.has(page); if (entry.ms >= EXPOSURE_MS) { seen.add(page); exposures.delete(page); } } for (const page of visible) if (!seen.has(page) && !exposures.has(page)) exposures.set(page, { ms: 0, at: now, visible: true }); return seen; } return { seen, update }; } function stateFor({ visible, focused, lastInputAt, now, owned, view }) { if (!visible) return 'hidden'; if (!focused) return 'unfocused'; if (now - lastInputAt >= IDLE_MS) return 'idle'; if (!owned) return 'other-tab'; if (view.atEnd) return 'finished'; if (view.pages.some(page => page.loaded)) return 'reading'; return view.pages.some(page => !page.failed) || !view.pages.length ? 'loading' : 'page-error'; } const policy = { IDLE_MS, EXPOSURE_MS, exposureTracker, stateFor }; if (typeof module !== 'undefined' && module.exports) module.exports = policy; else root.ReadingClockPolicy = policy; })(typeof window === 'undefined' ? globalThis : window);