{
  "aliases": [
    "password-recovery",
    "forgot-password",
    "reset-password",
    "mfa-challenge",
    "two-factor-challenge",
    "2fa-challenge",
    "otp-challenge",
    "passkey-failure",
    "scr-008"
  ],
  "code": "// ⚠️ There is NO <PasswordRecoveryPanel state=…/> and NO <MfaChallengePanel state=…/> in\n// @godxjp/ui. What the package owns is the MEASURE:\n//    <CenteredShell variant=\"auth-canonical\" preset=\"account-recovery\">   ← 432px panel, 15px gutter at 390\n// Docs page: docs/layout/auth-recovery/\n//\n// PRESENTATION ONLY. No route, no reset semantics, no OTP verification, no recovery-code\n// consumption, no passkey authentication, no permissions. The consumer owns all logic and copy.\n\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@godxjp/ui/data-display\";\nimport { FormField, Input, InputOTP, InputOTPGroup, InputOTPSlot, PasswordInput, PasswordStrength } from \"@godxjp/ui/data-entry\";\nimport { Alert, AlertDescription, AlertTitle } from \"@godxjp/ui/feedback\";\nimport { Button, Reveal } from \"@godxjp/ui/general\";\nimport { AuthFooter, CenteredShell, AuthStack, Flex } from \"@godxjp/ui/layout\";\n\n// ── THE CANONICAL PANEL ANATOMY — identical for ALL SEVEN states ───────────────────────\n//   Card > CardHeader(CardTitle + CardDescription)   ← title/description INSIDE the surface\n//        > CardContent > AuthStack\n//            [notice]   Alert tone=\"success|destructive\"   (only when the state has one)\n//            [fields]   FormField(s): email · password pair · ONE 6-slot InputOTP · one Input\n//            [primary]  Button fullWidth                    (spans the panel; exactly one)\n//            [fallback] Flex justify=\"between\" gap=\"sm\" wrap (two ghost actions share ONE row)\n//\n// DON'T put <AuthIdentity> above the panel here — it always renders the hosted mark, and the\n// SCR-008 hierarchy puts the heading INSIDE the bordered surface.\n// DON'T reuse <TwoFactorSetup> — that is the ENROLLMENT Dialog (QR / manual key / recovery\n// output). A sign-in challenge has no secret to reveal and no dialog to dismiss: it IS the page.\n\n// ── SIGN-IN MFA CHALLENGE (otp) ────────────────────────────────────────────────────────\n// Focus order IS DOM order: code field → verify → fallback A → fallback B. No tabindex.\n// The 6-slot row is ONE field: InputOTP owns paste/arrows/backspace/caret and is a single tab\n// stop. Six <Input>s would put six stops in the ring and break paste of a 6-digit code.\nexport function MfaChallengePage({ code, onCodeChange, error, pending, onVerify }) {\n  return (\n    <CenteredShell variant=\"auth-canonical\"\n      preset=\"account-recovery\"\n      brand={brand}\n      footer={<AuthFooter product=\"GoDX ID\" terms={termsLink} privacy={privacyLink} locale={localePicker} />}\n    >\n      <Reveal>\n        <Card>\n          <CardHeader>\n            <CardTitle level={1}>{t(\"mfa.title\")}</CardTitle>\n            <CardDescription>{t(\"mfa.description\")}</CardDescription>\n          </CardHeader>\n          <CardContent>\n            <AuthStack>\n              <FormField id=\"mfa-code\" label={t(\"mfa.codeLabel\")} error={error} required>\n                <InputOTP maxLength={6} pattern=\"^[0-9]+$\" value={code} onChange={onCodeChange}>\n                  <InputOTPGroup>\n                    {/* six <InputOTPSlot index={0..5} /> */}\n                  </InputOTPGroup>\n                </InputOTP>\n              </FormField>\n              <Button fullWidth loading={pending} loadingText={t(\"common.verifying\")} onClick={onVerify}>\n                {t(\"mfa.verify\")}\n              </Button>\n              <Flex justify=\"between\" gap=\"sm\" wrap>\n                <Button variant=\"ghost\" size=\"sm\">{t(\"mfa.useRecoveryCode\")}</Button>\n                <Button variant=\"ghost\" size=\"sm\">{t(\"mfa.retryPasskey\")}</Button>\n              </Flex>\n            </AuthStack>\n          </CardContent>\n        </Card>\n      </Reveal>\n    </CenteredShell>\n  );\n}\n\n// ── THE OTHER SIX STATES — same anatomy, only the notice/fields/copy change ─────────────\n// The STATE IS NOT A PROP: the server answers, and the route renders the matching body in the\n// SAME 432px panel. Nothing is reconstructed, because nothing was torn down.\n//\n//   password recovery · request        —  fields: email (autoComplete=\"username\")\n//   password recovery · sent           —  <Alert tone=\"success\"> + <Button fullWidth disabled> (cooldown)\n//   password recovery · new-password   —  two <PasswordInput autoComplete=\"new-password\"> + <PasswordStrength>\n//   password recovery · expired        —  <Alert tone=\"destructive\">, primary = request a new link\n//   MFA · recovery-code                —  ONE <Input autoComplete=\"one-time-code\">\n//   MFA · passkey-failure              —  <Alert tone=\"destructive\">, primary = retry passkey\n//\n// The masked address in `sent` (\"h*****@example.co.jp\") is produced by the SERVER — the panel\n// never reconstructs an identifier, it renders the string it is given.\n\n// ── STATES ─────────────────────────────────────────────────────────────────────────────\n//  error    FormField error ⇒ aria-invalid + aria-errormessage + role=\"alert\". Never colour-only.\n//  loading  Button loading + loadingText ⇒ aria-busy, the box does not resize, fallbacks disabled.\n//  disabled a resend cooldown is <Button disabled> — keep it VISIBLE so the affordance is known.\n\n// ── RESPONSIVE CONTRACT (1440 / 1024 / 390) ────────────────────────────────────────────\n//  1440 · 1024   panel 432px, centred, 16px page gutter; OTP one row (6 × 36px = 216px)\n//  390           panel 360px at x=15 (15px inline gutter, --auth-shell-recovery-main-padding-mobile),\n//                310px content column, OTP still ONE row, primary still full-width, the fallback\n//                row wraps to a stack only when the localized labels exceed the column.\n//  ⚠️ The 390 canonical reference is a desktop 2×2 COMPOSITE that overflows\n//  and crops horizontally. It is NOT a valid mobile source and was not traced; the row above is a\n//  DECIDED contract, documented in docs/layout/auth-recovery/ and pinned by tests.\n\n// ANTI-PATTERNS: a page-local --auth-shell-card-max-width override or a .recovery-panel{width:432px}\n// class · AuthIdentity above the panel · TwoFactorSetup as a challenge · six Inputs for the OTP row ·\n// re-scoping --control-height to widen the slots (use --otp-slot-size) · two primary actions.",
  "name": "auth-recovery-panels",
  "tagline": "Signed-OUT password recovery + sign-in MFA challenge panels (SCR-008). There is NO PasswordRecoveryPanel and NO MfaChallengePanel — compose Card + AuthStack + FormField/InputOTP + Button inside CenteredShell variant=\"auth-canonical\" preset=\"account-recovery\" (the 432px token-owned measure).",
  "tags": [
    "auth",
    "authshell",
    "recovery",
    "password",
    "mfa",
    "2fa",
    "otp",
    "inputotp",
    "passkey",
    "layout",
    "presentation"
  ]
}
