Vietnamese text rendered with split diacritics — "Tất cả tài liệu" came
out as "Tâ´t ca' tài liêụ" because the previous font stack led with
six CJK-only families (Noto Sans SC/TC, PingFang SC/TC, Microsoft
YaHei/JhengHei) that have zero Vietnamese coverage. The browser still
matched the Latin base letters in those fonts and dropped the combining
tone marks onto the next available slot, breaking shaping for every
precomposed Vietnamese codepoint (U+1EA5, U+1EC7, …).
Reorder the stack so ui-sans-serif / system-ui / -apple-system / Segoe UI
lead and the CJK families follow as fallbacks. Browsers do per-glyph
font selection so Chinese characters still hit PingFang SC / Noto Sans
SC etc.; the zh-CN and zh-TW pages render unchanged. The fix needs no
extra network requests — every modern OS bundles a Latin font with
Vietnamese support.
Verified in browser at /vi/browse ("Tất cả tài liệu" / "Liên kết" /
"Tệp nén" all compose correctly) and /cn/browse (still PingFang SC).
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>