One implementation each, for every page to use instead of its own copy:
- lib/toast.ts + components/Toaster.tsx: toast.success|error|info from
anywhere, rendered in polite/assertive live regions; an error stays until
dismissed, a success fades, a repeat collapses.
- lib/confirm.ts + components/ConfirmHost.tsx: await confirmDialog({...})
and confirmDiscard() through the themed ConfirmModal, replacing
window.confirm and the actions that asked nothing.
- hooks/useDialog.ts: the modal focus contract (focus in, Tab trapped,
Escape, focus restored), extracted from ConfirmModal; dialogs stack so
only the top one answers keys. ConfirmModal now uses it.
- hooks/useArmed.ts: two-click confirmation that disarms after 3 s.
- hooks/useUnsavedGuard.ts: beforeunload while a draft is dirty.
- lib/clipboard.ts copyText: Clipboard API with an execCommand fallback for
non-secure origins, outcome toasted.
- lib/keys.ts isSubmitEnter: ignores the Enter that confirms an IME
candidate (Vietnamese Telex, CJK).