# Phase 2B: Form Layout (Fullscreen Login) **Date:** 2026-05-02 **Status:** Spec, awaiting review **Surface:** Browser extension fullscreen vault UI (`extension/src/vault/`) **Parent spec:** `docs/superpowers/specs/2026-04-30-relicario-fullscreen-ux-redesign-design.md` (Section A) ## Goal Give the fullscreen login form a desktop-class layout: two-column field arrangement, sticky save bar, and a header that reflects dirty state and save shortcut. Other item types stay single-column for now. ## Non-goals - Two-column layout for `secure_note`, `identity`, `card`, `key`, `totp`, `document` — single-column stays. - Popup form changes — popup keeps its existing single-column layout. - New affordances — Phase 2A already shipped the 8 smart inputs. - Three-pane shell, keyboard nav, command palette — deferred to Phase 3. ## Layout ### Two-column grid (login only) ``` ┌────────────────────────────────────────────────────────────┐ │ ◀ new login ⌘+S to save │ │ unsaved · esc to cancel │ ├──────────────────────────┬─────────────────────────────────┤ │ IDENTITY │ CREDENTIALS │ │ title [required] │ username │ │ url + ⤓ │ password ⊙ ↻ │ │ group (autocomplete) │ strength: ████░ │ │ │ totp secret ◫ │ │ │ live: 492 837 · 23s │ ├──────────────────────────┴─────────────────────────────────┤ │ NOTES │ │ ▾ custom sections ▸ attachments │ ├────────────────────────────────────────────────────────────┤ │ STICKY SAVE BAR [cancel] [save] │ └────────────────────────────────────────────────────────────┘ ``` ### CSS rules - Form pane content: `max-width: 960px`, `margin: 0 auto`. - Two-column wrapper: `display: grid; grid-template-columns: 1fr 1fr; gap: 24px;`. - Below 720px viewport: `grid-template-columns: 1fr` (single column stack). Use a single `@media (max-width: 720px)` query. - Notes / custom sections / attachments live in a sibling block below the grid, full-width. ### Column assignment (login) **Left column — IDENTITY:** - title (required pill) - url + `⤓` fill-from-tab button + hostname chip below - group input + datalist autocomplete **Right column — CREDENTIALS:** - username - password + `⊙` reveal + `↻` generate; strength bar renders directly below the input - totp secret + `◫` QR button; live preview renders directly below the input **Full-width below grid:** - notes (with `≡` mono toggle) - custom sections / fields disclosure - attachments disclosure The strength bar and TOTP preview already render inline in Phase 2A — no changes needed beyond ensuring they fit within the column width. ### Section headers Each column gets a small uppercase section header per the parent spec's typography rules: - `text-transform: uppercase; letter-spacing: 1px; font-weight: 500;` - 1px bottom border in `var(--border-subtle)`. - Color: `var(--text-muted)`. ## Sticky save bar - Position: `sticky; bottom: 0;` inside the form pane's scroll container. - Background: `var(--bg-pane)` with a 24px gradient fade above (`linear-gradient(to top, var(--bg-pane) 60%, transparent)`). - Content: right-aligned `[cancel] [save]` buttons with 12px gap. - The save button reflects validity state — disabled when required fields are empty. - z-index: above form content, below modals/toasts. The fade ensures content scrolling behind the bar stays visible without a hard cutoff. ## Header treatment - Title (left): `new login` or `edit login`, body font, weight 500, size 18px. - Subtitle (left, below title): one of: - `unsaved · esc to cancel` when dirty - `no changes` when pristine - color: `var(--text-muted)`, size 12px. - Hint (right): `⌘+S to save` (visual only, not a button), `var(--text-dim)`, size 12px. On non-mac, render `Ctrl+S`. - Popout-to-tab `⤴` button: removed from fullscreen header (already done in Phase 1 visual baseline). The dirty/pristine state is tracked by existing form state. Phase 2B adds a small subscriber that updates the subtitle text on each input change. No new state machine — just a derived boolean. ## Other item types Single-column layout stays for `secure_note`, `identity`, `card`, `key`, `totp`, `document`. These types still get the new sticky save bar and header treatment. Only the column grid is login-specific. ## Files touched | File | Change | |------|--------| | `extension/src/vault/vault.css` | Add `.form-grid`, `.form-section-header`, `.sticky-save-bar`, `.form-header` styles + 720px media query | | `extension/src/popup/components/types/login.ts` | Wrap fields into Identity / Credentials column wrappers when rendered into the fullscreen surface | | `extension/src/vault/vault.ts` | Wire dirty-state subscriber to header subtitle; render header treatment + sticky bar | | `extension/src/vault/__tests__/` | Tests for two-column rendering, dirty subtitle transitions, sticky bar visibility | The login renderer needs to know which surface it's rendering into (popup vs fullscreen). The simplest approach: add an optional `surface: 'popup' | 'fullscreen'` parameter to `renderForm()`. Default to `popup` to preserve existing behavior. ## Testing Per-area tests using existing `vitest` + `happy-dom` setup: 1. **Layout test:** mount login form with `surface: 'fullscreen'`, assert grid layout is applied and Identity/Credentials columns contain the expected fields. 2. **Stack-down test:** simulate viewport ≤720px, assert single-column layout. 3. **Dirty subtitle test:** mount form, simulate input, assert subtitle changes from `no changes` → `unsaved · esc to cancel`. Assert reversion on reset. 4. **Sticky bar test:** assert save bar exists, has correct position style, and save button respects validity. 5. **Other-type non-regression:** mount `secure_note`, assert single-column layout (no grid). No e2e infrastructure changes — manual QA with the rebuilt extension loaded in Chrome. ## CLI parity This phase is purely visual / layout-shaped. No CLI counterpart. The CLI already accepts all login fields as flags (`--title`, `--username`, `--password`, etc.), which is its own form surface. ## Out of scope / deferred - Two-column layout for non-login types (could come in a future phase; current single-column works fine for forms with fewer fields). - Custom column-width adjustment by the user (drag divider). Fixed 1fr 1fr for now. - Animated transitions on subtitle text change (just snap). - Keyboard shortcut to actually save with ⌘+S — that arrives with Phase 3 keymap. The hint is purely a visual label until then. - Diff view ("you changed 3 fields") — future enhancement.