/* ============================================================ 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-elev-3: #34343f; /* one step above elev-2 — hover / raised bits */ --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-fg: #ffffff; /* text/icon colour on an accent background */ --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-elev-3: #e3e3dd; /* one step above elev-2 — hover / raised bits */ --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); } /* Existing-tag autocomplete dropdown anchored under the chip-input. */ .tag-suggest { position: absolute; top: 100%; left: 0; right: 0; margin-top: 4px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); z-index: 60; overflow: hidden; max-height: 240px; overflow-y: auto; } .tag-suggest.is-hidden { display: none; } .tag-suggest-item { display: flex; align-items: center; gap: 8px; width: 100%; padding: 7px 10px; background: transparent; border: none; color: var(--text); font-size: 13px; text-align: left; cursor: pointer; } .tag-suggest-item:hover { background: var(--bg-elev-2); } .tag-suggest-item svg { width: 12px; height: 12px; color: var(--text-faint); } .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: 50%; width: 14px; height: 14px; background: var(--text-dim); border-radius: 50%; transform: translateY(-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: translate(16px, -50%); } /* ---- 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); } /* Folder reorder: insertion line above or below the hovered item. */ .nav-item.drop-before { box-shadow: inset 0 2px 0 0 var(--accent); } .nav-item.drop-after { box-shadow: inset 0 -2px 0 0 var(--accent); } .nav-item.is-dragging { opacity: 0.4; } .nav-item[draggable="true"] { cursor: grab; } .nav-item[draggable="true"]:active { cursor: grabbing; } /* ---- 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 70px 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); } /* Replace the native (blue/grey) search-cancel button with a custom one tinted via background-color so it picks up the accent on hover and matches the other X buttons in the app. mask-image keeps it crisp. */ .search input::-webkit-search-cancel-button { appearance: none; -webkit-appearance: none; width: 16px; height: 16px; margin-right: 8px; cursor: pointer; background-color: var(--accent); -webkit-mask-image: url("data:image/svg+xml;utf8,"); mask-image: url("data:image/svg+xml;utf8,"); -webkit-mask-size: contain; mask-size: contain; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; opacity: 0.85; transition: opacity var(--t-fast); } .search input::-webkit-search-cancel-button:hover { opacity: 1; } .search kbd { position: absolute; right: 8px; } /* Search history dropdown */ .search-history { position: absolute; top: calc(100% + 4px); left: 0; right: 0; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); z-index: 50; overflow: hidden; } .search-history.is-hidden { display: none; } .search-history-header { display: flex; align-items: center; justify-content: space-between; padding: 6px 10px; border-bottom: 1px solid var(--border-soft); font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.4px; } .search-history-clear { background: transparent; border: none; color: var(--text-dim); font-size: 11px; cursor: pointer; padding: 2px 6px; border-radius: 3px; } .search-history-clear:hover { color: var(--danger); background: var(--danger-soft); } .search-history-row { display: flex; align-items: stretch; } .search-history-row:hover { background: var(--bg-elev-2); } .search-history-item { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; padding: 8px 12px; background: transparent; border: none; color: var(--text); font-size: 13px; cursor: pointer; text-align: left; } .search-history-item svg { width: 13px; height: 13px; color: var(--text-faint); } .search-history-del { display: inline-flex; align-items: center; justify-content: center; width: 32px; flex-shrink: 0; background: transparent; border: none; color: var(--text-dim); cursor: pointer; transition: color var(--t-fast), background var(--t-fast); } .search-history-del { font-size: 18px; line-height: 1; font-weight: 400; } .search-history-row:hover .search-history-del { color: var(--text); } .search-history-del:hover { color: var(--danger); background: var(--danger-soft); } .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: 8px; padding: 5px 12px 5px 6px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 20px; color: var(--text); font-size: 12px; transition: all var(--t-fast); } .user-chip:hover { background: var(--bg-elev-2); } /* Round initials avatar. Background colour is set inline from a hash of the username (deterministic — same user, same colour every render). Falls back to a background-image when a custom picture is set. */ .user-avatar { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; margin-left: 0; border-radius: 50%; font-size: 13px; font-weight: 600; color: #fff; text-transform: uppercase; background-size: cover; background-position: center; flex-shrink: 0; user-select: none; } /* Larger preview variant shown in Settings → Account. */ .user-avatar-lg { width: 48px; height: 48px; margin-left: 0; font-size: 20px; } .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); } /* Keyboard cursor (j/k nav) — distinct from selected so a focused card stays visible after the slideover closes. */ .entry-card.is-cursor, .entry-row.is-cursor { outline: 2px solid var(--accent); outline-offset: -2px; } /* === 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-note-row { display: contents; } .entry-grid.is-list .entry-note-placeholder { order: 3; flex: 1; min-width: 0; font-size: 11px; color: var(--text-dim); font-style: italic; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 4px 8px; background: var(--bg); border-radius: 6px; border: 1px solid var(--border-soft); } .entry-grid.is-list .entry-note-row .icon-btn { order: 4; flex-shrink: 0; } .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 , 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, .entry-pin { 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-pin.is-on { color: var(--accent); } .entry-pin:hover { color: var(--accent); 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; } .entry-chip.is-aged { color: #b45309; background: rgba(245, 158, 11, 0.15); font-weight: 600; } .entry-chip.is-aged svg { stroke: #b45309; } /* 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; } /* ---- Password history modal --------------------- */ .so-history-wrap { margin-top: -8px; margin-bottom: 4px; } .so-history-wrap .btn { padding: 4px 8px; font-size: 11px; } /* Make the history body actually scrollable. The .modal-body's default doesn't fix the height, so the panel grew to fit all rows → no scroll. */ #historyBody { max-height: 65vh; overflow-y: auto; padding: 12px 16px; } .history-loading, .history-empty { padding: 24px; text-align: center; color: var(--text-dim); font-size: 13px; } .history-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; } .history-row { background: var(--bg); border: 1px solid var(--border-soft); border-radius: var(--radius-sm); padding: 10px 12px; display: flex; flex-direction: column; gap: 6px; } .history-meta { display: flex; align-items: center; gap: 8px; } .history-date { font-size: 11px; color: var(--text-dim); font-family: 'JetBrains Mono', ui-monospace, monospace; } .history-preview { display: flex; align-items: flex-start; gap: 6px; min-width: 0; } .history-value { flex: 1 1 0; min-width: 0; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 12px; color: var(--text); /* Long revealed passwords wrap to multiple lines (no ellipsis) so the user sees the full value. break-all is needed because real passwords have no whitespace for the browser to break on. */ white-space: normal; word-break: break-all; overflow-wrap: anywhere; line-height: 1.4; } .history-row { min-width: 0; } .history-actions { display: flex; justify-content: flex-end; } /* ---- Cheatsheet overlay --------------------------- */ .cheatsheet-panel { max-width: 720px; width: 100%; } .cheatsheet-body { max-height: 60vh; overflow-y: auto; padding: 18px 22px; } .cheatsheet-group { margin-bottom: 18px; } .cheatsheet-group h4 { margin: 0 0 8px; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-dim); } .cheatsheet-list { display: flex; flex-direction: column; gap: 6px; } .cheatsheet-row { display: grid; grid-template-columns: 180px 1fr; gap: 16px; align-items: start; padding: 4px 0; font-size: 13px; } .cheatsheet-desc { color: var(--text-dim); line-height: 1.4; } .cheatsheet-keys { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; } .cheatsheet-keys kbd { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 11px; padding: 2px 7px; background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 4px; box-shadow: 0 1px 0 var(--border-soft); } .cheatsheet-plus { color: var(--text-faint); font-size: 10px; } .cheatsheet-icon-chip { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 22px; padding: 2px; background: var(--bg); border: 1px solid var(--border); border-radius: 4px; box-shadow: 0 1px 0 var(--border-soft); color: var(--text); } .cheatsheet-icon-chip svg { width: 14px; height: 14px; } /* ---- Slideover custom-fields editor ------------------ */ .so-custom-list { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; } .so-custom-row { display: grid; grid-template-columns: 1fr 1.4fr auto auto auto auto; gap: 4px; align-items: center; } .so-custom-row .so-input { padding: 4px 8px; font-size: 12px; } /* Editable combobox for option-backed custom fields (card brand, expiry year…). Input fills the cell; the arrow drops a menu of ALL options. */ .so-combo { position: relative; display: flex; align-items: center; } .so-combo-input { flex: 1; padding-right: 24px !important; width: 100%; } .so-combo-arrow { position: absolute; right: 2px; top: 50%; transform: translateY(-50%); display: flex; align-items: center; justify-content: center; width: 20px; height: 20px; background: transparent; border: 0; padding: 0; color: var(--text-faint); cursor: pointer; } .so-combo-arrow svg { width: 14px; height: 14px; } .so-combo-arrow:hover { color: var(--text); } .so-combo-menu { position: absolute; top: calc(100% + 2px); left: 0; right: 0; z-index: 20; max-height: 200px; overflow-y: auto; background: var(--bg-elev-2); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow); padding: 4px; } .so-combo-menu.is-hidden { display: none; } .so-combo-item { padding: 6px 10px; font-size: 12px; border-radius: 4px; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .so-combo-item:hover { background: var(--accent); color: #fff; } .so-custom-secret-toggle { background: var(--bg); border: 1px solid var(--border); border-radius: 4px; width: 28px; height: 28px; cursor: pointer; color: var(--text-dim); font-size: 13px; line-height: 1; padding: 0; } .so-custom-secret-toggle.is-on { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); } .so-custom-add { margin-top: 8px; } .so-custom-add .btn { padding: 4px 10px; font-size: 12px; } /* ---- Audit log viewer -------------------------------- */ .entry-grid.is-audit { display: flex; flex-direction: column; gap: 10px; } .audit-loading, .audit-empty { color: var(--text-dim); padding: 24px; text-align: center; font-size: 13px; } .audit-header { display: flex; gap: 8px; align-items: center; } .audit-search { flex: 1; padding: 6px 12px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); font-size: 13px; } .audit-search:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); } .audit-note { margin: 0; font-size: 11px; color: var(--text-faint); font-style: italic; } .audit-list { display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-elev); max-height: 70vh; overflow-y: auto; } .audit-row { display: grid; grid-template-columns: 160px 1fr 120px; gap: 12px; padding: 8px 14px; font-size: 12px; border-bottom: 1px solid var(--border-soft); align-items: center; } .audit-row:last-child { border-bottom: none; } .audit-row:hover { background: var(--bg); } .audit-date { color: var(--text-dim); font-family: 'JetBrains Mono', ui-monospace, monospace; white-space: nowrap; } .audit-action { color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .audit-ip { color: var(--text-faint); font-family: 'JetBrains Mono', ui-monospace, monospace; text-align: right; } /* ---- Filters dropdown + chips ------------------------ */ .filters-wrap { position: relative; } .filters-count { position: absolute; top: -2px; right: -4px; background: var(--accent); color: white; font-size: 9px; font-weight: 700; padding: 1px 5px; border-radius: 8px; line-height: 1.3; pointer-events: none; } .filters-menu { position: absolute; top: calc(100% + 4px); right: 0; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); z-index: 60; min-width: 240px; padding: 6px; } .filters-menu-title { padding: 4px 8px 6px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-faint); } .filters-menu-row { display: flex; align-items: center; gap: 8px; padding: 6px 8px; cursor: pointer; border-radius: 4px; font-size: 13px; color: var(--text); } .filters-menu-row:hover { background: var(--accent-soft); } .filters-menu-row svg { width: 14px; height: 14px; color: var(--text-dim); } .filters-menu-cb { margin: 0; accent-color: var(--accent); cursor: pointer; } .filters-menu-clear { width: 100%; margin-top: 6px; padding: 6px 8px; background: none; border: 1px solid var(--border); border-radius: 4px; color: var(--text-dim); font-size: 12px; cursor: pointer; } .filters-menu-clear:hover { color: var(--text); border-color: var(--accent); } .filter-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 8px 0; margin-bottom: 4px; } .filter-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent); border-radius: 14px; padding: 3px 4px 3px 10px; font-size: 11px; font-weight: 600; } .filter-chip svg { width: 12px; height: 12px; } .filter-chip-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; background: none; border: none; cursor: pointer; color: var(--accent); border-radius: 50%; padding: 0; } .filter-chip-x:hover { background: var(--accent); color: white; } .filter-chip-x svg { width: 10px; height: 10px; } .filter-chips-clear { background: none; border: none; color: var(--text-faint); font-size: 11px; cursor: pointer; padding: 3px 8px; text-decoration: underline; } .filter-chips-clear:hover { color: var(--text-dim); } /* ---- Note cards (kind=note) -------------------------- */ .entry-note-row { display: flex; align-items: center; padding: 4px 0 8px; color: var(--text-dim); font-size: 12px; font-style: italic; } .entry-note-placeholder { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Note marker in table-view "Name" cell + faint placeholder in user cell */ .kind-badge { display: inline-block; padding: 1px 6px; margin-left: 6px; border-radius: 3px; background: var(--accent-soft); color: var(--accent); font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; vertical-align: middle; } .col-user-note { color: var(--text-faint); font-style: italic; font-size: 12px; } /* ---- Slideover note textarea ------------------------- */ .so-note-body { min-height: 220px; resize: vertical; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 13px; line-height: 1.55; white-space: pre-wrap; } /* ---- + New dropdown ---------------------------------- */ .new-entry-wrap { position: relative; display: flex; gap: 1px; } .new-entry-caret { padding-left: 6px; padding-right: 6px; border-radius: 0 var(--radius-sm) var(--radius-sm) 0; } .new-entry-wrap > #newEntryBtn { border-radius: var(--radius-sm) 0 0 var(--radius-sm); } .new-entry-menu { position: absolute; top: calc(100% + 4px); right: 0; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); z-index: 60; min-width: 160px; padding: 4px; } .new-entry-menu .dropdown-item { width: 100%; display: flex; align-items: center; gap: 10px; padding: 8px 10px; background: none; border: none; color: var(--text); font: inherit; cursor: pointer; border-radius: 4px; text-align: left; } .new-entry-menu .dropdown-item:hover { background: var(--accent-soft); } .new-entry-menu .dropdown-item svg { width: 14px; height: 14px; } .new-entry-menu .dropdown-sep { height: 1px; background: var(--border-soft); margin: 4px 0; } .new-entry-menu .dropdown-section { padding: 4px 10px 2px; font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-faint); } /* Table column picker dropdown — only rendered in table view. */ .cols-menu { position: absolute; top: calc(100% + 4px); right: 0; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); z-index: 60; min-width: 160px; padding: 4px; overflow: hidden; } .cols-menu.is-hidden { display: none; } .cols-menu-item { display: flex; align-items: center; gap: 8px; padding: 7px 10px; font-size: 13px; color: var(--text); cursor: pointer; border-radius: 4px; } .cols-menu-item:hover { background: var(--bg-elev-2); } .cols-menu-item input { cursor: pointer; } /* ---- 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); } /* Suppress the slide animation when the panel is closed — otherwise changing editor-position animates the off-screen position from right to left and the panel briefly crosses the viewport. */ .slideover:not(.is-open) { transition: none; } /* Push the app shell to the left when the entry slideover is open, so the table, pagination etc. stay visible. Only applies to the entry editor (#slideover) — NOT #settingsPanel which would visually re-flow the whole app. Width matches .slideover (420px). */ body[data-editor-position="right"]:has(#slideover.is-open) #appShell { margin-right: 420px; } #appShell { transition: margin-right var(--t-base), margin-left var(--t-base); } /* ---- Editor position: LEFT (mirrored slideover) ---- */ body[data-editor-position="left"] #slideover, body[data-editor-position="left"] #settingsPanel { left: 0; right: auto; border-left: none; border-right: 1px solid var(--border); transform: translateX(-100%); } body[data-editor-position="left"] #slideover.is-open, body[data-editor-position="left"] #settingsPanel.is-open { transform: translateX(0); } body[data-editor-position="left"]:has(#slideover.is-open) #appShell { margin-left: 420px; } /* ---- Editor position: CENTER (modal-style) ---- */ body[data-editor-position="center"] #slideover, body[data-editor-position="center"] #settingsPanel { top: 50%; left: 50%; right: auto; bottom: auto; width: 520px; max-height: 90vh; border-radius: var(--radius-lg); border-left: 1px solid var(--border); transform: translate(-50%, -50%) scale(0.96); opacity: 0; /* Hidden panels in center mode live INSIDE the viewport (opacity 0 instead of off-screen translate), so without this guard the buttons would stay clickable through the invisible panel. */ pointer-events: none; transition: transform var(--t-base), opacity var(--t-base); } body[data-editor-position="center"] #slideover.is-open, body[data-editor-position="center"] #settingsPanel.is-open { transform: translate(-50%, -50%) scale(1); opacity: 1; pointer-events: auto; } /* Center mode = true modal: dim + blur backdrop, click anywhere outside the panel dismisses it (handled in JS). The backdrop is painted via a body pseudo-element so it covers everything but the active panel. */ body[data-editor-position="center"]:has(#slideover.is-open)::before, body[data-editor-position="center"]:has(#settingsPanel.is-open)::before { content: ''; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); z-index: 45; /* above topbar (40), below .slideover (50) */ pointer-events: auto; /* swallow clicks so cards/sidebar don't see them */ } .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; } /* Settings panel search — sits below the header, above the body. Only present inside #settingsPanel. */ .settings-search-wrap { position: relative; padding: 10px 16px; border-bottom: 1px solid var(--border); display: flex; align-items: center; } .settings-search-icon { position: absolute; left: 26px; top: 50%; transform: translateY(-50%); width: 14px; height: 14px; color: var(--text-faint); pointer-events: none; } .settings-search-input { flex: 1; padding: 7px 30px 7px 32px; background: var(--bg-elev-2); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); font-size: 13px; outline: none; transition: border-color var(--t-fast); } .settings-search-input:focus { border-color: var(--accent); } .settings-search-clear { position: absolute; right: 22px; top: 50%; transform: translateY(-50%); background: transparent; border: 0; padding: 4px; cursor: pointer; color: var(--text-faint); border-radius: 4px; display: none; } .settings-search-clear svg { width: 12px; height: 12px; } .settings-search-clear:hover { color: var(--text); background: var(--bg-elev-2); } .settings-search-wrap.has-query .settings-search-clear { display: inline-flex; } /* Hidden section + per-row + no-results banner driven by JS. */ .slideover-field.is-search-hidden, .setting-row.is-search-hidden { display: none; } .settings-no-results { padding: 20px; color: var(--text-faint); font-size: 13px; text-align: center; display: none; } .settings-no-results.is-visible { display: block; } /* Global busy overlay — spinner + text for long ops (export, big saves). */ .busy-overlay { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); } .busy-overlay.is-hidden { display: none; } .busy-box { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 24px 32px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); } .busy-spinner { width: 34px; height: 34px; border: 3px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: busy-spin 0.7s linear infinite; } @keyframes busy-spin { to { transform: rotate(360deg); } } .busy-text { font-size: 13px; color: var(--text-dim); text-align: center; } .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; } /* Sticky action row — stays glued to the bottom of the slideover body while it scrolls, so Save is reachable without scrolling all the way down on entries with lots of custom fields / attachments. */ .slideover-actions { display: flex; gap: 8px; position: sticky; bottom: -20px; /* cancel the .slideover-body padding-bottom */ margin: 24px -20px -20px; /* extend to the edges */ padding: 12px 20px; background: var(--bg-elev); border-top: 1px solid var(--border); z-index: 2; } /* ---- 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%; } /* On a narrow viewport the slideover fills the screen — no point pushing the shell, the table isn't visible anyway. */ body:has(.slideover.is-open) #appShell { margin-right: 0; margin-left: 0; } } /* ---- 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; } /* NAME stops growing past 360px so it doesn't push Username/Folder/ Updated all the way to the right. Long names ellipsise on a single line so the avatar never falls under the title. */ .col-name { min-width: 180px; width: auto; /* shrinks to short names, grows to fit long ones — no fixed cap, the column matches its widest entry. */ white-space: nowrap; padding-right: 32px; /* extra breathing room so the longest title never butts up against Username. */ } .col-name .cell-name-wrap { display: inline-flex; align-items: center; gap: 6px; vertical-align: middle; } .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; } /* Soak the remaining horizontal space so NAME/Username/Folder stay close to each other on the left rather than spreading out. */ .col-actions { width: 100%; min-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; } /* Folder edit (pencil) button — same hover-reveal as the delete X. */ .nav-item .folder-edit { 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-edit svg { width: 13px; height: 13px; display: block; } .nav-item:hover .folder-edit { opacity: 0.7; } .nav-item .folder-edit:hover { opacity: 1; color: var(--accent); background: var(--accent-soft); } /* When folder-edit is rendered before folder-delete in the DOM, push delete to the far right so the layout stays {icon} {label} … {edit} {delete}. */ .nav-item .folder-edit + .folder-delete { margin-left: 2px; } /* ============================================================ FOLDER CUSTOMIZATION MODAL ============================================================ */ #folderModal .form-field { margin-bottom: 14px; } #folderModal .form-field label { display: block; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-faint); margin-bottom: 4px; } #folderModal .so-input { width: 100%; } /* ============================================================ ATTACHMENTS list inside the slideover ============================================================ */ .so-attach-list { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; } .so-attach-empty { font-size: 12px; color: var(--text-faint); padding: 6px 2px; font-style: italic; } .so-attach-row { display: flex; align-items: center; gap: 8px; padding: 8px 10px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; } .so-attach-info { flex: 1; min-width: 0; } .so-attach-name { font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .so-attach-meta { font-size: 11px; color: var(--text-faint); margin-top: 1px; } .so-attach-row .icon-btn { flex-shrink: 0; } .folder-swatch-row, .folder-icon-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; } .folder-swatch { width: 26px; height: 26px; border-radius: 50%; border: 2px solid transparent; background: var(--bg-elev); cursor: pointer; padding: 0; transition: transform var(--t-fast), border-color var(--t-fast); } .folder-swatch:hover { transform: scale(1.1); } .folder-swatch.is-active { border-color: var(--text); box-shadow: 0 0 0 2px var(--bg); } .folder-swatch.is-default { background: linear-gradient(135deg, transparent 47%, var(--danger) 47% 53%, transparent 53%), var(--bg-elev); } .folder-icon-btn { width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--border); background: var(--bg-elev); border-radius: 6px; cursor: pointer; color: var(--text-dim); transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast); } .folder-icon-btn svg { width: 18px; height: 18px; } .folder-icon-btn:hover { background: var(--bg-elev-2); color: var(--text); } .folder-icon-btn.is-active { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); } .folder-preview { display: flex; align-items: center; gap: 10px; margin: 16px 0 4px; padding: 12px 14px; background: var(--bg-elev); border-radius: 6px; color: var(--text); font-weight: 500; } .folder-preview svg { width: 18px; height: 18px; } /* 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; } /* ============================================================ PRINTABLE RECOVERY CODE — only renders on the printed page ============================================================ */ #printRecoveryArea { display: none; } @media print { /* Hide the running app entirely; show only the printable sheet. */ body > *:not(#printRecoveryArea) { display: none !important; } #printRecoveryArea { display: block !important; position: static; background: #fff !important; color: #000 !important; } .prc-sheet { font-family: Georgia, 'Times New Roman', serif; padding: 40px; max-width: 700px; margin: 0 auto; } .prc-sheet h1 { font-size: 22px; margin: 0 0 18px; border-bottom: 2px solid #000; padding-bottom: 8px; } .prc-meta { display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 28px; } .prc-code { font-family: 'Courier New', monospace; font-size: 32px; letter-spacing: 6px; text-align: center; padding: 24px; border: 2px dashed #000; margin: 28px 0; font-weight: bold; } .prc-instructions { font-size: 13px; line-height: 1.6; } .prc-instructions ol { padding-left: 22px; } @page { margin: 1.5cm; } }