diff --git a/RECEIVER_PDF_VIEWER_CONTEXT.md b/RECEIVER_PDF_VIEWER_CONTEXT.md index 6bb8360f..28c56e57 100644 --- a/RECEIVER_PDF_VIEWER_CONTEXT.md +++ b/RECEIVER_PDF_VIEWER_CONTEXT.md @@ -543,535 +543,401 @@ A useful way to think about the page is: --- -## Detailed Technical Migration Plan: `PDF.js` -> `DxPdfViewer` +## Current Post-Migration Status and Step-by-Step Feature Recovery Plan -This section records the implementation plan for migrating the active receiver signing experience from `PDF.js` to `DxPdfViewer` without losing any workflow behavior. +This section replaces the earlier generic migration plan and records the current real status after the first `DxPdfViewer` swap attempt. -### 1. Core migration principle +### 1. Current status summary -This migration must be treated as: +The main document is now visible with `DxPdfViewer`, which means: -- a **rendering engine replacement** -- not a signing workflow redesign -- not a simplification to a read-only viewer -- not a direct PDF stamping rewrite +- receiver authorization still works +- document loading still works +- the route and page host still work +- `DxPdfViewer` is now the visible main rendering surface -The page-level orchestration in `EnvelopeReceiverPage.razor` remains the source of truth for: +However, the receiver experience is currently **feature-incomplete**. -- receiver authorization -- document loading -- signature placeholder loading -- cached signature loading/saving -- popup and validation flow -- signature locking rules -- reset/restart behavior -- toolbar intent +At the moment, the page is effectively in this state: -The rendering layer must be swapped while preserving those behaviors. +- PDF is displayed +- custom workflow shell still exists +- but the old `PDF.js` behavior contract is no longer fully connected to the new viewer -### 2. Current implementation findings from code +So this is no longer a rendering failure. +It is now a **behavior recovery** problem. -Based on the current files: +### 2. What is currently missing or unreliable -- `EnvelopeReceiverPage.razor` -- `wwwroot/js/pdf-viewer.js` -- `wwwroot/css/envelope-viewer.css` -- `EnvelopeReceiverPage_DxPdfViewer.razor` +The following features are currently missing, incomplete, or highly likely to be non-functional in the present state. -the current page is tightly coupled to a custom `pdfViewer` JavaScript object. +#### 2.1 Page navigation is not truly connected to `DxPdfViewer` -That object currently owns all viewer-engine behaviors: +Symptoms: -- PDF load and initialization -- current page state -- page rendering -- zoom rendering -- thumbnail rendering -- resize listener attachment -- signature button rendering -- applied signature overlay rendering -- signature navigation state +- previous page button may update Blazor state only +- next page button may update Blazor state only +- direct page input may update Blazor state only +- thumbnail click may update Blazor state only +- signature navigation page jumps may update Blazor state only -This means the migration cannot be done by replacing only the Razor markup. The current JavaScript object is effectively both: +Why: -- a `PDF.js` adapter -- and a receiver-signing overlay controller +- the earlier attempt tried to use `ActivePageIndex`, but `DxPdfViewer` does not expose it as a component parameter in this version +- after removing that invalid parameter, the page still updates `_currentPage`, but that does not automatically move the DevExpress viewer to another page +- in other words, there is currently no verified programmatic page-navigation bridge into `DxPdfViewer` -Those responsibilities must be separated conceptually during migration. +Impact: -### 3. Verified coordinate and viewport behavior from `PDF.js` +- all features that depend on true page switching are blocked or only partially simulated -Inspection of the `PDF.js` source comments and implementation confirms the following useful facts: +#### 2.2 Zoom controls are not truly connected to `DxPdfViewer` -1. `PageViewport` is created from: - - `viewBox` - - `scale` - - `rotation` - - optional offsets +Symptoms: -2. `PDF.js` explicitly documents that `PageViewport` creates a transform that converts: - - **PDF coordinate system** - - into **normal canvas-like coordinates** +- zoom in/out buttons may update `_currentZoom` +- slider may update `_currentZoom` +- ctrl+wheel logic may update `_currentZoom` +- but the visible viewer may not actually zoom accordingly, or may not do so reliably -3. `PageViewportParameters.viewBox` is documented as: - - `xMin, yMin, xMax, yMax` +Why: -4. `getViewport(...)` is documented as returning an object containing: - - `width` - - `height` - - transforms required for rendering +- `ZoomLevel` is exposed as a property on `DxPdfViewer`, but it is not yet confirmed that changing the bound value gives the same runtime behavior expected by the old `PDF.js` flow +- the current implementation updates Blazor state and triggers overlay refresh, but the real DevExpress zoom lifecycle and its timing have not yet been validated +- no verified zoom-changed callback from `DxPdfViewer` has been integrated -5. `convertToViewportPoint(x, y)` is documented as converting: - - PDF coordinates - - into viewport coordinates +Impact: -6. `convertToPdfPoint(x, y)` is documented as converting: - - viewport coordinates - - back into PDF coordinates - - specifically useful for converting canvas pixel locations into PDF coordinates +- zoom UX is incomplete +- overlay synchronization cannot be trusted until real zoom behavior is confirmed -7. `rawDims` exposes unscaled page dimensions: - - `pageWidth` - - `pageHeight` - - `pageX` - - `pageY` +#### 2.3 Overlay positioning is heuristic, not yet proven -8. For rotation `0`, `PageViewport` flips the Y axis into canvas-style coordinates unless `dontFlip` is used. +Symptoms: -### 4. Practical meaning of the current overlay math +- signature placeholders may not appear +- or may appear in the wrong location +- or may not track zoom/page changes correctly -The current `pdf-viewer.js` implementation does **not** call `convertToViewportPoint(...)` directly. -Instead, it uses this simplified mapping: +Why: -- `xPx = sig.x * scale` -- `yPx = sig.y * scale` +- old implementation owned the page canvas directly +- new implementation tries to detect the visible page surface inside `DxPdfViewer` DOM heuristically +- this means the current adapter is guessing which DOM element is the active rendered page surface +- page geometry, offsets, scaling and scroll surface are not yet bound to a stable DevExpress contract -This works only because the current upstream data contract already prepares signature coordinates in a way that matches the displayed page layout used by this app. +Impact: -From the wider workspace context, the receiver page data service already converts placeholder coordinates to `UnitOfLength.Point` before they reach the UI. +- placeholder buttons are not yet production-safe +- applied signatures are not yet production-safe -Therefore, the active overlay contract is effectively: +#### 2.4 Applied signature overlay behavior is not yet dependable -- incoming signature coordinates are already normalized for the receiver UI -- JavaScript currently assumes a top-left, page-relative, point-based overlay space -- visual pixel placement is obtained by multiplying by current display scale +Symptoms: -This is extremely important for the migration: +- clicking a placeholder may not place the visual signature correctly +- applied signatures may drift after zoom +- applied signatures may disappear or misalign when navigation changes -- do **not** casually reinterpret existing signature coordinates as raw PDF bottom-left coordinates -- do **not** assume `DxPdfViewer` uses the same visible page coordinate origin -- preserve the effective contract already used by the receiver workflow +Why: -### 5. Why the migration is technically hard +- applied signatures currently depend on the same unverified geometry bridge as placeholders +- they also depend on reliable page identity and zoom identity from the DevExpress surface -Although both viewers display PDFs, they are fundamentally different integration surfaces. +Impact: -#### Current `PDF.js` model +- the core signing UX is not yet restored -- low-level canvas rendering -- direct access to viewport scale -- direct control over single page rendering -- page DOM is owned by our code -- overlays are placed over known custom elements: - - `pdf-canvas` - - `pdf-text-layer` - - `pdf-signature-layer` +#### 2.5 Signature navigation is structurally present but functionally blocked -#### Target `DxPdfViewer` model +Symptoms: -- component-driven render surface -- internal DOM is owned by DevExpress -- page layout lifecycle is controlled by the component -- zoom/page events may differ from `PDF.js` -- overlay host placement must be rediscovered or reintroduced +- previous/next signature buttons may update internal navigation state +- but page-jump and scroll-to-target behavior may fail or be inconsistent -So the migration is not a `canvas -> component` rename. -It is a **viewer capability remapping** problem. +Why: -### 6. Technical target architecture +- signature navigation depends on: + - real page navigation + - real overlay rendering + - reliable scroll container discovery +- since all three are not yet stabilized, signature navigation cannot yet be trusted -The target architecture should be treated as four cooperating layers. +Impact: -#### 6.1 Blazor orchestration layer -Owned by `EnvelopeReceiverPage.razor`. +- navigation across signature fields is not complete -Remains responsible for: +#### 2.6 Thumbnail sidebar is only partially preserved -- auth and redirect -- data loading -- signature popup state -- signature metadata validation -- cached signature reuse -- signed/unsigned counts -- restart behavior -- toolbar user intent +What still exists: -#### 6.2 Viewer host layer -Main display surface becomes `DxPdfViewer`. - -This layer must provide equivalents for: - -- document load -- current page tracking -- total pages tracking -- page navigation -- zoom control -- layout change detection - -#### 6.3 Overlay adapter layer -Custom layer that translates page/zoom/layout information into overlay placement. - -This layer must handle: - -- signature placeholder buttons -- applied signature overlays -- page-relative visibility -- redraw after page/zoom/layout changes - -#### 6.4 Thumbnail/navigation support layer -Custom or hybrid support for: - -- left sidebar thumbnails -- active page highlight +- sidebar shell - width persistence -- signature previous/next navigation +- resize logic +- thumbnail rendering through helper pipeline -### 7. Mandatory first implementation step: extract the current viewer contract +What is missing or uncertain: -Before changing behavior, the following current `pdfViewer` capabilities must be listed and then mapped one-by-one to the target implementation: +- guaranteed synchronization between thumbnail click and visible page in `DxPdfViewer` +- guaranteed active-page highlight based on real viewer page -- `initialize` -- `getTotalPages` -- `getCurrentPage` -- `nextPage` -- `previousPage` -- `goToPage` -- `zoomIn` -- `zoomOut` -- `setScale` -- `getScale` -- `fitToWidth` -- `renderThumbnail` -- `attachResizeListeners` -- `startResize` -- `renderSignatureButtons` -- `applySignature` -- `getSignatureNavState` -- `goToNextSignature` -- `goToPreviousSignature` -- `dispose` +Why: -The migration should preserve this capability contract at the page level even if the internal engine changes. +- active thumbnail currently follows `_currentPage` +- but `_currentPage` is not yet guaranteed to reflect the actual active page inside `DxPdfViewer` -### 8. Planned migration strategy +#### 2.7 Single-page behavior is not yet guaranteed to match the old experience -#### Phase 1 — Confirm the `DxPdfViewer` integration surface +Why: -Use `EnvelopeReceiverPage_DxPdfViewer.razor` as a reference and determine exactly what `DxPdfViewer` exposes for: +- old implementation enforced a single active rendered page in a fully custom surface +- new implementation uses `DxPdfViewer IsSinglePagePreview="true"` +- but this still needs runtime verification against: + - page scroll behavior + - zoom behavior + - page switch timing + - overlay surface alignment -- document content binding -- page navigation -- current page reading -- page change events -- zoom setting -- zoom change events -- page layout readiness -- DOM surface that can host overlays +### 3. Root cause analysis: why features disappeared -Key question: +The features disappeared for one main reason: -- can we reliably obtain visible page geometry from the live `DxPdfViewer` DOM? +- the old receiver experience was not just a PDF viewer +- it was a **custom stateful viewer platform** built on top of `PDF.js` -If yes, overlays can be positioned relative to the rendered page. -If no, a wrapper-based approximation or alternative integration is required. +In the old system: -#### Phase 2 — Replace the main render surface in `EnvelopeReceiverPage.razor` +- page navigation was owned by our JavaScript +- zoom was owned by our JavaScript +- page metrics were owned by our JavaScript +- active page surface was owned by our JavaScript +- overlays were drawn on DOM elements owned by our JavaScript -The current custom `canvas + text layer + signature layer` block should be replaced with a `DxPdfViewer` host region while keeping: +After the swap: -- the same page route -- the same page state -- the same toolbar -- the same popup -- the same thumbnail sidebar shell +- the visible rendering surface belongs to DevExpress +- but the custom behavior layer still expects low-level ownership similar to `PDF.js` -At this stage, only the main document display needs to work. -Signature overlays may temporarily be disabled while the host geometry is established. +So the missing features are not random regressions. +They are the direct result of replacing the renderer before fully rebuilding the viewer behavior bridge. -#### Phase 3 — Introduce a dedicated overlay host above `DxPdfViewer` +### 4. New recommended implementation strategy -The new viewer surface should be wrapped with a custom page container. +Do **not** try to restore everything at once. -Planned structure: +The correct path now is to restore behavior in controlled stages, one capability at a time. -- outer frame -- thumbnail sidebar -- splitter -- main viewer wrapper -- `DxPdfViewer` -- absolute-positioned custom overlay layer +### 5. Step-by-step recovery plan -The overlay layer must be independently controlled by our code and not depend on internal `PDF.js` DOM ids. +#### Step 1 — Confirm the real `DxPdfViewer` API surface -#### Phase 4 — Rebuild page/zoom geometry acquisition +Goal: -Because the current implementation derives position using only `sig.x * scale`, the target implementation must determine: +- stop guessing which `DxPdfViewer` properties and behaviors are actually bindable and runtime-reactive -- currently visible page rectangle -- page top-left origin inside the wrapper -- effective display scale relative to logical point coordinates -- current page number +Tasks: -At redraw time, the adapter must produce page-relative pixel coordinates for: +- inspect the actual supported parameter surface for the installed DevExpress version +- determine which of the following are truly supported and reactive: + - zoom binding + - page navigation binding + - single-page mode behavior + - toolbar customization / suppression +- determine whether DevExpress exposes any JS/API for page switching or current page retrieval -- placeholder buttons -- applied signature blocks +Expected output: -This should be centralized in one geometry function rather than scattered across multiple viewer actions. +- a verified list of what `DxPdfViewer` can really do directly +- a list of behaviors that must remain custom because DevExpress does not expose them -#### Phase 5 — Move signature overlay state to a canonical model +This step is mandatory before further feature work. -The current JavaScript keeps runtime state in: +#### Step 2 — Restore real zoom behavior first -- `signatureButtons` -- `appliedSignatures` -- `appliedSignatureElements` -- `_allSignatures` -- `_lastViewedSignatureId` +Goal: -This must remain stable across redraws. +- make zoom in/out/slider visibly affect `DxPdfViewer` -Preferably: +Why first: -- Blazor continues to own the authoritative business state -- JavaScript owns transient rendered DOM state only +- zoom is simpler than full page navigation +- it is also required before overlay sizing can be trusted -If necessary, applied signature state should be re-sendable from .NET after viewer redraw. -That prevents losing visual signatures when page layout changes. +Tasks: -#### Phase 6 — Re-implement signature placeholder rendering on top of `DxPdfViewer` +- verify whether `ZoomLevel` binding actually updates the viewer at runtime +- if yes, stabilize it +- if no, find the supported DevExpress-side mechanism +- disable or adjust any overlay refresh logic until true zoom behavior is confirmed -The current implementation filters placeholders by: +Acceptance for this step: -- current page -- not already applied +- zoom in button visibly zooms document +- zoom out button visibly zooms document +- slider visibly changes viewer zoom +- `_currentZoom` matches what the user sees -That same behavior must remain. +#### Step 3 — Restore real page navigation -Rendering rules to preserve: +Goal: -- only placeholders for the active page are shown -- already applied placeholders are hidden as buttons -- button size grows/shrinks with zoom -- button click invokes `.NET` callback `OnSignatureButtonClick` +- make previous/next/page input/thumbnail click truly change the visible page in `DxPdfViewer` -The existing scaling behavior uses `baseScale = 1.5` as the visual reference. -That visual convention should be preserved initially unless a new normalized sizing model is intentionally introduced. +Tasks: -#### Phase 7 — Re-implement applied signature rendering on top of `DxPdfViewer` +- identify supported page navigation mechanism for this DevExpress version +- connect `_currentPage` to the real viewer page +- if direct binding is unavailable, create a supported indirect mechanism -The current applied signature overlay includes: +Acceptance for this step: -- signature image -- horizontal separator line -- signer full name -- optional position -- place and date +- previous page works +- next page works +- direct page input works +- `_currentPage` reflects visible page -The same visual block must be retained. +This step must be completed before signature navigation or page-specific overlays are considered reliable. -Required behavior: +#### Step 4 — Stabilize active page geometry extraction -- clicking a placeholder converts it to an applied signature overlay -- applied signature remains visible on the correct page -- applied signature rescales with zoom -- applied signature repositions on page/zoom changes -- applied signature is hidden when the user navigates to a different page +Goal: -#### Phase 8 — Re-implement page navigation through a central page-change pipeline +- determine a reliable way to identify the active visible rendered page inside the DevExpress DOM -The following actions must all converge into a single page navigation routine: +Tasks: -- previous page button -- next page button -- direct page number input -- thumbnail click -- signature previous/next navigation when target is on another page +- inspect the actual DOM produced by `DxPdfViewer` +- identify stable selectors for: + - viewer scroll container + - active page surface + - page content bounds +- replace heuristic “largest visible element” logic if a more stable pattern exists -That routine must do all of the following in order: +Acceptance for this step: -1. instruct viewer to change page -2. update canonical current page state -3. wait for rendered page surface readiness if needed -4. redraw placeholder overlays -5. refresh signature navigation counter state +- geometry retrieval returns correct page bounds repeatedly +- geometry remains stable after zoom +- geometry remains stable after page changes -#### Phase 9 — Re-implement zoom through a central zoom-change pipeline +#### Step 5 — Restore signature placeholder overlay rendering -The following actions must converge into one zoom update path: +Goal: -- toolbar zoom in -- toolbar zoom out -- slider change -- fit-to-width -- viewer-native zoom events if the user triggers zoom through gestures +- make unsigned signature placeholders render at correct positions on the current page -That routine must: +Tasks: -1. clamp to `50% - 300%` -2. update canonical zoom state -3. wait for layout/render completion if needed -4. redraw placeholder overlays -5. rescale applied signatures +- connect placeholder rendering to verified page bounds +- preserve current filtering rules: + - active page only + - hide already-signed fields +- validate size scaling against visible zoom -The current implementation already treats redraw after zoom as mandatory. That must remain true. +Acceptance for this step: -#### Phase 10 — Preserve signature navigation independently from the viewer engine +- placeholder appears on correct page +- placeholder appears in correct location +- placeholder size follows zoom -Current navigation logic is driven by the global ordered signature list and not by PDF rendering internals alone. +#### Step 6 — Restore applied signature overlays -This behavior must remain engine-independent: +Goal: -- previous/next traverses the full signature list -- traversal wraps around at the edges -- if the target signature is on another page, the viewer jumps first -- after page jump, the target element is scrolled into view -- toolbar counters reflect total/signed/unsigned/current index +- clicking a placeholder should place the actual signature overlay correctly -If `DxPdfViewer` changes scrolling mechanics, the `scrollToElement` / `scrollToButton` logic must be adapted, but the traversal rules must remain unchanged. +Tasks: -#### Phase 11 — Thumbnail sidebar should remain custom unless `DxPdfViewer` can match all current behavior +- keep current visual block format +- bind position/size to the same verified geometry system as placeholders +- ensure page changes hide/show correctly -The current sidebar is not just decorative. It also provides: +Acceptance for this step: -- show/hide toggle -- click navigation -- active page highlight -- resizable width -- width persistence in `localStorage` -- progressive rendering strategy +- clicking placeholder places signature correctly +- applied signature stays aligned after zoom +- applied signature stays aligned after page change -Because of that, the safest plan is: +#### Step 7 — Restore signature navigation -- keep the custom sidebar shell and resize behavior -- only replace the source of main document rendering +Goal: -If `DxPdfViewer` cannot provide matching thumbnails directly, a hybrid solution is acceptable: +- previous/next signature should work across all pages again -- main document rendered by `DxPdfViewer` -- thumbnails still generated through a separate custom preview pipeline +Tasks: -This still satisfies the requirement that `DxPdfViewer` becomes the main viewer technology. +- keep the existing global signature ordering logic +- connect it to real page switching +- connect it to real overlay availability +- connect it to real scroll-to-target behavior -#### Phase 12 — Keep signature capture popup unchanged unless integration forces a minimal adjustment +Acceptance for this step: -`receiver-signature.js` and the popup flow should remain mostly untouched. +- next signature works on same page +- next signature jumps across pages +- previous signature works +- current index / signed / unsigned counters are correct -Preserve exactly: +#### Step 8 — Validate and finish thumbnail behavior -- draw tab -- text tab -- image tab -- full name required -- place required -- signature data required -- cached signature reuse -- signature change lock after signing starts +Goal: -This area is low-risk and should not be refactored unnecessarily during the viewer migration. +- make sidebar behavior trustworthy again -### 9. File-by-file execution plan +Tasks: -#### `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage.razor` +- confirm thumbnails still render correctly +- ensure thumbnail click changes actual visible page +- ensure active thumbnail reflects actual page +- keep width persistence and resize behavior -Planned work: +Acceptance for this step: -- remove `PDF.js` CDN asset dependency from the active receiver page -- replace the custom canvas-based main surface with a `DxPdfViewer` host -- preserve toolbar, popup, auth, state and receiver-specific loading logic -- redirect viewer method calls through a new or adapted JS interop surface -- preserve current state fields wherever possible to minimize workflow regressions +- thumbnail click works +- active highlight is correct +- width persistence still works -#### `EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/js/pdf-viewer.js` +### 6. Recommended order of implementation -Planned work: +The recommended execution order is: -- split engine-specific logic from workflow-specific logic -- remove dependency on direct `pdf-canvas` rendering for the main viewer path -- introduce `DxPdfViewer`-compatible geometry and overlay placement helpers -- preserve signature navigation logic semantics -- preserve overlay rendering semantics -- preserve resize integration for sidebar handling +1. verify `DxPdfViewer` real API surface +2. restore zoom +3. restore page navigation +4. stabilize page geometry extraction +5. restore placeholder overlays +6. restore applied signatures +7. restore signature navigation +8. finish thumbnail synchronization -This file will likely become a viewer adapter rather than a pure `PDF.js` implementation. +This order is important because later features depend on earlier ones. -#### `EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/envelope-viewer.css` +### 7. What should not be changed yet -Planned work: +Until the viewer bridge is stable, avoid refactoring these parts unnecessarily: -- keep page shell, toolbar, thumbnails, splitter and popup-related styles -- replace canvas/text-layer specific assumptions with viewer-wrapper styles -- introduce overlay host styles for the `DxPdfViewer` surface -- ensure z-index ordering still makes signature buttons clickable -- avoid CSS leaking into DevExpress internal DOM more than necessary - -#### `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage_DxPdfViewer.razor` - -Planned role: - -- reference only -- used to understand document binding and minimal `DxPdfViewer` setup -- not the primary delivery target unless portions are borrowed into the main receiver page - -### 10. Risks that must be explicitly tested during implementation - -1. `DxPdfViewer` may not expose visible page geometry directly. -2. `DxPdfViewer` may render asynchronously in a way that requires delayed overlay redraw. -3. Built-in zoom/page state may not map 1:1 to current custom toolbar assumptions. -4. Sidebar width changes may require explicit overlay recalculation. -5. Applied signatures may visually drift if scaling math is not centralized. -6. Signature navigation may fail if target DOM nodes are created later than expected. -7. Built-in viewer scrolling may differ from the current wrapper scrolling model. - -### 11. Acceptance checklist for the migration - -The migration is only acceptable if all of the following still work in the active page: - -- receiver authorization before document access -- document load for the authenticated receiver -- single active page viewing -- previous/next page navigation -- direct page input navigation -- thumbnail click navigation -- zoom in/out and slider zoom -- overlay alignment after zoom changes -- signature placeholder rendering on the correct page -- placeholder click applying signature overlay -- previous/next signature navigation across pages -- signed/unsigned counters updating correctly -- cached signature reuse -- signature popup validation -- signature change lock after signing starts +- receiver authorization flow +- page data loading service +- cached signature flow +- popup tabs and signature capture JS +- signature metadata validation +- signature lock behavior - restart signing behavior -- thumbnail width persistence -### 12. Final implementation guidance +These parts are not the current problem. -The correct technical approach is: +### 8. Next implementation checkpoint -- keep `EnvelopeReceiverPage.razor` as the receiver workflow orchestrator -- treat `DxPdfViewer` as the new main rendering engine -- rebuild overlay placement as a viewer-agnostic custom layer -- preserve the current receiver-specific state machine -- preserve signature navigation rules -- preserve thumbnail/sidebar interaction model where practical +The next actual coding step should be: -In short: +- **Step 1 + Step 2** together if possible: + - confirm supported `DxPdfViewer` interaction surface + - restore real zoom behavior first -- **replace the renderer** -- **preserve the workflow** -- **rebuild the overlay adapter** -- **do not redesign the signing experience** +That is the safest first vertical slice because: + +- it is easy to verify visually +- it reduces uncertainty in overlay scaling +- it does not yet require full signature flow completion ---