personal memory agent

feat(convey): optional per-facet Lucide icon override + icon picker master

- Add an optional, additive `icon` (Lucide name) to facets that overrides the emoji-derived icon. The stored `emoji` stays the source of truth and the fallback; `icon` never mutates `emoji`. - icons.py becomes the single owner of icon precedence + search: resolve_facet_icon_svg (explicit icon → emoji translation → none, degrading a dangling icon to its emoji), is_lucide_icon, and search_lucide_icons (name-first then tag matches over the vendored name+tags data). - facets.py persists `icon` only when set; clearing removes the key (clearing an unset icon is a no-op — no change-diff, no audit, no empty key); unknown icons raise a resolution-guiding ValueError. - Settings routes accept/validate/persist/return `icon` on create (POST) and update (PUT, now mapping ValueError→400), expose raw `icon`+resolved `icon_svg` in the facet record, and add a server-backed GET /app/settings/api/icons search endpoint (no ~1MB icon JSON shipped to the browser). - CLI gains `--icon` on `facet create`/`facet update` (empty clears); cli.md documents it. - Facet appearance settings get an emoji-picker-style Lucide picker modal: server-backed debounced search, inline-SVG grid in the facet color, live preview, apply / use-emoji-instead, error+retry degraded state, and a focus-trap that stays valid across grid re-renders with roving arrow-key grid nav. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>