- MessageInlineVideo (new): custom-controlled inline video that disables
the iOS Safari / Chromium native overlays entirely and reimplements
the essentials: tap-to-play, centered play affordance while paused,
bottom bar with play/pause + current time + drag-to-scrub progress
bar + remaining time + fullscreen. Pointer events with pointer
capture cover both mouse and touch scrubbing, including dragging
past the bar's bounds. The element listens to 'seeked' as well as
'timeupdate' so external currentTime writes paint the bar even when
the video is paused, and the goFullscreen callback synchronously
syncs React state on close so the inline progress reflects the user's
fullscreen playhead with no perceptible delay.
- VideoBubble: replace the inline <video controls> with
MessageInlineVideo and thread postId through openVideo so the
fullscreen overlay can attach the download pill to the right post.
- VideoPlayer overlay: replace its <video controls> with
MessageInlineVideo size='lg', removing the iOS native arrows / PiP /
mute / overflow controls. The overlay supplies its own large
download pill and a beefier close button.
- AttachmentDownloadPill: new 'size' prop ('sm' default 30 px, 'lg'
44 px with 22 px icon and text-[14px]) for overlay surfaces where
the affordance can breathe and should feel touch-friendly.
- ImageLightbox: drop the inline LightboxDownloadButton and use the
shared AttachmentDownloadPill size='lg' instead, with a matching
larger close button. Unused imports cleaned up.
- AttachmentDownloadPill: bring back the optional adaptive sizing
branch (default off). When the host sets containerType: inline-size,
the pill scales 22-30px with the tile width using a steeper
18cqw curve, so two-image tiles already reach 30px while tiny
thumbs in mixed layouts stay at 22px.
- AlbumBubble: opt every tile into adaptive sizing and add the query
container so the cqw units resolve against each tile's width.
- Single-image and video bubbles continue to render the pill at a
fixed 30px (no host opt-in needed).
- VideoBubble: add a Maximize2 fullscreen button at the top-right of
the inline player (mirrors the download pill on the left), so the
user explicitly opts into fullscreen instead of any tile click being
promoted to one. Removed the outer onClick that opened fullscreen
on any tap.
- AttachmentDownloadPill: drop the adaptive (cqw-based) sizing branch
and the corresponding 'adaptive' prop. The pill is now a uniform
30px tall in every host (album tile, single image, video tile),
matching the design without needing query containers on parents.
- AlbumBubble: remove the now-unused 'adaptive' prop and the
containerType: inline-size hook that supported it.
Recommended cards already routed to /browse#post-<id>, but the stream had
no logic to scroll to the target bubble — and the post might not be paged
in yet. MessageStream now resolves the #post-<id> hash, auto-loads more
pages until the bubble renders, scrolls to it, and gives it a brief gold
highlight. Bubbles get scroll-mt so they clear the sticky header.
Also adds a global floating back-to-top button (BackToTop) mounted in
PublicLayout, shown after scrolling past 400px.
Bundles related staging UI work already present in the working tree.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>