f047fba9a3
Quick search from tray - New "Quick search…" entry in the tray context menu (between Open and Lock vault). - Compact modal with live-filtered top-8 entries, arrow keys / Enter to copy the password (Shift+Enter copies the username instead), Esc to dismiss. Each row shows the favicon when cached. - Locked vault → focus the master password input instead of opening the modal (same pattern as the locked-autofill-hotkey path). - Window-state restore: Delphi remembers whether the window was hidden before the menu was opened and tells JS via the Bridge.openQuickSearch(wasHidden) arg. After the copy (or cancel) we hide back to the tray so the previously-foreground app comes back and Ctrl+V drops the password in. Tray notifications toggle - New Settings → Security "Show tray notifications" toggle. Gates Shell_NotifyIcon NIF_INFO balloons (currently only the "still running in the tray" first-time popup). Default ON, synced via settings_json so it follows the user across devices. - PM.Bridge.ShowNotifications exposed as a public property; JS pushes the value on every settings sync. Privacy: WebView2 phone-home killed - WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS set in the unit initialization section (before the TMS WebBrowser instantiates its CoreWebView2Environment). Disables: background networking, sync, component updates, breakpad/crashpad, domain reliability, client-side phishing detection, experiments, UMA upload, MediaRouter, OptimizationHints, SafeBrowsing enhanced, autofill server, privacy sandbox APIs. Verified via Resource Monitor: only 127.0.0.1 connections remain (plus DDG when favicons are on). Fixes - Blank-window-on-launch race: the 1.5 s navigation timer assumes WebView2 finishes init in time, but on slow machines Edge Chromium needs 2-3 s and the Navigate() call is silently dropped. WebBrowserInitialized now also navigates if a URL is still pending — first to run wins. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1957 lines
54 KiB
CSS
1957 lines
54 KiB
CSS
/* ============================================================
|
|
Vault — UI V2 (Linear/Notion design system)
|
|
Dark default, cyan/violet accent, glassmorphism subtil.
|
|
============================================================ */
|
|
|
|
/* ---- 1. RESET & TOKENS ----------------------------------- */
|
|
|
|
*,*::before,*::after { box-sizing: border-box; }
|
|
html, body { margin: 0; padding: 0; height: 100%; }
|
|
body {
|
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
color: var(--text);
|
|
background: var(--bg);
|
|
-webkit-font-smoothing: antialiased;
|
|
overflow: hidden;
|
|
}
|
|
|
|
button { font-family: inherit; cursor: pointer; }
|
|
input, select, textarea { font-family: inherit; font-size: inherit; }
|
|
kbd {
|
|
font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
|
|
font-size: 11px;
|
|
padding: 2px 6px;
|
|
border: 1px solid var(--border);
|
|
border-radius: 4px;
|
|
background: var(--bg-elev);
|
|
color: var(--text-dim);
|
|
}
|
|
|
|
:root, [data-theme="dark"] {
|
|
/* Slightly lighter surfaces + warmer tones, brighter text-dim/faint
|
|
and more visible borders. Less "black hole" feel. */
|
|
--bg: #15151c;
|
|
--bg-elev: #1d1d26;
|
|
--bg-elev-2: #292932;
|
|
--bg-glass: rgba(29,29,38,0.78);
|
|
--border: #353541;
|
|
--border-soft: #25252e;
|
|
--text: #f1f1f5;
|
|
--text-dim: #b8b8c4;
|
|
--text-faint: #82828f;
|
|
--accent: #06b6d4;
|
|
--accent-hover: #22d3ee;
|
|
--accent-soft: rgba(6,182,212,0.12);
|
|
--accent-2: #a78bfa;
|
|
--danger: #f43f5e;
|
|
--danger-soft: rgba(244,63,94,0.12);
|
|
--success: #10b981;
|
|
--warning: #f59e0b;
|
|
--shadow: 0 8px 24px rgba(0,0,0,0.4);
|
|
--shadow-lg: 0 24px 48px rgba(0,0,0,0.55);
|
|
--blur: saturate(140%) blur(20px);
|
|
--radius: 12px;
|
|
--radius-sm: 8px;
|
|
--radius-lg: 16px;
|
|
--t-fast: 120ms cubic-bezier(0.16,1,0.3,1);
|
|
--t-base: 200ms cubic-bezier(0.16,1,0.3,1);
|
|
}
|
|
|
|
[data-theme="light"] {
|
|
--bg: #f7f7f5;
|
|
--bg-elev: #ffffff;
|
|
--bg-elev-2: #efefec;
|
|
--bg-glass: rgba(255,255,255,0.92);
|
|
--border: #dcdcd7;
|
|
--border-soft: #ebebe6;
|
|
--text: #1a1a1f;
|
|
--text-dim: #57575e;
|
|
--text-faint: #8e8e96;
|
|
--accent: #0891b2; /* cyan-600 — darker for better contrast on white */
|
|
--accent-hover: #0e7490;
|
|
--accent-soft: rgba(8,145,178,0.10);
|
|
--accent-2: #7c3aed;
|
|
--shadow: 0 4px 16px rgba(0,0,0,0.06);
|
|
--shadow-lg: 0 16px 36px rgba(0,0,0,0.08);
|
|
--blur: saturate(160%) blur(16px);
|
|
}
|
|
[data-theme="light"] .auth-screen {
|
|
background:
|
|
radial-gradient(ellipse at top, rgba(8,145,178,0.08), transparent 50%),
|
|
radial-gradient(ellipse at bottom right, rgba(124,58,237,0.06), transparent 50%),
|
|
var(--bg);
|
|
}
|
|
|
|
svg { width: 16px; height: 16px; flex-shrink: 0; }
|
|
|
|
/* ---- 2. UTILITIES ---------------------------------------- */
|
|
|
|
.is-hidden { display: none !important; }
|
|
.hint { color: var(--text-faint); font-weight: 400; font-size: 12px; margin-left: 4px; }
|
|
|
|
/* ---- 3. BUTTONS ------------------------------------------ */
|
|
|
|
.btn {
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
gap: 6px;
|
|
padding: 8px 14px;
|
|
border: 1px solid transparent;
|
|
border-radius: var(--radius-sm);
|
|
font-size: 13px; font-weight: 500; line-height: 1;
|
|
transition: all var(--t-fast);
|
|
white-space: nowrap;
|
|
}
|
|
.btn-primary { background: var(--accent); color: white; }
|
|
.btn-primary:hover { background: var(--accent-hover); }
|
|
.btn.is-danger { background: var(--danger); color: white; }
|
|
.btn.is-danger:hover { background: #e11d48; }
|
|
.btn-ghost {
|
|
background: transparent;
|
|
color: var(--text-dim);
|
|
border-color: var(--border);
|
|
}
|
|
.btn-ghost:hover { background: var(--bg-elev-2); color: var(--text); }
|
|
.btn-block { width: 100%; }
|
|
.btn-sm { padding: 6px 10px; font-size: 12px; }
|
|
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
.btn-link {
|
|
background: transparent;
|
|
color: var(--text-dim);
|
|
border-color: transparent;
|
|
text-decoration: underline;
|
|
text-underline-offset: 2px;
|
|
}
|
|
.btn-link:hover { color: var(--accent); background: transparent; }
|
|
|
|
.icon-btn {
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
width: 32px; height: 32px;
|
|
background: transparent;
|
|
border: 1px solid transparent;
|
|
border-radius: var(--radius-sm);
|
|
color: var(--text-dim);
|
|
transition: all var(--t-fast);
|
|
}
|
|
.icon-btn:hover { background: var(--bg-elev-2); color: var(--text); }
|
|
.icon-btn-sm { width: 24px; height: 24px; }
|
|
.icon-btn-sm svg { width: 14px; height: 14px; }
|
|
|
|
/* ---- 4. FORM CONTROLS ------------------------------------ */
|
|
|
|
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
|
|
.field > span {
|
|
font-size: 12px; font-weight: 500; color: var(--text-dim);
|
|
display: flex; align-items: center;
|
|
}
|
|
.field input[type="text"],
|
|
.field input[type="password"],
|
|
.field input[type="search"],
|
|
.field input[type="email"],
|
|
.field select {
|
|
width: 100%;
|
|
padding: 10px 12px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
color: var(--text);
|
|
transition: all var(--t-fast);
|
|
}
|
|
.field input:focus, .field select:focus {
|
|
outline: none;
|
|
border-color: var(--accent);
|
|
background: var(--bg);
|
|
box-shadow: 0 0 0 3px var(--accent-soft);
|
|
}
|
|
|
|
.input-with-action { position: relative; display: flex; align-items: center; gap: 4px; }
|
|
.input-with-action input { padding-right: 80px; }
|
|
.input-with-action .icon-btn {
|
|
position: absolute;
|
|
top: 50%; transform: translateY(-50%);
|
|
}
|
|
.input-with-action .icon-btn:nth-of-type(1) { right: 38px; }
|
|
.input-with-action .icon-btn:nth-of-type(2) { right: 4px; }
|
|
|
|
.strength-bar {
|
|
height: 4px;
|
|
background: var(--border);
|
|
border-radius: 2px;
|
|
position: relative;
|
|
overflow: hidden;
|
|
margin-top: 4px;
|
|
}
|
|
.strength-bar::after {
|
|
content: '';
|
|
position: absolute; inset: 0;
|
|
width: var(--strength, 0%);
|
|
background: linear-gradient(90deg, var(--danger), var(--warning) 50%, var(--success));
|
|
transition: width var(--t-base);
|
|
}
|
|
|
|
input[type="range"] {
|
|
-webkit-appearance: none; appearance: none;
|
|
width: 100%; height: 4px;
|
|
background: var(--border);
|
|
border-radius: 2px;
|
|
}
|
|
input[type="range"]::-webkit-slider-thumb {
|
|
-webkit-appearance: none; appearance: none;
|
|
width: 16px; height: 16px;
|
|
background: var(--accent);
|
|
border-radius: 50%;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.check {
|
|
display: inline-flex; align-items: center; gap: 6px;
|
|
padding: 6px 10px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.check:has(input:checked) {
|
|
background: var(--accent-soft);
|
|
border-color: var(--accent);
|
|
color: var(--accent);
|
|
}
|
|
.check input { display: none; }
|
|
|
|
/* ---- 5. AUTH SCREEN -------------------------------------- */
|
|
|
|
.auth-screen {
|
|
position: fixed; inset: 0;
|
|
display: grid; place-items: center;
|
|
padding: 24px;
|
|
background:
|
|
radial-gradient(ellipse at top, var(--accent-soft), transparent 50%),
|
|
radial-gradient(ellipse at bottom right, rgba(167,139,250,0.08), transparent 50%),
|
|
var(--bg);
|
|
}
|
|
.auth-card {
|
|
width: 100%; max-width: 400px;
|
|
padding: 32px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow-lg);
|
|
}
|
|
.auth-brand { text-align: center; margin-bottom: 24px; }
|
|
.auth-brand-icon {
|
|
width: 40px; height: 40px;
|
|
padding: 10px;
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
border-radius: var(--radius);
|
|
margin-bottom: 12px;
|
|
}
|
|
.auth-brand h1 { font-size: 20px; font-weight: 600; margin: 0 0 4px; }
|
|
.auth-brand p { color: var(--text-dim); font-size: 13px; margin: 0; }
|
|
.auth-tabs {
|
|
display: flex;
|
|
padding: 4px;
|
|
background: var(--bg);
|
|
border-radius: var(--radius-sm);
|
|
margin-bottom: 20px;
|
|
}
|
|
.auth-tab {
|
|
flex: 1;
|
|
padding: 8px 12px;
|
|
background: transparent;
|
|
border: none;
|
|
border-radius: 6px;
|
|
color: var(--text-dim);
|
|
font-size: 13px; font-weight: 500;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.auth-tab.is-active {
|
|
background: var(--bg-elev);
|
|
color: var(--text);
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
}
|
|
.auth-form { display: flex; flex-direction: column; }
|
|
.auth-form .btn-block { margin-top: 8px; }
|
|
|
|
.auth-hint {
|
|
padding: 10px 12px;
|
|
margin-bottom: 14px;
|
|
background: var(--accent-soft);
|
|
border: 1px solid var(--accent);
|
|
border-radius: var(--radius-sm);
|
|
color: var(--accent);
|
|
font-size: 12px;
|
|
text-align: center;
|
|
}
|
|
.auth-hint:empty { display: none; }
|
|
|
|
/* Tag chip input */
|
|
.chip-input {
|
|
display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
|
|
padding: 6px 8px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
min-height: 38px;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.chip-input:focus-within {
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 3px var(--accent-soft);
|
|
background: var(--bg);
|
|
}
|
|
.chip-input input {
|
|
flex: 1;
|
|
min-width: 80px;
|
|
background: transparent;
|
|
border: none;
|
|
outline: none;
|
|
color: var(--text);
|
|
font-size: 13px;
|
|
padding: 2px 4px;
|
|
}
|
|
.chip {
|
|
display: inline-flex; align-items: center; gap: 4px;
|
|
padding: 2px 4px 2px 8px;
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
border-radius: 10px;
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
}
|
|
.chip button {
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
width: 16px; height: 16px;
|
|
background: transparent;
|
|
border: none;
|
|
border-radius: 50%;
|
|
color: inherit;
|
|
cursor: pointer;
|
|
opacity: 0.6;
|
|
}
|
|
.chip button:hover { opacity: 1; background: rgba(0,0,0,0.1); }
|
|
.chip button svg { width: 10px; height: 10px; }
|
|
|
|
/* Tag suggestions dropdown */
|
|
.chip-suggestions {
|
|
position: absolute;
|
|
z-index: 50;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
box-shadow: var(--shadow);
|
|
padding: 4px;
|
|
max-height: 200px;
|
|
overflow-y: auto;
|
|
min-width: 160px;
|
|
}
|
|
.chip-suggestion {
|
|
padding: 6px 10px;
|
|
border-radius: 6px;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
}
|
|
.chip-suggestion:hover, .chip-suggestion.is-active { background: var(--bg-elev-2); color: var(--text); }
|
|
.chip-suggestion-empty { padding: 6px 10px; color: var(--text-faint); font-size: 12px; }
|
|
|
|
/* Settings rows */
|
|
.setting-row {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
gap: 12px;
|
|
padding: 10px 12px;
|
|
background: var(--bg);
|
|
border: 1px solid var(--border-soft);
|
|
border-radius: var(--radius-sm);
|
|
margin-bottom: 6px;
|
|
font-size: 13px;
|
|
}
|
|
.setting-row > span { display: flex; flex-direction: column; gap: 2px; }
|
|
.setting-hint {
|
|
color: var(--text-faint);
|
|
font-size: 11px;
|
|
font-weight: normal;
|
|
line-height: 1.35;
|
|
max-width: 320px;
|
|
}
|
|
.setting-row select {
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: 6px;
|
|
color: var(--text);
|
|
padding: 4px 8px;
|
|
font-size: 12px;
|
|
}
|
|
.setting-row select:focus {
|
|
outline: none;
|
|
border-color: var(--accent);
|
|
}
|
|
|
|
/* iOS-style toggle switch */
|
|
.toggle {
|
|
position: relative;
|
|
display: inline-block;
|
|
width: 36px; height: 20px;
|
|
flex-shrink: 0;
|
|
}
|
|
.toggle input { opacity: 0; width: 0; height: 0; }
|
|
.toggle-slider {
|
|
position: absolute; inset: 0;
|
|
background: var(--bg-elev-2);
|
|
border: 1px solid var(--border);
|
|
border-radius: 12px;
|
|
cursor: pointer;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.toggle-slider::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 2px; top: 1px;
|
|
width: 14px; height: 14px;
|
|
background: var(--text-dim);
|
|
border-radius: 50%;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.toggle input:checked + .toggle-slider {
|
|
background: var(--accent);
|
|
border-color: var(--accent);
|
|
}
|
|
.toggle input:checked + .toggle-slider::before {
|
|
background: white;
|
|
transform: translateX(16px);
|
|
}
|
|
|
|
/* ---- 6. APP SHELL ---------------------------------------- */
|
|
|
|
.app-shell {
|
|
display: grid;
|
|
grid-template-columns: 240px 1fr;
|
|
height: 100vh;
|
|
background: var(--bg);
|
|
}
|
|
|
|
/* ---- 7. SIDEBAR ------------------------------------------ */
|
|
|
|
.sidebar {
|
|
display: flex; flex-direction: column;
|
|
padding: 16px 12px;
|
|
background: var(--bg-elev);
|
|
border-right: 1px solid var(--border);
|
|
overflow-y: auto;
|
|
}
|
|
.sidebar-brand {
|
|
display: flex; align-items: center; gap: 10px;
|
|
padding: 6px 8px 18px;
|
|
font-size: 15px; font-weight: 600;
|
|
}
|
|
.sidebar-brand svg { color: var(--accent); width: 18px; height: 18px; }
|
|
|
|
.sidebar-nav { display: flex; flex-direction: column; gap: 2px; }
|
|
.nav-item {
|
|
display: flex; align-items: center; gap: 10px;
|
|
padding: 7px 10px;
|
|
background: transparent;
|
|
border: none;
|
|
border-radius: 6px;
|
|
color: var(--text-dim);
|
|
font-size: 13px; font-weight: 500;
|
|
text-align: left;
|
|
width: 100%;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.nav-item:hover { background: var(--bg-elev-2); color: var(--text); }
|
|
.nav-item.is-active {
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
}
|
|
.nav-item.is-active svg { color: var(--accent); }
|
|
.nav-item svg { color: var(--text-faint); }
|
|
.nav-item > span:first-of-type { flex: 1; }
|
|
.nav-count {
|
|
font-size: 11px;
|
|
color: var(--text-faint);
|
|
background: var(--bg-elev-2);
|
|
padding: 1px 6px;
|
|
border-radius: 8px;
|
|
min-width: 18px;
|
|
text-align: center;
|
|
}
|
|
.nav-item.is-active .nav-count { background: var(--accent); color: white; }
|
|
|
|
.sidebar-section { margin-top: 18px; }
|
|
.sidebar-section-header {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 4px 10px 6px;
|
|
font-size: 11px; font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
color: var(--text-faint);
|
|
}
|
|
.section-toggle {
|
|
flex: 1;
|
|
display: flex; align-items: center; gap: 6px;
|
|
background: none; border: none; padding: 2px 0;
|
|
font: inherit; color: inherit; text-transform: inherit;
|
|
letter-spacing: inherit;
|
|
cursor: pointer;
|
|
text-align: left;
|
|
}
|
|
.section-toggle:hover { color: var(--text-dim); }
|
|
.section-count {
|
|
min-width: 16px;
|
|
padding: 1px 6px;
|
|
border-radius: 9px;
|
|
background: var(--bg);
|
|
color: var(--text-dim);
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
text-align: center;
|
|
letter-spacing: 0;
|
|
}
|
|
/* Push everything after the count toward the right of the toggle button
|
|
so the +/etc. action button stays at the row's edge. */
|
|
.section-toggle { gap: 6px; }
|
|
.section-chevron {
|
|
width: 12px; height: 12px;
|
|
transition: transform 0.18s ease;
|
|
flex-shrink: 0;
|
|
}
|
|
.sidebar-section.is-collapsed .section-chevron {
|
|
transform: rotate(-90deg);
|
|
}
|
|
.sidebar-section.is-collapsed .section-body {
|
|
display: none;
|
|
}
|
|
.sidebar-bottom {
|
|
margin-top: auto;
|
|
padding-top: 12px;
|
|
border-top: 1px solid var(--border-soft);
|
|
display: flex; flex-direction: column; gap: 2px;
|
|
}
|
|
|
|
.folder-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
|
.nav-item.drag-over {
|
|
background: var(--accent-soft);
|
|
box-shadow: inset 0 0 0 2px var(--accent);
|
|
}
|
|
|
|
/* ---- 8. MAIN --------------------------------------------- */
|
|
|
|
.main { display: flex; flex-direction: column; overflow: hidden; }
|
|
.topbar {
|
|
display: flex; align-items: center; gap: 12px;
|
|
padding: 12px 24px;
|
|
border-bottom: 1px solid var(--border);
|
|
background: var(--bg-glass);
|
|
backdrop-filter: var(--blur);
|
|
-webkit-backdrop-filter: var(--blur);
|
|
position: relative;
|
|
/* backdrop-filter creates a stacking context, so child z-indexes (e.g.
|
|
.user-dropdown : 50) are confined here. Without an explicit z-index
|
|
the topbar lands behind .slideover (z-index 30), clipping the
|
|
dropdown when an entry detail panel is open. 40 puts the topbar
|
|
(and its children) above the slideover; modals at 200+ still win. */
|
|
z-index: 40;
|
|
}
|
|
.search { flex: 1; max-width: 480px; position: relative; display: flex; align-items: center; }
|
|
.search svg {
|
|
position: absolute; left: 10px;
|
|
color: var(--text-faint);
|
|
pointer-events: none;
|
|
}
|
|
.search input {
|
|
width: 100%;
|
|
padding: 8px 60px 8px 34px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
color: var(--text);
|
|
transition: all var(--t-fast);
|
|
}
|
|
.search input:focus {
|
|
outline: none;
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 3px var(--accent-soft);
|
|
}
|
|
.search kbd { position: absolute; right: 8px; }
|
|
.topbar-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
|
|
|
|
/* View toggle (Cards / List) */
|
|
.view-toggle {
|
|
display: inline-flex;
|
|
padding: 2px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
}
|
|
.view-btn {
|
|
width: 28px; height: 28px;
|
|
display: grid; place-items: center;
|
|
background: transparent;
|
|
border: none;
|
|
border-radius: 6px;
|
|
color: var(--text-dim);
|
|
transition: all var(--t-fast);
|
|
}
|
|
.view-btn:hover { color: var(--text); }
|
|
.view-btn.is-active {
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
}
|
|
|
|
[data-theme="dark"] .theme-icon-light { display: none; }
|
|
[data-theme="light"] .theme-icon-dark { display: none; }
|
|
|
|
.user-menu { position: relative; }
|
|
.user-chip {
|
|
display: inline-flex; align-items: center; gap: 6px;
|
|
padding: 6px 12px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: 16px;
|
|
color: var(--text);
|
|
font-size: 12px;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.user-chip:hover { background: var(--bg-elev-2); }
|
|
.user-dropdown {
|
|
position: absolute; top: calc(100% + 6px); right: 0;
|
|
min-width: 180px;
|
|
padding: 4px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
box-shadow: var(--shadow);
|
|
z-index: 50;
|
|
}
|
|
.dropdown-item {
|
|
display: flex; align-items: center; gap: 8px;
|
|
width: 100%;
|
|
padding: 8px 10px;
|
|
background: transparent;
|
|
border: none;
|
|
border-radius: 6px;
|
|
color: var(--text);
|
|
font-size: 13px;
|
|
text-align: left;
|
|
}
|
|
.dropdown-item:hover { background: var(--bg-elev-2); }
|
|
.dropdown-item svg { color: var(--text-dim); }
|
|
|
|
.content { flex: 1; padding: 24px 32px; overflow-y: auto; }
|
|
.content-header { display: flex; align-items: baseline; gap: 12px; margin-bottom: 20px; }
|
|
.content-header h2 { font-size: 22px; font-weight: 600; margin: 0; }
|
|
.content-meta { color: var(--text-faint); font-size: 12px; }
|
|
|
|
/* ---- 9. ENTRY GRID --------------------------------------- */
|
|
|
|
.entry-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
gap: 12px;
|
|
position: relative;
|
|
user-select: none; /* avoid native text-selection during marquee */
|
|
}
|
|
|
|
/* Marquee rectangle for rubber-band selection */
|
|
|
|
.entry-card {
|
|
position: relative;
|
|
padding: 14px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
transition: all var(--t-fast);
|
|
cursor: pointer;
|
|
}
|
|
.entry-card:hover {
|
|
transform: translateY(-1px);
|
|
border-color: var(--accent);
|
|
box-shadow: var(--shadow);
|
|
}
|
|
.entry-card.is-selected {
|
|
border-color: var(--accent);
|
|
background: var(--accent-soft);
|
|
}
|
|
.entry-card.is-checked {
|
|
border-color: var(--accent);
|
|
background: var(--accent-soft);
|
|
box-shadow: inset 0 0 0 2px var(--accent);
|
|
}
|
|
|
|
/* === List view layout === */
|
|
/* Cards are flattened into a single horizontal row using flexbox + `order`.
|
|
`.entry-head` and `.entry-pw-row` get display:contents so their children
|
|
participate directly in the card flex container — no wrapping, ever. */
|
|
.entry-grid.is-list {
|
|
grid-template-columns: 1fr;
|
|
gap: 4px;
|
|
}
|
|
.entry-grid.is-list .entry-card {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 8px 12px;
|
|
}
|
|
.entry-grid.is-list .entry-card:hover { transform: none; }
|
|
|
|
.entry-grid.is-list .entry-head { display: contents; }
|
|
.entry-grid.is-list .entry-pw-row { display: contents; }
|
|
|
|
.entry-grid.is-list .entry-avatar {
|
|
order: 1;
|
|
width: 28px; height: 28px;
|
|
font-size: 12px;
|
|
margin: 0;
|
|
}
|
|
.entry-grid.is-list .entry-title {
|
|
order: 2;
|
|
flex: 1;
|
|
min-width: 0;
|
|
display: flex; flex-direction: column;
|
|
}
|
|
.entry-grid.is-list .entry-title b { font-size: 13px; }
|
|
.entry-grid.is-list .entry-title small { font-size: 11px; }
|
|
|
|
.entry-grid.is-list .entry-pw {
|
|
order: 3;
|
|
font-size: 11px;
|
|
width: 110px;
|
|
flex-shrink: 0;
|
|
padding: 4px 8px;
|
|
background: var(--bg);
|
|
border-radius: 6px;
|
|
border: 1px solid var(--border-soft);
|
|
}
|
|
.entry-grid.is-list .entry-pw-row .icon-btn {
|
|
order: 4;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.entry-grid.is-list .entry-meta {
|
|
order: 5;
|
|
margin: 0;
|
|
flex-shrink: 0;
|
|
max-width: 220px;
|
|
overflow: hidden;
|
|
flex-wrap: nowrap;
|
|
}
|
|
.entry-grid.is-list .entry-meta .entry-chip {
|
|
flex-shrink: 0;
|
|
font-size: 10px;
|
|
}
|
|
|
|
/* Right-side action buttons: favorite + delete (normal view),
|
|
restore + purge (trash view), or kebab (compact mode). Same order slot. */
|
|
.entry-grid.is-list .entry-fav,
|
|
.entry-grid.is-list .entry-del,
|
|
.entry-grid.is-list .entry-dup,
|
|
.entry-grid.is-list .entry-kebab-wrap,
|
|
.entry-grid.is-list .entry-head .icon-btn {
|
|
order: 6;
|
|
flex-shrink: 0;
|
|
}
|
|
/* Selection checkbox overlay — nested INSIDE the avatar (.entry-avatar
|
|
is position:relative) so it covers the avatar 1:1, no overlap with the
|
|
avatar's footprint. Hidden by default; appears on card hover OR when
|
|
the entry is already checked. The avatar's initials stay visible
|
|
underneath through the checkbox's transparent-then-solid transition. */
|
|
.entry-check {
|
|
position: absolute;
|
|
inset: 0;
|
|
display: grid; place-items: center;
|
|
background: var(--bg);
|
|
border: 1.5px solid var(--accent);
|
|
border-radius: var(--radius-sm);
|
|
color: var(--text);
|
|
font-size: 14px;
|
|
line-height: 1;
|
|
cursor: pointer;
|
|
opacity: 0;
|
|
transition: opacity var(--t-fast),
|
|
background var(--t-fast), border-color var(--t-fast);
|
|
z-index: 2;
|
|
}
|
|
.entry-card:hover .entry-check,
|
|
.entry-check.is-checked {
|
|
opacity: 1;
|
|
}
|
|
.entry-check.is-checked {
|
|
background: var(--accent);
|
|
border-color: var(--accent);
|
|
color: white;
|
|
}
|
|
/* Standalone variant used in the table view's check column. The default
|
|
rule above is absolute+inset:0 so the box sizes itself from its avatar
|
|
parent (card view). When the checkbox lives on its own in a <td>, no
|
|
parent provides a size and the box collapses to a thin line. This
|
|
modifier restores explicit dimensions and always-on visibility. */
|
|
.entry-check.entry-check-static {
|
|
position: static;
|
|
width: 18px; height: 18px;
|
|
border-radius: 4px;
|
|
border-width: 1.5px;
|
|
opacity: 1;
|
|
font-size: 11px;
|
|
}
|
|
|
|
/* Batch action bar (appears when selection is non-empty) */
|
|
.batch-bar {
|
|
position: sticky;
|
|
top: -1px;
|
|
z-index: 10;
|
|
display: flex; align-items: center; gap: 8px;
|
|
padding: 10px 14px;
|
|
margin-bottom: 16px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--accent);
|
|
border-radius: var(--radius);
|
|
box-shadow: var(--shadow);
|
|
animation: toastIn var(--t-base);
|
|
}
|
|
.batch-bar-count {
|
|
font-weight: 600;
|
|
color: var(--accent);
|
|
margin-right: 8px;
|
|
}
|
|
.batch-bar select {
|
|
background: var(--bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 6px;
|
|
color: var(--text);
|
|
padding: 4px 8px;
|
|
font-size: 12px;
|
|
}
|
|
.batch-bar .grow { flex: 1; }
|
|
|
|
.entry-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
|
|
.entry-avatar {
|
|
position: relative; /* anchor for .entry-check overlay */
|
|
width: 32px; height: 32px;
|
|
display: grid; place-items: center;
|
|
background: var(--bg-elev-2);
|
|
border-radius: var(--radius-sm);
|
|
font-weight: 600; font-size: 14px;
|
|
color: var(--text);
|
|
flex-shrink: 0;
|
|
overflow: hidden;
|
|
}
|
|
.entry-avatar-img {
|
|
width: 100%; height: 100%;
|
|
object-fit: contain;
|
|
padding: 4px;
|
|
box-sizing: border-box;
|
|
image-rendering: -webkit-optimize-contrast; /* sharper 16x16 icons */
|
|
}
|
|
.entry-title { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
|
.entry-title b {
|
|
font-size: 14px; font-weight: 600;
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
}
|
|
.entry-title small {
|
|
color: var(--text-dim);
|
|
font-size: 12px;
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
}
|
|
.entry-fav, .entry-del, .entry-dup {
|
|
color: var(--text-faint);
|
|
background: transparent; border: none;
|
|
padding: 4px;
|
|
transition: all var(--t-fast);
|
|
cursor: pointer;
|
|
}
|
|
.entry-fav.is-on { color: var(--warning); }
|
|
.entry-fav:hover { color: var(--warning); transform: scale(1.1); }
|
|
.entry-dup {
|
|
color: var(--text-dim);
|
|
opacity: 0;
|
|
}
|
|
.entry-card:hover .entry-dup { opacity: 0.8; }
|
|
.entry-dup:hover {
|
|
opacity: 1;
|
|
color: var(--accent);
|
|
background: var(--accent-soft);
|
|
border-radius: 6px;
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
/* Delete button — always visible, brightens on hover */
|
|
.entry-del {
|
|
color: var(--text-dim);
|
|
opacity: 0.8;
|
|
}
|
|
.entry-del:hover {
|
|
opacity: 1;
|
|
color: var(--danger);
|
|
background: var(--danger-soft);
|
|
border-radius: 6px;
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
/* Username row with inline copy button (visible on card hover) */
|
|
.entry-user-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
}
|
|
.entry-user-row > span {
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
}
|
|
.entry-copy-user {
|
|
background: transparent; border: none;
|
|
padding: 2px;
|
|
color: var(--text-faint);
|
|
opacity: 0;
|
|
cursor: pointer;
|
|
transition: all var(--t-fast);
|
|
border-radius: 4px;
|
|
}
|
|
.entry-copy-user svg { width: 11px; height: 11px; }
|
|
.entry-card:hover .entry-copy-user { opacity: 0.7; }
|
|
.entry-copy-user:hover {
|
|
opacity: 1 !important;
|
|
color: var(--accent);
|
|
background: var(--accent-soft);
|
|
}
|
|
|
|
/* Kebab (⋯) menu */
|
|
.entry-kebab-wrap {
|
|
position: relative;
|
|
}
|
|
.entry-kebab {
|
|
background: transparent; border: none;
|
|
padding: 4px;
|
|
color: var(--text-dim);
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.entry-kebab:hover { color: var(--text); background: var(--bg-elev-2); }
|
|
|
|
.entry-kebab-menu {
|
|
position: absolute;
|
|
top: calc(100% + 4px);
|
|
right: 0;
|
|
min-width: 180px;
|
|
padding: 4px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
box-shadow: var(--shadow);
|
|
z-index: 60;
|
|
display: none;
|
|
animation: modalIn var(--t-fast);
|
|
}
|
|
.entry-kebab-menu.is-open { display: block; }
|
|
/* Lift the card containing an open kebab menu above its siblings so the
|
|
dropdown isn't clipped by the next card in DOM order. */
|
|
.entry-card:has(.entry-kebab-menu.is-open) { z-index: 100; }
|
|
.entry-row:has(.entry-kebab-menu.is-open) { position: relative; z-index: 100; }
|
|
|
|
.kebab-item {
|
|
display: flex; align-items: center; gap: 10px;
|
|
width: 100%;
|
|
padding: 8px 10px;
|
|
background: transparent;
|
|
border: none;
|
|
border-radius: 6px;
|
|
color: var(--text);
|
|
font-size: 13px;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.kebab-item:hover { background: var(--bg-elev-2); }
|
|
.kebab-item svg { color: var(--text-dim); }
|
|
.kebab-item.is-danger { color: var(--danger); }
|
|
.kebab-item.is-danger:hover { background: var(--danger-soft); }
|
|
.kebab-item.is-danger svg { color: var(--danger); }
|
|
|
|
.entry-pw-row {
|
|
display: flex; align-items: center; gap: 6px;
|
|
padding: 6px 8px;
|
|
background: var(--bg);
|
|
border: 1px solid var(--border-soft);
|
|
border-radius: 6px;
|
|
margin-bottom: 8px;
|
|
}
|
|
.entry-pw {
|
|
flex: 1;
|
|
font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
|
|
font-size: 12px;
|
|
color: var(--text-dim);
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
user-select: none;
|
|
}
|
|
.entry-pw.is-revealed { color: var(--text); }
|
|
.entry-pw.is-error { color: var(--danger); }
|
|
|
|
.entry-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
|
.entry-chip {
|
|
display: inline-flex; align-items: center; gap: 4px;
|
|
padding: 2px 8px;
|
|
background: var(--bg-elev-2);
|
|
border-radius: 10px;
|
|
font-size: 11px;
|
|
color: var(--text-dim);
|
|
}
|
|
.entry-chip svg { width: 11px; height: 11px; }
|
|
.entry-chip.is-folder { color: var(--accent); background: var(--accent-soft); }
|
|
.entry-chip.is-pwned {
|
|
color: #fff;
|
|
background: #dc2626; /* solid red — high-attention signal */
|
|
font-weight: 600;
|
|
}
|
|
.entry-chip.is-pwned svg { stroke: #fff; }
|
|
.entry-chip.is-2fa {
|
|
color: var(--accent);
|
|
background: var(--accent-soft);
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* TOTP live-code panel (inside slide-over Two-factor field) */
|
|
.totp-panel {
|
|
display: flex; align-items: center; gap: 12px;
|
|
margin-top: 8px;
|
|
padding: 10px 12px;
|
|
background: var(--bg);
|
|
border: 1px solid var(--border-soft);
|
|
border-radius: var(--radius-sm);
|
|
min-height: 36px;
|
|
}
|
|
.totp-code {
|
|
flex: 1;
|
|
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
|
font-size: 22px;
|
|
letter-spacing: 2px;
|
|
color: var(--accent);
|
|
font-weight: 600;
|
|
user-select: all; /* triple-click selects the code */
|
|
}
|
|
.totp-code.is-invalid {
|
|
color: var(--text-faint);
|
|
font-size: 13px;
|
|
letter-spacing: normal;
|
|
font-style: italic;
|
|
font-weight: normal;
|
|
}
|
|
.totp-bar-wrap {
|
|
margin-top: 4px;
|
|
height: 3px;
|
|
background: var(--bg);
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
}
|
|
.totp-bar {
|
|
height: 100%;
|
|
background: var(--accent);
|
|
width: 0%;
|
|
transition: width 0.8s linear, background 0.2s;
|
|
}
|
|
|
|
/* ---- Authenticator view (TOTP grid) ---------------------- */
|
|
.entry-grid.is-auth {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
gap: 12px;
|
|
}
|
|
.auth-card {
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
padding: 14px 16px;
|
|
cursor: pointer;
|
|
transition: border-color 0.15s, transform 0.05s;
|
|
}
|
|
.auth-card:hover { border-color: var(--accent); }
|
|
.auth-card:active { transform: scale(0.99); }
|
|
.auth-card-head { margin-bottom: 8px; }
|
|
.auth-card-title {
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
font-size: 14px;
|
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
}
|
|
.auth-card-sub {
|
|
font-size: 12px;
|
|
color: var(--text-dim);
|
|
margin-top: 2px;
|
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
}
|
|
.auth-card-code-row {
|
|
display: flex; align-items: center; gap: 8px;
|
|
}
|
|
.auth-card-code {
|
|
flex: 1;
|
|
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
|
font-size: 26px;
|
|
letter-spacing: 3px;
|
|
color: var(--accent);
|
|
font-weight: 600;
|
|
user-select: all;
|
|
}
|
|
.auth-card-bar-wrap {
|
|
margin-top: 8px;
|
|
height: 3px;
|
|
background: var(--bg);
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
}
|
|
.auth-card-bar {
|
|
height: 100%;
|
|
background: var(--accent);
|
|
width: 100%;
|
|
transition: width 0.8s linear, background 0.2s;
|
|
}
|
|
.auth-card-bar.is-warning { background: #f59e0b; }
|
|
|
|
/* ---- Vault health dashboard ----------------------------- */
|
|
.entry-grid.is-health {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
}
|
|
.health-loading {
|
|
color: var(--text-dim);
|
|
text-align: center;
|
|
padding: 40px;
|
|
font-size: 14px;
|
|
}
|
|
.health-header {
|
|
display: flex; align-items: center; gap: 20px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
padding: 20px;
|
|
}
|
|
.health-score {
|
|
width: 110px; height: 110px;
|
|
border-radius: 50%;
|
|
display: flex; flex-direction: column;
|
|
align-items: center; justify-content: center;
|
|
flex-shrink: 0;
|
|
border: 4px solid var(--accent);
|
|
background: var(--bg);
|
|
}
|
|
.health-score.is-ok { border-color: #10b981; color: #10b981; }
|
|
.health-score.is-fair { border-color: var(--accent); color: var(--accent); }
|
|
.health-score.is-warn { border-color: #f59e0b; color: #f59e0b; }
|
|
.health-score.is-danger { border-color: #ef4444; color: #ef4444; }
|
|
.health-score-num {
|
|
font-size: 36px; font-weight: 700;
|
|
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
|
}
|
|
.health-score-lbl {
|
|
font-size: 11px; font-weight: 600;
|
|
text-transform: uppercase; letter-spacing: 0.5px;
|
|
margin-top: 2px;
|
|
}
|
|
.health-intro { flex: 1; }
|
|
.health-intro h3 { margin: 0 0 6px; font-size: 16px; }
|
|
.health-intro p {
|
|
margin: 0 0 10px;
|
|
color: var(--text-dim);
|
|
font-size: 13px;
|
|
line-height: 1.5;
|
|
}
|
|
.health-card {
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
padding: 16px 18px;
|
|
}
|
|
.health-card-head {
|
|
display: flex; align-items: center; gap: 10px;
|
|
margin-bottom: 6px;
|
|
}
|
|
.health-card-head h4 {
|
|
margin: 0;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
}
|
|
.health-badge {
|
|
min-width: 22px;
|
|
padding: 2px 8px;
|
|
border-radius: 11px;
|
|
background: var(--accent);
|
|
color: white;
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
text-align: center;
|
|
}
|
|
.health-badge.is-empty {
|
|
background: var(--bg);
|
|
color: var(--text-dim);
|
|
}
|
|
.health-hint {
|
|
margin: 0 0 10px;
|
|
font-size: 12px;
|
|
color: var(--text-dim);
|
|
line-height: 1.4;
|
|
}
|
|
.health-empty {
|
|
margin: 0;
|
|
font-size: 12px;
|
|
color: var(--text-faint);
|
|
font-style: italic;
|
|
}
|
|
.health-list {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
display: flex; flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
.health-item {
|
|
display: flex; align-items: center; gap: 8px;
|
|
padding: 6px 10px;
|
|
background: var(--bg);
|
|
border-radius: var(--radius-sm);
|
|
font-size: 13px;
|
|
}
|
|
.health-item-label {
|
|
flex: 1;
|
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
color: var(--text);
|
|
}
|
|
.health-more {
|
|
margin: 6px 0 0;
|
|
color: var(--text-faint);
|
|
font-size: 11px;
|
|
font-style: italic;
|
|
text-align: center;
|
|
}
|
|
.health-more-btn {
|
|
display: block;
|
|
margin: 8px auto 0;
|
|
}
|
|
|
|
/* ---- Slideover custom icon field ------------------------ */
|
|
.so-icon-field {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
.so-icon-preview {
|
|
width: 56px; height: 56px;
|
|
display: grid; place-items: center;
|
|
background: var(--bg-elev-2);
|
|
border-radius: var(--radius-sm);
|
|
overflow: hidden;
|
|
font-weight: 600;
|
|
font-size: 20px;
|
|
color: var(--text);
|
|
flex-shrink: 0;
|
|
}
|
|
.so-icon-preview img {
|
|
width: 100%; height: 100%;
|
|
object-fit: contain;
|
|
padding: 6px;
|
|
box-sizing: border-box;
|
|
}
|
|
.so-icon-actions {
|
|
display: flex; flex-direction: column; gap: 6px;
|
|
}
|
|
|
|
/* ---- Quick search modal (tray menu) ------------------ */
|
|
.quick-search-panel {
|
|
padding: 0;
|
|
overflow: hidden;
|
|
max-width: 520px;
|
|
width: 100%;
|
|
}
|
|
.quick-search-input {
|
|
display: flex; align-items: center; gap: 10px;
|
|
padding: 14px 18px;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
.quick-search-input svg {
|
|
width: 18px; height: 18px;
|
|
color: var(--text-dim);
|
|
flex-shrink: 0;
|
|
}
|
|
.quick-search-input input {
|
|
flex: 1;
|
|
background: transparent;
|
|
border: none;
|
|
color: var(--text);
|
|
font-size: 15px;
|
|
outline: none;
|
|
}
|
|
.quick-search-input kbd {
|
|
font-size: 10px;
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
background: var(--bg);
|
|
color: var(--text-dim);
|
|
border: 1px solid var(--border);
|
|
}
|
|
.quick-search-results {
|
|
max-height: 360px;
|
|
overflow-y: auto;
|
|
padding: 6px 0;
|
|
}
|
|
.quick-search-row {
|
|
display: flex; align-items: center; gap: 10px;
|
|
padding: 8px 18px;
|
|
cursor: pointer;
|
|
}
|
|
.quick-search-row.is-selected {
|
|
background: var(--accent-soft);
|
|
}
|
|
.quick-search-row:hover { background: var(--accent-soft); }
|
|
.quick-search-avatar {
|
|
width: 32px; height: 32px;
|
|
border-radius: var(--radius-sm);
|
|
background: var(--bg-elev-2);
|
|
display: grid; place-items: center;
|
|
overflow: hidden;
|
|
font-weight: 600;
|
|
font-size: 13px;
|
|
flex-shrink: 0;
|
|
}
|
|
.quick-search-avatar img {
|
|
width: 100%; height: 100%;
|
|
object-fit: contain;
|
|
padding: 4px;
|
|
box-sizing: border-box;
|
|
}
|
|
.quick-search-main {
|
|
flex: 1; min-width: 0;
|
|
}
|
|
.quick-search-name {
|
|
font-size: 14px; font-weight: 600;
|
|
color: var(--text);
|
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
}
|
|
.quick-search-sub {
|
|
font-size: 12px;
|
|
color: var(--text-dim);
|
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
}
|
|
.quick-search-empty {
|
|
padding: 24px 18px;
|
|
text-align: center;
|
|
color: var(--text-dim);
|
|
font-size: 13px;
|
|
font-style: italic;
|
|
}
|
|
.quick-search-hint {
|
|
border-top: 1px solid var(--border);
|
|
padding: 8px 18px;
|
|
font-size: 11px;
|
|
color: var(--text-faint);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* Slideover title — tint the "+ New entry" prefix in accent colour so
|
|
the mode is unambiguous without changing the header layout. */
|
|
#slideoverTitle.is-new-mode { color: var(--accent); }
|
|
#slideoverTitle.is-edit-mode { color: var(--text); }
|
|
.btn-xs {
|
|
font-size: 11px;
|
|
padding: 3px 10px;
|
|
}
|
|
|
|
/* Brief attention pulse on the slideover generator button after Fix */
|
|
@keyframes attentionPulse {
|
|
0%, 100% { box-shadow: 0 0 0 0 var(--accent); }
|
|
50% { box-shadow: 0 0 0 6px transparent; }
|
|
}
|
|
.icon-btn.is-pulse {
|
|
animation: attentionPulse 0.7s ease-out 3;
|
|
border-radius: var(--radius-sm);
|
|
}
|
|
|
|
/* ---- 10. SLIDE-OVER -------------------------------------- */
|
|
|
|
.slideover {
|
|
position: fixed; top: 0; right: 0; bottom: 0;
|
|
width: 420px;
|
|
background: var(--bg-elev);
|
|
border-left: 1px solid var(--border);
|
|
box-shadow: var(--shadow-lg);
|
|
transform: translateX(100%);
|
|
transition: transform var(--t-base);
|
|
display: flex; flex-direction: column;
|
|
/* Above the topbar (z-index 40) — otherwise the topbar's
|
|
backdrop-filter stacking context clips the slideover header
|
|
(where the title / close button live) under it. */
|
|
z-index: 50;
|
|
}
|
|
.slideover.is-open { transform: translateX(0); }
|
|
.slideover-header {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 16px 20px;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
.slideover-header h3 {
|
|
font-size: 15px; font-weight: 600;
|
|
margin: 0;
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
}
|
|
.slideover-body { padding: 20px; overflow-y: auto; flex: 1; }
|
|
.slideover-field { margin-bottom: 16px; }
|
|
.slideover-field-label { font-size: 11px; font-weight: 500; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; }
|
|
.slideover-field-value {
|
|
display: flex; align-items: center; gap: 6px;
|
|
padding: 10px 12px;
|
|
background: var(--bg);
|
|
border: 1px solid var(--border-soft);
|
|
border-radius: var(--radius-sm);
|
|
font-size: 13px;
|
|
word-break: break-all;
|
|
}
|
|
.so-input {
|
|
width: 100%;
|
|
padding: 10px 12px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
color: var(--text);
|
|
font-size: 13px;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.so-input:focus {
|
|
outline: none;
|
|
border-color: var(--accent);
|
|
background: var(--bg);
|
|
box-shadow: 0 0 0 3px var(--accent-soft);
|
|
}
|
|
.so-pw-row {
|
|
display: flex; align-items: center; gap: 4px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
padding: 2px 4px 2px 10px;
|
|
}
|
|
.so-pw-row:focus-within {
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 3px var(--accent-soft);
|
|
}
|
|
.so-pw-row .so-input {
|
|
background: transparent;
|
|
border: none;
|
|
padding: 8px 4px;
|
|
}
|
|
.so-pw-row .so-input:focus { box-shadow: none; }
|
|
.slideover-actions { display: flex; gap: 8px; margin-top: 24px; }
|
|
|
|
/* ---- 11. MODALS ------------------------------------------ */
|
|
|
|
.modal {
|
|
position: fixed; inset: 0;
|
|
z-index: 100;
|
|
display: grid; place-items: center;
|
|
padding: 24px;
|
|
}
|
|
.modal-backdrop {
|
|
position: absolute; inset: 0;
|
|
background: rgba(0,0,0,0.5);
|
|
backdrop-filter: blur(4px);
|
|
}
|
|
.modal-panel {
|
|
position: relative;
|
|
width: 100%; max-width: 480px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow-lg);
|
|
overflow: hidden;
|
|
animation: modalIn var(--t-base);
|
|
}
|
|
.modal-panel-sm { max-width: 360px; }
|
|
@keyframes modalIn {
|
|
from { opacity: 0; transform: scale(0.96) translateY(8px); }
|
|
to { opacity: 1; transform: scale(1) translateY(0); }
|
|
}
|
|
.modal-header {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 16px 20px;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
.modal-header h3 { font-size: 15px; font-weight: 600; margin: 0; }
|
|
.modal-body { padding: 20px; }
|
|
.modal-footer {
|
|
display: flex; gap: 8px; justify-content: flex-end;
|
|
padding: 14px 20px;
|
|
background: var(--bg);
|
|
border-top: 1px solid var(--border);
|
|
}
|
|
|
|
.gen-preview {
|
|
padding: 12px;
|
|
background: var(--bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 13px;
|
|
word-break: break-all;
|
|
margin-bottom: 16px;
|
|
min-height: 42px;
|
|
display: flex; align-items: center;
|
|
}
|
|
.gen-options { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
|
|
|
|
/* ---- 12. COMMAND PALETTE -------------------------------- */
|
|
|
|
.cmd-palette {
|
|
position: fixed; inset: 0;
|
|
z-index: 200;
|
|
display: grid; place-items: start center;
|
|
padding-top: 15vh;
|
|
}
|
|
.cmd-panel {
|
|
position: relative;
|
|
width: 100%; max-width: 560px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow-lg);
|
|
overflow: hidden;
|
|
animation: modalIn var(--t-base);
|
|
}
|
|
.cmd-input {
|
|
display: flex; align-items: center; gap: 10px;
|
|
padding: 14px 16px;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
.cmd-input svg { color: var(--text-faint); }
|
|
.cmd-input input {
|
|
flex: 1;
|
|
background: transparent; border: none; outline: none;
|
|
color: var(--text);
|
|
font-size: 15px;
|
|
}
|
|
.cmd-results { max-height: 360px; overflow-y: auto; padding: 8px; }
|
|
.cmd-item {
|
|
display: flex; align-items: center; gap: 10px;
|
|
padding: 10px 12px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
color: var(--text);
|
|
font-size: 13px;
|
|
}
|
|
.cmd-item:hover, .cmd-item.is-active { background: var(--bg-elev-2); }
|
|
|
|
/* ---- 13. EMPTY STATE ------------------------------------ */
|
|
|
|
.empty-state {
|
|
display: flex; flex-direction: column; align-items: center; gap: 8px;
|
|
padding: 80px 20px;
|
|
color: var(--text-dim);
|
|
animation: fadeIn var(--t-base);
|
|
}
|
|
.empty-illustration {
|
|
width: 140px; height: 140px;
|
|
margin-bottom: 12px;
|
|
}
|
|
.empty-icon {
|
|
width: 48px; height: 48px;
|
|
padding: 12px;
|
|
background: var(--bg-elev);
|
|
border-radius: var(--radius);
|
|
color: var(--text-faint);
|
|
}
|
|
.empty-state h3 { margin: 8px 0 0; font-size: 18px; color: var(--text); font-weight: 600; }
|
|
.empty-state p { margin: 0; font-size: 13px; max-width: 320px; text-align: center; }
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(8px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
/* ---- Skeleton loaders ----------------------------------- */
|
|
.skeleton-card {
|
|
padding: 14px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
.skeleton-card::after {
|
|
content: '';
|
|
position: absolute; inset: 0;
|
|
background: linear-gradient(90deg, transparent, var(--bg-elev-2), transparent);
|
|
animation: shimmer 1.4s infinite;
|
|
}
|
|
.skeleton-line {
|
|
height: 12px;
|
|
background: var(--bg-elev-2);
|
|
border-radius: 4px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.skeleton-line.w-40 { width: 40%; }
|
|
.skeleton-line.w-60 { width: 60%; }
|
|
.skeleton-line.w-80 { width: 80%; }
|
|
.skeleton-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
|
|
.skeleton-circle {
|
|
width: 32px; height: 32px;
|
|
background: var(--bg-elev-2);
|
|
border-radius: var(--radius-sm);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
@keyframes shimmer {
|
|
from { transform: translateX(-100%); }
|
|
to { transform: translateX(100%); }
|
|
}
|
|
|
|
/* ---- Idle warning ---------------------------------------- */
|
|
.idle-warning {
|
|
position: fixed;
|
|
top: 50%; left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
z-index: 400;
|
|
width: 320px;
|
|
padding: 24px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--warning);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow-lg);
|
|
text-align: center;
|
|
animation: modalIn var(--t-base);
|
|
}
|
|
.idle-warning .idle-icon {
|
|
width: 36px; height: 36px;
|
|
padding: 8px;
|
|
background: rgba(245,158,11,0.12);
|
|
color: var(--warning);
|
|
border-radius: 50%;
|
|
margin: 0 auto 8px;
|
|
display: block;
|
|
}
|
|
.idle-warning h3 { font-size: 16px; font-weight: 600; margin: 0 0 4px; }
|
|
.idle-warning p { color: var(--text-dim); font-size: 13px; margin: 0 0 16px; }
|
|
.idle-warning b { color: var(--warning); font-size: 20px; }
|
|
|
|
/* ---- 14. TOASTS ----------------------------------------- */
|
|
|
|
.toast-container {
|
|
position: fixed; bottom: 20px; right: 20px;
|
|
z-index: 300;
|
|
display: flex; flex-direction: column-reverse; gap: 8px;
|
|
pointer-events: none;
|
|
}
|
|
.toast {
|
|
pointer-events: auto;
|
|
display: flex; align-items: center; gap: 8px;
|
|
padding: 10px 14px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-left: 3px solid var(--accent);
|
|
border-radius: var(--radius-sm);
|
|
box-shadow: var(--shadow);
|
|
font-size: 13px;
|
|
min-width: 240px;
|
|
animation: toastIn var(--t-base);
|
|
}
|
|
.toast.is-success { border-left-color: var(--success); }
|
|
.toast.is-error { border-left-color: var(--danger); }
|
|
.toast.is-warning { border-left-color: var(--warning); }
|
|
@keyframes toastIn {
|
|
from { opacity: 0; transform: translateX(20px); }
|
|
to { opacity: 1; transform: translateX(0); }
|
|
}
|
|
|
|
/* ---- 15. SCROLLBARS ------------------------------------- */
|
|
|
|
::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
::-webkit-scrollbar-track { background: transparent; }
|
|
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
|
|
::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
|
|
|
|
/* ---- 16. RESPONSIVE ------------------------------------- */
|
|
|
|
@media (max-width: 900px) {
|
|
.app-shell { grid-template-columns: 60px 1fr; }
|
|
.sidebar { padding: 12px 6px; }
|
|
.sidebar-brand span,
|
|
.nav-item > span:first-of-type,
|
|
.nav-count,
|
|
.sidebar-section-header { display: none; }
|
|
.nav-item { justify-content: center; padding: 8px; }
|
|
.topbar { padding: 12px 16px; }
|
|
.content { padding: 16px; }
|
|
.slideover { width: 100%; }
|
|
}
|
|
|
|
/* ---- 17. AUTOFILL PICKER -------------------------------- */
|
|
|
|
.autofill-pick-btn {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
width: 100%;
|
|
padding: 10px 16px;
|
|
background: none;
|
|
border: none;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
transition: background var(--t-fast);
|
|
}
|
|
.autofill-pick-btn:hover { background: var(--bg-elev-2); }
|
|
.autofill-pick-site {
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
color: var(--text);
|
|
}
|
|
.autofill-pick-user {
|
|
font-size: 11px;
|
|
color: var(--text-dim);
|
|
}
|
|
|
|
/* ---- Hotkey capture buttons (Settings → Autofill) ---- */
|
|
.hotkey-capture-btn {
|
|
font-family: ui-monospace, "Cascadia Code", Menlo, monospace;
|
|
font-size: 11px;
|
|
min-width: 140px;
|
|
text-align: center;
|
|
}
|
|
.hotkey-capture-btn.is-capturing {
|
|
background: var(--accent);
|
|
color: var(--accent-fg, #fff);
|
|
animation: pulse-capture 1.2s ease-in-out infinite;
|
|
}
|
|
@keyframes pulse-capture {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.6; }
|
|
}
|
|
|
|
/* ---- Card display title + subtitle (when entry.title set) ---- */
|
|
.entry-subtitle {
|
|
display: block;
|
|
font-size: 11px;
|
|
color: var(--text-faint);
|
|
margin-top: 1px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* ---- Sidebar "(no folder)" pseudo-entry ---- */
|
|
.nav-item.is-uncategorized {
|
|
color: var(--text-faint);
|
|
font-style: italic;
|
|
}
|
|
.nav-item.is-uncategorized:hover { color: var(--text-dim); }
|
|
.nav-item.is-uncategorized.is-active { color: var(--text); font-style: normal; }
|
|
/* Spacer occupies the same footprint as the SVG folder icon so labels
|
|
stay vertically aligned across real-folder rows and "(no folder)". */
|
|
.nav-icon-spacer {
|
|
display: inline-block;
|
|
width: 16px;
|
|
height: 16px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* ============================================================
|
|
Table view
|
|
============================================================ */
|
|
.entry-grid.is-table { display: block; padding: 0; }
|
|
.entry-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 13px;
|
|
}
|
|
.entry-table thead th {
|
|
text-align: left;
|
|
font-weight: 500;
|
|
font-size: 11px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
color: var(--text-faint);
|
|
padding: 10px 12px;
|
|
border-bottom: 1px solid var(--border);
|
|
background: var(--bg-elev);
|
|
user-select: none;
|
|
position: sticky; top: 0;
|
|
z-index: 1;
|
|
}
|
|
.entry-table th.is-sortable { cursor: pointer; }
|
|
.entry-table th.is-sortable:hover { color: var(--text-dim); }
|
|
.entry-table th.is-active { color: var(--accent); }
|
|
.entry-table th .sort-arrow {
|
|
margin-left: 4px;
|
|
font-size: 10px;
|
|
vertical-align: middle;
|
|
}
|
|
.entry-table tbody td {
|
|
padding: 8px 12px;
|
|
border-bottom: 1px solid var(--border-soft);
|
|
color: var(--text);
|
|
vertical-align: middle;
|
|
}
|
|
.entry-row { cursor: pointer; transition: background var(--t-fast); }
|
|
.entry-row:hover { background: var(--bg-elev); }
|
|
.entry-row.is-selected { background: var(--accent-soft); }
|
|
.entry-row.is-checked { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }
|
|
.col-check { width: 36px; }
|
|
.col-name { min-width: 180px; }
|
|
.col-name .entry-avatar-sm {
|
|
width: 22px; height: 22px;
|
|
display: inline-grid; place-items: center;
|
|
font-size: 10px;
|
|
margin-right: 8px;
|
|
vertical-align: middle;
|
|
}
|
|
.col-name .cell-name-wrap { display: inline-flex; align-items: center; gap: 6px; }
|
|
.col-name .fav-dot { color: var(--warning); font-size: 12px; }
|
|
.col-site, .col-user { color: var(--text-dim); }
|
|
.col-site { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.col-user { max-width: 200px; }
|
|
.col-user .icon-btn { margin-left: 4px; opacity: 0; transition: opacity var(--t-fast); }
|
|
.entry-row:hover .col-user .icon-btn { opacity: 0.7; }
|
|
.col-folder { color: var(--text-dim); white-space: nowrap; }
|
|
.col-updated { color: var(--text-faint); white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
.col-actions { width: 80px; text-align: right; white-space: nowrap; }
|
|
.col-actions .icon-btn { opacity: 0; transition: opacity var(--t-fast); }
|
|
.entry-row:hover .col-actions .icon-btn { opacity: 0.7; }
|
|
.col-actions .entry-kebab-wrap { display: inline-block; vertical-align: middle; }
|
|
|
|
/* Hide Edge/IE native password reveal eye (we ship our own toggle). */
|
|
input[type="password"]::-ms-reveal,
|
|
input[type="password"]::-ms-clear {
|
|
display: none !important;
|
|
width: 0;
|
|
height: 0;
|
|
}
|
|
|
|
/* Login screen pw toggle — only one action button, override the
|
|
2-buttons layout from .input-with-action. */
|
|
.input-with-action:has(> .icon-btn:only-of-type) input {
|
|
padding-right: 40px;
|
|
}
|
|
.input-with-action:has(> .icon-btn:only-of-type) .icon-btn:only-of-type {
|
|
right: 4px;
|
|
}
|
|
|
|
/* Custom right-click menu (replaces native Edge contextmenu in inputs). */
|
|
.custom-ctxmenu {
|
|
position: fixed;
|
|
z-index: 9999;
|
|
min-width: 160px;
|
|
padding: 4px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
box-shadow: var(--shadow);
|
|
}
|
|
.custom-ctxmenu-item {
|
|
display: block;
|
|
width: 100%;
|
|
text-align: left;
|
|
padding: 7px 12px;
|
|
font-size: 13px;
|
|
background: transparent;
|
|
border: none;
|
|
border-radius: 4px;
|
|
color: var(--text);
|
|
cursor: pointer;
|
|
}
|
|
.custom-ctxmenu-item:hover:not(.is-disabled) { background: var(--bg-elev-2); }
|
|
.custom-ctxmenu-item.is-disabled { color: var(--text-faint); cursor: default; }
|
|
|
|
/* Folder delete X button — visible on row hover only. */
|
|
.nav-item .folder-delete {
|
|
margin-left: auto;
|
|
width: 20px; height: 20px;
|
|
padding: 0;
|
|
line-height: 0;
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
background: transparent; border: none;
|
|
color: var(--text-faint);
|
|
border-radius: 4px;
|
|
opacity: 0;
|
|
transition: opacity var(--t-fast), color var(--t-fast), background var(--t-fast);
|
|
cursor: pointer;
|
|
}
|
|
.nav-item .folder-delete svg { width: 14px; height: 14px; display: block; }
|
|
.nav-item:hover .folder-delete { opacity: 0.7; }
|
|
.nav-item .folder-delete:hover {
|
|
opacity: 1;
|
|
color: var(--danger);
|
|
background: var(--danger-soft);
|
|
}
|
|
.nav-item:hover .nav-count { display: none; }
|
|
|
|
/* Remember username checkbox row on auth screen. */
|
|
.remember-row {
|
|
display: flex; align-items: center; gap: 8px;
|
|
margin: -4px 0 12px;
|
|
font-size: 12px;
|
|
color: var(--text-dim);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
}
|
|
.remember-row input[type="checkbox"] {
|
|
width: 14px; height: 14px;
|
|
accent-color: var(--accent);
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* Just-added entry feedback — pulse background fades out over 2.5s. */
|
|
@keyframes entryFlash {
|
|
0% { background: var(--accent-soft); box-shadow: 0 0 0 2px var(--accent), 0 8px 24px rgba(6,182,212,0.3); }
|
|
40% { background: var(--accent-soft); box-shadow: 0 0 0 2px var(--accent), 0 8px 24px rgba(6,182,212,0.2); }
|
|
100% { background: var(--bg-elev); box-shadow: 0 0 0 0 transparent; }
|
|
}
|
|
.entry-card.is-flash { animation: entryFlash 2.5s ease-out; }
|
|
.entry-row.is-flash { animation: entryFlash 2.5s ease-out; }
|
|
|
|
/* Pagination footer (list + table views). */
|
|
.pagination {
|
|
display: flex; align-items: center; gap: 6px;
|
|
padding: 14px 12px 4px;
|
|
flex-wrap: wrap;
|
|
font-size: 13px;
|
|
color: var(--text-dim);
|
|
grid-column: 1 / -1;
|
|
}
|
|
.pagination-info {
|
|
margin-right: auto;
|
|
color: var(--text-faint);
|
|
font-size: 12px;
|
|
}
|
|
.pagination-btn {
|
|
min-width: 32px;
|
|
padding: 5px 9px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: 6px;
|
|
color: var(--text-dim);
|
|
cursor: pointer;
|
|
transition: all var(--t-fast);
|
|
}
|
|
.pagination-btn:hover:not(.is-active):not(.is-disabled) {
|
|
border-color: var(--accent);
|
|
color: var(--text);
|
|
}
|
|
.pagination-btn.is-active {
|
|
background: var(--accent);
|
|
border-color: var(--accent);
|
|
color: white;
|
|
cursor: default;
|
|
}
|
|
.pagination-btn.is-disabled {
|
|
opacity: 0.4;
|
|
cursor: not-allowed;
|
|
}
|
|
.pagination-ellipsis { padding: 0 4px; color: var(--text-faint); }
|
|
.pagination-size {
|
|
margin-left: 8px;
|
|
padding: 5px 8px;
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
border-radius: 6px;
|
|
color: var(--text-dim);
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
}
|