ui: give Radial links a preview of their own master
A crawler does not run the app, so a pure SPA — one shell for every URL — unfurled as nothing at all: no title, no description, no image. Two layers fix that, and the first is the one that matters. The shell now carries defaults: a title, a description, and an absolute 1200x630 og:image built from PUBLIC_RADIAL_ORIGIN, the same knob client-metadata.json already uses. Any host serving this bundle unfurls every URL with the branded card. The card is static/og.png, drawn from the mark's own geometry by scripts/og-card.mjs and checked in. On Pages, build/_worker.js (src/edge/) upgrades those tags per record for the two path families whose URLs name one: /g/<did>/<rkey> is a goal's AT URI, and ?unit= carries the unit's. It fetches the same shell Pages would have served, reads the public record unauthenticated, and replaces <title>, og:title, og:description, og:type and og:url. A project route carries only a name, so that is all it claims. src/lib/meta.ts holds the text rules, shared with the browser so document.title and the shared card agree about the same URL. This is not a view server coming back: no materialize, no index, no write, no credential, and identical bytes for crawlers and people. static/_routes.json confines the worker to /g/* and /p/*; everything else keeps the byte-for-byte static path. Every failure — unresolvable DID, PDS down, bad record, malformed link, missed deadline — ends in the shell's defaults and a working app. Verified under wrangler pages dev against real records: deep links get their tags, garbage degrades to defaults at HTTP 200, and /, /awaiting, /space, /client-metadata.json, /og.png and /favicon.svg come back byte-identical to the bundle. That run is also what caught workerd rejecting a non-function named export from _worker.js, which is why the entry module is one default export and a test holds it there. Co-Authored-By: claudebot.disnetdev.com (did:plc:n6ku5xddiuguwze3f356evla) <claudebot.disnetdev.com@noreply.radial>