Feature: Password reset request screen As a RenewCMS user who forgot their password I want a /register/reset/request screen that emails a reset link via POST /v1/auth/password-reset, validates the email client-side before sending, and never reveals whether the address has an account So that I can ask for a reset link with the same neutral confirmation regardless of whether my account exists, and see plainly when I'm asking too often or the server failed Background: Given /register/reset/request is a public route (meta.auth "public") rendered as ResetRequestPage inside AuthShell, per docs/design/routes.md And ResetRequestPage only calls POST /v1/auth/password-reset And the form has a single Email field (placeholder "you@example.com") And client-side validation runs on submit only, before any request is sent: Email must be a well-formed email address (the same pattern RegisterPage already uses), and a failing Email shows "Enter a full email address, like name@example.com." And a valid submit calls POST /v1/auth/password-reset with { email } And every response the API gives — whether the email belongs to an account or not — is the same 200 with the same body, per features/request_password_reset.feature, so the screen shows the same Sent state either way And a 429 response carries a Retry-After header in seconds, surfaced by useApi and displayed as a live countdown on the submit button, the same mechanism LoginPage's own 429 handling uses, and the Email field is disabled for the same duration And a 500 response, or a request that never reaches the server, is surfaced as a server/network error; the field keeps whatever the user typed and the form re-enables And a 400 response is not expected once client-side validation passes, since the client checks the same required,email rule the API enforces; it is out of scope for this slice Scenario: Default — a fresh, empty form When the user navigates to /register/reset/request Then the heading is "Reset your password" And the description is "Enter the email for your account and we'll send you a link to choose a new password." And the Email field shows placeholder "you@example.com" with no value And the submit button reads "Send reset link" And the footer reads "Back to log in" linking to /login Scenario: Validation error — an invalid email blocks the request Given the user is on /register/reset/request When the user types "marta@renew" into Email and submits Then POST /v1/auth/password-reset is never called And the Email field shows the error "Enter a full email address, like name@example.com." Scenario: Submitting — the field and button are disabled while the request is in flight Given the user is on /register/reset/request with Email "marta@renew.example" When the user submits and POST /v1/auth/password-reset has not yet resolved Then the Email field is disabled And the submit button reads "Sending…" and shows a loading state Scenario: Sent — any 200 shows the same neutral confirmation Given the user is on /register/reset/request with Email "marta@renew.example" When the user submits and POST /v1/auth/password-reset resolves 200 Then the form is replaced by a ResultPanel with tone "success", icon "i-lucide-mail-check", title "Check your email", text "If an account exists for that email, a password reset link has been sent.", and note "The link expires in 1 hour." And its single action is a secondary "Back to log in" When the user activates "Back to log in" Then the app navigates to /login Scenario: Too many attempts — the button is disabled with a live countdown Given the user is on /register/reset/request with Email "marta@renew.example" When the user submits and POST /v1/auth/password-reset resolves 429 with a Retry-After of 58 seconds Then an info alert reads "Too many requests" with description "Wait a moment before asking for another link." And the Email field still shows "marta@renew.example" And the submit button reads "Try again in 0:58" and is disabled And the Email field is disabled while the countdown runs When 58 seconds elapse Then the submit button re-enables and reads "Send reset link" And the Email field is editable again Scenario Outline: Server or network error — the field keeps its value and re-enables Given the user is on /register/reset/request with Email "marta@renew.example" When the user submits and POST /v1/auth/password-reset Then an error alert reads "Couldn't send the link" with description "Check your connection and try again." And the Email field still shows "marta@renew.example" and is re-enabled And the submit button reads "Send reset link" again, no longer loading Examples: | failure | | fails with a 500 response | | never reaches the server |