Eight canonical auth states forming the complete sign-in / sign-up / recovery flow. Every screen
uses the same auth-card anatomy (icon glyph → title → subtitle → form → primary CTA → footer link),
so users learn the layout once and recognize it across all states.
The flow
Sign in
→
2FA challenge
→
App ✓
|
Sign up
→
Verify email
→
App ✓
|
Forgot password
→
Reset link sent
→
New password
→
Sign in
Usage rules
1. Auth-card anatomy (same for every state)
Glyph — 40×40 brand-tinted square with state-appropriate icon
Title — 18px, action-oriented or status. "Welcome back", not "Sign in form".
Subtitle — 12.5px muted. One sentence: what to do here, or what just happened.
Form fields — 10px gap. Show requirements progressively, not all at once.
Primary CTA — full-width, brand-primary. Verb that completes this step.
Footer link — alternate path ("Don't have an account? Sign up")
2. Field rules
Field
Rules
email
Always type="email" with autocomplete="email". Validate format on blur, not keystroke.
password (sign-in)
Single field. autocomplete="current-password". Show/hide toggle. No strength meter on sign-in (it's discouraging).
password (sign-up / reset)
autocomplete="new-password". Strength meter required. Requirements shown as hint, validated on blur.
code (2FA / OTP)
Single 6-digit input. inputmode="numeric". autocomplete="one-time-code" (browsers offer SMS auto-fill on iOS). Auto-submit on 6th digit.
terms (sign-up only)
Required checkbox. Default unchecked. Link out to terms page in new tab.
3. Per-brand voice
State
Perpetuals
Barriers
UpsideOnly
Sign-in title
Welcome back
Sign in
Welcome back
Sign-up title
Create your account
Open an account
Join UpsideOnly
Subtitle tone
Warm-professional
Direct-factual
Encouraging-clear
Forgot CTA
Send reset link
Send reset link
Send me a link
2FA subtitle
We sent a 6-digit code to your phone
Enter the 6-digit code from your authenticator
We texted a code to (***) ***-7421
4. Don't
❌ Don't show password requirements until the user blurs the password field — pre-emptive shaming
❌ Don't auto-submit the form on the email field's blur — wait for the user to take action
❌ Don't show "Email or username" — pick one (we use email everywhere)
❌ Don't trap focus inside a sign-in form (this is a full-page route, not a modal — Tab should be free)
❌ Don't redirect to the "Forgot password" page automatically after a wrong-password attempt — let the user try once more first
❌ Don't reset the form on validation error — preserve typed values; only the offending field shows error state
5. Accessibility
Every input has an associated <label>
Show/hide password toggle is a button with aria-label="Show password" / "Hide password"
Strength meter has aria-live="polite" announcing changes
Error messages link to inputs via aria-describedby
Submit button gets aria-busy="true" while pending
2FA input has autocomplete="one-time-code" for SMS autofill