+ {/* Surface 2 — Brand Slot (above the login card, in the flow) */} + + + {/* Surface 3 — Login Card */} +
+

+ 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 */} +
+ +
+ 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) */} + +
+
+ + {/* Surface 6 — Error / lockout banner */} + {loginError && ( +
+ {loginError === 'invalid' && ( +
+
+ )} + + {loginError === 'rate-limit' && ( +
+
+ )} + + {loginError === 'locked' && ( +
+
+ )} + + {loginError === 'server' && ( +
+
+ )} +
+ )} + + {/* Surface 7 — Primary submit button */} + + + {/* Surface 10 — Forgot password helper (informational only, not interactive) */} +

+ Forgot your password? Ask your admin. +

+
+ + {/* Surfaces 8 & 9 — Method divider + OIDC button (only when oidcEnabled) */} + {oidcEnabled && ( + <> + {/* Surface 8 — Method divider */} + + ); +} diff --git a/apps/pwa/src/styles/tokens.css b/apps/pwa/src/styles/tokens.css index 578ce00..88fa3bf 100644 --- a/apps/pwa/src/styles/tokens.css +++ b/apps/pwa/src/styles/tokens.css @@ -88,6 +88,18 @@ --text-display-weight: 600; --text-display-line-height: 1.2; + /* ───────────────────────────────────────────────────────────────────────── + * BRAND SLOT — Phase 17 seam tokens + * Phase 19 sets placeholder defaults; Phase 17 overrides these values only — + * never the BrandSlot component structure (see 19-UI-SPEC.md §Brand Slot). + * ───────────────────────────────────────────────────────────────────────── */ + + --brand-logo-bg: var(--color-member-0); /* placeholder circle background */ + --brand-logo-text: #ffffff; /* placeholder initials color */ + --brand-logo-size: 48px; /* reserved slot height; keep 1:1 aspect */ + --brand-logo-border-radius: 50%; /* circle for initials; Phase 17 may change */ + --brand-app-name: 'FamilySync'; /* drives doc only — not used as CSS content */ + /* ───────────────────────────────────────────────────────────────────────── * BREAKPOINTS (reference; use in @media queries) * ───────────────────────────────────────────────────────────────────────── */