docs(14): UI design contract

This commit is contained in:
Arthur Belleville 2026-05-16 18:48:32 +02:00
parent 0d49c20e42
commit 848f7480a8
No known key found for this signature in database

View file

@ -44,6 +44,8 @@ AuthLayout replaces `@Layout(...)` for both `/login` and `/signup`. It renders a
| Card glow | `.card-glow` | `background: var(--gradient-card-glow); border-radius: 1rem; filter: blur(24px); position: absolute; inset: 0; z-index: -1` — decorative only |
| Card shell | `.auth-card-shell` | `backdrop-filter: blur(12px); background: var(--color-surface-card); border: 1px solid var(--color-border-default); border-radius: 1rem; box-shadow: var(--shadow-auth-card); padding: 1.25rem; position: relative` |
Note on `.auth-card-shell` padding: `1.25rem` (20px) is ported verbatim from the go-backend reference as a port-fidelity constraint. It is not a design system spacing token and does not appear in the Spacing Scale table.
**Background gradient for `.login-screen`:** use `var(--gradient-shell)` which resolves to:
```
linear-gradient(135deg, var(--overlay-brand-muted), transparent 30%),
@ -59,7 +61,7 @@ This is already defined as a token in `base.css`. Do not hardcode color stops.
```
1. .auth-card-topbar — (empty in Phase 14; reserved placeholder div, no back-link or theme toggle)
2. .brand-header — logo image: <img src="/static/logo_dark.png" class="brand-logo" alt="Xtablo">
3. .title-group — <h1> page title
3. .title-group — <h1> page title ← PRIMARY VISUAL ANCHOR (brand logo + h1 together)
4. .auth-body — wraps: Google button → divider → form → nav link
├── Google button (.gsi-material-button as <a> or <button>)
├── Divider (.divider-row → .divider-line + .divider-pill + .divider-line)
@ -67,6 +69,8 @@ This is already defined as a token in `base.css`. Do not hardcode color stops.
└── Nav link (.signup-copy + .signup-link)
```
The `.brand-header` (logo image) and `.title-group` (`<h1>`) together form the **primary visual anchor** of the auth card. They are the first elements a user sees and establish brand identity before interacting with the form.
**Source:** D-AC02; go-backend `AuthScreen` templ + `auth_components.templ` structure; D-AB04 (AnimatedBackground separate component).
---
@ -114,29 +118,26 @@ Multiples of 4 only. All values from existing token usage in go-backend auth CSS
| sm | 8px | AnimatedBackground element gaps; `.auth-provider-stack` gap |
| md | 16px | `.auth-body` flex gap; auth-provider separator margin |
| lg | 24px | `.auth-card-topbar` margin-bottom; `.title-group` margin-bottom; `.brand-header` margin-bottom |
| xl | 32px | |
| xl | 32px | `.login-screen` padding |
| 2xl | 48px | — |
| card-padding | 20px (1.25rem) | `.auth-card-shell` padding — exception to 4pt grid, matches reference exactly |
| screen-padding | 32px (2rem 1rem) | `.login-screen` padding |
Exceptions: card-padding at 20px (1.25rem) — matches go-backend reference; screen horizontal padding at 16px (1rem).
**Out-of-grid values (not tokens):** `.auth-card-shell` padding is `1.25rem` (20px) — ported verbatim from go-backend as a port-fidelity constraint; see Page Structure Contract. Screen horizontal padding is `1rem` (16px) which falls on the grid.
---
## Typography
| Role | Size | Weight | Line Height | Usage |
| Role | Size | Weight | Line Height | Notes |
|------|------|--------|-------------|-------|
| Auth heading | clamp(1.5rem, 4vw, 1.875rem) | 700 | 1.2 | `.title-group h1` — page title ("Sign in to Xtablo", "Create your account") |
| Body / label | 14px (0.875rem) | 500 | 1.4 | Field labels, divider pill text, nav link copy |
| Small / muted | 14px (0.875rem) | 400 | 1.4 | `.signup-copy` nav link paragraph |
| Google button | 14px (Roboto), letter-spacing 0.25px | 500 | — | `.gsi-material-button-contents` only |
| Auth heading | clamp(1.5rem, 4vw, 1.875rem) | 700 | 1.2 | `.title-group h1` — "Sign in to Xtablo", "Create your account" |
| Body | 14px (0.875rem) | 400 | 1.4 | Field labels, divider pill text, nav link copy, `.signup-copy` muted paragraph |
| Google button label | 14px (0.875rem) | 500 | — | `.gsi-material-button-contents` only — Material Design spec; `font-family: "Roboto", Arial, sans-serif; letter-spacing: 0.25px`; must not propagate outside `.gsi-material-button` |
**Rules:**
- 3 effective sizes: `clamp(1.5rem1.875rem)` for heading, `0.875rem` for supporting text, `14px` for Google button label.
- 2 weights: 400 (regular) and 500/700 (semibold/bold) — heading uses 700, labels and links use 500, muted copy uses 400.
- 2 weights for page-authored elements: **400** (regular) and **700** (bold). Weight 500 is used only inside `.gsi-material-button-contents` per the Material Design Google Sign-In specification.
- 2 effective sizes for page-authored elements: `clamp(1.5rem1.875rem)` for the heading, `0.875rem` for all supporting text.
- Body font: inherited from `base.css` (`ui-sans-serif, system-ui, -apple-system, ...`).
- Google button font: `"Roboto", Arial, sans-serif` scoped to `.gsi-material-button` only.
- The scoped exception for the Google button (`font-family: "Roboto"`, `font-weight: 500`, `letter-spacing: 0.25px`) is contained entirely within the `.gsi-material-button` CSS block and does not propagate to any other element.
**Source:** go-backend CSS `.title-group h1`, `.field-stack label`, `.signup-copy`, `.gsi-material-button-contents`.
@ -265,7 +266,7 @@ signup page below form:
|---------|------|
| Login page title | Sign in to Xtablo |
| Signup page title | Create your account |
| Login CTA (submit button) | Sign in |
| Login CTA (submit button) | Sign in to Xtablo |
| Signup CTA (submit button) | Create account |
| Google button label | Sign in with Google |
| Divider label | or |
@ -332,7 +333,7 @@ No empty state: auth pages always show the form. No destructive actions on these
| File | Action | What changes |
|------|--------|-------------|
| `backend/internal/web/ui/auth.css` | Replace entirely | Port full auth CSS from go-backend: `.login-screen`, `.background-layer`/`.background-logo`/sizing/opacity/position classes, all `animate-*` utilities, all `@keyframes`, `.auth-card-shell`, `.auth-card-topbar`, `.brand-header`, `.brand-logo`, `.title-group`, `.auth-body`, `.login-form` (replaced by `@ui.FormField` but keep for compat), `.divider-row`/`.divider-line`/`.divider-pill`, `.signup-copy`, `.signup-link`, `.gsi-material-button` and sub-classes, `.card-wrap`, `.card-glow`, `.status-slot`, `.status-banner`, `.status-success`, `.status-error` |
| `backend/internal/web/ui/auth.css` | Replace entirely | Port full auth CSS from go-backend: `.login-screen`, `.background-layer`/`.background-logo`/sizing/opacity/position classes, all `animate-*` utilities, all `@keyframes`, `.auth-card-shell` (padding: 1.25rem — ported verbatim from go-backend reference; not a design system spacing token), `.auth-card-topbar`, `.brand-header`, `.brand-logo`, `.title-group`, `.auth-body`, `.login-form` (replaced by `@ui.FormField` but keep for compat), `.divider-row`/`.divider-line`/`.divider-pill`, `.signup-copy`, `.signup-link`, `.gsi-material-button` and sub-classes, `.card-wrap`, `.card-glow`, `.status-slot`, `.status-banner`, `.status-success`, `.status-error` |
| `backend/tailwind.input.css` | No change | `auth.css` path is unchanged; import remains valid |
| `backend/internal/web/ui/base.css` | No change | All required tokens already defined |