Your chat app's textarea is pinned to bottom: 0. On desktop it looks perfect. On iPhone, the software keyboard slides up and your input ends up underneath the keyboard. The user's thumbs hover over nothing. Safari fires CSS layout recalculation before visualViewport finishes resizing — and that's the whole bug, exactly as the Vercel AI SDK community hit it in production this week. Every chat product, every AI textbox, every mobile checkout flow with a sticky bottom CTA is shipping this.
position: fixed; bottom: 0 input slides under it. Every mobile chat app is shipping this. Apple still hasn't fixed it.The iOS software keyboard occupies the bottom \~45% of the viewport when open. Mobile Safari does not resize the layout viewport when the keyboard appears — it overlays the keyboard on top of your existing layout. Anything pinned to bottom: 0 ends up behind the keyboard. The visualViewport API does know the keyboard is there, but CSS layout has already settled before visualViewport.resize fires. Result: your textarea is invisible to your user. Their thumbs hover over the keyboard, expecting to type into something they can't see. They close your app. This is the single biggest mobile-web UX bug shipping in 2026.
visualViewport.resize + one CSS swap fixes every occurrence in your codebase · git-reversiblePLAIN ENGLISH You wrote position: fixed; bottom: 0 on your chat input because that's what the docs show. Now your user opens your app on their iPhone, taps the textarea, the keyboard pops up, and the textarea vanishes behind it. They can't see what they're typing. They close your app. This isn't your fault — it's the way Safari is built. But it IS your problem, because your users don't blame Safari, they blame your app. KeyboardPunk finds every place in your code where this can happen and gives you the deterministic fix.
Paste the part of your page that pins inputs to viewport bottom — chat composer, comment box, sticky CTA, mobile checkout, anything with position: fixed; bottom: 0 and a focus-able child. We render it in a 390×844 sandboxed iframe (iPhone 16 viewport) inside your browser, walk every fixed-position element looking for input / textarea / [contenteditable] descendants, and emit two snippets: a bootstrap JS that listens to visualViewport.resize and exposes the keyboard height as a CSS custom property, plus a one-line CSS swap that uses it. Zero upload, zero storage, zero AI.
Your pasted HTML loads into a hidden, script-disabled iframe sized to iPhone 16 viewport dimensions inside your own browser tab. Nothing leaves the page. The iframe is destroyed the moment the audit completes.
For every element where getComputedStyle(el).position === 'fixed' AND bottom !== 'auto' AND the element contains an input, textarea, select, or [contenteditable] descendant — we flag it as a keyboard trap. We also check whether any ancestor uses vh / dvh / svh / lvh height units, which makes the bug worse.
For each trap you get the selector, plus two copy-buttons: a bootstrap JS snippet that wires visualViewport.resize to a --keyboard-inset CSS custom property, and a one-line CSS change replacing bottom: 0 with bottom: var(--keyboard-inset, 0px). Two paste-and-go snippets per occurrence. Works on every iOS device shipped in the last 8 years.
KeyboardPunk is the third product in the Punk Store. PalettePunk audits color (Display P3 / OKLab gradients, sRGB color literals, modern color functions). StickyPunk finds position: sticky failures caused by ancestor overflow: hidden strangling the scroll context. Three more in the queue this quarter. The Punk Pass gets you all of them — current and future — for the price of buying three separately.
No subscription. No login wall. No "contact sales." Buy once, own forever, use on every project you ever ship.
The CSS-spec answer is env(keyboard-inset-height, 0px) — but it only ships in Safari 16.4+ and is behind a flag in Chrome. The JS fix using visualViewport.addEventListener('resize', ...) works on every iOS device shipped in the last 8 years, and adds up to about 15 lines of code total. The Punk Store sells deterministic browser-side patches; the patch language is CSS by default, JS where the bug demands it.
Yes. Nothing uploads. The pasted HTML loads into a sandboxed iframe sized to iPhone 16 viewport (390×844) inside your tab. No fetch, no XHR, no telemetry. View source on this page if you want to verify — the whole scanner is in /scan.js, vanilla JS with zero dependencies.
No. Android Chrome's visualViewport behavior is already keyboard-aware — Math.max(0, window.innerHeight - vv.height) evaluates to 0 there, so --keyboard-inset stays at 0px and your layout is unchanged. The patch is a no-op everywhere except iOS Safari where it's needed.
Hopefully. The bug has been in WebKit's tracker since 2022 across iOS 15 → 26.5 (current beta). The Vercel AI SDK community filed fresh issues in June 2026 — still broken. Tactical reason to ship our patch now: if Apple fixes it tomorrow, our patch becomes a no-op (good). If they don't, your users stop closing your app.
Same bug, same fix. Standalone PWA Safari has the same keyboard overlay behavior as in-browser Safari. The visualViewport patch works identically.
Yes. Same Radio Art LLC, same engineering, same lifetime-license model, same "we publish the methodology" doctrine. Punk Pass upgrade always pays for itself by your second Punk.