47559c
feat: 12 pastel accent colors with full-surface propagation (v1.5.0)
- time
- 2026-04-23 21:05 UTC · 6 months ago
- machine
- koh2
- parent
- d94d9e
↓ peach-browser-47559c.tar.gzatlas at this save
files changed14 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/vault.ts+2 −1src/content/inject.ts+37 −24src/content/save.ts+11 −3src/popup/App.tsx+21 −5src/popup/components/Ring.tsx+1 −1src/popup/styles/popup.css+102 −70src/popup/styles/vars.css+5 −4src/popup/views/Add.tsx+15 −15src/popup/views/Settings.tsx+24 −4src/popup/views/contracts.test.tsx+4 −0src/shared/types.ts+17 −0manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "1.4.56",4+ "version": "1.5.0",55 "description": "Zero-knowledge password manager",66 "browser_specific_settings": {77 "gecko": {manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "1.4.56",4+ "version": "1.5.0",55 "description": "Zero-knowledge password manager",66 "action": {77 "default_popup": "src/popup/index.html",package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "1.4.56",3+ "version": "1.5.0",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/background/vault.ts+2 −1
@@ -1,6 +1,7 @@11 import { deriveKey, generateSalt } from "../crypto/argon2";22 import { extractDomain } from "../shared/domain";33 import type {4+ AccentColorName,45 LegacyVaultEntry,56 StoredVault,67 VaultEntry,@@ -45,7 +46,7 @@4546 // ---------------------------------------------------------------------------4647 4748 export interface VaultSettings {48- accentColor?: string;49+ accentColor?: AccentColorName;4950 theme?: "dark" | "light";5051 autoLockMinutes?: number;5152 clipboardClearSeconds?: number;src/content/inject.ts+37 −24
@@ -1,3 +1,11 @@1+import { ACCENT_COLORS } from "../shared/types";2+3+let accentHex = "#E8956D";4+chrome.runtime.sendMessage({ type: "GET_SETTINGS" }, (resp: { ok: boolean; data?: { accentColor?: string } } | undefined) => {5+ const name = resp?.data?.accentColor ?? "peach";6+ accentHex = ACCENT_COLORS.find(c => c.name === name)?.hex ?? "#E8956D";7+});8+19 export interface SelectorEntry {210 id: string;311 title: string;@@ -39,11 +47,11 @@3947 }4048 4149 function plusSvgStr(): string {42- return `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="rgba(217,104,48,0.8)" stroke-width="1.2" stroke-linecap="round"><path d="M6 1.5v9M1.5 6h9"/></svg>`;50+ return `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"><path d="M6 1.5v9M1.5 6h9"/></svg>`;4351 }4452 4553 function peachIconSvg(): string {46- return `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 64 64" fill="none" aria-hidden="true"><path d="M32 54C16 54 8 44 8 31C8 18 17 10 27 10C28 7 30 5.5 32 5.5C34 5.5 36 7 37 10C47 10 56 18 56 31C56 44 48 54 32 54Z" fill="#D96830"/><path d="M37 8.5C40.5 3.5 48 5 46 10.5C42 11 37 8.5 37 8.5Z" fill="#7B9060"/></svg>`;54+ return `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 64 64" fill="none" aria-hidden="true"><path d="M32 54C16 54 8 44 8 31C8 18 17 10 27 10C28 7 30 5.5 32 5.5C34 5.5 36 7 37 10C47 10 56 18 56 31C56 44 48 54 32 54Z" fill="${accentHex}"/><path d="M37 8.5C40.5 3.5 48 5 46 10.5C42 11 37 8.5 37 8.5Z" fill="#7B9060"/></svg>`;4755 }4856 4957 function genSvgStr(): string {@@ -77,6 +85,7 @@7785 ): void {7886 const host = document.createElement("div");7987 host.style.cssText = "position:fixed;bottom:22px;left:50%;transform:translateX(-50%);z-index:2147483647;pointer-events:auto;";88+ host.style.setProperty("--peach-accent", accentHex);8089 const shadow = host.attachShadow({ mode: "closed" });8190 8291 const style = document.createElement("style");@@ -92,9 +101,9 @@92101 .txt { font-size:11px;color:rgba(240,232,216,0.55);font-family:"IBM Plex Mono",monospace; }93102 .yes {94103 padding:5px 12px;border-radius:6px;border:none;cursor:pointer;font-size:11px;95- background:#D96830;color:#fff;transition:background 100ms;font-family:Inter,sans-serif;104+ background:var(--peach-accent);color:#fff;transition:background 100ms;font-family:Inter,sans-serif;96105 }97- .yes:hover { background:#c55e28; }106+ .yes:hover { background:color-mix(in srgb, var(--peach-accent) 82%, #000); }98107 .no {99108 padding:5px 10px;border-radius:6px;border:none;cursor:pointer;font-size:11px;100109 background:rgba(240,232,216,0.07);color:rgba(240,232,216,0.45);font-family:Inter,sans-serif;@@ -203,8 +212,8 @@203212 opacity: 0;204213 `;205214 button.addEventListener("mouseenter", () => {206- button.style.background = "rgba(217,104,48,0.12)";207- button.style.boxShadow = "0 0 0 1px rgba(217,104,48,0.18), 0 0 14px rgba(217,104,48,0.12)";215+ button.style.background = `color-mix(in srgb, ${accentHex} 12%, transparent)`;216+ button.style.boxShadow = `0 0 0 1px color-mix(in srgb, ${accentHex} 18%, transparent), 0 0 14px color-mix(in srgb, ${accentHex} 12%, transparent)`;208217 button.style.transform = "scale(1.08)";209218 });210219 button.addEventListener("mouseleave", () => {@@ -274,7 +283,7 @@274283 color: rgba(240,232,216,0.28); font-family: "IBM Plex Mono", monospace;275284 }276285 .domain-name {277- font-size: 10px; color: rgba(217,104,48,0.6);286+ font-size: 10px; color: color-mix(in srgb, var(--peach-accent) 60%, transparent);278287 font-family: "IBM Plex Mono", monospace;279288 }280289 @@ -291,8 +300,8 @@291300 transition: border-color 120ms, box-shadow 120ms;292301 }293302 .search:focus {294- border-color: rgba(217,104,48,0.4);295- box-shadow: 0 0 0 2px rgba(217,104,48,0.10);303+ border-color: color-mix(in srgb, var(--peach-accent) 40%, transparent);304+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--peach-accent) 10%, transparent);296305 }297306 .search::placeholder { color: rgba(240,232,216,0.2); }298307 @@ -308,10 +317,10 @@308317 }309318 .entry:last-child { border-bottom: none; }310319 .entry:hover { background: rgba(240,232,216,0.04); }311- .entry.focused { background: rgba(217,104,48,0.08); }320+ .entry.focused { background: color-mix(in srgb, var(--peach-accent) 8%, transparent); }312321 .entry.focused::before {313322 content: ""; position: absolute; left: 0; top: 3px; bottom: 3px;314- width: 2px; border-radius: 2px; background: rgba(217,104,48,0.55);323+ width: 2px; border-radius: 2px; background: color-mix(in srgb, var(--peach-accent) 55%, transparent);315324 }316325 317326 .entry-icon {@@ -322,7 +331,9 @@322331 }323332 .entry-icon img { width: 15px; height: 15px; border-radius: 2px; display: block; }324333 .entry-icon.is-new {325- background: rgba(217,104,48,0.08); border-color: rgba(217,104,48,0.15);334+ background: color-mix(in srgb, var(--peach-accent) 8%, transparent);335+ border-color: color-mix(in srgb, var(--peach-accent) 15%, transparent);336+ color: color-mix(in srgb, var(--peach-accent) 80%, transparent);326337 }327338 328339 .entry-info { flex: 1; min-width: 0; }@@ -331,7 +342,7 @@331342 white-space: nowrap; overflow: hidden; text-overflow: ellipsis;332343 line-height: 1.3;333344 }334- .entry-title.is-new { color: rgba(217,104,48,0.9); font-size: 12px; }345+ .entry-title.is-new { color: color-mix(in srgb, var(--peach-accent) 90%, transparent); font-size: 12px; }335346 .entry-sub {336347 font-size: 10px; color: rgba(240,232,216,0.32);337348 font-family: "IBM Plex Mono", monospace;@@ -341,8 +352,8 @@341352 342353 .totp-badge {343354 font-size: 8px; letter-spacing: 0.04em; padding: 2px 6px;344- border-radius: 4px; background: rgba(217,104,48,0.10);345- color: rgba(217,104,48,0.75); font-family: "IBM Plex Mono", monospace;355+ border-radius: 4px; background: color-mix(in srgb, var(--peach-accent) 10%, transparent);356+ color: color-mix(in srgb, var(--peach-accent) 75%, transparent); font-family: "IBM Plex Mono", monospace;346357 flex-shrink: 0; margin-left: 8px;347358 }348359 @@ -385,30 +396,31 @@385396 font-size: 11px; font-family: "IBM Plex Mono", monospace;386397 outline: none; width: 100%; transition: border-color 120ms, box-shadow 120ms;387398 }388- .f-input:focus { border-color: rgba(217,104,48,0.4); box-shadow: 0 0 0 2px rgba(217,104,48,0.10); }399+ .f-input:focus { border-color: color-mix(in srgb, var(--peach-accent) 40%, transparent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--peach-accent) 10%, transparent); }389400 .f-input::placeholder { color: rgba(240,232,216,0.18); }390401 .f-input.url-f { font-size: 10px; color: rgba(240,232,216,0.5); letter-spacing: 0.01em; }391402 .f-row { display: flex; gap: 6px; }392403 .f-row .f-input { flex: 1; min-width: 0; }393404 .gen-btn {394405 padding: 0 10px; border-radius: 7px; border: none;395- background: rgba(217,104,48,0.10); color: rgba(217,104,48,0.8);406+ background: color-mix(in srgb, var(--peach-accent) 10%, transparent);407+ color: color-mix(in srgb, var(--peach-accent) 80%, transparent);396408 font-size: 10px; font-family: "IBM Plex Mono", monospace;397409 cursor: pointer; white-space: nowrap; flex-shrink: 0;398410 display: flex; align-items: center; gap: 4px;399411 transition: background 100ms;400412 }401- .gen-btn:hover { background: rgba(217,104,48,0.18); }413+ .gen-btn:hover { background: color-mix(in srgb, var(--peach-accent) 18%, transparent); }402414 .save-btn {403415 width: 100%; padding: 8px; border-radius: 8px; border: none;404- background: #D96830; color: #fff; font-size: 12px;416+ background: var(--peach-accent); color: #fff; font-size: 12px;405417 font-family: Inter, sans-serif; cursor: pointer; font-weight: 500;406418 transition: background 120ms; letter-spacing: 0.01em;407419 }408- .save-btn:hover { background: #c55e28; }420+ .save-btn:hover { background: color-mix(in srgb, var(--peach-accent) 82%, #000); }409421 .save-btn:disabled { opacity: 0.4; cursor: not-allowed; }410422 .url-hint {411- font-size: 9px; color: rgba(217,104,48,0.45);423+ font-size: 9px; color: color-mix(in srgb, var(--peach-accent) 45%, transparent);412424 font-family: "IBM Plex Mono", monospace; font-style: italic;413425 }414426 @@ -450,15 +462,15 @@450462 font-size: 11px; font-family: "IBM Plex Mono", monospace;451463 outline: none; transition: border-color 120ms, box-shadow 120ms;452464 }453- .locked-input:focus { border-color: rgba(217,104,48,0.4); box-shadow: 0 0 0 2px rgba(217,104,48,0.10); }465+ .locked-input:focus { border-color: color-mix(in srgb, var(--peach-accent) 40%, transparent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--peach-accent) 10%, transparent); }454466 .locked-input::placeholder { color: rgba(240,232,216,0.2); }455467 .locked-btn {456468 width: 100%; padding: 8px; border-radius: 8px; border: none;457- background: #D96830; color: #fff; font-size: 12px;469+ background: var(--peach-accent); color: #fff; font-size: 12px;458470 font-family: Inter, sans-serif; cursor: pointer; font-weight: 500;459471 transition: background 120ms; letter-spacing: 0.01em;460472 }461- .locked-btn:hover { background: #c55e28; }473+ .locked-btn:hover { background: color-mix(in srgb, var(--peach-accent) 82%, #000); }462474 .locked-btn:disabled { opacity: 0.4; cursor: not-allowed; }463475 .locked-error {464476 font-size: 10px; color: rgba(220,80,60,0.85);@@ -474,6 +486,7 @@474486 ): () => void {475487 const host = document.createElement("div");476488 host.style.cssText = "position: absolute; z-index: 2147483647;";489+ host.style.setProperty("--peach-accent", accentHex);477490 const shadow = host.attachShadow({ mode: "closed" });478491 479492 const style = shadow.appendChild(document.createElement("style"));src/content/save.ts+11 −3
@@ -1,6 +1,13 @@11 import { extractDomain } from "../shared/domain";2+import { ACCENT_COLORS } from "../shared/types";23 import type { VaultEntry } from "../shared/types";34 5+let accentHex = "#E8956D";6+chrome.runtime.sendMessage({ type: "GET_SETTINGS" }, (resp: { ok: boolean; data?: { accentColor?: string } } | undefined) => {7+ const name = resp?.data?.accentColor ?? "peach";8+ accentHex = ACCENT_COLORS.find(c => c.name === name)?.hex ?? "#E8956D";9+});10+411 let currentBanner: (() => void) | null = null;512 613 interface DetectedCredential {@@ -64,6 +71,7 @@6471 position: fixed; top: 16px; right: 16px; z-index: 2147483647;6572 font-family: Inter, sans-serif;6673 `;74+ host.style.setProperty("--peach-accent", accentHex);6775 const shadow = host.attachShadow({ mode: "closed" });6876 6977 const isUpdate = existingEntry !== null;@@ -77,8 +85,8 @@7785 :host { all: initial; }7886 .banner {7987 background:80- radial-gradient(120% 80% at 0% 0%, rgba(217,104,48,0.10) 0%, transparent 65%),81- radial-gradient(85% 100% at 100% 100%, rgba(217,104,48,0.06) 0%, transparent 70%),88+ radial-gradient(120% 80% at 0% 0%, color-mix(in srgb, var(--peach-accent) 10%, transparent) 0%, transparent 65%),89+ radial-gradient(85% 100% at 100% 100%, color-mix(in srgb, var(--peach-accent) 6%, transparent) 0%, transparent 70%),8290 #0C0A06;8391 border: 1px solid rgba(240,232,216,0.10);8492 border-radius: 14px;@@ -108,7 +116,7 @@108116 }109117 .btn-save {110118 flex: 1;111- background: #D96830;119+ background: var(--peach-accent);112120 color: rgba(0,0,0,0.75);113121 border: none;114122 border-radius: 10px;src/popup/App.tsx+21 −5
@@ -1,5 +1,6 @@11 import { createEffect, createMemo, createSignal, lazy, onCleanup, onMount, Show, Suspense } from "solid-js";2-import type { PasskeyEntry, PendingPasskeyRequest, VaultEntry } from "../shared/types";2+import { ACCENT_COLORS } from "../shared/types";3+import type { AccentColorName, PasskeyEntry, PendingPasskeyRequest, VaultEntry } from "../shared/types";34 import { LockView } from "./views/Lock";45 import { VaultView, type SortOrder } from "./views/Vault";56 import { EntryView } from "./views/Entry";@@ -56,7 +57,7 @@5657 {5758 offset: 0.3,5859 boxShadow:59- "0 2px 8px rgba(0,0,0,0.5), 0 14px 48px rgba(0,0,0,0.6), 0 0 0 1.5px rgba(217,104,48,0.58), 0 0 22px rgba(217,104,48,0.18)",60+ "0 2px 8px rgba(0,0,0,0.5), 0 14px 48px rgba(0,0,0,0.6), 0 0 0 1.5px color-mix(in srgb, var(--peach-accent) 58%, transparent), 0 0 22px color-mix(in srgb, var(--peach-accent) 18%, transparent)",6061 },6162 { offset: 1, boxShadow: "var(--copy-shadow)" },6263 ],@@ -159,7 +160,7 @@159160 const [entries, setEntries] = createSignal<VaultEntry[]>([]);160161 const [selectedEntry, setSelectedEntry] = createSignal<VaultEntry | null>(null);161162 const [editEntry, setEditEntry] = createSignal<VaultEntry | undefined>(undefined);162- const [accentColor, setAccentColor] = createSignal("#D96830");163+ const [accentColor, setAccentColor] = createSignal<AccentColorName>("peach");163164 const [theme, setTheme] = createSignal<"dark" | "light">("dark");164165 const [lockOnClose, setLockOnClose] = createSignal(true);165166 const [autoLockMinutes, setAutoLockMinutes] = createSignal(5);@@ -174,8 +175,13 @@174175 175176 let contentPhaseTimer: number | undefined;176177 178+ function applyAccent(name: AccentColorName) {179+ const color = ACCENT_COLORS.find(c => c.name === name) ?? ACCENT_COLORS[0]!;180+ document.documentElement.style.setProperty("--peach-accent", color.hex);181+ }182+177183 createEffect(() => {178- document.documentElement.style.setProperty("--ac", accentColor());184+ applyAccent(accentColor());179185 });180186 181187 createEffect(() => {@@ -189,6 +195,12 @@189195 return entries().findIndex((entry) => entry.id === currentId);190196 });191197 198+ async function applyAccentColor(name: AccentColorName) {199+ applyAccent(name);200+ setAccentColor(name);201+ await sendMessage({ type: "UPDATE_SETTINGS", payload: { accentColor: name } });202+ }203+192204 async function applyTheme(t: "dark" | "light") {193205 setTheme(t);194206 await sendMessage({ type: "UPDATE_SETTINGS", payload: { theme: t } });@@ -401,7 +413,9 @@401413 async function restoreSettings() {402414 const res = await sendMessage({ type: "GET_SETTINGS" });403415 const s = (res as { ok: boolean; data?: any }).data ?? {};404- if (s.accentColor) setAccentColor(s.accentColor);416+ if (s.accentColor && ACCENT_COLORS.some(c => c.name === s.accentColor)) {417+ setAccentColor(s.accentColor as AccentColorName);418+ }405419 setTheme(s.theme === "light" ? "light" : "dark");406420 setLockOnClose(s.lockOnClose !== false);407421 setAutoLockMinutes(typeof s.autoLockMinutes === "number" ? s.autoLockMinutes : 5);@@ -798,11 +812,13 @@798812 autoLockMinutes={autoLockMinutes()}799813 trashRetentionDays={trashRetentionDays()}800814 theme={theme()}815+ accentColor={accentColor()}801816 onBreachMonitoringChange={applyBreachMonitoring}802817 onLockOnCloseChange={applyLockOnClose}803818 onAutoLockMinutesChange={applyAutoLockMinutes}804819 onTrashRetentionChange={applyTrashRetention}805820 onThemeChange={applyTheme}821+ onAccentChange={applyAccentColor}806822 onBack={handleBack}807823 onImport={() => setView("import")}808824 onExport={() => setView("export")}src/popup/components/Ring.tsx+1 −1
@@ -73,7 +73,7 @@7373 stroke="var(--ac)"7474 stroke-width="1"7575 style={{76- filter: "drop-shadow(0 0 5px rgba(217,104,48,0.8))",76+ filter: "drop-shadow(0 0 5px color-mix(in srgb, var(--peach-accent) 80%, transparent))",7777 transform: "rotate(-90deg)",7878 "transform-origin": "50% 50%",7979 opacity: "0",src/popup/styles/popup.css+102 −70
@@ -79,8 +79,8 @@7979 /* Shell */8080 .peach-shell, .peach-screen {8181 background:82- radial-gradient(120% 80% at 0% 0%, rgba(217,104,48,0.08) 0%, transparent 65%),83- radial-gradient(85% 100% at 100% 100%, rgba(217,104,48,0.06) 0%, transparent 70%),82+ radial-gradient(120% 80% at 0% 0%, var(--shell-accent-a) 0%, transparent 65%),83+ radial-gradient(85% 100% at 100% 100%, var(--shell-accent-b) 0%, transparent 70%),8484 var(--peach-bg);8585 border: 1px solid var(--peach-t3);8686 box-shadow:@@ -698,7 +698,7 @@698698 border-top: 1px solid var(--peach-t3);699699 background: var(--peach-s1);700700 min-height: 54px; position: relative;701- box-shadow: inset 0 6px 18px rgba(217, 104, 48, 0);701+ box-shadow: inset 0 6px 18px transparent;702702 transition: box-shadow 700ms ease;703703 }704704 .peach-search-wrap::before {@@ -791,7 +791,7 @@791791 792792 .peach-btn:focus-visible {793793 outline: none;794- box-shadow: 0 0 0 2px var(--peach-bg), 0 0 0 4px rgba(217, 104, 48, 0.5);794+ box-shadow: 0 0 0 2px var(--peach-bg), 0 0 0 4px color-mix(in srgb, var(--peach-accent) 50%, transparent);795795 }796796 797797 /* Lock button */@@ -813,15 +813,15 @@813813 .peach-copy-icon-svg { display: block; }814814 .peach-copy-sheen {815815 position: absolute; inset: 0;816- background: linear-gradient(90deg, rgba(217,104,48,0) 0%, rgba(217,104,48,0.18) 30%, rgba(217,104,48,0.08) 100%);816+ background: linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--peach-accent) 18%, transparent) 30%, color-mix(in srgb, var(--peach-accent) 8%, transparent) 100%);817817 opacity: 0; transform: scaleX(0.15); transform-origin: left center;818818 }819819 .peach-copy-btn.is-copied {820820 animation: peach-copy-confirm var(--peach-dur-150) var(--peach-curve-settle) forwards;821821 box-shadow:822- 0 0 0 1px rgba(217,104,48,0.22),823- 0 0 18px rgba(217,104,48,0.2),824- inset 0 0 20px rgba(217,104,48,0.12);822+ 0 0 0 1px color-mix(in srgb, var(--peach-accent) 22%, transparent),823+ 0 0 18px color-mix(in srgb, var(--peach-accent) 20%, transparent),824+ inset 0 0 20px color-mix(in srgb, var(--peach-accent) 12%, transparent);825825 }826826 .peach-copy-btn.is-copied .peach-copy-icon {827827 animation: peach-copy-icon-settle var(--peach-dur-150) var(--peach-curve-settle) both;@@ -917,8 +917,8 @@917917 display: flex;918918 flex-direction: column;919919 background:920- radial-gradient(120% 80% at 0% 0%, rgba(217,104,48,0.08) 0%, transparent 65%),921- radial-gradient(85% 100% at 100% 100%, rgba(217,104,48,0.06) 0%, transparent 70%),920+ radial-gradient(120% 80% at 0% 0%, var(--shell-accent-a) 0%, transparent 65%),921+ radial-gradient(85% 100% at 100% 100%, var(--shell-accent-b) 0%, transparent 70%),922922 var(--peach-bg);923923 z-index: 2;924924 overflow: hidden;@@ -1420,10 +1420,10 @@14201420 background: rgba(240,232,216,0.02);14211421 }14221422 .peach-vault-list.is-selecting .peach-entry-row.is-selected {1423- background: rgba(217,104,48,0.06);1423+ background: color-mix(in srgb, var(--peach-accent) 6%, transparent);14241424 }14251425 .peach-vault-list.is-selecting .peach-entry-row.is-selected:hover {1426- background: rgba(217,104,48,0.1);1426+ background: color-mix(in srgb, var(--peach-accent) 10%, transparent);14271427 }14281428 14291429 /* Select indicator circles in icon slot */@@ -1502,7 +1502,7 @@15021502 }15031503 .peach-export-card--primary {15041504 background:1505- linear-gradient(180deg, rgba(217,104,48,0.08), rgba(217,104,48,0.02));1505+ linear-gradient(180deg, color-mix(in srgb, var(--peach-accent) 8%, transparent), color-mix(in srgb, var(--peach-accent) 2%, transparent));15061506 }15071507 .peach-export-card-head {15081508 display: flex;@@ -1527,8 +1527,8 @@15271527 align-items: center;15281528 padding: 4px 8px;15291529 border-radius: 999px;1530- border: 1px solid rgba(217,104,48,0.22);1531- background: rgba(217,104,48,0.08);1530+ border: 1px solid color-mix(in srgb, var(--peach-accent) 22%, transparent);1531+ background: color-mix(in srgb, var(--peach-accent) 8%, transparent);15321532 color: var(--peach-accent);15331533 font-family: "IBM Plex Mono", monospace;15341534 font-size: 8px;@@ -1602,8 +1602,8 @@16021602 cursor: pointer;16031603 }16041604 .peach-toggle.is-on {1605- background: rgba(217,104,48,0.22);1606- border-color: rgba(217,104,48,0.4);1605+ background: color-mix(in srgb, var(--peach-accent) 22%, transparent);1606+ border-color: color-mix(in srgb, var(--peach-accent) 40%, transparent);16071607 }16081608 .peach-toggle-knob {16091609 width: 10px; height: 10px;@@ -1908,7 +1908,7 @@19081908 .peach-new-type-btn.is-active {19091909 color: var(--peach-t0);19101910 border-color: var(--peach-accent);1911- background: rgba(217, 104, 48, 0.08);1911+ background: color-mix(in srgb, var(--peach-accent) 8%, transparent);19121912 }19131913 .peach-new-type-btn:not(.is-active):hover {19141914 color: var(--peach-t1);@@ -2168,8 +2168,8 @@21682168 .peach-regen-panel {21692169 position: relative;21702170 z-index: 1;2171- background: rgba(217, 104, 48, 0.08);2172- border: 1px solid rgba(217, 104, 48, 0.25);2171+ background: color-mix(in srgb, var(--peach-accent) 8%, transparent);2172+ border: 1px solid color-mix(in srgb, var(--peach-accent) 25%, transparent);21732173 border-radius: 8px;21742174 padding: 12px;21752175 margin-bottom: 8px;@@ -2187,7 +2187,7 @@21872187 font-weight: 600;21882188 letter-spacing: 0.06em;21892189 text-transform: uppercase;2190- color: rgba(217, 104, 48, 0.9);2190+ color: color-mix(in srgb, var(--peach-accent) 90%, transparent);21912191 }21922192 21932193 .peach-regen-output {@@ -2241,7 +2241,7 @@22412241 display: flex;22422242 flex-direction: column;22432243 background:2244- radial-gradient(120% 80% at 0% 0%, rgba(217,104,48,0.07) 0%, transparent 65%),2244+ radial-gradient(120% 80% at 0% 0%, color-mix(in srgb, var(--peach-accent) 7%, transparent) 0%, transparent 65%),22452245 var(--peach-bg);22462246 animation: overlay-in 180ms cubic-bezier(0.4, 0, 0.2, 1) both;22472247 }@@ -2280,7 +2280,7 @@22802280 22812281 .peach-note-editor-save-btn {22822282 background: transparent;2283- border: 1px solid rgba(217, 104, 48, 0.4);2283+ border: 1px solid color-mix(in srgb, var(--peach-accent) 40%, transparent);22842284 border-radius: 8px;22852285 color: var(--peach-accent);22862286 font-family: "IBM Plex Mono", monospace;@@ -2292,8 +2292,8 @@22922292 transition: background 120ms ease, border-color 120ms ease;22932293 }22942294 .peach-note-editor-save-btn:hover:not(:disabled) {2295- background: rgba(217, 104, 48, 0.1);2296- border-color: rgba(217, 104, 48, 0.65);2295+ background: color-mix(in srgb, var(--peach-accent) 10%, transparent);2296+ border-color: color-mix(in srgb, var(--peach-accent) 65%, transparent);22972297 }22982298 .peach-note-editor-save-btn:disabled { opacity: 0.4; cursor: not-allowed; }22992299 @@ -2361,9 +2361,6 @@23612361 23622362 /* Inline variant (Add.tsx, Entry.tsx note) — toolbar hoisted to parent row */23632363 .peach-note-editor-inline {2364- border: 1px solid var(--peach-t3);2365- border-radius: 8px;2366- overflow: hidden;23672364 display: flex;23682365 flex-direction: column;23692366 flex: 1;@@ -2371,12 +2368,23 @@23712368 }23722369 .peach-note-editor-body--inline {23732370 flex: 1;2374- min-height: 200px;2371+ min-height: 0;23752372 font-size: 15px;2376- padding: 10px 14px 14px;2377- background: var(--peach-t4);2373+ padding: 10px 20px 14px;23782374 }23792375 2376+/* Full-width toolbar row inside the body (Add.tsx note type).2377+ Negative horizontal margins cancel body padding so the border spans edge-to-edge. */2378+.peach-note-toolbar-body {2379+ display: flex;2380+ align-items: center;2381+ gap: 3px;2382+ padding: 5px 20px 4px;2383+ margin: 2px -20px 0;2384+ border-bottom: 1px solid var(--peach-t3);2385+ flex-shrink: 0;2386+}2387+23802388 /* Right-aligned inline toolbar sitting inside .peach-new-type-row (Add.tsx)23812389 or .peach-entry-note-toolbar-row (Entry.tsx). Reuses .peach-note-tool-btn23822390 and .peach-note-tool-divider button-level styles. */@@ -2413,7 +2421,7 @@24132421 margin: 4px 0 0;24142422 }24152423 .peach-entry-body--new .peach-note-body {2416- margin: 4px 12px 0;2424+ margin: 8px -20px 0;24172425 }24182426 24192427 /* Add.tsx body is a grid by default; swap to a flex column when a note is@@ -2598,10 +2606,10 @@25982606 }25992607 @keyframes peach-copy-confirm {26002608 from { color: var(--peach-t2); border-color: var(--peach-t3); background-color: transparent; box-shadow: none; }2601- to { color: var(--peach-accent); border-color: rgba(217,104,48,0.42); background-color: rgba(217,104,48,0.09); box-shadow: 0 0 18px rgba(217,104,48,0.22), inset 0 0 18px rgba(217,104,48,0.12); }2609+ to { color: var(--peach-accent); border-color: color-mix(in srgb, var(--peach-accent) 42%, transparent); background-color: color-mix(in srgb, var(--peach-accent) 9%, transparent); box-shadow: 0 0 18px color-mix(in srgb, var(--peach-accent) 22%, transparent), inset 0 0 18px color-mix(in srgb, var(--peach-accent) 12%, transparent); }26022610 }26032611 @keyframes peach-copy-retreat {2604- from { color: var(--peach-accent); border-color: rgba(217,104,48,0.42); background-color: rgba(217,104,48,0.09); box-shadow: 0 0 18px rgba(217,104,48,0.22), inset 0 0 18px rgba(217,104,48,0.12); }2612+ from { color: var(--peach-accent); border-color: color-mix(in srgb, var(--peach-accent) 42%, transparent); background-color: color-mix(in srgb, var(--peach-accent) 9%, transparent); box-shadow: 0 0 18px color-mix(in srgb, var(--peach-accent) 22%, transparent), inset 0 0 18px color-mix(in srgb, var(--peach-accent) 12%, transparent); }26052613 to { color: var(--peach-t2); border-color: var(--peach-t3); background-color: transparent; box-shadow: none; }26062614 }26072615 @keyframes peach-copy-flood {@@ -2719,8 +2727,8 @@27192727 transition: all 150ms ease;27202728 }27212729 .peach-pwgen-pill.is-on {2722- border-color: rgba(217, 104, 48, 0.5);2723- background: rgba(217, 104, 48, 0.1);2730+ border-color: color-mix(in srgb, var(--peach-accent) 50%, transparent);2731+ background: color-mix(in srgb, var(--peach-accent) 10%, transparent);27242732 color: var(--peach-accent);27252733 }27262734 .peach-pwgen-pill:not(.is-on):hover {@@ -2806,7 +2814,7 @@28062814 height: 160px;28072815 border-radius: 999px;28082816 background:2809- radial-gradient(circle at 50% 50%, rgba(217, 104, 48, 0.18) 0%, rgba(217, 104, 48, 0.06) 42%, transparent 72%);2817+ radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--peach-accent) 18%, transparent) 0%, color-mix(in srgb, var(--peach-accent) 6%, transparent) 42%, transparent 72%);28102818 filter: blur(6px);28112819 opacity: 0.7;28122820 pointer-events: none;@@ -2880,7 +2888,7 @@28802888 height: 100%;28812889 }28822890 .peach-lock-hero-mark path:first-child {2883- fill: rgba(217, 104, 48, 0.92);2891+ fill: color-mix(in srgb, var(--peach-accent) 92%, transparent);28842892 }28852893 .peach-lock-hero-mark path:nth-child(2),28862894 .peach-lock-hero-mark path:nth-child(3) {@@ -2898,8 +2906,8 @@28982906 width: fit-content;28992907 padding: 4px 9px;29002908 border-radius: 999px;2901- border: 1px solid rgba(217, 104, 48, 0.22);2902- background: rgba(217, 104, 48, 0.08);2909+ border: 1px solid color-mix(in srgb, var(--peach-accent) 22%, transparent);2910+ background: color-mix(in srgb, var(--peach-accent) 8%, transparent);29032911 color: var(--peach-t0);29042912 font-family: "IBM Plex Mono", monospace;29052913 font-size: 8px;@@ -2990,7 +2998,7 @@29902998 }29912999 29923000 .peach-lock-option:hover {2993- border-color: rgba(217, 104, 48, 0.28);3001+ border-color: color-mix(in srgb, var(--peach-accent) 28%, transparent);29943002 background: rgba(240, 232, 216, 0.04);29953003 transform: translateY(-1px);29963004 }@@ -3056,8 +3064,8 @@30563064 background: rgba(240, 232, 216, 0.03);30573065 }30583066 .peach-snapshot-row.is-selected {3059- border-color: rgba(217, 104, 48, 0.4);3060- background: rgba(217, 104, 48, 0.07);3067+ border-color: color-mix(in srgb, var(--peach-accent) 40%, transparent);3068+ background: color-mix(in srgb, var(--peach-accent) 7%, transparent);30613069 }30623070 .peach-snapshot-time {30633071 font-size: 11.5px;@@ -3114,11 +3122,11 @@31143122 }31153123 31163124 .peach-card-active {3117- border-color: rgba(217, 104, 48, 0.35);3125+ border-color: color-mix(in srgb, var(--peach-accent) 35%, transparent);31183126 box-shadow:31193127 inset 0 1px 0 rgba(240, 232, 216, 0.05),31203128 0 16px 38px rgba(0, 0, 0, 0.18),3121- 0 0 0 1px rgba(217, 104, 48, 0.08);3129+ 0 0 0 1px color-mix(in srgb, var(--peach-accent) 8%, transparent);31223130 }31233131 31243132 .peach-card-disabled {@@ -3160,7 +3168,7 @@31603168 31613169 .peach-lock-submit {31623170 width: 100%;3163- box-shadow: 0 14px 36px rgba(217, 104, 48, 0.22);3171+ box-shadow: 0 14px 36px color-mix(in srgb, var(--peach-accent) 22%, transparent);31643172 }31653173 31663174 .peach-lock-secondary {@@ -3381,9 +3389,9 @@33813389 .peach-restore-file::file-selector-button {33823390 margin-right: 10px;33833391 padding: 7px 10px;3384- border: 1px solid rgba(217, 104, 48, 0.28);3392+ border: 1px solid color-mix(in srgb, var(--peach-accent) 28%, transparent);33853393 border-radius: 999px;3386- background: rgba(217, 104, 48, 0.08);3394+ background: color-mix(in srgb, var(--peach-accent) 8%, transparent);33873395 color: var(--peach-t0);33883396 font-size: 10px;33893397 letter-spacing: 0.08em;@@ -3477,7 +3485,7 @@34773485 font-size: 10px;34783486 letter-spacing: 0.08em;34793487 text-transform: uppercase;3480- background: rgba(217, 104, 48, 0.14);3488+ background: color-mix(in srgb, var(--peach-accent) 14%, transparent);34813489 color: var(--peach-accent);34823490 }34833491 @@ -3858,8 +3866,8 @@38583866 gap: 4px;38593867 padding: 3px 8px;38603868 border-radius: 999px;3861- border: 1px solid rgba(217, 104, 48, 0.28);3862- background: rgba(217, 104, 48, 0.08);3869+ border: 1px solid color-mix(in srgb, var(--peach-accent) 28%, transparent);3870+ background: color-mix(in srgb, var(--peach-accent) 8%, transparent);38633871 color: rgba(240, 232, 216, 0.85);38643872 font-family: "IBM Plex Mono", monospace;38653873 font-size: 10px;@@ -3906,8 +3914,8 @@39063914 }39073915 39083916 .peach-tag-suggestion:hover {3909- border-color: rgba(217, 104, 48, 0.4);3910- background: rgba(217, 104, 48, 0.08);3917+ border-color: color-mix(in srgb, var(--peach-accent) 40%, transparent);3918+ background: color-mix(in srgb, var(--peach-accent) 8%, transparent);39113919 }39123920 39133921 /* Tag filter strip */@@ -3934,13 +3942,13 @@39343942 }39353943 39363944 .peach-tag-filter-chip:hover {3937- border-color: rgba(217, 104, 48, 0.35);3945+ border-color: color-mix(in srgb, var(--peach-accent) 35%, transparent);39383946 color: var(--peach-t1);39393947 }39403948 39413949 .peach-tag-filter-chip.is-selected {3942- border-color: rgba(217, 104, 48, 0.5);3943- background: rgba(217, 104, 48, 0.12);3950+ border-color: color-mix(in srgb, var(--peach-accent) 50%, transparent);3951+ background: color-mix(in srgb, var(--peach-accent) 12%, transparent);39443952 color: rgba(240, 232, 216, 0.9);39453953 }39463954 @@ -3976,13 +3984,13 @@39763984 }39773985 39783986 .peach-sort-btn:hover {3979- border-color: rgba(217, 104, 48, 0.3);3987+ border-color: color-mix(in srgb, var(--peach-accent) 30%, transparent);39803988 color: var(--peach-t1);39813989 }39823990 39833991 .peach-sort-btn.is-active {3984- border-color: rgba(217, 104, 48, 0.5);3985- background: rgba(217, 104, 48, 0.12);3992+ border-color: color-mix(in srgb, var(--peach-accent) 50%, transparent);3993+ background: color-mix(in srgb, var(--peach-accent) 12%, transparent);39863994 color: rgba(240, 232, 216, 0.9);39873995 }39883996 @@ -3990,7 +3998,7 @@39903998 margin-left: auto;39913999 font-family: "IBM Plex Mono", monospace;39924000 font-size: 9px;3993- color: rgba(217, 104, 48, 0.6);4001+ color: color-mix(in srgb, var(--peach-accent) 60%, transparent);39944002 white-space: nowrap;39954003 overflow: hidden;39964004 text-overflow: ellipsis;@@ -4003,20 +4011,20 @@40034011 width: 6px;40044012 height: 6px;40054013 border-radius: 50%;4006- background: rgba(217, 104, 48, 0.75);4014+ background: color-mix(in srgb, var(--peach-accent) 75%, transparent);40074015 margin-left: 5px;40084016 vertical-align: middle;40094017 flex-shrink: 0;4010- box-shadow: 0 0 4px rgba(217, 104, 48, 0.4);4018+ box-shadow: 0 0 4px color-mix(in srgb, var(--peach-accent) 40%, transparent);40114019 }40124020 40134021 .peach-entry-row.is-tab-match {4014- background: rgba(217, 104, 48, 0.04);4015- border-bottom-color: rgba(217, 104, 48, 0.08);4022+ background: color-mix(in srgb, var(--peach-accent) 4%, transparent);4023+ border-bottom-color: color-mix(in srgb, var(--peach-accent) 8%, transparent);40164024 }40174025 40184026 .peach-entry-row.is-tab-match:hover {4019- background: rgba(217, 104, 48, 0.08);4027+ background: color-mix(in srgb, var(--peach-accent) 8%, transparent);40204028 }40214029 40224030 /* Entry list stagger entrance */@@ -4101,8 +4109,8 @@41014109 }41024110 41034111 .peach-duress-status.is-active {4104- border-color: rgba(217, 104, 48, 0.45);4105- background: rgba(217, 104, 48, 0.1);4112+ border-color: color-mix(in srgb, var(--peach-accent) 45%, transparent);4113+ background: color-mix(in srgb, var(--peach-accent) 10%, transparent);41064114 color: rgba(240, 232, 216, 0.85);41074115 }41084116 @@ -4156,8 +4164,8 @@41564164 display: flex;41574165 flex-direction: column;41584166 background:4159- radial-gradient(120% 80% at 0% 0%, rgba(217,104,48,0.08) 0%, transparent 65%),4160- radial-gradient(85% 100% at 100% 100%, rgba(217,104,48,0.06) 0%, transparent 70%),4167+ radial-gradient(120% 80% at 0% 0%, var(--shell-accent-a) 0%, transparent 65%),4168+ radial-gradient(85% 100% at 100% 100%, var(--shell-accent-b) 0%, transparent 70%),41614169 var(--peach-bg);41624170 z-index: 2;41634171 overflow: hidden;@@ -4201,7 +4209,7 @@42014209 flex-shrink: 0;42024210 }42034211 .peach-duress-status-pill.is-active {4204- background: rgba(217, 104, 48, 0.15);4212+ background: color-mix(in srgb, var(--peach-accent) 15%, transparent);42054213 color: var(--peach-accent);42064214 }42074215 @@ -4364,4 +4372,28 @@43644372 }43654373 .peach-sort-trash-btn.is-active {43664374 color: var(--peach-accent);4375+}4376+4377+/* Accent color picker */4378+.peach-settings-row--accent { align-items: flex-start; padding-top: 10px; }4379+.peach-accent-picker {4380+ display: flex;4381+ flex-wrap: wrap;4382+ gap: 7px;4383+ padding: 2px 0;4384+}4385+.peach-accent-swatch {4386+ width: 22px;4387+ height: 22px;4388+ border-radius: 50%;4389+ border: 2px solid transparent;4390+ cursor: pointer;4391+ padding: 0;4392+ transition: transform 100ms;4393+ outline-offset: 2px;4394+}4395+.peach-accent-swatch:hover { transform: scale(1.15); }4396+.peach-accent-swatch.is-active {4397+ border-color: var(--peach-t0);4398+ transform: scale(1.1);43674399 }src/popup/styles/vars.css+5 −4
@@ -83,13 +83,13 @@8383 --t2: rgba(240, 232, 216, 0.20);8484 --t3: rgba(240, 232, 216, 0.07);8585 --t4: rgba(240, 232, 216, 0.04);86- --ac: #D96830;86+ --ac: #E8956D;8787 --surface-card: rgba(240, 232, 216, 0.02);8888 --surface-elevated: rgba(19, 17, 9, 0.88);8989 --shell-top-solid: #000000;9090 --shell-top-fade: rgba(12, 10, 6, 0.95);91- --shell-accent-a: rgba(217, 104, 48, 0.08);92- --shell-accent-b: rgba(217, 104, 48, 0.06);91+ --shell-accent-a: color-mix(in srgb, var(--peach-accent) 8%, transparent);92+ --shell-accent-b: color-mix(in srgb, var(--peach-accent) 6%, transparent);9393 --breach: rgba(220, 80, 60, 0.7);9494 --health: rgba(100, 210, 100, 0.75);9595 --totp-tag: rgba(120, 175, 255, 0.75);@@ -112,6 +112,7 @@112112 --peach-t2: var(--t2);113113 --peach-t3: var(--t3);114114 --peach-accent: var(--ac);115+ --peach-accent-dim: color-mix(in srgb, var(--peach-accent) 25%, transparent);115116 --peach-breach: var(--breach);116117 --peach-health-ok: var(--health);117118 --peach-totp-tag: var(--totp-tag);@@ -148,7 +149,7 @@148149 --surface-elevated: rgba(185, 170, 152, 0.96);149150 --shell-top-solid: rgba(210, 196, 178, 0.96);150151 --shell-top-fade: rgba(198, 180, 160, 0.96);151- --shell-accent-a: rgba(217, 104, 48, 0.12);152+ --shell-accent-a: color-mix(in srgb, var(--peach-accent) 12%, transparent);152153 --shell-accent-b: rgba(123, 144, 96, 0.10);153154 --copy-shadow: 0 2px 8px rgba(80, 56, 32, 0.22), 0 14px 48px rgba(80, 56, 32, 0.20), 0 0 0 1px rgba(28,25,21,0.06);154155 }src/popup/views/Add.tsx+15 −15
@@ -180,23 +180,23 @@180180 {/* ── Body — mirrors Entry.tsx field-card structure ── */}181181 <div class="peach-entry-body peach-entry-body--new">182182 183- {/* Type toggle + inline note formatting toolbar */}184- <Show when={!props.entry || selectedType() === "note"}>183+ {/* Type toggle */}184+ <Show when={!props.entry}>185185 <div class="peach-new-type-row">186- <Show when={!props.entry}>187- <button188- class={`peach-new-type-btn ${selectedType() === "login" ? "is-active" : ""}`}189- onClick={() => setSelectedType("login")}190- >login</button>191- <button192- class={`peach-new-type-btn ${selectedType() === "note" ? "is-active" : ""}`}193- onClick={() => setSelectedType("note")}194- >note</button>195- </Show>196- <Show when={selectedType() === "note"}>197- <Toolbar exec={noteExec} class="peach-note-toolbar-inline" />198- </Show>186+ <button187+ class={`peach-new-type-btn ${selectedType() === "login" ? "is-active" : ""}`}188+ onClick={() => setSelectedType("login")}189+ >login</button>190+ <button191+ class={`peach-new-type-btn ${selectedType() === "note" ? "is-active" : ""}`}192+ onClick={() => setSelectedType("note")}193+ >note</button>199194 </div>195+ </Show>196+197+ {/* Note formatting toolbar — own row so it never overflows */}198+ <Show when={selectedType() === "note"}>199+ <Toolbar exec={noteExec} class="peach-note-toolbar-body" />200200 </Show>201201 202202 {/* Title */}src/popup/views/Settings.tsx+24 −4
@@ -1,6 +1,7 @@1-import { createSignal, onMount, Show } from "solid-js";1+import { createSignal, For, onMount, Show } from "solid-js";22 import { sendMessage } from "../App";3-import type { PasskeyProviderState } from "../../shared/types";3+import { ACCENT_COLORS } from "../../shared/types";4+import type { AccentColorName, PasskeyProviderState } from "../../shared/types";45 import type { PairedDevice, TrustedNetwork, SyncStatus } from "../../shared/sync-types";56 67 interface LicenseInfo {@@ -16,11 +17,13 @@1617 autoLockMinutes: number;1718 trashRetentionDays: number;1819 theme: "dark" | "light";20+ accentColor: AccentColorName;1921 onBreachMonitoringChange: (enabled: boolean) => void | Promise<void>;2022 onLockOnCloseChange: (enabled: boolean) => void | Promise<void>;2123 onAutoLockMinutesChange: (minutes: number) => void | Promise<void>;2224 onTrashRetentionChange: (days: number) => void | Promise<void>;2325 onThemeChange: (theme: "dark" | "light") => void;26+ onAccentChange: (name: AccentColorName) => void | Promise<void>;2427 onBack: () => void;2528 onImport: () => void;2629 onExport: () => void;@@ -364,7 +367,7 @@364367 </div>365368 <div class="peach-sync-pro-gate-overlay">366369 <span class="peach-sync-pro-badge">Pro</span>367- <a href="https://peachpasswords.com/#pricing" target="_blank" rel="noopener noreferrer" class="peach-link" style="color:#D96830;font-size:13px;font-weight:500">370+ <a href="https://peachpasswords.com/#pricing" target="_blank" rel="noopener noreferrer" class="peach-link" style="color:var(--peach-accent);font-size:13px;font-weight:500">368371 Upgrade to Pro →369372 </a>370373 </div>@@ -780,6 +783,23 @@780783 </div>781784 </div>782785 </Show>786+ <div class="peach-settings-row peach-settings-row--meta peach-settings-row--accent">787+ <span>Accent</span>788+ <div class="peach-accent-picker">789+ <For each={ACCENT_COLORS}>790+ {(color) => (791+ <button792+ class="peach-accent-swatch"793+ classList={{ "is-active": props.accentColor === color.name }}794+ style={{ background: color.hex }}795+ onClick={() => void props.onAccentChange(color.name)}796+ aria-label={color.name}797+ title={color.name}798+ />799+ )}800+ </For>801+ </div>802+ </div>783803 <div class="peach-settings-row peach-settings-row--meta">784804 <span>Theme</span>785805 <button@@ -888,7 +908,7 @@888908 target="_blank"889909 rel="noopener noreferrer"890910 class="peach-link"891- style="color:#D96830"911+ style="color:var(--peach-accent)"892912 >893913 Purchase →894914 </a>src/popup/views/contracts.test.tsx+4 −0
@@ -288,11 +288,13 @@288288 autoLockMinutes={5}289289 trashRetentionDays={30}290290 theme="dark"291+ accentColor="peach"291292 onBreachMonitoringChange={vi.fn()}292293 onLockOnCloseChange={vi.fn()}293294 onAutoLockMinutesChange={vi.fn()}294295 onTrashRetentionChange={vi.fn()}295296 onThemeChange={vi.fn()}297+ onAccentChange={vi.fn()}296298 onBack={vi.fn()}297299 onImport={vi.fn()}298300 onExport={vi.fn()}@@ -335,11 +337,13 @@335337 autoLockMinutes={5}336338 trashRetentionDays={30}337339 theme="dark"340+ accentColor="peach"338341 onBreachMonitoringChange={vi.fn()}339342 onLockOnCloseChange={vi.fn()}340343 onAutoLockMinutesChange={onAutoLockMinutesChange}341344 onTrashRetentionChange={vi.fn()}342345 onThemeChange={onThemeChange}346+ onAccentChange={vi.fn()}343347 onBack={vi.fn()}344348 onImport={vi.fn()}345349 onExport={vi.fn()}src/shared/types.ts+17 −0
@@ -158,6 +158,23 @@158158 | "VAULT_LOCKED" // background → content/popup: vault just locked159159 | "VAULT_UNLOCKED"; // background → content/popup: vault just unlocked160160 161+export const ACCENT_COLORS = [162+ { name: "peach", hex: "#E8956D" },163+ { name: "rose", hex: "#E8909A" },164+ { name: "plum", hex: "#C49AC8" },165+ { name: "lavender", hex: "#9FA8D4" },166+ { name: "sky", hex: "#85BAD4" },167+ { name: "mint", hex: "#7EC8A4" },168+ { name: "sage", hex: "#9AB87A" },169+ { name: "butter", hex: "#D4B96A" },170+ { name: "sand", hex: "#C8A882" },171+ { name: "clay", hex: "#C4826A" },172+ { name: "slate", hex: "#8A9EAA" },173+ { name: "stone", hex: "#A89E92" },174+] as const;175+176+export type AccentColorName = typeof ACCENT_COLORS[number]["name"];177+161178 export interface PasswordPolicy {162179 minLength?: number;163180 maxLength?: number;