feat(profile): primary Main Link drives card target; Website becomes optional Landing Page
The whole /explore profile card is now a button: clicking it sends
visitors to the project's mainLink (the actual app, service, or
landing page) with an external-link arrow in the top-right corner.
The previous "Website" concept becomes an optional secondary
"Landing Page" button on the profile detail page.
Lexicon
* com.atmosphereaccount.registry.profile: add optional mainLink
string (uri, <=512). Optional in the lexicon for backward-compat
reads of pre-mainLink records; the registry UI/API enforce it as
required for new/updated records.
* The legacy `website` link kind is repurposed as the storage shape
for the optional Landing Page button (no schema rename — keeps
existing records valid).
DB
* profile.main_link TEXT column (additive migration; safe on
existing Turso DBs).
* upsertProfile reads/writes main_link; ON CONFLICT preserves the
same admin/icon semantics as before.
Form (/explore/manage)
* New required "Main Link (URL)" field directly above Atmosphere
links.
* Legacy `kind: website` URL is auto-promoted into the Main Link
slot on first load when the record has no mainLink — the user
agreed to "treat existing website as Main Link" semantics so this
is one save away from clean.
* Renamed Website field to "Landing Page (URL)" with a hint
clarifying it's a separate marketing/landing surface.
* Client-side guard: empty / non-http(s) Main Link surfaces a clean
inline error before round-tripping.
API (PUT /api/registry/profile)
* mainLink is required server-side; rejects with 400 + a clear
error otherwise. Validation library still treats mainLink as
optional so reads of pre-mainLink records keep parsing.
Public surfaces
* ProfileCard: whole card is an anchor to mainLink (target=_blank,
rel="noopener noreferrer external"), with a small inline SVG
arrow that lifts on hover. Falls back to /explore/<handle> for
legacy records that lack mainLink so the card never 404s.
* ProfileLinks already filters out empty entries, so missing
Atmosphere links / missing Landing Page just don't render — no
empty placeholder buttons.
* Globe icon + "Landing page" label propagate via the existing
resolveLink path; no detail-page changes needed.
i18n
* Added forms.profile.mainLink + forms.profile.landingPage; kept
the legacy bskyDescription strings around for now (used elsewhere).
* linkKinds.website re-labelled "Landing page" so the public button
reads correctly without renaming the underlying kind.
Migration story
* Existing records keep working unchanged. On first re-save through
the form, mainLink lands on the record and the legacy website
entry drops off (the form leaves Landing Page empty post-promotion
so users don't end up with two buttons pointing at the same URL).
Made-with: Cursor