Previously the profile editor only accepted external URLs for
picture/banner — typing in a URL works, but anyone without their
own image host couldn't use an avatar at all. Now there's an
"Upload" button next to each field that pushes the selected file
to /api/blob and pastes the returned capability-signed local URL
(`/blob/<cid>?cap=…&exp=…&peer=…`) straight into the form field.
- Two new refs: avatarUploading / bannerUploading so each button
shows "Uploading…" independently.
- uploadAsset(ev, 'picture' | 'banner') wraps the POST, validates
HTTP 200 + presence of self_test_url, surfaces failures in the
existing profileError banner.
- File input is re-cleared on completion so the user can pick the
same file again without refreshing.
- Live preview in the <img> at the top of the editor updates
immediately because profileForm[field] is reactive.
Image persists through Save & Publish via the existing
identity.update-profile + identity.publish-profile (both now
multi-relay). The image URL is still local-only — external nostr
clients won't resolve it until we integrate a public image host
(noted in task #29).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>