+
+
+ {/* Surfaces 8 & 9 — Method divider + OIDC button (only when oidcEnabled) */}
+ {oidcEnabled && (
+ <>
+ {/* Surface 8 — Method divider */}
+
+
+ {/* Surface 9 — OIDC login button — uses generic copy per D-06 */}
+
+ >
+ )}
+ + Sign in +
+ + {/* Surface 4 — Username field */} +
+
+ setUsername(e.target.value)}
+ onKeyDown={handleUsernameKeyDown}
+ aria-describedby={loginError ? 'login-error' : undefined}
+ style={inputStyle(inputHasError)}
+ />
+
+
+ {/* Surface 5 — Password field with show/hide toggle */}
+
+
+
+
+ {/* Surface 6 — Error / lockout banner */}
+ {loginError && (
+
+ setPassword(e.target.value)}
+ onKeyDown={handlePasswordKeyDown}
+ onBlur={() => setShowPassword(false)}
+ aria-describedby={loginError ? 'login-error' : undefined}
+ style={{ ...inputStyle(inputHasError), paddingRight: '44px' }}
+ />
+ {/* Show/hide toggle button — 44px tap target (UI-SPEC Surface 5) */}
+
+
+
+ {loginError === 'invalid' && (
+
+ )}
+
+ {/* Surface 7 — Primary submit button */}
+
+
+ {/* Surface 10 — Forgot password helper (informational only, not interactive) */}
+
+
+ Incorrect username or password.
+
+ )}
+
+ {loginError === 'rate-limit' && (
+
+
+ Too many attempts. Please wait a moment and try again.
+
+ )}
+
+ {loginError === 'locked' && (
+
+
+ This account is temporarily locked. Contact your admin to reset access.
+
+ )}
+
+ {loginError === 'server' && (
+
+
+ Something went wrong. Please try again.
+
+ )}
+ + Forgot your password? Ask your admin. +
+