web: invite landing leads straight to sign-in — skip becomes small print (#1430)
* web: prejoin card leads straight to sign-in — skip demoted to small print The invitation landing card presented two equal-weight buttons (sign in / continue without an account) — a choice where there should be one path. Now: a single primary CTA, "Sign in with Eleven", with "Continue without signing in" as a quiet grey link under the caveat (still a real <button>, keyboard-operable, ≥24px target). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * home: clear the stale 'Checking your sign-in…' status when auto-enrol falls back A fresh sign-up reaches /enroll with a live session but no blob yet (the first blob needs a ceremony's PRF), so the auto fast path falls back to the card — but left its busy status painted, reading as a stuck spinner under the re-enabled buttons. Clear it on that return. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> ---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
5 files changed,
+29
−8
changelog/2026-08-06-prejoin-signin-lead.md+4 −0docs/onboarding-and-home-server.md+4 −3home/web/static/enroll.js+5 −1web/pages/join.html+5 −4web/static/style.css+11 −0
diff --git a/changelog/2026-08-06-prejoin-signin-lead.md b/changelog/2026-08-06-prejoin-signin-lead.md| new file mode 100644 |
| index 0000000..cf1af0c |
| --- /dev/null |
| +++ b/changelog/2026-08-06-prejoin-signin-lead.md |
| @@ -0,0 +1,4 @@ |
| +🤖 The invite page now leads with one clear step: **Sign in with Eleven**. No |
| +more choosing between two ways in — signing in is the path, and "Continue |
| +without signing in" waits underneath as small print for anyone who'd rather |
| +skip it. |
diff --git a/docs/onboarding-and-home-server.md b/docs/onboarding-and-home-server.md| index 7c3f74f..3bd0222 100644 |
| --- a/docs/onboarding-and-home-server.md |
| +++ b/docs/onboarding-and-home-server.md |
| @@ -87,9 +87,10 @@ URL bar. Claim happens only on an explicit choice. |
| access to this chat — save a passkey"), Apple-style, after they've arrived. |
| 🤖 *Shipped 2026-07-31 (signup-first join):* the sign-in-first ordering above |
| -now exists as the join page's **lead card** — fresh joiners see "Continue with |
| -your Eleven sign-in" before the app/web choice, with a quiet "Continue without |
| -an account" escape. The round trip differs from the sketch in two details: |
| +now exists as the join page's **lead card** — fresh joiners see "Sign in with |
| +Eleven" before the app/web choice, with "Continue without signing in" as small |
| +print (a quiet link, not a competing button — one path, plus an escape hatch; |
| +Paul, 2026-08-06). The round trip differs from the sketch in two details: |
| it's always a same-tab navigation (never a popup — Safari blocks WebAuthn in |
| cross-origin popups), and the fragment parks in the instance origin's |
| `localStorage` (nonce-stamped, expiring), not `sessionStorage`, so a mobile |
diff --git a/home/web/static/enroll.js b/home/web/static/enroll.js| index 63bc891..06480f4 100644 |
| --- a/home/web/static/enroll.js |
| +++ b/home/web/static/enroll.js |
| @@ -159,7 +159,11 @@ async function trySessionReuse() { |
| try { |
| setStatus("Checking your sign-in…", "busy"); |
| got = await fetchBlob(cand.token); // throws on a dead token (401) |
| - if (!got) return false; // signed in but no backup yet — the ceremony path knows that case |
| + // Signed in but no backup yet (a fresh sign-up — the first blob needs a |
| + // ceremony's PRF, which reuse can't supply). Clear the busy status before |
| + // falling back: in auto mode nothing else repaints, so "Checking your |
| + // sign-in…" would sit under the re-enabled buttons like a stuck spinner. |
| + if (!got) { setStatus("", ""); return false; } |
| dek = await importDEK(cand.dek); |
| opened = await openBlob(got.bytes, dek); |
| } catch { |
diff --git a/web/pages/join.html b/web/pages/join.html| index 66308a1..d27a6a4 100644 |
| --- a/web/pages/join.html |
| +++ b/web/pages/join.html |
| @@ -115,20 +115,21 @@ |
| <!-- The signup-first lead card (docs/superpowers/specs/2026-07-31-signup-first- |
| join-design.md): fresh joiners see the sign-in door BEFORE the app/web |
| - choice, so their access is saved to their account from the start. Skippable |
| - — "Continue without an account" reveals the classic welcome card. --> |
| + choice, so their access is saved to their account from the start. ONE path |
| + — sign in — not a choice: the skip is deliberately small print (a quiet |
| + link revealing the classic welcome card), never a competing button. --> |
| <template id="prejoin-tpl"> |
| <img id="prejoin-photo" class="onboard-photo hidden" alt="" /> |
| <div class="onboard-icon" id="prejoin-icon">💬</div> |
| <h1 id="prejoin-title">You're invited to __GROUP_NAME__</h1> |
| <p id="prejoin-sub">Private, end-to-end encrypted chat.</p> |
| <p id="prejoin-desc" class="welcome-desc hidden"></p> |
| - <div class="row"><button id="prejoin-signin">Continue with your Eleven sign-in</button></div> |
| - <div class="row"><button id="prejoin-skip" class="secondary">Continue without an account</button></div> |
| + <div class="row"><button id="prejoin-signin">Sign in with Eleven</button></div> |
| <p class="welcome-caveat"> |
| Signing in first keeps your access safe — get back into this space from any |
| device, with nothing to remember. |
| </p> |
| + <div class="row"><button id="prejoin-skip" class="link-quiet">Continue without signing in</button></div> |
| </template> |
| <!-- The welcome card (deferred claim — see docs/onboarding-and-home-server.md). |
diff --git a/web/static/style.css b/web/static/style.css| index ae62725..79552b7 100644 |
| --- a/web/static/style.css |
| +++ b/web/static/style.css |
| @@ -1923,6 +1923,17 @@ select:disabled { opacity: 0.5; cursor: default; } |
| air between it and the button it annotates. (.card selectors so this outranks |
| the generic .card p margin rule.) */ |
| .card .welcome-caveat { font-size: 13px; color: var(--muted); margin: 20px auto 4px; max-width: 42ch; } |
| +/* A quiet escape hatch on the onboarding cards (e.g. the prejoin card's |
| + "Continue without signing in"): small print that acts, not a competing |
| + button — a real <button> so it stays keyboard-operable and focusable. */ |
| +button.link-quiet { |
| + background: none; |
| + color: var(--muted); |
| + font-size: 13px; |
| + font-weight: 400; |
| + text-decoration: underline; |
| + padding: 6px 8px; /* keeps the tap target ≥24px despite the small type */ |
| +} |
| /* the space's own description on the welcome card: the admin's note to the |
| person joining — content to read, not chrome. A tinted panel with |
| full-strength text sets it apart from the muted boilerplate around it. */ |