@embedpdf/plugin-stage 3.0.0-next.13 → 3.0.0-next.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["ZoomMode","S","ActionsHostToken","StageToken","PublicActionsToken","ActionsHostToken","destinationToReveal"],"sources":["../src/motion.ts","../src/responsive.ts","../src/settings.ts","../src/capability.ts","../src/effects.ts","../src/reducer.ts","../src/stage.plugin.ts","../src/scroll-handler.ts"],"sourcesContent":["/**\n * The camera's MOTION vocabulary — every formula, pure.\n *\n * The capability owns the impure drivers (scheduler frames, dispatch, gesture\n * state); the LAWS those drivers integrate live here, parameterized by dt/t\n * with no state, no scheduler, no dispatch — unit-testable in isolation, and\n * with zero plugin dependencies, liftable into stage-core if the native port\n * ever wants them.\n *\n * Two families:\n * • ballistic — one per-axis law for every free motion: `glideStep` (the\n * touch fling, decaying on UIScrollView's curve) and `springStep` (a\n * critically-damped return to the clamp). A glide that reaches a content\n * edge converts to a spring with its velocity carried in, so the bounce\n * grows out of physics rather than a scripted overshoot.\n * • resistance — the iOS rubber-band curve `rubberOut` and its exact\n * inverse `rubberIn`: dragging `d` px past an edge displays an\n * asymptotically-bounded stretch, and re-entering a gesture over a\n * stretched camera (the mid-bounce catch) reconstructs the\n * finger-integrated position the curve came from.\n * Plus the tween interpolators: `easeOutCubic` for coordinate tweens and\n * `zoomLerp` — GEOMETRIC zoom interpolation (zoom is multiplicative; equal\n * ratios per unit time, not equal deltas — the linear lerp's visible \"dip\").\n */\n\n// ── constants ─────────────────────────────────────────────────────────────────\n/** Resistance coefficient of the rubber-band curve (the iOS feel). */\nexport const RUBBER = 0.55;\n/** Glide decay per ms — UIScrollView's normal deceleration rate. */\nexport const FLING_DECAY = 0.998;\n/** px/ms — below ~20 px/s the eye reads \"stopped\". */\nexport const FLING_STOP = 0.02;\n/** rad/ms — critically damped, ~400ms to settle. */\nexport const SPRING_OMEGA = 0.015;\n\n// ── resistance (rubber-band) ──────────────────────────────────────────────────\n/**\n * Overshoot distance → displayed stretch: asymptotic to the viewport\n * dimension `dim`, so the content never leaves the screen however far the\n * finger travels. `rubberOut(0) === 0` — inside the bounds the curve is\n * invisible.\n */\nexport const rubberOut = (d: number, dim: number): number => (1 - 1 / ((d * RUBBER) / dim + 1)) * dim;\n/** Exact inverse of `rubberOut` (defined for `out < dim`). */\nexport const rubberIn = (out: number, dim: number): number => (out * dim) / (RUBBER * (dim - out));\n\n// ── ballistic (one axis, one frame) ───────────────────────────────────────────\n/** The state one integration step hands back; `done` means \"at rest\". */\nexport interface MotionStep {\n p: number;\n v: number;\n done: boolean;\n}\n/**\n * One frame of free glide: exponential velocity decay, position advanced by\n * the midpoint integral of the decay over `dt` (exact for the exponential —\n * frame-rate independent).\n */\nexport const glideStep = (p: number, v: number, dt: number): MotionStep => {\n const k = Math.pow(FLING_DECAY, dt);\n const np = p + v * ((dt * (1 + k)) / 2);\n const nv = v * k;\n return Math.abs(nv) < FLING_STOP ? { p: np, v: 0, done: true } : { p: np, v: nv, done: false };\n};\n/**\n * One frame of critically-damped spring toward `edge` — semi-implicit Euler\n * on x'' = −ω²(x−e) − 2ωx'. Lands exactly ON the edge (position snapped,\n * velocity zeroed) once inside half a pixel at negligible speed.\n */\nexport const springStep = (p: number, v: number, edge: number, dt: number): MotionStep => {\n const nv = v + (-SPRING_OMEGA * SPRING_OMEGA * (p - edge) - 2 * SPRING_OMEGA * v) * dt;\n const np = p + nv * dt;\n if (Math.abs(np - edge) < 0.5 && Math.abs(nv) < 0.01) return { p: edge, v: 0, done: true };\n return { p: np, v: nv, done: false };\n};\n\n// ── tween interpolators ───────────────────────────────────────────────────────\nexport const easeOutCubic = (t: number): number => 1 - Math.pow(1 - t, 3);\n/**\n * Geometric zoom interpolation: `z0·(z1/z0)^k`. Zoom is multiplicative, so a\n * constant-RATE zoom moves equal ratios per unit time; interpolating the\n * level linearly instead makes the start rush and the end crawl (and, under\n * a focal anchor, swings the anchored point along a curved path).\n */\nexport const zoomLerp = (z0: number, z1: number, k: number): number => z0 * Math.pow(z1 / z0, k);\n","import type { Size } from '@embedpdf/core-stage';\nimport type { BoxQuery, ResponsiveRule, StageBox, StageSettings } from './types';\n\n/**\n * Container queries for the settings bag — the pure half. The capability owns\n * the driver (when to re-resolve, how to react); the LAWS live here: what a\n * box is, when a query matches, and what the effective settings are. No state,\n * no dispatch — property-testable in isolation (the `wheel.ts` convention).\n *\n * The query vocabulary is deliberately just the box: a headless, DOM-free\n * stage knows exactly one environmental fact — the viewport it was told.\n * Anything else (pointer coarseness, platform, app state) is either per-event\n * (`PointerSample.pointerType`) or the app's own business via `update()`.\n */\n\n/** The reported viewport as a queryable box. A square box is 'portrait' (CSS). */\nexport const boxOf = (vp: Size): StageBox => ({\n width: vp.width,\n height: vp.height,\n orientation: vp.height >= vp.width ? 'portrait' : 'landscape',\n});\n\n/** All bounds inclusive, all fields optional, conditions AND-ed (CSS ranges). */\nexport const matchesQuery = (q: BoxQuery, box: StageBox): boolean =>\n (q.minWidth === undefined || box.width >= q.minWidth) &&\n (q.maxWidth === undefined || box.width <= q.maxWidth) &&\n (q.minHeight === undefined || box.height >= q.minHeight) &&\n (q.maxHeight === undefined || box.height <= q.maxHeight) &&\n (q.orientation === undefined || box.orientation === q.orientation);\n\nconst ruleMatches = (rule: ResponsiveRule, box: StageBox): boolean =>\n typeof rule.when === 'function' ? !!rule.when(box) : matchesQuery(rule.when, box);\n\n/** Merge a patch over settings, skipping undefined values (Partial semantics). */\nexport const mergeSettings = (into: StageSettings, patch: Partial<StageSettings>): StageSettings => {\n const out = { ...into };\n let key: keyof StageSettings;\n for (key in patch) {\n const value = patch[key];\n if (value !== undefined) Object.assign(out, { [key]: value });\n }\n return out;\n};\n\n/**\n * Setting-value equality: primitives by identity, the flat objects the\n * settings vocabulary uses (`{ px }`, `{ x, y }`, page frames, zoom specs) by\n * one level of own-key comparison. Settings values are never nested deeper.\n */\nexport const eqSetting = (a: unknown, b: unknown): boolean => {\n if (a === b) return true;\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false;\n const ka = Object.keys(a);\n const kb = Object.keys(b);\n return (\n ka.length === kb.length &&\n ka.every((k) => (a as Record<string, unknown>)[k] === (b as Record<string, unknown>)[k])\n );\n};\n\nexport interface ResolvedResponsive {\n /** base ⊕ every matching rule's patch, in source order (later wins per key). */\n effective: StageSettings;\n /** Names of the matching rules, in source order. */\n active: string[];\n}\n\nexport const resolveResponsive = (\n base: StageSettings,\n rules: readonly ResponsiveRule[],\n box: StageBox,\n): ResolvedResponsive => {\n let effective = base;\n const active: string[] = [];\n for (const rule of rules) {\n if (!ruleMatches(rule, box)) continue;\n if (rule.name !== undefined) active.push(rule.name);\n if (rule.settings) effective = mergeSettings(effective, rule.settings);\n }\n return { effective, active };\n};\n","import { ZoomMode } from '@embedpdf/core-stage';\nimport type { ResponsiveRule, StageSettings } from './types';\n\n/**\n * Out-of-the-box defaults — a sensible document-reading feel. They are JUST\n * defaults: every field is overridable in `stagePlugin(config)` and at runtime via\n * the setters / `update()`. The plugin ships NO named presets (\"document\",\n * \"canvas\", …) — a preset is simply an object the app keeps and passes to\n * `update()`, so that taxonomy stays a customer concern.\n */\nexport const DEFAULT_SETTINGS: StageSettings = {\n flow: 'continuous',\n layout: 'vertical',\n spread: 'none',\n sizing: 'intrinsic',\n columns: 'square',\n bounded: true,\n padding: 24,\n gap: 16,\n pageFrame: { top: 0, right: 0, bottom: 0, left: 0 },\n direction: 'ltr',\n fitAlign: { x: 'center', y: 'center' },\n // The reading defaults: navigation lands top/reading-start at every zoom\n // (v2 parity), button-zoom inflates around the middle, resizes pin the top\n // (the browser scroll model). Construction/presentation apps set all four\n // to center/center.\n arrivalAlign: { x: 'start', y: 'start' },\n zoomAlign: { x: 'center', y: 'center' },\n anchorAlign: { x: 'start', y: 'start' },\n viewRotation: 0,\n zoom: { mode: ZoomMode.Automatic },\n scrollBehavior: 'smooth',\n // Web: 1 PDF point = 96/72 CSS px, so 100% is physically accurate. A native\n // adapter overrides this at registration with its own logical-unit factor.\n viewUnitsPerPoint: 96 / 72,\n};\n\n/**\n * Out-of-the-box responsive rules — the platform feel with zero configuration:\n * a compact container gets the thin gutter phones use (space, not device — an\n * embedded 500px pane on a desktop is compact too). Override the whole list\n * with `stagePlugin({ responsive: [...] })`; `responsive: []` opts out. The\n * 'compact' name is queryable app-side via `stage.matches('compact')`.\n */\nexport const DEFAULT_RESPONSIVE: readonly ResponsiveRule[] = [\n { name: 'compact', when: { maxWidth: 600 }, settings: { padding: 4 } },\n];\n\n/**\n * How a CHANGE to each setting affects the view — THE single source of truth.\n * One row per setting, completeness enforced by the compiler (`Record<keyof\n * StageSettings, …>`: adding a setting without classifying it is a type error).\n * Everything else derives from this table: the scene-cache invalidation and key,\n * `update()`'s reaction, the settings snapshot/patch picks, and the React\n * selector equality.\n *\n * 'reflow' — crosses the flow boundary: camera coordinates are meaningless\n * there, so re-place canonically onto the cursor's page.\n * 'scene' — a LAYOUT INPUT: invalidates the scene, then re-applies the anchor.\n * 'refit' — re-resolves zoom against the (possibly re-keyed) scene: re-applies\n * the anchor without an explicit invalidation.\n * 'reclamp' — pure clamp policy: re-clamp the current camera in place.\n * 'none' — guides future verbs only (arrival/zoom/anchor alignment,\n * scroll behavior).\n *\n * The classes also carry each change's INVARIANT — what stays fixed while the\n * view reacts: 'refit' (a zoom-intent change) holds the zoomAlign focal point;\n * 'scene' reframes (and viewport resizes) hold the anchorAlign point.\n */\nexport type SettingEffect = 'reflow' | 'scene' | 'refit' | 'reclamp' | 'none';\nexport const SETTINGS_EFFECT: Record<keyof StageSettings, SettingEffect> = {\n flow: 'reflow',\n layout: 'scene',\n spread: 'scene',\n sizing: 'scene',\n columns: 'scene',\n bounded: 'reclamp',\n padding: 'reclamp',\n gap: 'scene',\n pageFrame: 'scene',\n direction: 'scene',\n fitAlign: 'reclamp',\n arrivalAlign: 'none',\n zoomAlign: 'none',\n anchorAlign: 'none',\n viewRotation: 'scene', // a layout input: every page's footprint swaps w↔h\n zoom: 'refit',\n scrollBehavior: 'none',\n viewUnitsPerPoint: 'scene', // a layout input: changing it resizes every page\n};\nexport const SETTING_KEYS = Object.keys(SETTINGS_EFFECT) as Array<keyof StageSettings>;\n\n// Settings values are primitives or one-level objects (align pairs, pageFrame,\n// gap { px }, zoom intents) — one level of structural equality covers them all.\nconst valueEq = (a: unknown, b: unknown): boolean => {\n if (a === b) return true;\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false;\n const ka = Object.keys(a);\n return (\n ka.length === Object.keys(b).length &&\n ka.every((k) => (a as Record<string, unknown>)[k] === (b as Record<string, unknown>)[k])\n );\n};\n/** Field-by-field settings equality, derived from the registry — a new setting is\n * covered automatically. (The React `useStageSettings` selector equality.) */\nexport const settingsEqual = (a: StageSettings, b: StageSettings): boolean =>\n SETTING_KEYS.every((k) => valueEq(a[k], b[k]));\n","import * as S from '@embedpdf/core-stage';\nimport {\n addRotations,\n applyRect,\n applyPoint,\n displaySize,\n intersectRects,\n pageTransform,\n rotateScaleMatrix,\n snapToDevice,\n} from '@embedpdf/core-geometry';\nimport type { Rect } from '@embedpdf/core-geometry';\nimport type { PluginContext } from '@embedpdf/core';\nimport { FLING_STOP, easeOutCubic, glideStep, rubberIn, rubberOut, springStep, zoomLerp } from './motion';\nimport { boxOf, eqSetting, mergeSettings, resolveResponsive } from './responsive';\nimport { DEFAULT_RESPONSIVE, SETTINGS_EFFECT, SETTING_KEYS } from './settings';\nimport type { SettingEffect } from './settings';\nimport type {\n GoToOptions,\n ResponsiveRule,\n RevealAnchorValue,\n RevealOptions,\n Scheduler,\n StageAction,\n StageCapability,\n StageConfig,\n StageSettings,\n StageState,\n StageViewState,\n Viewpoint,\n VisiblePage,\n} from './types';\n\n/**\n * The Stage capability — selectors (pure reads) + intents (the only writers).\n *\n * Layering, stated honestly:\n * • stage-core — PURE spatial math (no DOM, no time). Ports to Rust later.\n * • this capability — the IMPURE platform shell. It dispatches, caches, and owns\n * the camera tween. It is NOT pure; its one host dependency (frame timing)\n * enters through the Scheduler seam — injectable, defaulting to the host's\n * own frame clock when one exists (see the seam below).\n *\n * The model: EVERY camera move is defined by what it holds fixed.\n * • gestures (pan/pinch/wheel) — the content under the pointer. Physics, no setting.\n * • focal zoom (zoomIn/zoomTo/fit-mode switches) — the zoomAlign viewport point.\n * • reframes (resize/rotate/re-layout) — the page-point at the anchorAlign\n * viewport point: captured there before the change, restored there after.\n * • arrivals (goToPage/next/prev/reset) — nothing prior: a fresh landing at\n * arrivalAlign, THE SAME at every zoom (landing is policy, never a zoom side effect).\n * • explicit (reveal/destination/viewpoint) — whatever the call specifies.\n * fitAlign stands apart: the clamp's standing rest constraint wherever an axis has no\n * freedom against the TRUE bounds — it shapes every move above, and is why a fitting\n * axis settles identically whatever arrivalAlign says.\n *\n * \"Does it fit the viewport?\" still decides SIZE and SUBJECT — never alignment:\n * • step size: next/prev step by ITEM (spread) when the item fits, by PAGE when\n * zoomed in past it.\n * • subject: you arrive AT the unit that fits (item, page — or the whole scene\n * under fit-all).\n *\n * The `cursor` is THE current page in both flows: navigation sets it; continuous\n * scrolling syncs it from the camera; paged panning never moves it.\n */\nexport function createStageCapability(\n ctx: PluginContext<StageState, StageAction>,\n config: StageConfig = {},\n): StageCapability {\n // ── host timing seam ─────────────────────────────────────────────────────────\n // Frame timing enters through the Scheduler seam. By DEFAULT the seam binds\n // to the host's own frame clock (globalThis.requestAnimationFrame) when one\n // exists — inject to override (tests do); a frameless host degrades to\n // instant navigation, no animation.\n const host = globalThis as {\n requestAnimationFrame?: (cb: (t: number) => void) => number;\n cancelAnimationFrame?: (handle: number) => void;\n };\n const canAnimate = !!config.scheduler || typeof host.requestAnimationFrame === 'function';\n const scheduler: Scheduler =\n config.scheduler ??\n (typeof host.requestAnimationFrame === 'function'\n ? { raf: (cb) => host.requestAnimationFrame!(cb), caf: (h) => host.cancelAnimationFrame!(h) }\n : { raf: () => 0, caf: () => {} }); // no host frames → navigation jumps instantly\n\n const cam = () => ctx.getState().camera;\n const vp = () => ctx.getState().vp;\n const dpr = () => ctx.getState().dpr;\n const pad = () => ctx.getState().padding;\n const paged = () => ctx.getState().flow === 'paged';\n const isFitAll = () => {\n const z = ctx.getState().zoom;\n return 'mode' in z && z.mode === S.ZoomMode.FitAll;\n };\n\n // ── the document's item model (spread grouping) — independent of the rendered\n // scene, so navigation can reason about ALL items while a paged SCENE holds\n // only one. The cursor is a page; itemIndexOfPage maps it (survives regrouping).\n let groupingCache: { key: string; grouping: number[][]; firstPages: number[] } | null = null;\n const grouping = (): { grouping: number[][]; firstPages: number[] } => {\n const doc = ctx.document();\n const st = ctx.getState();\n const key = `${doc ? doc.pageCount : 0}|${st.spread}`;\n if (groupingCache && groupingCache.key === key) return groupingCache;\n const g = S.groupPages(doc ? doc.pageCount : 0, st.spread);\n groupingCache = { key, grouping: g, firstPages: g.map((item) => item[0]) };\n return groupingCache;\n };\n const itemCountFull = (): number => grouping().grouping.length;\n const itemIndexOfPage = (pageIndex: number): number => {\n const fp = grouping().firstPages;\n let lo = 0;\n let hi = fp.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (fp[mid] <= pageIndex) lo = mid + 1;\n else hi = mid;\n }\n return Math.max(0, lo - 1);\n };\n\n // The effective zoom for converting SCREEN px settings into world units — a\n // fixed zoom intent gives an exact, stable value (the thumbnail case); other\n // intents fall back to the camera's current zoom (`stabilized` converges it).\n // Screen-px settings (wrapped lineWidth, pageFrame) are the ONLY way a scene\n // depends on the viewport/zoom.\n const effectiveZoom = (): number => {\n const z = ctx.getState().zoom;\n return 'level' in z ? z.level : Math.max(ctx.getState().camera.zoom, 0.0001);\n };\n\n // Wrapped grid: the line width (world units) the columns must fit.\n const wrapLineWidth = (): number => Math.max(1, (vp().width - 2 * pad()) / effectiveZoom());\n\n // pageFrame (screen px) → world units at the effective zoom.\n const worldPageFrame = (): S.PageFrame => {\n const m = ctx.getState().pageFrame;\n if (!m.top && !m.right && !m.bottom && !m.left) return m;\n const ez = effectiveZoom();\n return { top: m.top / ez, right: m.right / ez, bottom: m.bottom / ez, left: m.left / ez };\n };\n const frameKey = (): string => {\n const m = ctx.getState().pageFrame;\n if (!m.top && !m.right && !m.bottom && !m.left) return '-';\n const w = worldPageFrame();\n return `${Math.round(w.top)},${Math.round(w.right)},${Math.round(w.bottom)},${Math.round(w.left)}`;\n };\n\n // gap → world units. A plain number IS world (the scene stays zoom-invariant —\n // the rigid-canvas default); { px } converts at the effective zoom, exactly\n // like pageFrame (UI-stable spacing for browser-style lenses).\n const worldGap = (): number => {\n const g = ctx.getState().gap;\n return typeof g === 'number' ? g : g.px ? g.px / effectiveZoom() : 0;\n };\n const gapKey = (): string => {\n const g = ctx.getState().gap;\n return typeof g === 'number' ? String(g) : `px:${Math.round(worldGap())}`;\n };\n\n const layoutFor = (groups: number[][]): S.Scene => {\n const st = ctx.getState();\n // Engine PageLayout (PDF document geometry) structurally satisfies stage-core's\n // viewer-local PageGeom (`size` + `rotation`): intrinsic page size needs no\n // transform, so it flows straight into the layout with no conversion.\n //\n // THE view-rotation injection point: each page's display rotation is its\n // /Rotate + this lens's viewRotation, composed HERE — the one spot where\n // the \"TOTAL = document /Rotate + view rotation\" of geometry's PageRotation\n // doc is resolved. Everything downstream (displaySize w↔h swap, the page\n // transform + CSS rotate, hit-testing, fit zoom, content overlays) reads the\n // composed `PageBox.rotation` and needs no other change. `size` stays the\n // page's own un-rotated points, so content space is view-rotation-invariant.\n const raw = ctx.document()?.pages ?? [];\n const vr = st.viewRotation;\n const pages =\n vr === 0 ? raw : raw.map((p) => ({ ...p, rotation: addRotations(p.rotation, vr) }));\n const pageFrame = worldPageFrame();\n const gap = worldGap();\n const vupp = st.viewUnitsPerPoint;\n if (st.layout === 'grid') {\n return S.gridLayout(pages, groups, {\n gap,\n sizing: st.sizing,\n direction: st.direction,\n pageFrame,\n viewUnitsPerPoint: vupp,\n columns: typeof st.columns === 'number' ? st.columns : undefined,\n lineWidth: st.columns === 'auto' ? wrapLineWidth() : undefined,\n });\n }\n return st.layout === 'horizontal'\n ? S.linearLayout(pages, groups, {\n axis: 'x',\n gap,\n sizing: st.sizing,\n direction: st.direction,\n pageFrame,\n viewUnitsPerPoint: vupp,\n })\n : S.linearLayout(pages, groups, {\n axis: 'y',\n gap,\n sizing: st.sizing,\n direction: st.direction,\n pageFrame,\n viewUnitsPerPoint: vupp,\n });\n };\n\n // Scene-cache key fragment for the column policy ('auto' quantizes the line width\n // so sub-pixel resizes don't churn the cache).\n const columnsKey = (): string => {\n const st = ctx.getState();\n if (st.layout !== 'grid') return '-';\n return st.columns === 'auto' ? `auto:${Math.round(wrapLineWidth())}` : String(st.columns);\n };\n\n // The scene's settings signature — DERIVED from the registry: every 'scene'\n // setting contributes automatically, so a new layout-affecting setting only\n // needs its SETTINGS_EFFECT row — it can't be forgotten here, which is what\n // makes stale-scene bugs unrepresentable. The default keys by VALUE (objects\n // via JSON); the custom fns aren't for correctness, they QUANTIZE px-derived\n // values so sub-pixel zoom/resize churn doesn't rebuild the scene.\n const SCENE_KEY_FNS: Partial<Record<keyof StageSettings, () => string>> = {\n columns: columnsKey,\n gap: gapKey,\n pageFrame: frameKey,\n };\n const SCENE_KEYS = SETTING_KEYS.filter((k) => SETTINGS_EFFECT[k] === 'scene');\n const settingsKey = (): string =>\n SCENE_KEYS.map((k) => {\n const fn = SCENE_KEY_FNS[k];\n if (fn) return fn();\n const v = ctx.getState()[k];\n return typeof v === 'object' && v !== null ? JSON.stringify(v) : String(v);\n }).join('|');\n\n // Scene cache. Continuous = the whole document. Paged = a ONE-ITEM SLICE at the\n // origin containing only the cursor's item — so isolation is STRUCTURAL (no other\n // page exists to leak), unbounded pan is free, and coordinates stay local.\n let sceneCache: { key: string; scene: S.Scene } | null = null;\n // Registry signature: page count + the kernel's monotonic `revision`. The\n // revision bumps on every page-mutation event (rotate/move/delete), so a\n // change that leaves pageCount the same — a rotation — still re-keys the\n // scene. Without it a rotated page would render in its stale box.\n const docKey = (): string => {\n const doc = ctx.document();\n return doc ? `${doc.pageCount}.${doc.revision}` : '0.0';\n };\n const buildScene = (): S.Scene => {\n const st = ctx.getState();\n const { grouping: g } = grouping();\n if (st.flow === 'paged') {\n const idx = g.length ? Math.min(itemIndexOfPage(st.cursor), g.length - 1) : 0;\n const key = `paged|${docKey()}|${settingsKey()}|${idx}`;\n if (sceneCache && sceneCache.key === key) return sceneCache.scene;\n const scene = layoutFor(g.length ? [g[idx]] : []);\n sceneCache = { key, scene };\n return scene;\n }\n const key = `cont|${docKey()}|${settingsKey()}`;\n if (sceneCache && sceneCache.key === key) return sceneCache.scene;\n const scene = layoutFor(g);\n sceneCache = { key, scene };\n return scene;\n };\n\n // ── geometry helpers ──────────────────────────────────────────────────────────\n const sceneRect = (): S.Rect => {\n const { width, height } = buildScene().size;\n return { x: 0, y: 0, width, height };\n };\n const itemRect = (it: S.SceneItem): S.Rect => ({\n x: it.x,\n y: it.y,\n width: it.width,\n height: it.height,\n });\n const pageRectOf = (it: S.SceneItem, pageIndex: number): S.Rect => {\n const box = it.pages.find((p) => p.pageIndex === pageIndex) ?? it.pages[0];\n return { x: box.x, y: box.y, width: box.width, height: box.height };\n };\n /** The item shown for the cursor: the slice's only item (paged) / the full-scene item. */\n const cursorItem = (): S.SceneItem => {\n const sc = buildScene();\n return paged() ? sc.items[0] : sc.items[itemIndexOfPage(ctx.getState().cursor)];\n };\n\n /**\n * CONTENT-space rect on a page → WORLD rect: the same quarter-turn matrix\n * `pageRectToScreen` uses, minus the camera — so a positioned reveal and\n * the rendered overlay can never disagree about where a rect is.\n */\n const worldRectForContent = (it: S.SceneItem, pageIndex: number, rect: Rect): S.Rect => {\n const box = it.pages.find((p) => p.pageIndex === pageIndex) ?? it.pages[0];\n const content = displaySize({ width: box.width, height: box.height }, box.rotation);\n const m = rotateScaleMatrix(box.contentScale, content.width, content.height, box.rotation);\n const wr = applyRect(m, rect);\n return { x: box.x + wr.x, y: box.y + wr.y, width: wr.width, height: wr.height };\n };\n\n /**\n * One axis of a positioned-reveal camera. `undefined` = 'nearest' (only\n * move if the target is outside the padded view) — unless the zoom just\n * changed, where \"don't move\" is meaningless and the spec's slack-axis\n * rule (center) applies. 'keep' never moves the axis (PDF /XYZ null).\n */\n const revealAxis = (\n a: RevealAnchorValue | undefined,\n camPos: number,\n rectPos: number,\n rectExtent: number,\n vpExtent: number,\n zoom: number,\n zoomChanged: boolean,\n ): number => {\n if (a === 'keep') return camPos;\n const p = pad();\n if (a === undefined) {\n if (!zoomChanged) {\n const lo = camPos + p / zoom;\n const hi = camPos + (vpExtent - p) / zoom;\n if (rectPos >= lo && rectPos + rectExtent <= hi) return camPos; // already visible\n if (rectExtent > hi - lo || rectPos < lo) return rectPos - p / zoom;\n return rectPos + rectExtent - (vpExtent - p) / zoom;\n }\n a = 'center';\n }\n if (a === 'start') return rectPos - p / zoom;\n if (a === 'end') return rectPos + rectExtent - (vpExtent - p) / zoom;\n const f = a === 'center' ? 0.5 : Math.min(1, Math.max(0, a));\n return rectPos + rectExtent / 2 - (vpExtent * f) / zoom;\n };\n\n // THE predicate. \"Does this rect fit the padded viewport at this zoom?\" decides\n // the navigation step size and the arrival subject — never alignment.\n const fits = (rect: S.Rect, zoom: number): boolean => {\n const v = vp();\n const p = pad();\n const eps = 0.5;\n return (\n rect.width * zoom <= v.width - 2 * p + eps && rect.height * zoom <= v.height - 2 * p + eps\n );\n };\n // An alignment policy → a concrete viewport point (a fraction per axis:\n // start=0, center=½, end=1; named x stops are LOGICAL under RTL). Both\n // zoomAlign (the focal point of pointer-less zooms) and anchorAlign (the\n // reframe reference point) resolve through this. The fraction interpolates\n // the PADDED range: 'start' is the first visible content line (just inside\n // the gutter), not the absolute corner — an arrival puts the page edge\n // exactly there, so the reference pins to the page, never to the gap above.\n const alignFraction = (a: S.AlignValue): number =>\n a === 'start' ? 0 : a === 'center' ? 0.5 : a === 'end' ? 1 : Math.min(1, Math.max(0, a));\n const alignPoint = (al: S.AlignmentValue, v: S.Size): S.Point => {\n const rtl = ctx.getState().direction === 'rtl';\n const ax = rtl && al.x === 'start' ? 'end' : rtl && al.x === 'end' ? 'start' : al.x;\n const p = pad();\n return {\n x: p + (v.width - 2 * p) * alignFraction(ax),\n y: p + (v.height - 2 * p) * alignFraction(al.y),\n };\n };\n const anchorPoint = (): S.Point => alignPoint(ctx.getState().anchorAlign, vp());\n\n /** Fit-box for resolving the zoom intent: whole scene (fit-all), the current item\n * (paged — per-page fit), or the document max (continuous — doc-stable zoom). */\n const fitBox = (item: S.SceneItem): S.Size => {\n if (isFitAll()) return buildScene().size;\n return paged() ? { width: item.width, height: item.height } : buildScene().maxItemSize;\n };\n /** Clamp rect for a camera write targeting this item (scene-wide in continuous). */\n const boundsFor = (it: S.SceneItem): S.Rect => (paged() ? itemRect(it) : sceneRect());\n /** Clamp rect for a \"stay\" write (pan/zoom): the slice item (paged) / the scene. */\n const stayBounds = (): S.Rect => (paged() ? itemRect(buildScene().items[0]) : sceneRect());\n\n const constraint = (): S.CameraConstraint => ({\n bounded: ctx.getState().bounded,\n padding: pad(),\n fitAlign: ctx.getState().fitAlign,\n direction: ctx.getState().direction,\n });\n\n // Behavioral latch: flips when initial placement STARTS, while state.placed\n // is the render-commit latch that flips only after placement finishes. The\n // distinction keeps placement-time camera behavior unchanged while making\n // partial geometry unobservable to renderers.\n let placementStarted = false;\n\n // ── gesture transaction (touch pan/pinch) ───────────────────────────────────\n // While open: zoomAround defers its intent PATCH, and the rest countdown is\n // held — a hesitation inside a pinch is not \"at rest\". Depth-counted so\n // nested brackets compose. An ELASTIC gesture may additionally hold the\n // camera past the clamp (rubber-band); `gestureRaw` is its unclamped,\n // finger-integrated camera — the resistance curve maps it to what renders.\n let gestureDepth = 0;\n let gestureZoomed = false;\n let gestureElastic = false;\n let gestureRaw: S.Camera | null = null;\n\n // ── camera-rest detector ────────────────────────────────────────────────────\n // A continuous zoom and a device-snapped origin cannot coexist without the\n // anchor point jittering (each step rounds differently, ±0.5 device px per\n // axis). So origin snapping is gated on REST: fractional placement while\n // the zoom moves, one snap when it settles — when crispness matters. The\n // window is counted in scheduler frames (the same timing seam the tween\n // uses), so tests stay deterministic.\n const REST_MS = 150;\n let restRaf = 0;\n const armRest = () => {\n // Initial placement snaps immediately (first paint is crisp), and an\n // environment without real frames keeps snapping always-on — rest-gating\n // is a live-gesture refinement, not a contract.\n if (!canAnimate || !placementStarted) return;\n if (ctx.getState().cameraResting) ctx.dispatch({ type: 'CAMERA_REST', resting: false });\n if (restRaf) scheduler.caf(restRaf);\n let t0 = 0;\n const tick = (ts: number) => {\n restRaf = 0;\n if (!t0) t0 = ts;\n if (ts - t0 >= REST_MS) {\n ctx.dispatch({ type: 'CAMERA_REST', resting: true });\n return;\n }\n restRaf = scheduler.raf(tick);\n };\n restRaf = scheduler.raf(tick);\n };\n\n // The ONE low-level camera write: clamp to `bounds`, dispatch. MECHANISM only —\n // it never touches the cursor (see syncCursorFromCamera for the policy).\n const setCam = (next: S.Camera, bounds: S.Rect = stayBounds()) => {\n const clamped = S.clampCamera(next, bounds, vp(), constraint());\n if (clamped.zoom !== cam().zoom) {\n if (gestureDepth > 0) {\n // Mid-gesture: un-rest immediately (fractional placement) but hold the\n // 150 ms countdown — rest is declared at endGesture, not at a pinch\n // hesitation.\n gestureZoomed = true;\n if (ctx.getState().cameraResting) ctx.dispatch({ type: 'CAMERA_REST', resting: false });\n if (restRaf) {\n scheduler.caf(restRaf);\n restRaf = 0;\n }\n } else {\n armRest();\n }\n }\n ctx.dispatch({ type: 'CAMERA', camera: clamped });\n };\n\n // ── rubber-band (elastic overscroll) ────────────────────────────────────────\n // The curve pair lives in motion.ts; these are its STATE adapters. One rule\n // governs where the rubber exists at all: it softens only the edges of a\n // scroll RANGE. An axis whose content FITS the viewport has no travel — the\n // clamp holds it at its fitAlign rest, and it stays rigid however hard the\n // finger tugs (the UIScrollView default: bouncing exists only where content\n // exceeds bounds).\n const axisTravels = (origin: number, content: number, view: number, zoom: number): boolean =>\n !S.travelRange(origin, content, view, zoom, constraint().padding).fits;\n /** Unclamped finger-integrated camera → the DISPLAYED camera: clamp, then\n * re-apply the overshoot through the resistance curve, per travelling axis.\n * Inside the bounds this is exactly the clamp (rubber of zero is zero);\n * on a fitting axis it is exactly the clamp ALWAYS. */\n const rubberize = (raw: S.Camera): S.Camera => {\n const clamped = S.clampCamera(raw, stayBounds(), vp(), constraint());\n const v = vp();\n const b = stayBounds();\n const axis = (rawA: number, clampedA: number, dim: number, travels: boolean): number => {\n if (!travels) return clampedA;\n const dWorld = rawA - clampedA;\n if (dWorld === 0) return clampedA;\n const out = rubberOut(Math.abs(dWorld) * raw.zoom, Math.max(1, dim));\n return clampedA + (Math.sign(dWorld) * out) / raw.zoom;\n };\n return {\n zoom: raw.zoom,\n x: axis(raw.x, clamped.x, v.width, axisTravels(b.x, b.width, v.width, raw.zoom)),\n y: axis(raw.y, clamped.y, v.height, axisTravels(b.y, b.height, v.height, raw.zoom)),\n };\n };\n /** Displayed camera → the raw position `rubberize` would have produced it\n * from. Overshoot is capped just under the asymptote so the inverse stays\n * finite whatever state a catch finds the camera in. */\n const unrubberize = (displayed: S.Camera): S.Camera => {\n const clamped = S.clampCamera(displayed, stayBounds(), vp(), constraint());\n const v = vp();\n const b = stayBounds();\n const axis = (dispA: number, clampedA: number, dim: number, travels: boolean): number => {\n if (!travels) return clampedA;\n const dWorld = dispA - clampedA;\n if (dWorld === 0) return clampedA;\n const d = Math.max(1, dim);\n const out = Math.min(Math.abs(dWorld) * displayed.zoom, d - 1);\n return clampedA + (Math.sign(dWorld) * rubberIn(out, d)) / displayed.zoom;\n };\n return {\n zoom: displayed.zoom,\n x: axis(displayed.x, clamped.x, v.width, axisTravels(b.x, b.width, v.width, displayed.zoom)),\n y: axis(displayed.y, clamped.y, v.height, axisTravels(b.y, b.height, v.height, displayed.zoom)),\n };\n };\n // The elastic write path: NO clamp — used only by the elastic pan and the\n // edge spring, whose math guarantees every trajectory terminates clamped.\n const setCamRaw = (c: S.Camera) => ctx.dispatch({ type: 'CAMERA', camera: c });\n\n /**\n * Cursor reconciliation, one direction per interaction:\n * navigation → cursor is INTENT, set explicitly; the camera honors it as far\n * as the clamp allows — and a clamped camera never revokes it.\n * manipulation → (pan / drag / pinch) the camera moves freely; the cursor is\n * DERIVED from it. Only those verbs call this. Paged never syncs.\n */\n const syncCursorFromCamera = () => {\n if (paged()) return;\n const sc = buildScene();\n if (!sc.itemCount) return;\n const page = S.anchorFromCamera(cam(), sc, vp()).pageIndex;\n if (page !== ctx.getState().cursor) ctx.dispatch({ type: 'CURSOR', cursor: page });\n };\n\n // ── camera tween (impure shell concern; uses the injected Scheduler) ─────────\n let raf = 0;\n const cancelAnim = () => {\n if (raf) {\n scheduler.caf(raf);\n raf = 0;\n }\n };\n const lerp = (a: number, b: number, k: number) => a + (b - a) * k;\n // The tween clamps to an EXPLICIT bounds rect every frame (never a re-derived\n // current item), so animating toward a different item isn't clamped back.\n // `then` runs on natural completion only — a cancelled tween belongs to the\n // verb that cancelled it.\n const animateTo = (target: S.Camera, bounds: S.Rect, ms = 240, then?: () => void) => {\n if (!canAnimate) {\n setCam(target, bounds);\n then?.();\n return;\n }\n cancelAnim();\n const from = cam();\n let started = false;\n let t0 = 0;\n const tick = (now: number) => {\n if (!started) {\n started = true;\n t0 = now; // anchor to the first real timestamp (works even when now === 0)\n }\n const k = easeOutCubic(Math.min(1, (now - t0) / ms));\n setCam(\n {\n x: lerp(from.x, target.x, k),\n y: lerp(from.y, target.y, k),\n zoom: lerp(from.zoom, target.zoom, k),\n },\n bounds,\n );\n if (k < 1) {\n raf = scheduler.raf(tick);\n } else {\n raf = 0;\n then?.();\n }\n };\n raf = scheduler.raf(tick);\n };\n\n /**\n * Zoom-anchored tween — animates THE INVARIANT, not the coordinates. A\n * camera move is defined by what it holds fixed; for an anchored zoom that\n * is \"the focal page-point stays at `pt` while scale changes\". Lerping\n * x/y/zoom independently (the plain tween) breaks that mid-flight: holding\n * a screen point requires `x(t) = focal.x − pt.x / zoom(t)` — hyperbolic in\n * the zoom — so linear coordinates swing the tapped point along a curved\n * path (the visible \"dip\"). Here the zoom interpolates GEOMETRICALLY\n * (constant rate — zoom is multiplicative) and each frame's camera derives\n * from the anchor at that zoom, then clamps: the focal point is stationary\n * by construction, and a zoom-out rails into its fit progressively as the\n * shrinking travel range lets the clamp take over.\n */\n const animateZoomAnchored = (\n focal: S.Anchor,\n pt: S.Point,\n targetZoom: number,\n ms = 240,\n then?: () => void,\n ) => {\n if (!canAnimate) {\n const sc = buildScene();\n if (sc.itemCount) setCam(S.cameraForAnchorAtScreen(focal, sc, pt, targetZoom));\n then?.();\n return;\n }\n cancelAnim();\n const z0 = cam().zoom;\n let started = false;\n let t0 = 0;\n const tick = (now: number) => {\n if (!started) {\n started = true;\n t0 = now;\n }\n const k = easeOutCubic(Math.min(1, (now - t0) / ms));\n const z = zoomLerp(z0, targetZoom, k);\n const sc = buildScene();\n if (sc.itemCount) setCam(S.cameraForAnchorAtScreen(focal, sc, pt, z));\n if (k < 1) {\n raf = scheduler.raf(tick);\n } else {\n raf = 0;\n then?.();\n }\n };\n raf = scheduler.raf(tick);\n };\n\n // Momentum + edge physics — the driver over motion.ts's per-axis laws:\n // glide — the touch fling, decaying on UIScrollView's curve across free\n // travel;\n // spring — a critically-damped return to the clamp, entered when a glide\n // reaches a content edge (remaining velocity becomes the bounce)\n // or when the motion STARTS displaced (release while stretched).\n // Axes are independent (a diagonal fling can bounce off the bottom while\n // still gliding horizontally). Every trajectory terminates ON the clamp.\n // Shares the `raf` handle with the tween, so cancelAnim() — every verb's\n // first act — is also \"catch\": catching mid-bounce holds the stretch.\n const startCameraPhysics = (vxFinger: number, vyFinger: number) => {\n if (!canAnimate) {\n setCam(cam()); // no host frames: snap straight into bounds\n return;\n }\n cancelAnim();\n const zoom = cam().zoom;\n // Per-axis state in camera-space SCREEN px (the camera moves OPPOSITE the\n // finger; positions scale by zoom once, here, so the laws read in px).\n interface AxisState {\n p: number;\n v: number;\n springing: boolean;\n done: boolean;\n }\n const c0 = cam();\n const cl0 = S.clampCamera(c0, stayBounds(), vp(), constraint());\n const b0 = stayBounds();\n const v0 = vp();\n const mk = (camA: number, clampedA: number, fingerV: number): AxisState => ({\n p: camA * zoom,\n v: -fingerV / 1000,\n springing: camA !== clampedA,\n done: false,\n });\n // A fitting axis takes no ballistic motion: no travel to glide across and\n // no bounce (rigid, like the platform) — release velocity is discarded.\n // The spring stays armed for a DISPLACED fitting axis (repair to rest).\n const ax = mk(c0.x, cl0.x, axisTravels(b0.x, b0.width, v0.width, zoom) ? vxFinger : 0);\n const ay = mk(c0.y, cl0.y, axisTravels(b0.y, b0.height, v0.height, zoom) ? vyFinger : 0);\n if (!ax.springing && !ay.springing && Math.hypot(ax.v, ay.v) < FLING_STOP) return;\n let started = false;\n let last = 0;\n const tick = (now: number) => {\n raf = 0;\n // First frame assumes one 60Hz step (anchoring like the tween — works\n // even when the first timestamp is 0).\n const dt = started ? Math.min(64, Math.max(1, now - last)) : 16;\n started = true;\n last = now;\n // The clamp of the CURRENT position is each axis's home this frame: for\n // a stretched axis it is the edge; for a fitting axis, its rest point.\n const cl = S.clampCamera(\n { x: ax.p / zoom, y: ay.p / zoom, zoom },\n stayBounds(),\n vp(),\n constraint(),\n );\n const step = (a: AxisState, edgeWorld: number) => {\n if (a.done) return;\n const r = a.springing\n ? springStep(a.p, a.v, edgeWorld * zoom, dt)\n : glideStep(a.p, a.v, dt);\n a.p = r.p;\n a.v = r.v;\n a.done = r.done;\n };\n step(ax, cl.x);\n step(ay, cl.y);\n // A glide that left the travel range converts to a spring AT the edge —\n // the incoming velocity carries in, so the bounce grows out of physics\n // rather than a scripted overshoot.\n const ncl = S.clampCamera(\n { x: ax.p / zoom, y: ay.p / zoom, zoom },\n stayBounds(),\n vp(),\n constraint(),\n );\n const convert = (a: AxisState, clampedA: number) => {\n if (!a.springing && Math.abs(clampedA * zoom - a.p) > 1e-6) {\n a.p = clampedA * zoom;\n a.springing = true;\n a.done = false;\n }\n };\n convert(ax, ncl.x);\n convert(ay, ncl.y);\n setCamRaw({ x: ax.p / zoom, y: ay.p / zoom, zoom });\n syncCursorFromCamera();\n if (ax.done && ay.done) {\n setCam(cam()); // exact landing: clamped, snapped, settled\n return;\n }\n raf = scheduler.raf(tick);\n };\n raf = scheduler.raf(tick);\n };\n\n // ── anchor: the durable \"what am I looking at\". Capture before a structural\n // change, re-apply after — one mechanism for layout/spread/zoom/resize/restore.\n // WHERE in the viewport the anchor lives is the reframe's invariant policy:\n // anchorAlign for reframes (resize, scene changes), zoomAlign for pure\n // zoom-intent changes. Capture and restore always use the SAME point.\n const anchorAt = (at: S.Point): S.Anchor => {\n const sc = buildScene();\n return sc.itemCount\n ? S.anchorFromCamera(cam(), sc, vp(), at)\n : { pageIndex: ctx.getState().cursor, fx: 0.5, fy: 0 };\n };\n const currentAnchor = (): S.Anchor => anchorAt(anchorPoint());\n\n /**\n * Run a placement whose RESOLVED zoom may change the scene (wrapped mode: zoom is\n * a layout input). Re-run it until the scene it placed against is the scene that\n * results — every non-wrapped mode is stable after the first pass by construction,\n * and wrapped fit-modes converge on the second (the fit-box is wrap-independent).\n * Capped at 3 passes for the one genuinely circular case (fit-all + wrapped).\n */\n const stabilized = (place: () => void) => {\n for (let attempt = 0; attempt < 3; attempt++) {\n const scene = buildScene();\n place();\n if (buildScene() === scene) return;\n }\n };\n\n const applyAnchor = (anchor: S.Anchor, align?: S.AlignmentValue) => {\n stabilized(() => {\n const scene = buildScene();\n if (!scene.itemCount) return;\n const item = scene.items[scene.itemOfPage(anchor.pageIndex)];\n const zoom = S.resolveZoom(ctx.getState().zoom, fitBox(item), vp(), pad());\n // resolved against the CURRENT viewport — a resize restores the anchor to\n // the new viewport's policy point (start/start: the top stays pinned)\n const at = alignPoint(align ?? ctx.getState().anchorAlign, vp());\n setCam(S.cameraFromAnchor(anchor, scene, vp(), zoom, at), boundsFor(item));\n });\n };\n /**\n * Re-apply the view after a structural/zoom/viewport change. Normally anchor-\n * preserving (keep looking at the same spot, held at the invariant point).\n * Under fit-all the subject is the WHOLE scene, so \"keep my anchor\" is\n * meaningless — re-place instead (this is what centers the scene even when\n * unbounded).\n */\n const reapply = (anchor: S.Anchor, align?: S.AlignmentValue) => {\n if (isFitAll()) goToTarget(ctx.getState().cursor, { behavior: 'instant' });\n else applyAnchor(anchor, align);\n };\n\n // ── navigation: ONE arrival procedure for goToPage / next / prev / reset ─────\n // Navigation is CANONICAL: goToPage(N) always ends in the same camera state,\n // regardless of where you came from, what happens to be visible, or how zoomed\n // you are (no zoom-dependent landing — that's a discontinuity at the fit\n // threshold).\n // 1. move the cursor to the target page (paged: rebuilds the one-item slice),\n // 2. choose the SUBJECT by the fits-predicate (scene under fit-all; the item if\n // it fits; else the page),\n // 3. placeCamera(subject) lands it at arrivalAlign — the same rule at every\n // zoom — and setCam clamps against the TRUE bounds, which collapses any\n // axis with no freedom to the fitAlign rest point.\n // The legitimate \"nothing moves\" cases are STRUCTURAL, not conditional: under\n // fit-all the canonical placement is the centered scene, which doesn't change.\n /** Tag what drives the NEXT camera/cursor change — dispatched on flips\n * only, read by the page-state feed (see StageState.motionCause). */\n const markCause = (cause: 'user' | 'programmatic'): void => {\n if (ctx.getState().motionCause !== cause) ctx.dispatch({ type: 'MOTION_CAUSE', cause });\n };\n\n const goToTarget = (pageIndex: number, opts?: GoToOptions) => {\n markCause('programmatic');\n cancelAnim();\n const doc = ctx.document();\n if (!doc || doc.pageCount === 0) return;\n const target = Math.max(0, Math.min(pageIndex, doc.pageCount - 1));\n if (target !== ctx.getState().cursor) ctx.dispatch({ type: 'CURSOR', cursor: target });\n\n // Restore path (per-page view memory): exact viewpoint instead of fresh placement.\n if (opts?.viewpoint) {\n ctx.dispatch({ type: 'PATCH', patch: { zoom: opts.viewpoint.zoom } });\n applyAnchor(opts.viewpoint.anchor);\n return;\n }\n\n // Placement against the CURRENT scene; null when there is nothing to place.\n const placement = (): { camera: S.Camera; bounds: S.Rect } | null => {\n const sc = buildScene(); // paged: the (possibly new) slice; continuous: full scene\n if (!sc.itemCount) return null;\n const item = paged() ? sc.items[0] : sc.items[itemIndexOfPage(target)];\n const zoom = S.resolveZoom(ctx.getState().zoom, fitBox(item), vp(), pad());\n const subject = isFitAll()\n ? sceneRect()\n : fits(itemRect(item), zoom)\n ? itemRect(item)\n : pageRectOf(item, target);\n // The landing policy: a per-call override beats the setting (explicit\n // beats default); 'keep' pins that axis to the current camera.\n const want = { ...ctx.getState().arrivalAlign, ...opts?.arrivalAlign };\n const placed = S.placeCamera(\n subject,\n vp(),\n zoom,\n pad(),\n {\n x: want.x === 'keep' ? 'start' : want.x,\n y: want.y === 'keep' ? 'start' : want.y,\n },\n ctx.getState().direction,\n );\n // Arrivals are canonical even on an UNBOUNDED stage: the landing clamps\n // within the true bounds regardless (free roam is a manipulation\n // affordance, not an arrival one) — an axis with no freedom collapses to\n // its fitAlign rest here, and the fit-all scene centers even unbounded.\n const bounds = boundsFor(item);\n const settled = S.clampCamera(placed, bounds, vp(), { ...constraint(), bounded: true });\n return {\n camera: {\n zoom,\n x: want.x === 'keep' ? cam().x : settled.x,\n y: want.y === 'keep' ? cam().y : settled.y,\n },\n bounds,\n };\n };\n\n if ((opts?.behavior ?? ctx.getState().scrollBehavior) === 'smooth') {\n const p = placement();\n if (p) animateTo(p.camera, p.bounds);\n } else {\n // instant placement converges with the scene (wrapped: zoom is a layout input)\n stabilized(() => {\n const p = placement();\n if (p) setCam(p.camera, p.bounds);\n });\n }\n };\n\n /** Step by the navigation unit: the ITEM when it fits the viewport, else the PAGE. */\n const step = (direction: 1 | -1, opts?: GoToOptions) => {\n const st = ctx.getState();\n const item = cursorItem();\n if (!item) return;\n const { grouping: g } = grouping();\n if (isFitAll() || fits(itemRect(item), cam().zoom)) {\n const idx = Math.max(0, Math.min(itemIndexOfPage(st.cursor) + direction, g.length - 1));\n goToTarget(g[idx][0], opts);\n } else {\n goToTarget(st.cursor + direction, opts);\n }\n };\n\n // pon (durable identity) for a page's display index, from the registry captured at open.\n const ponForIndex = (index: number): number =>\n ctx.document()?.pages[index]?.pageObjectNumber ?? index + 1;\n\n // Fallback un-rotated point size from a laid-out box, when the registry entry is\n // momentarily absent. `displaySize` is its own inverse (display box → content\n // box); ÷ contentScale recovers points.\n const unrotatedPoints = (box: S.PageBox): S.Size => {\n const content = displaySize({ width: box.width, height: box.height }, box.rotation);\n return { width: content.width / box.contentScale, height: content.height / box.contentScale };\n };\n\n // Attach durable identity + the per-page transform (PDF points → view px →\n // device px). `scale` is view px per point = contentScale (world per point) ×\n // zoom (view px per world); `pageSize` is the page's UN-rotated points from the\n // registry. Camera-invariant (only zoom/rotation/contentScale/dpr), so the same\n // box always yields the same transform regardless of pan.\n const withTransform = (box: S.PageBox): VisiblePage => {\n const reg = ctx.document()?.pages[box.pageIndex];\n const pageSize = reg\n ? { width: reg.size.width, height: reg.size.height }\n : unrotatedPoints(box);\n const c = cam();\n const ratio = dpr();\n // Footprint top-left (camera-resolved). Device-snapped AT REST — keeps a\n // rotated page on the device grid; while the zoom is in motion it places\n // fractionally, because snapping mid-zoom makes the anchor point jitter\n // ±0.5 device px per step (see StageState.cameraResting).\n const rawX = (box.x - c.x) * c.zoom;\n const rawY = (box.y - c.y) * c.zoom;\n const resting = ctx.getState().cameraResting;\n const screenX = resting ? snapToDevice(rawX, ratio) : rawX;\n const screenY = resting ? snapToDevice(rawY, ratio) : rawY;\n const transform = pageTransform({\n pageSize,\n rotation: box.rotation,\n scale: box.contentScale * c.zoom,\n // The page's PHYSICAL 100%: platform unit factor × its /UserUnit — so\n // `transform.zoom` reads as \"percent of Acrobat's 100%\" per page,\n // independent of sizing mode or camera state.\n baseScale: ctx.getState().viewUnitsPerPoint * (reg?.userUnit ?? 1),\n dpr: ratio,\n });\n // The on-screen page region in points: viewport ∩ footprint in VIEW space\n // (both axis-aligned), inverted through the transform (exact for\n // quarter-turns). The same intersection the virtualizer's query already\n // decided coarsely — refined per page, once, HERE, so no adapter ever\n // re-derives camera math (tiling's demand reads this field).\n const v = vp();\n const onScreen = intersectRects(\n { x: -screenX, y: -screenY, width: v.width, height: v.height },\n { x: 0, y: 0, width: transform.viewWidth, height: transform.viewHeight },\n );\n const visibleRect =\n onScreen.width > 0 && onScreen.height > 0\n ? transform.viewToContentRect(onScreen)\n : { x: 0, y: 0, width: 0, height: 0 };\n return {\n ...box,\n pon: ponForIndex(box.pageIndex),\n screenX,\n screenY,\n transform,\n visibleRect,\n };\n };\n\n // The scroller projection — the camera in native DOM vocabulary, against the\n // SAME bounds the pan clamp uses (stayBounds: the slice item in paged flow,\n // the scene in continuous). Memoized like visiblePages: a stable reference\n // until a field actually moves, so adapter selectors can use plain equality.\n const EMPTY_SCROLL_METRICS: S.ScrollMetrics = {\n scrollLeft: 0,\n scrollTop: 0,\n scrollWidth: 0,\n scrollHeight: 0,\n clientWidth: 0,\n clientHeight: 0,\n scrollableX: false,\n scrollableY: false,\n };\n let scrollMemo: S.ScrollMetrics | null = null;\n const scrollMetricsNow = (): S.ScrollMetrics => {\n if (!ctx.getState().placed) return EMPTY_SCROLL_METRICS;\n const sc = buildScene();\n const m = S.scrollMetrics(\n cam(),\n sc.itemCount ? stayBounds() : { x: 0, y: 0, width: 0, height: 0 },\n vp(),\n pad(),\n );\n const p = scrollMemo;\n if (\n p &&\n p.scrollLeft === m.scrollLeft &&\n p.scrollTop === m.scrollTop &&\n p.scrollWidth === m.scrollWidth &&\n p.scrollHeight === m.scrollHeight &&\n p.clientWidth === m.clientWidth &&\n p.clientHeight === m.clientHeight\n ) {\n return p; // scrollableX/Y derive from the numbers — covered by the six\n }\n scrollMemo = m;\n return m;\n };\n\n // Memoized visiblePages -> stable reference (no useSyncExternalStore tearing loop).\n // Paged renders ONLY the slice's item; continuous renders the camera's query window.\n const EMPTY_VISIBLE_PAGES: VisiblePage[] = [];\n let visSig = '';\n let vis: VisiblePage[] = [];\n const visiblePages = (): VisiblePage[] => {\n if (!ctx.getState().placed) return EMPTY_VISIBLE_PAGES;\n const c = cam();\n const v = vp();\n const sc = buildScene();\n const items = paged() ? sc.items.slice(0, 1) : sc.query(S.cameraWorldRect(c, v));\n const sig = `${sceneCache!.key}|${ctx.getState().flow}|${c.x},${c.y},${c.zoom}|${v.width}x${v.height}|${dpr()}|r${ctx.getState().cameraResting ? 1 : 0}`;\n if (sig === visSig) return vis;\n visSig = sig;\n vis = items.flatMap((it) => it.pages).map(withTransform);\n return vis;\n };\n\n // The settings slice of a larger object (state, or a saved view) — derived from\n // the registry, so the shape is never spelled out by hand again.\n const pickSettings = (src: StageSettings): StageSettings => {\n const out: Partial<Record<keyof StageSettings, unknown>> = {};\n for (const k of SETTING_KEYS) out[k] = src[k];\n return out as StageSettings;\n };\n const snapshotSettings = (): StageSettings => pickSettings(ctx.getState());\n\n /**\n * Settings change, reacted per the registry — the strongest effect among the\n * touched settings wins: 'reflow' ⊃ 'scene'/'refit' ⊃ 'reclamp' ⊃ 'none'.\n * The ONE reactive applier: the public `update()` and the responsive driver\n * both land here, so a breakpoint crossing gets exactly the invariant a\n * hand-written update would.\n */\n const applySettings = (patch: Partial<StageSettings>) => {\n cancelAnim();\n const touched = (effect: SettingEffect) =>\n SETTING_KEYS.some((k) => patch[k] !== undefined && SETTINGS_EFFECT[k] === effect);\n // The change's INVARIANT point: a pure zoom-intent change ('refit' alone)\n // holds the zoomAlign focal point — zoomTo/fit-mode switches magnify\n // around the same spot the zoom buttons do; every other reframe holds\n // the anchorAlign reference. Resolved once, used for capture AND restore.\n const align =\n touched('refit') && !touched('scene') && !touched('reflow')\n ? ctx.getState().zoomAlign\n : ctx.getState().anchorAlign;\n const anchor = anchorAt(alignPoint(align, vp())); // capture against the current scene\n ctx.dispatch({ type: 'PATCH', patch });\n if (touched('scene')) sceneCache = null;\n if (touched('reflow')) {\n // flow toggled: re-place onto the cursor's page under the new flow's scene\n // (the camera's coordinates are meaningless across the flow boundary).\n goToTarget(ctx.getState().cursor, { behavior: 'instant' });\n } else if (touched('scene') || touched('refit')) {\n reapply(anchor, align); // rebuild + keep page + re-fit (fit-all: re-place the scene)\n } else if (touched('reclamp')) {\n setCam(cam()); // clamp policy changed: just re-clamp the current camera\n }\n // 'none' (arrivalAlign, zoomAlign, anchorAlign, scrollBehavior): future verbs only\n };\n\n // ── responsive settings (container queries for the settings bag) ─────────────\n // BASE (config + runtime setters) ⊕ matching rules' patches = the EFFECTIVE\n // settings the reducer holds. Rules assert at TRANSITIONS — box, base, or\n // rules changes — which is why the sync diffs against the last EFFECTIVE\n // resolution, never against live state: between crossings interaction owns\n // the state (a pinch-zoomed level survives a resize unless a rule actually\n // flips), and keys the rules don't touch never get re-asserted.\n let base = snapshotSettings();\n let rules: readonly ResponsiveRule[] = config.responsive ?? DEFAULT_RESPONSIVE;\n let lastEffective = base; // rules first assert when a real box arrives\n const publishActive = (active: readonly string[]) => {\n const prev = ctx.getState().activeRules;\n if (prev.length !== active.length || active.some((n, i) => n !== prev[i])) {\n ctx.dispatch({ type: 'RESPONSIVE', active });\n }\n };\n /**\n * Re-resolve and apply what CHANGED since the last resolution. `react: true`\n * routes the patch through `applySettings` (full anchor-preserving update);\n * `react: false` (inside `setViewport`, whose caller runs its own reframe)\n * just lands the patch + cache invalidation and reports the strongest\n * effect so the caller can escalate a rule-driven flow flip.\n */\n const syncResponsive = (react: boolean): SettingEffect => {\n const { effective, active } = resolveResponsive(base, rules, boxOf(vp()));\n const patch: Partial<StageSettings> = {};\n for (const k of SETTING_KEYS) {\n if (!eqSetting(effective[k], lastEffective[k])) {\n Object.assign(patch, { [k]: effective[k] });\n }\n }\n lastEffective = effective;\n publishActive(active);\n const keys = Object.keys(patch) as Array<keyof StageSettings>;\n if (keys.length === 0) return 'none';\n if (react) {\n applySettings(patch);\n return 'none'; // reacted in full — nothing left for the caller\n }\n ctx.dispatch({ type: 'PATCH', patch });\n const rank: Record<SettingEffect, number> = { none: 0, reclamp: 1, refit: 2, scene: 3, reflow: 4 };\n let strongest: SettingEffect = 'none';\n for (const k of keys) if (rank[SETTINGS_EFFECT[k]] > rank[strongest]) strongest = SETTINGS_EFFECT[k];\n if (strongest === 'scene' || strongest === 'reflow') sceneCache = null;\n return strongest;\n };\n\n // Initial-view providers (storage restore, deep-link, an explicit prop…). One owner\n // (placeInitial) resolves them by priority — no effect-ordering races.\n // (`placementStarted` is declared above the camera-rest detector, which reads it.)\n const initialViewProviders: Array<{ priority: number; fn: () => StageViewState | null }> = [];\n\n const api: StageCapability = {\n // ── selectors ──\n camera: cam,\n viewport: vp,\n scrollMetrics: scrollMetricsNow,\n pageCount: () => ctx.document()?.pageCount ?? 0,\n visiblePages,\n currentPage: () => ctx.getState().cursor,\n currentItemPages: () => {\n const item = cursorItem();\n return item ? [...item.pageIndexes] : [];\n },\n pages: () =>\n (ctx.document()?.pages ?? []).map((p) => ({\n index: p.index,\n pon: p.pageObjectNumber,\n label: p.label ?? null,\n })),\n pageRect: (pon) => {\n if (!ctx.getState().placed) return null;\n const meta = ctx.document();\n const index = meta ? meta.pages.findIndex((p) => p.pageObjectNumber === pon) : -1;\n if (index < 0) return null;\n const sc = buildScene();\n if (!sc.itemCount) return null;\n const box = sc.items[sc.itemOfPage(index)].pages.find((p) => p.pageIndex === index);\n return box ? withTransform(box) : null;\n },\n pageAt: (screen) => {\n // Find the visible page whose device-snapped display box contains the\n // point, then invert that page's transform — same `viewToContent` the\n // per-page PageContext.toContentPoint uses, so the two never drift.\n for (const p of visiblePages()) {\n const lx = screen.x - p.screenX;\n const ly = screen.y - p.screenY;\n if (lx >= 0 && ly >= 0 && lx <= p.transform.viewWidth && ly <= p.transform.viewHeight) {\n return {\n pon: p.pon,\n point: p.transform.viewToContent({ x: lx, y: ly }),\n scale: p.transform.viewScale,\n rotation: p.rotation,\n zoom: p.transform.zoom,\n };\n }\n }\n return null;\n },\n pointOnPage: (pon, screen) => {\n // `pageAt` minus the containment check: project onto ONE page's plane,\n // valid outside its bounds — the same inverse transform, so no drift.\n const p = visiblePages().find((v) => v.pon === pon);\n if (!p) return null;\n return p.transform.viewToContent({ x: screen.x - p.screenX, y: screen.y - p.screenY });\n },\n pageToWorld: (pon, pt) => {\n const pr = api.pageRect(pon);\n if (!pr) return null;\n // Place the content point into the page's display box via the SAME\n // quarter-turn matrix the layout/renderer use (`rotateScaleMatrix`) — so\n // this forward transform and the adapter's inverse hit-test (which inverts\n // the same matrix) can't drift. `displaySize` is its own inverse, so it\n // recovers the un-rotated content size from the display box.\n const content = displaySize({ width: pr.width, height: pr.height }, pr.rotation);\n const m = rotateScaleMatrix(pr.contentScale, content.width, content.height, pr.rotation);\n const offset = applyPoint(m, pt);\n return { x: pr.x + offset.x, y: pr.y + offset.y };\n },\n pageRectToScreen: (pon, rect) => {\n const pr = api.pageRect(pon);\n if (!pr) return null;\n const content = displaySize({ width: pr.width, height: pr.height }, pr.rotation);\n const m = rotateScaleMatrix(pr.contentScale, content.width, content.height, pr.rotation);\n const wr = applyRect(m, rect);\n const c = cam();\n const tl = S.toScreen(c, { x: pr.x + wr.x, y: pr.y + wr.y });\n return { x: tl.x, y: tl.y, width: wr.width * c.zoom, height: wr.height * c.zoom };\n },\n toScreen: (w) => S.toScreen(cam(), w),\n toWorld: (s) => S.toWorld(cam(), s),\n flow: () => ctx.getState().flow,\n layout: () => ctx.getState().layout,\n spread: () => ctx.getState().spread,\n sizing: () => ctx.getState().sizing,\n columns: () => ctx.getState().columns,\n bounded: () => ctx.getState().bounded,\n padding: () => ctx.getState().padding,\n gap: () => ctx.getState().gap,\n pageFrame: () => ctx.getState().pageFrame,\n fitAlign: () => ctx.getState().fitAlign,\n arrivalAlign: () => ctx.getState().arrivalAlign,\n zoomAlign: () => ctx.getState().zoomAlign,\n anchorAlign: () => ctx.getState().anchorAlign,\n direction: () => ctx.getState().direction,\n scrollBehavior: () => ctx.getState().scrollBehavior,\n viewRotation: () => ctx.getState().viewRotation,\n zoomLevel: () => cam().zoom,\n zoomMode: () => {\n const z = ctx.getState().zoom;\n return 'mode' in z ? z.mode : 'custom';\n },\n viewpoint: (): Viewpoint => ({ anchor: currentAnchor(), zoom: ctx.getState().zoom }),\n settings: snapshotSettings,\n viewState: (): StageViewState => ({\n ...snapshotSettings(),\n cursor: ctx.getState().cursor,\n anchor: currentAnchor(),\n }),\n\n // ── intents ──\n setViewport: (v) => {\n // Initial placement is LEVEL-triggered, owned here: the moment the stage\n // first learns a real size (both axes) and the document has pages, resolve\n // the initial view (storage/deep-link providers, else reset). Every report\n // re-checks the condition — no watch, no effect-registration race, no edge\n // to miss when the viewport was already sized before anyone listened.\n if (!placementStarted) {\n ctx.dispatch({ type: 'VP', vp: v });\n syncResponsive(false); // rules see the box before placement resolves\n if (v.width > 0 && v.height > 0 && (ctx.document()?.pageCount ?? 0) > 0) {\n api.placeInitial();\n }\n return;\n }\n // Afterwards every resize keeps the same page and re-resolves fit-modes.\n cancelAnim();\n const anchor = currentAnchor(); // measured against the OLD viewport\n ctx.dispatch({ type: 'VP', vp: v }); // new viewport\n // A breakpoint crossing rides the SAME reframe: the rule patch lands\n // before the anchor is re-applied, so the restore resolves under the\n // new settings. Only a rule-driven FLOW flip escalates past reapply\n // (camera coordinates are meaningless across the flow boundary).\n const fx = syncResponsive(false);\n if (fx === 'reflow') {\n goToTarget(ctx.getState().cursor, { behavior: 'instant' });\n } else {\n reapply(anchor);\n }\n },\n setDevicePixelRatio: (ratio) => {\n // Pure device-resolution change: it only affects each page transform's\n // device px (crispness) + sub-pixel box snapping, never the layout or\n // camera — so no re-place, just store it; visiblePages re-keys on dpr.\n if (ratio > 0 && ratio !== dpr()) ctx.dispatch({ type: 'DPR', dpr: ratio });\n },\n setCamera: (c) => {\n markCause('user');\n cancelAnim();\n setCam(c);\n syncCursorFromCamera();\n },\n panBy: (dx, dy) => {\n markCause('user');\n cancelAnim();\n if (gestureDepth > 0 && gestureElastic) {\n // Elastic: integrate the finger on the UNCLAMPED camera and display it\n // through the resistance curve. Initialized from the displayed camera's\n // inverse, so catching a mid-bounce stretch continues seamlessly.\n gestureRaw = S.panByScreen(gestureRaw ?? unrubberize(cam()), dx, dy);\n setCamRaw(rubberize(gestureRaw));\n } else {\n setCam(S.panByScreen(cam(), dx, dy));\n }\n syncCursorFromCamera();\n },\n scrollTo: (opts) => {\n markCause('user');\n cancelAnim();\n const sc = buildScene();\n if (!sc.itemCount) return;\n const next = S.cameraFromScroll(cam(), stayBounds(), vp(), pad(), opts);\n if (opts.behavior === 'smooth') {\n animateTo(next, stayBounds(), 240, syncCursorFromCamera);\n } else {\n setCam(next);\n syncCursorFromCamera();\n }\n },\n scrollBy: ({ left, top, behavior }) => {\n const m = scrollMetricsNow();\n api.scrollTo({\n left: left === undefined ? undefined : m.scrollLeft + left,\n top: top === undefined ? undefined : m.scrollTop + top,\n behavior,\n });\n },\n zoomAround: (pt, factor) => {\n cancelAnim();\n const before = buildScene();\n // page-relative focal point: the durable identity of \"what's under the cursor\"\n const focal = before.itemCount ? S.anchorAtPoint(before, S.toWorld(cam(), pt)) : null;\n setCam(S.zoomAround(cam(), pt, factor));\n // record the resulting fixed level as the zoom intent — focal, so no\n // re-anchor… deferred to endGesture inside a gesture bracket (one PATCH\n // per pinch instead of one per event).\n if (gestureDepth === 0) {\n ctx.dispatch({ type: 'PATCH', patch: { zoom: { level: cam().zoom } } });\n }\n // …UNLESS zoom is a LAYOUT INPUT (wrapped grid) and the scene just re-wrapped\n // underneath the camera. The old world point is stale then — re-pin the SAME\n // page-point under the cursor and clamp against the new geometry. In every\n // non-wrapped mode the scene reference is unchanged and this never runs.\n const after = buildScene();\n if (after !== before && focal && after.itemCount) {\n setCam(S.cameraForAnchorAtScreen(focal, after, pt, cam().zoom));\n }\n // A zoom write mid-elastic-gesture (pinch) re-bases the pan integrator:\n // bounds just changed shape under the stretch, so the displayed camera\n // becomes the new reference and resistance re-accumulates from here.\n if (gestureDepth > 0 && gestureElastic) gestureRaw = unrubberize(cam());\n syncCursorFromCamera();\n },\n beginGesture: (options) => {\n gestureDepth++;\n if (gestureDepth === 1) {\n cancelAnim(); // catch: the next touch-down stops any tween or fling\n gestureZoomed = false;\n gestureElastic = options?.elastic === true;\n gestureRaw = null;\n }\n },\n endGesture: () => {\n if (gestureDepth === 0) return;\n gestureDepth--;\n if (gestureDepth > 0) return;\n gestureRaw = null;\n const wasElastic = gestureElastic;\n gestureElastic = false;\n if (gestureZoomed) {\n gestureZoomed = false;\n // The deferred zoom intent: ONE patch for the whole gesture. (In a\n // wrapped grid this may re-wrap the scene; the next reframe\n // re-anchors through the normal update path.)\n ctx.dispatch({ type: 'PATCH', patch: { zoom: { level: cam().zoom } } });\n armRest(); // the gesture is over — NOW the 150 ms rest countdown runs\n }\n syncCursorFromCamera();\n if (wasElastic) {\n // Released while stretched → spring home. A fling() arriving right\n // after simply re-enters the same physics with the release velocity.\n const c = cam();\n const cl = S.clampCamera(c, stayBounds(), vp(), constraint());\n if (cl.x !== c.x || cl.y !== c.y) startCameraPhysics(0, 0);\n }\n },\n fling: (vx, vy) => startCameraPhysics(vx, vy),\n cameraInMotion: () => raf !== 0,\n doubleTapZoom: (pt) => {\n cancelAnim();\n const sc0 = buildScene();\n if (!sc0.itemCount) return;\n const item = paged() ? sc0.items[0] : sc0.items[itemIndexOfPage(ctx.getState().cursor)];\n // The ladder (the platform convention): ascending READING POSTURES, each\n // derived from a zoom intent — see the page (automatic), read the text\n // (fit-width), inspect (2.5× the automatic fit). Stops within 10% of a\n // neighbor collapse — on phones automatic IS fit-width, so the ladder\n // degenerates to the familiar two-state toggle.\n //\n // The rule (iOS's): the ladder ascends only from ON a rung — a tap at a\n // posture moves to the next, wrapping past the top. A pinch to any\n // OTHER level is leaving the ladder, and double-tap there is a RESET to\n // the base fit (\"take me back to reading\"), never a further zoom-in.\n const fit = fitBox(item);\n const auto = S.resolveZoom({ mode: S.ZoomMode.Automatic }, fit, vp(), pad());\n const fitW = S.resolveZoom({ mode: S.ZoomMode.FitWidth }, fit, vp(), pad());\n const stops = [auto, fitW, Math.min(auto * 2.5, S.ZOOM_MAX)]\n .sort((a, b) => a - b)\n .filter((z, i, all) => i === 0 || z > all[i - 1] * 1.1);\n // the same ±10% band the dedupe uses: \"at a posture\" tolerates fit drift\n const near = (z: number, stop: number) => z > stop / 1.1 && z < stop * 1.1;\n const onRung = stops.findIndex((s) => near(cam().zoom, s));\n const target = onRung >= 0 ? stops[(onRung + 1) % stops.length] : stops[0];\n // The INTENT commits UP FRONT (the `reveal` precedent): a caught tween\n // must never leave the camera on some intermediate zoom while the stored\n // intent still says \"fit\" — the next refit would snap somewhere the user\n // didn't ask for. Interrupted or not, the record says where we were going.\n ctx.dispatch({ type: 'PATCH', patch: { zoom: { level: target } } });\n // Wrapped grids re-layout on the intent change — anchor the focal point\n // against the scene that will actually be on screen.\n const sc = buildScene();\n if (!sc.itemCount) return;\n const focal = S.anchorAtPoint(sc, S.toWorld(cam(), pt));\n // The focal-anchored tween: the tapped point holds still by construction\n // (linear coordinate lerps would swing it mid-flight — the \"dip\").\n animateZoomAnchored(focal, pt, target, 240, syncCursorFromCamera);\n },\n // Pointer-less zooms magnify around the zoomAlign focal point (pinch and\n // wheel pass their own pointer to zoomAround — physics beats policy).\n zoomIn: () => api.zoomAround(alignPoint(ctx.getState().zoomAlign, vp()), 1.2),\n zoomOut: () => api.zoomAround(alignPoint(ctx.getState().zoomAlign, vp()), 1 / 1.2),\n zoomTo: (spec) => api.update({ zoom: spec }),\n fitWidth: () => api.update({ zoom: { mode: S.ZoomMode.FitWidth } }),\n fitPage: () => api.update({ zoom: { mode: S.ZoomMode.FitPage } }),\n fitAll: () => api.update({ zoom: { mode: S.ZoomMode.FitAll } }),\n automatic: () => api.update({ zoom: { mode: S.ZoomMode.Automatic } }),\n refit: () => {\n // The page geometry changed underneath us (rotate/move/delete). Treat it\n // exactly like a viewport resize: re-resolve the active zoom intent and\n // re-place against the now-current scene, keeping the anchored page-point.\n // No-op until the first placement; the scene is re-keyed on the registry\n // revision, so `reapply` reads the rotated footprint.\n if (!placementStarted) return;\n cancelAnim();\n reapply(currentAnchor());\n },\n goToPage: (pageIndex, opts) => goToTarget(pageIndex, opts),\n reveal: (pageIndex, opts) => {\n markCause('programmatic');\n const doc = ctx.document();\n if (!doc || doc.pageCount === 0) return;\n const target = Math.max(0, Math.min(pageIndex, doc.pageCount - 1));\n const positioned =\n !!opts &&\n // `rect: null` means \"no rect\", same as absent — so nullable sources\n // (`CommentThreadView.contentRect`) flow in without a `?? undefined`.\n (opts.rect != null ||\n opts.anchor !== undefined ||\n (opts.zoom !== undefined && opts.zoom !== 'keep'));\n\n if (!positioned) {\n // Bare reveal — NOT navigation: minimal visibility, cursor untouched.\n if (paged()) {\n // the page isn't in the one-item slice — revealing it IS navigating to it\n goToTarget(target, opts);\n return;\n }\n const sc = buildScene();\n if (!sc.itemCount) return;\n const page = pageRectOf(sc.items[itemIndexOfPage(target)], target);\n // Reveal the OUTER box: pageFrame chrome (labels, buttons) belongs to the\n // page, so \"make the page visible\" includes its reserved bands.\n const m = worldPageFrame();\n const box = {\n x: page.x - m.left,\n y: page.y - m.top,\n width: page.width + m.left + m.right,\n height: page.height + m.top + m.bottom,\n };\n const camera = S.revealCamera(cam(), box, vp(), pad());\n const current = cam();\n if (camera.x === current.x && camera.y === current.y) return; // already visible\n cancelAnim();\n if ((opts?.behavior ?? ctx.getState().scrollBehavior) === 'smooth') {\n animateTo(camera, sceneRect());\n } else {\n setCam(camera, sceneRect());\n }\n return;\n }\n\n // Positioned reveal: an ARRIVAL at a rect/point (search hit, PDF\n // destination). Like navigation, the cursor is INTENT — set up front\n // (paged: this also rebuilds the one-item slice), not derived from a\n // possibly mid-tween camera.\n cancelAnim();\n if (target !== ctx.getState().cursor) {\n ctx.dispatch({ type: 'CURSOR', cursor: target });\n }\n\n const place = (): { camera: S.Camera; bounds: S.Rect; zoomChanged: boolean } | null => {\n const sc = buildScene();\n if (!sc.itemCount) return null;\n const item = paged() ? sc.items[0] : sc.items[itemIndexOfPage(target)];\n const world = opts.rect\n ? worldRectForContent(item, target, opts.rect)\n : pageRectOf(item, target);\n const zd = opts.zoom ?? 'keep';\n const availW = Math.max(1, vp().width - 2 * pad());\n const availH = Math.max(1, vp().height - 2 * pad());\n let zoom =\n typeof zd === 'object'\n ? zd.level\n : zd === 'fit'\n ? Math.min(availW / world.width, availH / world.height)\n : zd === 'fit-width'\n ? availW / world.width\n : zd === 'fit-height'\n ? availH / world.height\n : cam().zoom;\n // Degenerate target (a point with a fit directive) → pan only.\n if (!Number.isFinite(zoom) || zoom <= 0) zoom = cam().zoom;\n const zoomChanged = zd !== 'keep';\n const a = opts.anchor ?? {};\n return {\n camera: {\n x: revealAxis(a.x, cam().x, world.x, world.width, vp().width, zoom, zoomChanged),\n y: revealAxis(a.y, cam().y, world.y, world.height, vp().height, zoom, zoomChanged),\n zoom,\n },\n bounds: boundsFor(item),\n zoomChanged,\n };\n };\n\n const first = place();\n if (!first) return;\n // A resolved zoom becomes the zoom intent (like zoomAround), so later\n // resizes/refits keep the destination's magnification.\n if (first.zoomChanged) {\n ctx.dispatch({ type: 'PATCH', patch: { zoom: { level: first.camera.zoom } } });\n }\n if ((opts.behavior ?? ctx.getState().scrollBehavior) === 'smooth') {\n // If the zoom patch re-wrapped the scene (zoom is a layout input in\n // wrapped mode), recompute once against the new geometry.\n const p = place() ?? first;\n animateTo(p.camera, p.bounds);\n } else {\n stabilized(() => {\n const p = place();\n if (p) setCam(p.camera, p.bounds);\n });\n }\n },\n next: (opts) => step(1, opts),\n prev: (opts) => step(-1, opts),\n lensId: () => ctx.id,\n update: (patch) => {\n // Writes the responsive BASE; the resolver decides what actually lands\n // (a matching rule's key wins until its rule stops matching). With no\n // rules in play this degenerates to exactly the old direct update.\n base = mergeSettings(base, patch);\n syncResponsive(true);\n },\n setResponsive: (next) => {\n rules = next;\n syncResponsive(true);\n },\n matches: (name) => ctx.getState().activeRules.includes(name),\n activeRules: () => ctx.getState().activeRules,\n setFlow: (flow) => api.update({ flow }),\n setLayout: (layout) => api.update({ layout }),\n setSpread: (spread) => api.update({ spread }),\n setSizing: (sizing) => api.update({ sizing }),\n setColumns: (columns) => api.update({ columns }),\n setBounded: (bounded) => api.update({ bounded }),\n setPadding: (padding) => api.update({ padding }),\n setGap: (gap) => api.update({ gap }),\n setPageFrame: (pageFrame) => api.update({ pageFrame }),\n setFitAlign: (fitAlign) => api.update({ fitAlign }),\n setArrivalAlign: (arrivalAlign) => api.update({ arrivalAlign }),\n setZoomAlign: (zoomAlign) => api.update({ zoomAlign }),\n setAnchorAlign: (anchorAlign) => api.update({ anchorAlign }),\n setDirection: (direction) => api.update({ direction }),\n setViewRotation: (viewRotation) => api.update({ viewRotation }),\n rotateView: (delta) =>\n api.setViewRotation(addRotations(ctx.getState().viewRotation, delta === 90 ? 90 : 270)),\n setScrollBehavior: (behavior) => api.update({ scrollBehavior: behavior }),\n applyViewState: (view) => {\n cancelAnim();\n // A restored view is app-level state: it writes the BASE, and the rules\n // re-assert on top — so a snapshot saved on a desktop restores compact\n // padding on a phone. One PATCH carries the full effective result.\n base = mergeSettings(base, pickSettings(view));\n const { effective, active } = resolveResponsive(base, rules, boxOf(vp()));\n lastEffective = effective;\n publishActive(active);\n ctx.dispatch({ type: 'PATCH', patch: effective });\n ctx.dispatch({ type: 'CURSOR', cursor: view.cursor ?? 0 });\n sceneCache = null;\n applyAnchor(view.anchor);\n },\n provideInitialView: (priority, fn) => {\n initialViewProviders.push({ priority, fn });\n },\n placeInitial: () => {\n placementStarted = true;\n const sorted = [...initialViewProviders].sort((a, b) => b.priority - a.priority);\n for (const p of sorted) {\n const view = p.fn();\n if (view) {\n api.applyViewState(view);\n ctx.dispatch({ type: 'PLACED' });\n return;\n }\n }\n api.resetView();\n // Publish renderability LAST. The VP/responsive/camera writes above are\n // still ordinary observable store updates, but page/scroll render-root\n // selectors return stable empty values until this commit lands.\n ctx.dispatch({ type: 'PLACED' });\n },\n // Home = page 0, a fresh arrival at arrivalAlign (the clamp collapses any\n // fitting axis to its fitAlign rest point).\n resetView: () => goToTarget(0, { behavior: 'instant' }),\n };\n return api;\n}\n","import type { CapabilityToken, EffectContext } from '@embedpdf/core';\nimport { ActionsToken as ActionsHostToken } from '@embedpdf/plugin-actions/contract/host';\nimport type { StageAction, StageCapability, StageState } from './types';\n\n/**\n * Stage lens effects.\n *\n * 1. Re-fit on page-registry mutations: when rotate/move/delete bump\n * `DocumentMeta.revision`, the page geometry under this lens changed, so\n * re-resolve the active zoom intent and re-place against the new\n * footprint. Steady-state only — it reacts to revision CHANGES, never the\n * initial value, so it can't race the capability's level-triggered\n * initial placement.\n *\n * 2. The page-state feed (main lens only, actions plugin present): stage is\n * AUTHORITATIVE for what page the viewer is on; the action engine's\n * lifecycle coordinator owns WHEN page-lifecycle triggers fire. This feed\n * pushes `{ currentPon, visiblePons, placed, cause }` snapshots — pons,\n * not indexes (reorder-safe) — on placement and on every change; the\n * coordinator buffers them behind the document-open barrier and diffs\n * against its last-emitted state, so this side stays a dumb reporter.\n */\nexport function registerStageEffects(\n ctx: EffectContext<StageState, StageAction>,\n token: CapabilityToken<StageCapability>,\n feedActions = false,\n): void {\n ctx.watch(\n () => ctx.document()?.revision ?? 0,\n () => ctx.get(token).refit(),\n );\n\n if (!feedActions) return;\n const actions = ctx.tryGet(ActionsHostToken);\n if (!actions) return;\n\n const snapshot = () => {\n const state = ctx.getState();\n if (!state.placed) return null;\n const stage = ctx.get(token);\n return {\n currentPon: stage.pages()[state.cursor]?.pon ?? null,\n visiblePons: stage.visiblePages().map((page) => page.pon),\n cause: state.motionCause,\n };\n };\n ctx.watch(\n // Signature over the REPORTABLE truth: current pon + the visible pon\n // set. `cause` is deliberately absent — a cause flip alone is not a\n // page-state change and must not produce a report.\n () => {\n const s = snapshot();\n return s === null\n ? 'unplaced'\n : `${s.currentPon ?? -1}|${[...s.visiblePons].sort((a, b) => a - b).join(',')}`;\n },\n () => {\n const s = snapshot();\n if (s === null) return;\n actions.reportPageState({\n currentPon: s.currentPon,\n visiblePons: s.visiblePons,\n placed: true,\n cause: s.cause,\n });\n },\n );\n}\n","import { DEFAULT_SETTINGS } from './settings';\nimport type { StageAction, StageConfig, StageSettings, StageState } from './types';\n\nexport const initialStageState = (config: StageConfig): StageState => {\n // `scheduler` and `responsive` are capability config, not settings — strip\n // them so the spread below stays a pure settings override.\n const { scheduler: _scheduler, responsive: _responsive, ...overrides } = config;\n return {\n camera: { x: 0, y: 0, zoom: 1 },\n placed: false,\n cameraResting: true,\n vp: { width: 0, height: 0 },\n dpr: 1,\n cursor: 0,\n motionCause: 'user',\n activeRules: [],\n ...DEFAULT_SETTINGS,\n ...overrides, // config overrides any default; the rest fall back to DEFAULT_SETTINGS\n };\n};\n\n/** Merge a settings patch, ignoring undefined values (safe for partial restores). */\nconst applyPatch = (state: StageState, patch: Partial<StageSettings>): StageState => {\n const next: StageState = { ...state };\n let key: keyof StageSettings;\n for (key in patch) {\n const value = patch[key];\n if (value !== undefined) Object.assign(next, { [key]: value });\n }\n return next;\n};\n\n/**\n * Pure. Every transition is here; nothing else mutates Stage state. Settings are a\n * flat bag of primitives — one PATCH action sets any subset (the capability decides\n * what camera follow-up, if any, each change needs).\n */\nexport const stageReducer = (state: StageState, a: StageAction): StageState => {\n switch (a.type) {\n case 'CAMERA':\n return { ...state, camera: a.camera };\n case 'CAMERA_REST':\n return state.cameraResting === a.resting ? state : { ...state, cameraResting: a.resting };\n case 'PLACED':\n return state.placed ? state : { ...state, placed: true };\n case 'VP':\n return { ...state, vp: a.vp };\n case 'DPR':\n return { ...state, dpr: a.dpr };\n case 'CURSOR':\n return { ...state, cursor: a.cursor };\n case 'MOTION_CAUSE':\n return { ...state, motionCause: a.cause };\n case 'PATCH':\n return applyPatch(state, a.patch);\n case 'RESPONSIVE':\n return { ...state, activeRules: a.active };\n default:\n return state;\n }\n};\n","import { definePlugin } from '@embedpdf/core';\nimport type { CapabilityToken } from '@embedpdf/core';\nimport { ActionsToken as PublicActionsToken } from '@embedpdf/plugin-actions/contract';\nimport { ActionsToken as ActionsHostToken } from '@embedpdf/plugin-actions/contract/host';\nimport { createStageCapability } from './capability';\nimport { destinationToReveal } from './destination';\nimport { registerStageEffects } from './effects';\nimport { initialStageState, stageReducer } from './reducer';\nimport { StageToken } from './types';\nimport type { StageAction, StageCapability, StageConfig, StageState } from './types';\n\n/**\n * Options for registering a stage instance. The Stage is a LENS, not a singleton:\n * a document may be viewed through several stages at once (the main view, a wrapped\n * thumbnail sidebar, …), each with independent camera/settings. Register additional\n * lenses by giving them their own `id` + `token`:\n *\n * const ThumbsToken = createCapabilityToken<StageCapability>('stage-thumbs');\n * plugins = [\n * stagePlugin(), // main lens\n * stagePlugin({ id: 'stage-thumbs', token: ThumbsToken,\n * layout: 'grid', columns: 'auto', zoom: { level: 0.2 } }),\n * ];\n *\n * Everything multiplexes automatically: state slices, capabilities, and teardown\n * are already keyed by plugin-id × document in the kernel.\n */\nexport interface StagePluginOptions extends StageConfig {\n id?: string;\n token?: CapabilityToken<StageCapability>;\n}\n\n/**\n * Wires the parts into a kernel plugin. This file is the \"manifest\": it says what\n * the plugin IS (id, token, state, reducer, capability) — the how lives in the\n * sibling files.\n */\nexport const stagePlugin = (options: StagePluginOptions = {}) => {\n const { id = 'stage', token = StageToken, ...config } = options;\n return definePlugin<StageState, StageAction, StageCapability>({\n id,\n token,\n scope: 'document', // one instance of THIS lens per open document\n optional: [PublicActionsToken],\n initialState: () => initialStageState(config),\n reduce: stageReducer,\n capability: (ctx) => createStageCapability(ctx, config),\n // Interaction opt-in lives with the SAMPLE SOURCE, not here: the surface\n // binding (`<Stage interaction>` / `createStageSurface`) both forwards\n // pointer samples AND registers this lens's scroll handler, lens-scoped —\n // one knob, and a handler can never exist without its input stream.\n // INITIAL placement is deliberately NOT an effect: it's LEVEL-triggered\n // inside the capability's setViewport (place when the stage first learns a\n // real size), so it cannot race effect registration. Other plugins only\n // *offer* initial views via provideInitialView; placeInitial resolves them\n // by priority. The one effect below is STEADY-STATE — it re-fits when the\n // page registry mutates (rotate/move/delete) and so has no such race.\n effects: (ctx) => registerStageEffects(ctx, token, id === 'stage'),\n init: (ctx) => {\n // Navigation executors for the action engine — registered by the\n // DEFAULT lens only (a thumbnail lens must never win the last-wins\n // registry and start navigating the sidebar). Executor bodies resolve\n // the stage capability at CALL time; the dispatcher invokes them as\n // DEFERRED navigation effects, never mid-walk.\n if (id !== 'stage') return;\n const actions = ctx.tryGet(ActionsHostToken);\n if (!actions) return;\n ctx.cleanup(\n actions.registerExecutor('goto', (node) => {\n if (node.type !== 'goto') return { status: 'inert', reason: 'not a goto node' };\n const stage = ctx.tryGet(token);\n const layout = ctx\n .document()\n ?.pages.find((p) => p.pageObjectNumber === node.destination.pageObjectNumber);\n if (!stage || !layout) {\n return { status: 'failed', error: 'no stage or destination page available' };\n }\n const { pageIndex, options: reveal } = destinationToReveal(node.destination, layout);\n stage.reveal(pageIndex, { ...reveal, behavior: 'smooth' });\n return { status: 'executed' };\n }),\n );\n ctx.cleanup(\n actions.registerExecutor('named', (node) => {\n if (node.type !== 'named') return { status: 'inert', reason: 'not a named node' };\n const stage = ctx.tryGet(token);\n if (!stage) return { status: 'failed', error: 'no stage available' };\n // Page verbs only — the dispatcher owns /N Print (policy + adapter).\n switch (node.name) {\n case 'NextPage':\n stage.next({ behavior: 'smooth' });\n return { status: 'executed' };\n case 'PrevPage':\n stage.prev({ behavior: 'smooth' });\n return { status: 'executed' };\n case 'FirstPage':\n stage.goToPage(0, { behavior: 'smooth' });\n return { status: 'executed' };\n case 'LastPage':\n stage.goToPage(Math.max(0, stage.pageCount() - 1), { behavior: 'smooth' });\n return { status: 'executed' };\n default:\n return { status: 'inert', reason: `unknown named action '${node.name}'` };\n }\n }),\n );\n },\n });\n};\n","import type {\n InteractionCapability,\n InteractionHandler,\n} from '@embedpdf/plugin-interaction/contract';\nimport type { StageCapability } from './types';\n\nexport interface ScrollHandlerOptions {\n /**\n * Let a drag over a page GAP pan regardless of the active tool — and show a grab\n * cursor there — so the gutter always pans (v2 parity, and the natural feel:\n * outside a page there's nothing to draw/select on). On-page behaviour is\n * untouched; the tool's own gesture still owns page space. Default true.\n */\n panFallback?: boolean;\n}\n\n/**\n * Pan-the-camera as an interaction handler. Live under the built-in `pan` tool\n * (the `scroll` tag) and — with `panFallback` — under every tool, where it then\n * captures ONLY page-gap drags (on-page downs belong to the active tool, which\n * claims them first at higher priority). It uses the sample's viewport delta, so\n * it pans over the whole viewport (pages and gaps).\n *\n * Cursor feel: a closed hand (`grabbing`) while dragging; an open hand (`grab`)\n * hovering a gap under a non-pan tool. The pan tool's own resting `grab` comes\n * from its `Tool.cursor`, so hovering it needs no claim here.\n */\nexport function createScrollHandler(\n stage: StageCapability,\n interaction: InteractionCapability,\n options: ScrollHandlerOptions = {},\n): InteractionHandler {\n const panFallback = options.panFallback ?? true;\n let last = { x: 0, y: 0 };\n const isPanTool = (): boolean => interaction.activeTool().enables.has('scroll');\n return {\n id: 'stage-scroll',\n priority: 10, // below page-aware handlers (selection/annotation) — they claim first\n enabledFor: (tool) => tool.enables.has('scroll') || panFallback,\n onDown: (s) => {\n // Fallback: a non-pan tool pans only over a gap. On a page, decline so the\n // tool's own (higher-priority) handler keeps the down it already captured.\n if (!isPanTool() && s.page) return false;\n last = s.viewport;\n interaction.setCursor('stage-grab', 'grabbing', 40); // closed hand while panning\n return true; // capture the drag\n },\n onMove: (s) => {\n stage.panBy(s.viewport.x - last.x, s.viewport.y - last.y);\n last = s.viewport;\n },\n onUp: () => interaction.setCursor('stage-grab', null),\n onHover: (s) => {\n // Open hand over a gap when a non-pan tool would fall back to pan there;\n // cleared over a page (the tool's cursor shows). The pan tool skips this —\n // its resting `grab` is the tool cursor.\n if (panFallback && !isPanTool()) {\n interaction.setCursor('stage-pan-fallback', s.page ? null : 'grab', 5);\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAa,SAAS;;AAEtB,MAAa,cAAc;;AAI3B,MAAa,eAAe;;;;;;;AAS5B,MAAa,aAAa,GAAW,SAAyB,IAAI,KAAM,IAAI,SAAU,MAAM,MAAM;;AAElG,MAAa,YAAY,KAAa,QAAyB,MAAM,OAAQ,UAAU,MAAM;;;;;;AAc7F,MAAa,aAAa,GAAW,GAAW,OAA2B;CACzE,MAAM,IAAI,KAAK,IAAI,aAAa,EAAE;CAClC,MAAM,KAAK,IAAI,KAAM,MAAM,IAAI,KAAM;CACrC,MAAM,KAAK,IAAI;CACf,OAAO,KAAK,IAAI,EAAE,IAAA,MAAiB;EAAE,GAAG;EAAI,GAAG;EAAG,MAAM;CAAK,IAAI;EAAE,GAAG;EAAI,GAAG;EAAI,MAAM;CAAM;AAC/F;;;;;;AAMA,MAAa,cAAc,GAAW,GAAW,MAAc,OAA2B;CACxF,MAAM,KAAK,KAAK,QAAgB,gBAAgB,IAAI,QAAQ,IAAI,eAAe,KAAK;CACpF,MAAM,KAAK,IAAI,KAAK;CACpB,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,MAAO,KAAK,IAAI,EAAE,IAAI,KAAM,OAAO;EAAE,GAAG;EAAM,GAAG;EAAG,MAAM;CAAK;CACzF,OAAO;EAAE,GAAG;EAAI,GAAG;EAAI,MAAM;CAAM;AACrC;AAGA,MAAa,gBAAgB,MAAsB,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;;;;;;;AAOxE,MAAa,YAAY,IAAY,IAAY,MAAsB,KAAK,KAAK,IAAI,KAAK,IAAI,CAAC;;;;;;;;;;;;;;;ACpE/F,MAAa,SAAS,QAAwB;CAC5C,OAAO,GAAG;CACV,QAAQ,GAAG;CACX,aAAa,GAAG,UAAU,GAAG,QAAQ,aAAa;AACpD;;AAGA,MAAa,gBAAgB,GAAa,SACvC,EAAE,aAAa,KAAA,KAAa,IAAI,SAAS,EAAE,cAC3C,EAAE,aAAa,KAAA,KAAa,IAAI,SAAS,EAAE,cAC3C,EAAE,cAAc,KAAA,KAAa,IAAI,UAAU,EAAE,eAC7C,EAAE,cAAc,KAAA,KAAa,IAAI,UAAU,EAAE,eAC7C,EAAE,gBAAgB,KAAA,KAAa,IAAI,gBAAgB,EAAE;AAExD,MAAM,eAAe,MAAsB,QACzC,OAAO,KAAK,SAAS,aAAa,CAAC,CAAC,KAAK,KAAK,GAAG,IAAI,aAAa,KAAK,MAAM,GAAG;;AAGlF,MAAa,iBAAiB,MAAqB,UAAiD;CAClG,MAAM,MAAM,EAAE,GAAG,KAAK;CACtB,IAAI;CACJ,KAAK,OAAO,OAAO;EACjB,MAAM,QAAQ,MAAM;EACpB,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO,KAAK,GAAG,MAAM,MAAM,CAAC;CAC9D;CACA,OAAO;AACT;;;;;;AAOA,MAAa,aAAa,GAAY,MAAwB;CAC5D,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,MAAM,QAAQ,MAAM,MAAM,OAAO;CACvF,MAAM,KAAK,OAAO,KAAK,CAAC;CACxB,MAAM,KAAK,OAAO,KAAK,CAAC;CACxB,OACE,GAAG,WAAW,GAAG,UACjB,GAAG,OAAO,MAAO,EAA8B,OAAQ,EAA8B,EAAE;AAE3F;AASA,MAAa,qBACX,MACA,OACA,QACuB;CACvB,IAAI,YAAY;CAChB,MAAM,SAAmB,CAAC;CAC1B,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,CAAC,YAAY,MAAM,GAAG,GAAG;EAC7B,IAAI,KAAK,SAAS,KAAA,GAAW,OAAO,KAAK,KAAK,IAAI;EAClD,IAAI,KAAK,UAAU,YAAY,cAAc,WAAW,KAAK,QAAQ;CACvE;CACA,OAAO;EAAE;EAAW;CAAO;AAC7B;;;;;;;;;;ACtEA,MAAa,mBAAkC;CAC7C,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,KAAK;CACL,WAAW;EAAE,KAAK;EAAG,OAAO;EAAG,QAAQ;EAAG,MAAM;CAAE;CAClD,WAAW;CACX,UAAU;EAAE,GAAG;EAAU,GAAG;CAAS;CAKrC,cAAc;EAAE,GAAG;EAAS,GAAG;CAAQ;CACvC,WAAW;EAAE,GAAG;EAAU,GAAG;CAAS;CACtC,aAAa;EAAE,GAAG;EAAS,GAAG;CAAQ;CACtC,cAAc;CACd,MAAM,EAAE,MAAMA,qBAAAA,SAAS,UAAU;CACjC,gBAAgB;CAGhB,mBAAmB,KAAK;AAC1B;;;;;;;;AASA,MAAa,qBAAgD,CAC3D;CAAE,MAAM;CAAW,MAAM,EAAE,UAAU,IAAI;CAAG,UAAU,EAAE,SAAS,EAAE;AAAE,CACvE;AAwBA,MAAa,kBAA8D;CACzE,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,KAAK;CACL,WAAW;CACX,WAAW;CACX,UAAU;CACV,cAAc;CACd,WAAW;CACX,aAAa;CACb,cAAc;CACd,MAAM;CACN,gBAAgB;CAChB,mBAAmB;AACrB;AACA,MAAa,eAAe,OAAO,KAAK,eAAe;AAIvD,MAAM,WAAW,GAAY,MAAwB;CACnD,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,MAAM,QAAQ,MAAM,MAAM,OAAO;CACvF,MAAM,KAAK,OAAO,KAAK,CAAC;CACxB,OACE,GAAG,WAAW,OAAO,KAAK,CAAC,CAAC,CAAC,UAC7B,GAAG,OAAO,MAAO,EAA8B,OAAQ,EAA8B,EAAE;AAE3F;;;AAGA,MAAa,iBAAiB,GAAkB,MAC9C,aAAa,OAAO,MAAM,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1C/C,SAAgB,sBACd,KACA,SAAsB,CAAC,GACN;CAMjB,MAAM,OAAO;CAIb,MAAM,aAAa,CAAC,CAAC,OAAO,aAAa,OAAO,KAAK,0BAA0B;CAC/E,MAAM,YACJ,OAAO,cACN,OAAO,KAAK,0BAA0B,aACnC;EAAE,MAAM,OAAO,KAAK,sBAAuB,EAAE;EAAG,MAAM,MAAM,KAAK,qBAAsB,CAAC;CAAE,IAC1F;EAAE,WAAW;EAAG,WAAW,CAAC;CAAE;CAEpC,MAAM,YAAY,IAAI,SAAS,CAAC,CAAC;CACjC,MAAM,WAAW,IAAI,SAAS,CAAC,CAAC;CAChC,MAAM,YAAY,IAAI,SAAS,CAAC,CAAC;CACjC,MAAM,YAAY,IAAI,SAAS,CAAC,CAAC;CACjC,MAAM,cAAc,IAAI,SAAS,CAAC,CAAC,SAAS;CAC5C,MAAM,iBAAiB;EACrB,MAAM,IAAI,IAAI,SAAS,CAAC,CAAC;EACzB,OAAO,UAAU,KAAK,EAAE,SAASC,qBAAE,SAAS;CAC9C;CAKA,IAAI,gBAAoF;CACxF,MAAM,iBAAiE;EACrE,MAAM,MAAM,IAAI,SAAS;EACzB,MAAM,KAAK,IAAI,SAAS;EACxB,MAAM,MAAM,GAAG,MAAM,IAAI,YAAY,EAAE,GAAG,GAAG;EAC7C,IAAI,iBAAiB,cAAc,QAAQ,KAAK,OAAO;EACvD,MAAM,IAAIA,qBAAE,WAAW,MAAM,IAAI,YAAY,GAAG,GAAG,MAAM;EACzD,gBAAgB;GAAE;GAAK,UAAU;GAAG,YAAY,EAAE,KAAK,SAAS,KAAK,EAAE;EAAE;EACzE,OAAO;CACT;CAEA,MAAM,mBAAmB,cAA8B;EACrD,MAAM,KAAK,SAAS,CAAC,CAAC;EACtB,IAAI,KAAK;EACT,IAAI,KAAK,GAAG;EACZ,OAAO,KAAK,IAAI;GACd,MAAM,MAAO,KAAK,MAAO;GACzB,IAAI,GAAG,QAAQ,WAAW,KAAK,MAAM;QAChC,KAAK;EACZ;EACA,OAAO,KAAK,IAAI,GAAG,KAAK,CAAC;CAC3B;CAOA,MAAM,sBAA8B;EAClC,MAAM,IAAI,IAAI,SAAS,CAAC,CAAC;EACzB,OAAO,WAAW,IAAI,EAAE,QAAQ,KAAK,IAAI,IAAI,SAAS,CAAC,CAAC,OAAO,MAAM,IAAM;CAC7E;CAGA,MAAM,sBAA8B,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,QAAQ,IAAI,IAAI,KAAK,cAAc,CAAC;CAG1F,MAAM,uBAAoC;EACxC,MAAM,IAAI,IAAI,SAAS,CAAC,CAAC;EACzB,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,OAAO;EACvD,MAAM,KAAK,cAAc;EACzB,OAAO;GAAE,KAAK,EAAE,MAAM;GAAI,OAAO,EAAE,QAAQ;GAAI,QAAQ,EAAE,SAAS;GAAI,MAAM,EAAE,OAAO;EAAG;CAC1F;CACA,MAAM,iBAAyB;EAC7B,MAAM,IAAI,IAAI,SAAS,CAAC,CAAC;EACzB,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,OAAO;EACvD,MAAM,IAAI,eAAe;EACzB,OAAO,GAAG,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,MAAM,EAAE,IAAI;CACjG;CAKA,MAAM,iBAAyB;EAC7B,MAAM,IAAI,IAAI,SAAS,CAAC,CAAC;EACzB,OAAO,OAAO,MAAM,WAAW,IAAI,EAAE,KAAK,EAAE,KAAK,cAAc,IAAI;CACrE;CACA,MAAM,eAAuB;EAC3B,MAAM,IAAI,IAAI,SAAS,CAAC,CAAC;EACzB,OAAO,OAAO,MAAM,WAAW,OAAO,CAAC,IAAI,MAAM,KAAK,MAAM,SAAS,CAAC;CACxE;CAEA,MAAM,aAAa,WAAgC;EACjD,MAAM,KAAK,IAAI,SAAS;EAYxB,MAAM,MAAM,IAAI,SAAS,CAAC,EAAE,SAAS,CAAC;EACtC,MAAM,KAAK,GAAG;EACd,MAAM,QACJ,OAAO,IAAI,MAAM,IAAI,KAAK,OAAO;GAAE,GAAG;GAAG,WAAA,GAAA,wBAAA,aAAA,CAAuB,EAAE,UAAU,EAAE;EAAE,EAAE;EACpF,MAAM,YAAY,eAAe;EACjC,MAAM,MAAM,SAAS;EACrB,MAAM,OAAO,GAAG;EAChB,IAAI,GAAG,WAAW,QAChB,OAAOA,qBAAE,WAAW,OAAO,QAAQ;GACjC;GACA,QAAQ,GAAG;GACX,WAAW,GAAG;GACd;GACA,mBAAmB;GACnB,SAAS,OAAO,GAAG,YAAY,WAAW,GAAG,UAAU,KAAA;GACvD,WAAW,GAAG,YAAY,SAAS,cAAc,IAAI,KAAA;EACvD,CAAC;EAEH,OAAO,GAAG,WAAW,eACjBA,qBAAE,aAAa,OAAO,QAAQ;GAC5B,MAAM;GACN;GACA,QAAQ,GAAG;GACX,WAAW,GAAG;GACd;GACA,mBAAmB;EACrB,CAAC,IACDA,qBAAE,aAAa,OAAO,QAAQ;GAC5B,MAAM;GACN;GACA,QAAQ,GAAG;GACX,WAAW,GAAG;GACd;GACA,mBAAmB;EACrB,CAAC;CACP;CAIA,MAAM,mBAA2B;EAC/B,MAAM,KAAK,IAAI,SAAS;EACxB,IAAI,GAAG,WAAW,QAAQ,OAAO;EACjC,OAAO,GAAG,YAAY,SAAS,QAAQ,KAAK,MAAM,cAAc,CAAC,MAAM,OAAO,GAAG,OAAO;CAC1F;CAQA,MAAM,gBAAoE;EACxE,SAAS;EACT,KAAK;EACL,WAAW;CACb;CACA,MAAM,aAAa,aAAa,QAAQ,MAAM,gBAAgB,OAAO,OAAO;CAC5E,MAAM,oBACJ,WAAW,KAAK,MAAM;EACpB,MAAM,KAAK,cAAc;EACzB,IAAI,IAAI,OAAO,GAAG;EAClB,MAAM,IAAI,IAAI,SAAS,CAAC,CAAC;EACzB,OAAO,OAAO,MAAM,YAAY,MAAM,OAAO,KAAK,UAAU,CAAC,IAAI,OAAO,CAAC;CAC3E,CAAC,CAAC,CAAC,KAAK,GAAG;CAKb,IAAI,aAAqD;CAKzD,MAAM,eAAuB;EAC3B,MAAM,MAAM,IAAI,SAAS;EACzB,OAAO,MAAM,GAAG,IAAI,UAAU,GAAG,IAAI,aAAa;CACpD;CACA,MAAM,mBAA4B;EAChC,MAAM,KAAK,IAAI,SAAS;EACxB,MAAM,EAAE,UAAU,MAAM,SAAS;EACjC,IAAI,GAAG,SAAS,SAAS;GACvB,MAAM,MAAM,EAAE,SAAS,KAAK,IAAI,gBAAgB,GAAG,MAAM,GAAG,EAAE,SAAS,CAAC,IAAI;GAC5E,MAAM,MAAM,SAAS,OAAO,EAAE,GAAG,YAAY,EAAE,GAAG;GAClD,IAAI,cAAc,WAAW,QAAQ,KAAK,OAAO,WAAW;GAC5D,MAAM,QAAQ,UAAU,EAAE,SAAS,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;GAChD,aAAa;IAAE;IAAK;GAAM;GAC1B,OAAO;EACT;EACA,MAAM,MAAM,QAAQ,OAAO,EAAE,GAAG,YAAY;EAC5C,IAAI,cAAc,WAAW,QAAQ,KAAK,OAAO,WAAW;EAC5D,MAAM,QAAQ,UAAU,CAAC;EACzB,aAAa;GAAE;GAAK;EAAM;EAC1B,OAAO;CACT;CAGA,MAAM,kBAA0B;EAC9B,MAAM,EAAE,OAAO,WAAW,WAAW,CAAC,CAAC;EACvC,OAAO;GAAE,GAAG;GAAG,GAAG;GAAG;GAAO;EAAO;CACrC;CACA,MAAM,YAAY,QAA6B;EAC7C,GAAG,GAAG;EACN,GAAG,GAAG;EACN,OAAO,GAAG;EACV,QAAQ,GAAG;CACb;CACA,MAAM,cAAc,IAAiB,cAA8B;EACjE,MAAM,MAAM,GAAG,MAAM,MAAM,MAAM,EAAE,cAAc,SAAS,KAAK,GAAG,MAAM;EACxE,OAAO;GAAE,GAAG,IAAI;GAAG,GAAG,IAAI;GAAG,OAAO,IAAI;GAAO,QAAQ,IAAI;EAAO;CACpE;;CAEA,MAAM,mBAAgC;EACpC,MAAM,KAAK,WAAW;EACtB,OAAO,MAAM,IAAI,GAAG,MAAM,KAAK,GAAG,MAAM,gBAAgB,IAAI,SAAS,CAAC,CAAC,MAAM;CAC/E;;;;;;CAOA,MAAM,uBAAuB,IAAiB,WAAmB,SAAuB;EACtF,MAAM,MAAM,GAAG,MAAM,MAAM,MAAM,EAAE,cAAc,SAAS,KAAK,GAAG,MAAM;EACxE,MAAM,WAAA,GAAA,wBAAA,YAAA,CAAsB;GAAE,OAAO,IAAI;GAAO,QAAQ,IAAI;EAAO,GAAG,IAAI,QAAQ;EAElF,MAAM,MAAA,GAAA,wBAAA,UAAA,EAAA,GAAA,wBAAA,kBAAA,CADsB,IAAI,cAAc,QAAQ,OAAO,QAAQ,QAAQ,IAAI,QAC5D,GAAG,IAAI;EAC5B,OAAO;GAAE,GAAG,IAAI,IAAI,GAAG;GAAG,GAAG,IAAI,IAAI,GAAG;GAAG,OAAO,GAAG;GAAO,QAAQ,GAAG;EAAO;CAChF;;;;;;;CAQA,MAAM,cACJ,GACA,QACA,SACA,YACA,UACA,MACA,gBACW;EACX,IAAI,MAAM,QAAQ,OAAO;EACzB,MAAM,IAAI,IAAI;EACd,IAAI,MAAM,KAAA,GAAW;GACnB,IAAI,CAAC,aAAa;IAChB,MAAM,KAAK,SAAS,IAAI;IACxB,MAAM,KAAK,UAAU,WAAW,KAAK;IACrC,IAAI,WAAW,MAAM,UAAU,cAAc,IAAI,OAAO;IACxD,IAAI,aAAa,KAAK,MAAM,UAAU,IAAI,OAAO,UAAU,IAAI;IAC/D,OAAO,UAAU,cAAc,WAAW,KAAK;GACjD;GACA,IAAI;EACN;EACA,IAAI,MAAM,SAAS,OAAO,UAAU,IAAI;EACxC,IAAI,MAAM,OAAO,OAAO,UAAU,cAAc,WAAW,KAAK;EAChE,MAAM,IAAI,MAAM,WAAW,KAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;EAC3D,OAAO,UAAU,aAAa,IAAK,WAAW,IAAK;CACrD;CAIA,MAAM,QAAQ,MAAc,SAA0B;EACpD,MAAM,IAAI,GAAG;EACb,MAAM,IAAI,IAAI;EACd,MAAM,MAAM;EACZ,OACE,KAAK,QAAQ,QAAQ,EAAE,QAAQ,IAAI,IAAI,OAAO,KAAK,SAAS,QAAQ,EAAE,SAAS,IAAI,IAAI;CAE3F;CAQA,MAAM,iBAAiB,MACrB,MAAM,UAAU,IAAI,MAAM,WAAW,KAAM,MAAM,QAAQ,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;CACzF,MAAM,cAAc,IAAsB,MAAuB;EAC/D,MAAM,MAAM,IAAI,SAAS,CAAC,CAAC,cAAc;EACzC,MAAM,KAAK,OAAO,GAAG,MAAM,UAAU,QAAQ,OAAO,GAAG,MAAM,QAAQ,UAAU,GAAG;EAClF,MAAM,IAAI,IAAI;EACd,OAAO;GACL,GAAG,KAAK,EAAE,QAAQ,IAAI,KAAK,cAAc,EAAE;GAC3C,GAAG,KAAK,EAAE,SAAS,IAAI,KAAK,cAAc,GAAG,CAAC;EAChD;CACF;CACA,MAAM,oBAA6B,WAAW,IAAI,SAAS,CAAC,CAAC,aAAa,GAAG,CAAC;;;CAI9E,MAAM,UAAU,SAA8B;EAC5C,IAAI,SAAS,GAAG,OAAO,WAAW,CAAC,CAAC;EACpC,OAAO,MAAM,IAAI;GAAE,OAAO,KAAK;GAAO,QAAQ,KAAK;EAAO,IAAI,WAAW,CAAC,CAAC;CAC7E;;CAEA,MAAM,aAAa,OAA6B,MAAM,IAAI,SAAS,EAAE,IAAI,UAAU;;CAEnF,MAAM,mBAA4B,MAAM,IAAI,SAAS,WAAW,CAAC,CAAC,MAAM,EAAE,IAAI,UAAU;CAExF,MAAM,oBAAwC;EAC5C,SAAS,IAAI,SAAS,CAAC,CAAC;EACxB,SAAS,IAAI;EACb,UAAU,IAAI,SAAS,CAAC,CAAC;EACzB,WAAW,IAAI,SAAS,CAAC,CAAC;CAC5B;CAMA,IAAI,mBAAmB;CAQvB,IAAI,eAAe;CACnB,IAAI,gBAAgB;CACpB,IAAI,iBAAiB;CACrB,IAAI,aAA8B;CASlC,MAAM,UAAU;CAChB,IAAI,UAAU;CACd,MAAM,gBAAgB;EAIpB,IAAI,CAAC,cAAc,CAAC,kBAAkB;EACtC,IAAI,IAAI,SAAS,CAAC,CAAC,eAAe,IAAI,SAAS;GAAE,MAAM;GAAe,SAAS;EAAM,CAAC;EACtF,IAAI,SAAS,UAAU,IAAI,OAAO;EAClC,IAAI,KAAK;EACT,MAAM,QAAQ,OAAe;GAC3B,UAAU;GACV,IAAI,CAAC,IAAI,KAAK;GACd,IAAI,KAAK,MAAM,SAAS;IACtB,IAAI,SAAS;KAAE,MAAM;KAAe,SAAS;IAAK,CAAC;IACnD;GACF;GACA,UAAU,UAAU,IAAI,IAAI;EAC9B;EACA,UAAU,UAAU,IAAI,IAAI;CAC9B;CAIA,MAAM,UAAU,MAAgB,SAAiB,WAAW,MAAM;EAChE,MAAM,UAAUA,qBAAE,YAAY,MAAM,QAAQ,GAAG,GAAG,WAAW,CAAC;EAC9D,IAAI,QAAQ,SAAS,IAAI,CAAC,CAAC,MACzB,IAAI,eAAe,GAAG;GAIpB,gBAAgB;GAChB,IAAI,IAAI,SAAS,CAAC,CAAC,eAAe,IAAI,SAAS;IAAE,MAAM;IAAe,SAAS;GAAM,CAAC;GACtF,IAAI,SAAS;IACX,UAAU,IAAI,OAAO;IACrB,UAAU;GACZ;EACF,OACE,QAAQ;EAGZ,IAAI,SAAS;GAAE,MAAM;GAAU,QAAQ;EAAQ,CAAC;CAClD;CASA,MAAM,eAAe,QAAgB,SAAiB,MAAc,SAClE,CAACA,qBAAE,YAAY,QAAQ,SAAS,MAAM,MAAM,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC;;;;;CAKpE,MAAM,aAAa,QAA4B;EAC7C,MAAM,UAAUA,qBAAE,YAAY,KAAK,WAAW,GAAG,GAAG,GAAG,WAAW,CAAC;EACnE,MAAM,IAAI,GAAG;EACb,MAAM,IAAI,WAAW;EACrB,MAAM,QAAQ,MAAc,UAAkB,KAAa,YAA6B;GACtF,IAAI,CAAC,SAAS,OAAO;GACrB,MAAM,SAAS,OAAO;GACtB,IAAI,WAAW,GAAG,OAAO;GACzB,MAAM,MAAM,UAAU,KAAK,IAAI,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI,GAAG,GAAG,CAAC;GACnE,OAAO,WAAY,KAAK,KAAK,MAAM,IAAI,MAAO,IAAI;EACpD;EACA,OAAO;GACL,MAAM,IAAI;GACV,GAAG,KAAK,IAAI,GAAG,QAAQ,GAAG,EAAE,OAAO,YAAY,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC;GAC/E,GAAG,KAAK,IAAI,GAAG,QAAQ,GAAG,EAAE,QAAQ,YAAY,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,IAAI,IAAI,CAAC;EACpF;CACF;;;;CAIA,MAAM,eAAe,cAAkC;EACrD,MAAM,UAAUA,qBAAE,YAAY,WAAW,WAAW,GAAG,GAAG,GAAG,WAAW,CAAC;EACzE,MAAM,IAAI,GAAG;EACb,MAAM,IAAI,WAAW;EACrB,MAAM,QAAQ,OAAe,UAAkB,KAAa,YAA6B;GACvF,IAAI,CAAC,SAAS,OAAO;GACrB,MAAM,SAAS,QAAQ;GACvB,IAAI,WAAW,GAAG,OAAO;GACzB,MAAM,IAAI,KAAK,IAAI,GAAG,GAAG;GACzB,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI,MAAM,IAAI,UAAU,MAAM,IAAI,CAAC;GAC7D,OAAO,WAAY,KAAK,KAAK,MAAM,IAAI,SAAS,KAAK,CAAC,IAAK,UAAU;EACvE;EACA,OAAO;GACL,MAAM,UAAU;GAChB,GAAG,KAAK,UAAU,GAAG,QAAQ,GAAG,EAAE,OAAO,YAAY,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,UAAU,IAAI,CAAC;GAC3F,GAAG,KAAK,UAAU,GAAG,QAAQ,GAAG,EAAE,QAAQ,YAAY,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,UAAU,IAAI,CAAC;EAChG;CACF;CAGA,MAAM,aAAa,MAAgB,IAAI,SAAS;EAAE,MAAM;EAAU,QAAQ;CAAE,CAAC;;;;;;;;CAS7E,MAAM,6BAA6B;EACjC,IAAI,MAAM,GAAG;EACb,MAAM,KAAK,WAAW;EACtB,IAAI,CAAC,GAAG,WAAW;EACnB,MAAM,OAAOA,qBAAE,iBAAiB,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;EACjD,IAAI,SAAS,IAAI,SAAS,CAAC,CAAC,QAAQ,IAAI,SAAS;GAAE,MAAM;GAAU,QAAQ;EAAK,CAAC;CACnF;CAGA,IAAI,MAAM;CACV,MAAM,mBAAmB;EACvB,IAAI,KAAK;GACP,UAAU,IAAI,GAAG;GACjB,MAAM;EACR;CACF;CACA,MAAM,QAAQ,GAAW,GAAW,MAAc,KAAK,IAAI,KAAK;CAKhE,MAAM,aAAa,QAAkB,QAAgB,KAAK,KAAK,SAAsB;EACnF,IAAI,CAAC,YAAY;GACf,OAAO,QAAQ,MAAM;GACrB,OAAO;GACP;EACF;EACA,WAAW;EACX,MAAM,OAAO,IAAI;EACjB,IAAI,UAAU;EACd,IAAI,KAAK;EACT,MAAM,QAAQ,QAAgB;GAC5B,IAAI,CAAC,SAAS;IACZ,UAAU;IACV,KAAK;GACP;GACA,MAAM,IAAI,aAAa,KAAK,IAAI,IAAI,MAAM,MAAM,EAAE,CAAC;GACnD,OACE;IACE,GAAG,KAAK,KAAK,GAAG,OAAO,GAAG,CAAC;IAC3B,GAAG,KAAK,KAAK,GAAG,OAAO,GAAG,CAAC;IAC3B,MAAM,KAAK,KAAK,MAAM,OAAO,MAAM,CAAC;GACtC,GACA,MACF;GACA,IAAI,IAAI,GACN,MAAM,UAAU,IAAI,IAAI;QACnB;IACL,MAAM;IACN,OAAO;GACT;EACF;EACA,MAAM,UAAU,IAAI,IAAI;CAC1B;;;;;;;;;;;;;;CAeA,MAAM,uBACJ,OACA,IACA,YACA,KAAK,KACL,SACG;EACH,IAAI,CAAC,YAAY;GACf,MAAM,KAAK,WAAW;GACtB,IAAI,GAAG,WAAW,OAAOA,qBAAE,wBAAwB,OAAO,IAAI,IAAI,UAAU,CAAC;GAC7E,OAAO;GACP;EACF;EACA,WAAW;EACX,MAAM,KAAK,IAAI,CAAC,CAAC;EACjB,IAAI,UAAU;EACd,IAAI,KAAK;EACT,MAAM,QAAQ,QAAgB;GAC5B,IAAI,CAAC,SAAS;IACZ,UAAU;IACV,KAAK;GACP;GACA,MAAM,IAAI,aAAa,KAAK,IAAI,IAAI,MAAM,MAAM,EAAE,CAAC;GACnD,MAAM,IAAI,SAAS,IAAI,YAAY,CAAC;GACpC,MAAM,KAAK,WAAW;GACtB,IAAI,GAAG,WAAW,OAAOA,qBAAE,wBAAwB,OAAO,IAAI,IAAI,CAAC,CAAC;GACpE,IAAI,IAAI,GACN,MAAM,UAAU,IAAI,IAAI;QACnB;IACL,MAAM;IACN,OAAO;GACT;EACF;EACA,MAAM,UAAU,IAAI,IAAI;CAC1B;CAYA,MAAM,sBAAsB,UAAkB,aAAqB;EACjE,IAAI,CAAC,YAAY;GACf,OAAO,IAAI,CAAC;GACZ;EACF;EACA,WAAW;EACX,MAAM,OAAO,IAAI,CAAC,CAAC;EASnB,MAAM,KAAK,IAAI;EACf,MAAM,MAAMA,qBAAE,YAAY,IAAI,WAAW,GAAG,GAAG,GAAG,WAAW,CAAC;EAC9D,MAAM,KAAK,WAAW;EACtB,MAAM,KAAK,GAAG;EACd,MAAM,MAAM,MAAc,UAAkB,aAAgC;GAC1E,GAAG,OAAO;GACV,GAAG,CAAC,UAAU;GACd,WAAW,SAAS;GACpB,MAAM;EACR;EAIA,MAAM,KAAK,GAAG,GAAG,GAAG,IAAI,GAAG,YAAY,GAAG,GAAG,GAAG,OAAO,GAAG,OAAO,IAAI,IAAI,WAAW,CAAC;EACrF,MAAM,KAAK,GAAG,GAAG,GAAG,IAAI,GAAG,YAAY,GAAG,GAAG,GAAG,QAAQ,GAAG,QAAQ,IAAI,IAAI,WAAW,CAAC;EACvF,IAAI,CAAC,GAAG,aAAa,CAAC,GAAG,aAAa,KAAK,MAAM,GAAG,GAAG,GAAG,CAAC,IAAA,KAAgB;EAC3E,IAAI,UAAU;EACd,IAAI,OAAO;EACX,MAAM,QAAQ,QAAgB;GAC5B,MAAM;GAGN,MAAM,KAAK,UAAU,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI;GAC7D,UAAU;GACV,OAAO;GAGP,MAAM,KAAKA,qBAAE,YACX;IAAE,GAAG,GAAG,IAAI;IAAM,GAAG,GAAG,IAAI;IAAM;GAAK,GACvC,WAAW,GACX,GAAG,GACH,WAAW,CACb;GACA,MAAM,QAAQ,GAAc,cAAsB;IAChD,IAAI,EAAE,MAAM;IACZ,MAAM,IAAI,EAAE,YACR,WAAW,EAAE,GAAG,EAAE,GAAG,YAAY,MAAM,EAAE,IACzC,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE;IAC1B,EAAE,IAAI,EAAE;IACR,EAAE,IAAI,EAAE;IACR,EAAE,OAAO,EAAE;GACb;GACA,KAAK,IAAI,GAAG,CAAC;GACb,KAAK,IAAI,GAAG,CAAC;GAIb,MAAM,MAAMA,qBAAE,YACZ;IAAE,GAAG,GAAG,IAAI;IAAM,GAAG,GAAG,IAAI;IAAM;GAAK,GACvC,WAAW,GACX,GAAG,GACH,WAAW,CACb;GACA,MAAM,WAAW,GAAc,aAAqB;IAClD,IAAI,CAAC,EAAE,aAAa,KAAK,IAAI,WAAW,OAAO,EAAE,CAAC,IAAI,MAAM;KAC1D,EAAE,IAAI,WAAW;KACjB,EAAE,YAAY;KACd,EAAE,OAAO;IACX;GACF;GACA,QAAQ,IAAI,IAAI,CAAC;GACjB,QAAQ,IAAI,IAAI,CAAC;GACjB,UAAU;IAAE,GAAG,GAAG,IAAI;IAAM,GAAG,GAAG,IAAI;IAAM;GAAK,CAAC;GAClD,qBAAqB;GACrB,IAAI,GAAG,QAAQ,GAAG,MAAM;IACtB,OAAO,IAAI,CAAC;IACZ;GACF;GACA,MAAM,UAAU,IAAI,IAAI;EAC1B;EACA,MAAM,UAAU,IAAI,IAAI;CAC1B;CAOA,MAAM,YAAY,OAA0B;EAC1C,MAAM,KAAK,WAAW;EACtB,OAAO,GAAG,YACNA,qBAAE,iBAAiB,IAAI,GAAG,IAAI,GAAG,GAAG,EAAE,IACtC;GAAE,WAAW,IAAI,SAAS,CAAC,CAAC;GAAQ,IAAI;GAAK,IAAI;EAAE;CACzD;CACA,MAAM,sBAAgC,SAAS,YAAY,CAAC;;;;;;;;CAS5D,MAAM,cAAc,UAAsB;EACxC,KAAK,IAAI,UAAU,GAAG,UAAU,GAAG,WAAW;GAC5C,MAAM,QAAQ,WAAW;GACzB,MAAM;GACN,IAAI,WAAW,MAAM,OAAO;EAC9B;CACF;CAEA,MAAM,eAAe,QAAkB,UAA6B;EAClE,iBAAiB;GACf,MAAM,QAAQ,WAAW;GACzB,IAAI,CAAC,MAAM,WAAW;GACtB,MAAM,OAAO,MAAM,MAAM,MAAM,WAAW,OAAO,SAAS;GAC1D,MAAM,OAAOA,qBAAE,YAAY,IAAI,SAAS,CAAC,CAAC,MAAM,OAAO,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC;GAGzE,MAAM,KAAK,WAAW,SAAS,IAAI,SAAS,CAAC,CAAC,aAAa,GAAG,CAAC;GAC/D,OAAOA,qBAAE,iBAAiB,QAAQ,OAAO,GAAG,GAAG,MAAM,EAAE,GAAG,UAAU,IAAI,CAAC;EAC3E,CAAC;CACH;;;;;;;;CAQA,MAAM,WAAW,QAAkB,UAA6B;EAC9D,IAAI,SAAS,GAAG,WAAW,IAAI,SAAS,CAAC,CAAC,QAAQ,EAAE,UAAU,UAAU,CAAC;OACpE,YAAY,QAAQ,KAAK;CAChC;;;CAiBA,MAAM,aAAa,UAAyC;EAC1D,IAAI,IAAI,SAAS,CAAC,CAAC,gBAAgB,OAAO,IAAI,SAAS;GAAE,MAAM;GAAgB;EAAM,CAAC;CACxF;CAEA,MAAM,cAAc,WAAmB,SAAuB;EAC5D,UAAU,cAAc;EACxB,WAAW;EACX,MAAM,MAAM,IAAI,SAAS;EACzB,IAAI,CAAC,OAAO,IAAI,cAAc,GAAG;EACjC,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,WAAW,IAAI,YAAY,CAAC,CAAC;EACjE,IAAI,WAAW,IAAI,SAAS,CAAC,CAAC,QAAQ,IAAI,SAAS;GAAE,MAAM;GAAU,QAAQ;EAAO,CAAC;EAGrF,IAAI,MAAM,WAAW;GACnB,IAAI,SAAS;IAAE,MAAM;IAAS,OAAO,EAAE,MAAM,KAAK,UAAU,KAAK;GAAE,CAAC;GACpE,YAAY,KAAK,UAAU,MAAM;GACjC;EACF;EAGA,MAAM,kBAA+D;GACnE,MAAM,KAAK,WAAW;GACtB,IAAI,CAAC,GAAG,WAAW,OAAO;GAC1B,MAAM,OAAO,MAAM,IAAI,GAAG,MAAM,KAAK,GAAG,MAAM,gBAAgB,MAAM;GACpE,MAAM,OAAOA,qBAAE,YAAY,IAAI,SAAS,CAAC,CAAC,MAAM,OAAO,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC;GACzE,MAAM,UAAU,SAAS,IACrB,UAAU,IACV,KAAK,SAAS,IAAI,GAAG,IAAI,IACvB,SAAS,IAAI,IACb,WAAW,MAAM,MAAM;GAG7B,MAAM,OAAO;IAAE,GAAG,IAAI,SAAS,CAAC,CAAC;IAAc,GAAG,MAAM;GAAa;GACrE,MAAM,SAASA,qBAAE,YACf,SACA,GAAG,GACH,MACA,IAAI,GACJ;IACE,GAAG,KAAK,MAAM,SAAS,UAAU,KAAK;IACtC,GAAG,KAAK,MAAM,SAAS,UAAU,KAAK;GACxC,GACA,IAAI,SAAS,CAAC,CAAC,SACjB;GAKA,MAAM,SAAS,UAAU,IAAI;GAC7B,MAAM,UAAUA,qBAAE,YAAY,QAAQ,QAAQ,GAAG,GAAG;IAAE,GAAG,WAAW;IAAG,SAAS;GAAK,CAAC;GACtF,OAAO;IACL,QAAQ;KACN;KACA,GAAG,KAAK,MAAM,SAAS,IAAI,CAAC,CAAC,IAAI,QAAQ;KACzC,GAAG,KAAK,MAAM,SAAS,IAAI,CAAC,CAAC,IAAI,QAAQ;IAC3C;IACA;GACF;EACF;EAEA,KAAK,MAAM,YAAY,IAAI,SAAS,CAAC,CAAC,oBAAoB,UAAU;GAClE,MAAM,IAAI,UAAU;GACpB,IAAI,GAAG,UAAU,EAAE,QAAQ,EAAE,MAAM;EACrC,OAEE,iBAAiB;GACf,MAAM,IAAI,UAAU;GACpB,IAAI,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM;EAClC,CAAC;CAEL;;CAGA,MAAM,QAAQ,WAAmB,SAAuB;EACtD,MAAM,KAAK,IAAI,SAAS;EACxB,MAAM,OAAO,WAAW;EACxB,IAAI,CAAC,MAAM;EACX,MAAM,EAAE,UAAU,MAAM,SAAS;EACjC,IAAI,SAAS,KAAK,KAAK,SAAS,IAAI,GAAG,IAAI,CAAC,CAAC,IAAI,GAAG;GAClD,MAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,gBAAgB,GAAG,MAAM,IAAI,WAAW,EAAE,SAAS,CAAC,CAAC;GACtF,WAAW,EAAE,IAAI,CAAC,IAAI,IAAI;EAC5B,OACE,WAAW,GAAG,SAAS,WAAW,IAAI;CAE1C;CAGA,MAAM,eAAe,UACnB,IAAI,SAAS,CAAC,EAAE,MAAM,MAAM,EAAE,oBAAoB,QAAQ;CAK5D,MAAM,mBAAmB,QAA2B;EAClD,MAAM,WAAA,GAAA,wBAAA,YAAA,CAAsB;GAAE,OAAO,IAAI;GAAO,QAAQ,IAAI;EAAO,GAAG,IAAI,QAAQ;EAClF,OAAO;GAAE,OAAO,QAAQ,QAAQ,IAAI;GAAc,QAAQ,QAAQ,SAAS,IAAI;EAAa;CAC9F;CAOA,MAAM,iBAAiB,QAAgC;EACrD,MAAM,MAAM,IAAI,SAAS,CAAC,EAAE,MAAM,IAAI;EACtC,MAAM,WAAW,MACb;GAAE,OAAO,IAAI,KAAK;GAAO,QAAQ,IAAI,KAAK;EAAO,IACjD,gBAAgB,GAAG;EACvB,MAAM,IAAI,IAAI;EACd,MAAM,QAAQ,IAAI;EAKlB,MAAM,QAAQ,IAAI,IAAI,EAAE,KAAK,EAAE;EAC/B,MAAM,QAAQ,IAAI,IAAI,EAAE,KAAK,EAAE;EAC/B,MAAM,UAAU,IAAI,SAAS,CAAC,CAAC;EAC/B,MAAM,UAAU,WAAA,GAAA,wBAAA,aAAA,CAAuB,MAAM,KAAK,IAAI;EACtD,MAAM,UAAU,WAAA,GAAA,wBAAA,aAAA,CAAuB,MAAM,KAAK,IAAI;EACtD,MAAM,aAAA,GAAA,wBAAA,cAAA,CAA0B;GAC9B;GACA,UAAU,IAAI;GACd,OAAO,IAAI,eAAe,EAAE;GAI5B,WAAW,IAAI,SAAS,CAAC,CAAC,qBAAqB,KAAK,YAAY;GAChE,KAAK;EACP,CAAC;EAMD,MAAM,IAAI,GAAG;EACb,MAAM,YAAA,GAAA,wBAAA,eAAA,CACJ;GAAE,GAAG,CAAC;GAAS,GAAG,CAAC;GAAS,OAAO,EAAE;GAAO,QAAQ,EAAE;EAAO,GAC7D;GAAE,GAAG;GAAG,GAAG;GAAG,OAAO,UAAU;GAAW,QAAQ,UAAU;EAAW,CACzE;EACA,MAAM,cACJ,SAAS,QAAQ,KAAK,SAAS,SAAS,IACpC,UAAU,kBAAkB,QAAQ,IACpC;GAAE,GAAG;GAAG,GAAG;GAAG,OAAO;GAAG,QAAQ;EAAE;EACxC,OAAO;GACL,GAAG;GACH,KAAK,YAAY,IAAI,SAAS;GAC9B;GACA;GACA;GACA;EACF;CACF;CAMA,MAAM,uBAAwC;EAC5C,YAAY;EACZ,WAAW;EACX,aAAa;EACb,cAAc;EACd,aAAa;EACb,cAAc;EACd,aAAa;EACb,aAAa;CACf;CACA,IAAI,aAAqC;CACzC,MAAM,yBAA0C;EAC9C,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,QAAQ,OAAO;EACnC,MAAM,KAAK,WAAW;EACtB,MAAM,IAAIA,qBAAE,cACV,IAAI,GACJ,GAAG,YAAY,WAAW,IAAI;GAAE,GAAG;GAAG,GAAG;GAAG,OAAO;GAAG,QAAQ;EAAE,GAChE,GAAG,GACH,IAAI,CACN;EACA,MAAM,IAAI;EACV,IACE,KACA,EAAE,eAAe,EAAE,cACnB,EAAE,cAAc,EAAE,aAClB,EAAE,gBAAgB,EAAE,eACpB,EAAE,iBAAiB,EAAE,gBACrB,EAAE,gBAAgB,EAAE,eACpB,EAAE,iBAAiB,EAAE,cAErB,OAAO;EAET,aAAa;EACb,OAAO;CACT;CAIA,MAAM,sBAAqC,CAAC;CAC5C,IAAI,SAAS;CACb,IAAI,MAAqB,CAAC;CAC1B,MAAM,qBAAoC;EACxC,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,QAAQ,OAAO;EACnC,MAAM,IAAI,IAAI;EACd,MAAM,IAAI,GAAG;EACb,MAAM,KAAK,WAAW;EACtB,MAAM,QAAQ,MAAM,IAAI,GAAG,MAAM,MAAM,GAAG,CAAC,IAAI,GAAG,MAAMA,qBAAE,gBAAgB,GAAG,CAAC,CAAC;EAC/E,MAAM,MAAM,GAAG,WAAY,IAAI,GAAG,IAAI,SAAS,CAAC,CAAC,KAAK,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,OAAO,GAAG,IAAI,EAAE,IAAI,IAAI,SAAS,CAAC,CAAC,gBAAgB,IAAI;EACrJ,IAAI,QAAQ,QAAQ,OAAO;EAC3B,SAAS;EACT,MAAM,MAAM,SAAS,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,aAAa;EACvD,OAAO;CACT;CAIA,MAAM,gBAAgB,QAAsC;EAC1D,MAAM,MAAqD,CAAC;EAC5D,KAAK,MAAM,KAAK,cAAc,IAAI,KAAK,IAAI;EAC3C,OAAO;CACT;CACA,MAAM,yBAAwC,aAAa,IAAI,SAAS,CAAC;;;;;;;;CASzE,MAAM,iBAAiB,UAAkC;EACvD,WAAW;EACX,MAAM,WAAW,WACf,aAAa,MAAM,MAAM,MAAM,OAAO,KAAA,KAAa,gBAAgB,OAAO,MAAM;EAKlF,MAAM,QACJ,QAAQ,OAAO,KAAK,CAAC,QAAQ,OAAO,KAAK,CAAC,QAAQ,QAAQ,IACtD,IAAI,SAAS,CAAC,CAAC,YACf,IAAI,SAAS,CAAC,CAAC;EACrB,MAAM,SAAS,SAAS,WAAW,OAAO,GAAG,CAAC,CAAC;EAC/C,IAAI,SAAS;GAAE,MAAM;GAAS;EAAM,CAAC;EACrC,IAAI,QAAQ,OAAO,GAAG,aAAa;EACnC,IAAI,QAAQ,QAAQ,GAGlB,WAAW,IAAI,SAAS,CAAC,CAAC,QAAQ,EAAE,UAAU,UAAU,CAAC;OACpD,IAAI,QAAQ,OAAO,KAAK,QAAQ,OAAO,GAC5C,QAAQ,QAAQ,KAAK;OAChB,IAAI,QAAQ,SAAS,GAC1B,OAAO,IAAI,CAAC;CAGhB;CASA,IAAI,OAAO,iBAAiB;CAC5B,IAAI,QAAmC,OAAO,cAAc;CAC5D,IAAI,gBAAgB;CACpB,MAAM,iBAAiB,WAA8B;EACnD,MAAM,OAAO,IAAI,SAAS,CAAC,CAAC;EAC5B,IAAI,KAAK,WAAW,OAAO,UAAU,OAAO,MAAM,GAAG,MAAM,MAAM,KAAK,EAAE,GACtE,IAAI,SAAS;GAAE,MAAM;GAAc;EAAO,CAAC;CAE/C;;;;;;;;CAQA,MAAM,kBAAkB,UAAkC;EACxD,MAAM,EAAE,WAAW,WAAW,kBAAkB,MAAM,OAAO,MAAM,GAAG,CAAC,CAAC;EACxE,MAAM,QAAgC,CAAC;EACvC,KAAK,MAAM,KAAK,cACd,IAAI,CAAC,UAAU,UAAU,IAAI,cAAc,EAAE,GAC3C,OAAO,OAAO,OAAO,GAAG,IAAI,UAAU,GAAG,CAAC;EAG9C,gBAAgB;EAChB,cAAc,MAAM;EACpB,MAAM,OAAO,OAAO,KAAK,KAAK;EAC9B,IAAI,KAAK,WAAW,GAAG,OAAO;EAC9B,IAAI,OAAO;GACT,cAAc,KAAK;GACnB,OAAO;EACT;EACA,IAAI,SAAS;GAAE,MAAM;GAAS;EAAM,CAAC;EACrC,MAAM,OAAsC;GAAE,MAAM;GAAG,SAAS;GAAG,OAAO;GAAG,OAAO;GAAG,QAAQ;EAAE;EACjG,IAAI,YAA2B;EAC/B,KAAK,MAAM,KAAK,MAAM,IAAI,KAAK,gBAAgB,MAAM,KAAK,YAAY,YAAY,gBAAgB;EAClG,IAAI,cAAc,WAAW,cAAc,UAAU,aAAa;EAClE,OAAO;CACT;CAKA,MAAM,uBAAqF,CAAC;CAE5F,MAAM,MAAuB;EAE3B,QAAQ;EACR,UAAU;EACV,eAAe;EACf,iBAAiB,IAAI,SAAS,CAAC,EAAE,aAAa;EAC9C;EACA,mBAAmB,IAAI,SAAS,CAAC,CAAC;EAClC,wBAAwB;GACtB,MAAM,OAAO,WAAW;GACxB,OAAO,OAAO,CAAC,GAAG,KAAK,WAAW,IAAI,CAAC;EACzC;EACA,cACG,IAAI,SAAS,CAAC,EAAE,SAAS,CAAC,EAAA,CAAG,KAAK,OAAO;GACxC,OAAO,EAAE;GACT,KAAK,EAAE;GACP,OAAO,EAAE,SAAS;EACpB,EAAE;EACJ,WAAW,QAAQ;GACjB,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,QAAQ,OAAO;GACnC,MAAM,OAAO,IAAI,SAAS;GAC1B,MAAM,QAAQ,OAAO,KAAK,MAAM,WAAW,MAAM,EAAE,qBAAqB,GAAG,IAAI;GAC/E,IAAI,QAAQ,GAAG,OAAO;GACtB,MAAM,KAAK,WAAW;GACtB,IAAI,CAAC,GAAG,WAAW,OAAO;GAC1B,MAAM,MAAM,GAAG,MAAM,GAAG,WAAW,KAAK,EAAE,CAAC,MAAM,MAAM,MAAM,EAAE,cAAc,KAAK;GAClF,OAAO,MAAM,cAAc,GAAG,IAAI;EACpC;EACA,SAAS,WAAW;GAIlB,KAAK,MAAM,KAAK,aAAa,GAAG;IAC9B,MAAM,KAAK,OAAO,IAAI,EAAE;IACxB,MAAM,KAAK,OAAO,IAAI,EAAE;IACxB,IAAI,MAAM,KAAK,MAAM,KAAK,MAAM,EAAE,UAAU,aAAa,MAAM,EAAE,UAAU,YACzE,OAAO;KACL,KAAK,EAAE;KACP,OAAO,EAAE,UAAU,cAAc;MAAE,GAAG;MAAI,GAAG;KAAG,CAAC;KACjD,OAAO,EAAE,UAAU;KACnB,UAAU,EAAE;KACZ,MAAM,EAAE,UAAU;IACpB;GAEJ;GACA,OAAO;EACT;EACA,cAAc,KAAK,WAAW;GAG5B,MAAM,IAAI,aAAa,CAAC,CAAC,MAAM,MAAM,EAAE,QAAQ,GAAG;GAClD,IAAI,CAAC,GAAG,OAAO;GACf,OAAO,EAAE,UAAU,cAAc;IAAE,GAAG,OAAO,IAAI,EAAE;IAAS,GAAG,OAAO,IAAI,EAAE;GAAQ,CAAC;EACvF;EACA,cAAc,KAAK,OAAO;GACxB,MAAM,KAAK,IAAI,SAAS,GAAG;GAC3B,IAAI,CAAC,IAAI,OAAO;GAMhB,MAAM,WAAA,GAAA,wBAAA,YAAA,CAAsB;IAAE,OAAO,GAAG;IAAO,QAAQ,GAAG;GAAO,GAAG,GAAG,QAAQ;GAE/E,MAAM,UAAA,GAAA,wBAAA,WAAA,EAAA,GAAA,wBAAA,kBAAA,CADsB,GAAG,cAAc,QAAQ,OAAO,QAAQ,QAAQ,GAAG,QACrD,GAAG,EAAE;GAC/B,OAAO;IAAE,GAAG,GAAG,IAAI,OAAO;IAAG,GAAG,GAAG,IAAI,OAAO;GAAE;EAClD;EACA,mBAAmB,KAAK,SAAS;GAC/B,MAAM,KAAK,IAAI,SAAS,GAAG;GAC3B,IAAI,CAAC,IAAI,OAAO;GAChB,MAAM,WAAA,GAAA,wBAAA,YAAA,CAAsB;IAAE,OAAO,GAAG;IAAO,QAAQ,GAAG;GAAO,GAAG,GAAG,QAAQ;GAE/E,MAAM,MAAA,GAAA,wBAAA,UAAA,EAAA,GAAA,wBAAA,kBAAA,CADsB,GAAG,cAAc,QAAQ,OAAO,QAAQ,QAAQ,GAAG,QAC1D,GAAG,IAAI;GAC5B,MAAM,IAAI,IAAI;GACd,MAAM,KAAKA,qBAAE,SAAS,GAAG;IAAE,GAAG,GAAG,IAAI,GAAG;IAAG,GAAG,GAAG,IAAI,GAAG;GAAE,CAAC;GAC3D,OAAO;IAAE,GAAG,GAAG;IAAG,GAAG,GAAG;IAAG,OAAO,GAAG,QAAQ,EAAE;IAAM,QAAQ,GAAG,SAAS,EAAE;GAAK;EAClF;EACA,WAAW,MAAMA,qBAAE,SAAS,IAAI,GAAG,CAAC;EACpC,UAAU,MAAMA,qBAAE,QAAQ,IAAI,GAAG,CAAC;EAClC,YAAY,IAAI,SAAS,CAAC,CAAC;EAC3B,cAAc,IAAI,SAAS,CAAC,CAAC;EAC7B,cAAc,IAAI,SAAS,CAAC,CAAC;EAC7B,cAAc,IAAI,SAAS,CAAC,CAAC;EAC7B,eAAe,IAAI,SAAS,CAAC,CAAC;EAC9B,eAAe,IAAI,SAAS,CAAC,CAAC;EAC9B,eAAe,IAAI,SAAS,CAAC,CAAC;EAC9B,WAAW,IAAI,SAAS,CAAC,CAAC;EAC1B,iBAAiB,IAAI,SAAS,CAAC,CAAC;EAChC,gBAAgB,IAAI,SAAS,CAAC,CAAC;EAC/B,oBAAoB,IAAI,SAAS,CAAC,CAAC;EACnC,iBAAiB,IAAI,SAAS,CAAC,CAAC;EAChC,mBAAmB,IAAI,SAAS,CAAC,CAAC;EAClC,iBAAiB,IAAI,SAAS,CAAC,CAAC;EAChC,sBAAsB,IAAI,SAAS,CAAC,CAAC;EACrC,oBAAoB,IAAI,SAAS,CAAC,CAAC;EACnC,iBAAiB,IAAI,CAAC,CAAC;EACvB,gBAAgB;GACd,MAAM,IAAI,IAAI,SAAS,CAAC,CAAC;GACzB,OAAO,UAAU,IAAI,EAAE,OAAO;EAChC;EACA,kBAA6B;GAAE,QAAQ,cAAc;GAAG,MAAM,IAAI,SAAS,CAAC,CAAC;EAAK;EAClF,UAAU;EACV,kBAAkC;GAChC,GAAG,iBAAiB;GACpB,QAAQ,IAAI,SAAS,CAAC,CAAC;GACvB,QAAQ,cAAc;EACxB;EAGA,cAAc,MAAM;GAMlB,IAAI,CAAC,kBAAkB;IACrB,IAAI,SAAS;KAAE,MAAM;KAAM,IAAI;IAAE,CAAC;IAClC,eAAe,KAAK;IACpB,IAAI,EAAE,QAAQ,KAAK,EAAE,SAAS,MAAM,IAAI,SAAS,CAAC,EAAE,aAAa,KAAK,GACpE,IAAI,aAAa;IAEnB;GACF;GAEA,WAAW;GACX,MAAM,SAAS,cAAc;GAC7B,IAAI,SAAS;IAAE,MAAM;IAAM,IAAI;GAAE,CAAC;GAMlC,IADW,eAAe,KACrB,MAAM,UACT,WAAW,IAAI,SAAS,CAAC,CAAC,QAAQ,EAAE,UAAU,UAAU,CAAC;QAEzD,QAAQ,MAAM;EAElB;EACA,sBAAsB,UAAU;GAI9B,IAAI,QAAQ,KAAK,UAAU,IAAI,GAAG,IAAI,SAAS;IAAE,MAAM;IAAO,KAAK;GAAM,CAAC;EAC5E;EACA,YAAY,MAAM;GAChB,UAAU,MAAM;GAChB,WAAW;GACX,OAAO,CAAC;GACR,qBAAqB;EACvB;EACA,QAAQ,IAAI,OAAO;GACjB,UAAU,MAAM;GAChB,WAAW;GACX,IAAI,eAAe,KAAK,gBAAgB;IAItC,aAAaA,qBAAE,YAAY,cAAc,YAAY,IAAI,CAAC,GAAG,IAAI,EAAE;IACnE,UAAU,UAAU,UAAU,CAAC;GACjC,OACE,OAAOA,qBAAE,YAAY,IAAI,GAAG,IAAI,EAAE,CAAC;GAErC,qBAAqB;EACvB;EACA,WAAW,SAAS;GAClB,UAAU,MAAM;GAChB,WAAW;GAEX,IAAI,CADO,WACL,CAAC,CAAC,WAAW;GACnB,MAAM,OAAOA,qBAAE,iBAAiB,IAAI,GAAG,WAAW,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI;GACtE,IAAI,KAAK,aAAa,UACpB,UAAU,MAAM,WAAW,GAAG,KAAK,oBAAoB;QAClD;IACL,OAAO,IAAI;IACX,qBAAqB;GACvB;EACF;EACA,WAAW,EAAE,MAAM,KAAK,eAAe;GACrC,MAAM,IAAI,iBAAiB;GAC3B,IAAI,SAAS;IACX,MAAM,SAAS,KAAA,IAAY,KAAA,IAAY,EAAE,aAAa;IACtD,KAAK,QAAQ,KAAA,IAAY,KAAA,IAAY,EAAE,YAAY;IACnD;GACF,CAAC;EACH;EACA,aAAa,IAAI,WAAW;GAC1B,WAAW;GACX,MAAM,SAAS,WAAW;GAE1B,MAAM,QAAQ,OAAO,YAAYA,qBAAE,cAAc,QAAQA,qBAAE,QAAQ,IAAI,GAAG,EAAE,CAAC,IAAI;GACjF,OAAOA,qBAAE,WAAW,IAAI,GAAG,IAAI,MAAM,CAAC;GAItC,IAAI,iBAAiB,GACnB,IAAI,SAAS;IAAE,MAAM;IAAS,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,CAAC,CAAC,KAAK,EAAE;GAAE,CAAC;GAMxE,MAAM,QAAQ,WAAW;GACzB,IAAI,UAAU,UAAU,SAAS,MAAM,WACrC,OAAOA,qBAAE,wBAAwB,OAAO,OAAO,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC;GAKhE,IAAI,eAAe,KAAK,gBAAgB,aAAa,YAAY,IAAI,CAAC;GACtE,qBAAqB;EACvB;EACA,eAAe,YAAY;GACzB;GACA,IAAI,iBAAiB,GAAG;IACtB,WAAW;IACX,gBAAgB;IAChB,iBAAiB,SAAS,YAAY;IACtC,aAAa;GACf;EACF;EACA,kBAAkB;GAChB,IAAI,iBAAiB,GAAG;GACxB;GACA,IAAI,eAAe,GAAG;GACtB,aAAa;GACb,MAAM,aAAa;GACnB,iBAAiB;GACjB,IAAI,eAAe;IACjB,gBAAgB;IAIhB,IAAI,SAAS;KAAE,MAAM;KAAS,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,CAAC,CAAC,KAAK,EAAE;IAAE,CAAC;IACtE,QAAQ;GACV;GACA,qBAAqB;GACrB,IAAI,YAAY;IAGd,MAAM,IAAI,IAAI;IACd,MAAM,KAAKA,qBAAE,YAAY,GAAG,WAAW,GAAG,GAAG,GAAG,WAAW,CAAC;IAC5D,IAAI,GAAG,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,mBAAmB,GAAG,CAAC;GAC3D;EACF;EACA,QAAQ,IAAI,OAAO,mBAAmB,IAAI,EAAE;EAC5C,sBAAsB,QAAQ;EAC9B,gBAAgB,OAAO;GACrB,WAAW;GACX,MAAM,MAAM,WAAW;GACvB,IAAI,CAAC,IAAI,WAAW;GACpB,MAAM,OAAO,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI,MAAM,gBAAgB,IAAI,SAAS,CAAC,CAAC,MAAM;GAWrF,MAAM,MAAM,OAAO,IAAI;GACvB,MAAM,OAAOA,qBAAE,YAAY,EAAE,MAAMA,qBAAE,SAAS,UAAU,GAAG,KAAK,GAAG,GAAG,IAAI,CAAC;GAE3E,MAAM,QAAQ;IAAC;IADFA,qBAAE,YAAY,EAAE,MAAMA,qBAAE,SAAS,SAAS,GAAG,KAAK,GAAG,GAAG,IAAI,CACjD;IAAG,KAAK,IAAI,OAAO,KAAKA,qBAAE,QAAQ;GAAC,CAAC,CACzD,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CACrB,QAAQ,GAAG,GAAG,QAAQ,MAAM,KAAK,IAAI,IAAI,IAAI,KAAK,GAAG;GAExD,MAAM,QAAQ,GAAW,SAAiB,IAAI,OAAO,OAAO,IAAI,OAAO;GACvE,MAAM,SAAS,MAAM,WAAW,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;GACzD,MAAM,SAAS,UAAU,IAAI,OAAO,SAAS,KAAK,MAAM,UAAU,MAAM;GAKxE,IAAI,SAAS;IAAE,MAAM;IAAS,OAAO,EAAE,MAAM,EAAE,OAAO,OAAO,EAAE;GAAE,CAAC;GAGlE,MAAM,KAAK,WAAW;GACtB,IAAI,CAAC,GAAG,WAAW;GACnB,MAAM,QAAQA,qBAAE,cAAc,IAAIA,qBAAE,QAAQ,IAAI,GAAG,EAAE,CAAC;GAGtD,oBAAoB,OAAO,IAAI,QAAQ,KAAK,oBAAoB;EAClE;EAGA,cAAc,IAAI,WAAW,WAAW,IAAI,SAAS,CAAC,CAAC,WAAW,GAAG,CAAC,GAAG,GAAG;EAC5E,eAAe,IAAI,WAAW,WAAW,IAAI,SAAS,CAAC,CAAC,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG;EACjF,SAAS,SAAS,IAAI,OAAO,EAAE,MAAM,KAAK,CAAC;EAC3C,gBAAgB,IAAI,OAAO,EAAE,MAAM,EAAE,MAAMA,qBAAE,SAAS,SAAS,EAAE,CAAC;EAClE,eAAe,IAAI,OAAO,EAAE,MAAM,EAAE,MAAMA,qBAAE,SAAS,QAAQ,EAAE,CAAC;EAChE,cAAc,IAAI,OAAO,EAAE,MAAM,EAAE,MAAMA,qBAAE,SAAS,OAAO,EAAE,CAAC;EAC9D,iBAAiB,IAAI,OAAO,EAAE,MAAM,EAAE,MAAMA,qBAAE,SAAS,UAAU,EAAE,CAAC;EACpE,aAAa;GAMX,IAAI,CAAC,kBAAkB;GACvB,WAAW;GACX,QAAQ,cAAc,CAAC;EACzB;EACA,WAAW,WAAW,SAAS,WAAW,WAAW,IAAI;EACzD,SAAS,WAAW,SAAS;GAC3B,UAAU,cAAc;GACxB,MAAM,MAAM,IAAI,SAAS;GACzB,IAAI,CAAC,OAAO,IAAI,cAAc,GAAG;GACjC,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,WAAW,IAAI,YAAY,CAAC,CAAC;GASjE,IAAI,EAPF,CAAC,CAAC,SAGD,KAAK,QAAQ,QACZ,KAAK,WAAW,KAAA,KACf,KAAK,SAAS,KAAA,KAAa,KAAK,SAAS,UAE7B;IAEf,IAAI,MAAM,GAAG;KAEX,WAAW,QAAQ,IAAI;KACvB;IACF;IACA,MAAM,KAAK,WAAW;IACtB,IAAI,CAAC,GAAG,WAAW;IACnB,MAAM,OAAO,WAAW,GAAG,MAAM,gBAAgB,MAAM,IAAI,MAAM;IAGjE,MAAM,IAAI,eAAe;IACzB,MAAM,MAAM;KACV,GAAG,KAAK,IAAI,EAAE;KACd,GAAG,KAAK,IAAI,EAAE;KACd,OAAO,KAAK,QAAQ,EAAE,OAAO,EAAE;KAC/B,QAAQ,KAAK,SAAS,EAAE,MAAM,EAAE;IAClC;IACA,MAAM,SAASA,qBAAE,aAAa,IAAI,GAAG,KAAK,GAAG,GAAG,IAAI,CAAC;IACrD,MAAM,UAAU,IAAI;IACpB,IAAI,OAAO,MAAM,QAAQ,KAAK,OAAO,MAAM,QAAQ,GAAG;IACtD,WAAW;IACX,KAAK,MAAM,YAAY,IAAI,SAAS,CAAC,CAAC,oBAAoB,UACxD,UAAU,QAAQ,UAAU,CAAC;SAE7B,OAAO,QAAQ,UAAU,CAAC;IAE5B;GACF;GAMA,WAAW;GACX,IAAI,WAAW,IAAI,SAAS,CAAC,CAAC,QAC5B,IAAI,SAAS;IAAE,MAAM;IAAU,QAAQ;GAAO,CAAC;GAGjD,MAAM,cAAiF;IACrF,MAAM,KAAK,WAAW;IACtB,IAAI,CAAC,GAAG,WAAW,OAAO;IAC1B,MAAM,OAAO,MAAM,IAAI,GAAG,MAAM,KAAK,GAAG,MAAM,gBAAgB,MAAM;IACpE,MAAM,QAAQ,KAAK,OACf,oBAAoB,MAAM,QAAQ,KAAK,IAAI,IAC3C,WAAW,MAAM,MAAM;IAC3B,MAAM,KAAK,KAAK,QAAQ;IACxB,MAAM,SAAS,KAAK,IAAI,GAAG,GAAG,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC;IACjD,MAAM,SAAS,KAAK,IAAI,GAAG,GAAG,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC;IAClD,IAAI,OACF,OAAO,OAAO,WACV,GAAG,QACH,OAAO,QACL,KAAK,IAAI,SAAS,MAAM,OAAO,SAAS,MAAM,MAAM,IACpD,OAAO,cACL,SAAS,MAAM,QACf,OAAO,eACL,SAAS,MAAM,SACf,IAAI,CAAC,CAAC;IAElB,IAAI,CAAC,OAAO,SAAS,IAAI,KAAK,QAAQ,GAAG,OAAO,IAAI,CAAC,CAAC;IACtD,MAAM,cAAc,OAAO;IAC3B,MAAM,IAAI,KAAK,UAAU,CAAC;IAC1B,OAAO;KACL,QAAQ;MACN,GAAG,WAAW,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,MAAM,WAAW;MAC/E,GAAG,WAAW,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,MAAM,WAAW;MACjF;KACF;KACA,QAAQ,UAAU,IAAI;KACtB;IACF;GACF;GAEA,MAAM,QAAQ,MAAM;GACpB,IAAI,CAAC,OAAO;GAGZ,IAAI,MAAM,aACR,IAAI,SAAS;IAAE,MAAM;IAAS,OAAO,EAAE,MAAM,EAAE,OAAO,MAAM,OAAO,KAAK,EAAE;GAAE,CAAC;GAE/E,KAAK,KAAK,YAAY,IAAI,SAAS,CAAC,CAAC,oBAAoB,UAAU;IAGjE,MAAM,IAAI,MAAM,KAAK;IACrB,UAAU,EAAE,QAAQ,EAAE,MAAM;GAC9B,OACE,iBAAiB;IACf,MAAM,IAAI,MAAM;IAChB,IAAI,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM;GAClC,CAAC;EAEL;EACA,OAAO,SAAS,KAAK,GAAG,IAAI;EAC5B,OAAO,SAAS,KAAK,IAAI,IAAI;EAC7B,cAAc,IAAI;EAClB,SAAS,UAAU;GAIjB,OAAO,cAAc,MAAM,KAAK;GAChC,eAAe,IAAI;EACrB;EACA,gBAAgB,SAAS;GACvB,QAAQ;GACR,eAAe,IAAI;EACrB;EACA,UAAU,SAAS,IAAI,SAAS,CAAC,CAAC,YAAY,SAAS,IAAI;EAC3D,mBAAmB,IAAI,SAAS,CAAC,CAAC;EAClC,UAAU,SAAS,IAAI,OAAO,EAAE,KAAK,CAAC;EACtC,YAAY,WAAW,IAAI,OAAO,EAAE,OAAO,CAAC;EAC5C,YAAY,WAAW,IAAI,OAAO,EAAE,OAAO,CAAC;EAC5C,YAAY,WAAW,IAAI,OAAO,EAAE,OAAO,CAAC;EAC5C,aAAa,YAAY,IAAI,OAAO,EAAE,QAAQ,CAAC;EAC/C,aAAa,YAAY,IAAI,OAAO,EAAE,QAAQ,CAAC;EAC/C,aAAa,YAAY,IAAI,OAAO,EAAE,QAAQ,CAAC;EAC/C,SAAS,QAAQ,IAAI,OAAO,EAAE,IAAI,CAAC;EACnC,eAAe,cAAc,IAAI,OAAO,EAAE,UAAU,CAAC;EACrD,cAAc,aAAa,IAAI,OAAO,EAAE,SAAS,CAAC;EAClD,kBAAkB,iBAAiB,IAAI,OAAO,EAAE,aAAa,CAAC;EAC9D,eAAe,cAAc,IAAI,OAAO,EAAE,UAAU,CAAC;EACrD,iBAAiB,gBAAgB,IAAI,OAAO,EAAE,YAAY,CAAC;EAC3D,eAAe,cAAc,IAAI,OAAO,EAAE,UAAU,CAAC;EACrD,kBAAkB,iBAAiB,IAAI,OAAO,EAAE,aAAa,CAAC;EAC9D,aAAa,UACX,IAAI,iBAAA,GAAA,wBAAA,aAAA,CAA6B,IAAI,SAAS,CAAC,CAAC,cAAc,UAAU,KAAK,KAAK,GAAG,CAAC;EACxF,oBAAoB,aAAa,IAAI,OAAO,EAAE,gBAAgB,SAAS,CAAC;EACxE,iBAAiB,SAAS;GACxB,WAAW;GAIX,OAAO,cAAc,MAAM,aAAa,IAAI,CAAC;GAC7C,MAAM,EAAE,WAAW,WAAW,kBAAkB,MAAM,OAAO,MAAM,GAAG,CAAC,CAAC;GACxE,gBAAgB;GAChB,cAAc,MAAM;GACpB,IAAI,SAAS;IAAE,MAAM;IAAS,OAAO;GAAU,CAAC;GAChD,IAAI,SAAS;IAAE,MAAM;IAAU,QAAQ,KAAK,UAAU;GAAE,CAAC;GACzD,aAAa;GACb,YAAY,KAAK,MAAM;EACzB;EACA,qBAAqB,UAAU,OAAO;GACpC,qBAAqB,KAAK;IAAE;IAAU;GAAG,CAAC;EAC5C;EACA,oBAAoB;GAClB,mBAAmB;GACnB,MAAM,SAAS,CAAC,GAAG,oBAAoB,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;GAC/E,KAAK,MAAM,KAAK,QAAQ;IACtB,MAAM,OAAO,EAAE,GAAG;IAClB,IAAI,MAAM;KACR,IAAI,eAAe,IAAI;KACvB,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;KAC/B;IACF;GACF;GACA,IAAI,UAAU;GAId,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;EACjC;EAGA,iBAAiB,WAAW,GAAG,EAAE,UAAU,UAAU,CAAC;CACxD;CACA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;AC9gDA,SAAgB,qBACd,KACA,OACA,cAAc,OACR;CACN,IAAI,YACI,IAAI,SAAS,CAAC,EAAE,YAAY,SAC5B,IAAI,IAAI,KAAK,CAAC,CAAC,MAAM,CAC7B;CAEA,IAAI,CAAC,aAAa;CAClB,MAAM,UAAU,IAAI,OAAOC,uCAAAA,YAAgB;CAC3C,IAAI,CAAC,SAAS;CAEd,MAAM,iBAAiB;EACrB,MAAM,QAAQ,IAAI,SAAS;EAC3B,IAAI,CAAC,MAAM,QAAQ,OAAO;EAC1B,MAAM,QAAQ,IAAI,IAAI,KAAK;EAC3B,OAAO;GACL,YAAY,MAAM,MAAM,CAAC,CAAC,MAAM,OAAO,EAAE,OAAO;GAChD,aAAa,MAAM,aAAa,CAAC,CAAC,KAAK,SAAS,KAAK,GAAG;GACxD,OAAO,MAAM;EACf;CACF;CACA,IAAI,YAII;EACJ,MAAM,IAAI,SAAS;EACnB,OAAO,MAAM,OACT,aACA,GAAG,EAAE,cAAc,GAAG,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG;CAChF,SACM;EACJ,MAAM,IAAI,SAAS;EACnB,IAAI,MAAM,MAAM;EAChB,QAAQ,gBAAgB;GACtB,YAAY,EAAE;GACd,aAAa,EAAE;GACf,QAAQ;GACR,OAAO,EAAE;EACX,CAAC;CACH,CACF;AACF;;;AChEA,MAAa,qBAAqB,WAAoC;CAGpE,MAAM,EAAE,WAAW,YAAY,YAAY,aAAa,GAAG,cAAc;CACzE,OAAO;EACL,QAAQ;GAAE,GAAG;GAAG,GAAG;GAAG,MAAM;EAAE;EAC9B,QAAQ;EACR,eAAe;EACf,IAAI;GAAE,OAAO;GAAG,QAAQ;EAAE;EAC1B,KAAK;EACL,QAAQ;EACR,aAAa;EACb,aAAa,CAAC;EACd,GAAG;EACH,GAAG;CACL;AACF;;AAGA,MAAM,cAAc,OAAmB,UAA8C;CACnF,MAAM,OAAmB,EAAE,GAAG,MAAM;CACpC,IAAI;CACJ,KAAK,OAAO,OAAO;EACjB,MAAM,QAAQ,MAAM;EACpB,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO,MAAM,GAAG,MAAM,MAAM,CAAC;CAC/D;CACA,OAAO;AACT;;;;;;AAOA,MAAa,gBAAgB,OAAmB,MAA+B;CAC7E,QAAQ,EAAE,MAAV;EACE,KAAK,UACH,OAAO;GAAE,GAAG;GAAO,QAAQ,EAAE;EAAO;EACtC,KAAK,eACH,OAAO,MAAM,kBAAkB,EAAE,UAAU,QAAQ;GAAE,GAAG;GAAO,eAAe,EAAE;EAAQ;EAC1F,KAAK,UACH,OAAO,MAAM,SAAS,QAAQ;GAAE,GAAG;GAAO,QAAQ;EAAK;EACzD,KAAK,MACH,OAAO;GAAE,GAAG;GAAO,IAAI,EAAE;EAAG;EAC9B,KAAK,OACH,OAAO;GAAE,GAAG;GAAO,KAAK,EAAE;EAAI;EAChC,KAAK,UACH,OAAO;GAAE,GAAG;GAAO,QAAQ,EAAE;EAAO;EACtC,KAAK,gBACH,OAAO;GAAE,GAAG;GAAO,aAAa,EAAE;EAAM;EAC1C,KAAK,SACH,OAAO,WAAW,OAAO,EAAE,KAAK;EAClC,KAAK,cACH,OAAO;GAAE,GAAG;GAAO,aAAa,EAAE;EAAO;EAC3C,SACE,OAAO;CACX;AACF;;;;;;;;ACvBA,MAAa,eAAe,UAA8B,CAAC,MAAM;CAC/D,MAAM,EAAE,KAAK,SAAS,QAAQC,iBAAAA,YAAY,GAAG,WAAW;CACxD,QAAA,GAAA,eAAA,aAAA,CAA8D;EAC5D;EACA;EACA,OAAO;EACP,UAAU,CAACC,kCAAAA,YAAkB;EAC7B,oBAAoB,kBAAkB,MAAM;EAC5C,QAAQ;EACR,aAAa,QAAQ,sBAAsB,KAAK,MAAM;EAWtD,UAAU,QAAQ,qBAAqB,KAAK,OAAO,OAAO,OAAO;EACjE,OAAO,QAAQ;GAMb,IAAI,OAAO,SAAS;GACpB,MAAM,UAAU,IAAI,OAAOC,uCAAAA,YAAgB;GAC3C,IAAI,CAAC,SAAS;GACd,IAAI,QACF,QAAQ,iBAAiB,SAAS,SAAS;IACzC,IAAI,KAAK,SAAS,QAAQ,OAAO;KAAE,QAAQ;KAAS,QAAQ;IAAkB;IAC9E,MAAM,QAAQ,IAAI,OAAO,KAAK;IAC9B,MAAM,SAAS,IACZ,SAAS,CAAC,EACT,MAAM,MAAM,MAAM,EAAE,qBAAqB,KAAK,YAAY,gBAAgB;IAC9E,IAAI,CAAC,SAAS,CAAC,QACb,OAAO;KAAE,QAAQ;KAAU,OAAO;IAAyC;IAE7E,MAAM,EAAE,WAAW,SAAS,WAAWC,oBAAAA,oBAAoB,KAAK,aAAa,MAAM;IACnF,MAAM,OAAO,WAAW;KAAE,GAAG;KAAQ,UAAU;IAAS,CAAC;IACzD,OAAO,EAAE,QAAQ,WAAW;GAC9B,CAAC,CACH;GACA,IAAI,QACF,QAAQ,iBAAiB,UAAU,SAAS;IAC1C,IAAI,KAAK,SAAS,SAAS,OAAO;KAAE,QAAQ;KAAS,QAAQ;IAAmB;IAChF,MAAM,QAAQ,IAAI,OAAO,KAAK;IAC9B,IAAI,CAAC,OAAO,OAAO;KAAE,QAAQ;KAAU,OAAO;IAAqB;IAEnE,QAAQ,KAAK,MAAb;KACE,KAAK;MACH,MAAM,KAAK,EAAE,UAAU,SAAS,CAAC;MACjC,OAAO,EAAE,QAAQ,WAAW;KAC9B,KAAK;MACH,MAAM,KAAK,EAAE,UAAU,SAAS,CAAC;MACjC,OAAO,EAAE,QAAQ,WAAW;KAC9B,KAAK;MACH,MAAM,SAAS,GAAG,EAAE,UAAU,SAAS,CAAC;MACxC,OAAO,EAAE,QAAQ,WAAW;KAC9B,KAAK;MACH,MAAM,SAAS,KAAK,IAAI,GAAG,MAAM,UAAU,IAAI,CAAC,GAAG,EAAE,UAAU,SAAS,CAAC;MACzE,OAAO,EAAE,QAAQ,WAAW;KAC9B,SACE,OAAO;MAAE,QAAQ;MAAS,QAAQ,yBAAyB,KAAK,KAAK;KAAG;IAC5E;GACF,CAAC,CACH;EACF;CACF,CAAC;AACH;;;;;;;;;;;;;;ACjFA,SAAgB,oBACd,OACA,aACA,UAAgC,CAAC,GACb;CACpB,MAAM,cAAc,QAAQ,eAAe;CAC3C,IAAI,OAAO;EAAE,GAAG;EAAG,GAAG;CAAE;CACxB,MAAM,kBAA2B,YAAY,WAAW,CAAC,CAAC,QAAQ,IAAI,QAAQ;CAC9E,OAAO;EACL,IAAI;EACJ,UAAU;EACV,aAAa,SAAS,KAAK,QAAQ,IAAI,QAAQ,KAAK;EACpD,SAAS,MAAM;GAGb,IAAI,CAAC,UAAU,KAAK,EAAE,MAAM,OAAO;GACnC,OAAO,EAAE;GACT,YAAY,UAAU,cAAc,YAAY,EAAE;GAClD,OAAO;EACT;EACA,SAAS,MAAM;GACb,MAAM,MAAM,EAAE,SAAS,IAAI,KAAK,GAAG,EAAE,SAAS,IAAI,KAAK,CAAC;GACxD,OAAO,EAAE;EACX;EACA,YAAY,YAAY,UAAU,cAAc,IAAI;EACpD,UAAU,MAAM;GAId,IAAI,eAAe,CAAC,UAAU,GAC5B,YAAY,UAAU,sBAAsB,EAAE,OAAO,OAAO,QAAQ,CAAC;EAEzE;CACF;AACF"}
1
+ {"version":3,"file":"index.cjs","names":["ActionsToken","NO_FRAME","ZoomMode","ZoomMode","ZOOM_MAX","ZoomMode","StageToken","ActionsToken","StageToken","ZoomMode"],"sources":["../src/working-set.ts","../src/connect.ts","../src/motion.ts","../src/camera/animation.ts","../src/responsive.ts","../src/settings.ts","../src/model.ts","../src/camera/gestures.ts","../src/camera/write.ts","../src/services/placement-latch.ts","../src/navigation/arrive.ts","../src/destination.ts","../src/navigation/reveal.ts","../src/navigation/zoom.ts","../src/read/pages.ts","../src/services/events.ts","../src/services/scene.ts","../src/services/index.ts","../src/settings/settings.ts","../src/view/lifecycle.ts","../src/controller.ts","../src/stage.plugin.ts","../src/state.ts","../src/scroll-handler.ts"],"sourcesContent":["/**\n * What this lens shows, told to the engine as the lens's working set\n * (`doc.setWorkingSet`): the engine ranks the jobs for those pages by it, and\n * keeps those pages parsed longest. Every lens tells its own, so a thumbnail\n * rail's small pages rank after the main view's.\n *\n * It comes from the pages the lens lays out (`listVisiblePages`):\n * - `visible`: a page with some of it on screen, with that part and its device\n * pixels, which rank visible pages among themselves: the page the user looks\n * at has the most;\n * - `near`: a page laid out just off screen (the scene's overscan), where the\n * view goes next.\n */\nimport type { PluginContext, WorkingSetPage } from '@embedpdf/core';\n\nimport type { VisiblePage } from './contract';\nimport type { StageHostCapability } from './host-contract';\nimport type { StageState } from './model';\n\n/** A lens's working set, from the pages it lays out. */\nexport function workingSetOf(pages: readonly VisiblePage[]): WorkingSetPage[] {\n return pages.map(({ ref, visibleRect, transform }) => {\n if (visibleRect.width <= 0 || visibleRect.height <= 0) {\n return { page: ref, role: 'near', pixels: 0 };\n }\n const pixels = visibleRect.width * visibleRect.height * transform.renderScale ** 2;\n return { page: ref, role: 'visible', visible: visibleRect, pixels: Math.round(pixels) };\n });\n}\n\n/**\n * Tells the engine what the lens shows, now and whenever it changes: once per\n * camera move, so at most once per input event while the camera moves.\n */\nexport function connectWorkingSet(\n ctx: PluginContext<StageState>,\n stage: Pick<StageHostCapability, 'listVisiblePages'>,\n): void {\n let told = '';\n const tell = (shown: readonly VisiblePage[]) => {\n const pages = workingSetOf(shown);\n const key = keyOf(pages);\n if (key === told) return;\n told = key;\n ctx.doc.setWorkingSet(ctx.id, pages);\n };\n ctx.watch(() => stage.listVisiblePages(), tell);\n tell(stage.listVisiblePages());\n}\n\n/** A working set as one comparable string. */\nfunction keyOf(pages: readonly WorkingSetPage[]): string {\n return pages\n .map(({ page, role, visible, pixels }) => {\n const part = visible\n ? `${Math.round(visible.x)},${Math.round(visible.y)},${Math.round(visible.width)},${Math.round(visible.height)}`\n : '';\n return `${page.objectNumber}:${role}:${pixels}:${part}`;\n })\n .join('|');\n}\n","/**\n * The stage's wiring to its surroundings, run once every dependency exists:\n * the refit on page-registry changes and the working set told to the engine\n * (every lens) and, for the default lens only, the page-state feed and the navigation executors of the actions\n * plugin. A thumbnail lens must never report page state or win the\n * last-wins executor registry and start navigating the sidebar.\n */\nimport type { PluginContext } from '@embedpdf/core';\nimport { ActionsToken, type ActionsHostCapability } from '@embedpdf/plugin-actions/contract/host';\n\nimport type { StageHostCapability } from './host-contract';\nimport type { StageState } from './model';\nimport { connectWorkingSet } from './working-set';\n\n/** The id of the main lens; additional lenses register under their own id. */\nexport const DEFAULT_LENS_ID = 'stage';\n\nexport function connectStage(ctx: PluginContext<StageState>, stage: StageHostCapability): void {\n // Rotate, move and delete change the registry revision, so the page geometry\n // under this lens changed: re-resolve the zoom intent and re-place. It\n // reacts to changes only, never to the initial value, so it cannot race the\n // level-triggered initial placement.\n ctx.watch(\n () => ctx.document()?.revision ?? 0,\n () => stage.refit(),\n );\n connectWorkingSet(ctx, stage);\n\n if (ctx.id !== DEFAULT_LENS_ID) return;\n const actions = ctx.tryGet(ActionsToken);\n if (!actions) return;\n feedPageState(ctx, stage, actions);\n registerNavigationExecutors(ctx, stage, actions);\n}\n\n/**\n * The page-state feed. The stage is authoritative for what page the viewer is\n * on; the actions plugin's lifecycle coordinator owns when page-lifecycle\n * triggers fire. The feed reports `{ currentPage, visiblePages, placed, cause }`\n * (page refs, not indexes, so reordering is safe) on placement and on every\n * change; the coordinator buffers reports until the document has opened and\n * diffs them against what it last emitted, so this side only reports.\n */\nfunction feedPageState(\n ctx: PluginContext<StageState>,\n stage: StageHostCapability,\n actions: ActionsHostCapability,\n): void {\n const snapshot = () => {\n const state = ctx.state.get();\n if (!state.placed) return null;\n return {\n currentPage: stage.getCurrentPage(),\n visiblePages: stage.listVisiblePages().map((page) => page.ref),\n cause: state.motionCause,\n };\n };\n ctx.watch(\n // The signature covers what is reported: the current page and the visible\n // page set. `cause` is left out on purpose: a cause flip alone is not a\n // page-state change and must not produce a report.\n () => {\n const current = snapshot();\n return current === null\n ? 'unplaced'\n : `${current.currentPage?.objectNumber ?? -1}|${current.visiblePages\n .map((page) => page.objectNumber)\n .sort((left, right) => left - right)\n .join(',')}`;\n },\n () => {\n const current = snapshot();\n if (current === null) return;\n actions.reportPageState({\n currentPage: current.currentPage,\n visiblePages: current.visiblePages,\n placed: true,\n cause: current.cause,\n });\n },\n );\n}\n\n/**\n * The GoTo and Named page verbs for the action engine. The dispatcher runs\n * them as deferred navigation effects, after every document node of a tree\n * succeeded, never in the middle of a walk. They move the view by its own\n * `scrollBehavior` setting, as a link does. /N Print is not handled here: the\n * dispatcher owns it (policy and the UI adapter).\n */\nfunction registerNavigationExecutors(\n ctx: PluginContext<StageState>,\n stage: StageHostCapability,\n actions: ActionsHostCapability,\n): void {\n ctx.cleanup(\n actions.registerExecutor('goto', (node) => {\n if (node.type !== 'goto') return { status: 'inert', reason: 'not a goto node' };\n if (!ctx.getPage(node.destination.page))\n return { status: 'failed', error: 'the destination page is not in this document' };\n stage.goToDestination(node.destination);\n return { status: 'executed' };\n }),\n );\n ctx.cleanup(\n actions.registerExecutor('named', (node) => {\n if (node.type !== 'named') return { status: 'inert', reason: 'not a named node' };\n switch (node.name) {\n case 'NextPage':\n stage.nextPage();\n return { status: 'executed' };\n case 'PrevPage':\n stage.previousPage();\n return { status: 'executed' };\n case 'FirstPage':\n stage.goToFirstPage();\n return { status: 'executed' };\n case 'LastPage':\n stage.goToLastPage();\n return { status: 'executed' };\n default:\n return { status: 'inert', reason: `unknown named action '${node.name}'` };\n }\n }),\n );\n}\n","/**\n * The camera's motion vocabulary, every formula pure.\n *\n * The capability owns the impure drivers (the clock's frames, state writes,\n * gesture state); the laws those drivers integrate live here, parameterized\n * by elapsed time with no state and no clock, so they are unit-testable in\n * isolation and have no plugin dependencies.\n *\n * Two families:\n * • ballistic — one per-axis law for every free motion: `glideStep` (the\n * touch fling, decaying on UIScrollView's curve) and `springStep` (a\n * critically-damped return to the clamp). A glide that reaches a content\n * edge converts to a spring with its velocity carried in, so the bounce\n * grows out of physics rather than a scripted overshoot.\n * • resistance — the iOS rubber-band curve `rubberOut` and its exact inverse\n * `rubberIn`: dragging past an edge displays an asymptotically bounded\n * stretch, and re-entering a gesture over a stretched camera (catching it\n * mid-bounce) reconstructs the finger-integrated position the curve came\n * from.\n * Plus the tween interpolators: `easeOutCubic` for coordinate tweens and\n * `zoomLerp`, a geometric zoom interpolation (zoom is multiplicative: equal\n * ratios per unit time, not equal deltas).\n */\n\n// ── constants ──\n/** Resistance coefficient of the rubber-band curve (the iOS feel). */\nexport const RUBBER = 0.55;\n/** Glide decay per ms: UIScrollView's normal deceleration rate. */\nexport const FLING_DECAY = 0.998;\n/** px/ms; below about 20 px/s the eye reads \"stopped\". */\nexport const FLING_STOP = 0.02;\n/** rad/ms; critically damped, settling in about 400 ms. */\nexport const SPRING_OMEGA = 0.015;\n\n// ── resistance (rubber-band) ──\n/**\n * Overshoot distance → displayed stretch, asymptotic to the viewport\n * dimension, so the content never leaves the screen however far the finger\n * travels. `rubberOut(0) === 0`: inside the bounds the curve is invisible.\n */\nexport const rubberOut = (distance: number, dimension: number): number =>\n (1 - 1 / ((distance * RUBBER) / dimension + 1)) * dimension;\n/** The exact inverse of `rubberOut` (defined for `stretch < dimension`). */\nexport const rubberIn = (stretch: number, dimension: number): number =>\n (stretch * dimension) / (RUBBER * (dimension - stretch));\n\n// ── ballistic (one axis, one frame) ──\n/** The state one integration step hands back; `done` means \"at rest\". */\nexport interface MotionStep {\n position: number;\n velocity: number;\n done: boolean;\n}\n/**\n * One frame of free glide: exponential velocity decay, the position advanced\n * by the midpoint integral of the decay over `elapsedMs` (exact for the\n * exponential, so frame-rate independent).\n */\nexport const glideStep = (position: number, velocity: number, elapsedMs: number): MotionStep => {\n const decay = Math.pow(FLING_DECAY, elapsedMs);\n const nextPosition = position + velocity * ((elapsedMs * (1 + decay)) / 2);\n const nextVelocity = velocity * decay;\n return Math.abs(nextVelocity) < FLING_STOP\n ? { position: nextPosition, velocity: 0, done: true }\n : { position: nextPosition, velocity: nextVelocity, done: false };\n};\n/**\n * One frame of a critically-damped spring toward `edge`: semi-implicit Euler\n * on x'' = −ω²(x−e) − 2ωx'. Lands exactly on the edge (position snapped,\n * velocity zeroed) once within half a pixel at negligible speed.\n */\nexport const springStep = (\n position: number,\n velocity: number,\n edge: number,\n elapsedMs: number,\n): MotionStep => {\n const nextVelocity =\n velocity +\n (-SPRING_OMEGA * SPRING_OMEGA * (position - edge) - 2 * SPRING_OMEGA * velocity) * elapsedMs;\n const nextPosition = position + nextVelocity * elapsedMs;\n if (Math.abs(nextPosition - edge) < 0.5 && Math.abs(nextVelocity) < 0.01) {\n return { position: edge, velocity: 0, done: true };\n }\n return { position: nextPosition, velocity: nextVelocity, done: false };\n};\n\n// ── tween interpolators ──\nexport const easeOutCubic = (progress: number): number => 1 - Math.pow(1 - progress, 3);\n/**\n * Geometric zoom interpolation: `from·(to/from)^progress`. Zoom is\n * multiplicative, so a constant-rate zoom moves equal ratios per unit time;\n * interpolating the level linearly makes the start rush and the end crawl\n * (and, under a focal anchor, swings the anchored point along a curve).\n */\nexport const zoomLerp = (from: number, to: number, progress: number): number =>\n from * Math.pow(to / from, progress);\n","/**\n * Camera motion over the host's frames (`ctx.clock`): the coordinate tween,\n * the zoom-anchored tween (it animates the invariant, so the focal page-point\n * holds still by construction), and the momentum and edge physics (glide,\n * spring). One frame is waited for at a time: `cancelAnimation`, every verb's\n * first act, is also \"catch\".\n */\nimport {\n cameraForAnchorAtScreen,\n clampCamera,\n type Anchor,\n type Camera,\n type Point,\n type Rect,\n} from '@embedpdf/core-stage';\nimport type { Cancel } from '@embedpdf/core';\n\nimport type { StageHostCapability } from '../host-contract';\nimport { easeOutCubic, FLING_STOP, glideStep, springStep, zoomLerp } from '../motion';\nimport type { StageServices } from '../services';\nimport type { StageCameraWrite } from './write';\n\n/** The default tween duration. */\nconst TWEEN_MS = 240;\n\nconst lerp = (from: number, to: number, progress: number) => from + (to - from) * progress;\n\nexport function createAnimation(\n { events, clock, scene }: Pick<StageServices, 'events' | 'clock' | 'scene'>,\n write: StageCameraWrite,\n) {\n const { motionEnded } = events;\n const { camera, viewport, buildScene, stayBounds, constraint } = scene;\n const { writeCamera, writeCameraUnclamped, axisTravels, syncCursorFromCamera } = write;\n\n // Cancels the frame the running motion waits for; null while nothing moves.\n let cancelFrame: Cancel | null = null;\n const cancelAnimation = () => {\n cancelFrame?.();\n cancelFrame = null;\n };\n /** A tween or fling reached its natural end. */\n const endMotion = () => {\n cancelFrame = null;\n motionEnded.emit({ camera: camera() });\n };\n\n // The tween clamps to an explicit bounds rect every frame (never a\n // re-derived current item), so animating toward a different item is not\n // clamped back. `then` runs on natural completion only: a cancelled tween\n // belongs to the verb that cancelled it.\n const animateTo = (target: Camera, bounds: Rect, durationMs = TWEEN_MS, then?: () => void) => {\n if (!clock.hasFrames) {\n writeCamera(target, bounds);\n then?.();\n return;\n }\n cancelAnimation();\n const from = camera();\n let started = false;\n let startedAt = 0;\n const tick = (now: number) => {\n if (!started) {\n started = true;\n startedAt = now; // anchor to the first real timestamp (works even when now === 0)\n }\n const progress = easeOutCubic(Math.min(1, (now - startedAt) / durationMs));\n writeCamera(\n {\n x: lerp(from.x, target.x, progress),\n y: lerp(from.y, target.y, progress),\n zoom: lerp(from.zoom, target.zoom, progress),\n },\n bounds,\n );\n if (progress < 1) {\n cancelFrame = clock.nextFrame(tick);\n } else {\n endMotion();\n then?.();\n }\n };\n cancelFrame = clock.nextFrame(tick);\n };\n\n /**\n * The zoom-anchored tween animates the invariant, not the coordinates: the\n * focal page-point stays at `point` while the scale changes. Lerping x, y\n * and zoom independently breaks that mid-flight, because holding a screen\n * point requires `x(t) = focal.x − point.x / zoom(t)`, hyperbolic in the\n * zoom, so linear coordinates swing the tapped point along a curve (a\n * visible dip). Here the zoom interpolates geometrically (zoom is\n * multiplicative) and each frame's camera derives from the anchor at that\n * zoom, then clamps: the focal point is stationary by construction, and a\n * zoom-out rails into its fit as the shrinking travel range lets the clamp\n * take over.\n */\n const animateZoomAnchored = (\n focal: Anchor,\n point: Point,\n targetZoom: number,\n durationMs = TWEEN_MS,\n then?: () => void,\n ) => {\n if (!clock.hasFrames) {\n const scene = buildScene();\n if (scene.itemCount) writeCamera(cameraForAnchorAtScreen(focal, scene, point, targetZoom));\n then?.();\n return;\n }\n cancelAnimation();\n const startZoom = camera().zoom;\n let started = false;\n let startedAt = 0;\n const tick = (now: number) => {\n if (!started) {\n started = true;\n startedAt = now;\n }\n const progress = easeOutCubic(Math.min(1, (now - startedAt) / durationMs));\n const zoom = zoomLerp(startZoom, targetZoom, progress);\n const scene = buildScene();\n if (scene.itemCount) writeCamera(cameraForAnchorAtScreen(focal, scene, point, zoom));\n if (progress < 1) {\n cancelFrame = clock.nextFrame(tick);\n } else {\n endMotion();\n then?.();\n }\n };\n cancelFrame = clock.nextFrame(tick);\n };\n\n // Momentum and edge physics, the driver over motion.ts's per-axis laws:\n // glide — the touch fling, decaying on UIScrollView's curve across free\n // travel;\n // spring — a critically-damped return to the clamp, entered when a glide\n // reaches a content edge (the remaining velocity becomes the\n // bounce) or when the motion starts displaced (released while\n // stretched).\n // Axes are independent (a diagonal fling can bounce off the bottom while\n // still gliding horizontally), and every trajectory ends on the clamp. It\n // shares the tween's frame, so cancelAnimation() is also \"catch\":\n // catching mid-bounce holds the stretch.\n const startCameraPhysics = (fingerVelocityX: number, fingerVelocityY: number) => {\n if (!clock.hasFrames) {\n writeCamera(camera()); // no host frames: snap straight into bounds\n return;\n }\n cancelAnimation();\n const zoom = camera().zoom;\n // Per-axis state in screen px (the camera moves opposite the finger;\n // positions scale by zoom once, here, so the laws read in px).\n interface AxisState {\n position: number;\n velocity: number;\n springing: boolean;\n done: boolean;\n }\n const start = camera();\n const startClamped = clampCamera(start, stayBounds(), viewport(), constraint());\n const startBounds = stayBounds();\n const startViewport = viewport();\n const axisState = (\n cameraPosition: number,\n clampedPosition: number,\n fingerVelocity: number,\n ): AxisState => ({\n position: cameraPosition * zoom,\n velocity: -fingerVelocity / 1000,\n springing: cameraPosition !== clampedPosition,\n done: false,\n });\n // A fitting axis takes no ballistic motion: no travel to glide across and\n // no bounce (rigid, like the platform), so its release velocity is\n // discarded. The spring stays armed for a displaced fitting axis.\n const axisX = axisState(\n start.x,\n startClamped.x,\n axisTravels(startBounds.x, startBounds.width, startViewport.width, zoom)\n ? fingerVelocityX\n : 0,\n );\n const axisY = axisState(\n start.y,\n startClamped.y,\n axisTravels(startBounds.y, startBounds.height, startViewport.height, zoom)\n ? fingerVelocityY\n : 0,\n );\n if (\n !axisX.springing &&\n !axisY.springing &&\n Math.hypot(axisX.velocity, axisY.velocity) < FLING_STOP\n ) {\n return;\n }\n let started = false;\n let lastFrameAt = 0;\n const tick = (now: number) => {\n cancelFrame = null;\n // The first frame assumes one 60 Hz step (anchored like the tween, so a\n // first timestamp of 0 works).\n const elapsedMs = started ? Math.min(64, Math.max(1, now - lastFrameAt)) : 16;\n started = true;\n lastFrameAt = now;\n // The clamp of the current position is each axis's home this frame: the\n // edge for a stretched axis, the rest point for a fitting one.\n const home = clampCamera(\n { x: axisX.position / zoom, y: axisY.position / zoom, zoom },\n stayBounds(),\n viewport(),\n constraint(),\n );\n const step = (axis: AxisState, edgeWorld: number) => {\n if (axis.done) return;\n const next = axis.springing\n ? springStep(axis.position, axis.velocity, edgeWorld * zoom, elapsedMs)\n : glideStep(axis.position, axis.velocity, elapsedMs);\n axis.position = next.position;\n axis.velocity = next.velocity;\n axis.done = next.done;\n };\n step(axisX, home.x);\n step(axisY, home.y);\n // A glide that left the travel range converts to a spring at the edge;\n // the incoming velocity carries in, so the bounce grows out of physics\n // rather than a scripted overshoot.\n const nextHome = clampCamera(\n { x: axisX.position / zoom, y: axisY.position / zoom, zoom },\n stayBounds(),\n viewport(),\n constraint(),\n );\n const convert = (axis: AxisState, clampedPosition: number) => {\n if (!axis.springing && Math.abs(clampedPosition * zoom - axis.position) > 1e-6) {\n axis.position = clampedPosition * zoom;\n axis.springing = true;\n axis.done = false;\n }\n };\n convert(axisX, nextHome.x);\n convert(axisY, nextHome.y);\n writeCameraUnclamped({ x: axisX.position / zoom, y: axisY.position / zoom, zoom });\n syncCursorFromCamera();\n if (axisX.done && axisY.done) {\n writeCamera(camera()); // the exact landing: clamped, snapped, settled\n motionEnded.emit({ camera: camera() });\n return;\n }\n cancelFrame = clock.nextFrame(tick);\n };\n cancelFrame = clock.nextFrame(tick);\n };\n\n return {\n cancelAnimation,\n animateTo,\n animateZoomAnchored,\n startCameraPhysics,\n api: {\n fling: (velocityX, velocityY) => startCameraPhysics(velocityX, velocityY),\n isMoving: () => cancelFrame !== null,\n stopMotion: () => {\n if (!cancelFrame) return;\n cancelAnimation();\n motionEnded.emit({ camera: camera() });\n },\n } satisfies Partial<StageHostCapability>,\n };\n}\nexport type StageAnimation = ReturnType<typeof createAnimation>;\n","import { NO_FRAME } from '@embedpdf/core-geometry';\nimport type { Size } from '@embedpdf/core-stage';\nimport type {\n BoxQuery,\n ResponsiveRule,\n StageBox,\n StageSettings,\n StageSettingsPatch,\n} from './contract';\n\n/**\n * Container queries for the settings bag, the pure half. The capability owns\n * the driver (when to re-resolve, how to react); the laws live here: what a\n * box is, when a query matches, and what the effective settings are. No\n * state, so they are property-testable in isolation.\n *\n * The query vocabulary is only the box: a headless, DOM-free stage knows\n * exactly one environmental fact, the viewport it was told. Anything else\n * (pointer coarseness, platform, app state) is either per event\n * (`PointerSample.pointerType`) or the app's own business via\n * `updateSettings()`.\n */\n\n/** The reported viewport as a queryable box. A square box is 'portrait' (CSS). */\nexport const boxOf = (size: Size): StageBox => ({\n width: size.width,\n height: size.height,\n orientation: size.height >= size.width ? 'portrait' : 'landscape',\n});\n\n/** All bounds inclusive, all fields optional, every condition must hold (CSS ranges). */\nexport const matchesQuery = (query: BoxQuery, box: StageBox): boolean =>\n (query.minWidth === undefined || box.width >= query.minWidth) &&\n (query.maxWidth === undefined || box.width <= query.maxWidth) &&\n (query.minHeight === undefined || box.height >= query.minHeight) &&\n (query.maxHeight === undefined || box.height <= query.maxHeight) &&\n (query.orientation === undefined || box.orientation === query.orientation);\n\nconst ruleMatches = (rule: ResponsiveRule, box: StageBox): boolean =>\n typeof rule.when === 'function' ? !!rule.when(box) : matchesQuery(rule.when, box);\n\n/**\n * Merge a patch over settings, skipping undefined values (Partial semantics).\n * Each value replaces the setting whole; a `pageFrame` that names only some\n * sides reserves 0 on the others.\n */\nexport const mergeSettings = (into: StageSettings, patch: StageSettingsPatch): StageSettings => {\n const merged = { ...into };\n let key: keyof StageSettingsPatch;\n for (key in patch) {\n const value = key === 'pageFrame' ? frameOf(patch.pageFrame) : patch[key];\n if (value !== undefined) Object.assign(merged, { [key]: value });\n }\n return merged;\n};\n\nconst frameOf = (frame: StageSettingsPatch['pageFrame']) =>\n frame === undefined ? undefined : { ...NO_FRAME, ...frame };\n\n/**\n * Setting-value equality: primitives by identity, the flat objects the\n * settings vocabulary uses (`{ px }`, `{ x, y }`, page frames, zoom specs) by\n * one level of own-key comparison. Settings values are never nested deeper.\n */\nexport const eqSetting = (left: unknown, right: unknown): boolean => {\n if (left === right) return true;\n if (typeof left !== 'object' || typeof right !== 'object' || left === null || right === null) {\n return false;\n }\n const leftKeys = Object.keys(left);\n return (\n leftKeys.length === Object.keys(right).length &&\n leftKeys.every(\n (key) => (left as Record<string, unknown>)[key] === (right as Record<string, unknown>)[key],\n )\n );\n};\n\nexport interface ResolvedResponsive {\n /** The base merged with every matching rule's patch, in source order (later wins per key). */\n effective: StageSettings;\n /** Names of the matching rules, in source order. */\n active: string[];\n}\n\nexport const resolveResponsive = (\n base: StageSettings,\n rules: readonly ResponsiveRule[],\n box: StageBox,\n): ResolvedResponsive => {\n let effective = base;\n const active: string[] = [];\n for (const rule of rules) {\n if (!ruleMatches(rule, box)) continue;\n if (rule.name !== undefined) active.push(rule.name);\n if (rule.settings) effective = mergeSettings(effective, rule.settings);\n }\n return { effective, active };\n};\n","import { ZoomMode } from '@embedpdf/core-stage';\nimport type { ResponsiveRule, StageSettings } from './contract';\nimport { eqSetting } from './responsive';\n\n/**\n * Out-of-the-box defaults: a document-reading feel. Every field is overridable\n * in `stagePlugin(config)` and at runtime through `updateSettings()`. The\n * plugin ships no named presets (\"document\", \"canvas\", …): a preset is an\n * object the app keeps and passes to `updateSettings()`, so that taxonomy\n * stays the app's concern.\n */\nexport const DEFAULT_SETTINGS: StageSettings = {\n flow: 'continuous',\n layout: 'vertical',\n spread: 'none',\n sizing: 'intrinsic',\n columns: 'square',\n bounded: true,\n padding: 24,\n gap: 16,\n pageFrame: { top: 0, right: 0, bottom: 0, left: 0 },\n direction: 'ltr',\n fitAlign: { x: 'center', y: 'center' },\n // The reading defaults: navigation lands at the top and reading start at\n // every zoom, button zoom inflates around the middle, and resizes pin the\n // top (the browser scroll model). Construction and presentation apps set\n // all of these to center/center.\n arrivalAlign: { x: 'start', y: 'start' },\n zoomAlign: { x: 'center', y: 'center' },\n anchorAlign: { x: 'start', y: 'start' },\n viewRotation: 0,\n zoom: { mode: ZoomMode.Automatic },\n scrollBehavior: 'smooth',\n interaction: true,\n panFallback: true,\n zoomGestures: true,\n // Web: 1 PDF point = 96/72 CSS px, so 100% is physically accurate. A native\n // adapter overrides this at registration with its own logical-unit factor.\n viewUnitsPerPoint: 96 / 72,\n};\n\n/**\n * Out-of-the-box responsive rules, the platform feel with zero configuration:\n * a compact container gets the thin gutter phones use (space, not device: an\n * embedded 500px pane on a desktop is compact too). Override the whole list\n * with `stagePlugin({ responsive: [...] })`; `responsive: []` opts out. The\n * 'compact' name is queryable by the app through `stage.matchesRule('compact')`.\n */\nexport const DEFAULT_RESPONSIVE: readonly ResponsiveRule[] = [\n { name: 'compact', when: { maxWidth: 600 }, settings: { padding: 4 } },\n];\n\n/**\n * How a change to each setting affects the view: the single source of truth.\n * One row per setting, completeness enforced by the compiler (`Record<keyof\n * StageSettings, …>`: adding a setting without classifying it is a type error).\n * Everything else derives from this table: the scene-cache invalidation and\n * key, `updateSettings()`'s reaction, the settings snapshot and patch picks,\n * and the React selector equality.\n *\n * 'reflow' — crosses the flow boundary: camera coordinates are meaningless\n * there, so re-place canonically onto the cursor's page.\n * 'scene' — a layout input: invalidates the scene, then re-applies the anchor.\n * 'refit' — re-resolves zoom against the (possibly re-keyed) scene: re-applies\n * the anchor without an explicit invalidation.\n * 'reclamp' — pure clamp policy: re-clamp the current camera in place.\n * 'none' — guides future verbs and the surface binding only\n * (arrival/zoom/anchor alignment, scroll behavior, input).\n *\n * The classes also carry each change's invariant — what stays fixed while the\n * view reacts: 'refit' (a zoom-intent change) holds the zoomAlign focal point;\n * 'scene' reframes (and viewport resizes) hold the anchorAlign point.\n */\nexport type SettingEffect = 'reflow' | 'scene' | 'refit' | 'reclamp' | 'none';\nexport const SETTINGS_EFFECT: Record<keyof StageSettings, SettingEffect> = {\n flow: 'reflow',\n layout: 'scene',\n spread: 'scene',\n sizing: 'scene',\n columns: 'scene',\n bounded: 'reclamp',\n padding: 'reclamp',\n gap: 'scene',\n pageFrame: 'scene',\n direction: 'scene',\n fitAlign: 'reclamp',\n arrivalAlign: 'none',\n zoomAlign: 'none',\n anchorAlign: 'none',\n viewRotation: 'scene', // a layout input: every page's footprint swaps w↔h\n zoom: 'refit',\n scrollBehavior: 'none',\n // Read by the surface binding, which rebinds its pointer input when they change.\n interaction: 'none',\n panFallback: 'none',\n zoomGestures: 'none',\n viewUnitsPerPoint: 'scene', // a layout input: changing it resizes every page\n};\nexport const SETTING_KEYS = Object.keys(SETTINGS_EFFECT) as Array<keyof StageSettings>;\n\n/** Field-by-field settings equality, derived from the registry, so a new\n * setting is covered automatically: what an adapter compares settings with. */\nexport const settingsEqual = (left: StageSettings, right: StageSettings): boolean =>\n SETTING_KEYS.every((key) => eqSetting(left[key], right[key]));\n\n/** The settings slice of a larger object (state, or a saved view), derived\n * from the registry so the shape is never spelled out by hand. */\nexport const pickSettings = (source: StageSettings): StageSettings => {\n const settings: Partial<Record<keyof StageSettings, unknown>> = {};\n for (const key of SETTING_KEYS) settings[key] = source[key];\n return settings as StageSettings;\n};\n","/**\n * The stage's session state: the flat settings bag plus the camera, the\n * viewport, the cursor and the render-commit latch. Every function below is a\n * pure transition; the controller's areas apply them with `ctx.state.update`,\n * and nothing else changes stage state.\n */\nimport type { Camera, Size } from '@embedpdf/core-stage';\n\nimport type { StageConfig, StageSettings } from './contract';\nimport { mergeSettings } from './responsive';\nimport { DEFAULT_SETTINGS } from './settings';\n\nexport interface StageState extends StageSettings {\n readonly camera: Camera;\n /**\n * One-way render-commit latch. False while the initial viewport-driven\n * placement is unresolved; true only after its camera and settings writes\n * have completed. Page and scroll screen-space reads refuse to answer while\n * false, so an adapter can never paint the placeholder camera at the origin.\n */\n readonly placed: boolean;\n /**\n * Names of the responsive rules currently matching the box, in source order.\n * State (not derived) so `matchesRule()` is reactive in every framework.\n */\n readonly activeRules: readonly string[];\n /**\n * False while the zoom is in motion, true once it has rested (about 150 ms\n * of frames without a zoom write). Device-snapping of page origins is gated\n * on this: a continuous zoom and a snapped origin cannot coexist without the\n * anchor point jittering ±0.5 device px per step, so pages place\n * fractionally while zooming and snap once at rest. Pans always snap (a pure\n * translation has no anchor error).\n */\n readonly cameraResting: boolean;\n /** The container size the host reported, in viewport px. */\n readonly viewport: Size;\n /**\n * Device pixels per view pixel (web: `window.devicePixelRatio`). Feeds each\n * page's transform so bitmaps render crisp and boxes land on the device\n * grid. Defaults to 1.\n */\n readonly dpr: number;\n /**\n * The current page index, valid in both flows. Navigation sets it; in\n * continuous flow manipulation derives it from the camera; in paged flow\n * panning never moves it (the scene is a one-item slice at this page).\n * An index, so it survives spread and layout regrouping.\n */\n readonly cursor: number;\n /**\n * What last drove the camera or cursor: `'programmatic'` for the arrival\n * and reveal verbs (the ones action executors use), `'user'` for direct\n * manipulation (wheel, drag, scrollbars, embedder scroll calls). The\n * page-state feed hands it to the actions plugin, whose cascade budget\n * counts only programmatic rounds, so user scrolling is never throttled.\n */\n readonly motionCause: 'user' | 'programmatic';\n}\n\nexport const initialStageState = (config: StageConfig): StageState => {\n // `responsive` configures the capability, not the settings: strip it so the\n // spread below stays a pure settings override.\n const { responsive: _responsive, ...overrides } = config;\n return {\n camera: { x: 0, y: 0, zoom: 1 },\n placed: false,\n cameraResting: true,\n viewport: { width: 0, height: 0 },\n dpr: 1,\n cursor: 0,\n motionCause: 'user',\n activeRules: [],\n ...mergeSettings(DEFAULT_SETTINGS, overrides),\n };\n};\n\nexport const setCamera = (state: StageState, camera: Camera): StageState =>\n state.camera === camera ? state : { ...state, camera };\n\nexport const setCameraResting = (state: StageState, resting: boolean): StageState =>\n state.cameraResting === resting ? state : { ...state, cameraResting: resting };\n\nexport const markPlaced = (state: StageState): StageState =>\n state.placed ? state : { ...state, placed: true };\n\nexport const setViewport = (state: StageState, viewport: Size): StageState =>\n state.viewport === viewport ? state : { ...state, viewport };\n\nexport const setDpr = (state: StageState, dpr: number): StageState =>\n state.dpr === dpr ? state : { ...state, dpr };\n\nexport const setCursor = (state: StageState, cursor: number): StageState =>\n state.cursor === cursor ? state : { ...state, cursor };\n\nexport const setMotionCause = (\n state: StageState,\n motionCause: StageState['motionCause'],\n): StageState => (state.motionCause === motionCause ? state : { ...state, motionCause });\n\n/**\n * Merge a settings patch. Undefined values are skipped, so a partial restore\n * never clears a setting; the area that patches decides what camera\n * follow-up the change needs.\n */\nexport function patchSettings(state: StageState, patch: Partial<StageSettings>): StageState {\n let next = state;\n let key: keyof StageSettings;\n for (key in patch) {\n const value = patch[key];\n if (value === undefined || Object.is(next[key], value)) continue;\n if (next === state) next = { ...state };\n Object.assign(next, { [key]: value });\n }\n return next;\n}\n\nexport const setActiveRules = (state: StageState, activeRules: readonly string[]): StageState =>\n state.activeRules === activeRules ? state : { ...state, activeRules };\n","/**\n * Direct manipulation: set, pan, scroll and pinch-zoom the camera, and the\n * gesture bracket. The camera moves freely and the cursor is derived from it\n * (the manipulation direction of cursor reconciliation).\n */\nimport {\n anchorAtPoint,\n cameraForAnchorAtScreen,\n cameraFromScroll,\n clampCamera,\n panByScreen,\n toWorld,\n zoomAround,\n} from '@embedpdf/core-stage';\nimport type { PluginContext } from '@embedpdf/core';\n\nimport type { StageScrollToOptions } from '../contract';\nimport type { StageHostCapability } from '../host-contract';\nimport { patchSettings, type StageState } from '../model';\nimport type { StagePageReads } from '../read/pages';\nimport type { StageServices } from '../services';\nimport type { StageAnimation } from './animation';\nimport type { StageCameraWrite } from './write';\n\nexport function createGestures(\n ctx: PluginContext<StageState>,\n { scene }: Pick<StageServices, 'scene'>,\n write: StageCameraWrite,\n { cancelAnimation, animateTo, startCameraPhysics }: StageAnimation,\n { scrollMetricsNow }: Pick<StagePageReads, 'scrollMetricsNow'>,\n) {\n const { camera, viewport, padding, buildScene, stayBounds, constraint } = scene;\n const {\n gesture,\n armRest,\n writeCamera,\n writeCameraUnclamped,\n rubberize,\n unrubberize,\n syncCursorFromCamera,\n markCause,\n } = write;\n\n const scrollTo = (options: StageScrollToOptions): void => {\n markCause('user');\n cancelAnimation();\n if (!buildScene().itemCount) return;\n const next = cameraFromScroll(camera(), stayBounds(), viewport(), padding(), options);\n if (options.behavior === 'smooth') {\n animateTo(next, stayBounds(), undefined, syncCursorFromCamera);\n } else {\n writeCamera(next);\n syncCursorFromCamera();\n }\n };\n\n return {\n api: {\n setCamera: (next) => {\n markCause('user');\n cancelAnimation();\n writeCamera(next);\n syncCursorFromCamera();\n },\n panBy: (dx, dy) => {\n markCause('user');\n cancelAnimation();\n if (gesture.depth > 0 && gesture.elastic) {\n // Elastic: integrate the finger on the unclamped camera and display\n // it through the resistance curve. Initialized from the displayed\n // camera's inverse, so catching a mid-bounce stretch continues\n // seamlessly.\n gesture.raw = panByScreen(gesture.raw ?? unrubberize(camera()), dx, dy);\n writeCameraUnclamped(rubberize(gesture.raw));\n } else {\n writeCamera(panByScreen(camera(), dx, dy));\n }\n syncCursorFromCamera();\n },\n scrollTo,\n scrollBy: ({ left, top, behavior }) => {\n const metrics = scrollMetricsNow();\n scrollTo({\n left: left === undefined ? undefined : metrics.scrollLeft + left,\n top: top === undefined ? undefined : metrics.scrollTop + top,\n behavior,\n });\n },\n zoomAround: (point, factor) => {\n cancelAnimation();\n const before = buildScene();\n // The page-relative focal point: the durable identity of \"what is\n // under the pointer\".\n const focal = before.itemCount ? anchorAtPoint(before, toWorld(camera(), point)) : null;\n writeCamera(zoomAround(camera(), point, factor));\n // Record the resulting level as the zoom intent (focal, so no\n // re-anchor). Inside a gesture bracket it is deferred to endGesture:\n // one patch per pinch instead of one per event.\n if (gesture.depth === 0) {\n ctx.state.update(patchSettings, { zoom: { level: camera().zoom } });\n }\n // When zoom is a layout input (a wrapped grid) the scene may just have\n // re-wrapped under the camera, leaving the old world point stale:\n // re-pin the same page-point under the pointer and clamp against the\n // new geometry. In every other mode the scene is unchanged and this\n // never runs.\n const after = buildScene();\n if (after !== before && focal && after.itemCount) {\n writeCamera(cameraForAnchorAtScreen(focal, after, point, camera().zoom));\n }\n // A zoom write in an elastic gesture (a pinch) re-bases the pan\n // integrator: the bounds just changed shape under the stretch, so\n // the displayed camera becomes the new reference.\n if (gesture.depth > 0 && gesture.elastic) gesture.raw = unrubberize(camera());\n syncCursorFromCamera();\n },\n beginGesture: (options) => {\n gesture.depth++;\n if (gesture.depth === 1) {\n cancelAnimation(); // catch: the next touch-down stops any tween or fling\n gesture.zoomed = false;\n gesture.elastic = options?.elastic === true;\n gesture.raw = null;\n }\n },\n endGesture: () => {\n if (gesture.depth === 0) return;\n gesture.depth--;\n if (gesture.depth > 0) return;\n gesture.raw = null;\n const wasElastic = gesture.elastic;\n gesture.elastic = false;\n if (gesture.zoomed) {\n gesture.zoomed = false;\n // The deferred zoom intent: one patch for the whole gesture. (In a\n // wrapped grid this may re-wrap the scene; the next reframe\n // re-anchors through the normal update path.)\n ctx.state.update(patchSettings, { zoom: { level: camera().zoom } });\n armRest(); // the gesture is over: the rest countdown runs now\n }\n syncCursorFromCamera();\n if (wasElastic) {\n // Released while stretched: spring home. A fling() right after\n // re-enters the same physics with the release velocity.\n const current = camera();\n const clamped = clampCamera(current, stayBounds(), viewport(), constraint());\n if (clamped.x !== current.x || clamped.y !== current.y) startCameraPhysics(0, 0);\n }\n },\n } satisfies Partial<StageHostCapability>,\n };\n}\nexport type StageGestures = ReturnType<typeof createGestures>;\n","/**\n * The camera write path: the one low-level clamped write (`writeCamera`), the\n * elastic unclamped write and its rubber-band curves, the rest detector that\n * gates device snapping, the gesture bracket state, and cursor reconciliation\n * from the camera (manipulation only; navigation sets the cursor as intent).\n */\nimport {\n clampCamera,\n anchorFromCamera,\n travelRange,\n type Camera,\n type Rect,\n} from '@embedpdf/core-stage';\nimport type { Cancel, PluginContext } from '@embedpdf/core';\n\nimport { setCamera, setCameraResting, setCursor, setMotionCause, type StageState } from '../model';\nimport { rubberIn, rubberOut } from '../motion';\nimport type { StageServices } from '../services';\n\n/** How long the zoom must hold still before the camera counts as resting. */\nconst REST_MS = 150;\n\nexport function createCameraWrite(\n ctx: PluginContext<StageState>,\n { clock, placement, scene }: Pick<StageServices, 'clock' | 'placement' | 'scene'>,\n) {\n const { camera, viewport, paged, buildScene, stayBounds, constraint } = scene;\n\n // ── the gesture bracket (touch pan and pinch) ──\n // While open, zoomAround defers its zoom-intent patch and the rest\n // countdown is held: a hesitation inside a pinch is not \"at rest\". Depth-\n // counted so nested brackets compose. An elastic gesture may also hold the\n // camera past the clamp (rubber-band); `raw` is its unclamped,\n // finger-integrated camera, which the resistance curve maps to what renders.\n const gesture = { depth: 0, zoomed: false, elastic: false, raw: null as Camera | null };\n\n // ── the camera-rest detector ──\n // Origin snapping is gated on rest (see `StageState.cameraResting`): pages\n // place fractionally while the zoom moves and snap once it has held still\n // for REST_MS.\n let cancelRest: Cancel | null = null;\n const stopRestCountdown = () => {\n cancelRest?.();\n cancelRest = null;\n };\n const armRest = () => {\n // Initial placement snaps immediately (the first paint is crisp), and a\n // host without frames keeps snapping always on: rest-gating refines live\n // gestures and is not part of the contract.\n if (!clock.hasFrames || !placement.started) return;\n ctx.state.update(setCameraResting, false);\n stopRestCountdown();\n cancelRest = clock.after(REST_MS, () => {\n cancelRest = null;\n ctx.state.update(setCameraResting, true);\n });\n };\n\n // The one low-level camera write: clamp to `bounds` and store. It never\n // touches the cursor (see syncCursorFromCamera for that policy).\n const writeCamera = (next: Camera, bounds: Rect = stayBounds()) => {\n const clamped = clampCamera(next, bounds, viewport(), constraint());\n if (clamped.zoom !== camera().zoom) {\n if (gesture.depth > 0) {\n // Mid-gesture: un-rest at once (fractional placement) but hold the\n // countdown; rest is declared at endGesture, not at a pinch hesitation.\n gesture.zoomed = true;\n ctx.state.update(setCameraResting, false);\n stopRestCountdown();\n } else {\n armRest();\n }\n }\n ctx.state.update(setCamera, clamped);\n };\n\n // ── rubber-band (elastic overscroll) ──\n // The curve pair lives in motion.ts; these adapt it to camera state. The\n // rubber softens only the edges of a scroll range: an axis whose content\n // fits the viewport has no travel, the clamp holds it at its fitAlign rest,\n // and it stays rigid however hard the finger tugs (the UIScrollView\n // default: bouncing exists only where content exceeds the bounds).\n const axisTravels = (origin: number, content: number, view: number, zoom: number): boolean =>\n !travelRange(origin, content, view, zoom, constraint().padding).fits;\n /** The unclamped finger-integrated camera → the displayed camera: clamp,\n * then re-apply the overshoot through the resistance curve, per travelling\n * axis. Inside the bounds this is exactly the clamp, and on a fitting axis\n * it is always the clamp. */\n const rubberize = (raw: Camera): Camera => {\n const clamped = clampCamera(raw, stayBounds(), viewport(), constraint());\n const size = viewport();\n const bounds = stayBounds();\n const axis = (\n rawPosition: number,\n clampedPosition: number,\n dimension: number,\n travels: boolean,\n ): number => {\n if (!travels) return clampedPosition;\n const overshootWorld = rawPosition - clampedPosition;\n if (overshootWorld === 0) return clampedPosition;\n const stretch = rubberOut(Math.abs(overshootWorld) * raw.zoom, Math.max(1, dimension));\n return clampedPosition + (Math.sign(overshootWorld) * stretch) / raw.zoom;\n };\n return {\n zoom: raw.zoom,\n x: axis(\n raw.x,\n clamped.x,\n size.width,\n axisTravels(bounds.x, bounds.width, size.width, raw.zoom),\n ),\n y: axis(\n raw.y,\n clamped.y,\n size.height,\n axisTravels(bounds.y, bounds.height, size.height, raw.zoom),\n ),\n };\n };\n /** The displayed camera → the raw position `rubberize` would have produced\n * it from. The overshoot is capped just under the asymptote so the inverse\n * stays finite whatever state a catch finds the camera in. */\n const unrubberize = (displayed: Camera): Camera => {\n const clamped = clampCamera(displayed, stayBounds(), viewport(), constraint());\n const size = viewport();\n const bounds = stayBounds();\n const axis = (\n displayedPosition: number,\n clampedPosition: number,\n dimension: number,\n travels: boolean,\n ): number => {\n if (!travels) return clampedPosition;\n const overshootWorld = displayedPosition - clampedPosition;\n if (overshootWorld === 0) return clampedPosition;\n const span = Math.max(1, dimension);\n const stretch = Math.min(Math.abs(overshootWorld) * displayed.zoom, span - 1);\n return (\n clampedPosition + (Math.sign(overshootWorld) * rubberIn(stretch, span)) / displayed.zoom\n );\n };\n return {\n zoom: displayed.zoom,\n x: axis(\n displayed.x,\n clamped.x,\n size.width,\n axisTravels(bounds.x, bounds.width, size.width, displayed.zoom),\n ),\n y: axis(\n displayed.y,\n clamped.y,\n size.height,\n axisTravels(bounds.y, bounds.height, size.height, displayed.zoom),\n ),\n };\n };\n // The elastic write path, with no clamp: used only by the elastic pan and\n // the edge spring, whose math guarantees every trajectory ends clamped.\n const writeCameraUnclamped = (next: Camera) => ctx.state.update(setCamera, next);\n\n /**\n * Cursor reconciliation, one direction per interaction:\n * navigation → the cursor is intent, set explicitly; the camera honors\n * it as far as the clamp allows, and a clamped camera\n * never revokes it.\n * manipulation → (pan, drag, pinch) the camera moves freely and the\n * cursor is derived from it. Only those verbs call this.\n * Paged flow never syncs.\n */\n const syncCursorFromCamera = () => {\n if (paged()) return;\n const scene = buildScene();\n if (!scene.itemCount) return;\n ctx.state.update(setCursor, anchorFromCamera(camera(), scene, viewport()).pageIndex);\n };\n\n /** Tag what drives the next camera or cursor change (see `StageState.motionCause`). */\n const markCause = (cause: StageState['motionCause']): void =>\n ctx.state.update(setMotionCause, cause);\n\n return {\n gesture,\n armRest,\n writeCamera,\n writeCameraUnclamped,\n axisTravels,\n rubberize,\n unrubberize,\n syncCursorFromCamera,\n markCause,\n };\n}\nexport type StageCameraWrite = ReturnType<typeof createCameraWrite>;\n","/**\n * The behavioral placement latch: it flips when initial placement starts,\n * while `StageState.placed` is the render-commit latch that flips only after\n * placement finishes. Camera behavior keys on this one; renderers key on\n * `placed`, so partial geometry is never observable.\n */\nimport type { ScrollBehaviorKind } from '../contract';\n\nexport interface PlacementLatch {\n started: boolean;\n /** The last navigation asked for before placement; placement applies it last. */\n pending: (() => void) | null;\n}\n\nexport const createPlacementLatch = (): PlacementLatch => ({ started: false, pending: null });\n\n/**\n * Run a navigation verb now, or, before the first placement, when it happens.\n * Before placement there is no viewport to move a camera in, and placement\n * would reset it anyway, so the last call waits and lands instantly after the\n * initial view: an app that reveals something as the document opens sees it\n * on the first frame.\n */\nexport function whenPlaced<Options extends { behavior?: ScrollBehaviorKind }>(\n latch: PlacementLatch,\n options: Options | undefined,\n run: (options: Options | undefined) => void,\n): void {\n if (latch.started) {\n run(options);\n return;\n }\n latch.pending = () => run({ ...options, behavior: 'instant' } as Options);\n}\n","/**\n * Anchors and arrivals. The anchor is the durable \"what am I looking at\":\n * captured before a structural change and re-applied after, one mechanism for\n * layout, spread, zoom, resize and restore. Navigation is canonical:\n * goToPage(N) always ends in the same camera state whatever the zoom or the\n * starting point.\n */\nimport {\n cameraFromAnchor,\n clampCamera,\n placeCamera,\n resolveZoom,\n type AlignmentValue,\n type Anchor,\n type Camera,\n type Rect,\n} from '@embedpdf/core-stage';\nimport type { PluginContext } from '@embedpdf/core';\n\nimport type { GoToOptions } from '../contract';\nimport type { StageAnimation } from '../camera/animation';\nimport type { StageCameraWrite } from '../camera/write';\nimport type { StageHostCapability } from '../host-contract';\nimport { patchSettings, setCursor, type StageState } from '../model';\nimport type { StageServices } from '../services';\nimport { whenPlaced } from '../services/placement-latch';\n\nexport function createArrival(\n ctx: PluginContext<StageState>,\n { scene, placement }: Pick<StageServices, 'scene' | 'placement'>,\n { writeCamera, markCause }: Pick<StageCameraWrite, 'writeCamera' | 'markCause'>,\n { cancelAnimation, animateTo }: Pick<StageAnimation, 'cancelAnimation' | 'animateTo'>,\n) {\n const {\n camera,\n viewport,\n padding,\n paged,\n isFitAll,\n grouping,\n itemIndexOfPage,\n buildScene,\n sceneRect,\n itemRect,\n pageRectOf,\n cursorItem,\n fits,\n alignPoint,\n fitBox,\n boundsFor,\n constraint,\n indexOfTarget,\n } = scene;\n const state = () => ctx.state.get();\n const pageCount = () => ctx.document()?.pageCount ?? 0;\n\n /**\n * Run a placement whose resolved zoom may change the scene (in wrapped mode\n * zoom is a layout input), until the scene it placed against is the scene\n * that results. Every non-wrapped mode is stable after the first pass, and\n * wrapped fit modes converge on the second (the fit box does not depend on\n * wrapping). Capped at 3 passes for the one circular case (fit-all +\n * wrapped).\n */\n const stabilized = (place: () => void) => {\n for (let attempt = 0; attempt < 3; attempt++) {\n const before = buildScene();\n place();\n if (buildScene() === before) return;\n }\n };\n\n const applyAnchor = (anchor: Anchor, align?: AlignmentValue) => {\n stabilized(() => {\n const current = buildScene();\n if (!current.itemCount) return;\n const item = current.items[current.itemOfPage(anchor.pageIndex)];\n const zoom = resolveZoom(state().zoom, fitBox(item), viewport(), padding());\n // Resolved against the current viewport: a resize restores the anchor\n // to the new viewport's policy point (start/start keeps the top pinned).\n const at = alignPoint(align ?? state().anchorAlign, viewport());\n writeCamera(cameraFromAnchor(anchor, current, viewport(), zoom, at), boundsFor(item));\n });\n };\n /**\n * Re-apply the view after a structural, zoom or viewport change. Normally\n * anchor-preserving (keep looking at the same spot, held at the invariant\n * point). Under fit-all the subject is the whole scene, so keeping an\n * anchor is meaningless: re-place instead (which also centers the scene\n * when unbounded).\n */\n const reapply = (anchor: Anchor, align?: AlignmentValue) => {\n if (isFitAll()) goToTarget(state().cursor, { behavior: 'instant' });\n else applyAnchor(anchor, align);\n };\n\n const goToTarget = (pageIndex: number, options?: GoToOptions) => {\n markCause('programmatic');\n cancelAnimation();\n if (pageCount() === 0) return;\n const target = Math.max(0, Math.min(pageIndex, pageCount() - 1));\n ctx.state.update(setCursor, target);\n\n // The restore path (per-page view memory): the exact viewpoint instead of\n // a fresh placement.\n if (options?.viewpoint) {\n ctx.state.update(patchSettings, { zoom: options.viewpoint.zoom });\n applyAnchor(options.viewpoint.anchor);\n return;\n }\n\n // Placement against the current scene; null when there is nothing to place.\n const placement = (): { camera: Camera; bounds: Rect } | null => {\n const current = buildScene(); // paged: the (possibly new) slice; continuous: the full scene\n if (!current.itemCount) return null;\n const item = paged() ? current.items[0] : current.items[itemIndexOfPage(target)];\n const zoom = resolveZoom(state().zoom, fitBox(item), viewport(), padding());\n const subject = isFitAll()\n ? sceneRect()\n : fits(itemRect(item), zoom)\n ? itemRect(item)\n : pageRectOf(item, target);\n // The landing policy: a per-call override beats the setting, and 'keep'\n // pins that axis to the current camera.\n const landing = { ...state().arrivalAlign, ...options?.arrivalAlign };\n const placed = placeCamera(\n subject,\n viewport(),\n zoom,\n padding(),\n {\n x: landing.x === 'keep' ? 'start' : landing.x,\n y: landing.y === 'keep' ? 'start' : landing.y,\n },\n state().direction,\n );\n // Arrivals are canonical even on an unbounded stage: the landing clamps\n // within the true bounds regardless (free roam is a manipulation\n // affordance, not an arrival one), so an axis with no freedom collapses\n // to its fitAlign rest and the fit-all scene centers even unbounded.\n const bounds = boundsFor(item);\n const settled = clampCamera(placed, bounds, viewport(), { ...constraint(), bounded: true });\n return {\n camera: {\n zoom,\n x: landing.x === 'keep' ? camera().x : settled.x,\n y: landing.y === 'keep' ? camera().y : settled.y,\n },\n bounds,\n };\n };\n\n if ((options?.behavior ?? state().scrollBehavior) === 'smooth') {\n const landing = placement();\n if (landing) animateTo(landing.camera, landing.bounds);\n } else {\n // An instant placement converges with the scene (wrapped: zoom is a layout input).\n stabilized(() => {\n const landing = placement();\n if (landing) writeCamera(landing.camera, landing.bounds);\n });\n }\n };\n\n /** Step by the navigation unit: the item when it fits the viewport, else the page. */\n const step = (direction: 1 | -1, options?: GoToOptions) => {\n const item = cursorItem();\n if (!item) return;\n const { grouping: groups } = grouping();\n if (isFitAll() || fits(itemRect(item), camera().zoom)) {\n const index = Math.max(\n 0,\n Math.min(itemIndexOfPage(state().cursor) + direction, groups.length - 1),\n );\n goToTarget(groups[index][0], options);\n } else {\n goToTarget(state().cursor + direction, options);\n }\n };\n\n // Home is page 0, a fresh arrival at arrivalAlign (the clamp collapses any\n // fitting axis to its fitAlign rest point).\n const resetView = (): void => goToTarget(0, { behavior: 'instant' });\n\n return {\n stabilized,\n applyAnchor,\n reapply,\n goToTarget,\n resetView,\n api: {\n goToPage: (page, options) => {\n const index = indexOfTarget(page);\n if (index !== null) whenPlaced(placement, options, (go) => goToTarget(index, go));\n },\n goToFirstPage: (options) => whenPlaced(placement, options, (go) => goToTarget(0, go)),\n goToLastPage: (options) =>\n whenPlaced(placement, options, (go) =>\n goToTarget(Math.max(0, (ctx.document()?.pageCount ?? 1) - 1), go),\n ),\n canGoNext: () => state().cursor < pageCount() - 1,\n canGoPrevious: () => state().cursor > 0,\n nextPage: (options) => whenPlaced(placement, options, (go) => step(1, go)),\n previousPage: (options) => whenPlaced(placement, options, (go) => step(-1, go)),\n resetView,\n } satisfies Partial<StageHostCapability>,\n };\n}\nexport type StageArrival = ReturnType<typeof createArrival>;\n","/**\n * A destination as a reveal. A destination (ISO 32000-1 §12.3.2.2) says\n * where on a page to look and how close; the stage's reveal takes the same\n * three knobs:\n * rect — what to look at: a point for `xyz`, a rect for `fitR`, the page\n * for `fit` and the `fitB*` kinds\n * zoom — 'keep' | {level} | 'fit' | 'fit-width' | 'fit-height'\n * anchor — where it lands; 'keep' is the specification's `null`: keep the\n * current value on that axis\n *\n * Destinations are in page space, the stage's own space, so nothing converts.\n * The `fitB*` kinds fit the page's content bounding box; the whole page\n * stands in for it.\n */\nimport type { PageDestination, PdfSize } from '@embedpdf/core';\n\nimport type { RevealOptions } from './contract';\n\nexport function revealOfDestination(destination: PageDestination, size: PdfSize): RevealOptions {\n const { width, height } = size;\n switch (destination.kind) {\n case 'xyz': {\n const { x, y, zoom } = destination;\n return {\n // A null axis keeps the current camera value; the number fed in for\n // it is never read (the 'keep' anchor).\n rect: { x: x ?? 0, y: y ?? 0, width: 0, height: 0 },\n anchor: { x: x != null ? 'start' : 'keep', y: y != null ? 'start' : 'keep' },\n // A zoom of 0 means the same as null: keep the current zoom.\n zoom: zoom != null && zoom !== 0 ? { level: zoom } : 'keep',\n };\n }\n case 'fit':\n return { zoom: 'fit' };\n case 'fitB':\n return { rect: { x: 0, y: 0, width, height }, zoom: 'fit' };\n case 'fitH':\n case 'fitBH': {\n const { y } = destination;\n return {\n rect: { x: 0, y: y ?? 0, width, height: 0 },\n zoom: 'fit-width',\n anchor: { y: y != null ? 'start' : 'keep' },\n };\n }\n case 'fitV':\n case 'fitBV': {\n const { x } = destination;\n return {\n rect: { x: x ?? 0, y: 0, width: 0, height },\n zoom: 'fit-height',\n anchor: { x: x != null ? 'start' : 'keep' },\n };\n }\n case 'fitR': {\n const { x, y, width: rectWidth, height: rectHeight } = destination;\n return { rect: { x, y, width: rectWidth, height: rectHeight }, zoom: 'fit' };\n }\n }\n}\n","/**\n * Reveals and destinations. A bare reveal is not navigation: minimal\n * visibility, cursor untouched (in paged flow, revealing a page is navigating\n * to it). A positioned reveal (rect, anchor or zoom: a search hit) is an\n * arrival: the cursor is set up front, the camera lands per the anchor\n * policy, and a resolved zoom becomes the zoom intent. A destination is a\n * positioned reveal of the spot it names.\n */\nimport { revealCamera, type Camera, type Rect as StageRect } from '@embedpdf/core-stage';\nimport type { PageDestination, PluginContext, PageRef } from '@embedpdf/core';\n\nimport type { GoToDestinationOptions, RevealAnchorValue, RevealOptions } from '../contract';\nimport { revealOfDestination } from '../destination';\nimport type { StageAnimation } from '../camera/animation';\nimport type { StageCameraWrite } from '../camera/write';\nimport type { StageHostCapability } from '../host-contract';\nimport { patchSettings, setCursor, type StageState } from '../model';\nimport type { StageServices } from '../services';\nimport { whenPlaced } from '../services/placement-latch';\nimport type { StageArrival } from './arrive';\n\nexport function createReveal(\n ctx: PluginContext<StageState>,\n { scene, placement }: Pick<StageServices, 'scene' | 'placement'>,\n { writeCamera, markCause }: Pick<StageCameraWrite, 'writeCamera' | 'markCause'>,\n { cancelAnimation, animateTo }: Pick<StageAnimation, 'cancelAnimation' | 'animateTo'>,\n { stabilized, goToTarget }: Pick<StageArrival, 'stabilized' | 'goToTarget'>,\n) {\n const {\n camera,\n viewport,\n padding,\n paged,\n itemIndexOfPage,\n worldPageFrame,\n buildScene,\n sceneRect,\n pageRectOf,\n worldRectForContent,\n boundsFor,\n indexOfTarget,\n } = scene;\n const state = () => ctx.state.get();\n\n /**\n * One axis of a positioned-reveal camera. `undefined` is 'nearest' (move\n * only when the target is outside the padded view), unless the zoom just\n * changed: then \"do not move\" is meaningless and the slack-axis rule\n * (center) applies. 'keep' never moves the axis (PDF /XYZ null).\n */\n const revealAxis = (\n anchor: RevealAnchorValue | undefined,\n cameraPosition: number,\n rectPosition: number,\n rectExtent: number,\n viewportExtent: number,\n zoom: number,\n zoomChanged: boolean,\n ): number => {\n if (anchor === 'keep') return cameraPosition;\n const inset = padding();\n if (anchor === undefined) {\n if (!zoomChanged) {\n const low = cameraPosition + inset / zoom;\n const high = cameraPosition + (viewportExtent - inset) / zoom;\n if (rectPosition >= low && rectPosition + rectExtent <= high) return cameraPosition; // already visible\n if (rectExtent > high - low || rectPosition < low) return rectPosition - inset / zoom;\n return rectPosition + rectExtent - (viewportExtent - inset) / zoom;\n }\n anchor = 'center';\n }\n if (anchor === 'start') return rectPosition - inset / zoom;\n if (anchor === 'end') return rectPosition + rectExtent - (viewportExtent - inset) / zoom;\n const fraction = anchor === 'center' ? 0.5 : Math.min(1, Math.max(0, anchor));\n return rectPosition + rectExtent / 2 - (viewportExtent * fraction) / zoom;\n };\n\n const revealAt = (pageIndex: number, options?: RevealOptions): void => {\n markCause('programmatic');\n const pageCount = ctx.document()?.pageCount ?? 0;\n if (pageCount === 0) return;\n const target = Math.max(0, Math.min(pageIndex, pageCount - 1));\n const positioned =\n !!options &&\n // `rect: null` means \"no rect\", the same as absent, so nullable sources\n // flow in without a `?? undefined`.\n (options.rect != null ||\n options.anchor !== undefined ||\n (options.zoom !== undefined && options.zoom !== 'keep'));\n\n if (!positioned) {\n // A bare reveal is not navigation: minimal visibility, cursor untouched.\n if (paged()) {\n // The page is not in the one-item slice: revealing it is navigating to it.\n goToTarget(target, options);\n return;\n }\n const current = buildScene();\n if (!current.itemCount) return;\n const page = pageRectOf(current.items[itemIndexOfPage(target)], target);\n // Reveal the outer box: pageFrame chrome (labels, buttons) belongs to\n // the page, so \"make the page visible\" includes its reserved bands.\n const frame = worldPageFrame();\n const box = {\n x: page.x - frame.left,\n y: page.y - frame.top,\n width: page.width + frame.left + frame.right,\n height: page.height + frame.top + frame.bottom,\n };\n const next = revealCamera(camera(), box, viewport(), padding());\n const now = camera();\n if (next.x === now.x && next.y === now.y) return; // already visible\n cancelAnimation();\n if ((options?.behavior ?? state().scrollBehavior) === 'smooth') {\n animateTo(next, sceneRect());\n } else {\n writeCamera(next, sceneRect());\n }\n return;\n }\n\n // A positioned reveal is an arrival at a rect or point (a search hit, a\n // PDF destination). Like navigation, the cursor is intent, set up front\n // (in paged flow this also rebuilds the one-item slice), never derived\n // from a camera that may be mid-tween.\n cancelAnimation();\n ctx.state.update(setCursor, target);\n\n const place = (): { camera: Camera; bounds: StageRect; zoomChanged: boolean } | null => {\n const current = buildScene();\n if (!current.itemCount) return null;\n const item = paged() ? current.items[0] : current.items[itemIndexOfPage(target)];\n const world = options.rect\n ? worldRectForContent(item, target, options.rect)\n : pageRectOf(item, target);\n const zoomDirective = options.zoom ?? 'keep';\n const availableWidth = Math.max(1, viewport().width - 2 * padding());\n const availableHeight = Math.max(1, viewport().height - 2 * padding());\n let zoom =\n typeof zoomDirective === 'object'\n ? zoomDirective.level\n : zoomDirective === 'fit'\n ? Math.min(availableWidth / world.width, availableHeight / world.height)\n : zoomDirective === 'fit-width'\n ? availableWidth / world.width\n : zoomDirective === 'fit-height'\n ? availableHeight / world.height\n : camera().zoom;\n // A degenerate target (a point with a fit directive) only pans.\n if (!Number.isFinite(zoom) || zoom <= 0) zoom = camera().zoom;\n const zoomChanged = zoomDirective !== 'keep';\n const anchor = options.anchor ?? {};\n return {\n camera: {\n x: revealAxis(\n anchor.x,\n camera().x,\n world.x,\n world.width,\n viewport().width,\n zoom,\n zoomChanged,\n ),\n y: revealAxis(\n anchor.y,\n camera().y,\n world.y,\n world.height,\n viewport().height,\n zoom,\n zoomChanged,\n ),\n zoom,\n },\n bounds: boundsFor(item),\n zoomChanged,\n };\n };\n\n const first = place();\n if (!first) return;\n // A resolved zoom becomes the zoom intent (like zoomAround), so later\n // resizes and refits keep the destination's magnification.\n if (first.zoomChanged) {\n ctx.state.update(patchSettings, { zoom: { level: first.camera.zoom } });\n }\n if ((options.behavior ?? state().scrollBehavior) === 'smooth') {\n // If the zoom patch re-wrapped the scene (zoom is a layout input in\n // wrapped mode), recompute once against the new geometry.\n const landing = place() ?? first;\n animateTo(landing.camera, landing.bounds);\n } else {\n stabilized(() => {\n const landing = place();\n if (landing) writeCamera(landing.camera, landing.bounds);\n });\n }\n };\n\n const reveal = (page: PageRef | number, options?: RevealOptions): void => {\n const index = indexOfTarget(page);\n if (index !== null) whenPlaced(placement, options, (go) => revealAt(index, go));\n };\n\n const goToDestination = (\n destination: PageDestination,\n options?: GoToDestinationOptions,\n ): void => {\n const layout = ctx.getPage(destination.page);\n if (!layout) return;\n const spot = revealOfDestination(destination, layout.size);\n whenPlaced(placement, { ...spot, behavior: options?.behavior }, (go) =>\n revealAt(layout.index, go),\n );\n };\n\n return {\n api: { reveal, goToDestination } satisfies Partial<StageHostCapability>,\n };\n}\n","/**\n * Zoom verbs. Pointer-less zooms magnify around the zoomAlign focal point\n * (pinch and wheel pass their own pointer to `zoomAround`: physics beats\n * policy); fit modes are zoom intents written through the settings; the\n * double-tap ladder ascends reading postures.\n */\nimport { anchorAtPoint, resolveZoom, toWorld, ZOOM_MAX, ZoomMode } from '@embedpdf/core-stage';\nimport { addRotations, type PageRotation } from '@embedpdf/core-geometry';\nimport type { PluginContext } from '@embedpdf/core';\n\nimport type { StageAnimation } from '../camera/animation';\nimport type { StageCameraWrite } from '../camera/write';\nimport type { StageGestures } from '../camera/gestures';\nimport type { StageHostCapability } from '../host-contract';\nimport { patchSettings, type StageState } from '../model';\nimport type { StageServices } from '../services';\nimport type { StageSettingsArea } from '../settings/settings';\n\n/** The zoom factor of one zoomIn or zoomOut step. */\nconst ZOOM_STEP = 1.2;\n\nexport function createZoom(\n ctx: PluginContext<StageState>,\n { scene }: Pick<StageServices, 'scene'>,\n { syncCursorFromCamera }: Pick<StageCameraWrite, 'syncCursorFromCamera'>,\n {\n cancelAnimation,\n animateZoomAnchored,\n }: Pick<StageAnimation, 'cancelAnimation' | 'animateZoomAnchored'>,\n gestures: StageGestures['api'],\n settings: Pick<StageSettingsArea, 'updateSettings'>,\n) {\n const { camera, viewport, padding, paged, itemIndexOfPage, buildScene, alignPoint, fitBox } =\n scene;\n const state = () => ctx.state.get();\n const zoomAlignPoint = () => alignPoint(state().zoomAlign, viewport());\n\n const setViewRotation = (viewRotation: PageRotation): void =>\n settings.updateSettings({ viewRotation });\n\n return {\n api: {\n doubleTapZoom: (point) => {\n cancelAnimation();\n const before = buildScene();\n if (!before.itemCount) return;\n const item = paged() ? before.items[0] : before.items[itemIndexOfPage(state().cursor)];\n // The ladder (the platform convention) ascends reading postures, each\n // derived from a zoom intent: see the page (automatic), read the text\n // (fit-width), inspect (2.5× the automatic fit). Stops within 10% of\n // a neighbor collapse, so on phones, where automatic is fit-width,\n // the ladder is the familiar two-state toggle.\n //\n // As on iOS, the ladder ascends only from a rung: a tap at a posture\n // moves to the next, wrapping past the top. A pinch to any other\n // level leaves the ladder, and a double-tap there resets to the base\n // fit (\"take me back to reading\"), never a further zoom-in.\n const fit = fitBox(item);\n const automatic = resolveZoom({ mode: ZoomMode.Automatic }, fit, viewport(), padding());\n const fitWidth = resolveZoom({ mode: ZoomMode.FitWidth }, fit, viewport(), padding());\n const stops = [automatic, fitWidth, Math.min(automatic * 2.5, ZOOM_MAX)]\n .sort((left, right) => left - right)\n .filter((zoom, index, all) => index === 0 || zoom > all[index - 1] * 1.1);\n // The same ±10% band the dedupe uses: \"at a posture\" tolerates fit drift.\n const near = (zoom: number, stop: number) => zoom > stop / 1.1 && zoom < stop * 1.1;\n const onRung = stops.findIndex((stop) => near(camera().zoom, stop));\n const target = onRung >= 0 ? stops[(onRung + 1) % stops.length] : stops[0];\n // The intent commits up front, as in `reveal`: a caught tween must\n // never leave the camera at an intermediate zoom while the stored\n // intent still says \"fit\", or the next refit would snap somewhere the\n // user did not ask for.\n ctx.state.update(patchSettings, { zoom: { level: target } });\n // Wrapped grids re-layout on the intent change: anchor the focal\n // point against the scene that will actually be on screen.\n const after = buildScene();\n if (!after.itemCount) return;\n const focal = anchorAtPoint(after, toWorld(camera(), point));\n // The focal-anchored tween keeps the tapped point still.\n animateZoomAnchored(focal, point, target, undefined, syncCursorFromCamera);\n },\n zoomIn: () => gestures.zoomAround(zoomAlignPoint(), ZOOM_STEP),\n zoomOut: () => gestures.zoomAround(zoomAlignPoint(), 1 / ZOOM_STEP),\n zoomTo: (zoom, options) => {\n if (typeof zoom === 'number') {\n if (options?.around) gestures.zoomAround(options.around, zoom / camera().zoom);\n else settings.updateSettings({ zoom: { level: zoom } });\n return;\n }\n settings.updateSettings({ zoom });\n },\n zoomBy: (factor, options) => gestures.zoomAround(options?.around ?? zoomAlignPoint(), factor),\n fitWidth: () => settings.updateSettings({ zoom: { mode: ZoomMode.FitWidth } }),\n fitPage: () => settings.updateSettings({ zoom: { mode: ZoomMode.FitPage } }),\n fitAll: () => settings.updateSettings({ zoom: { mode: ZoomMode.FitAll } }),\n fitAutomatic: () => settings.updateSettings({ zoom: { mode: ZoomMode.Automatic } }),\n setViewRotation,\n rotateViewBy: (delta) =>\n setViewRotation(addRotations(state().viewRotation, delta === 90 ? 90 : 270)),\n } satisfies Partial<StageHostCapability>,\n };\n}\n","/**\n * The page reads: laid-out pages with their transforms (PDF points → view px\n * → device px), the scroller projection, the visible set (memoized so reads\n * stay reference-stable), coordinate conversions and the camera, zoom and\n * viewpoint reads.\n */\nimport {\n cameraWorldRect,\n scrollMetrics,\n toScreen,\n toWorld,\n type PageBox,\n type ScrollMetrics,\n type Size,\n} from '@embedpdf/core-stage';\nimport {\n applyPoint,\n applyRect,\n displaySize,\n intersectRects,\n pageTransform,\n rotateScaleMatrix,\n snapToDevice,\n} from '@embedpdf/core-geometry';\nimport type { Point } from '@embedpdf/core-geometry';\nimport { memo, toPageRef, type PluginContext, type PageRef } from '@embedpdf/core';\n\nimport type { Viewpoint, VisiblePage } from '../contract';\nimport type { StageHostCapability } from '../host-contract';\nimport type { StageState } from '../model';\nimport type { StageServices } from '../services';\n\nexport function createPageReads(\n ctx: PluginContext<StageState>,\n { scene }: Pick<StageServices, 'scene'>,\n) {\n const {\n camera,\n viewport,\n dpr,\n padding,\n paged,\n buildScene,\n cacheKey,\n stayBounds,\n cursorItem,\n currentAnchor,\n } = scene;\n const state = () => ctx.state.get();\n\n // The durable identity of the page at a display index, from the registry.\n const pageObjectNumberAt = (index: number): number =>\n ctx.document()?.pages[index]?.ref.objectNumber ?? index + 1;\n\n // The un-rotated point size of a laid-out box, for when the registry entry\n // is momentarily absent. `displaySize` is its own inverse (display box →\n // content box); dividing by contentScale recovers points.\n const unrotatedPoints = (box: PageBox): Size => {\n const content = displaySize({ width: box.width, height: box.height }, box.rotation);\n return { width: content.width / box.contentScale, height: content.height / box.contentScale };\n };\n\n // Attach durable identity and the per-page transform (PDF points → view px\n // → device px). `scale` is view px per point: contentScale (world per\n // point) × zoom (view px per world); `pageSize` is the page's un-rotated\n // points from the registry. The transform depends only on zoom, rotation,\n // contentScale and dpr, so the same box yields the same transform at any pan.\n const withTransform = (box: PageBox): VisiblePage => {\n const registered = ctx.document()?.pages[box.pageIndex];\n const pageSize = registered\n ? { width: registered.size.width, height: registered.size.height }\n : unrotatedPoints(box);\n const current = camera();\n const ratio = dpr();\n // The footprint's top-left, camera-resolved. Device-snapped at rest, which\n // keeps a rotated page on the device grid; while the zoom moves it places\n // fractionally (see `StageState.cameraResting`).\n const rawX = (box.x - current.x) * current.zoom;\n const rawY = (box.y - current.y) * current.zoom;\n const resting = state().cameraResting;\n const screenX = resting ? snapToDevice(rawX, ratio) : rawX;\n const screenY = resting ? snapToDevice(rawY, ratio) : rawY;\n const transform = pageTransform({\n pageSize,\n rotation: box.rotation,\n scale: box.contentScale * current.zoom,\n // The page's physical 100%: the platform unit factor × its /UserUnit,\n // so `transform.zoom` reads as \"percent of Acrobat's 100%\" per page,\n // independent of sizing mode or camera state.\n baseScale: state().viewUnitsPerPoint * (registered?.userUnit ?? 1),\n dpr: ratio,\n });\n // The on-screen page region in points: viewport ∩ footprint in view\n // space (both axis-aligned), inverted through the transform (exact for\n // quarter-turns). The virtualizer's query already decided this coarsely;\n // it is refined per page here, once, so no adapter re-derives camera math\n // (tiling's demand reads this field).\n const size = viewport();\n const onScreen = intersectRects(\n { x: -screenX, y: -screenY, width: size.width, height: size.height },\n { x: 0, y: 0, width: transform.viewWidth, height: transform.viewHeight },\n );\n const visibleRect =\n onScreen.width > 0 && onScreen.height > 0\n ? transform.viewToPageRect(onScreen)\n : { x: 0, y: 0, width: 0, height: 0 };\n return {\n ...box,\n ref: toPageRef(pageObjectNumberAt(box.pageIndex)),\n screenX,\n screenY,\n transform,\n visibleRect,\n };\n };\n\n // The scroller projection: the camera in native DOM vocabulary, against the\n // same bounds the pan clamp uses (stayBounds: the slice item in paged flow,\n // the scene in continuous). Memoized like the visible pages: the same\n // reference until a field moves, so adapter reads can use plain equality.\n const emptyScrollMetrics: ScrollMetrics = {\n scrollLeft: 0,\n scrollTop: 0,\n scrollWidth: 0,\n scrollHeight: 0,\n clientWidth: 0,\n clientHeight: 0,\n scrollableX: false,\n scrollableY: false,\n };\n let lastMetrics: ScrollMetrics | null = null;\n const scrollMetricsNow = (): ScrollMetrics => {\n if (!state().placed) return emptyScrollMetrics;\n const metrics = scrollMetrics(\n camera(),\n buildScene().itemCount ? stayBounds() : { x: 0, y: 0, width: 0, height: 0 },\n viewport(),\n padding(),\n );\n const previous = lastMetrics;\n if (\n previous &&\n previous.scrollLeft === metrics.scrollLeft &&\n previous.scrollTop === metrics.scrollTop &&\n previous.scrollWidth === metrics.scrollWidth &&\n previous.scrollHeight === metrics.scrollHeight &&\n previous.clientWidth === metrics.clientWidth &&\n previous.clientHeight === metrics.clientHeight\n ) {\n return previous; // scrollableX/Y derive from the six numbers\n }\n lastMetrics = metrics;\n return metrics;\n };\n\n // The visible pages, memoized on everything they depend on so the read is\n // reference-stable (no useSyncExternalStore tearing loop). Paged flow\n // renders only the slice's item; continuous flow renders the camera's\n // query window.\n const noVisiblePages: VisiblePage[] = [];\n const placedVisiblePages = memo(\n () => {\n const current = camera();\n const size = viewport();\n buildScene(); // keys the scene cache that `cacheKey` reads\n return [\n cacheKey(),\n state().flow,\n current.x,\n current.y,\n current.zoom,\n size.width,\n size.height,\n dpr(),\n state().cameraResting,\n ] as const;\n },\n (_sceneKey, _flow, x, y, zoom, width, height, _dpr, _resting): VisiblePage[] => {\n const scene = buildScene();\n const items = paged()\n ? scene.items.slice(0, 1)\n : scene.query(cameraWorldRect({ x, y, zoom }, { width, height }));\n return items.flatMap((item) => item.pages).map(withTransform);\n },\n );\n const visiblePages = (): VisiblePage[] =>\n state().placed ? placedVisiblePages() : noVisiblePages;\n\n const getPageFrame = (page: PageRef | number): VisiblePage | null => {\n if (!state().placed) return null;\n const index = ctx.getPage(page)?.index ?? -1;\n if (index < 0) return null;\n const scene = buildScene();\n if (!scene.itemCount) return null;\n const box = scene.items[scene.itemOfPage(index)].pages.find(\n (candidate) => candidate.pageIndex === index,\n );\n return box ? withTransform(box) : null;\n };\n\n const pageToWorld = (page: PageRef | number, point: Point): Point | null => {\n const frame = getPageFrame(page);\n if (!frame) return null;\n // Place the page point into the page's display box through the same\n // quarter-turn matrix the layout and renderer use (`rotateScaleMatrix`),\n // so this forward transform and the adapter's inverse hit-test cannot\n // drift. `displaySize` is its own inverse, so it recovers the un-rotated\n // content size from the display box.\n const content = displaySize({ width: frame.width, height: frame.height }, frame.rotation);\n const matrix = rotateScaleMatrix(\n frame.contentScale,\n content.width,\n content.height,\n frame.rotation,\n );\n const offset = applyPoint(matrix, point);\n return { x: frame.x + offset.x, y: frame.y + offset.y };\n };\n\n // The visible entry of a page given by its ref or its index; null when it is\n // off screen or not in the document.\n const visiblePageOf = (page: PageRef | number): VisiblePage | null => {\n const objectNumber = ctx.getPage(page)?.ref.objectNumber;\n if (objectNumber === undefined) return null;\n return visiblePages().find((visible) => visible.ref.objectNumber === objectNumber) ?? null;\n };\n\n return {\n scrollMetricsNow,\n visiblePages,\n api: {\n getCamera: camera,\n getViewportSize: viewport,\n getScrollMetrics: scrollMetricsNow,\n listVisiblePages: visiblePages,\n isPageVisible: (page) => visiblePageOf(page) !== null,\n getCurrentPageIndex: () => state().cursor,\n getCurrentPage: () => ctx.document()?.pages[state().cursor]?.ref ?? null,\n getPageCount: () => ctx.document()?.pageCount ?? 0,\n listCurrentItemPages: () => {\n const item = cursorItem();\n const pages = ctx.document()?.pages ?? [];\n return item\n ? item.pageIndexes.map((index) => pages[index]).filter((page) => page !== undefined)\n : [];\n },\n getPageFrame,\n getPageAt: (point) => {\n // Find the visible page whose device-snapped display box contains the\n // point, then invert that page's transform: the same `viewToPage`\n // the per-page context's `toPagePoint` uses, so the two never drift.\n for (const page of visiblePages()) {\n const localX = point.x - page.screenX;\n const localY = point.y - page.screenY;\n if (\n localX >= 0 &&\n localY >= 0 &&\n localX <= page.transform.viewWidth &&\n localY <= page.transform.viewHeight\n ) {\n return {\n ref: page.ref,\n point: page.transform.viewToPage({ x: localX, y: localY }),\n scale: page.transform.viewScale,\n rotation: page.rotation,\n zoom: page.transform.zoom,\n };\n }\n }\n return null;\n },\n viewportToPage: (page, point) => {\n // `getPageAt` without the containment check: project onto one page's\n // plane, valid outside its bounds, through the same inverse transform.\n const target = visiblePageOf(page);\n if (!target) return null;\n return target.transform.viewToPage({\n x: point.x - target.screenX,\n y: point.y - target.screenY,\n });\n },\n pageToWorld,\n pageRectToViewport: (page, rect) => {\n const frame = getPageFrame(page);\n if (!frame) return null;\n const content = displaySize({ width: frame.width, height: frame.height }, frame.rotation);\n const matrix = rotateScaleMatrix(\n frame.contentScale,\n content.width,\n content.height,\n frame.rotation,\n );\n const world = applyRect(matrix, rect);\n const current = camera();\n const topLeft = toScreen(current, { x: frame.x + world.x, y: frame.y + world.y });\n return {\n x: topLeft.x,\n y: topLeft.y,\n width: world.width * current.zoom,\n height: world.height * current.zoom,\n };\n },\n worldToViewport: (world) => toScreen(camera(), world),\n viewportToWorld: (point) => toWorld(camera(), point),\n pageToViewport: (page, point) => {\n const world = pageToWorld(page, point);\n return world ? toScreen(camera(), world) : null;\n },\n getViewRotation: () => state().viewRotation,\n getZoomLevel: () => camera().zoom,\n getZoomMode: () => {\n const zoom = state().zoom;\n return 'mode' in zoom ? zoom.mode : 'custom';\n },\n getViewpoint: (): Viewpoint => ({ anchor: currentAnchor(), zoom: state().zoom }),\n } satisfies Partial<StageHostCapability>,\n };\n}\nexport type StagePageReads = ReturnType<typeof createPageReads>;\n","/**\n * The stage's six events. Five of them are derived in one `ctx.state.onChange`\n * listener, from the state before and after each committed change, so a new\n * verb can never forget to announce a page, zoom, camera, settings or viewport\n * change. `motionEnded` is an occurrence: the camera animation emits it where a\n * tween or fling ends.\n */\nimport type { PluginContext } from '@embedpdf/core';\n\nimport type {\n StageCameraChangedEvent,\n StageMotionEndedEvent,\n StagePageChangedEvent,\n StageSettingsChangedEvent,\n StageViewportChangedEvent,\n StageZoomChangedEvent,\n} from '../contract';\nimport type { StageState } from '../model';\nimport { eqSetting } from '../responsive';\nimport { pickSettings, SETTING_KEYS } from '../settings';\n\nexport function createEvents(ctx: PluginContext<StageState>) {\n const pageChanged = ctx.events.source<StagePageChangedEvent>();\n const zoomChanged = ctx.events.source<StageZoomChangedEvent>();\n const cameraChanged = ctx.events.source<StageCameraChangedEvent>();\n const motionEnded = ctx.events.source<StageMotionEndedEvent>();\n const settingsChanged = ctx.events.source<StageSettingsChangedEvent>();\n const viewportChanged = ctx.events.source<StageViewportChangedEvent>();\n\n ctx.state.onChange(({ previous, next }) => {\n if (previous.camera !== next.camera) {\n cameraChanged.emit({ camera: next.camera });\n if (previous.camera.zoom !== next.camera.zoom) {\n zoomChanged.emit({\n level: next.camera.zoom,\n previousLevel: previous.camera.zoom,\n mode: 'mode' in next.zoom ? next.zoom.mode : 'custom',\n });\n }\n }\n if (previous.cursor !== next.cursor) {\n pageChanged.emit({\n page: ctx.document()?.pages[next.cursor]?.ref ?? null,\n pageIndex: next.cursor,\n previousPageIndex: previous.cursor,\n });\n }\n if (previous.viewport !== next.viewport) viewportChanged.emit({ size: next.viewport });\n const changed = SETTING_KEYS.filter((key) => !eqSetting(previous[key], next[key]));\n if (changed.length) settingsChanged.emit({ settings: pickSettings(next), changed });\n });\n\n return { pageChanged, zoomChanged, cameraChanged, motionEnded, settingsChanged, viewportChanged };\n}\nexport type StageEvents = ReturnType<typeof createEvents>;\n","/**\n * The scene model: the document's item grouping, the layout, the memoized\n * scene (continuous flow lays out the whole document; paged flow a one-item\n * slice at the origin), and the pure geometry reads every area builds on:\n * fit, alignment points, clamp bounds and anchors. Reads only; nothing here\n * changes state.\n */\nimport {\n anchorFromCamera,\n gridLayout,\n groupPages,\n linearLayout,\n ZoomMode,\n type AlignmentValue,\n type AlignValue,\n type Anchor,\n type CameraConstraint,\n type PageFrame,\n type Point,\n type Rect as StageRect,\n type Scene,\n type SceneItem,\n type Size,\n} from '@embedpdf/core-stage';\nimport { addRotations, applyRect, displaySize, rotateScaleMatrix } from '@embedpdf/core-geometry';\nimport type { Rect } from '@embedpdf/core-geometry';\nimport { memo, type PluginContext, type PageRef } from '@embedpdf/core';\n\nimport type { StageSettings } from '../contract';\nimport type { StageState } from '../model';\nimport { SETTINGS_EFFECT, SETTING_KEYS } from '../settings';\n\nexport function createScene(ctx: PluginContext<StageState>) {\n const state = () => ctx.state.get();\n const camera = () => state().camera;\n const viewport = () => state().viewport;\n const dpr = () => state().dpr;\n const padding = () => state().padding;\n const paged = () => state().flow === 'paged';\n const isFitAll = () => {\n const zoom = state().zoom;\n return 'mode' in zoom && zoom.mode === ZoomMode.FitAll;\n };\n\n // The document's item model (spread grouping) is independent of the\n // rendered scene, so navigation can reason about every item while a paged\n // scene holds only one. The cursor is a page; `itemIndexOfPage` maps it,\n // which survives regrouping.\n const grouping = memo(\n () => [ctx.document()?.pageCount ?? 0, state().spread] as const,\n (pageCount, spread): { grouping: number[][]; firstPages: number[] } => {\n const groups = groupPages(pageCount, spread);\n return { grouping: groups, firstPages: groups.map((item) => item[0]) };\n },\n );\n const itemCountFull = (): number => grouping().grouping.length;\n const itemIndexOfPage = (pageIndex: number): number => {\n const firstPages = grouping().firstPages;\n let low = 0;\n let high = firstPages.length;\n while (low < high) {\n const middle = (low + high) >> 1;\n if (firstPages[middle] <= pageIndex) low = middle + 1;\n else high = middle;\n }\n return Math.max(0, low - 1);\n };\n\n // The zoom that converts screen-px settings into world units. A fixed zoom\n // intent gives an exact, stable value (the thumbnail case); other intents\n // use the camera's current zoom, which `stabilized` converges. Screen-px\n // settings (the wrapped line width, pageFrame, `{ px }` gaps) are the only\n // way a scene depends on the viewport or the zoom.\n const effectiveZoom = (): number => {\n const zoom = state().zoom;\n return 'level' in zoom ? zoom.level : Math.max(state().camera.zoom, 0.0001);\n };\n\n // Wrapped grid: the line width (world units) the columns must fit.\n const wrapLineWidth = (): number =>\n Math.max(1, (viewport().width - 2 * padding()) / effectiveZoom());\n\n // pageFrame (screen px) → world units at the effective zoom.\n const worldPageFrame = (): PageFrame => {\n const frame = state().pageFrame;\n if (!frame.top && !frame.right && !frame.bottom && !frame.left) return frame;\n const zoom = effectiveZoom();\n return {\n top: frame.top / zoom,\n right: frame.right / zoom,\n bottom: frame.bottom / zoom,\n left: frame.left / zoom,\n };\n };\n const frameKey = (): string => {\n const frame = state().pageFrame;\n if (!frame.top && !frame.right && !frame.bottom && !frame.left) return '-';\n const world = worldPageFrame();\n return `${Math.round(world.top)},${Math.round(world.right)},${Math.round(world.bottom)},${Math.round(world.left)}`;\n };\n\n // gap → world units. A plain number is world units (the scene stays\n // zoom-invariant, the rigid-canvas default); `{ px }` converts at the\n // effective zoom like pageFrame (UI-stable spacing for browser-style lenses).\n const worldGap = (): number => {\n const gap = state().gap;\n return typeof gap === 'number' ? gap : gap.px ? gap.px / effectiveZoom() : 0;\n };\n const gapKey = (): string => {\n const gap = state().gap;\n return typeof gap === 'number' ? String(gap) : `px:${Math.round(worldGap())}`;\n };\n\n const layoutFor = (groups: number[][]): Scene => {\n const settings = state();\n // Engine page layouts structurally satisfy stage-core's page geometry\n // (`size` + `rotation`): the intrinsic page size flows straight in.\n //\n // The view rotation is composed here, and only here: each page's display\n // rotation is its /Rotate plus this lens's viewRotation. Everything\n // downstream (the display-size swap, the page transform, hit-testing, fit\n // zoom, overlays) reads the composed rotation. `size` stays the page's\n // own un-rotated points, so page space is view-rotation-invariant.\n const registryPages = ctx.document()?.pages ?? [];\n const viewRotation = settings.viewRotation;\n const pages =\n viewRotation === 0\n ? registryPages\n : registryPages.map((page) => ({\n ...page,\n rotation: addRotations(page.rotation, viewRotation),\n }));\n const pageFrame = worldPageFrame();\n const gap = worldGap();\n const viewUnitsPerPoint = settings.viewUnitsPerPoint;\n if (settings.layout === 'grid') {\n return gridLayout(pages, groups, {\n gap,\n sizing: settings.sizing,\n direction: settings.direction,\n pageFrame,\n viewUnitsPerPoint,\n columns: typeof settings.columns === 'number' ? settings.columns : undefined,\n lineWidth: settings.columns === 'auto' ? wrapLineWidth() : undefined,\n });\n }\n return linearLayout(pages, groups, {\n axis: settings.layout === 'horizontal' ? 'x' : 'y',\n gap,\n sizing: settings.sizing,\n direction: settings.direction,\n pageFrame,\n viewUnitsPerPoint,\n });\n };\n\n // The column policy's part of the scene key; 'auto' quantizes the line\n // width so sub-pixel resizes do not rebuild the scene.\n const columnsKey = (): string => {\n const settings = state();\n if (settings.layout !== 'grid') return '-';\n return settings.columns === 'auto'\n ? `auto:${Math.round(wrapLineWidth())}`\n : String(settings.columns);\n };\n\n // The scene's settings signature, derived from the settings registry: every\n // 'scene' setting contributes automatically, so a new layout-affecting\n // setting only needs its SETTINGS_EFFECT row and a stale scene cannot be\n // forgotten here. Values key by value (objects via JSON); the custom\n // functions quantize px-derived values so sub-pixel zoom and resize churn\n // does not rebuild the scene.\n const SCENE_KEY_FUNCTIONS: Partial<Record<keyof StageSettings, () => string>> = {\n columns: columnsKey,\n gap: gapKey,\n pageFrame: frameKey,\n };\n const SCENE_KEYS = SETTING_KEYS.filter((key) => SETTINGS_EFFECT[key] === 'scene');\n const settingsKey = (): string =>\n SCENE_KEYS.map((key) => {\n const keyFunction = SCENE_KEY_FUNCTIONS[key];\n if (keyFunction) return keyFunction();\n const value = state()[key];\n return typeof value === 'object' && value !== null ? JSON.stringify(value) : String(value);\n }).join('|');\n\n // The scene cache. Continuous flow lays out the whole document. Paged flow\n // is a one-item slice at the origin holding only the cursor's item, so\n // isolation is structural (no other page exists to leak into view),\n // unbounded pan is free, and coordinates stay local.\n let sceneCache: { key: string; scene: Scene } | null = null;\n // The registry signature: page count plus the kernel's monotonic\n // `revision`. The revision changes on every page mutation (rotate, move,\n // delete), so a change that keeps the page count (a rotation) still re-keys\n // the scene instead of rendering the page in its stale box.\n const documentKey = (): string => {\n const document = ctx.document();\n return document ? `${document.pageCount}.${document.revision}` : '0.0';\n };\n const buildScene = (): Scene => {\n const { grouping: groups } = grouping();\n if (state().flow === 'paged') {\n const index = groups.length\n ? Math.min(itemIndexOfPage(state().cursor), groups.length - 1)\n : 0;\n const key = `paged|${documentKey()}|${settingsKey()}|${index}`;\n if (sceneCache && sceneCache.key === key) return sceneCache.scene;\n const scene = layoutFor(groups.length ? [groups[index]] : []);\n sceneCache = { key, scene };\n return scene;\n }\n const key = `continuous|${documentKey()}|${settingsKey()}`;\n if (sceneCache && sceneCache.key === key) return sceneCache.scene;\n const scene = layoutFor(groups);\n sceneCache = { key, scene };\n return scene;\n };\n /** Drop the memoized scene (a 'scene' or 'reflow' setting changed, or a view was restored). */\n const invalidate = (): void => {\n sceneCache = null;\n };\n /** The current scene's cache key, part of the visible-pages signature. */\n const cacheKey = (): string => sceneCache!.key;\n\n // ── geometry helpers ──\n const sceneRect = (): StageRect => {\n const { width, height } = buildScene().size;\n return { x: 0, y: 0, width, height };\n };\n const itemRect = (item: SceneItem): StageRect => ({\n x: item.x,\n y: item.y,\n width: item.width,\n height: item.height,\n });\n const pageRectOf = (item: SceneItem, pageIndex: number): StageRect => {\n const box = item.pages.find((page) => page.pageIndex === pageIndex) ?? item.pages[0];\n return { x: box.x, y: box.y, width: box.width, height: box.height };\n };\n /** The item shown for the cursor: the slice's only item (paged) or the full-scene item. */\n const cursorItem = (): SceneItem => {\n const scene = buildScene();\n return paged() ? scene.items[0] : scene.items[itemIndexOfPage(state().cursor)];\n };\n\n /**\n * A page-space rect on a page → a world rect: the same quarter-turn\n * matrix `pageRectToViewport` uses, minus the camera, so a positioned\n * reveal and the rendered overlay never disagree about where a rect is.\n */\n const worldRectForContent = (item: SceneItem, pageIndex: number, rect: Rect): StageRect => {\n const box = item.pages.find((page) => page.pageIndex === pageIndex) ?? item.pages[0];\n const content = displaySize({ width: box.width, height: box.height }, box.rotation);\n const matrix = rotateScaleMatrix(box.contentScale, content.width, content.height, box.rotation);\n const world = applyRect(matrix, rect);\n return { x: box.x + world.x, y: box.y + world.y, width: world.width, height: world.height };\n };\n\n // Does this rect fit the padded viewport at this zoom? It decides the\n // navigation step size and the arrival subject, never the alignment.\n const fits = (rect: StageRect, zoom: number): boolean => {\n const size = viewport();\n const inset = padding();\n const tolerance = 0.5;\n return (\n rect.width * zoom <= size.width - 2 * inset + tolerance &&\n rect.height * zoom <= size.height - 2 * inset + tolerance\n );\n };\n // An alignment policy → a concrete viewport point: a fraction per axis\n // (start = 0, center = ½, end = 1; named x stops are logical under RTL).\n // zoomAlign and anchorAlign both resolve through this. The fraction spans\n // the padded range: 'start' is the first visible content line just inside\n // the gutter, where an arrival puts the page edge, so the reference pins\n // to the page and never to the gap above it.\n const alignFraction = (value: AlignValue): number =>\n value === 'start'\n ? 0\n : value === 'center'\n ? 0.5\n : value === 'end'\n ? 1\n : Math.min(1, Math.max(0, value));\n const alignPoint = (alignment: AlignmentValue, size: Size): Point => {\n const rtl = state().direction === 'rtl';\n const alignX =\n rtl && alignment.x === 'start' ? 'end' : rtl && alignment.x === 'end' ? 'start' : alignment.x;\n const inset = padding();\n return {\n x: inset + (size.width - 2 * inset) * alignFraction(alignX),\n y: inset + (size.height - 2 * inset) * alignFraction(alignment.y),\n };\n };\n const anchorPoint = (): Point => alignPoint(state().anchorAlign, viewport());\n\n /** The box the zoom intent fits: the whole scene (fit-all), the current\n * item (paged: per-page fit), or the document maximum (continuous: a\n * document-stable zoom). */\n const fitBox = (item: SceneItem): Size => {\n if (isFitAll()) return buildScene().size;\n return paged() ? { width: item.width, height: item.height } : buildScene().maxItemSize;\n };\n /** The clamp rect for a camera write targeting this item (the scene in continuous flow). */\n const boundsFor = (item: SceneItem): StageRect => (paged() ? itemRect(item) : sceneRect());\n /** The clamp rect for a write that stays put (pan, zoom): the slice item (paged) or the scene. */\n const stayBounds = (): StageRect => (paged() ? itemRect(buildScene().items[0]) : sceneRect());\n\n const constraint = (): CameraConstraint => ({\n bounded: state().bounded,\n padding: padding(),\n fitAlign: state().fitAlign,\n direction: state().direction,\n });\n\n const anchorAt = (at: Point): Anchor => {\n const scene = buildScene();\n return scene.itemCount\n ? anchorFromCamera(camera(), scene, viewport(), at)\n : { pageIndex: state().cursor, fx: 0.5, fy: 0 };\n };\n const currentAnchor = (): Anchor => anchorAt(anchorPoint());\n\n const indexOfPage = (page: PageRef): number => ctx.getPage(page)?.index ?? -1;\n /**\n * A page argument (a `PageRef` or a display index) as a display index, or\n * null when it names no page: a ref not in the document, or a number that\n * isn't a whole number. An index past either end is kept; arrivals clamp it.\n */\n const indexOfTarget = (page: PageRef | number): number | null => {\n if (typeof page === 'number') return Number.isInteger(page) ? page : null;\n const index = indexOfPage(page);\n return index >= 0 ? index : null;\n };\n\n return {\n camera,\n viewport,\n dpr,\n padding,\n paged,\n isFitAll,\n grouping,\n itemCountFull,\n itemIndexOfPage,\n worldPageFrame,\n buildScene,\n invalidate,\n cacheKey,\n sceneRect,\n itemRect,\n pageRectOf,\n cursorItem,\n worldRectForContent,\n fits,\n alignPoint,\n anchorPoint,\n fitBox,\n boundsFor,\n stayBounds,\n constraint,\n anchorAt,\n currentAnchor,\n indexOfPage,\n indexOfTarget,\n };\n}\nexport type StageScene = ReturnType<typeof createScene>;\n","/**\n * Plugin-private services every area is built on: the events, the host's\n * clock, the placement latch and the scene model.\n */\nimport type { PluginClock, PluginContext } from '@embedpdf/core';\n\nimport type { StageState } from '../model';\nimport { createEvents, type StageEvents } from './events';\nimport { createPlacementLatch, type PlacementLatch } from './placement-latch';\nimport { createScene, type StageScene } from './scene';\n\nexport interface StageServices {\n readonly events: StageEvents;\n /** Time, from the host (`ctx.clock`): the tweens, flings and the rest countdown run on it. */\n readonly clock: PluginClock;\n readonly placement: PlacementLatch;\n readonly scene: StageScene;\n}\n\nexport function createServices(ctx: PluginContext<StageState>): StageServices {\n return {\n events: createEvents(ctx),\n clock: ctx.clock,\n placement: createPlacementLatch(),\n scene: createScene(ctx),\n };\n}\n","/**\n * The settings bag and its responsive resolution. The base (config plus\n * `updateSettings()` changes) merged with the matching rules' patches is the effective\n * settings the state holds. `applySettings` is the one reactive applier: the\n * strongest effect among the touched settings wins ('reflow' ⊃ 'scene'/'refit'\n * ⊃ 'reclamp' ⊃ 'none'), so a breakpoint crossing gets exactly the invariant a\n * hand-written update would.\n */\nimport { memo, type PluginContext } from '@embedpdf/core';\n\nimport type {\n ResponsiveRule,\n StageConfig,\n StageSettings,\n StageSettingsPatch,\n StageViewState,\n} from '../contract';\nimport type { StageAnimation } from '../camera/animation';\nimport type { StageCameraWrite } from '../camera/write';\nimport type { StageHostCapability } from '../host-contract';\nimport { patchSettings, setActiveRules, setCursor, type StageState } from '../model';\nimport type { StageArrival } from '../navigation/arrive';\nimport { boxOf, eqSetting, mergeSettings, resolveResponsive } from '../responsive';\nimport type { StageServices } from '../services';\nimport { DEFAULT_RESPONSIVE, pickSettings, SETTINGS_EFFECT, SETTING_KEYS } from '../settings';\nimport type { SettingEffect } from '../settings';\n\nconst EFFECT_RANK: Record<SettingEffect, number> = {\n none: 0,\n reclamp: 1,\n refit: 2,\n scene: 3,\n reflow: 4,\n};\n\nexport function createSettings(\n ctx: PluginContext<StageState>,\n { scene }: Pick<StageServices, 'scene'>,\n config: StageConfig,\n { writeCamera }: Pick<StageCameraWrite, 'writeCamera'>,\n { cancelAnimation }: Pick<StageAnimation, 'cancelAnimation'>,\n {\n applyAnchor,\n reapply,\n goToTarget,\n }: Pick<StageArrival, 'applyAnchor' | 'reapply' | 'goToTarget'>,\n) {\n const { camera, viewport, alignPoint, anchorAt } = scene;\n const state = () => ctx.state.get();\n\n // The same object while no setting changed, so readers compare by identity.\n const snapshotSettings: () => StageSettings = memo(\n () => SETTING_KEYS.map((key) => state()[key]),\n () => pickSettings(state()),\n );\n\n /**\n * React to a settings change per the registry: the strongest effect among\n * the touched settings wins. Both the public `updateSettings()` and the\n * responsive driver land here.\n */\n const applySettings = (patch: Partial<StageSettings>) => {\n cancelAnimation();\n const touched = (effect: SettingEffect) =>\n SETTING_KEYS.some((key) => patch[key] !== undefined && SETTINGS_EFFECT[key] === effect);\n // The change's invariant point: a pure zoom-intent change ('refit' alone)\n // holds the zoomAlign focal point, so zoomTo and fit-mode switches magnify\n // around the same spot the zoom buttons do; every other reframe holds the\n // anchorAlign reference. Resolved once, used for capture and restore.\n const align =\n touched('refit') && !touched('scene') && !touched('reflow')\n ? state().zoomAlign\n : state().anchorAlign;\n const anchor = anchorAt(alignPoint(align, viewport())); // captured against the current scene\n ctx.state.update(patchSettings, patch);\n if (touched('scene')) scene.invalidate();\n if (touched('reflow')) {\n // The flow toggled: re-place onto the cursor's page under the new\n // flow's scene (camera coordinates are meaningless across the flow\n // boundary).\n goToTarget(state().cursor, { behavior: 'instant' });\n } else if (touched('scene') || touched('refit')) {\n reapply(anchor, align); // rebuild, keep the page, re-fit (fit-all re-places the scene)\n } else if (touched('reclamp')) {\n writeCamera(camera()); // the clamp policy changed: re-clamp the current camera\n }\n // 'none' (arrivalAlign, zoomAlign, anchorAlign, scrollBehavior) guides future verbs only.\n };\n\n // ── responsive settings (container queries for the settings bag) ──\n // Rules assert at transitions (box, base or rules changes), which is why\n // the sync diffs against the last effective resolution, never against live\n // state: between crossings interaction owns the state (a pinch-zoomed level\n // survives a resize unless a rule actually flips), and keys the rules do\n // not touch are never re-asserted.\n let base = snapshotSettings();\n const initialBase = base;\n let rules: readonly ResponsiveRule[] = config.responsive ?? DEFAULT_RESPONSIVE;\n let lastEffective = base; // rules first assert when a real box arrives\n const publishActive = (active: readonly string[]) => {\n const current = state().activeRules;\n if (current.length !== active.length || active.some((name, index) => name !== current[index])) {\n ctx.state.update(setActiveRules, active);\n }\n };\n /**\n * Re-resolve and apply what changed since the last resolution. `react:\n * true` routes the patch through `applySettings` (the full\n * anchor-preserving update); `react: false` (inside `setViewportSize`,\n * whose caller runs its own reframe) only lands the patch and the cache\n * invalidation and reports the strongest effect, so the caller can\n * escalate a rule-driven flow flip.\n */\n const syncResponsive = (react: boolean): SettingEffect => {\n const { effective, active } = resolveResponsive(base, rules, boxOf(viewport()));\n const patch: Partial<StageSettings> = {};\n for (const key of SETTING_KEYS) {\n if (!eqSetting(effective[key], lastEffective[key])) {\n Object.assign(patch, { [key]: effective[key] });\n }\n }\n lastEffective = effective;\n publishActive(active);\n const keys = Object.keys(patch) as Array<keyof StageSettings>;\n if (keys.length === 0) return 'none';\n if (react) {\n applySettings(patch);\n return 'none'; // reacted in full: nothing left for the caller\n }\n ctx.state.update(patchSettings, patch);\n let strongest: SettingEffect = 'none';\n for (const key of keys) {\n if (EFFECT_RANK[SETTINGS_EFFECT[key]] > EFFECT_RANK[strongest]) {\n strongest = SETTINGS_EFFECT[key];\n }\n }\n if (strongest === 'scene' || strongest === 'reflow') scene.invalidate();\n return strongest;\n };\n\n const updateSettings = (changes: StageSettingsPatch): void => {\n // Writes the responsive base; the resolver decides what actually lands (a\n // matching rule's key wins until its rule stops matching). With no rules\n // in play this is a direct update.\n base = mergeSettings(base, changes);\n syncResponsive(true);\n };\n\n const applyViewState = (view: StageViewState): void => {\n cancelAnimation();\n // A restored view is app-level state: it writes the base, and the rules\n // re-assert on top, so a snapshot saved on a desktop restores compact\n // padding on a phone. One patch carries the full effective result.\n base = mergeSettings(base, pickSettings(view));\n const { effective, active } = resolveResponsive(base, rules, boxOf(viewport()));\n lastEffective = effective;\n publishActive(active);\n ctx.state.update(patchSettings, effective);\n ctx.state.update(setCursor, view.cursor ?? 0);\n scene.invalidate();\n applyAnchor(view.anchor);\n };\n\n return {\n snapshotSettings,\n syncResponsive,\n updateSettings,\n applyViewState,\n api: {\n getSettings: snapshotSettings,\n resetSettings: () => {\n base = mergeSettings(initialBase, {});\n syncResponsive(true);\n },\n updateSettings,\n setResponsiveRules: (next) => {\n rules = next;\n syncResponsive(true);\n },\n matchesRule: (name) => state().activeRules.includes(name),\n listActiveRules: () => state().activeRules,\n applyViewState,\n } satisfies Partial<StageHostCapability>,\n };\n}\nexport type StageSettingsArea = ReturnType<typeof createSettings>;\n","/**\n * The view lifecycle: the viewport report (initial placement is\n * level-triggered here, the moment the stage first learns a real size and the\n * document has pages), the device pixel ratio, initial-view providers resolved\n * once by priority, the refit after page-registry changes, and the view\n * memento reads.\n */\nimport type { PluginContext } from '@embedpdf/core';\n\nimport type { StageViewState } from '../contract';\nimport type { StageAnimation } from '../camera/animation';\nimport type { StageHostCapability } from '../host-contract';\nimport { markPlaced, setDpr, setViewport, type StageState } from '../model';\nimport type { StageArrival } from '../navigation/arrive';\nimport type { StageServices } from '../services';\nimport type { StageSettingsArea } from '../settings/settings';\n\ninterface InitialViewProvider {\n readonly priority: number;\n readonly provide: () => StageViewState | null;\n}\n\nexport function createViewLifecycle(\n ctx: PluginContext<StageState>,\n { scene, placement }: Pick<StageServices, 'scene' | 'placement'>,\n { cancelAnimation }: Pick<StageAnimation, 'cancelAnimation'>,\n arrive: Pick<StageArrival, 'goToTarget' | 'reapply' | 'resetView'>,\n settings: Pick<StageSettingsArea, 'snapshotSettings' | 'syncResponsive' | 'applyViewState'>,\n) {\n const { dpr, currentAnchor } = scene;\n const { goToTarget, reapply } = arrive;\n const { snapshotSettings, syncResponsive } = settings;\n const state = () => ctx.state.get();\n\n // Initial-view providers (a storage restore, a deep link, an explicit\n // prop). One owner, `placeInitial`, resolves them by priority, so there is\n // no ordering race between the providers.\n const initialViewProviders: InitialViewProvider[] = [];\n\n const placeInitial = (): void => {\n placement.started = true;\n const byPriority = [...initialViewProviders].sort(\n (left, right) => right.priority - left.priority,\n );\n let view: StageViewState | null = null;\n for (const provider of byPriority) {\n view = provider.provide();\n if (view) break;\n }\n if (view) settings.applyViewState(view);\n else arrive.resetView();\n // Navigation the app asked for before there was a viewport lands last,\n // from the initial view, so the first frame already shows it.\n const pending = placement.pending;\n placement.pending = null;\n pending?.();\n // Publish renderability last. The viewport, responsive and camera writes\n // above are ordinary observable state changes, but page and scroll reads\n // return stable empty values until this commit lands.\n ctx.state.update(markPlaced);\n };\n\n return {\n api: {\n setViewportSize: (size) => {\n // Initial placement is level-triggered here: the moment the stage\n // first learns a real size (both axes) and the document has pages,\n // resolve the initial view (providers, else a reset). Every report\n // re-checks the condition, so there is no edge to miss when the\n // viewport was sized before anyone listened.\n if (!placement.started) {\n ctx.state.update(setViewport, size);\n syncResponsive(false); // rules see the box before placement resolves\n if (size.width > 0 && size.height > 0 && (ctx.document()?.pageCount ?? 0) > 0) {\n placeInitial();\n }\n return;\n }\n // Afterwards a report with no area means the view isn't shown: a hidden tab, or an\n // element taken out of the page before its stage is torn down. There is nothing to fit\n // to, so the stage keeps its last real viewport and its view, and carries on from them\n // when it's shown again (as a browser keeps a hidden element's scroll position).\n if (size.width <= 0 || size.height <= 0) return;\n // A report of the size the stage already has says nothing new either. Hosts send\n // them (a ResizeObserver's first callback repeats the size reported at attach), and\n // treating one as a resize would cancel a navigation still animating, like a reveal\n // the app asked for as the view opened.\n const current = state().viewport;\n if (size.width === current.width && size.height === current.height) return;\n // Every real resize keeps the same page and re-resolves fit modes.\n cancelAnimation();\n const anchor = currentAnchor(); // measured against the old viewport\n ctx.state.update(setViewport, size);\n // A breakpoint crossing rides the same reframe: the rule patch lands\n // before the anchor is re-applied, so the restore resolves under the\n // new settings. Only a rule-driven flow flip escalates past reapply\n // (camera coordinates are meaningless across the flow boundary).\n const effect = syncResponsive(false);\n if (effect === 'reflow') {\n goToTarget(state().cursor, { behavior: 'instant' });\n } else {\n reapply(anchor);\n }\n },\n setDevicePixelRatio: (ratio) => {\n // A device-resolution change only affects each page transform's device\n // px (crispness) and sub-pixel box snapping, never the layout or the\n // camera: store it, and the visible pages re-key on dpr.\n if (ratio > 0 && ratio !== dpr()) ctx.state.update(setDpr, ratio);\n },\n refit: () => {\n // The page geometry changed underneath (rotate, move, delete). Treat\n // it like a viewport resize: re-resolve the zoom intent and re-place\n // against the current scene, keeping the anchored page-point. A no-op\n // before the first placement; the scene is keyed on the registry\n // revision, so `reapply` reads the new footprint.\n if (!placement.started) return;\n cancelAnimation();\n reapply(currentAnchor());\n },\n getViewState: (): StageViewState => ({\n ...snapshotSettings(),\n cursor: state().cursor,\n anchor: currentAnchor(),\n }),\n getLensId: () => ctx.id,\n provideInitialView: (priority, provide) => {\n const entry: InitialViewProvider = { priority, provide };\n initialViewProviders.push(entry);\n return () => {\n const index = initialViewProviders.indexOf(entry);\n if (index >= 0) initialViewProviders.splice(index, 1);\n };\n },\n placeInitial,\n } satisfies Partial<StageHostCapability>,\n };\n}\n","/**\n * The stage controller: the composition root. It builds the plugin's services\n * once (the events, the timing seam, the scene model), wires each area with\n * the services it declares, and assembles the host capability from the areas'\n * API slices. stage-core is the pure spatial math; the areas are the impure\n * shell that writes state, caches and drives motion, and time enters only\n * through the host's clock (`ctx.clock`).\n *\n * The camera model: every camera move is defined by what it holds fixed.\n * Gestures (pan, pinch, wheel) hold the page-point under the pointer;\n * navigation lands its target at the arrivalAlign point; positioned reveals\n * and restored viewpoints hold what the call specifies; pointer-less zooms\n * hold the zoomAlign point; reframes (resize, rotation, layout changes) hold\n * the anchorAlign point; and an axis the camera cannot travel rests at fitAlign.\n */\nimport { composeApi, type PluginContext } from '@embedpdf/core';\n\nimport { createAnimation } from './camera/animation';\nimport { createGestures } from './camera/gestures';\nimport { createCameraWrite } from './camera/write';\nimport { connectStage } from './connect';\nimport type { StageConfig } from './contract';\nimport type { StageHostCapability } from './host-contract';\nimport type { StageState } from './model';\nimport { createArrival } from './navigation/arrive';\nimport { createReveal } from './navigation/reveal';\nimport { createZoom } from './navigation/zoom';\nimport { createPageReads } from './read/pages';\nimport { createServices } from './services';\nimport { createSettings } from './settings/settings';\nimport { createViewLifecycle } from './view/lifecycle';\n\nexport function createStageController(\n ctx: PluginContext<StageState>,\n config: StageConfig = {},\n) {\n const services = createServices(ctx);\n const { events } = services;\n\n // Reads: pure projections of the scene and the camera.\n const reads = createPageReads(ctx, services);\n\n // The camera: the one write path, motion over the clock's frames, gestures.\n const write = createCameraWrite(ctx, services);\n const animation = createAnimation(services, write);\n const gestures = createGestures(ctx, services, write, animation, reads);\n\n // Navigation, settings, zoom and the view lifecycle.\n const arrive = createArrival(ctx, services, write, animation);\n const reveal = createReveal(ctx, services, write, animation, arrive);\n const settings = createSettings(ctx, services, config, write, animation, arrive);\n const zoom = createZoom(ctx, services, write, animation, gestures.api, settings);\n const view = createViewLifecycle(ctx, services, animation, arrive, settings);\n\n const api: StageHostCapability = composeApi('stage', [\n reads.api,\n animation.api,\n gestures.api,\n arrive.api,\n reveal.api,\n settings.api,\n zoom.api,\n view.api,\n {\n onPageChanged: events.pageChanged.on,\n onZoomChanged: events.zoomChanged.on,\n onCameraChanged: events.cameraChanged.on,\n onMotionEnded: events.motionEnded.on,\n onSettingsChanged: events.settingsChanged.on,\n onViewportChanged: events.viewportChanged.on,\n },\n ]);\n\n return {\n api,\n connect: () => connectStage(ctx, api),\n };\n}\n","import { createHostToken, definePlugin } from '@embedpdf/core';\nimport { ActionsToken } from '@embedpdf/plugin-actions/contract';\n\nimport { DEFAULT_LENS_ID } from './connect';\nimport type { StagePluginOptions } from './contract';\nimport { createStageController } from './controller';\nimport type { StageHostCapability } from './host-contract';\nimport { initialStageState } from './model';\nimport { StageToken } from './token';\n\n/**\n * The stage plugin: one lens's camera, layout, zoom and navigation over a\n * document. Document-scoped. The actions plugin is optional: with it, the\n * main lens feeds page state to it and interprets GoTo and Named page\n * actions. Pointer input is opted into by the surface binding\n * (`<Stage interaction>` / `createStageSurface`), which both forwards pointer\n * samples and registers this lens's scroll handler.\n */\nexport const stagePlugin = (options: StagePluginOptions = {}) => {\n const { id = DEFAULT_LENS_ID, token = StageToken, ...config } = options;\n return definePlugin({\n id,\n token: createHostToken<StageHostCapability>(token),\n scope: 'document',\n optional: [ActionsToken],\n state: () => initialStageState(config),\n create: (ctx) => createStageController(ctx, config),\n });\n};\n","/**\n * The Stage page's State table as code: what `useStageState()` returns, and\n * the same fields in every other framework. A second view registered with its\n * own token reads the same fields through its own capability.\n */\nimport { defineState } from '@embedpdf/core';\n\nimport { StageToken, ZoomMode } from './contract';\n\nexport const stageState = defineState(StageToken, {\n read: (stage) => ({\n zoomLevel: stage.getZoomLevel(),\n zoomMode: stage.getZoomMode(),\n currentPageIndex: stage.getCurrentPageIndex(),\n currentPage: stage.getCurrentPage(),\n pageCount: stage.getPageCount(),\n viewRotation: stage.getViewRotation(),\n activeRules: stage.listActiveRules(),\n }),\n empty: {\n zoomLevel: 1,\n zoomMode: ZoomMode.Automatic,\n currentPageIndex: 0,\n currentPage: null,\n pageCount: 0,\n viewRotation: 0,\n activeRules: [],\n },\n});\n","import type {\n InteractionHostCapability,\n InteractionHandler,\n} from '@embedpdf/plugin-interaction/contract/host';\nimport type { StageCapability } from './contract';\n\nexport interface ScrollHandlerOptions {\n /**\n * Let a drag over a page gap pan regardless of the active tool, and show a\n * grab cursor there, so the gutter always pans (outside a page there is\n * nothing to draw on or select). On-page behavior is untouched: the tool's\n * own gesture still owns page space. Default true.\n */\n panFallback?: boolean;\n}\n\n/**\n * Pan-the-camera as an interaction handler. Live under the built-in `pan` tool\n * (the `scroll` tag) and, with `panFallback`, under every tool, where it then\n * captures only page-gap drags (on-page downs belong to the active tool, which\n * claims them first at higher priority). It uses the sample's viewport delta,\n * so it pans over the whole viewport (pages and gaps).\n *\n * Cursors: a closed hand (`grabbing`) while dragging; an open hand (`grab`)\n * hovering a gap under a non-pan tool. The pan tool's own resting `grab` comes\n * from its `Tool.cursor`, so hovering it needs no claim here.\n */\nexport function createScrollHandler(\n stage: StageCapability,\n interaction: InteractionHostCapability,\n options: ScrollHandlerOptions = {},\n): InteractionHandler {\n const panFallback = options.panFallback ?? true;\n let last = { x: 0, y: 0 };\n const isPanTool = (): boolean => interaction.getActiveTool().enables.has('scroll');\n return {\n id: 'stage-scroll',\n priority: 10, // below page-aware handlers (selection, annotation), which claim first\n enabledFor: (tool) => tool.enables.has('scroll') || panFallback,\n onDown: (sample) => {\n // Fallback: a non-pan tool pans only over a gap. On a page, decline so the\n // tool's own (higher-priority) handler keeps the down it already captured.\n if (!isPanTool() && sample.page) return false;\n last = sample.viewport;\n interaction.claimCursor('stage-grab', 'grabbing', 40); // closed hand while panning\n return true; // capture the drag\n },\n onMove: (sample) => {\n stage.panBy(sample.viewport.x - last.x, sample.viewport.y - last.y);\n last = sample.viewport;\n },\n onUp: () => interaction.claimCursor('stage-grab', null),\n onHover: (sample) => {\n // An open hand over a gap when a non-pan tool would fall back to pan\n // there; cleared over a page (the tool's cursor shows). The pan tool\n // skips this: its resting `grab` is the tool cursor.\n if (panFallback && !isPanTool()) {\n interaction.claimCursor('stage-pan-fallback', sample.page ? null : 'grab', 5);\n }\n },\n };\n}\n"],"mappings":"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"}