77f35c4e9e
Ship-blocking fix (Fable consult): useNodeActions.duplicate() appended the regenerated tree at the end of the parent while leaving the ORIGINAL selected, so duplicating a top-level section landed the copy off-screen at the bottom of the page with no visible change -- shared by both the mobile selection toolbar and the desktop right-click ContextMenu. Now inserts the copy immediately after the source (actions.addNodeTree(tree, parentId, sourceIndex + 1)) and selects it (actions.selectNode(tree.rootNodeId)), falling back to append-at-end if the source's index can't be resolved. Mobile also scrolls the new node into view. Three cheap fast-follows: - canSelectParent on useNodeActions (false when the node's parent is ROOT or missing); MobileSelectionToolbar disables "Select Parent" instead of dead-ending on a page-wide ROOT outline with no toolbar of its own. - Opening the Styles sheet on mobile now scrolls the selected node above the 65dvh sheet; a temporary generous bottom-padding class handles the case where the node is the last thing on the page and there'd otherwise be no room left to scroll it into view. - Canvas gets bottom padding equal to the fixed selection toolbar's height while it's visible, so the last section of a short page isn't stuck permanently underneath it. Desktop duplicate behavior improves (inserts after + selects) via the shared hook; no toHtml changes. Verified live via Playwright at 375px and 1280px (screenshots in craft/scratchpad/mobileB2/). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>