docs(spec): expand Phase 2B to polish foundation + form layout
Bundles patina palette shift, logo update (translucent gradient gem), glass-card vocabulary across login/setup/fullscreen, and the original two-column form layout. Updates relicario-logo.svg and -16.svg to the patina palette. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,31 +1,241 @@
|
||||
# Phase 2B: Form Layout (Fullscreen Login)
|
||||
# Phase 2B: Polish Foundation + Form Layout
|
||||
|
||||
**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)
|
||||
**Surface:** Browser extension — popup, fullscreen vault, setup wizard
|
||||
**Parent spec:** `docs/superpowers/specs/2026-04-30-relicario-fullscreen-ux-redesign-design.md`
|
||||
|
||||
## 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.
|
||||
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
|
||||
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
## Layout
|
||||
## Visual language
|
||||
|
||||
### Two-column grid (login only)
|
||||
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:
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ ◀ new login ⌘+S to save │
|
||||
│ edit login ⌘+S to save │
|
||||
│ unsaved · esc to cancel │
|
||||
├──────────────────────────┬─────────────────────────────────┤
|
||||
│ IDENTITY │ CREDENTIALS │
|
||||
│ [ glass: IDENTITY ] │ [ glass: CREDENTIALS ] │
|
||||
│ title [required] │ username │
|
||||
│ url + ⤓ │ password ⊙ ↻ │
|
||||
│ group (autocomplete) │ strength: ████░ │
|
||||
@@ -39,11 +249,11 @@ Give the fullscreen login form a desktop-class layout: two-column field arrangem
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### CSS rules
|
||||
### 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). Use a single `@media (max-width: 720px)` query.
|
||||
- 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)
|
||||
@@ -55,80 +265,74 @@ Give the fullscreen login form a desktop-class layout: two-column field arrangem
|
||||
|
||||
**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
|
||||
- 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
|
||||
|
||||
The strength bar and TOTP preview already render inline in Phase 2A — no changes needed beyond ensuring they fit within the column width.
|
||||
### Sticky save bar
|
||||
|
||||
### Section headers
|
||||
- `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.
|
||||
|
||||
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)`.
|
||||
### Header treatment
|
||||
|
||||
## Sticky save bar
|
||||
- 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).
|
||||
|
||||
- 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.
|
||||
### Other item types
|
||||
|
||||
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.
|
||||
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/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 |
|
||||
| `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). The simplest approach: add an optional `surface: 'popup' | 'fullscreen'` parameter to `renderForm()`. Default to `popup` to preserve existing behavior.
|
||||
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. **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).
|
||||
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.
|
||||
|
||||
No e2e infrastructure changes — manual QA with the rebuilt extension loaded in Chrome.
|
||||
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.), which is its own form surface.
|
||||
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 (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.
|
||||
- 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.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none">
|
||||
<defs>
|
||||
<radialGradient id="redThecaSm" cx="0.4" cy="0.35">
|
||||
<stop offset="0%" stop-color="#9a1a1a"/>
|
||||
<stop offset="100%" stop-color="#3a0a0a"/>
|
||||
<stop offset="0%" stop-color="#7d2622"/>
|
||||
<stop offset="100%" stop-color="#2c0d0a"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="goldRingSm" x1="0" x2="1">
|
||||
<stop offset="0%" stop-color="#d2ab43"/>
|
||||
<stop offset="50%" stop-color="#f5d97a"/>
|
||||
<stop offset="100%" stop-color="#7c5719"/>
|
||||
<stop offset="0%" stop-color="#a88a4a"/>
|
||||
<stop offset="50%" stop-color="#cdb47a"/>
|
||||
<stop offset="100%" stop-color="#5a3f12"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
<circle cx="8" cy="9" r="6.5" fill="url(#goldRingSm)"/>
|
||||
<circle cx="8" cy="9" r="4.8" fill="url(#redThecaSm)"/>
|
||||
|
||||
<!-- Asterisk-as-3-bars -->
|
||||
<g transform="translate(8, 9)" stroke="#f5d97a" stroke-width="1.2" stroke-linecap="round">
|
||||
<!-- Asterisk-as-3-bars (translucent) -->
|
||||
<g transform="translate(8, 9)" stroke="#dac8a0" stroke-width="1.2" stroke-linecap="round" stroke-opacity="0.8">
|
||||
<line x1="0" y1="-3" x2="0" y2="3"/>
|
||||
<line x1="-2.6" y1="-1.5" x2="2.6" y2="1.5"/>
|
||||
<line x1="-2.6" y1="1.5" x2="2.6" y2="-1.5"/>
|
||||
</g>
|
||||
<circle cx="8" cy="9" r="0.7" fill="#fff3cf"/>
|
||||
<circle cx="8" cy="9" r="0.7" fill="#dac8a0"/>
|
||||
|
||||
<!-- Fleur (3 tips) -->
|
||||
<path d="M 8 0 L 7.2 2.5 L 8.8 2.5 Z" fill="url(#goldRingSm)"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -1,79 +1,93 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 240" fill="none">
|
||||
<defs>
|
||||
<radialGradient id="redTheca" cx="0.4" cy="0.35">
|
||||
<stop offset="0%" stop-color="#9a1a1a"/>
|
||||
<stop offset="100%" stop-color="#3a0a0a"/>
|
||||
<stop offset="0%" stop-color="#7d2622"/>
|
||||
<stop offset="100%" stop-color="#2c0d0a"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="goldRing" x1="0" x2="1">
|
||||
<stop offset="0%" stop-color="#d2ab43"/>
|
||||
<stop offset="50%" stop-color="#f5d97a"/>
|
||||
<stop offset="100%" stop-color="#7c5719"/>
|
||||
<stop offset="0%" stop-color="#a88a4a"/>
|
||||
<stop offset="50%" stop-color="#cdb47a"/>
|
||||
<stop offset="100%" stop-color="#5a3f12"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="goldHi" x1="0" x2="1">
|
||||
<stop offset="0%" stop-color="#fde9a8"/>
|
||||
<stop offset="100%" stop-color="#d2ab43"/>
|
||||
<stop offset="0%" stop-color="#dac8a0"/>
|
||||
<stop offset="100%" stop-color="#a88a4a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gemFacetLight" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#dac8a0" stop-opacity="0.8"/>
|
||||
<stop offset="100%" stop-color="#cdb47a" stop-opacity="0.3"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gemFacetDark" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#6e4d18" stop-opacity="0.7"/>
|
||||
<stop offset="100%" stop-color="#5a3f12" stop-opacity="0.25"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="gemCore" cx="0.4" cy="0.35">
|
||||
<stop offset="0%" stop-color="#dac8a0" stop-opacity="0.85"/>
|
||||
<stop offset="60%" stop-color="#b89556" stop-opacity="0.4"/>
|
||||
<stop offset="100%" stop-color="#7d2622" stop-opacity="0.2"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Pedestal (compact) -->
|
||||
<!-- Pedestal -->
|
||||
<ellipse cx="110" cy="226" rx="44" ry="5" fill="url(#goldRing)"/>
|
||||
<rect x="78" y="212" width="64" height="14" rx="2" fill="url(#goldRing)"/>
|
||||
<rect x="98" y="202" width="24" height="12" fill="url(#goldRing)"/>
|
||||
<ellipse cx="110" cy="208" rx="14" ry="3" fill="#7c5719"/>
|
||||
<ellipse cx="110" cy="208" rx="14" ry="3" fill="#5a3f12"/>
|
||||
<ellipse cx="110" cy="202" rx="18" ry="4" fill="url(#goldRing)"/>
|
||||
|
||||
<!-- Body, bezel, theca -->
|
||||
<circle cx="110" cy="130" r="72" fill="url(#goldRing)"/>
|
||||
<path d="M 110 58 A 72 72 0 0 0 38 130" stroke="#fde9a8" stroke-width="2" fill="none" opacity="0.6"/>
|
||||
<circle cx="110" cy="130" r="60" fill="#7c5719"/>
|
||||
<path d="M 110 58 A 72 72 0 0 0 38 130" stroke="#dac8a0" stroke-width="2" fill="none" opacity="0.5"/>
|
||||
<circle cx="110" cy="130" r="60" fill="#5a3f12"/>
|
||||
<circle cx="110" cy="130" r="56" fill="url(#redTheca)"/>
|
||||
<ellipse cx="86" cy="108" rx="16" ry="7" fill="#ffffff" opacity="0.14" transform="rotate(-30 86 108)"/>
|
||||
<ellipse cx="86" cy="108" rx="16" ry="7" fill="#ffffff" opacity="0.10" transform="rotate(-30 86 108)"/>
|
||||
|
||||
<!-- Asterisk gem with pinwheel facets -->
|
||||
<!-- Asterisk gem with translucent gradient facets -->
|
||||
<g transform="translate(110, 130)">
|
||||
<g transform="rotate(0)">
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="#f5d97a"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="#8a5e1c"/>
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="url(#gemFacetLight)"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="url(#gemFacetDark)"/>
|
||||
</g>
|
||||
<g transform="rotate(60)">
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="#f5d97a"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="#8a5e1c"/>
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="url(#gemFacetLight)"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="url(#gemFacetDark)"/>
|
||||
</g>
|
||||
<g transform="rotate(120)">
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="#f5d97a"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="#8a5e1c"/>
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="url(#gemFacetLight)"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="url(#gemFacetDark)"/>
|
||||
</g>
|
||||
<g transform="rotate(180)">
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="#f5d97a"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="#8a5e1c"/>
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="url(#gemFacetLight)"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="url(#gemFacetDark)"/>
|
||||
</g>
|
||||
<g transform="rotate(240)">
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="#f5d97a"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="#8a5e1c"/>
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="url(#gemFacetLight)"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="url(#gemFacetDark)"/>
|
||||
</g>
|
||||
<g transform="rotate(300)">
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="#f5d97a"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="#8a5e1c"/>
|
||||
<path d="M 0 0 L -4.5 -3.5 C -5.5 -16, -3.5 -29, 0 -36 Z" fill="url(#gemFacetLight)"/>
|
||||
<path d="M 0 0 L 4.5 -3.5 C 5.5 -16, 3.5 -29, 0 -36 Z" fill="url(#gemFacetDark)"/>
|
||||
</g>
|
||||
<polygon points="0,-6 5.2,-3 5.2,3 0,6 -5.2,3 -5.2,-3" fill="#d2ab43" stroke="#7c5719" stroke-width="0.6"/>
|
||||
<circle cx="-1.5" cy="-2" r="1.4" fill="#fff3cf"/>
|
||||
<polygon points="0,-6 5.2,-3 5.2,3 0,6 -5.2,3 -5.2,-3" fill="url(#gemCore)" stroke="#5a3f12" stroke-width="0.5" stroke-opacity="0.6"/>
|
||||
<circle cx="-1.8" cy="-2.2" r="1.6" fill="#dac8a0" opacity="0.95"/>
|
||||
<circle cx="1.5" cy="2" r="0.6" fill="#dac8a0" opacity="0.5"/>
|
||||
</g>
|
||||
|
||||
<!-- Hinge collar -->
|
||||
<rect x="98" y="50" width="24" height="10" rx="2" fill="url(#goldRing)"/>
|
||||
<line x1="100" y1="55" x2="120" y2="55" stroke="#7c5719" stroke-width="0.8"/>
|
||||
<line x1="100" y1="55" x2="120" y2="55" stroke="#5a3f12" stroke-width="0.8"/>
|
||||
|
||||
<!-- Fleur-de-lis -->
|
||||
<g transform="translate(110, 50)">
|
||||
<rect x="-3.5" y="-12" width="7" height="12" fill="url(#goldRing)"/>
|
||||
<rect x="-16" y="-18" width="32" height="7" rx="1.5" fill="url(#goldRing)"/>
|
||||
<rect x="-3" y="-19" width="6" height="9" rx="0.8" fill="#7c5719"/>
|
||||
<rect x="-3" y="-19" width="6" height="9" rx="0.8" fill="#5a3f12"/>
|
||||
<path d="M 0 -18 Q -8 -36, -4 -54 Q -1 -62, 0 -64 Q 1 -62, 4 -54 Q 8 -36, 0 -18 Z" fill="url(#goldRing)"/>
|
||||
<path d="M 0 -22 Q -2.5 -36, 0 -52 Q 2.5 -36, 0 -22 Z" fill="#7c5719" opacity="0.55"/>
|
||||
<path d="M 0 -22 Q -2.5 -36, 0 -52 Q 2.5 -36, 0 -22 Z" fill="#5a3f12" opacity="0.55"/>
|
||||
<circle cx="0" cy="-66" r="2.5" fill="url(#goldHi)"/>
|
||||
<path d="M -4 -18 Q -22 -22, -26 -38 Q -22 -50, -16 -50 Q -16 -38, -10 -32 Q -6 -28, -4 -28 Z" fill="url(#goldRing)"/>
|
||||
<ellipse cx="-25" cy="-44" rx="2" ry="3" fill="#7c5719" opacity="0.4" transform="rotate(-20 -25 -44)"/>
|
||||
<ellipse cx="-25" cy="-44" rx="2" ry="3" fill="#5a3f12" opacity="0.4" transform="rotate(-20 -25 -44)"/>
|
||||
<path d="M 4 -18 Q 22 -22, 26 -38 Q 22 -50, 16 -50 Q 16 -38, 10 -32 Q 6 -28, 4 -28 Z" fill="url(#goldRing)"/>
|
||||
<ellipse cx="25" cy="-44" rx="2" ry="3" fill="#7c5719" opacity="0.4" transform="rotate(20 25 -44)"/>
|
||||
<ellipse cx="25" cy="-44" rx="2" ry="3" fill="#5a3f12" opacity="0.4" transform="rotate(20 25 -44)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 5.0 KiB |
Reference in New Issue
Block a user