# Phase 2B: Polish Foundation + Form Layout

**Date:** 2026-05-02
**Status:** Spec, awaiting review
**Surface:** Browser extension — popup, fullscreen vault, setup wizard
**Parent spec:** `docs/superpowers/specs/2026-04-30-relicario-fullscreen-ux-redesign-design.md`

## Goal

Bring the extension up to a "professional, contained" feel — like opening 1Password or another polished password manager — without losing the terminal-monospace soul. Three surfaces (login popup, setup wizard, fullscreen vault) all get the same polish vocabulary applied. Phase 2B also lands the two-column login form layout from the parent spec.

## What changed from the original Phase 2B scope

The original Phase 2B was scoped to form layout only. After visual review, we expanded scope to include:

- A **patina** palette shift — gold accent dialed from bright `#d2ab43` toward weathered `#a88a4a`/`#cdb47a`/`#5a3f12`. Red theca dialed from saturated `#9a1a1a` toward brick `#7d2622`.
- **Logo update** — same composition, patina palette, translucent gradient gem.
- **Polish vocabulary** — backdrop with subtle radial glow + 18px grid texture, glass cards (translucent panels with backdrop-blur), refined typography lockup, primary/secondary button hierarchy.
- **Arrow glyph** — `▸` (U+25B8) for "next" buttons, matching the `▾`/`▸` disclosure glyphs already in use.

These items now ship together so the form layout lands inside an already-polished surface, rather than as a layout change inside flat CSS.

## Non-goals

- Three-pane shell, keyboard nav, command palette — deferred to Phase 3.
- New affordances — Phase 2A already shipped the 8 smart inputs.
- Light theme — single dark theme stays.
- Mobile/narrow layouts under 720px — popup handles narrow.
- Animated transitions / motion — focus state is the only transition.
- Item types other than `login` getting a two-column treatment.

## Visual language

The polish vocabulary lives in `extension/src/popup/styles.css` and `extension/src/vault/vault.css`. Both files share token definitions and class names where possible.

### Palette (patina)

```css
:root {
  /* Patina gold — replaces the bright amber */
  --gold-base:    #a88a4a;          /* base, less yellow / more bronze */
  --gold-mid:     #cdb47a;          /* duller mid-highlight */
  --gold-shadow:  #5a3f12;          /* deeper bronze shadow */
  --gold-text:    #c9a868;          /* legible on dark, brand text */
  --gold-soft:    rgba(184,149,86,0.14);   /* hover/active fill */
  --gold-ring:    rgba(184,149,86,0.18);   /* focus ring */
  --gold-stroke:  #b89556;          /* default border on emphasized elements */

  /* Surface — slightly deeper than current bg */
  --bg-base:      #0a0e14;          /* page (was #0d1117) */
  --bg-pane:      #11161e;          /* slightly elevated surface */
  --bg-card:      rgba(22, 27, 34, 0.55);  /* glass card fill */
  --bg-input:     #0a0e14;          /* matches base for sunken feel */

  /* Borders */
  --border-soft:  rgba(255,255,255,0.05);   /* card edges */
  --border-mid:   #262d36;          /* input borders */
  --border-warm:  #2a3140;          /* slightly warmer for vault.css */

  /* Text */
  --text:         #c9d1d9;
  --text-muted:   #8b949e;
  --text-dim:     #6b7888;
}
```

The bright accent token `--accent: #d2ab43` is renamed to `--gold-base: #a88a4a`. Aliases keep existing component code working during the migration (`--accent: var(--gold-base)`).

### Backdrop

A reusable backdrop applied to popup body, setup wizard body, and the vault shell:

```css
.surface-backdrop {
  position: relative;
  background:
    radial-gradient(ellipse 700px 240px at 50% -40px, rgba(184,149,86,0.05), transparent 65%),
    linear-gradient(180deg, #11161e 0%, #0a0e14 100%);
}
.surface-backdrop::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,0.012) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.012) 1px, transparent 1px);
  background-size: 18px 18px;
  pointer-events: none;
}
.surface-backdrop > * { position: relative; z-index: 1; }
```

The radial top-glow opacity is intentionally low (`0.05`) so it doesn't wash out on cheaper monitors. The grid texture is barely visible (`0.012` white) — adds a sense of "place" without becoming busy.

### Glass card

Used for the unlock card, setup step card, mode-picker cards, and form section cards (Identity / Credentials):

```css
.glass {
  background: rgba(22, 27, 34, 0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,0.05);
  border-radius: 10px;
  box-shadow:
    0 1px 0 rgba(255,255,255,0.03) inset,
    0 6px 18px rgba(0,0,0,0.35);
}
```

Browsers without `backdrop-filter` support fall back gracefully — the card stays semi-translucent over the backdrop without the blur.

### Buttons

Two clear tiers:

```css
.btn-primary {
  background: var(--gold-base);
  color: var(--bg-base);
  border: none;
  padding: 9px 14px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  letter-spacing: 0.3px;
}
.btn-primary:hover { background: #c9a868; }

.btn-secondary {
  background: transparent;
  border: 1px solid rgba(255,255,255,0.06);
  color: var(--text-muted);
  padding: 6px 12px;
  font-size: 11px;
  border-radius: 5px;
}
```

Existing `.btn` class keeps existing styling for backwards compatibility; new `.btn-primary` / `.btn-secondary` are used in updated views.

### Typography lockup

Logo + brand + tagline group with tighter spacing on login and setup:

- Logo mark: 40-44px square, 9-10px corner radius, inner highlight only (no outer glow).
- Brand text: weight 600, color `var(--gold-text)`, letter-spacing 0.5px.
- Tagline: 11px, `var(--text-dim)`, letter-spacing 0.3px.

### Inputs

```css
.input {
  background: var(--bg-input);
  border: 1px solid var(--border-mid);
  color: var(--text);
  padding: 9px 10px;
  border-radius: 6px;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.input:focus {
  outline: none;
  border-color: var(--gold-stroke);
  box-shadow: 0 0 0 2px var(--gold-ring);
}
```

### Arrow glyph

The `▸` (U+25B8, small right triangle) replaces ASCII `→` in "next" buttons. Reuses the existing disclosure-glyph vocabulary already used in `▾ custom sections` / `▸ attachments`.

## Logo update

`extension/icons/relicario-logo.svg` and `extension/icons/relicario-logo-16.svg` updated:

- Gold gradient stops shifted: `#d2ab43 → #f5d97a → #7c5719` becomes `#a88a4a → #cdb47a → #5a3f12`.
- Red theca radial: `#9a1a1a → #3a0a0a` becomes `#7d2622 → #2c0d0a`.
- Highlight gradient: `#fde9a8 → #d2ab43` becomes `#dac8a0 → #a88a4a`.
- Solid gold tones (`#7c5719`, `#fff3cf`, `#8a5e1c`) remapped to patina equivalents.
- Center asterisk gem now translucent: facets use vertical gradients (`gemFacetLight` / `gemFacetDark`) that fade to transparent at the tip; gem core uses a radial glass gradient (`gemCore`); two refraction highlights replace the single white-yellow dot.

The composition (pedestal, theca, gem, hinge collar, fleur-de-lis) is unchanged.

## Surface-by-surface changes

### Login popup (`extension/src/popup/`)

`unlock.ts` view:

```
┌──────────────────────────────────┐
│      [logo]                       │
│      Relicario                    │
│      two-factor vault             │
│                                   │
│  ┌─[ glass card ]──────────────┐  │
│  │ UNLOCK                       │  │
│  │ [passphrase input        ]   │  │
│  │ [   unlock vault          ]  │  │ ← btn-primary, full width
│  └──────────────────────────────┘  │
│                                   │
│      [open vault] [settings]      │ ← btn-secondary, demoted
└──────────────────────────────────┘
```

- Body gets `.surface-backdrop`.
- Logo lockup grouped (logo / brand / tagline) with tighter spacing (8-12px between).
- Form moves into `.glass` card with `UNLOCK` label inside.
- Primary action is a real button ("unlock vault") — replaces the "press Enter to submit" implicit flow.
- Open-vault and settings demoted to secondary buttons below the card.

### Setup wizard (`extension/src/setup/`)

- Body gets `.surface-backdrop`.
- Header lockup at top (logo + "Relicario vault setup").
- Progress dots get a tiny shadow on the current step (`box-shadow: 0 0 4px rgba(184,149,86,0.4)`).
- Each `wizard-step` becomes a `.glass` card.
- Mode-picker cards become smaller `.glass` cards with patina active state.
- All "next" buttons use `▸` glyph.

### Fullscreen vault (`extension/src/vault/`)

- Body gets `.surface-backdrop`.
- Form section panels (Identity, Credentials) are `.glass` cards.
- Save bar matches glass treatment with translucent fill + backdrop-blur.
- Form layout switches to two-column for login (see below).

## Form layout (login, fullscreen only)

The original Phase 2B scope:

```
┌────────────────────────────────────────────────────────────┐
│ edit login                              ⌘+S to save        │
│ unsaved · esc to cancel                                    │
├──────────────────────────┬─────────────────────────────────┤
│ [ glass: IDENTITY ]      │ [ glass: CREDENTIALS ]          │
│   title  [required]      │   username                      │
│   url + ⤓                │   password ⊙ ↻                  │
│   group (autocomplete)   │     strength: ████░             │
│                          │   totp secret ◫                 │
│                          │     live: 492 837 · 23s         │
├──────────────────────────┴─────────────────────────────────┤
│ NOTES                                                       │
│ ▾ custom sections    ▸ attachments                          │
├────────────────────────────────────────────────────────────┤
│  STICKY SAVE BAR              [cancel] [save]              │
└────────────────────────────────────────────────────────────┘
```

### Layout 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).
- 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 below the input
- totp secret + `◫` QR button; live preview below the input

**Full-width below grid:**
- notes (with `≡` mono toggle)
- custom sections / fields disclosure
- attachments disclosure

### Sticky save bar

- `position: sticky; bottom: 0;` inside the form pane scroll container.
- Translucent fill matching the glass vocabulary, with a 24px gradient fade above (content scrolls under).
- Right-aligned `[cancel] [save]` buttons.
- Save button reflects validity state — disabled when required fields are empty.

### Header treatment

- Title (left): `new login` / `edit login`, weight 500, size 18px.
- Subtitle (left, below title): `unsaved · esc to cancel` (dirty) or `no changes` (pristine), `var(--text-muted)`, size 12px.
- Hint (right): `⌘+S to save` (visual only — actual save shortcut arrives in Phase 3 keymap), `var(--text-dim)`, size 12px. Renders `Ctrl+S` on non-mac.
- Popout-to-tab `⤴` removed from fullscreen forms (already done in Phase 1).

### Other item types

Single-column stays for `secure_note`, `identity`, `card`, `key`, `totp`, `document`. They still get the new glass-card treatment around the form section, sticky save bar, and header treatment — only the column grid is login-specific.

## Files touched

| File | Change |
|------|--------|
| `extension/icons/relicario-logo.svg` | Patina palette + gradient glass gem |
| `extension/icons/relicario-logo-16.svg` | Patina palette (toolbar size) |
| `extension/src/popup/styles.css` | Patina tokens, `.surface-backdrop`, `.glass`, `.btn-primary/secondary` |
| `extension/src/popup/components/unlock.ts` | Logo lockup, glass card, primary unlock button |
| `extension/src/popup/components/types/login.ts` | Add `surface: 'popup' \| 'fullscreen'` param; column wrapping when fullscreen |
| `extension/src/setup/setup.ts` | `.surface-backdrop`, glass step cards, glass mode-picker cards, `▸` arrows |
| `extension/src/setup/setup.html` | Body wrapper class |
| `extension/src/vault/vault.css` | Patina tokens, glass form sections, form-grid, sticky save bar, header treatment |
| `extension/src/vault/vault.ts` | Header subtitle dirty-state subscriber, surface flag passed to login renderer |
| `extension/src/vault/components/*.ts` | Glass class on form panels |

The login renderer needs to know which surface it's rendering into (popup vs fullscreen). 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. **Palette migration test:** computed style on `.btn-primary` resolves to `#a88a4a`.
2. **Layout test:** mount login form with `surface: 'fullscreen'`, assert grid layout, Identity / Credentials columns contain expected fields.
3. **Stack-down test:** simulate viewport ≤720px, assert single-column.
4. **Dirty subtitle test:** mount form, simulate input, assert subtitle text changes.
5. **Sticky bar test:** assert save bar exists, position style, save button validity.
6. **Glass class application:** unlock card, setup step card, form panels all get `.glass` class.
7. **Arrow glyph test:** all "next" buttons render `▸` (no `→`).
8. **Other-type non-regression:** mount `secure_note`, assert single-column layout.
9. **Logo regression:** snapshot test on `relicario-logo.svg` defs/colors.

Manual QA pass per surface with the rebuilt extension loaded in Chrome and Firefox.

## 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.).

## Out of scope / deferred

- Two-column layout for non-login types.
- User-resizable column widths.
- Animated transitions on subtitle text change (snap is fine).
- Functional ⌘+S keyboard shortcut — arrives with Phase 3 keymap. The hint is a visual label until then.
- Diff view / form-level "you changed N fields" indicator.
- Light theme.
