b0df06a9f5
Task #476. On iPad Safari, opening the keyboard while writing a new note or replying inside the note thread dialog covered the bottom of the dialog (textarea + send button). The dialog used `top:50%; translate(-50%,-50%)` against the layout viewport and never reacted to the visual viewport shrinking when the keyboard appeared. Changes: - artifacts/tx-os/index.html: added `interactive-widget=resizes-content` to the viewport meta so iOS 17+ resizes the layout viewport when the software keyboard opens. - artifacts/tx-os/src/hooks/use-visual-viewport.ts: new hook that subscribes to `window.visualViewport` `resize` / `scroll` / `orientationchange` (rAF-throttled) and exposes the visible height, the visual viewport `offsetTop`, and the bottom keyboard inset. - artifacts/tx-os/src/components/ui/dialog.tsx: `DialogContent` now reads the hook and, only when the keyboard inset exceeds ~80px, pins its center to `offsetTop + height/2` and caps `max-height` to the visible height. With the existing `translate(-50%,-50%)`, both edges stay inside the visible region above the keyboard. Desktop unaffected (inset is 0 → no inline style applied). - artifacts/tx-os/src/pages/notes.tsx: thread reply textarea and the top composer textarea now call `scrollIntoView({ block: "center" })` on focus and again whenever the keyboard inset changes while the field is focused. Both paths are gated on `keyboardInset > 80`, so desktop focus is untouched. Verification: - `tsc --noEmit` clean. - e2e: `notes-thread-dialog` and `notes-composer-color` both pass.