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>