Task 12 batch around the existing crop/preview flow:
- Success Notice (auto-dismiss ~2.5s) after an avatar upload.
- "Reposition" re-crops the current avatar without re-picking a file.
- Drag & drop an image straight onto the profile avatar circle.
- Real upload progress via a new XHR-backed api.upload (fetch has none);
refreshOnce now also stores the renewed token (reload-restore fix).
- Local avatar history (last 5, IndexedDB, this-device-only) strip that
re-uploads a stored crop. Stored as ArrayBuffer (Blob is not cloneable
under structuredClone); label makes the per-device scope explicit.
- Added a "success" tone to Notice.
Infra (same session): registered @shared/@features/@pages/@app/@test path
aliases in vite.config + tsconfigs and rewrote deep ../../../ imports;
moved avatar components into components/avatar/ to keep folders at <=4 files.
Tests: avatarHistory cap/order, recrop visibility, drop-opens-cropper,
client upload/progress/401-retry. bun test 103 pass, lint 0 errors, build ok.
Implements the last unbuilt easter egg (PLAN Task 11 #5, TODO «Пасхалки» #5): the
404 used to show static ASCII art; now a grass block drops into a dusk world,
cracks over three clicks, then bursts into square debris and respawns. Keyboard
accessible (a real button), and under prefers-reduced-motion the fall and burst
are skipped while the crack stages still work. Replaces the NOT_FOUND_ART pane;
i18n adds notFound.blockAria/blockHint (ru+en).