The link screen carries the whole burden of the five-minute bar: it names
where to find the instance ID, validates the format before asking the server
so a typo is instant rather than a round trip, surfaces the backend's own
message when a UUID is already linked, and on success lands the customer
directly on the download rather than back on a list.
Billing is deliberately thin and says plainly that billing changes go
through support, rather than linking to a Paddle portal that does not exist
until spec 5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The blob is shown inline as well as offered as a file, because a licence is
signed public data bound to one instance -- useless anywhere else -- and a
blocked download must never leave a paying customer stuck. Admin now returns
it to its owner for the same reason.
Relink shows the remaining allowance from the backend's max_relinks rather
than a hardcoded 3, and at zero it disables and says to contact support
instead of failing at the API.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
State reads three ways on every card -- a stripe, a shaped-and-labelled
pill, and the copy -- so it survives a colourblind reader and a glance at
arm's length. Colour alone would fail on the one screen where getting it
wrong costs money.
The expired card leads with what still works, because that is the first
thing a worried customer wants to know and the backend really does keep
servers, monitors and agent keys running. The awaiting-link card is
deliberately loud: a customer who has paid and not linked has paid for
nothing yet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Route-group layouts do the guarding. A customer session on /staff/* is
redirected to its own home rather than shown a refusal -- there is nothing to
tell them about. This is UX only: admin enforces the same boundary with
RequireStaff/RequireCustomer and answers 404 rather than 403 for another
account's data, which is the layer that actually matters.
Signup carries the honeypot the backend expects and reports "check your
email" rather than claiming an account exists, matching a backend that
creates nothing until the link is opened.
Buttons match site/'s .btn--solid and .btn--line, neutral border included.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>