The hub rendered all 8 standalones statically and greyed out any whose
VITE_HUB_<APP>_URL was unset — so an events-only deploy showed 7 dead
"coming soon" tiles. The greyed path was overloaded: hubLink() returned
null for both "not deployed" and "logged out", which the template then
couldn't tell apart.
Replace that with a registry → resolver → view-model pipeline:
- availabilityOf(m) resolves an explicit state from deploy config + auth:
available | auth-locked | inactive | unavailable.
- A `tiles` computed maps the catalog to view-models and drops
'unavailable' (not provisioned) entirely — no more ghost tiles.
- 'auth-locked' keeps today's greyed + login-prompt behavior for
deployed-but-logged-out apps (wallet, chat, tasks, libra).
- 'inactive' (active:false) is wired as a greyed, inert state — an unused
seam for a future install/disable model; no app sets it yet.
The view treats the catalog as an opaque list, so the source can later
move from this in-code array to a runtime feed (LNbits /hub/apps or a
NIP-78 event) without touching the render path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>