Half of #669, re-planned after pull #2859's preview failed to deploy. Keep the change to src/web/pages/site.ts and one new test so the preview stays deployable.
Done looks like
[ ] On /signin, "Sign in with a passkey" is the primary button and comes before the password form. Today it is an outline button below the form (site.ts ~line 381).
[ ] When signup is invite, /signin says "This forge is invite-only: new accounts need an invite link." When it is closed, it says "This forge is closed to new accounts." When it is open, it says neither.
[ ] /signup with a valid invite link still opens the passkey sign-up, with the human check (#661) on the page.
[ ] Usable at 360px width: no horizontal scroll.
[ ] test/signin-page.test.ts renders /signin in each signup mode, checks the sentence, and checks that the passkey button comes before the <form. Each assertion fails on main.
[ ] Before pushing, run bun x tsc --noEmit and the sign-in and sign-up suites (test/signin*.test.ts, test/signup*.test.ts, test/forge-signin*.test.ts).
Half of #669, re-planned after pull #2859's preview failed to deploy. Keep the change to
src/web/pages/site.tsand one new test so the preview stays deployable.Done looks like
/signin, "Sign in with a passkey" is the primary button and comes before the password form. Today it is an outline button below the form (site.ts~line 381).signupisinvite,/signinsays "This forge is invite-only: new accounts need an invite link." When it isclosed, it says "This forge is closed to new accounts." When it is open, it says neither./signupwith a valid invite link still opens the passkey sign-up, with the human check (#661) on the page.test/signin-page.test.tsrenders/signinin eachsignupmode, checks the sentence, and checks that the passkey button comes before the<form. Each assertion fails on main.bun x tsc --noEmitand the sign-in and sign-up suites (test/signin*.test.ts,test/signup*.test.ts,test/forge-signin*.test.ts).