- History drawer in a local (offline) game: the seat plaques no longer
show the add-friend/block controls — canAddFriend/canBlock now exclude a
local game (hotseat seats have synthetic account ids that slipped past
the vs_ai-only guard) — and the Dictionary entry is restored: an active
hotseat game keeps the comms button, and CommsHub is Dictionary-only for
a chatless vs_ai OR hotseat game (ChatScreen never mounts offline).
- Enter on any single-line <input> now dismisses the soft keyboard (blur);
a <textarea> (feedback) keeps Enter for newlines. One global handler.
- Login email code: the friend-code spread-digit style (.codein), a
6-char cap, auto-submit on the 6th digit, and Enter to submit.
- e2e: the local-game history has no social controls and keeps the
dictionary entry.
Make the web SPA an installable PWA and surface it to users:
- manifest.webmanifest + an install-only service worker + 192/512/maskable
icons (ui/public); PWA head tags in index.html; the .webmanifest MIME type
registered in the gateway (the distroless image has no /etc/mime.types).
- Platform-adaptive install CTA (components/InstallApp.svelte + lib/pwa):
one-tap on Chromium, manual Add-to-Home-Screen instructions on iOS Safari,
hidden elsewhere / once installed / inside a Mini App. Shown under the
logged-out login card and at the bottom of Settings.
- The landing gains a third entry linking /app/ (the brand tile), with a
caption under all three (Telegram / VK / Веб-версия).
The service worker is navigation-only (network-first, cached-shell fallback);
hashed assets and the Connect stream are untouched. It exists to satisfy
Chromium's installability requirement and is the single growth point for a
future opt-in offline mode.
Tests: pwa.ts unit tests; a webui probe (manifest/sw.js content-type + the
SPA-fallback-to-HTML trap); e2e for the one-tap CTA, the iOS instructions
modal and the landing web entry. Docs: ARCHITECTURE §13, FUNCTIONAL (+ru),
gateway README.