Files
ObsiGate/frontend/style.css
T
bruno 06f8e63d06 feat: tableurs indexables, saisie typée et valeurs calculées #153
Les tableurs étaient invisibles à la recherche, chaque saisie devenait
du texte, et une formule n'affichait que sa formule.

- A5 : extract_indexable_text() indexe les noms de feuilles et les 20
  premières lignes (plafond 5 k caractères) pour le TF-IDF et la
  recherche sémantique. Un mot tapé dans une cellule rend le fichier
  trouvable ; un classeur chiffré s'indexe par son seul nom.
- A10 : la saisie est typée comme dans Excel — booléens
  (TRUE/FAUX/OUI/NON) et dates FR JJ/MM/AAAA en ordre jour-first, donc
  01/02/2026 est le 1er février. Une saisie ressemblant à une formule
  n'est jamais convertie (BUG-088 préservé).
- A12 : la valeur calculée par Excel s'affiche sous la formule, via une
  2e lecture data_only=True faite seulement si l'archive contient un
  <v>. Info-bulle traduite FR/EN, aucun texte d'interface côté backend.
- BUG-089 : un reindex manuel ne reconstruisait pas l'index inversé, et
  backend/search.py lisait l'index via un import par valeur — après un
  rechargement du module, la recherche écrivait dans un dict périmé.

Contre-preuves vérifiées pour A5, A10 et A12 (neutralisation de chaque
fonction → échec des tests concernés). Tests : 1402 pytest, 10 JSDOM,
4 E2E, suite E2E complète verte, ruff/mypy 0.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-27 22:43:24 -04:00

12134 lines
284 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Lora:ital,wght@0,400;0,600;1,400&display=swap");
/* ===== RESET ===== */
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* ── Editor save dot state colors ── */
:root {
--ok: #34d399;
--warn: #fbbf24;
--ai: #8b5cf6;
--err: #f87171;
}
/* ===== THEME — DARK (fallback default, no data-theme) ===== */
:root {
--bg-primary: #0f1117;
--bg-secondary: #161b22;
--bg-sidebar: #13161d;
--bg-hover: #1f2430;
--border: #21262d;
--text-primary: #e6edf3;
--text-secondary: #8b949e;
--text-muted: #484f58;
--accent: #58a6ff;
--accent-green: #3fb950;
--tag-bg: #1f2a3a;
--tag-text: #79c0ff;
--code-bg: #161b22;
--search-bg: #21262d;
--scrollbar: #30363d;
--resize-handle: #30363d;
--overlay-bg: rgba(0, 0, 0, 0.5);
--danger: #ff7b72;
--danger-bg: #3d1a18;
--success: #3fb950;
--success-bg: #1a3d1f;
--accent-card: #58a6ff;
--accent-bg: #1f2a3a;
--accent-text: #79c0ff;
--green: #3fb950;
--green-bg: #1a3d1f;
--purple: #a371f7;
--purple-bg: #2d1b4e;
--surface: #161b22;
--surface2: #0f1117;
--surface3: #0d0f14;
--border-md: #30363d;
--text: #e6edf3;
--text-2: #8b949e;
--text-3: #484f58;
--mono: "JetBrains Mono", monospace;
--radius: 6px;
--radius-lg: 10px;
}
/* ===== THEME — DARK (explicit) ===== */
:root[data-theme="dark"] {
--bg-primary: #0f1117;
--bg-secondary: #161b22;
--bg-sidebar: #13161d;
--bg-hover: #1f2430;
--border: #21262d;
--text-primary: #e6edf3;
--text-secondary: #8b949e;
--text-muted: #484f58;
--accent: #58a6ff;
--accent-green: #3fb950;
--tag-bg: #1f2a3a;
--tag-text: #79c0ff;
--code-bg: #161b22;
--search-bg: #21262d;
--scrollbar: #30363d;
--resize-handle: #30363d;
--overlay-bg: rgba(0, 0, 0, 0.5);
--danger: #ff7b72;
--danger-bg: #3d1a18;
--success: #3fb950;
--success-bg: #1a3d1f;
/* Accent Card variables */
--accent-card: #58a6ff;
--accent-bg: #1f2a3a;
--accent-text: #79c0ff;
--green: #3fb950;
--green-bg: #1a3d1f;
--purple: #a371f7;
--purple-bg: #2d1b4e;
--surface: #161b22;
--surface2: #0f1117;
--surface3: #0d0f14;
--border-md: #30363d;
--text: #e6edf3;
--text-2: #8b949e;
--text-3: #484f58;
--mono: "JetBrains Mono", monospace;
--radius: 6px;
--radius-lg: 10px;
}
/* ===== THEME — LIGHT ===== */
:root[data-theme="light"] {
--bg-primary: #ffffff;
--bg-secondary: #f6f8fa;
--bg-sidebar: #f0f2f5;
--bg-hover: #e8ecf0;
--border: #d0d7de;
--text-primary: #1f2328;
--text-secondary: #57606a;
--text-muted: #9198a1;
--accent: #0969da;
--accent-green: #1a7f37;
--tag-bg: #ddf4ff;
--tag-text: #0969da;
--code-bg: #f6f8fa;
--search-bg: #ffffff;
--scrollbar: #d0d7de;
--resize-handle: #d0d7de;
--overlay-bg: rgba(0, 0, 0, 0.3);
--danger: #cf222e;
--danger-bg: #ffebe9;
--success: #1a7f37;
--success-bg: #dafbe1;
/* Accent Card variables */
--accent-card: #4f6ef7;
--accent-bg: #eef1fe;
--accent-text: #2540c9;
--green: #1a7f50;
--green-bg: #eaf5ee;
--purple: #6b40c4;
--purple-bg: #f1ecfd;
--surface: #ffffff;
--surface2: #f2f1ef;
--surface3: #ebe9e6;
--border-md: rgba(0, 0, 0, 0.13);
--text: #1a1917;
--text-2: #6b6a67;
--text-3: #a09e9b;
--mono: "JetBrains Mono", monospace;
--radius: 6px;
--radius-lg: 10px;
}
/* ===== BASE ===== */
html {
font-size: 16px;
scroll-behavior: smooth;
}
body {
font-family: "Lora", Georgia, serif;
background: var(--bg-primary);
color: var(--text-primary);
line-height: 1.7;
transition:
background 200ms ease,
color 200ms ease;
overflow: hidden;
height: 100vh;
}
a {
color: var(--accent);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* ===== LAYOUT ===== */
.app-container {
display: flex;
flex-direction: column;
height: 100vh;
}
/* --- Header --- */
.header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 10px 20px;
background: var(--bg-secondary);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
z-index: 100;
transition: background 200ms ease;
}
.header-left {
display: flex;
align-items: center;
gap: 12px;
flex: 0 1 auto;
}
.header-center {
display: flex;
justify-content: center;
flex: 1 1 auto;
max-width: 600px;
}
.header-right {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
flex: 0 1 auto;
}
.vault-context-indicator {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
border: 1px solid var(--border);
border-radius: 8px;
font-family: "JetBrains Mono", monospace;
font-size: 0.75rem;
font-weight: 600;
cursor: default;
transition: all 200ms ease;
/* Default: neutral (overridden by classes below) */
background: var(--bg-tertiary);
color: var(--text-muted);
}
.vault-context-indicator:hover {
filter: brightness(1.15);
}
.vault-context-indicator i {
opacity: 0.8;
}
/* ── Offline Indicator ── */
.offline-indicator {
position: relative;
display: flex;
align-items: center;
justify-content: center;
margin-right: 8px;
cursor: default;
}
.offline-indicator.offline i {
color: var(--warning, #f59e0b);
opacity: 1;
}
.offline-pending {
position: absolute;
top: -4px;
right: -8px;
background: var(--danger, #ef4444);
color: #fff;
font-size: 0.6rem;
font-weight: 700;
min-width: 14px;
height: 14px;
line-height: 14px;
text-align: center;
border-radius: 7px;
padding: 0 3px;
}
/* ── Offline Search Result Badge ── */
.search-result-offline-badge {
display: inline-block;
background: var(--warning, #f59e0b);
color: #000;
font-size: 0.55rem;
font-weight: 700;
padding: 1px 5px;
border-radius: 3px;
margin-left: 6px;
vertical-align: middle;
text-transform: uppercase;
}
/* ── Conflict Resolution Modal ── */
.conflict-modal-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.6);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
}
.conflict-modal {
background: var(--bg-card, #1e1e2e);
border: 1px solid var(--border, #333);
border-radius: 8px;
padding: 24px;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
}
.conflict-modal h3 {
margin: 0 0 8px;
font-size: 1.1rem;
}
.conflict-modal p {
color: var(--text-muted, #888);
font-size: 0.85rem;
margin: 0 0 16px;
}
.conflict-modal-actions {
display: flex;
gap: 8px;
justify-content: flex-end;
}
.conflict-modal-actions button {
padding: 8px 16px;
border-radius: 6px;
border: 1px solid var(--border, #333);
background: var(--bg-input, #2a2a3c);
color: var(--text, #ddd);
cursor: pointer;
font-size: 0.85rem;
}
.conflict-modal-actions .btn-primary {
background: var(--accent, #3b82f6);
border-color: var(--accent);
color: #fff;
}
/* All vaults — blue */
.vault-ctx-all {
background: color-mix(in srgb, #3b82f6 14%, transparent) !important;
border-color: color-mix(in srgb, #3b82f6 30%, var(--border)) !important;
color: #60a5fa !important;
}
.vault-ctx-all i { color: #60a5fa !important; }
/* Specific vault — mauve/violet */
.vault-ctx-vault {
background: color-mix(in srgb, #a855f7 14%, transparent) !important;
border-color: color-mix(in srgb, #a855f7 30%, var(--border)) !important;
color: #c084fc !important;
}
.vault-ctx-vault i { color: #c084fc !important; }
/* Directory — amber/yellow */
.vault-ctx-dir {
background: color-mix(in srgb, #f59e0b 14%, transparent) !important;
border-color: color-mix(in srgb, #f59e0b 30%, var(--border)) !important;
color: #fbbf24 !important;
}
.vault-ctx-dir i { color: #fbbf24 !important; }
.hamburger-btn {
display: none;
background: none;
border: none;
color: var(--text-secondary);
cursor: pointer;
padding: 4px;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.hamburger-btn:hover {
color: var(--accent);
}
.sidebar-toggle-btn {
display: flex;
background: none;
border: none;
color: var(--text-secondary);
cursor: pointer;
padding: 4px;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: color 200ms ease;
}
.sidebar-toggle-btn:hover {
color: var(--accent);
}
.sidebar-toggle-btn.active {
color: var(--accent);
}
.header-logo {
font-family: "JetBrains Mono", monospace;
font-weight: 700;
font-size: 1.15rem;
color: var(--accent);
white-space: nowrap;
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
transition: opacity 200ms ease;
text-decoration: none;
}
.header-logo:hover {
opacity: 0.8;
text-decoration: none;
}
.search-wrapper {
width: 100%;
max-width: 620px;
position: relative;
display: flex;
flex-direction: column;
gap: 4px;
}
.search-wrapper .search-icon {
position: absolute;
left: 10px;
top: 14px;
color: var(--text-secondary);
pointer-events: none;
z-index: 1;
}
.search-input-wrapper {
position: relative;
flex: 1;
display: flex;
align-items: center;
}
.search-input-wrapper input {
flex: 1;
min-width: 0;
padding: 8px 14px 8px 38px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-secondary);
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.9rem;
outline: none;
transition:
border-color 200ms ease,
background 200ms ease;
}
.search-input-wrapper input:focus {
border-color: var(--accent);
}
.search-actions {
display: flex;
align-items: center;
gap: 2px;
flex-shrink: 0;
padding-left: 4px;
}
.search-btn {
display: flex;
align-items: center;
justify-content: center;
min-width: 26px;
height: 26px;
padding: 0 4px;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--bg-secondary);
color: var(--text-secondary);
cursor: pointer;
font-family: "JetBrains Mono", monospace;
font-size: 0.7rem;
font-weight: 600;
transition: all 150ms ease;
flex-shrink: 0;
}
.search-btn:hover {
border-color: var(--accent);
color: var(--accent);
background: color-mix(in srgb, var(--accent) 10%, var(--bg-secondary));
}
.search-btn.active {
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 20%, var(--bg-secondary));
color: var(--accent);
}
.header-menu {
position: relative;
}
.header-menu-btn {
background: transparent;
border: 1px solid color-mix(in srgb, var(--accent) 22%, var(--border));
border-radius: 12px;
padding: 10px 12px;
cursor: pointer;
color: var(--text-secondary);
display: flex;
align-items: center;
justify-content: center;
transition:
color 200ms ease,
border-color 200ms ease,
background 200ms ease,
transform 180ms ease;
}
.header-menu-btn:hover {
color: var(--accent);
border-color: var(--accent);
transform: translateY(-1px);
}
.header-menu-btn.active {
color: var(--accent);
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 10%, transparent);
}
/* Version badge in header — always visible */
.version-badge {
display: inline-block;
font-size: 11px;
color: var(--text-secondary);
font-weight: 500;
padding: 3px 10px;
border-radius: 10px;
background: color-mix(in srgb, var(--text-secondary) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--text-secondary) 20%, transparent);
font-family: var(--font-mono, monospace);
white-space: nowrap;
cursor: default;
user-select: none;
}
.header-menu-dropdown {
display: none;
position: absolute;
top: calc(100% + 8px);
right: 0;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 16px;
box-shadow: 0 16px 36px rgba(0, 0, 0, 0.28);
min-width: 260px;
z-index: 100;
padding: 8px;
}
.header-menu-dropdown.active {
display: block;
}
.menu-list {
display: flex;
flex-direction: column;
}
.menu-list-row {
width: 100%;
display: grid;
grid-template-columns: 28px minmax(0, 1fr);
align-items: center;
gap: 8px;
padding: 4px 8px;
border-radius: 6px;
text-align: left;
}
.menu-list-button {
border: none;
background: transparent;
cursor: pointer;
transition:
background 160ms ease,
color 160ms ease;
}
.menu-list-button:hover,
.menu-list-select-row:hover {
background: var(--bg-hover);
}
.menu-list-button + .menu-list-button,
.menu-list-select-row + .menu-list-button {
margin-top: 2px;
}
.menu-list-icon {
width: 18px;
height: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--accent);
}
.menu-list-content {
display: flex;
flex-direction: column;
gap: 1px;
min-width: 0;
}
.menu-list-title {
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
font-weight: 600;
color: var(--text-primary);
}
.menu-list-subtitle {
font-size: 0.7rem;
color: var(--text-muted);
}
.menu-select {
width: 100%;
padding: 4px 22px 4px 0;
border: none;
border-radius: 0;
background: inherit;
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.78rem;
font-weight: 500;
outline: none;
cursor: pointer;
transition: color 160ms ease;
color-scheme: dark;
background-color: transparent;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.menu-select option {
background-color: var(--bg-secondary);
color: var(--text-primary);
}
[data-theme="dark"] .menu-select,
[data-theme="dark"] .menu-select option {
background-color: #1e1e1e;
color: #e0e0e0;
}
.menu-select:hover,
.menu-select:focus {
color: var(--accent);
}
.menu-list-select {
margin-top: 1px;
}
/* Force dark mode on all select elements */
select {
color-scheme: dark;
}
[data-theme="dark"] select,
[data-theme="dark"] select option {
background-color: #161b22 !important;
color: #e6edf3 !important;
}
[data-theme="light"] select,
[data-theme="light"] select option {
background-color: #f6f8fa !important;
color: #1f2328 !important;
}
/* Custom Dropdown Styles */
.custom-dropdown {
position: relative;
width: 100%;
}
.custom-dropdown-trigger {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 8px 12px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
cursor: pointer;
transition:
border-color 200ms ease,
background 200ms ease;
}
.custom-dropdown-trigger:hover {
border-color: var(--accent);
background: var(--bg-hover);
}
.custom-dropdown-trigger[aria-expanded="true"] {
border-color: var(--accent);
}
.custom-dropdown-selected {
flex: 1;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.custom-dropdown-menu {
display: none;
position: absolute;
top: calc(100% + 4px);
left: 0;
right: 0;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 6px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
max-height: 240px;
overflow-y: auto;
z-index: 1000;
list-style: none;
padding: 3px;
margin: 0;
}
.custom-dropdown.open .custom-dropdown-menu {
display: block;
}
.custom-dropdown-option {
padding: 6px 10px;
border-radius: 4px;
cursor: pointer;
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
color: var(--text-primary);
transition:
background 150ms ease,
color 150ms ease;
}
.custom-dropdown-option:hover,
.custom-dropdown-option:focus {
background: var(--bg-hover);
color: var(--accent);
}
.custom-dropdown-option.selected {
background: color-mix(in srgb, var(--accent) 15%, transparent);
color: var(--accent);
}
/* Sidebar dropdown specific */
.sidebar-dropdown {
padding: 0 16px 12px;
position: relative;
}
.sidebar-dropdown .custom-dropdown-menu {
position: fixed;
z-index: 10000;
left: auto;
right: auto;
width: auto;
min-width: 200px;
}
.sidebar-dropdown .custom-dropdown-trigger {
background: var(--bg-sidebar);
}
/* Menu list dropdown specific */
.menu-list-select-row .custom-dropdown {
margin-top: 4px;
}
.menu-list-select-row .custom-dropdown-trigger {
padding: 6px 10px;
font-size: 0.78rem;
background: var(--bg-primary);
}
.main-body {
display: flex;
flex: 1;
overflow: hidden;
position: relative;
}
/* --- Mobile overlay --- */
.sidebar-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--overlay-bg);
z-index: 199;
}
.sidebar-overlay.active {
display: block;
}
/* --- Sidebar --- */
.sidebar {
width: 280px;
min-width: 200px;
max-width: 500px;
background: var(--bg-sidebar);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
overflow: hidden;
transition:
background 200ms ease,
transform 300ms ease;
flex-shrink: 0;
}
.sidebar.hidden {
transform: translateX(-100%);
width: 0;
min-width: 0;
border-right: none;
}
/* --- Sidebar filter --- */
.sidebar-filter {
padding: 10px 12px;
border-bottom: 1px solid var(--border);
position: relative;
flex-shrink: 0;
display: flex;
align-items: center;
}
.sidebar-filter-input-wrapper {
position: relative;
flex: 1;
display: flex;
align-items: center;
}
.sidebar-filter-input-wrapper input {
width: 100%;
padding: 6px 10px 6px 32px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--search-bg);
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.78rem;
outline: none;
transition: border-color 200ms ease;
}
.sidebar-filter-input-wrapper input:focus {
border-color: var(--accent);
}
.sidebar-filter-icon {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
pointer-events: none;
z-index: 1;
}
.sidebar-filter-actions {
position: absolute;
right: 4px;
top: 50%;
transform: translateY(-50%);
display: flex;
align-items: center;
gap: 4px;
}
.sidebar-filter-btn {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--bg-secondary);
color: var(--text-secondary);
cursor: pointer;
font-family: "JetBrains Mono", monospace;
font-size: 0.65rem;
font-weight: 600;
transition: all 150ms ease;
padding: 0;
flex-shrink: 0;
}
.sidebar-filter-btn:hover {
border-color: var(--accent);
color: var(--accent);
background: color-mix(in srgb, var(--accent) 10%, var(--bg-secondary));
}
.sidebar-filter-btn.active {
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 20%, var(--bg-secondary));
color: var(--accent);
}
/* --- Sidebar tabs --- */
.sidebar-tabs {
display: flex;
flex-shrink: 0;
border-bottom: 1px solid var(--border);
padding: 0 8px;
gap: 2px;
background: var(--bg-sidebar);
}
.sidebar-tab {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 8px 4px 6px;
border: none;
border-bottom: 2px solid transparent;
background: transparent;
color: var(--text-muted);
cursor: pointer;
transition: color 150ms ease, border-color 150ms ease;
margin-bottom: -1px;
}
.sidebar-tab:hover {
color: var(--text-primary);
}
.sidebar-tab.active {
color: var(--accent);
border-bottom-color: var(--accent);
}
.sidebar-tab .icon {
flex-shrink: 0;
color: inherit;
}
/* --- Sidebar tab panels --- */
.sidebar-tab-panel {
display: none;
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
scroll-behavior: smooth;
flex-direction: column;
}
.sidebar-tab-panel.active {
display: flex;
flex-direction: column;
}
.sidebar-tab-panel::-webkit-scrollbar {
width: 6px;
}
.sidebar-tab-panel::-webkit-scrollbar-thumb {
background: var(--scrollbar);
border-radius: 3px;
}
#sidebar-panel-vaults .sidebar-dropdown {
padding: 10px 12px 6px;
}
.tree-item {
display: flex;
align-items: center;
gap: 6px;
padding: 5px 16px;
font-family: "JetBrains Mono", monospace;
font-size: 0.82rem;
color: var(--text-secondary);
cursor: pointer;
border-radius: 0;
transition:
background 120ms ease,
color 120ms ease;
white-space: nowrap;
min-width: 0; /* Allow flex item to shrink */
}
.tree-item > .tree-item-text {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
}
.tree-item:hover {
background: var(--bg-hover);
color: var(--text-primary);
}
.tree-item > .badge-small {
margin-left: 4px;
}
.tree-item.active {
background: var(--bg-hover);
color: var(--accent);
}
.tree-item.focused {
background: color-mix(in srgb, var(--accent) 12%, transparent);
color: var(--text-primary);
box-shadow: inset 2px 0 0 var(--accent);
}
.tree-item.path-selected {
background: color-mix(in srgb, var(--accent) 20%, transparent);
color: var(--accent);
box-shadow:
inset 0 0 0 2px var(--accent),
inset 2px 0 0 var(--accent);
border-radius: 6px;
animation: pathPulse 1.5s ease-out;
}
@keyframes pathPulse {
0% {
background: color-mix(in srgb, var(--accent) 40%, transparent);
}
100% {
background: color-mix(in srgb, var(--accent) 20%, transparent);
}
}
.tree-item.filtered-out {
display: none;
}
.tree-item .icon {
width: 16px;
height: 16px;
flex-shrink: 0;
color: var(--accent);
}
.tree-item.active .icon {
color: var(--accent);
}
.tree-item.vault-item .icon {
color: var(--accent);
}
.tree-item-action-btn {
margin-left: auto;
width: 24px;
height: 24px;
display: inline-flex;
align-items: center;
justify-content: center;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-secondary);
color: var(--accent);
cursor: pointer;
opacity: 1;
pointer-events: auto;
transition:
opacity 140ms ease,
color 140ms ease,
background 140ms ease,
border-color 140ms ease;
flex-shrink: 0;
z-index: 1;
}
.tree-item-action-btn:hover,
.tree-item-action-btn:focus-visible {
background: color-mix(in srgb, var(--accent) 10%, transparent);
border-color: color-mix(in srgb, var(--accent) 25%, var(--border));
color: var(--accent);
outline: none;
}
/* ---------------------------------------------------------------------------
Drag & Drop — tree items
--------------------------------------------------------------------------- */
/* Source item being dragged */
.tree-item.drag-source {
opacity: 0.35;
outline: 1px dashed var(--border);
}
/* Valid drop targets during drag — subtle pulse indicator */
.tree-item.drag-valid-target {
outline: 1px dashed color-mix(in srgb, var(--accent) 30%, transparent);
outline-offset: -1px;
}
/* Active drop target (hovering over) */
.tree-item.drag-over {
background: color-mix(in srgb, var(--accent) 18%, transparent) !important;
outline: 2px solid var(--accent);
outline-offset: -2px;
border-radius: 4px;
}
/* Vault item as drop target */
.tree-item.vault-item.drag-over {
background: color-mix(in srgb, var(--accent) 15%, transparent) !important;
outline: 2px solid var(--accent);
outline-offset: -2px;
}
/* Global Drag & Drop Overlay (#89) */
.obsigate-drop-overlay {
position: fixed;
inset: 0;
z-index: 99999;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.obsigate-drop-overlay.active {
opacity: 1;
pointer-events: auto;
}
.obsigate-drop-backdrop {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.65);
backdrop-filter: blur(4px);
}
.obsigate-drop-modal {
position: relative;
z-index: 1;
background: var(--bg-primary, #1e1e2e);
border: 1px solid var(--border-color, #313244);
border-radius: 12px;
padding: 24px;
width: min(600px, 90vw);
box-shadow: 0 16px 32px rgba(0, 0, 0, 0.4);
text-align: center;
}
.obsigate-drop-title {
margin: 0 0 20px 0;
font-size: 1.25rem;
font-weight: 600;
color: var(--text-normal, #cdd6f4);
}
.obsigate-drop-zones {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.obsigate-drop-zone {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 28px 16px;
border: 2px dashed var(--border-color, #45475a);
border-radius: 8px;
background: var(--bg-secondary, #181825);
cursor: pointer;
transition: all 0.15s ease;
}
.obsigate-drop-zone.hover {
border-color: var(--accent, #89b4fa);
background: color-mix(in srgb, var(--accent, #89b4fa) 15%, var(--bg-secondary, #181825));
transform: scale(1.02);
}
.obsigate-drop-zone-icon {
font-size: 2.5rem;
margin-bottom: 12px;
}
.obsigate-drop-zone-title {
font-size: 1rem;
font-weight: 600;
color: var(--text-normal, #cdd6f4);
margin-bottom: 6px;
}
.bookslm-composer.bookslm-drop-over {
outline: 2px dashed var(--accent, #89b4fa);
outline-offset: 2px;
background: color-mix(in srgb, var(--accent, #89b4fa) 10%, var(--bg-secondary, #181825));
}
.tree-children {
padding-left: 16px;
overflow: hidden;
}
.tree-children.collapsed {
display: none;
}
.tree-children.filtered-out {
display: none;
}
.filter-results-header {
margin-top: 8px;
}
.filter-results-group {
display: flex;
flex-direction: column;
gap: 4px;
padding: 4px 0 10px 12px;
}
.filter-result-item {
align-items: flex-start;
white-space: normal;
overflow: visible;
border-radius: 6px;
}
.filter-result-text {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
white-space: normal;
}
.filter-result-primary {
color: var(--text-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.filter-result-secondary {
color: var(--text-muted);
font-size: 0.75rem;
word-break: break-all;
opacity: 0.8;
}
.sidebar-filter-empty {
padding: 12px 16px;
color: var(--text-muted);
font-size: 0.85rem;
}
.filter-highlight {
background: color-mix(in srgb, var(--accent) 22%, transparent);
color: var(--accent);
padding: 0 2px;
border-radius: 4px;
}
/* --- Tag Cloud --- */
.tag-cloud {
display: flex;
flex-wrap: wrap;
gap: 6px;
padding: 14px 16px 16px;
align-content: flex-start;
}
.tag-item {
display: inline-block;
padding: 2px 8px;
background: var(--tag-bg);
color: var(--tag-text);
border-radius: 4px;
font-family: "JetBrains Mono", monospace;
cursor: pointer;
transition: opacity 150ms ease;
line-height: 1.4;
}
.tag-item:hover {
opacity: 0.8;
}
.tag-item.filtered-out {
display: none;
}
/* --- Sidebar resize handle (horizontal) --- */
.sidebar-resize-handle {
width: 5px;
cursor: ew-resize;
background: transparent;
flex-shrink: 0;
transition:
background 150ms ease,
opacity 300ms ease;
z-index: 10;
}
.sidebar-resize-handle:hover,
.sidebar-resize-handle.active {
background: var(--accent);
opacity: 0.5;
}
.sidebar-resize-handle.hidden {
width: 0;
opacity: 0;
pointer-events: none;
}
/* --- Content Wrapper (tabs + content) --- */
.content-wrapper {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
overflow: hidden;
position: relative;
}
/* --- Multi-Pane Grid (Split View #75) --- */
.pane-grid {
flex: 1;
display: grid;
overflow: hidden;
min-width: 0;
min-height: 0;
}
.pane-container {
display: flex;
flex-direction: column;
overflow: hidden;
min-width: 0;
min-height: 0;
border: 2px solid transparent;
transition: border-color 150ms ease;
position: relative;
}
.pane-container.pane-active {
border-color: var(--accent);
}
.pane-container .tab-bar.pane-tab-bar {
flex-shrink: 0;
}
.pane-container .content-area.pane-content {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: clamp(12px, 2vw, 24px) clamp(12px, 3vw, 24px) 40px;
}
.pane-resize-handle {
width: 4px;
background: var(--border);
transition: background 150ms ease;
position: relative;
z-index: 2;
flex-shrink: 0;
}
.pane-resize-handle:hover {
background: var(--accent);
}
.pane-resize-handle::after {
content: '';
position: absolute;
top: 10%;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
width: 2px;
background: var(--accent);
opacity: 0;
transition: opacity 150ms ease;
}
.pane-resize-handle:hover::after {
opacity: 1;
}
/* Pane active state */
.pane-container.pane-active {
outline: none;
border: 2px solid var(--accent);
}
/* --- Drop zone indicators for drag-to-split --- */
.pane-drop-zone-indicator {
position: absolute;
z-index: 10;
background: var(--accent);
opacity: 0.4;
pointer-events: none;
transition: opacity 100ms ease;
}
.pane-drop-zone-indicator.pane-drop-zone-right {
top: 0;
right: 0;
width: 25%;
height: 100%;
}
.pane-drop-zone-indicator.pane-drop-zone-bottom {
bottom: 0;
left: 0;
width: 100%;
height: 25%;
}
/* Tab bar drop target highlight */
.tab-bar.drop-target {
background: var(--accent);
opacity: 0.15;
outline: 2px dashed var(--accent);
outline-offset: -2px;
}
/* Responsive: disable split view below 768px */
@media (max-width: 768px) {
.pane-grid {
display: flex !important;
flex-direction: column !important;
}
.pane-grid .pane-container:not(:first-child) {
display: none;
}
.pane-grid .pane-resize-handle {
display: none;
}
.pane-container.pane-active {
border-color: transparent;
}
}
/* --- Content Area --- */
.content-area {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: clamp(16px, 3vw, 40px) clamp(16px, 4vw, 40px) 60px;
transition:
background 200ms ease,
margin 300ms ease;
min-width: 0;
}
/* Center content when sidebar is hidden */
.sidebar.hidden ~ .content-wrapper .content-area {
margin: 0 auto;
max-width: 1200px;
}
/* Full-bleed viewers (PDF, images, Excalidraw) must use the whole width when
the navigation sidebar is hidden instead of the centered reading column. */
.sidebar.hidden ~ .content-wrapper .content-area:has(.pdf-viewer-container),
.sidebar.hidden ~ .content-wrapper .content-area:has(.image-viewer-container),
.sidebar.hidden ~ .content-wrapper .content-area:has(iframe[src*="excalidraw-editor.html"]) {
margin: 0;
max-width: none;
}
.content-area::-webkit-scrollbar {
width: 8px;
}
.content-area::-webkit-scrollbar-thumb {
background: var(--scrollbar);
border-radius: 4px;
}
/* --- Right Sidebar Resize Handle --- */
.right-sidebar-resize-handle {
width: 5px;
cursor: ew-resize;
background: transparent;
flex-shrink: 0;
transition:
background 150ms ease,
opacity 300ms ease;
z-index: 10;
}
.right-sidebar-resize-handle:hover,
.right-sidebar-resize-handle.active {
background: var(--accent);
opacity: 0.5;
}
.right-sidebar-resize-handle.hidden {
width: 0;
opacity: 0;
pointer-events: none;
}
/* --- Right Sidebar (Outline/TOC) --- */
.right-sidebar {
width: 280px;
min-width: 200px;
max-width: 400px;
background: var(--bg-sidebar);
border-left: 1px solid var(--border);
display: flex;
flex-direction: column;
overflow: hidden;
transition:
background 200ms ease,
transform 300ms ease,
width 300ms ease;
flex-shrink: 0;
}
.right-sidebar.hidden {
transform: translateX(100%);
width: 0;
min-width: 0;
border-left: none;
}
/* Right sidebar header */
.right-sidebar-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border-bottom: 1px solid var(--border);
background: var(--bg-sidebar);
flex-shrink: 0;
}
.right-sidebar-title {
font-family: "JetBrains Mono", monospace;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
margin: 0;
}
.right-sidebar-toggle-btn {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
padding: 0;
background: transparent;
border: 1px solid var(--border);
border-radius: 4px;
color: var(--text-secondary);
cursor: pointer;
transition: all 150ms ease;
}
.right-sidebar-toggle-btn:hover {
background: var(--bg-hover);
border-color: var(--accent);
color: var(--accent);
}
.right-sidebar-toggle-btn i {
transition: transform 200ms ease;
}
.right-sidebar.hidden .right-sidebar-toggle-btn i {
transform: rotate(180deg);
}
/* Outline panel */
.outline-panel {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: 8px 0;
min-height: 0;
}
.outline-panel::-webkit-scrollbar {
width: 6px;
}
.outline-panel::-webkit-scrollbar-thumb {
background: var(--scrollbar);
border-radius: 3px;
}
.outline-list {
display: flex;
flex-direction: column;
gap: 2px;
padding: 0 8px;
}
.outline-item {
display: flex;
align-items: center;
padding: 8px 12px;
border-radius: 6px;
font-family: "JetBrains Mono", monospace;
font-size: 0.82rem;
color: var(--text-secondary);
cursor: pointer;
transition: all 150ms ease;
position: relative;
text-decoration: none;
line-height: 1.4;
word-break: break-word;
}
.outline-item:hover {
background: var(--bg-hover);
color: var(--text-primary);
}
.outline-item.active {
background: color-mix(in srgb, var(--accent) 12%, transparent);
color: var(--accent);
font-weight: 500;
}
.outline-item.active::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: var(--accent);
border-radius: 0 2px 2px 0;
}
/* Heading levels */
.outline-item.level-2 {
font-weight: 600;
font-size: 0.85rem;
padding-left: 12px;
}
.outline-item.level-3 {
font-weight: 400;
font-size: 0.8rem;
padding-left: 28px;
color: var(--text-muted);
}
.outline-item.level-3:hover {
color: var(--text-secondary);
}
.outline-item.level-3.active {
color: var(--accent);
}
/* Empty state */
.outline-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 20px;
gap: 12px;
color: var(--text-muted);
font-size: 0.85rem;
text-align: center;
}
/* Reading progress */
.reading-progress {
padding: 12px 16px;
border-top: 1px solid var(--border);
background: var(--bg-sidebar);
flex-shrink: 0;
}
.reading-progress-bar {
width: 100%;
height: 6px;
background: color-mix(in srgb, var(--border) 50%, transparent);
border-radius: 3px;
overflow: hidden;
margin-bottom: 8px;
}
.reading-progress-fill {
height: 100%;
background: var(--accent);
border-radius: 3px;
transition: width 150ms ease;
width: 0%;
}
.reading-progress-text {
font-family: "JetBrains Mono", monospace;
font-size: 0.75rem;
font-weight: 600;
color: var(--text-muted);
text-align: center;
}
/* Welcome */
.welcome {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
color: var(--text-muted);
text-align: center;
gap: 12px;
}
.welcome h2 {
font-family: "JetBrains Mono", monospace;
font-size: 1.6rem;
color: var(--text-secondary);
}
.welcome p {
font-size: 0.95rem;
max-width: 400px;
}
/* Breadcrumb */
.breadcrumb {
font-family: "JetBrains Mono", monospace;
font-size: 0.78rem;
color: var(--text-muted);
margin-bottom: 12px;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 4px;
}
.breadcrumb span {
cursor: pointer;
color: var(--text-secondary);
transition: color 120ms ease;
}
.breadcrumb span:hover {
color: var(--accent);
}
.breadcrumb .sep {
cursor: default;
color: var(--text-muted);
}
.breadcrumb .sep:hover {
color: var(--text-muted);
}
/* File header */
.file-header {
margin-bottom: 8px;
}
/* #115 — sticky document action bar: stays visible while long content scrolls.
A direct child of `.content-area` (the scroll container), opaque so the text
scrolling underneath never bleeds through. */
.file-toolbar {
position: sticky;
top: 0;
z-index: 30;
margin: 0 0 16px;
padding: 8px 0;
background: var(--bg-primary);
border-bottom: 1px solid var(--border);
}
.file-toolbar .file-actions {
margin-top: 0;
}
.file-title {
font-family: "JetBrains Mono", monospace;
font-size: 1.6rem;
font-weight: 700;
margin-bottom: 8px;
}
.file-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 6px;
}
.file-tag {
display: inline-block;
padding: 2px 8px;
background: var(--tag-bg);
color: var(--tag-text);
border-radius: 4px;
font-family: "JetBrains Mono", monospace;
font-size: 0.75rem;
margin-right: 6px;
margin-bottom: 4px;
cursor: pointer;
transition:
opacity 150ms ease,
transform 100ms ease;
}
.file-tag:hover {
opacity: 0.8;
transform: translateY(-1px);
}
.file-actions {
margin-top: 8px;
display: flex;
flex-wrap: wrap;
gap: 6px;
align-items: center;
}
/* Separateur vertical entre groupes d'actions (#90) */
.file-actions .action-sep {
align-self: stretch;
width: 1px;
min-height: 20px;
margin: 2px 4px;
background: var(--border-md, var(--border));
flex-shrink: 0;
}
.btn-action {
font-family: "JetBrains Mono", monospace;
font-size: 0.75rem;
padding: 4px 10px;
border: 1px solid var(--border);
border-radius: 6px;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
transition:
color 150ms ease,
border-color 150ms ease;
display: inline-flex;
align-items: center;
gap: 4px;
}
.btn-action:hover {
color: var(--accent);
border-color: var(--accent);
}
.btn-action.active {
color: var(--accent);
border-color: var(--accent);
background: var(--tag-bg);
}
/* ===== FRONTMATTER — ACCENT CARD ===== */
/* Frontmatter section wrapper */
.fm-section {
margin-bottom: 20px;
}
/* Header toggle */
.fm-header {
font-family: "JetBrains Mono", monospace;
font-size: 0.78rem;
color: var(--text-muted);
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
margin-bottom: 12px;
user-select: none;
transition: color 150ms ease;
}
.fm-header:hover {
color: var(--text-secondary);
}
/* Chevron icon */
.fm-chevron {
transition: transform 0.2s;
display: inline-flex;
align-items: center;
justify-content: center;
}
.fm-chevron.open {
transform: rotate(0deg);
}
.fm-chevron.closed {
transform: rotate(-90deg);
}
/* Accent Card main container */
.ac-card {
border: 1px solid var(--border-md);
border-left: 3px solid var(--accent-card);
border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
background: var(--surface);
overflow: hidden;
}
/* ZONE 1 — Top strip */
.ac-top {
padding: 12px 16px 10px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.ac-title {
font-size: 14px;
font-weight: 600;
color: var(--text);
font-family: var(--mono);
letter-spacing: -0.01em;
flex-shrink: 0;
}
.ac-badge {
padding: 2px 9px;
border-radius: 99px;
font-size: 11px;
font-weight: 500;
display: inline-flex;
align-items: center;
gap: 4px;
}
.ac-badge.green {
background: var(--green-bg);
color: var(--green);
}
.ac-badge.blue {
background: var(--accent-bg);
color: var(--accent-text);
}
.ac-badge.purple {
background: var(--purple-bg);
color: var(--purple);
}
.ac-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: currentColor;
opacity: 0.7;
}
/* ZONE 2 — Body 2 columns */
.ac-body {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0;
}
.ac-col {
padding: 12px 16px;
}
.ac-col + .ac-col {
border-left: 1px solid var(--border);
}
.ac-row {
display: flex;
align-items: baseline;
gap: 6px;
padding: 4px 0;
font-size: 12.5px;
}
.ac-row + .ac-row {
border-top: 1px solid var(--border);
}
.ac-k {
color: var(--text-3);
font-size: 11px;
font-family: var(--mono);
min-width: 110px;
flex-shrink: 0;
}
.ac-v {
color: var(--text);
font-weight: 500;
font-size: 12.5px;
}
.ac-v.mono {
font-family: var(--mono);
font-weight: 400;
color: var(--text-2);
font-size: 11px;
}
.ac-v.muted {
color: var(--text-3);
font-weight: 400;
}
/* ZONE 3 — Tags row */
.ac-tags-row {
padding: 10px 16px;
border-top: 1px solid var(--border);
display: flex;
align-items: center;
gap: 10px;
}
.ac-tags-k {
font-size: 11px;
font-family: var(--mono);
color: var(--text-3);
flex-shrink: 0;
}
.ac-tags-wrap {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.ac-tag {
padding: 2px 9px;
border-radius: 99px;
font-size: 11px;
font-weight: 500;
background: var(--accent-bg);
color: var(--accent-text);
border: 1px solid rgba(79, 110, 247, 0.18);
}
/* ZONE 4 — Flags row */
.ac-flags-row {
padding: 9px 16px;
border-top: 1px solid var(--border);
background: var(--surface2);
display: flex;
flex-wrap: wrap;
gap: 6px;
align-items: center;
}
.ac-flags-k {
font-size: 11px;
font-family: var(--mono);
color: var(--text-3);
margin-right: 2px;
}
.flag-chip {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
border-radius: var(--radius);
font-size: 11px;
font-weight: 500;
border: 1px solid var(--border-md);
}
.flag-chip.on {
background: var(--green-bg);
color: var(--green);
border-color: rgba(26, 127, 80, 0.2);
}
.flag-chip.off {
background: var(--surface3);
color: var(--text-3);
}
.flag-dot {
width: 5px;
height: 5px;
border-radius: 50%;
background: currentColor;
opacity: 0.7;
}
/* --- Raw source view --- */
.raw-source-view {
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 8px;
padding: 16px;
margin-top: 12px;
font-family: "JetBrains Mono", monospace;
font-size: 0.82rem;
color: var(--text-secondary);
white-space: pre-wrap;
word-break: break-word;
overflow-x: auto;
line-height: 1.55;
max-height: 70vh;
overflow-y: auto;
}
/* --- Pretty print (mode lecture fichiers texte non-markdown) --- */
.pretty-view {
position: relative;
display: grid;
grid-template-columns: auto 1fr;
align-items: stretch;
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 8px;
overflow: auto;
max-height: 78vh;
}
.pretty-view .pp-gutter {
position: sticky; /* figee au scroll horizontal, suit le scroll vertical */
left: 0;
z-index: 2;
display: flex;
flex-direction: column;
padding: 16px 10px 16px 14px;
text-align: right;
font-family: "JetBrains Mono", monospace;
font-size: 0.85rem;
line-height: 1.55;
color: var(--text-muted);
opacity: 0.65;
user-select: none;
background: var(--bg-secondary);
border-right: 1px solid var(--border);
box-sizing: border-box;
}
.pretty-view .pp-pre {
margin: 0 !important;
border: none !important;
border-radius: 0 !important;
background: transparent !important;
padding: 16px !important;
overflow: visible;
}
.pretty-view .pp-pre code {
font-family: "JetBrains Mono", monospace;
font-size: 0.85rem;
line-height: 1.55;
white-space: pre;
display: block;
}
/* Niveaux de log colorises par le fallback pretty-print (pas d'equivalent hljs) */
.pretty-view .pp-level {
font-weight: 700;
}
.pretty-view .pp-err {
color: #f87171;
}
.pretty-view .pp-warn {
color: #fbbf24;
}
.pretty-view .pp-info {
color: #38bdf8;
}
.pretty-view .pp-debug {
color: var(--text-muted);
}
[data-theme="light"] .pretty-view .pp-err {
color: #dc2626;
}
[data-theme="light"] .pretty-view .pp-warn {
color: #b45309;
}
[data-theme="light"] .pretty-view .pp-info {
color: #0369a1;
}
/* --- Markdown Rendered Content --- */
.md-content h1,
.md-content h2,
.md-content h3,
.md-content h4,
.md-content h5,
.md-content h6 {
font-family: "JetBrains Mono", monospace;
font-weight: 700;
margin: 1.4em 0 0.5em;
color: var(--text-primary);
}
.md-content h1 {
font-size: 1.5rem;
border-bottom: 1px solid var(--border);
padding-bottom: 6px;
}
.md-content h2 {
font-size: 1.25rem;
}
.md-content h3 {
font-size: 1.1rem;
}
.md-content p {
margin: 0.6em 0;
}
.md-content ul,
.md-content ol {
padding-left: 1.6em;
margin: 0.5em 0;
}
.md-content li {
margin: 0.25em 0;
}
.md-content blockquote {
border-left: 3px solid var(--accent);
padding: 4px 16px;
margin: 0.8em 0;
color: var(--text-secondary);
background: var(--bg-secondary);
border-radius: 0 6px 6px 0;
}
.md-content code {
font-family: "JetBrains Mono", monospace;
background: var(--code-bg);
padding: 2px 6px;
border-radius: 4px;
font-size: 0.88em;
border: 1px solid var(--border);
}
.md-content pre {
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 8px;
padding: 16px;
overflow-x: auto;
margin: 0.8em 0;
}
.md-content pre code {
background: none;
border: none;
padding: 0;
font-size: 0.85rem;
line-height: 1.55;
}
.md-content table {
width: 100%;
border-collapse: collapse;
margin: 0.8em 0;
font-size: 0.92rem;
}
.md-content th,
.md-content td {
border: 1px solid var(--border);
padding: 8px 12px;
text-align: left;
}
.md-content th {
background: var(--bg-secondary);
font-family: "JetBrains Mono", monospace;
font-weight: 600;
font-size: 0.85rem;
}
.md-content img {
max-width: 100%;
border-radius: 8px;
margin: 0.6em 0;
}
.md-content hr {
border: none;
border-top: 1px solid var(--border);
margin: 1.5em 0;
}
.md-content .task-list-item {
list-style: none;
margin-left: -1.2em;
}
.md-content .task-list-item input[type="checkbox"] {
margin-right: 6px;
}
/* Wikilinks */
.wikilink,
.wikilink-anchor {
color: var(--accent);
border-bottom: 1px dashed var(--accent);
cursor: pointer;
}
.wikilink:hover,
.wikilink-anchor:hover {
opacity: 0.8;
}
.wikilink-anchor {
text-decoration: none;
}
.wikilink-missing {
color: var(--text-muted);
border-bottom: 1px dashed var(--text-muted);
cursor: default;
}
/* Image placeholders */
.image-not-found {
display: inline-block;
padding: 8px 12px;
background: var(--danger-bg);
color: var(--danger);
border: 1px dashed var(--danger);
border-radius: 4px;
font-family: "JetBrains Mono", monospace;
font-size: 0.85rem;
cursor: help;
}
/* Markdown images */
.file-content img {
max-width: 100%;
height: auto;
display: block;
margin: 16px 0;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.file-content a img {
cursor: pointer;
transition: opacity 0.2s ease;
}
.file-content a img:hover {
opacity: 0.85;
}
/* --- Search Results --- */
.search-results {
padding: 0;
}
.search-results-header {
font-family: "JetBrains Mono", monospace;
font-size: 0.85rem;
color: var(--text-muted);
margin-bottom: 16px;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.search-results-summary-text {
display: inline;
}
.search-results-active-tags {
display: inline-flex;
flex-wrap: wrap;
gap: 6px;
align-items: center;
}
.search-results-active-tag {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 3px 8px;
background: var(--tag-bg);
color: var(--tag-text);
border-radius: 999px;
font-family: "JetBrains Mono", monospace;
font-size: 0.75rem;
line-height: 1.2;
}
.search-results-active-tag-remove {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
border: none;
background: transparent;
color: inherit;
cursor: pointer;
padding: 0;
}
.search-result-item {
padding: 14px 16px;
border: 1px solid var(--border);
border-radius: 8px;
margin-bottom: 10px;
cursor: pointer;
transition:
background 120ms ease,
border-color 120ms ease;
position: relative;
}
.search-result-item:hover {
background: var(--bg-hover);
border-color: var(--accent);
}
.search-result-ext {
position: absolute;
top: 8px;
right: 10px;
font-size: 0.65rem;
font-weight: 700;
text-transform: uppercase;
color: var(--accent);
background: var(--accent-bg, rgba(99, 102, 241, 0.12));
padding: 2px 8px;
border-radius: 4px;
letter-spacing: 0.5px;
border: 1px solid rgba(99, 102, 241, 0.2);
}
.search-filters-row {
display: flex;
gap: 4px;
flex-wrap: wrap;
margin-top: 4px;
}
.search-filter-badge {
font-size: 0.65rem;
font-family: "JetBrains Mono", monospace;
padding: 1px 6px;
border-radius: 3px;
background: rgba(99, 102, 241, 0.1);
color: var(--accent);
font-weight: 600;
}
.search-filter-badge.path {
background: rgba(5, 150, 105, 0.1);
color: #059669;
}
/* Save search button */
.search-save-btn {
padding: 4px 10px;
font-size: 0.75rem;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--bg-secondary);
color: var(--text-primary);
cursor: pointer;
display: flex;
align-items: center;
gap: 4px;
}
.search-save-btn:hover { background: var(--bg-hover); }
/* Saved searches sidebar */
.saved-search-item {
position: relative;
padding: 10px 12px;
cursor: pointer;
border-radius: 6px;
transition: background 0.15s;
border: 1px solid transparent;
margin-bottom: 4px;
}
.saved-search-item:hover { background: var(--bg-hover); border-color: var(--border); }
.saved-search-query {
font-size: 0.82rem;
font-family: "JetBrains Mono", monospace;
line-height: 1.4;
word-break: break-word;
overflow-wrap: anywhere;
margin-bottom: 6px;
}
.saved-search-meta {
display: flex;
gap: 4px;
align-items: center;
flex-wrap: wrap;
margin-bottom: 2px;
}
.saved-search-badges {
display: flex;
gap: 4px;
align-items: center;
flex-wrap: wrap;
flex: 1;
min-width: 0;
}
.saved-search-type-icon {
margin-left: auto;
flex-shrink: 0;
opacity: 0.6;
}
/* Saved filter bar */
.saved-filter-bar {
display: flex;
gap: 6px;
padding: 8px 10px 10px;
}
.saved-filter-pill {
padding: 3px 10px;
font-size: 0.7rem;
font-weight: 500;
border: 1px solid var(--border);
border-radius: 12px;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.saved-filter-pill:hover { background: var(--bg-hover); color: var(--text-primary); }
.saved-filter-pill.active {
background: var(--accent-bg, rgba(99,102,241,0.12));
color: var(--accent);
border-color: var(--accent);
}
/* Offline indicator */
.offline-indicator {
display: flex;
align-items: center;
gap: 6px;
padding: 2px 8px;
border-radius: 4px;
font-size: 0.7rem;
cursor: default;
}
.offline-indicator.offline {
background: var(--warn-bg, rgba(251,191,36,0.12));
color: var(--warn);
border: 1px solid var(--warn);
}
.offline-pending {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 16px;
height: 16px;
padding: 0 4px;
border-radius: 8px;
background: var(--warn);
color: #000;
font-size: 0.6rem;
font-weight: 700;
}
/* Theme picker grid */
.theme-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 10px;
margin-top: 12px;
}
.theme-card {
background: var(--bg-secondary);
border: 2px solid var(--border);
border-radius: 8px;
padding: 10px;
cursor: pointer;
transition: border-color 0.2s, transform 0.15s;
}
.theme-card:hover { border-color: var(--accent); transform: translateY(-1px); }
.theme-card.active { border-color: var(--accent-green); }
.theme-card-preview {
height: 40px;
border-radius: 4px;
margin-bottom: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.theme-card-preview-bar {
height: 14px;
}
.theme-card-preview-body {
flex: 1;
display: flex;
align-items: center;
padding: 0 6px;
}
.theme-card-preview-btn {
width: 50%;
height: 10px;
border-radius: 3px;
}
.theme-card-name {
font-size: 0.75rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 2px;
}
.theme-card-desc {
font-size: 0.65rem;
color: var(--text-muted);
}
.theme-mode-toggle {
display: flex;
gap: 0;
margin-top: 16px;
border: 1px solid var(--border);
border-radius: 6px;
overflow: hidden;
width: fit-content;
}
.theme-mode-btn {
padding: 4px 14px;
font-size: 0.7rem;
border: none;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
}
.theme-mode-btn.active {
background: var(--accent);
color: #fff;
}
/* Theme import/export actions */
.theme-actions {
display: flex;
gap: 8px;
margin-top: 14px;
padding-top: 12px;
border-top: 1px solid var(--border);
}
.theme-action-btn {
padding: 5px 14px;
font-size: 0.7rem;
font-weight: 600;
border: 1px solid var(--border);
background: var(--bg-secondary);
color: var(--text-secondary);
border-radius: 6px;
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.theme-action-btn:hover {
background: var(--bg-hover);
color: var(--text-primary);
}
.theme-custom-badge {
font-size: 0.6rem;
color: var(--accent);
margin-left: 2px;
}
/* Profile section */
.profile-form { max-width: 420px; }
.profile-field { margin-bottom: 14px; }
.profile-field label { display: block; font-size: 0.75rem; font-weight: 600; color: var(--text-primary); margin-bottom: 4px; }
.profile-field .config-input,
.profile-field .config-select {
width: 100%; padding: 6px 10px; font-size: 0.8rem;
background: var(--bg-primary); color: var(--text-primary);
border: 1px solid var(--border); border-radius: 6px;
font-family: inherit;
}
.profile-hint { display: block; font-size: 0.65rem; color: var(--text-muted); margin-top: 4px; }
.profile-saved { font-size: 0.7rem; color: var(--accent-green); margin-left: 10px; }
/* Profile picture picker (#113) */
.profile-avatar-field { margin-bottom: 18px; }
.profile-avatar-label { display: block; font-size: 0.75rem; font-weight: 600; color: var(--text-primary); margin-bottom: 8px; }
.profile-avatar-row { display: flex; align-items: center; gap: 16px; }
.profile-avatar-preview {
position: relative;
width: 88px;
height: 88px;
border-radius: 50%;
flex-shrink: 0;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #7c3aed));
border: 2px solid var(--border);
cursor: pointer;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.profile-avatar-preview:hover,
.profile-avatar-preview:focus-within {
border-color: var(--accent);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.profile-avatar-preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
.profile-avatar-initials {
font-size: 1.5rem;
font-weight: 700;
letter-spacing: 0.02em;
color: #fff;
user-select: none;
}
.profile-avatar-overlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
border: 0;
padding: 0;
margin: 0;
background: rgba(0, 0, 0, 0.45);
color: #fff;
cursor: pointer;
opacity: 0;
transition: opacity 0.15s ease;
}
.profile-avatar-preview:hover .profile-avatar-overlay,
.profile-avatar-overlay:focus-visible { opacity: 1; }
.profile-avatar-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; min-width: 0; }
.profile-avatar-actions .config-btn-secondary { font-size: 0.75rem; padding: 6px 14px; }
.profile-avatar-remove-btn { background: var(--danger-bg) !important; color: var(--danger) !important; border-color: var(--danger) !important; }
.profile-avatar-error { font-size: 0.7rem; color: var(--danger); margin-top: 8px; }
.profile-avatar-error.hidden { display: none; }
/* #117 — preset avatar gallery */
.profile-avatar-presets {
display: grid;
grid-template-columns: repeat(6, minmax(0, 1fr));
gap: 8px;
margin-top: 10px;
max-width: 420px;
}
.profile-avatar-preset {
padding: 0;
margin: 0;
border: 2px solid var(--border);
border-radius: 50%;
overflow: hidden;
cursor: pointer;
background: var(--bg-secondary);
aspect-ratio: 1;
transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}
.profile-avatar-preset img { width: 100%; height: 100%; object-fit: cover; display: block; }
.profile-avatar-preset:hover { border-color: var(--accent); transform: translateY(-1px); }
.profile-avatar-preset.active {
border-color: var(--accent);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.profile-avatar-preset:disabled { opacity: 0.6; cursor: progress; }
.config-save-btn {
padding: 6px 18px; font-size: 0.75rem; font-weight: 600;
background: var(--accent); color: #fff;
border: 1px solid var(--accent); border-radius: 6px;
cursor: pointer; transition: opacity 0.15s;
}
.config-save-btn:hover { opacity: 0.85; }
.saved-search-vault {
font-size: 0.65rem;
color: var(--text-muted);
padding: 1px 5px;
background: var(--bg-secondary);
border-radius: 3px;
}
.saved-search-filters {
font-size: 0.65rem;
color: var(--accent);
display: flex;
gap: 4px;
flex-wrap: wrap;
}
.saved-search-path {
font-size: 0.6rem;
color: #059669;
background: rgba(5,150,105,0.08);
padding: 1px 5px;
border-radius: 3px;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.saved-search-delete {
position: absolute;
top: 6px;
right: 8px;
background: none;
border: none;
color: var(--text-muted);
cursor: pointer;
font-size: 0.9rem;
padding: 2px 6px;
opacity: 0;
transition: opacity 0.15s;
}
.saved-search-item:hover .saved-search-delete { opacity: 1; }
.saved-search-delete:hover { color: var(--text-error); }
.search-result-title {
font-family: "JetBrains Mono", monospace;
font-size: 0.92rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 4px;
}
.search-result-vault {
font-family: "JetBrains Mono", monospace;
font-size: 0.72rem;
color: var(--accent-green);
margin-bottom: 4px;
}
.search-result-snippet {
font-size: 0.85rem;
color: var(--text-secondary);
line-height: 1.5;
}
.search-result-snippet .search-highlight {
background: color-mix(in srgb, var(--accent) 25%, transparent);
color: var(--accent);
font-weight: 600;
padding: 1px 3px;
border-radius: 3px;
}
.search-result-title .search-highlight {
background: color-mix(in srgb, var(--accent) 25%, transparent);
color: var(--accent);
font-weight: 700;
padding: 1px 3px;
border-radius: 3px;
}
.search-result-tags {
margin-top: 6px;
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.search-result-tags .file-tag {
font-size: 0.7rem;
padding: 1px 6px;
}
/* --- Loading indicator --- */
.loading-indicator {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 20px;
color: var(--text-muted);
gap: 12px;
}
.loading-spinner {
width: 32px;
height: 32px;
border: 3px solid var(--border);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* --- Search progress bar --- */
.search-progress-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 3px;
z-index: 9999;
background: transparent;
pointer-events: none;
opacity: 0;
transition: opacity 0.15s;
}
.search-progress-bar.active {
opacity: 1;
}
.search-progress-bar .search-progress-bar__fill {
height: 100%;
background: var(--accent);
width: 0%;
animation: progress-indeterminate 1.5s ease-in-out infinite;
}
@keyframes progress-indeterminate {
0% {
width: 0%;
margin-left: 0%;
}
50% {
width: 40%;
margin-left: 30%;
}
100% {
width: 0%;
margin-left: 100%;
}
}
.search-time-badge {
font-size: 0.7rem;
color: var(--text-muted);
margin-left: 8px;
}
/* --- Editor Modal --- */
.editor-modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
background: var(--overlay-bg);
align-items: center;
justify-content: center;
padding: 20px;
}
.editor-modal.active {
display: flex;
}
.help-container {
max-width: 1320px;
}
.editor-container {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 12px;
width: 100%;
max-width: 1200px;
max-height: 90vh;
display: flex;
flex-direction: column;
overflow: hidden;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}
/* Native fullscreen (#101) — the editor fills the viewport regardless of the
inline/modal constraints above. */
.editor-container:fullscreen {
width: 100vw;
height: 100vh;
max-width: none;
max-height: none;
border: none;
border-radius: 0;
box-shadow: none;
}
.editor-container:fullscreen .editor-body,
.editor-container:fullscreen .editor-body-cm {
flex: 1;
min-height: 0;
}
/* --- Inline edition (#93) --------------------------------------------------
When a document is being edited, `#editor-container` is moved into the
document content area: the editor *replaces* the read view instead of
covering it with the overlay, so the AI assistant sidebar stays usable.
The overlay itself is neutralised but kept mounted (and `active`) because
the mobile editing ribbon (`#me-toolbar`, `.me-ribbon`) is anchored to it. */
.editor-modal.editor-inline-mode {
display: block;
background: transparent;
padding: 0;
pointer-events: none;
}
.editor-modal.editor-inline-mode .me-ribbon {
pointer-events: auto;
}
.content-area.editor-inline-host,
.pane-content.editor-inline-host {
display: flex;
flex-direction: column;
padding: 0;
overflow: hidden;
}
.content-area.editor-inline-host .editor-container.editor-inline,
.pane-content.editor-inline-host .editor-container.editor-inline {
flex: 1;
height: auto;
width: 100%;
min-height: 0;
max-width: none;
max-height: none;
border: none;
border-radius: 0;
box-shadow: none;
background: var(--bg-primary);
}
.editor-container.editor-inline .editor-body,
.editor-container.editor-inline .editor-body-cm {
flex: 1;
min-height: 0;
}
.editor-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border-bottom: 1px solid var(--border);
background: var(--bg-primary);
flex-shrink: 0;
position: sticky;
top: 0;
z-index: 10;
}
/* AI processing indicator — shown inside editor header during AI calls */
.ai-processing-indicator {
display: none;
align-items: center;
gap: 6px;
padding: 3px 10px;
border-radius: 12px;
font-size: 0.72rem;
font-weight: 500;
color: #ffffff;
background: rgba(59, 130, 246, 0.3);
border: 1px solid rgba(96, 165, 250, 0.4);
animation: ai-indicator-pulse 1s ease-in-out infinite;
margin-left: 12px;
}
.ai-spinner {
width: 10px;
height: 10px;
border: 2px solid rgba(255,255,255,0.3);
border-top-color: #ffffff;
border-radius: 50%;
animation: ai-spinner-spin 0.6s linear infinite;
}
@keyframes ai-spinner-spin {
to { transform: rotate(360deg); }
}
@keyframes ai-indicator-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
/* AI custom-rewrite modal — replaces the browser prompt() for a consistent,
theme-aware and keyboard-accessible experience. */
.ai-modal-overlay {
position: fixed;
inset: 0;
z-index: 10050;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
background: rgba(0, 0, 0, 0.55);
backdrop-filter: blur(2px);
}
.ai-modal {
width: 100%;
max-width: 460px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 10px;
padding: 18px 18px 14px;
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45);
}
.ai-modal-title {
margin: 0 0 4px;
font-size: 0.95rem;
color: var(--text-primary);
}
.ai-modal-hint {
margin: 0 0 10px;
font-size: 0.78rem;
color: var(--text-muted);
}
.ai-modal-input {
width: 100%;
resize: vertical;
min-height: 72px;
padding: 8px 10px;
font-family: inherit;
font-size: 0.85rem;
color: var(--text-primary);
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 6px;
}
.ai-modal-input:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.25);
}
.ai-modal-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 12px;
}
.ai-modal-btn {
padding: 6px 14px;
font-size: 0.8rem;
border-radius: 6px;
cursor: pointer;
border: 1px solid var(--border);
background: transparent;
color: var(--text-primary);
}
.ai-modal-btn:hover { background: var(--bg-hover); }
.ai-modal-btn.primary {
background: var(--accent);
border-color: var(--accent);
color: #fff;
}
.ai-modal-btn.primary:hover { filter: brightness(1.08); }
.editor-title {
font-family: "JetBrains Mono", monospace;
font-size: 0.9rem;
color: var(--text-primary);
font-weight: 600;
}
.editor-brand { font-weight: 700; font-size: 12px; color: var(--accent); letter-spacing: 0.5px; white-space: nowrap; margin-right: 8px; }
.editor-title-input { flex: 1; min-width: 80px; background: transparent; border: 1px solid transparent; color: var(--text-primary); font-size: 13px; padding: 3px 6px; border-radius: 6px; outline: none; font-family: var(--font-sans); }
.editor-title-input:hover { border-color: var(--border); }
.editor-title-input:focus { border-color: var(--accent); background: var(--bg-input); }
.editor-sep { color: var(--text-muted); font-size: 13px; padding: 0 2px; user-select: none; }
.editor-filename-input { width: 140px; background: transparent; border: 1px solid transparent; color: var(--text-primary); font-size: 12px; padding: 3px 6px; border-radius: 6px; outline: none; font-family: var(--font-mono); }
.editor-filename-input:hover { border-color: var(--border); }
.editor-filename-input:focus { border-color: var(--ok); background: var(--bg-input); }
.editor-spacer { flex: 1; }
/* Collaboration temps réel (#62) — indicateur de présence */
.collab-presence { display: flex; align-items: center; gap: 6px; margin-right: 10px; }
.collab-status { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.collab-status-connected { background: var(--ok); }
.collab-status-connecting { background: var(--warn); animation: editor-pulse 1s infinite; }
.collab-status-disconnected { background: var(--err); animation: editor-pulse 0.8s infinite; }
.collab-avatars { display: flex; align-items: center; }
.collab-avatar { width: 20px; height: 20px; border-radius: 50%; color: #fff; font-size: 11px; font-weight: 600; display: flex; align-items: center; justify-content: center; margin-left: -6px; border: 2px solid var(--bg-secondary); }
.collab-avatar:first-child { margin-left: 0; }
.collab-avatar-self { box-shadow: 0 0 0 2px var(--bg-primary); }
.collab-count { font-size: 11px; color: var(--text-muted); min-width: 10px; }
/* Collaboration temps réel (#62) — curseurs distants CodeMirror */
.cm-remote-cursor { display: inline-block; width: 0; border-left: 2px solid; height: 1.2em; vertical-align: text-bottom; position: relative; margin-left: -1px; }
.cm-remote-cursor-label { position: absolute; top: -1.35em; left: -1px; padding: 1px 4px; border-radius: 3px 3px 3px 0; color: #fff; font-size: 10px; font-weight: 600; white-space: nowrap; pointer-events: none; z-index: 5; }
.editor-save-dot { display: flex; align-items: center; gap: 4px; font-size: 11px; padding: 0 4px; margin-right: 8px; }
.editor-btn + .editor-btn { margin-left: 6px; }
.editor-save-dot .dot { width: 6px; height: 6px; border-radius: 50%; }
.editor-save-dot.ok { color: var(--ok); } .editor-save-dot.ok .dot { background: var(--ok); }
.editor-save-dot.dirty { color: var(--warn); } .editor-save-dot.dirty .dot { background: var(--warn); }
.editor-save-dot.saving { color: var(--ai); } .editor-save-dot.saving .dot { background: var(--ai); }
@keyframes editor-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
.editor-save-dot.saving { animation: editor-pulse 0.8s infinite; }
.editor-save-dot.err { color: var(--err); } .editor-save-dot.err .dot { background: var(--err); }
/* BUG-045: only the CodeMirror scroller scrolls. #editor-body used to keep
overflow:auto AND host a 100%-tall .cm-editor below the AI toolbar row,
so the body (toolbar + editor) and the scroller both overflowed → two
stacked scrollbars. Flex column: toolbar fixed, editor fills, scroller
scrolls. Combined selector on purpose: `.editor-body` (defined later with
equal specificity) must not re-introduce overflow-y:auto. */
.editor-body.editor-body-cm { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }
.editor-body.editor-body-cm #ai-toolbar-container { flex: 0 0 auto; }
.editor-body.editor-body-cm .cm-editor { flex: 1 1 auto; height: auto; min-height: 0; overflow: hidden; }
.editor-body.editor-body-cm .fallback-editor { flex: 1 1 auto; height: auto; min-height: 0; resize: none; overflow: auto; }
.editor-body-cm .cm-editor .cm-scroller { font-family: var(--font-mono); font-size: 13.5px; line-height: 1.75; }
.editor-footer { height: 26px; min-height: 26px; display: flex; align-items: center; justify-content: space-between; padding: 0 12px; background: var(--bg-secondary); border-top: 1px solid var(--border); font-size: 11px; color: var(--text-muted); flex-shrink: 0; }
.editor-stat-file { color: var(--text-secondary); max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.editor-actions {
display: flex;
gap: 6px;
}
.editor-btn {
width: 36px;
height: 36px;
padding: 0;
border: 1px solid var(--border);
border-radius: 6px;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
transition: all 150ms ease;
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
}
.editor-btn:hover {
color: var(--accent);
border-color: var(--accent);
}
.editor-btn.primary {
background: var(--accent);
color: #ffffff;
border-color: var(--accent);
}
.editor-btn.primary:hover {
opacity: 0.9;
}
.editor-btn.danger:hover {
color: var(--danger);
border-color: var(--danger);
}
.editor-body {
flex: 1;
min-height: 0;
position: relative;
overflow-y: auto;
overflow-x: hidden;
}
.help-body {
padding: 0;
background: radial-gradient(circle at top right, color-mix(in srgb, var(--accent) 10%, transparent), transparent 30%), var(--bg-primary);
display: flex;
gap: 0;
overflow-y: auto;
overflow-x: hidden;
scroll-behavior: smooth;
}
/* Help Navigation Menu */
.help-hamburger {
display: none;
width: 36px; height: 36px;
padding: 0;
border: 1px solid var(--border);
border-radius: 6px;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-right: 8px;
}
.help-hamburger:hover { color: var(--accent); border-color: var(--accent); }
/* #114: close button for the mobile TOC drawer (hidden on desktop where the
nav is always visible). Scoped to #config-modal so the help modal — which
has no such button — is unaffected. */
.help-toc-close {
display: none;
width: 44px;
height: 44px;
padding: 0;
border: 1px solid var(--border);
border-radius: 6px;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.help-nav {
width: 260px;
min-width: 260px;
background: color-mix(in srgb, var(--bg-secondary) 94%, var(--bg-primary));
border-right: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
display: flex;
flex-direction: column;
position: sticky;
top: 0;
align-self: flex-start;
height: 100%;
max-height: calc(90vh - 57px);
flex-shrink: 0;
backdrop-filter: blur(12px);
overflow: hidden;
}
.help-nav-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 16px 10px;
flex-shrink: 0;
}
.help-nav-title {
font-family: "JetBrains Mono", monospace;
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
}
.help-nav-search-wrap {
padding: 0 12px 8px;
flex-shrink: 0;
display: flex;
align-items: center;
gap: 0;
}
.help-nav-search {
flex: 1;
padding: 7px 10px;
border: 1px solid var(--border);
border-right: none;
border-radius: 8px 0 0 8px;
background: var(--bg-primary);
color: var(--text-primary);
font-size: 0.78rem;
outline: none;
transition: border-color 0.2s;
min-width: 0;
}
.help-nav-search:focus {
border-color: var(--accent);
}
.help-nav-search:focus + .help-search-clear {
border-color: var(--accent);
border-left-color: var(--accent);
}
.help-nav-search::placeholder { color: var(--text-muted); }
.help-search-clear {
padding: 7px 10px;
border: 1px solid var(--border);
border-left: none;
border-radius: 0 8px 8px 0;
background: var(--bg-primary);
color: var(--text-muted);
cursor: pointer;
font-size: 14px;
line-height: 1;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: color 0.15s, background 0.15s;
}
.help-search-clear:hover {
color: var(--text-primary);
background: rgba(255,255,255,0.06);
}
.help-nav-list {
list-style: none;
margin: 0;
padding: 0 12px 20px;
flex: 1;
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
.help-nav-list li {
margin: 0 0 3px;
}
.help-nav-link {
display: block;
padding: 8px 12px;
font-size: 0.85rem;
color: var(--text-secondary);
text-decoration: none;
transition: all 150ms ease;
border: 1px solid transparent;
border-radius: 8px;
outline: none;
}
.help-nav-link:hover {
color: var(--accent);
background: color-mix(in srgb, var(--bg-hover) 80%, transparent);
border-color: color-mix(in srgb, var(--accent) 16%, transparent);
text-decoration: none;
transform: translateX(2px);
}
.help-nav-link:focus-visible {
outline: 2px solid var(--accent);
outline-offset: -2px;
border-radius: 8px;
}
.help-nav-link.active {
color: var(--accent);
background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 16%, transparent), color-mix(in srgb, var(--accent) 7%, transparent));
border-color: color-mix(in srgb, var(--accent) 22%, transparent);
font-weight: 600;
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 10%, transparent);
}
.help-nav-link.hidden {
display: none;
}
.help-section.help-hidden {
display: none;
}
.help-search-highlight {
background: rgba(250, 204, 21, 0.35);
color: inherit;
border-radius: 2px;
padding: 0 1px;
}
.help-content {
flex: 1;
max-width: 980px;
margin: 0 auto;
padding: 32px 40px 56px;
overflow: visible;
min-width: 0;
}
.help-lead {
font-size: 1.08rem;
line-height: 1.75;
color: var(--text-primary);
margin-bottom: 18px;
}
.help-footer {
margin-top: 48px;
padding-top: 24px;
border-top: 1px solid var(--border);
text-align: center;
color: var(--text-muted);
font-size: 0.85rem;
}
.help-footer a {
color: var(--accent);
text-decoration: none;
}
.help-footer a:hover {
text-decoration: underline;
}
.help-content h1,
.help-content h2,
.help-content h3 {
font-family: "JetBrains Mono", monospace;
color: var(--text-primary);
}
.help-content h1 {
font-size: 2rem;
margin-bottom: 16px;
letter-spacing: -0.02em;
}
.help-content h2 {
font-size: 1.18rem;
margin: 0 0 14px;
}
.help-content h3 {
font-size: 0.95rem;
margin: 20px 0 8px;
color: var(--text-secondary);
}
.help-content p {
margin: 0 0 14px;
color: var(--text-secondary);
line-height: 1.7;
}
.help-content pre,
.help-content table {
max-width: 100%;
overflow-x: auto;
}
.help-content pre code {
white-space: pre;
}
.help-content ul,
.help-content ol {
margin: 10px 0 18px;
padding-left: 24px;
color: var(--text-secondary);
}
.help-content ul li,
.help-content ol li {
margin: 6px 0;
line-height: 1.6;
}
.help-content code {
font-family: "JetBrains Mono", monospace;
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 4px;
padding: 1px 5px;
color: var(--text-primary);
font-size: 0.88em;
}
.help-content strong {
color: var(--text-primary);
font-weight: 600;
}
.help-section {
position: relative;
margin-bottom: 22px;
padding: 24px 26px;
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
border-radius: 18px;
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-secondary) 94%, var(--bg-primary)), color-mix(in srgb, var(--bg-secondary) 86%, var(--bg-primary)));
box-shadow: 0 14px 34px rgba(0, 0, 0, 0.18);
}
.help-section::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 8%, transparent), transparent 35%);
}
.help-hero {
display: grid;
grid-template-columns: minmax(0, 1.5fr) minmax(260px, 1fr);
gap: 22px;
align-items: stretch;
padding: 22px;
border: 1px solid color-mix(in srgb, var(--accent) 16%, var(--border));
border-radius: 18px;
background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 12%, transparent), transparent 45%), color-mix(in srgb, var(--bg-secondary) 92%, var(--bg-primary));
margin-bottom: 26px;
}
.help-kicker {
display: inline-flex;
align-items: center;
padding: 5px 10px;
border-radius: 999px;
background: color-mix(in srgb, var(--accent) 16%, transparent);
color: var(--accent);
font-family: "JetBrains Mono", monospace;
font-size: 0.72rem;
margin-bottom: 12px;
}
.help-badges {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 16px;
}
.help-badge {
display: inline-flex;
align-items: center;
padding: 6px 10px;
border-radius: 999px;
background: color-mix(in srgb, var(--bg-primary) 72%, transparent);
border: 1px solid var(--border);
color: var(--text-primary);
font-size: 0.8rem;
}
.help-hero-visual {
display: flex;
align-items: center;
justify-content: center;
}
.help-mini-window {
width: 100%;
max-width: 320px;
border-radius: 18px;
overflow: hidden;
border: 1px solid color-mix(in srgb, var(--accent) 18%, var(--border));
background: color-mix(in srgb, var(--bg-primary) 88%, black 12%);
box-shadow: 0 18px 44px rgba(0, 0, 0, 0.28);
}
.help-mini-window-bar {
display: flex;
gap: 7px;
padding: 12px 14px;
border-bottom: 1px solid var(--border);
}
.help-mini-window-bar span {
width: 9px;
height: 9px;
border-radius: 50%;
background: color-mix(in srgb, var(--accent) 45%, var(--text-muted));
}
.help-mini-window-body {
display: flex;
min-height: 190px;
}
.help-mini-sidebar {
width: 72px;
background: color-mix(in srgb, var(--bg-secondary) 92%, black 8%);
border-right: 1px solid var(--border);
}
.help-mini-content {
flex: 1;
padding: 16px;
}
.help-mini-line {
height: 10px;
border-radius: 999px;
background: color-mix(in srgb, var(--text-muted) 28%, transparent);
margin-bottom: 10px;
}
.help-mini-line.short {
width: 62%;
}
.help-mini-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin: 14px 0;
}
.help-mini-tags span {
padding: 3px 8px;
border-radius: 999px;
background: color-mix(in srgb, var(--accent) 16%, transparent);
color: var(--text-primary);
font-size: 0.72rem;
}
.help-mini-card {
height: 64px;
border-radius: 12px;
border: 1px solid var(--border);
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-secondary) 94%, white 6%), var(--bg-primary));
}
.help-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
margin-bottom: 26px;
}
.help-card {
padding: 18px;
border-radius: 16px;
border: 1px solid var(--border);
background: color-mix(in srgb, var(--bg-secondary) 92%, var(--bg-primary));
}
.help-card-icon {
width: 42px;
height: 42px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 12px;
background: color-mix(in srgb, var(--accent) 14%, transparent);
font-size: 1.2rem;
margin-bottom: 10px;
}
.help-section {
margin-top: 26px;
}
.help-feature-list,
.help-steps,
.help-checklist,
.help-tip-grid {
display: grid;
gap: 14px;
}
.help-feature-item,
.help-step,
.help-check-item,
.help-tip-card {
border: 1px solid var(--border);
border-radius: 16px;
background: color-mix(in srgb, var(--bg-secondary) 92%, var(--bg-primary));
}
.help-feature-item {
display: grid;
grid-template-columns: 52px minmax(0, 1fr);
gap: 14px;
padding: 16px;
}
.help-feature-emoji {
width: 52px;
height: 52px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 14px;
background: color-mix(in srgb, var(--accent) 12%, transparent);
font-size: 1.4rem;
}
.help-steps {
counter-reset: step;
}
.help-step {
display: grid;
grid-template-columns: 44px minmax(0, 1fr);
gap: 14px;
padding: 16px;
}
.help-step-number {
width: 44px;
height: 44px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background: color-mix(in srgb, var(--accent) 18%, transparent);
color: var(--accent);
font-family: "JetBrains Mono", monospace;
font-weight: 700;
}
.help-check-item {
display: grid;
grid-template-columns: 28px minmax(0, 1fr);
gap: 12px;
padding: 14px 16px;
align-items: start;
}
.help-check-item span {
font-size: 1rem;
line-height: 1.4;
}
.help-check-item p {
margin-bottom: 0;
}
.help-tip-panel {
margin-top: 28px;
}
.help-tip-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.help-tip-card {
padding: 16px;
}
/* BUG-045: inside the editor, the CodeMirror scroller is the ONLY scroll
surface. `#editor-body` stays `overflow:hidden` (BUG-020 rule below) and
the scroller fills it — otherwise the body and the scroller scroll
together and render two stacked scrollbars. */
.cm-editor {
font-size: 0.9rem;
}
.cm-scroller {
font-family: "JetBrains Mono", monospace;
overflow-x: auto !important;
max-width: 100%;
}
/* BUG-058: CodeMirror paints its line-number gutter with hardcoded light
defaults (#f5f5f5 background, #ddd border), so the bar stayed pale in dark
themes while the editor body followed the theme. Deriving the tint from
`--text-primary` keeps the gutter subtle and makes it adapt to every theme
and mode (dark, light, high-contrast, sepia). */
.cm-editor .cm-gutters {
background: color-mix(in srgb, var(--text-primary) 5%, transparent) !important;
color: var(--text-secondary) !important;
border-right: 1px solid var(--border) !important;
}
.cm-editor .cm-gutters .cm-activeLineGutter {
background: color-mix(in srgb, var(--text-primary) 10%, transparent) !important;
color: var(--text-primary) !important;
}
.fallback-editor {
width: 100%;
min-height: 100%;
height: auto;
border: none;
outline: none;
resize: none;
padding: 16px;
background: var(--code-bg);
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.9rem;
line-height: 1.55;
box-sizing: border-box;
overflow-y: auto;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
/* Mobile right sidebar - hide by default */
@media (max-width: 768px) {
.right-sidebar {
display: none;
}
.right-sidebar-resize-handle {
display: none;
}
}
/* Mobile help navigation */
@media (max-width: 768px) {
.help-nav {
display: none;
}
.help-content {
padding: 20px 16px 32px;
}
.vault-context-indicator {
/* Keep visible on mobile — same look as desktop */
padding: 4px 8px;
font-size: 0.7rem;
}
}
/* Mobile editor */
@media (max-width: 768px) {
.editor-modal {
padding: 0;
align-items: stretch;
}
.editor-container {
max-width: 100%;
max-height: 100vh;
border-radius: 0;
height: 100vh;
overflow: hidden;
}
.editor-header {
padding: 10px 12px;
position: sticky;
top: 0;
z-index: 20;
background: var(--bg-primary);
}
.editor-title {
font-size: 0.85rem;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.editor-actions {
gap: 4px;
}
.editor-btn {
width: 36px;
height: 36px;
min-width: 36px;
}
/* BUG-018: keep the Save / Cancel / Delete buttons reachable on small
screens by shrinking the inputs and hiding secondary header items. */
.editor-brand,
.editor-sep,
.editor-spacer,
.collab-presence {
display: none !important;
}
.editor-title-input {
flex: 1 1 60px;
min-width: 0;
font-size: 13px;
}
.editor-filename-input {
width: auto;
flex: 0 1 84px;
min-width: 0;
font-size: 11px;
}
.editor-save-dot {
margin-right: 2px;
padding: 0;
}
#editor-save-label {
display: none;
}
.editor-header .editor-btn {
flex: 0 0 auto;
}
.editor-body {
flex: 1;
min-height: 0;
/* BUG-020: only the CodeMirror scroller scrolls — no double scrollbar. */
overflow: hidden;
display: flex;
flex-direction: column;
}
#ai-toolbar-container {
flex: 0 0 auto;
}
.cm-editor {
flex: 1 1 auto;
height: auto;
min-height: 0;
}
.cm-scroller {
overflow-y: auto !important;
overflow-x: hidden !important;
/* BUG-019: keep the caret clear of the fixed ribbon. */
padding-bottom: 72px;
}
.fallback-editor {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
padding-bottom: 72px;
}
.search-results-header {
align-items: flex-start;
}
}
/* --- No-select during resize --- */
body.resizing {
user-select: none;
-webkit-user-select: none;
cursor: ew-resize;
}
body.resizing-v {
user-select: none;
-webkit-user-select: none;
cursor: ns-resize;
}
/* --- Responsive — Tablet --- */
@media (max-width: 1024px) {
.sidebar {
width: 240px;
min-width: 200px;
}
}
/* --- Responsive — Mobile --- */
@media (max-width: 768px) {
.hamburger-btn {
display: flex;
}
.sidebar-toggle-btn {
display: none;
}
.header {
flex-wrap: wrap;
gap: 8px 10px;
padding: 10px 12px;
}
.header-left {
flex: 1;
gap: 12px;
}
.header-center {
flex: 0 0 100%;
order: 3;
max-width: none;
padding: 4px 0;
}
.header-right {
flex: 0 0 auto;
gap: 8px;
}
.header-logo {
font-size: 1.05rem;
gap: 8px;
}
.header-right .user-display-name {
display: none; /* Masquer le nom d'utilisateur dans le header sur mobile */
}
.search-wrapper {
max-width: none;
width: 100%;
}
.search-input-wrapper input {
padding: 10px 40px 10px 40px;
font-size: 1rem;
border-radius: 12px;
}
.search-wrapper .search-icon {
left: 14px;
top: 14px;
width: 18px !important;
height: 18px !important;
}
/* Mobile: keep only filter + clear visible in header search */
.search-actions .tog,
.search-actions .search-sep,
.search-actions .search-count { display: none; }
.search-actions { gap: 4px; }
.search-actions .search-btn#search-clear-btn { display: flex; }
.search-dropdown {
position: fixed;
top: 100px;
left: 8px;
right: 8px;
width: calc(100vw - 16px);
max-height: calc(100vh - 120px);
border-radius: 12px;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}
.search-dropdown__item {
padding: 14px 16px;
font-size: 0.95rem;
}
.search-dropdown__icon {
width: 18px;
height: 18px;
margin-right: 8px;
}
.header-menu-btn {
padding: 10px;
border-radius: 10px;
}
.header-menu-dropdown {
position: fixed;
top: 60px;
right: 10px;
left: 10px;
width: auto;
min-width: 0;
border-radius: 16px;
}
.sidebar-quick-select {
padding: 0 16px 12px;
}
.sidebar-quick-select select {
color-scheme: dark;
background-color: var(--bg-secondary);
color: var(--text-primary);
}
[data-theme="dark"] .sidebar-quick-select select {
background-color: #1e1e1e;
color: #e0e0e0;
}
.sidebar-panel-toggle {
padding: 8px 12px 10px;
}
.tag-cloud {
padding: 0 12px 12px;
}
.sidebar {
position: fixed;
top: 0;
left: 0;
bottom: 0;
z-index: 200;
width: 280px !important;
min-width: 280px !important;
max-width: 85vw !important;
transform: translateX(-100%);
transition:
transform 250ms ease,
background 200ms ease;
box-shadow: none;
}
.sidebar.mobile-open {
transform: translateX(0);
box-shadow: 4px 0 20px rgba(0, 0, 0, 0.3);
}
/* Mobile sidebar overlay */
.sidebar-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.4);
z-index: 199;
}
.sidebar-overlay.active { display: block; }
/* Right Sidebar handling on mobile */
.right-sidebar {
position: fixed;
top: 0;
right: 0;
bottom: 0;
z-index: 200;
width: 280px !important;
min-width: 280px !important;
max-width: 85vw !important;
transform: translateX(100%);
transition:
transform 250ms ease,
background 200ms ease;
box-shadow: none;
border-left: 1px solid var(--border);
}
.right-sidebar.hidden {
transform: translateX(100%) !important;
width: 280px !important;
min-width: 280px !important;
display: flex;
}
.right-sidebar:not(.hidden) {
transform: translateX(0) !important;
box-shadow: -4px 0 20px rgba(0, 0, 0, 0.3) !important;
display: flex !important;
visibility: visible !important;
}
.right-sidebar-resize-handle {
display: none;
}
.sidebar-resize-handle {
display: none;
}
.tag-resize-handle {
display: none;
}
.tag-cloud-section {
height: auto;
max-height: 200px;
min-height: 80px;
}
#vault-panel-content {
max-height: none;
}
#tag-panel-content {
max-height: none;
}
.help-content {
padding: 20px 16px 28px;
}
.help-hero {
grid-template-columns: 1fr;
padding: 18px;
}
.help-grid,
.help-tip-grid {
grid-template-columns: 1fr;
}
.content-area {
padding: 12px 8px 24px;
width: 100%;
}
.file-title {
font-size: 1.15rem;
}
.file-actions {
flex-wrap: wrap;
gap: 4px;
}
.file-actions .btn-action {
padding: 6px 8px;
font-size: 0.75rem;
}
/* Full-width search results */
.search-result-item {
padding: 12px 14px;
border-radius: 8px;
margin-bottom: 8px;
}
.search-result-title {
font-size: 0.9rem;
padding-right: 40px;
}
.search-result-ext {
top: 6px;
right: 8px;
font-size: 0.6rem;
}
.search-results-header {
flex-wrap: wrap;
gap: 6px;
}
/* Full-width dashboard */
.dashboard-stats-grid {
grid-template-columns: repeat(2, 1fr);
gap: 8px;
}
.stat-card {
padding: 12px 8px;
}
.dashboard-tab {
padding: 6px 5px !important;
font-size: 0 !important;
gap: 0 !important;
overflow: hidden;
min-width: 32px;
}
.dashboard-tab > *:not(i):not(svg) { display: none; }
.dashboard-tab i, .dashboard-tab svg {
width: 18px !important;
height: 18px !important;
flex-shrink: 0;
}
.breadcrumb {
font-size: 0.75rem;
flex-wrap: wrap;
}
/* Mobile tab bar */
.tab-bar {
padding: 0 4px;
}
.tab-item {
padding: 6px 10px;
font-size: 0.7rem;
}
.tab-item .tab-name { max-width: 80px; }
.tab-item .tab-close { opacity: 0.6; width: 14px; height: 14px; }
.md-content {
padding: 0 4px;
}
.md-content h1 { font-size: 1.4rem; }
.md-content h2 { font-size: 1.15rem; }
.md-content h3 { font-size: 1rem; }
.md-content pre {
margin: 8px -4px;
border-radius: 6px;
padding: 10px 12px;
font-size: 0.8rem;
}
/* Full-width content wrapper */
.content-wrapper {
margin-left: 0 !important;
}
}
/* --- Configuration Modal --- */
.config-content {
max-width: 720px;
margin: 0 auto;
padding: 28px 24px 40px;
}
.config-section {
margin-bottom: 28px;
}
.config-section h2 {
font-family: "JetBrains Mono", monospace;
font-size: 1.05rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
}
.config-description {
font-size: 0.85rem;
color: var(--text-secondary);
margin-bottom: 16px;
line-height: 1.5;
}
.config-filters-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
min-height: 32px;
}
.config-filter-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
background: var(--tag-bg);
color: var(--tag-text);
border-radius: 6px;
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
border: 1px solid color-mix(in srgb, var(--tag-text) 30%, transparent);
}
.config-filter-badge.disabled {
opacity: 0.5;
}
.config-filter-remove {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
border: none;
background: transparent;
color: inherit;
cursor: pointer;
padding: 0;
font-size: 1.1rem;
line-height: 1;
}
.config-filter-remove:hover {
opacity: 0.7;
}
.config-filter-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
border: none;
background: transparent;
color: inherit;
cursor: pointer;
padding: 0;
font-size: 0.9rem;
}
.config-add-pattern {
display: flex;
gap: 8px;
margin-bottom: 12px;
}
.config-input {
flex: 1;
padding: 8px 12px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-secondary);
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
outline: none;
transition: border-color 200ms ease;
}
.config-input:focus {
border-color: var(--accent);
}
.config-select {
padding: 8px 12px;
border: 1px solid var(--border);
border-radius: var(--r);
background: var(--bg-input);
color: var(--text-primary);
font-size: 0.86rem;
font-family: var(--mono);
cursor: pointer;
}
.config-select option {
background: var(--bg-input, #1a1a2e);
color: var(--text-primary, #e0e0e0);
padding: 4px 8px;
}
.config-btn-add {
padding: 8px 16px;
border: 1px solid var(--accent);
border-radius: 6px;
background: var(--accent);
color: #ffffff;
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
font-weight: 600;
cursor: pointer;
transition: opacity 150ms ease;
}
.config-btn-add:hover {
opacity: 0.9;
}
.config-regex-preview {
padding: 8px 12px;
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 6px;
font-size: 0.75rem;
color: var(--text-secondary);
}
.config-regex-preview code {
font-family: "JetBrains Mono", monospace;
color: var(--accent);
background: transparent;
border: none;
padding: 0;
}
/* --- Config rows & controls --- */
.config-row {
display: grid;
grid-template-columns: 200px 120px 1fr;
align-items: center;
gap: 12px;
margin-bottom: 10px;
}
.config-label {
font-size: 0.82rem;
color: var(--text-primary);
font-weight: 500;
}
.config-input--num {
flex: none;
width: 120px;
text-align: right;
}
.config-hint {
font-size: 0.72rem;
color: var(--text-muted);
}
.config-badge-restart {
display: inline-block;
font-size: 0.65rem;
font-weight: 500;
padding: 2px 8px;
border-radius: 4px;
background: var(--danger-bg, #3d1a18);
color: var(--danger, #ff7b72);
vertical-align: middle;
margin-left: 6px;
}
.config-actions-row {
display: flex;
gap: 8px;
margin-top: 16px;
flex-wrap: wrap;
}
.config-btn-save {
padding: 8px 20px;
border: 1px solid var(--accent);
border-radius: 6px;
background: var(--accent);
color: #fff;
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
font-weight: 600;
cursor: pointer;
transition: opacity 150ms;
}
.config-btn-save:hover {
opacity: 0.9;
}
.config-btn-save.config-btn-highlight {
background: var(--accent-green);
border-color: var(--accent-green);
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.8;
}
}
.config-btn-secondary {
padding: 8px 16px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-secondary);
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
cursor: pointer;
transition: background 150ms;
}
.config-btn-secondary:hover {
background: var(--bg-hover);
}
/* BUG-068: .config-btn-primary / .config-btn-danger were used by the account
security section (frontend/js/auth.js) but never defined — the buttons fell
back to the browser default and ignored the theme. Defined here with the
same conventions as .config-btn-save / .config-btn-secondary. */
.config-btn-primary {
padding: 8px 16px;
border: 1px solid var(--accent);
border-radius: 6px;
background: var(--accent);
color: #fff;
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
font-weight: 600;
cursor: pointer;
transition: opacity 150ms;
}
.config-btn-primary:hover {
opacity: 0.9;
}
.config-btn-primary:disabled {
opacity: 0.55;
cursor: not-allowed;
}
.config-btn-danger {
padding: 8px 16px;
border: 1px solid var(--danger, #e74c3c);
border-radius: 6px;
background: var(--danger-bg, #3d1a18);
color: var(--danger, #ff7b72);
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
font-weight: 600;
cursor: pointer;
transition: opacity 150ms;
}
.config-btn-danger:hover {
opacity: 0.9;
}
.config-btn-danger:disabled {
opacity: 0.55;
cursor: not-allowed;
}
/* BUG-068: local QR code (backend SVG data: URI) + password section share the
security-tab card conventions. */
.mfa-qr-code-img {
max-width: 200px;
border-radius: 8px;
background: #fff;
padding: 8px;
}
.password-settings {
margin-top: 20px;
padding-top: 16px;
border-top: 1px solid var(--border, #333);
}
.password-settings .form-group {
margin: 8px 0;
}
.password-settings .form-group label {
display: block;
font-size: 0.78rem;
color: var(--text-secondary, #aaa);
margin-bottom: 4px;
}
.password-settings .config-input {
width: 100%;
max-width: 320px;
}
/* --- AI keys section: accordion redesign (#104) --- */
.ai-keys-header {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 18px;
}
.ai-keys-header-text {
flex: 1 1 320px;
min-width: 0;
}
.ai-keys-header-text h2 {
margin-bottom: 4px;
}
.ai-keys-search {
position: relative;
flex: 0 1 260px;
min-width: 200px;
}
.ai-keys-search .icon {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
width: 14px;
height: 14px;
color: var(--text-muted);
pointer-events: none;
}
.ai-keys-search input {
width: 100%;
padding: 8px 12px 8px 32px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--bg-secondary);
color: var(--text-primary);
font-size: 0.8rem;
outline: none;
transition: border-color 150ms ease;
}
.ai-keys-search input:focus {
border-color: var(--accent);
}
.ai-card-title {
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.6px;
text-transform: uppercase;
color: var(--text-secondary);
}
.ai-default-card {
background: var(--surface, #1e1e24);
border: 1px solid var(--border);
border-radius: 10px;
padding: 16px 18px;
margin-bottom: 22px;
}
.ai-default-card > .ai-card-title {
margin-bottom: 12px;
}
.ai-default-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
margin-bottom: 12px;
}
.ai-field {
display: flex;
flex-direction: column;
gap: 6px;
min-width: 0;
}
.ai-field-label {
font-size: 0.75rem;
font-weight: 500;
color: var(--text-secondary);
letter-spacing: 0.2px;
}
.ai-field .config-select,
.ai-field .config-input {
width: 100%;
}
.ai-caps-badges {
display: flex;
flex-wrap: wrap;
gap: 6px;
min-height: 22px;
}
.ai-cap-badge {
display: inline-flex;
align-items: center;
padding: 3px 10px;
border-radius: 999px;
font-size: 0.7rem;
font-weight: 600;
background: var(--accent-bg);
color: var(--accent);
border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
}
.ai-providers-header {
margin: 0 0 10px;
}
.ai-providers-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.ai-provider-card {
background: var(--surface, #1e1e24);
border: 1px solid var(--border);
border-radius: 10px;
transition: border-color 150ms ease;
}
.ai-provider-card:hover {
border-color: var(--border-md);
}
.ai-provider-card.open {
border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
}
.ai-provider-head {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 14px;
cursor: pointer;
user-select: none;
border-radius: 10px;
}
.ai-provider-head:focus-visible {
outline: 2px solid var(--accent);
outline-offset: -2px;
}
.ai-provider-logo {
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 8px;
background: var(--accent-bg);
color: var(--accent);
font-weight: 700;
font-size: 0.85rem;
flex: none;
}
.ai-provider-name {
flex: 1;
font-size: 0.88rem;
font-weight: 600;
color: var(--text-primary);
min-width: 0;
}
.ai-provider-badge {
font-size: 0.68rem;
padding: 2px 9px;
border-radius: 999px;
white-space: nowrap;
background: var(--muted-bg, rgba(255, 255, 255, 0.06));
color: var(--text-muted);
border: 1px solid var(--border);
}
.ai-provider-badge.configured {
background: var(--success-bg);
color: var(--success);
border-color: color-mix(in srgb, var(--success) 40%, transparent);
}
.ai-provider-delete {
display: inline-flex;
align-items: center;
justify-content: center;
width: 26px;
height: 26px;
border: none;
border-radius: 6px;
background: transparent;
color: var(--text-muted);
cursor: pointer;
flex: none;
transition: color 150ms ease, background 150ms ease;
}
.ai-provider-delete:hover {
color: var(--danger);
background: var(--danger-bg);
}
.ai-provider-chevron {
flex: none;
color: var(--text-muted);
transition: transform 200ms ease;
}
.ai-provider-card.open .ai-provider-chevron {
transform: rotate(180deg);
}
.ai-provider-body {
padding: 0 14px 14px;
}
.ai-provider-body.hidden {
display: none;
}
.ai-provider-fields {
display: grid;
grid-template-columns: 3fr 2fr;
gap: 12px;
padding-top: 12px;
border-top: 1px solid var(--border);
}
.ai-providers-empty {
padding: 14px;
text-align: center;
color: var(--text-muted);
font-size: 0.8rem;
border: 1px dashed var(--border);
border-radius: 10px;
}
.ai-keys-footer {
position: sticky;
bottom: 0;
z-index: 5;
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
margin-top: 20px;
padding: 12px 16px;
background: var(--surface, #1e1e24);
border: 1px solid var(--border);
border-radius: 10px;
box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.25);
}
.ai-keys-status {
flex: 1;
font-size: 0.75rem;
color: var(--text-muted);
min-width: 0;
}
@media (max-width: 600px) {
.ai-default-grid,
.ai-provider-fields {
grid-template-columns: 1fr;
}
.ai-keys-search {
flex: 1 1 100%;
}
}
/* --- Config diagnostics panel --- */
.config-diagnostics {
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 6px;
padding: 14px 16px;
font-family: "JetBrains Mono", monospace;
font-size: 0.78rem;
line-height: 1.7;
color: var(--text-secondary);
}
.config-diag-loading {
color: var(--text-muted);
}
.config-diag-row {
display: flex;
justify-content: space-between;
}
.config-diag-row .diag-label {
color: var(--text-secondary);
}
.config-diag-row .diag-value {
color: var(--text-primary);
font-weight: 500;
}
.config-diag-section {
margin-bottom: 8px;
padding-bottom: 8px;
border-bottom: 1px solid var(--border);
}
.config-diag-section:last-child {
margin-bottom: 0;
padding-bottom: 0;
border-bottom: none;
}
.config-diag-section-title {
font-weight: 600;
color: var(--accent);
margin-bottom: 4px;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
@media (max-width: 768px) {
.config-row {
grid-template-columns: 1fr;
gap: 4px;
}
.config-input--num {
width: 100%;
}
}
/* --- #114: Configurations modal — mobile UX refonte (viewport ≤ 768px).
Builds on BUG-071 (which stacked grids/wrapped rows): the TOC becomes a
left slide-over drawer with a backdrop, the modal goes full-screen with
100dvh, every interactive control gets a ≥44px touch target, inputs are
≥16px to stop iOS auto-zoom, and the backend Save row sticks to the
bottom of its scroll container. The drawer is opened by JS toggling
.config-toc-open on #config-modal (backdrop + nav visibility) plus an
inline display on #config-nav (kept for the display-reset contract). */
@media (max-width: 768px) {
/* Full-screen modal with dynamic viewport height (mobile browser chrome). */
#config-modal {
padding: 0;
align-items: stretch;
}
#config-modal .editor-container {
max-width: 100%;
width: 100%;
height: 100vh;
height: 100dvh;
max-height: 100vh;
max-height: 100dvh;
border-radius: 0;
border: none;
overflow: hidden;
}
/* Hamburger: 44px touch target (shared .help-hamburger rule in the help
modal media query also sets 44px; this scopes it to the config modal
in case rule order changes). */
#config-modal .help-hamburger {
display: inline-flex;
width: 44px;
height: 44px;
min-width: 44px;
}
/* Close button in the TOC drawer header. */
#config-modal .help-toc-close {
display: inline-flex;
align-items: center;
justify-content: center;
}
#config-modal .help-nav-header {
padding: 12px 12px 8px;
gap: 8px;
}
/* Close (X) in the modal header. */
#config-modal .editor-btn {
width: 44px;
height: 44px;
min-width: 44px;
}
/* Anti-zoom: ≥16px font on text fields inside the config modal. Never
target input[type=text] globally — it would clobber .mfa-code-input. */
#config-modal .config-input,
#config-modal .config-select,
#config-modal .help-nav-search,
#config-modal .profile-field .config-input,
#config-modal .profile-field .config-select {
min-height: 44px;
font-size: 16px;
}
#config-modal .config-input--num {
width: 100%;
text-align: left;
}
#config-modal .help-nav-search-wrap {
padding: 0 12px 10px;
}
#config-modal .help-search-clear {
min-width: 44px;
min-height: 44px;
}
#config-modal .help-nav-link {
min-height: 44px;
display: flex;
align-items: center;
box-sizing: border-box;
}
/* Sticky Save row inside #cfg-backend-settings (its scroll container is
#config-scroll.help-content, which is the overflow ancestor). */
#config-modal .config-actions-row {
position: sticky;
bottom: 0;
z-index: 5;
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 16px;
margin-bottom: 0;
padding: 10px 0 calc(10px + env(safe-area-inset-bottom, 0));
background: var(--bg-primary);
border-top: 1px solid var(--border);
}
#config-modal .config-actions-row .config-btn-save,
#config-modal .config-actions-row .config-btn-secondary,
#config-modal .config-actions-row .config-btn-primary,
#config-modal .config-actions-row .config-btn-danger {
flex: 1 1 auto;
width: 100%;
min-height: 44px;
box-sizing: border-box;
}
#config-modal .config-btn-save,
#config-modal .config-btn-secondary,
#config-modal .config-btn-primary,
#config-modal .config-btn-danger,
#config-modal .config-btn-add,
#config-modal .config-btn-sm,
#config-modal .mfa-link-btn,
#config-modal .theme-action-btn,
#config-modal .profile-avatar-actions .config-btn-secondary,
#config-modal .editor-btn {
min-height: 44px;
box-sizing: border-box;
}
#config-modal .config-btn-sm,
#config-modal .mfa-link-btn,
#config-modal .theme-action-btn {
min-width: 44px;
padding-left: 12px;
padding-right: 12px;
}
/* Profile avatar row: wrap instead of overflowing a 360px viewport. */
#config-modal .profile-avatar-row {
flex-wrap: wrap;
gap: 12px;
}
/* Preset avatars: 4 per row on narrow screens (44px touch targets). */
#config-modal .profile-avatar-presets {
grid-template-columns: repeat(4, minmax(0, 1fr));
max-width: 100%;
}
#config-modal .profile-form {
max-width: 100%;
}
/* MFA: one-column recovery list, wrapping action rows, full-width code
input with a readable letter-spacing (12px overflows 360px). */
#config-modal .mfa-recovery-list {
grid-template-columns: 1fr;
gap: 6px;
}
#config-modal .mfa-verify-section,
#config-modal .mfa-recovery-actions,
#config-modal .mfa-disable-actions {
flex-wrap: wrap;
}
#config-modal .mfa-verify-section .config-input,
#config-modal .mfa-verify-section .config-btn-primary {
flex: 1 1 100%;
width: 100%;
min-width: 0;
box-sizing: border-box;
}
#config-modal .mfa-recovery-actions .config-btn-secondary,
#config-modal .mfa-disable-actions .config-btn-danger {
flex: 1 1 auto;
min-height: 44px;
box-sizing: border-box;
}
#config-modal .mfa-code-input {
width: 100%;
max-width: 320px;
min-height: 52px;
font-size: 24px;
letter-spacing: 6px;
}
#config-modal .mfa-secret-code {
display: block;
word-break: break-all;
overflow-wrap: anywhere;
}
#config-modal .mfa-code-input-group {
flex-wrap: wrap;
justify-content: flex-start;
}
/* WebAuthn key rows: wrap instead of clipping the remove button. */
#config-modal .webauthn-key-item {
flex-wrap: wrap;
gap: 8px;
}
#config-modal .webauthn-key-label {
flex: 1 1 100%;
min-width: 0;
}
#config-modal .webauthn-key-item .config-btn-sm {
min-height: 44px;
min-width: 44px;
}
#config-modal .hidden-files-add-row {
flex-wrap: wrap;
}
#config-modal .hidden-files-add-row .config-input {
flex: 1 1 100%;
max-width: none;
min-width: 0;
}
#config-modal .config-diag-row {
flex-wrap: wrap;
gap: 4px 8px;
}
/* AI keys sticky footer: clear the mobile toolbar + home indicator. */
#config-modal .ai-keys-footer {
padding-bottom: calc(12px + env(safe-area-inset-bottom, 0));
bottom: 0;
}
/* Two-column grids → single column. */
#config-modal .ai-default-grid,
#config-modal .ai-provider-fields {
grid-template-columns: 1fr;
}
/* Add-rows (tokens, webhooks, tag filters) wrap instead of overflowing. */
#config-modal .config-add-row,
#config-modal .config-add-pattern {
flex-wrap: wrap;
}
#config-modal .config-add-row .config-input,
#config-modal .config-add-pattern .config-input,
#config-modal .config-add-row .config-select {
flex: 1 1 140px;
width: auto !important; /* override fixed inline widths (180/140/100px) */
min-width: 0;
}
#config-modal .config-add-row .config-btn-add,
#config-modal .config-add-pattern .config-btn-add {
flex: 1 1 auto;
min-height: 44px;
}
/* Webhook / token / share rows wrap; long URLs and meta take their own
line instead of squeezing the delete control off-screen. */
#config-modal .webhook-item,
#config-modal .token-item,
#config-modal .share-item {
flex-wrap: wrap;
}
#config-modal .webhook-url,
#config-modal .token-meta,
#config-modal .share-url {
flex: 1 1 100%;
min-width: 0;
white-space: normal;
overflow-wrap: anywhere;
}
#config-modal .webhook-delete,
#config-modal .token-delete,
#config-modal .share-revoke {
min-width: 44px;
min-height: 44px;
}
/* Sticky AI-keys footer: full-width touch-friendly buttons. */
#config-modal .ai-keys-footer .config-btn-save,
#config-modal .ai-keys-footer .config-btn-secondary {
flex: 1 1 100%;
min-height: 44px;
}
/* Long inline code in tips (ex. MCP usage snippet) must wrap. */
#config-modal .qh-tip {
flex-wrap: wrap;
}
#config-modal .qh-tip span {
min-width: 0;
overflow-wrap: anywhere;
}
/* Drawer: left slide-over above a dimming backdrop. Higher specificity
than the generic .help-nav rules (body .help-nav / .help-nav) that hide
the nav on mobile. JS toggles .config-toc-open on #config-modal. */
#config-modal #config-nav {
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: min(320px, 88vw);
min-width: 0;
max-width: 88vw;
max-height: 100dvh;
height: 100%;
box-sizing: border-box;
z-index: 40;
background: var(--bg-secondary);
border-right: 1px solid var(--border);
border-bottom: none;
box-shadow: none;
backdrop-filter: none;
display: none;
overflow: hidden;
animation: config-toc-slide-in 200ms ease-out;
}
#config-modal.config-toc-open #config-nav {
display: flex;
max-height: 100dvh;
}
#config-modal .help-nav-list {
padding-bottom: calc(20px + env(safe-area-inset-bottom, 0));
}
/* Backdrop: covers the full modal, sits above the content (z-index auto)
and below the drawer (z-index 40). Clicks on the pseudo-element are
attributed to #config-modal, so the existing e.target === modal handler
closes the drawer first; it also blocks taps reaching the content. */
#config-modal.config-toc-open::before {
content: "";
position: absolute;
inset: 0;
z-index: 35;
background: rgba(0, 0, 0, 0.45);
}
@keyframes config-toc-slide-in {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
/* Content area gets a bottom pad so the sticky Save row never covers the
last controls while the virtual keyboard is open. */
#config-modal #config-scroll .config-content {
padding-bottom: 80px;
}
}
/* --- Toast notifications --- */
.toast-container {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 10000;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
pointer-events: none;
}
.toast {
padding: 10px 20px;
border-radius: 8px;
font-family: "JetBrains Mono", monospace;
font-size: 0.82rem;
color: var(--text-primary);
background: var(--bg-secondary);
border: 1px solid var(--border);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
opacity: 0;
transform: translateY(12px);
transition:
opacity 250ms ease,
transform 250ms ease;
pointer-events: auto;
max-width: 420px;
text-align: center;
}
.toast.show {
opacity: 1;
transform: translateY(0);
}
.toast-error {
border-color: var(--danger);
background: var(--danger-bg);
color: var(--danger);
}
.toast-success {
border-color: var(--success);
background: var(--success-bg);
color: var(--success);
}
/* --- Tree loading indicator --- */
.tree-loading {
display: flex;
align-items: center;
justify-content: center;
padding: 8px 16px;
}
/* ---------------------------------------------------------------------------
Advanced Search — Autocomplete Dropdown
--------------------------------------------------------------------------- */
.search-dropdown {
position: absolute;
top: 100%;
left: 0;
right: 0;
margin-top: 4px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
z-index: 200;
}
.search-dropdown[hidden] {
display: none;
}
.search-dropdown__section {
border-bottom: 1px solid var(--border);
}
.search-dropdown__section:last-child {
border-bottom: none;
}
.search-dropdown__section[hidden] {
display: none;
}
.search-dropdown__section-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 12px;
font-size: 0.7rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
background: var(--bg-primary);
position: sticky;
top: 0;
z-index: 1;
}
.search-dropdown__clear-btn {
background: none;
border: none;
color: var(--text-muted);
cursor: pointer;
padding: 2px 4px;
border-radius: 4px;
display: flex;
align-items: center;
}
.search-dropdown__clear-btn:hover {
color: var(--danger);
background: var(--danger-bg, rgba(255, 0, 0, 0.08));
}
.search-dropdown__list {
list-style: none;
margin: 0;
padding: 0;
}
.search-dropdown__item {
display: flex;
align-items: center;
gap: 8px;
padding: 7px 12px;
cursor: pointer;
font-size: 0.82rem;
color: var(--text-primary);
transition: background 120ms ease;
}
.search-dropdown__item:hover,
.search-dropdown__item.active {
background: var(--bg-hover);
}
.search-dropdown__item--history {
color: var(--text-secondary);
}
.search-dropdown__item--history .search-dropdown__icon {
color: var(--text-muted);
}
.search-dropdown__item--title .search-dropdown__meta {
font-size: 0.72rem;
color: var(--text-muted);
margin-left: auto;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.search-dropdown__item--tag .search-dropdown__badge {
margin-left: auto;
font-size: 0.7rem;
color: var(--text-muted);
background: var(--bg-primary);
padding: 1px 6px;
border-radius: 10px;
}
.search-dropdown__icon {
flex-shrink: 0;
width: 14px;
height: 14px;
color: var(--text-muted);
}
.search-dropdown__text {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.search-dropdown__text mark {
background: var(--accent);
color: var(--bg-primary);
border-radius: 2px;
padding: 0 1px;
}
.search-dropdown__empty {
padding: 16px 12px;
text-align: center;
font-size: 0.82rem;
color: var(--text-muted);
}
.search-dropdown__empty[hidden] {
display: none;
}
/* ---------------------------------------------------------------------------
Advanced Search — Filter Chips
--------------------------------------------------------------------------- */
.search-chips {
display: flex;
flex-wrap: wrap;
gap: 6px;
padding: 6px 0 0;
}
.search-chips[hidden] {
display: none;
}
.search-chip {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 3px 8px;
font-size: 0.75rem;
font-family: "JetBrains Mono", monospace;
border-radius: 12px;
background: var(--accent);
color: var(--bg-primary);
cursor: default;
max-width: 200px;
white-space: nowrap;
}
.search-chip__label {
overflow: hidden;
text-overflow: ellipsis;
}
.search-chip__remove {
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
color: inherit;
cursor: pointer;
padding: 0;
opacity: 0.7;
transition: opacity 120ms;
}
.search-chip__remove:hover {
opacity: 1;
}
.search-chip--tag {
background: var(--accent);
color: var(--bg-primary);
}
.search-chip--vault {
background: var(--success, #22c55e);
color: #fff;
}
.search-chip--title {
background: var(--warning, #f59e0b);
color: #1a1a1a;
}
.search-chip--path {
background: var(--text-muted);
color: var(--bg-primary);
}
/* ---------------------------------------------------------------------------
Advanced Search — Snippet Highlights
--------------------------------------------------------------------------- */
.search-result__snippet mark {
background: var(--accent);
color: var(--bg-primary);
border-radius: 2px;
padding: 0 2px;
font-weight: 600;
}
/* ---------------------------------------------------------------------------
Advanced Search — Facets Panel
--------------------------------------------------------------------------- */
.search-facets {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 12px;
padding: 10px 12px;
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 8px;
}
.search-facets[hidden] {
display: none;
}
.search-facets__group {
display: flex;
flex-wrap: wrap;
gap: 6px;
align-items: center;
}
.search-facets__label {
font-size: 0.72rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
margin-right: 4px;
}
.search-facets__item {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
font-size: 0.75rem;
border: 1px solid var(--border);
border-radius: 12px;
color: var(--text-secondary);
background: var(--bg-secondary);
cursor: pointer;
transition:
border-color 120ms,
background 120ms;
}
.search-facets__item:hover {
border-color: var(--accent);
background: var(--bg-hover);
}
.search-facets__item .facet-count {
font-size: 0.68rem;
color: var(--text-muted);
}
/* ---------------------------------------------------------------------------
Advanced Search — Pagination
--------------------------------------------------------------------------- */
.search-pagination {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px 0;
}
.search-pagination__btn {
padding: 6px 14px;
font-size: 0.82rem;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-secondary);
color: var(--text-primary);
cursor: pointer;
transition:
border-color 120ms,
background 120ms;
}
.search-pagination__btn:hover:not(:disabled) {
border-color: var(--accent);
background: var(--bg-hover);
}
.search-pagination__btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.search-pagination__info {
font-size: 0.78rem;
color: var(--text-muted);
}
/* ---------------------------------------------------------------------------
Advanced Search — Sort Controls
--------------------------------------------------------------------------- */
.search-sort {
display: flex;
align-items: center;
gap: 6px;
margin-left: auto;
}
.search-sort__btn {
padding: 3px 10px;
font-size: 0.75rem;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-secondary);
color: var(--text-secondary);
cursor: pointer;
transition: all 120ms;
}
.search-sort__btn.active {
border-color: var(--accent);
color: var(--accent);
background: var(--bg-hover);
}
/* ---------------------------------------------------------------------------
Advanced Search — Responsive
--------------------------------------------------------------------------- */
@media (max-width: 768px) {
.search-dropdown {
max-height: 280px;
}
.search-facets {
flex-direction: column;
gap: 8px;
}
.search-chip {
max-width: 150px;
}
}
/* ---------------------------------------------------------------------------
Sync Badge — real-time connection status indicator
--------------------------------------------------------------------------- */
.sync-badge {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
margin-left: 8px;
cursor: pointer;
transition:
background 300ms,
box-shadow 300ms;
flex-shrink: 0;
vertical-align: middle;
}
.sync-badge--disconnected {
background: #ef4444;
box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.25);
}
.sync-badge--connecting {
background: #f59e0b;
box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.25);
animation: sync-pulse 1.5s ease-in-out infinite;
}
.sync-badge--connected {
background: #22c55e;
box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2);
}
.sync-badge--syncing {
background: #3b82f6;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.3);
animation: sync-pulse 0.8s ease-in-out infinite;
}
@keyframes sync-pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.4;
}
}
/* AI processing — white flash on the sync badge */
.sync-badge--ai-processing {
background: #ffffff !important;
box-shadow: 0 0 6px 3px rgba(255, 255, 255, 0.6) !important;
animation: ai-flash 0.6s ease-in-out infinite;
}
@keyframes ai-flash {
0%, 100% { opacity: 1; box-shadow: 0 0 6px 3px rgba(255,255,255,0.6); }
50% { opacity: 0.3; box-shadow: 0 0 12px 6px rgba(255,255,255,0.9); }
}
/* ── AI Status section inside sync panel ── */
.sync-panel__ai-section {
border-top: 1px solid var(--border);
padding: 10px 14px;
}
.sync-panel__ai-title {
font-size: 0.78rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
}
.sync-panel__ai-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 5px;
}
.sync-panel__ai-label {
font-size: 0.72rem;
color: var(--text-muted);
}
.sync-panel__ai-state {
font-size: 0.75rem;
display: flex;
align-items: center;
gap: 5px;
padding: 2px 8px;
border-radius: 4px;
}
.sync-panel__ai-state i {
flex-shrink: 0;
}
.sync-panel__ai--active {
color: #22c55e;
background: rgba(34, 197, 94, 0.1);
}
.sync-panel__ai--inactive {
color: #f59e0b;
background: rgba(245, 158, 11, 0.1);
}
.sync-panel__ai--processing {
color: #ffffff;
background: rgba(59, 130, 246, 0.2);
animation: ai-status-pulse 1s ease-in-out infinite;
}
.sync-panel__ai--unknown {
color: var(--text-muted);
background: var(--bg-tertiary);
}
@keyframes ai-status-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
/* ---------------------------------------------------------------------------
Vault Home Page
--------------------------------------------------------------------------- */
.vault-home {
padding: 16px 24px;
max-width: 900px;
margin: 0 auto;
}
.vault-home-breadcrumb {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 2px;
font-size: 0.85rem;
margin-bottom: 16px;
padding: 8px 12px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
}
.vault-home-breadcrumb-item {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 6px;
border-radius: 4px;
color: var(--text-secondary);
transition: background 0.15s, color 0.15s;
user-select: none;
}
.vault-home-breadcrumb-item:hover {
background: color-mix(in srgb, var(--accent) 10%, transparent);
color: var(--text-primary);
}
.vault-home-breadcrumb-root {
font-weight: 600;
color: var(--accent);
}
.vault-home-breadcrumb-sep {
color: var(--text-muted);
user-select: none;
font-size: 0.8rem;
}
.vault-home-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid var(--border);
}
.vault-home-count {
font-size: 0.8rem;
font-weight: 600;
color: var(--text-primary);
background: var(--bg-secondary);
padding: 3px 10px;
border-radius: 4px;
}
.vault-home-recursive-badge {
font-size: 0.7rem;
font-weight: 600;
color: var(--accent);
background: color-mix(in srgb, var(--accent) 12%, transparent);
padding: 2px 8px;
border-radius: 4px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.vault-home-dir-info {
font-size: 0.75rem;
color: var(--text-muted);
font-family: var(--font-mono);
}
.vault-home-results {
min-height: 200px;
}
.vault-home-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 3rem;
color: var(--text-muted);
gap: 8px;
}
.vault-home-empty p {
font-size: 0.85rem;
margin: 0;
}
.vault-home-error {
padding: 2rem;
text-align: center;
color: var(--danger, #ef4444);
font-size: 0.85rem;
}
/* ── Recent files section on vault home ── */
.vault-home-recent {
margin-bottom: 20px;
padding: 12px 16px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
}
.vault-home-recent-header {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.75rem;
font-weight: 600;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 8px;
padding-bottom: 6px;
border-bottom: 1px solid var(--border);
}
.vault-home-recent-list {
display: flex;
flex-direction: column;
gap: 2px;
}
.vault-home-recent-item {
display: flex;
align-items: center;
gap: 8px;
padding: 5px 6px;
border-radius: 4px;
cursor: pointer;
transition: background 0.12s;
font-size: 0.82rem;
}
.vault-home-recent-item:hover {
background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.vault-home-recent-title {
color: var(--text-primary);
font-weight: 500;
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.vault-home-recent-dir {
color: var(--text-muted);
font-size: 0.72rem;
font-family: var(--font-mono);
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.vault-home-recent-time {
color: var(--text-muted);
font-size: 0.7rem;
white-space: nowrap;
flex-shrink: 0;
}
.vault-home-item {
cursor: pointer;
}
.vault-home-item:hover {
background: var(--bg-secondary);
}
/* ---------------------------------------------------------------------------
Sync Panel — event log overlay
--------------------------------------------------------------------------- */
.sync-panel {
position: fixed;
top: 52px;
left: 16px;
width: 340px;
max-height: 400px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 10px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
z-index: 9999;
overflow: hidden;
font-size: 0.82rem;
}
.sync-panel__header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 14px;
border-bottom: 1px solid var(--border);
}
.sync-panel__title {
font-weight: 600;
color: var(--text-primary);
}
.sync-panel__state {
font-size: 0.72rem;
padding: 2px 8px;
border-radius: 8px;
font-weight: 500;
}
.sync-panel__state--connected {
background: rgba(34, 197, 94, 0.15);
color: #22c55e;
}
.sync-panel__state--disconnected {
background: rgba(239, 68, 68, 0.15);
color: #ef4444;
}
.sync-panel__state--connecting {
background: rgba(245, 158, 11, 0.15);
color: #f59e0b;
}
.sync-panel__state--syncing {
background: rgba(59, 130, 246, 0.15);
color: #3b82f6;
}
.sync-panel__empty {
padding: 20px 14px;
text-align: center;
color: var(--text-muted);
}
.sync-panel__events {
max-height: 320px;
overflow-y: auto;
padding: 4px 0;
}
.sync-panel__event {
display: flex;
align-items: center;
gap: 8px;
padding: 7px 14px;
border-bottom: 1px solid var(--border);
}
.sync-panel__event:last-child {
border-bottom: none;
}
.sync-panel__event-type {
font-weight: 500;
color: var(--text-primary);
white-space: nowrap;
}
.sync-panel__event-detail {
color: var(--text-secondary);
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.sync-panel__event-time {
font-size: 0.7rem;
color: var(--text-muted);
white-space: nowrap;
}
/* ---------------------------------------------------------------------------
Toast — info variant (blue)
--------------------------------------------------------------------------- */
.toast.toast-info {
background: #1e3a5f;
border-left: 4px solid #3b82f6;
color: #bfdbfe;
}
[data-theme="light"] .toast.toast-info {
background: #eff6ff;
border-left: 4px solid #3b82f6;
color: #1e40af;
}
/* ---------------------------------------------------------------------------
Config Toggle Switch
--------------------------------------------------------------------------- */
.config-toggle {
position: relative;
display: inline-block;
width: 40px;
height: 22px;
flex-shrink: 0;
}
.config-toggle input {
opacity: 0;
width: 0;
height: 0;
}
.config-toggle-slider {
position: absolute;
cursor: pointer;
inset: 0;
background: var(--bg-hover);
border: 1px solid var(--border);
border-radius: 22px;
transition:
background 200ms,
border-color 200ms;
}
.config-toggle-slider::before {
content: "";
position: absolute;
height: 16px;
width: 16px;
left: 2px;
bottom: 2px;
background: var(--text-muted);
border-radius: 50%;
transition:
transform 200ms,
background 200ms;
}
.config-toggle input:checked + .config-toggle-slider {
background: rgba(34, 197, 94, 0.2);
border-color: #22c55e;
}
.config-toggle input:checked + .config-toggle-slider::before {
transform: translateX(18px);
background: #22c55e;
}
/* ---------------------------------------------------------------------------
Hidden Files Configuration
--------------------------------------------------------------------------- */
.hidden-files-vault-card {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 6px;
padding: 12px;
margin-bottom: 12px;
transition: border-color 200ms ease;
}
.hidden-files-vault-card:hover {
border-color: var(--accent);
}
.hidden-files-vault-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid var(--border);
}
.hidden-files-vault-header h3 {
font-size: 0.95rem;
font-weight: 600;
color: var(--text-primary);
margin: 0;
}
.hidden-files-vault-type {
font-size: 0.7rem;
padding: 2px 6px;
background: var(--tag-bg);
color: var(--tag-text);
border-radius: 3px;
font-family: var(--mono);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.hidden-files-whitelist {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid var(--border);
}
.hidden-files-whitelist-items {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 10px;
min-height: 28px;
padding: 4px;
background: var(--bg-primary);
border-radius: 4px;
border: 1px dashed var(--border);
}
.hidden-files-whitelist-items:empty::before {
content: "Aucun dossier dans la liste blanche";
color: var(--text-muted);
font-size: 0.85rem;
font-style: italic;
}
.hidden-files-whitelist-item {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 3px 6px 3px 8px;
background: var(--tag-bg);
color: var(--tag-text);
border-radius: 4px;
font-size: 0.85rem;
font-family: var(--mono);
border: 1px solid color-mix(in srgb, var(--tag-text) 30%, transparent);
transition: all 150ms ease;
}
.hidden-files-whitelist-item:hover {
background: color-mix(in srgb, var(--tag-bg) 80%, var(--accent) 20%);
border-color: var(--accent);
}
.whitelist-item-text {
user-select: none;
}
.whitelist-item-remove {
background: none;
border: none;
color: var(--text-muted);
cursor: pointer;
font-size: 1.1rem;
line-height: 1;
padding: 0 2px;
transition: all 150ms ease;
border-radius: 2px;
}
.whitelist-item-remove:hover {
color: var(--danger);
background: color-mix(in srgb, var(--danger) 15%, transparent);
}
.hidden-files-add-row {
display: flex;
gap: 8px;
align-items: center;
margin-top: 4px;
}
.hidden-files-add-row .config-input {
flex: 1;
max-width: 250px;
font-family: var(--mono);
font-size: 0.9rem;
}
/* ---------------------------------------------------------------------------
Utility — hidden class
--------------------------------------------------------------------------- */
.hidden {
display: none !important;
}
/* ---------------------------------------------------------------------------
Login Screen
--------------------------------------------------------------------------- */
.login-screen {
position: fixed;
inset: 0;
z-index: 10001;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #090e17 0%, #101827 50%, #1b2838 100%);
}
.login-card {
width: 380px;
max-width: 90vw;
background: rgba(30, 30, 46, 0.85);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 16px;
padding: 40px 36px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
animation: loginFadeIn 0.4s ease-out;
}
@keyframes loginFadeIn {
from {
opacity: 0;
transform: translateY(20px) scale(0.97);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.login-header {
text-align: center;
margin-bottom: 32px;
}
.login-logo {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin-bottom: 8px;
}
.login-logo-icon {
font-size: 2rem;
}
.login-logo-text {
font-size: 1.8rem;
font-weight: 700;
background: linear-gradient(135deg, #7dd3fc, #38bdf8, #0ea5e9);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: -0.02em;
}
.login-subtitle {
font-size: 0.88rem;
color: rgba(255, 255, 255, 0.45);
margin: 0;
}
.login-form .form-group {
margin-bottom: 20px;
}
.login-form .form-group label {
display: block;
font-size: 0.82rem;
font-weight: 500;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 6px;
}
.login-form input[type="text"],
.login-form input[type="password"] {
width: 100%;
padding: 12px 14px;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 10px;
background: rgba(255, 255, 255, 0.06);
color: #e2e8f0;
font-size: 0.92rem;
font-family: inherit;
outline: none;
transition:
border-color 200ms,
box-shadow 200ms;
box-sizing: border-box;
}
.login-form input:focus {
border-color: #818cf8;
box-shadow: 0 0 0 3px rgba(129, 140, 248, 0.2);
}
.login-form input::placeholder {
color: rgba(255, 255, 255, 0.25);
}
.password-input-wrapper {
position: relative;
}
.password-toggle {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
font-size: 1rem;
opacity: 0.5;
transition: opacity 150ms;
padding: 4px;
}
.password-toggle:hover {
opacity: 0.9;
}
.form-group--inline {
display: flex;
align-items: center;
}
.checkbox-label {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
font-size: 0.82rem;
color: rgba(255, 255, 255, 0.5);
}
.checkbox-label input[type="checkbox"] {
accent-color: #818cf8;
width: 15px;
height: 15px;
}
.login-error {
padding: 10px 14px;
border-radius: 8px;
background: rgba(239, 68, 68, 0.12);
border: 1px solid rgba(239, 68, 68, 0.3);
color: #fca5a5;
font-size: 0.82rem;
margin-bottom: 16px;
}
.btn-login {
width: 100%;
padding: 13px 24px;
border: none;
border-radius: 10px;
background: linear-gradient(135deg, #3b82f6, #2563eb);
color: #fff;
font-size: 0.95rem;
font-weight: 600;
cursor: pointer;
transition:
opacity 200ms,
transform 100ms;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
font-family: inherit;
}
.btn-login:hover:not(:disabled) {
opacity: 0.92;
}
.btn-login:active:not(:disabled) {
transform: scale(0.98);
}
.btn-login:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.btn-spinner {
font-size: 1rem;
}
/* Light theme login */
[data-theme="light"] .login-screen {
background: linear-gradient(135deg, #dbeafe, #eff6ff, #bfdbfe);
}
[data-theme="light"] .login-card {
background: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.12);
}
[data-theme="light"] .login-subtitle {
color: rgba(0, 0, 0, 0.45);
}
[data-theme="light"] .login-form .form-group label {
color: rgba(0, 0, 0, 0.6);
}
[data-theme="light"] .login-form input[type="text"],
[data-theme="light"] .login-form input[type="password"] {
background: rgba(0, 0, 0, 0.04);
border-color: rgba(0, 0, 0, 0.12);
color: #1e293b;
}
[data-theme="light"] .login-form input::placeholder {
color: rgba(0, 0, 0, 0.3);
}
[data-theme="light"] .checkbox-label {
color: rgba(0, 0, 0, 0.5);
}
[data-theme="light"] .login-error {
background: rgba(239, 68, 68, 0.08);
color: #dc2626;
}
/* ---------------------------------------------------------------------------
User Menu (header)
--------------------------------------------------------------------------- */
.user-menu {
display: flex;
align-items: center;
gap: 8px;
}
.user-display-name {
font-size: 0.8rem;
color: var(--text-secondary);
font-weight: 500;
max-width: 120px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.user-menu-link,
.btn-logout {
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
color: var(--text-muted);
cursor: pointer;
padding: 4px;
border-radius: 4px;
transition:
color 150ms,
background 150ms;
}
.user-menu-link:hover,
.btn-logout:hover {
color: var(--text-primary);
background: var(--bg-hover);
}
.btn-logout:hover {
color: var(--danger);
}
/* ---------------------------------------------------------------------------
Sidebar account section (#112) — identity + logout pinned at the bottom
--------------------------------------------------------------------------- */
.sidebar-user {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-top: 1px solid var(--border);
background: var(--bg-sidebar);
flex-shrink: 0;
}
.sidebar-user[hidden] {
display: none;
}
.sidebar-user-profile {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
gap: 10px;
padding: 6px 8px;
border: 1px solid transparent;
border-radius: 8px;
background: transparent;
cursor: pointer;
text-align: left;
transition: background 150ms ease, border-color 150ms ease;
}
.sidebar-user-profile:hover {
background: var(--bg-hover);
border-color: var(--border);
}
.sidebar-user-avatar {
width: 34px;
height: 34px;
border-radius: 50%;
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.02em;
color: #fff;
background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #7c3aed));
}
/* #113 — custom avatar image fills the circle; initials stay the fallback */
.sidebar-user-avatar-img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
display: block;
}
.sidebar-user-meta {
display: flex;
flex-direction: column;
gap: 1px;
min-width: 0;
}
.sidebar-user-name {
font-size: 0.82rem;
font-weight: 600;
color: var(--text-primary);
max-width: none;
}
.sidebar-user-role {
font-size: 0.7rem;
color: var(--text-muted);
}
.sidebar-user-logout {
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
flex-shrink: 0;
border: 1px solid transparent;
border-radius: 8px;
background: transparent;
color: var(--text-muted);
cursor: pointer;
transition: color 150ms ease, background 150ms ease, border-color 150ms ease;
}
.sidebar-user-logout:hover {
color: var(--danger);
background: var(--bg-hover);
border-color: var(--border);
}
/* Version row inside the header options menu (#112) */
.menu-list-version {
cursor: default;
border-top: 1px solid var(--border);
margin-top: 4px;
padding-top: 8px;
}
.menu-list-version .version-badge {
margin-left: 4px;
}
/* ---------------------------------------------------------------------------
Admin Panel
--------------------------------------------------------------------------- */
.admin-toolbar {
padding: 16px;
display: flex;
justify-content: flex-end;
}
.admin-users-list {
padding: 0 16px 16px;
}
.admin-table {
width: 100%;
border-collapse: collapse;
font-size: 0.82rem;
}
.admin-table th,
.admin-table td {
padding: 10px 12px;
text-align: left;
border-bottom: 1px solid var(--border);
}
.admin-table th {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
font-weight: 600;
background: var(--bg-primary);
position: sticky;
top: 0;
}
.admin-table td {
color: var(--text-primary);
}
.admin-role-badge {
display: inline-block;
padding: 2px 10px;
border-radius: 10px;
font-size: 0.72rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.03em;
}
.admin-role-admin {
background: rgba(59, 130, 246, 0.15);
color: #3b82f6;
}
.admin-role-user {
background: rgba(34, 197, 94, 0.12);
color: #22c55e;
}
.admin-vaults-text {
font-size: 0.78rem;
color: var(--text-secondary);
}
.admin-actions {
white-space: nowrap;
}
.admin-action-btn {
background: none;
border: none;
cursor: pointer;
padding: 4px 6px;
border-radius: 4px;
font-size: 0.9rem;
transition: background 150ms;
}
.admin-action-btn:hover {
background: var(--bg-hover);
}
.admin-action-btn.danger:hover {
background: rgba(239, 68, 68, 0.12);
}
/* Admin form overlay */
.admin-form-overlay {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
backdrop-filter: blur(4px);
}
.admin-form-card {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 12px;
padding: 28px 24px;
width: 440px;
max-width: 90vw;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
}
.admin-form-card h3 {
margin: 0 0 20px;
font-size: 1.05rem;
color: var(--text-primary);
}
.admin-form-card .form-group {
margin-bottom: 16px;
}
.admin-form-card .form-group label {
display: block;
font-size: 0.82rem;
font-weight: 500;
color: var(--text-secondary);
margin-bottom: 6px;
}
.admin-form-card input[type="text"],
.admin-form-card input[type="password"],
.admin-form-card select {
width: 100%;
padding: 10px 12px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--bg-primary);
color: var(--text-primary);
font-size: 0.88rem;
font-family: inherit;
outline: none;
transition: border-color 200ms;
box-sizing: border-box;
}
.admin-form-card input:focus,
.admin-form-card select:focus {
border-color: var(--accent);
}
.admin-vault-list {
display: flex;
flex-direction: column;
gap: 6px;
max-height: 160px;
overflow-y: auto;
padding: 8px;
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 8px;
}
.admin-vault-list .checkbox-label {
color: var(--text-primary);
font-size: 0.82rem;
}
.admin-form-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 20px;
}
/* ---------------------------------------------------------------------------
Popup Mode (Nouvelle fenêtre)
--------------------------------------------------------------------------- */
body.popup-mode .top-nav,
body.popup-mode .sidebar,
body.popup-mode .resizer,
body.popup-mode .content-header {
display: none !important;
}
body.popup-mode .main-layout {
height: 100vh;
}
body.popup-mode .content-area {
margin: 15px auto;
padding: 30px;
border: 1px solid var(--border);
border-radius: 12px;
height: calc(100vh - 30px);
max-width: 1000px;
overflow-y: auto;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15);
box-sizing: border-box;
}
/* ---------------------------------------------------------------------------
Recent Tab Styles
--------------------------------------------------------------------------- */
/* Liste récente */
.recent-list {
display: flex;
flex-direction: column;
gap: 2px;
padding: 4px 0;
}
/* Item */
.recent-item {
padding: 10px 12px;
border-radius: 6px;
cursor: pointer;
border-left: 3px solid transparent;
transition:
background 0.15s,
border-color 0.15s;
}
.recent-item:hover {
background: var(--bg-secondary);
border-left-color: var(--accent);
}
.recent-item.active {
border-left-color: var(--accent);
background: var(--bg-secondary);
}
/* Header: temps + badge vault */
.recent-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3px;
}
.recent-time {
font-size: 11px;
color: var(--text-muted);
display: flex;
align-items: center;
gap: 4px;
}
.recent-vault-badge {
font-size: 10px;
font-weight: 600;
padding: 1px 6px;
border-radius: 10px;
background: var(--accent);
color: #fff;
opacity: 0.85;
}
/* Titre */
.recent-item-title {
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 2px;
}
/* Breadcrumb path */
.recent-item-path {
font-size: 11px;
color: var(--text-muted);
margin-bottom: 4px;
font-family: monospace;
}
/* Preview */
.recent-item-preview {
font-size: 12px;
color: var(--text-muted);
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
line-height: 1.4;
margin-bottom: 5px;
}
/* Tags */
.recent-item-tags {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.recent-item-tags .tag-pill {
font-size: 10px;
padding: 1px 6px;
border-radius: 10px;
background: var(--bg-secondary);
color: var(--accent);
border: 1px solid var(--border);
}
/* Filtre vault */
.recent-filter-bar {
padding: 8px 12px 4px;
}
.recent-filter-bar select {
width: 100%;
padding: 4px 8px;
font-size: 12px;
background: var(--bg-secondary);
color: var(--text-primary);
border: 1px solid var(--border);
border-radius: 4px;
cursor: pointer;
}
/* État vide */
.recent-empty {
display: flex;
flex-direction: column;
align-items: center;
padding: 32px 16px;
color: var(--text-muted);
gap: 8px;
font-size: 13px;
}
/* ---------------------------------------------------------------------------
Find in Page
--------------------------------------------------------------------------- */
/* Animation d'entrée */
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Barre principale */
.find-in-page-bar {
position: fixed;
bottom: 20px;
right: 20px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 12px;
padding: 12px 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
z-index: 1000;
animation: slideUp 200ms ease;
max-width: calc(100vw - 40px);
}
.find-in-page-bar[hidden] {
display: none;
}
/* Contenu de la barre */
.find-in-page-content {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
/* Icône de recherche */
.find-icon {
color: var(--text-secondary);
flex-shrink: 0;
}
/* Input de recherche */
#find-input {
flex: 1;
min-width: 200px;
padding: 6px 10px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-primary);
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.85rem;
outline: none;
transition: border-color 200ms ease;
}
#find-input:focus {
border-color: var(--accent);
}
/* Compteur d'occurrences */
.find-counter {
font-family: "JetBrains Mono", monospace;
font-size: 0.75rem;
color: var(--text-secondary);
white-space: nowrap;
min-width: 90px;
text-align: center;
}
/* Boutons de navigation */
.find-nav-buttons {
display: flex;
gap: 4px;
}
/* Boutons génériques */
.find-btn {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-primary);
color: var(--text-secondary);
cursor: pointer;
transition: all 150ms ease;
padding: 0;
flex-shrink: 0;
}
.find-btn:hover:not(:disabled) {
border-color: var(--accent);
color: var(--accent);
background: color-mix(in srgb, var(--accent) 10%, var(--bg-primary));
}
.find-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
/* Options */
.find-options {
display: flex;
gap: 4px;
border-left: 1px solid var(--border);
padding-left: 10px;
}
.find-option-btn {
font-family: "JetBrains Mono", monospace;
font-size: 0.7rem;
font-weight: 600;
}
.find-option-btn[aria-pressed="true"] {
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 20%, var(--bg-primary));
color: var(--accent);
}
.find-option-text {
pointer-events: none;
}
/* Bouton fermer */
.find-close {
border-left: 1px solid var(--border);
margin-left: 6px;
}
.find-close:hover {
background: var(--danger-bg);
border-color: var(--danger);
color: var(--danger);
}
/* Message d'erreur */
.find-error {
margin-top: 8px;
padding: 6px 10px;
background: var(--danger-bg);
border: 1px solid var(--danger);
border-radius: 6px;
color: var(--danger);
font-size: 0.75rem;
font-family: "JetBrains Mono", monospace;
}
.find-error[hidden] {
display: none;
}
/* Highlights dans le contenu */
.find-highlight {
background: rgba(255, 235, 59, 0.4);
padding: 0 2px;
border-radius: 2px;
transition: background 150ms ease;
}
[data-theme="dark"] .find-highlight {
background: rgba(255, 193, 7, 0.35);
}
.find-highlight-active {
background: rgba(255, 193, 7, 0.7);
box-shadow: 0 0 0 2px rgba(255, 193, 7, 0.3);
}
[data-theme="dark"] .find-highlight-active {
background: rgba(255, 193, 7, 0.6);
box-shadow: 0 0 0 2px rgba(255, 193, 7, 0.4);
}
/* Responsive mobile */
@media (max-width: 768px) {
.find-in-page-bar {
bottom: 10px;
left: 10px;
right: 10px;
max-width: none;
padding: 10px 12px;
}
.find-in-page-content {
gap: 6px;
}
#find-input {
min-width: 120px;
font-size: 0.8rem;
}
.find-counter {
font-size: 0.7rem;
min-width: 80px;
}
.find-btn {
width: 32px;
height: 32px;
}
.find-options {
padding-left: 6px;
}
}
/* ===== PWA STYLES ===== */
/* PWA Update Notification */
.pwa-update-notification {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 10000;
animation: slideInUp 0.3s ease-out;
}
.pwa-update-content {
background: var(--accent);
color: white;
padding: 16px 20px;
border-radius: var(--radius);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
gap: 12px;
max-width: 400px;
}
.pwa-update-content span {
flex: 1;
font-size: 0.9rem;
font-weight: 500;
}
.pwa-update-btn {
background: white;
color: var(--accent);
border: none;
padding: 8px 16px;
border-radius: var(--radius);
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
white-space: nowrap;
}
.pwa-update-btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.pwa-update-dismiss {
background: transparent;
border: none;
color: white;
font-size: 1.5rem;
line-height: 1;
cursor: pointer;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.8;
transition: opacity 0.2s ease;
}
.pwa-update-dismiss:hover {
opacity: 1;
}
/* PWA Install Button (optional - can be added to header) */
#pwa-install-btn {
display: none;
background: var(--accent);
color: white;
border: none;
padding: 8px 16px;
border-radius: var(--radius);
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}
#pwa-install-btn:hover {
background: var(--accent-green);
transform: translateY(-1px);
}
/* Animations */
@keyframes slideInUp {
from {
transform: translateY(100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
/* Mobile responsive */
@media (max-width: 768px) {
.pwa-update-notification {
bottom: 10px;
right: 10px;
left: 10px;
}
.pwa-update-content {
padding: 12px 16px;
font-size: 0.85rem;
}
.pwa-update-btn {
padding: 6px 12px;
font-size: 0.8rem;
}
}
/* ---------------------------------------------------------------------------
Dashboard Home - Recent Files Widget
--------------------------------------------------------------------------- */
.dashboard-home {
padding: 0;
width: 100%;
display: flex;
flex-direction: column;
gap: 32px;
}
.dashboard-section {
display: flex;
flex-direction: column;
}
.dashboard-header {
margin-bottom: 20px;
}
.dashboard-title-row {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.dashboard-icon {
width: 28px;
height: 28px;
color: var(--accent);
}
.dashboard-title-row h2 {
font-family: "JetBrains Mono", monospace;
font-size: 1.4rem;
font-weight: 600;
color: var(--text-primary);
margin: 0;
}
.dashboard-filter-row {
display: flex;
align-items: center;
gap: 12px;
}
.dashboard-select {
padding: 6px 12px;
font-size: 13px;
background: var(--bg-secondary);
color: var(--text-primary);
border: 1px solid var(--border);
border-radius: 6px;
cursor: pointer;
min-width: 160px;
}
.dashboard-select:focus {
outline: none;
border-color: var(--accent);
}
.dashboard-count {
font-size: 12px;
color: var(--text-muted);
padding: 4px 10px;
background: var(--bg-secondary);
border-radius: 12px;
}
/* Grid */
.dashboard-recent-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
flex: 1;
width: 100%;
}
@media (max-width: 1200px) {
.dashboard-recent-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.dashboard-home {
padding: 16px;
}
.dashboard-recent-grid {
grid-template-columns: 1fr;
}
.dashboard-title-row h2 {
font-size: 1.2rem;
}
}
/* Card */
.dashboard-card {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 12px;
padding: 12px;
cursor: pointer;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
display: flex;
flex-direction: column;
gap: 4px;
animation: fadeSlideIn 0.3s ease forwards;
opacity: 0;
/* BUG-017: allow the card to shrink inside the grid instead of overflowing
the viewport because of long nowrap titles/paths. */
min-width: 0;
overflow: hidden;
}
.dashboard-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
border-color: var(--accent);
}
.dashboard-card:active {
transform: translateY(0);
}
@keyframes fadeSlideIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Staggered animation for cards */
.dashboard-card:nth-child(1) {
animation-delay: 0ms;
}
.dashboard-card:nth-child(2) {
animation-delay: 50ms;
}
.dashboard-card:nth-child(3) {
animation-delay: 100ms;
}
.dashboard-card:nth-child(4) {
animation-delay: 150ms;
}
.dashboard-card:nth-child(5) {
animation-delay: 200ms;
}
.dashboard-card:nth-child(6) {
animation-delay: 250ms;
}
.dashboard-card:nth-child(7) {
animation-delay: 300ms;
}
.dashboard-card:nth-child(8) {
animation-delay: 350ms;
}
.dashboard-card:nth-child(9) {
animation-delay: 400ms;
}
/* Card header */
.dashboard-card-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 8px;
min-width: 0;
}
.dashboard-card-icon {
width: 40px;
height: 40px;
padding: 4px;
background: transparent;
border: 2px solid var(--accent);
border-radius: 8px;
color: var(--accent);
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.dashboard-card-icon svg {
width: 24px;
height: 24px;
}
.dashboard-vault-badge {
font-size: 10px;
font-weight: 600;
padding: 3px 8px;
border-radius: 10px;
background: var(--bg-primary);
color: var(--text-secondary);
border: 1px solid var(--border);
margin-right: auto;
}
.dashboard-card-bookmark-btn {
background: transparent;
border: none;
color: var(--text-muted);
cursor: pointer;
padding: 4px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
}
.dashboard-card-bookmark-btn:hover {
background: var(--bg-primary);
color: var(--accent);
}
.dashboard-card-bookmark-btn.active {
color: var(--accent-green);
}
/* Card title */
.dashboard-card-title {
font-size: 14px;
font-weight: 600;
color: var(--text-primary);
margin: 0;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
/* Card path */
.dashboard-card-path {
font-size: 11px;
color: var(--text-muted);
font-family: "JetBrains Mono", monospace;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Card preview */
.dashboard-card-preview {
display: none;
}
/* Card footer */
.dashboard-card-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin-top: 4px;
padding-top: 6px;
border-top: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
min-width: 0;
}
.dashboard-card-time {
font-size: 11px;
color: var(--text-muted);
display: flex;
align-items: center;
gap: 4px;
}
.dashboard-card-time svg {
width: 12px;
height: 12px;
}
/* Card tags */
.dashboard-card-tags {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.dashboard-card-tags .tag-pill {
font-size: 10px;
padding: 2px 6px;
border-radius: 8px;
background: var(--bg-tertiary);
color: var(--accent);
border: 1px solid var(--border);
}
/* Empty state */
.dashboard-recent-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 48px 24px;
color: var(--text-muted);
gap: 12px;
text-align: center;
flex: 1;
}
.dashboard-recent-empty svg {
width: 48px;
height: 48px;
opacity: 0.4;
}
.dashboard-recent-empty span {
font-size: 16px;
font-weight: 500;
}
.dashboard-recent-empty p {
font-size: 13px;
margin: 0;
opacity: 0.7;
}
/* Loading skeletons */
.dashboard-loading {
display: none;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.dashboard-loading.active {
display: grid;
}
@media (max-width: 1200px) {
.dashboard-loading {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.dashboard-loading {
grid-template-columns: 1fr;
}
}
.skeleton-card {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 12px;
padding: 16px;
height: 160px;
position: relative;
overflow: hidden;
}
.skeleton-card::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.05), transparent);
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
/* ===== CONTEXT MENU ===== */
.context-menu {
position: fixed;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
min-width: 200px;
z-index: 10000;
padding: 4px;
display: none;
}
.context-menu.active {
display: block;
}
.context-menu-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
border-radius: 6px;
cursor: pointer;
font-family: "JetBrains Mono", monospace;
font-size: 0.82rem;
color: var(--text-primary);
transition: all 150ms ease;
}
.context-menu-item:hover:not(.disabled) {
background: var(--bg-hover);
color: var(--accent);
}
.context-menu-item.disabled {
opacity: 0.4;
cursor: not-allowed;
}
.context-menu-item .icon {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.context-menu-separator {
height: 1px;
background: var(--border);
margin: 4px 0;
}
/* ===== INLINE RENAME ===== */
.sidebar-item-input {
width: 100%;
padding: 4px 8px;
background: var(--bg-primary);
border: 1px solid var(--accent);
border-radius: 4px;
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.82rem;
outline: none;
}
/* ===== VAULT READONLY BADGE ===== */
.vault-readonly-badge {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 6px;
background: var(--danger-bg);
color: var(--danger);
border-radius: 4px;
font-size: 0.7rem;
font-weight: 600;
margin-left: 6px;
}
/* ===== OBSIGATE MODALS ===== */
.obsigate-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--overlay-bg);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 200ms ease;
}
.obsigate-modal-overlay.active {
opacity: 1;
pointer-events: all;
}
.obsigate-modal {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 12px;
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
min-width: 400px;
max-width: 600px;
transform: scale(0.9);
transition: transform 200ms ease;
}
.obsigate-modal-overlay.active .obsigate-modal {
transform: scale(1);
}
.obsigate-modal-header {
padding: 16px 20px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
}
.obsigate-modal-title {
font-family: "JetBrains Mono", monospace;
font-size: 1.1rem;
font-weight: 700;
color: var(--text-primary);
}
.obsigate-modal-body {
padding: 20px;
}
.obsigate-modal-footer {
padding: 16px 20px;
border-top: 1px solid var(--border);
display: flex;
gap: 10px;
justify-content: flex-end;
}
.modal-input {
width: 100%;
padding: 10px 12px;
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.9rem;
outline: none;
transition: border-color 200ms ease;
}
.modal-input:focus {
border-color: var(--accent);
}
.modal-input.error {
border-color: var(--danger);
}
.modal-label {
display: block;
font-family: "JetBrains Mono", monospace;
font-size: 0.85rem;
font-weight: 600;
color: var(--text-secondary);
margin-bottom: 8px;
}
.modal-hint {
font-size: 0.75rem;
color: var(--text-muted);
margin-top: 6px;
}
.modal-error {
font-size: 0.8rem;
color: var(--danger);
margin-top: 6px;
}
.modal-select {
width: 100%;
padding: 10px 12px;
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.9rem;
outline: none;
cursor: pointer;
transition: border-color 200ms ease;
}
.modal-select:focus {
border-color: var(--accent);
}
.modal-btn {
padding: 8px 16px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-primary);
color: var(--text-primary);
font-family: "JetBrains Mono", monospace;
font-size: 0.85rem;
cursor: pointer;
transition: all 150ms ease;
}
.modal-btn:hover {
border-color: var(--accent);
color: var(--accent);
}
.modal-btn.primary {
background: var(--accent);
color: white;
border-color: var(--accent);
}
.modal-btn.primary:hover {
opacity: 0.9;
}
.modal-btn.danger {
background: var(--danger);
color: white;
border-color: var(--danger);
}
.modal-btn.danger:hover {
opacity: 0.9;
}
.modal-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.modal-form-group {
margin-bottom: 16px;
}
.modal-form-group:last-child {
margin-bottom: 0;
}
.modal-warning {
padding: 12px;
background: var(--danger-bg);
border: 1px solid var(--danger);
border-radius: 6px;
color: var(--danger);
font-size: 0.85rem;
margin-bottom: 16px;
display: flex;
align-items: flex-start;
gap: 10px;
}
.modal-warning .icon {
flex-shrink: 0;
margin-top: 2px;
}
/* ===== TAB BAR ===== */
.tab-bar {
display: flex;
align-items: stretch;
background: var(--bg-secondary);
border-bottom: 1px solid var(--border);
overflow: hidden;
flex-shrink: 0;
min-height: 36px;
}
.tab-bar[hidden] {
display: none;
}
.tab-list {
display: flex;
align-items: stretch;
overflow-x: auto;
overflow-y: hidden;
flex: 1;
scrollbar-width: thin;
}
/* Split buttons in tab bar */
.tab-split-buttons {
display: flex;
align-items: center;
gap: 2px;
padding: 0 4px;
flex-shrink: 0;
opacity: 0.3;
transition: opacity 150ms ease;
}
.tab-bar:hover .tab-split-buttons,
.tab-split-buttons:hover {
opacity: 1;
}
.tab-split-btn {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border: none;
border-radius: 4px;
background: transparent;
color: var(--text-muted);
cursor: pointer;
transition: background 100ms ease, color 100ms ease;
}
.tab-split-btn:hover {
background: var(--bg-hover);
color: var(--accent);
}
.tab-list::-webkit-scrollbar {
height: 3px;
}
.tab-item {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
font-size: 0.8rem;
color: var(--text-muted);
cursor: pointer;
white-space: nowrap;
border-right: 1px solid var(--border);
background: transparent;
transition: background 0.15s, color 0.15s;
user-select: none;
position: relative;
min-width: 0;
flex-shrink: 0;
}
.tab-item:hover {
background: var(--bg-hover);
color: var(--text-secondary);
}
.tab-item.active {
background: var(--bg-primary);
color: var(--text-primary);
border-bottom: 2px solid var(--accent);
margin-bottom: -1px;
}
.tab-item .tab-icon {
width: 14px;
height: 14px;
flex-shrink: 0;
opacity: 0.7;
}
.tab-item .tab-name {
overflow: hidden;
text-overflow: ellipsis;
max-width: 150px;
}
/* Preview tab (single-click) — italic title, slightly muted */
.tab-item.preview .tab-name {
font-style: italic;
opacity: 0.75;
}
.tab-item.preview {
background: var(--bg-hover);
}
.tab-item .tab-close {
width: 16px;
height: 16px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 3px;
flex-shrink: 0;
opacity: 0;
transition: opacity 0.15s, background 0.15s;
}
.tab-item:hover .tab-close,
.tab-item.active .tab-close {
opacity: 0.6;
}
.tab-item .tab-close:hover {
opacity: 1;
background: var(--bg-hover);
}
.tab-item.dragging {
opacity: 0.5;
background: var(--bg-hover);
}
.tab-drop-indicator {
width: 2px;
background: var(--accent);
flex-shrink: 0;
}
/* ── Backlinks panel ── */
.backlinks-panel {
margin-top: 24px;
padding: 12px 16px;
background: var(--bg-card, var(--bg-secondary));
border-radius: 8px;
border: 1px solid var(--border);
}
.backlinks-header {
font-size: 0.8rem;
font-weight: 600;
color: var(--text-muted);
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.backlinks-list {
display: flex;
flex-direction: column;
gap: 4px;
}
.backlink-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border-radius: 4px;
cursor: pointer;
transition: background 0.15s;
}
.backlink-item:hover {
background: var(--bg-hover);
}
.backlink-vault {
font-size: 0.7rem;
color: var(--accent);
background: var(--accent-bg, rgba(99, 102, 241, 0.1));
padding: 1px 6px;
border-radius: 3px;
}
.backlink-title {
font-size: 0.85rem;
color: var(--text-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ── Unsupported file notice ── */
.unsupported-file {
padding: 40px;
text-align: center;
color: var(--text-muted);
}
.unsupported-file i {
display: block;
margin: 0 auto 12px;
opacity: 0.4;
}
.unsupported-file .filename {
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
word-break: break-all;
}
.unsupported-file .btn-action {
margin-top: 12px;
display: inline-flex;
}
/* ── Dashboard Stats Grid ── */
.dashboard-stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 12px;
}
.stat-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 16px 12px;
background: var(--bg-card, var(--bg-secondary));
border-radius: 8px;
border: 1px solid var(--border);
}
.stat-icon {
width: 24px;
height: 24px;
opacity: 0.6;
margin-bottom: 8px;
color: var(--accent);
}
.stat-value {
font-size: 1.4rem;
font-weight: 700;
color: var(--text-primary);
}
.stat-label {
font-size: 0.75rem;
color: var(--text-muted);
margin-top: 2px;
}
.dashboard-stats-loading {
padding: 16px;
text-align: center;
color: var(--text-muted);
}
/* ── Dashboard Conflicts ── */
.dashboard-conflicts-grid {
display: flex;
flex-direction: column;
gap: 8px;
}
.conflict-card {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 14px;
background: var(--bg-card, var(--bg-secondary));
border-radius: 6px;
border: 1px solid var(--border);
gap: 12px;
}
.conflict-info {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.conflict-vault {
font-size: 0.7rem;
color: var(--accent);
background: var(--accent-bg, rgba(99,102,241,0.1));
padding: 1px 6px;
border-radius: 3px;
align-self: flex-start;
}
.conflict-name {
font-size: 0.85rem;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.conflict-date {
font-size: 0.7rem;
color: var(--text-muted);
}
.conflict-actions {
display: flex;
gap: 8px;
flex-shrink: 0;
}
.conflict-btn {
padding: 4px 10px;
font-size: 0.75rem;
border: 1px solid var(--border);
border-radius: 4px;
cursor: pointer;
background: var(--bg-primary);
color: var(--text-primary);
white-space: nowrap;
}
.conflict-btn:hover { background: var(--bg-hover); }
/* ── Quick Help (Dashboard) ── */
.quick-help {
margin-top: 16px;
background: var(--bg-card, var(--bg-secondary));
border: 1px solid var(--border);
border-radius: var(--radius-lg);
overflow: hidden;
}
.qh-header {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 14px;
font-size: 0.8rem;
font-weight: 600;
color: var(--text-secondary);
border-bottom: 1px solid var(--border);
user-select: none;
}
.qh-header i { color: var(--accent); opacity: 0.7; }
.qh-toggle {
margin-left: auto;
background: none;
border: none;
color: var(--text-muted);
cursor: pointer;
font-size: 1rem;
line-height: 1;
padding: 2px 6px;
border-radius: 4px;
}
.qh-toggle:hover { color: var(--text-secondary); background: var(--bg-hover); }
.qh-body {
padding: 10px 14px 14px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 6px 20px;
}
.qh-body.collapsed { display: none; }
.qh-row {
display: flex;
align-items: center;
gap: 10px;
padding: 4px 0;
}
.qh-kbd {
display: inline-flex;
align-items: center;
padding: 2px 8px;
font-family: var(--mono);
font-size: 0.7rem;
font-weight: 500;
color: var(--accent-text, #79c0ff);
background: var(--accent-bg, #1f2a3a);
border: 1px solid var(--border-md, #30363d);
border-radius: 4px;
white-space: nowrap;
min-width: 0;
letter-spacing: 0.3px;
}
.qh-desc {
font-size: 0.78rem;
color: var(--text-secondary);
}
.qh-divider {
grid-column: 1 / -1;
height: 1px;
background: var(--border);
margin: 6px 0 8px;
}
.qh-tip {
grid-column: 1 / -1;
display: flex;
align-items: flex-start;
gap: 8px;
font-size: 0.75rem;
color: var(--text-muted);
line-height: 1.5;
}
.qh-tip i { color: var(--warn); flex-shrink: 0; margin-top: 1px; }
.qh-tip strong { color: var(--text-secondary); }
/* ── Webhooks UI ── */
.webhook-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
background: var(--bg-card, var(--bg-secondary));
border-radius: 6px;
margin-bottom: 6px;
font-size: 0.8rem;
}
.webhook-name { font-weight: 500; min-width: 80px; }
.webhook-url { color: var(--accent); overflow: hidden; text-overflow: ellipsis; flex: 1; }
.webhook-events { color: var(--text-muted); font-size: 0.7rem; }
.webhook-delete { background: none; border: none; color: var(--text-error); cursor: pointer; font-size: 1rem; padding: 2px 6px; }
.config-add-row { display: flex; gap: 8px; margin-top: 8px; }
/* ── API/MCP tokens UI (#107) ── */
.token-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
background: var(--bg-card, var(--bg-secondary));
border-radius: 6px;
margin-bottom: 6px;
font-size: 0.8rem;
}
.token-name { font-weight: 500; min-width: 90px; }
.token-badge { font-size: 0.65rem; padding: 2px 8px; border-radius: 10px; white-space: nowrap; }
.token-badge-active { background: color-mix(in srgb, var(--success, #2e7d32) 18%, transparent); color: var(--success, #2e7d32); }
.token-badge-expired { background: color-mix(in srgb, var(--text-error, #c62828) 15%, transparent); color: var(--text-error, #c62828); }
.token-meta { color: var(--text-muted); font-size: 0.7rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
.token-delete { background: none; border: none; color: var(--text-error); cursor: pointer; font-size: 1rem; padding: 2px 6px; }
.token-secret-area { margin-top: 10px; padding: 10px; border: 1px dashed var(--accent); border-radius: 8px; }
.token-secret-area.hidden { display: none; }
.token-secret-text { width: 100%; font-family: monospace; font-size: 0.7rem; word-break: break-all; resize: none; }
/* ── Shares UI ── */
.share-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
background: var(--bg-card, var(--bg-secondary));
border-radius: 6px;
margin-bottom: 6px;
font-size: 0.8rem;
}
.share-path { font-weight: 500; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.share-url a { color: var(--accent); font-size: 0.75rem; }
.share-meta { color: var(--text-muted); font-size: 0.7rem; }
.share-revoke { background: none; border: 1px solid var(--text-error); color: var(--text-error); cursor: pointer; padding: 2px 8px; border-radius: 4px; font-size: 0.7rem; }
/* ── Share Dialog ── */
.share-dialog-overlay {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
}
.share-dialog {
background: var(--bg-primary);
border-radius: 12px;
padding: 24px;
max-width: 480px;
width: 90%;
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
}
.share-dialog h3 { margin: 0 0 4px; }
.share-url-input {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--border);
border-radius: 6px;
font-size: 0.8rem;
background: var(--bg-secondary);
color: var(--text-primary);
box-sizing: border-box;
}
.share-dialog-actions {
display: flex;
gap: 8px;
margin-top: 12px;
justify-content: flex-end;
}
.share-copy-btn {
padding: 6px 16px;
background: var(--accent);
color: #fff;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.85rem;
}
.share-close-btn {
padding: 6px 16px;
background: var(--bg-secondary);
color: var(--text-primary);
border: 1px solid var(--border);
border-radius: 6px;
cursor: pointer;
font-size: 0.85rem;
}
.share-create-btn {
padding: 6px 16px;
background: var(--accent);
color: #fff;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.85rem;
}
.share-revoke-btn {
padding: 6px 16px;
background: none;
color: var(--text-error);
border: 1px solid var(--text-error);
border-radius: 6px;
cursor: pointer;
font-size: 0.85rem;
}
/* ── Enhanced Search Bar Toggles ── */
.search-actions .tog {
font-family: var(--font-mono, monospace);
font-size: 10px;
font-weight: 600;
padding: 2px 5px;
border-radius: 3px;
min-width: auto;
line-height: 1.4;
}
.search-actions .tog.active {
color: var(--accent);
border-color: var(--accent);
background: rgba(99, 102, 241, 0.12);
}
.search-actions .icon-only {
padding: 2px 4px;
min-width: auto;
}
.search-sep {
width: 1px;
height: 16px;
background: var(--border);
margin: 0 2px;
align-self: center;
}
.search-count {
font-size: 10px;
color: var(--text-muted);
font-family: var(--font-mono, monospace);
white-space: nowrap;
min-width: 28px;
text-align: center;
}
.search-filter-row, .search-replace-row {
display: flex;
gap: 6px;
align-items: center;
padding: 4px 0 0 0;
}
.search-filter-input {
flex: 1;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--text-primary);
font-family: var(--font-mono, monospace);
font-size: 11px;
padding: 4px 8px;
outline: none;
}
.search-filter-input:focus { border-color: var(--accent); }
.search-filter-input::placeholder { color: var(--text-muted); }
/* ── Floating Results Bar ── */
.results-bar {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
gap: 2px;
margin: 0 auto;
padding: 6px 10px;
background: var(--bg-secondary);
border: 1px solid var(--border-md, var(--border));
border-radius: 10px;
box-shadow: 0 2px 16px rgba(0,0,0,0.35);
width: fit-content;
max-width: 95%;
z-index: 50;
backdrop-filter: blur(8px);
}
.results-bar-count {
font-size: 10px;
color: var(--text-muted);
font-family: var(--mono);
white-space: nowrap;
min-width: 28px;
text-align: center;
padding: 0 4px;
}
.results-bar-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border: 1px solid transparent;
border-radius: 4px;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
font-size: 12px;
transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.results-bar-btn:hover { background: var(--bg-hover); color: var(--text-primary); }
.results-bar-btn.tog {
font-family: var(--mono);
font-size: 10px;
font-weight: 600;
width: auto;
padding: 2px 5px;
}
.results-bar-btn.tog.active {
color: var(--accent);
border-color: var(--accent);
background: rgba(99,102,241,0.12);
}
.results-bar-sep {
width: 1px;
height: 16px;
background: var(--border);
margin: 0 6px;
align-self: center;
}
.search-replace-btn {
padding: 4px 10px;
font-size: 11px;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--bg-secondary);
color: var(--text-primary);
cursor: pointer;
white-space: nowrap;
}
.search-replace-btn:hover { background: var(--bg-hover); }
.search-replace-btn.destructive { border-color: var(--text-error); color: var(--text-error); }
/* ── Active search result highlight ── */
.btn-bookmark.active {
color: #059669;
border-color: #059669;
background: rgba(5, 150, 105, 0.08);
}
.btn-bookmark.active:hover {
background: rgba(5, 150, 105, 0.15);
}
.btn-share.shared {
color: #059669;
border-color: #059669;
background: rgba(5, 150, 105, 0.08);
}
.btn-share.shared:hover {
background: rgba(5, 150, 105, 0.15);
}
/* ── Shared Cards ── */
.shared-card {
padding: 10px 14px;
background: var(--bg-card, var(--bg-secondary));
border-radius: 6px;
border: 1px solid var(--border);
cursor: pointer;
transition: background 0.15s;
display: flex;
flex-direction: column;
gap: 6px;
}
.shared-card:hover { background: var(--bg-hover); }
.shared-card-header {
display: flex;
align-items: center;
gap: 8px;
}
.shared-card-title { font-weight: 500; font-size: 0.85rem; }
.shared-card-vault {
font-size: 0.65rem;
color: var(--accent);
background: var(--accent-bg, rgba(99,102,241,0.1));
padding: 1px 6px;
border-radius: 3px;
margin-left: auto;
}
.shared-card-meta {
font-size: 0.7rem;
color: var(--text-muted);
display: flex;
gap: 12px;
}
.shared-card-actions {
display: flex;
gap: 6px;
}
.shared-card-actions button {
font-size: 0.7rem;
padding: 2px 8px;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--bg-primary);
color: var(--text-primary);
cursor: pointer;
}
.shared-card-actions button:hover { background: var(--bg-hover); }
/* ── Dashboard Tab Navigation ── */
.dashboard-tabs {
display: flex;
gap: 2px;
margin-bottom: 16px;
border-bottom: 2px solid var(--border);
}
.dashboard-tab {
padding: 8px 16px;
border: none;
background: none;
color: var(--text-muted);
cursor: pointer;
font-size: 0.85rem;
font-weight: 500;
display: flex;
align-items: center;
gap: 6px;
border-bottom: 2px solid transparent;
margin-bottom: -2px;
transition: color 0.15s, border-color 0.15s;
}
.dashboard-tab:hover { color: var(--text-primary); }
.dashboard-tab.active {
color: var(--accent);
border-bottom-color: var(--accent);
}
.dashboard-panel {
display: none;
}
.dashboard-panel.active {
display: block;
}
/* ═══════════════════════════════════════════════════════════════════
Command Palette (Ctrl+P)
═══════════════════════════════════════════════════════════════════ */
.command-palette-overlay {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: 0 0;
z-index: 10000;
display: flex;
justify-content: center;
padding-top: 12vh;
pointer-events: none;
opacity: 0;
transition: opacity 0.1s ease, background 0.1s ease;
}
.command-palette-overlay.active {
opacity: 1;
background: var(--overlay-bg);
pointer-events: auto;
}
.command-palette {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 10px;
box-shadow: 0 8px 40px rgba(0,0,0,0.45), 0 0 0 1px rgba(255,255,255,0.03);
width: 580px;
max-width: calc(100vw - 40px);
max-height: 60vh;
display: flex;
flex-direction: column;
overflow: hidden;
animation: cp-slide-in 0.12s ease-out;
}
@keyframes cp-slide-in {
from { transform: translateY(-12px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.cp-header {
display: flex;
align-items: center;
border-bottom: 1px solid var(--border);
padding: 0 14px;
}
.cp-input {
flex: 1;
border: none;
background: none;
padding: 14px 0;
font-size: 16px;
color: var(--text-primary);
outline: none;
font-family: inherit;
}
.cp-input::placeholder {
color: var(--text-muted);
}
.cp-hint {
font-size: 11px;
color: var(--text-muted);
background: var(--bg-hover);
padding: 3px 8px;
border-radius: 4px;
font-family: "JetBrains Mono", monospace;
opacity: 0.7;
}
.cp-results {
flex: 1;
overflow-y: auto;
padding: 6px 0;
max-height: 40vh;
}
.cp-empty {
padding: 24px 16px;
text-align: center;
color: var(--text-muted);
font-size: 13px;
}
.cp-error {
color: var(--accent-orange, #d29922);
}
.cp-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 14px;
cursor: pointer;
border-left: 3px solid transparent;
}
.cp-item:hover {
background: var(--bg-hover);
border-left-color: var(--accent);
}
.cp-item.cp-selected {
background: var(--accent-bg);
border-left-color: var(--accent);
}
.cp-item-label {
font-size: 14px;
color: var(--text-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.cp-item-sublabel {
font-size: 11px;
color: var(--text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 45%;
text-align: right;
margin-left: 12px;
}
.cp-footer {
display: flex;
gap: 14px;
padding: 8px 14px;
border-top: 1px solid var(--border);
font-size: 11px;
color: var(--text-muted);
}
.cp-footer span {
display: flex;
align-items: center;
gap: 4px;
}
.cp-footer span::before {
content: '';
display: inline-block;
width: 3px; height: 3px;
background: var(--text-muted);
border-radius: 50%;
margin-right: 4px;
}
.cp-footer span:first-child::before { display: none; }
/* ── Breadcrumb ── */
.cp-breadcrumb {
display: none;
align-items: center;
gap: 2px;
padding: 8px 14px;
font-size: 12px;
color: var(--text-secondary);
background: var(--bg-primary);
border-bottom: 1px solid var(--border);
overflow-x: auto;
white-space: nowrap;
scrollbar-width: none;
}
.cp-breadcrumb::-webkit-scrollbar { display: none; }
.cp-bc-root { font-weight: 600; color: var(--accent); }
.cp-bc-sep { color: var(--text-muted); padding: 0 2px; }
.cp-bc-item { cursor: pointer; padding: 1px 4px; border-radius: 3px; }
.cp-bc-item:hover { background: var(--bg-hover); }
/* ── Name input ── */
.cp-name-input {
display: flex;
flex-direction: column;
padding: 8px 14px;
border-bottom: 1px solid var(--border);
background: var(--bg-primary);
}
.cp-name-field {
width: 100%;
border: 1px solid var(--border);
background: var(--bg-secondary);
color: var(--text-primary);
padding: 10px 12px;
border-radius: 6px;
font-size: 14px;
font-family: inherit;
outline: none;
transition: border-color 0.15s;
}
.cp-name-field:focus { border-color: var(--accent); }
.cp-name-hint {
font-size: 11px;
color: var(--text-muted);
margin-top: 6px;
}
/* Browse filter in command palette */
.cp-browse-filter {
width: calc(100% - 24px);
margin: 8px 12px 4px;
padding: 7px 10px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-primary);
color: var(--text-primary);
font-size: 0.8rem;
font-family: inherit;
outline: none;
transition: border-color 0.15s;
}
.cp-browse-filter:focus { border-color: var(--accent); }
.cp-browse-filter::placeholder { color: var(--text-muted); }
/* ── Help Modal: desktop = wider reading (#105) ──
The Tauri shell (body.desktop-mode) and wide web viewports get the full
reading layout instead of the 1320px modal cap. */
body.desktop-mode .help-container {
max-width: 1760px;
width: 96vw;
}
body.desktop-mode .help-content {
max-width: 1440px;
padding: 36px 56px 64px;
}
body.desktop-mode .editor-container {
max-height: 94vh;
}
@media (min-width: 1400px) {
.help-container {
max-width: min(1640px, calc(100vw - 48px));
}
.help-content {
max-width: 1280px;
}
}
/* ── Help Modal: Mobile responsive ── */
@media (max-width: 768px) {
.help-container,
.editor-container.help-container {
max-width: 100vw;
width: 100vw;
height: 100vh;
max-height: 100vh;
border-radius: 0;
box-sizing: border-box;
}
.help-hamburger {
display: inline-flex;
width: 44px;
height: 44px;
min-width: 44px;
}
/* TOC drawer: collapsible block for the help modal; the config modal
(#114) overrides this with a fixed left drawer + backdrop. */
.help-nav {
position: static;
width: 100%;
min-width: 0;
max-width: 100%;
max-height: none;
height: auto;
z-index: auto;
transform: none;
transition: none;
border-right: none;
border-bottom: 1px solid var(--border);
box-shadow: none;
flex-shrink: 0;
display: none;
box-sizing: border-box;
}
.help-nav-header {
padding: 10px 16px 6px;
}
/* Content full-width */
.help-body {
flex-direction: column;
overflow-y: auto;
overflow-x: hidden;
padding: 0;
width: 100%;
box-sizing: border-box;
}
.help-content {
padding: 14px 14px 40px;
flex: 1;
overflow-y: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
word-break: break-word;
width: 100%;
max-width: 100%;
box-sizing: border-box;
}
.help-content pre, .help-content code, .help-content table {
max-width: 100%;
overflow-x: auto;
}
.help-content:focus { outline: none; }
.help-hero {
flex-direction: column;
gap: 16px;
min-width: 0;
width: 100%;
box-sizing: border-box;
padding: 20px 16px;
}
.help-hero-copy {
min-width: 0;
width: 100%;
}
.help-badges {
flex-wrap: wrap;
gap: 6px;
}
.help-badge {
white-space: normal;
}
.help-hero-visual { display: none; }
.help-section {
padding: 20px 0 16px;
min-width: 0;
width: 100%;
box-sizing: border-box;
}
.help-nav-link {
padding: 10px 12px;
font-size: 0.88rem;
}
}
/* ══════════════════════════════════════════
Mobile Bottom Toolbar (Obsidian-style)
══════════════════════════════════════════ */
.mobile-toolbar {
display: none;
}
.vault-context-bar {
display: none;
}
@media (max-width: 768px) {
.mobile-toolbar {
display: flex;
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 64px;
background: var(--bg-secondary);
border-top: 1px solid var(--border);
z-index: 900;
align-items: center;
justify-content: space-around;
padding: 4px 4px;
padding-bottom: calc(4px + env(safe-area-inset-bottom, 0));
-webkit-backdrop-filter: blur(12px);
backdrop-filter: blur(12px);
}
/* Push content up to avoid toolbar overlap */
.main-body {
padding-bottom: 64px;
padding-bottom: calc(64px + env(safe-area-inset-bottom, 0));
}
/* Enable pull-to-refresh on mobile — unblock the overscroll chain */
html {
overscroll-behavior-y: auto;
}
body {
overflow-y: auto;
overscroll-behavior-y: auto;
height: 100vh;
height: 100dvh;
}
.app-container {
overflow-y: visible;
}
.main-layout {
overflow-y: visible;
}
.content-wrapper {
overflow: visible;
}
.content-area {
overscroll-behavior-y: auto;
}
/* Hide desktop tab bar on mobile (bottom toolbar has its own tab button) */
.tab-bar {
display: none !important;
}
/* Vault context indicator — hidden (now in header) */
.vault-context-bar {
display: none !important;
}
.vault-context-pill {
display: none;
}
.mt-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 3px;
flex: 1;
height: auto;
min-height: 48px;
padding: 4px 4px;
border: none;
border-radius: 8px;
background: transparent;
color: var(--text-muted);
cursor: pointer;
transition: color 0.15s, background 0.15s;
position: relative;
-webkit-tap-highlight-color: transparent;
}
.mt-btn:active {
background: rgba(255,255,255,0.06);
}
.mt-btn svg {
flex-shrink: 0;
}
.mt-label {
font-size: 10px;
font-weight: 500;
line-height: 1;
}
.mt-btn-primary {
color: var(--accent);
}
.mt-btn-primary .mt-label {
color: var(--accent);
}
/* Explorer, Search and Tabs share the Commands button accent color */
#mt-explorer,
#mt-search,
#mt-tabs {
color: var(--accent);
}
/* Hide the floating AI pastille on mobile — the assistant lives in the
centre of the bottom toolbar instead (below). */
.ai-fab {
display: none !important;
}
/* AI assistant — raised central button, stands out from the 4 other items */
.mt-btn-ai {
flex: 0 0 auto;
width: 56px;
height: 56px;
min-height: 56px;
margin: -18px 2px 0;
border-radius: 50%;
background: var(--accent);
color: #fff;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35), 0 0 0 4px var(--bg-secondary);
z-index: 2;
}
.mt-btn-ai:active {
background: var(--accent);
transform: scale(0.94);
}
.mt-btn-ai svg {
width: 26px;
height: 26px;
}
.mt-btn-ai .mt-label {
display: none;
}
/* Tab count badge */
.mt-badge {
position: absolute;
top: 2px;
right: 50%;
transform: translateX(18px);
background: var(--accent);
color: #fff;
font-size: 9px;
font-weight: 700;
min-width: 16px;
height: 16px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 4px;
line-height: 1;
}
/* ── Tab Switcher Bottom Sheet ── */
.mt-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.5);
z-index: 950;
opacity: 0;
transition: opacity 0.25s;
}
.mt-overlay.visible {
display: block;
opacity: 1;
}
.mt-tab-switcher {
position: fixed;
bottom: 0;
left: 0;
right: 0;
max-height: 60vh;
background: var(--bg-secondary);
border-radius: 16px 16px 0 0;
z-index: 960;
transform: translateY(100%);
transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
display: flex;
flex-direction: column;
box-shadow: 0 -4px 24px rgba(0,0,0,0.4);
padding-bottom: env(safe-area-inset-bottom, 0);
}
.mt-tab-switcher.open {
transform: translateY(0);
}
.mt-sheet-handle {
width: 36px;
height: 4px;
background: var(--border);
border-radius: 2px;
margin: 10px auto 6px;
flex-shrink: 0;
}
.mt-sheet-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px 12px;
flex-shrink: 0;
}
.mt-sheet-title {
font-family: "JetBrains Mono", monospace;
font-size: 0.8rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
}
.mt-sheet-close {
width: 28px; height: 28px;
padding: 0;
border: 1px solid var(--border);
border-radius: 6px;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.mt-sheet-close:hover { color: var(--accent); border-color: var(--accent); }
.mt-sheet-actions {
display: flex;
align-items: center;
gap: 8px;
}
.mt-sheet-close-all {
padding: 5px 10px;
border: 1px solid var(--danger, #ef4444);
border-radius: 6px;
background: transparent;
color: var(--danger, #ef4444);
cursor: pointer;
font-size: 0.7rem;
font-weight: 600;
transition: background 0.15s;
}
.mt-sheet-close-all:hover {
background: rgba(239,68,68,0.1);
}
.mt-sheet-list {
flex: 1;
overflow-y: auto;
padding: 0 12px 12px;
-webkit-overflow-scrolling: touch;
}
.mt-tab-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-radius: 8px;
cursor: pointer;
color: var(--text-primary);
font-size: 0.85rem;
transition: background 0.1s;
margin-bottom: 2px;
}
.mt-tab-item:active {
background: rgba(255,255,255,0.06);
}
.mt-tab-item.active {
background: color-mix(in srgb, var(--accent) 12%, transparent);
color: var(--accent);
font-weight: 600;
}
.mt-tab-item-icon {
flex-shrink: 0;
opacity: 0.6;
}
.mt-tab-item-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mt-tab-item-close {
width: 24px; height: 24px;
padding: 0;
border: none;
border-radius: 4px;
background: transparent;
color: var(--text-muted);
cursor: pointer;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.mt-tab-item-close:hover {
color: var(--danger, #ef4444);
background: rgba(239,68,68,0.1);
}
}
/* ==========================================================================
Backup / Diff Viewer Modal
========================================================================== */
.backup-viewer-panel {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: min(90vw, 960px);
height: min(85vh, 700px);
background: var(--bg-primary, #1e1e2e);
border: 1px solid var(--border);
border-radius: 12px;
box-shadow: 0 25px 60px rgba(0,0,0,0.5);
display: flex;
flex-direction: column;
overflow: hidden;
z-index: 1001;
}
.backup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 18px;
border-bottom: 1px solid var(--border);
background: var(--bg-secondary);
flex-shrink: 0;
}
.backup-header-left {
display: flex;
align-items: baseline;
gap: 10px;
min-width: 0;
}
.backup-header h3 {
margin: 0;
font-size: 1rem;
font-weight: 600;
color: var(--text-primary);
}
.backup-file-path {
font-size: 0.78rem;
color: var(--text-muted);
font-family: var(--font-mono, 'SF Mono', 'Fira Code', monospace);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.backup-header-right {
display: flex;
align-items: center;
gap: 12px;
flex-shrink: 0;
}
.backup-count {
font-size: 0.75rem;
color: var(--text-muted);
background: var(--bg-tertiary);
padding: 3px 8px;
border-radius: 4px;
}
.backup-close-btn {
width: 36px;
height: 36px;
padding: 0;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-primary);
color: var(--text-secondary);
cursor: pointer;
transition: all 150ms ease;
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
.backup-close-btn:hover {
color: var(--accent);
border-color: var(--accent);
}
.backup-toolbar {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 18px;
border-bottom: 1px solid var(--border);
background: var(--bg-primary);
flex-shrink: 0;
}
.backup-selector-group {
display: flex;
align-items: center;
gap: 6px;
}
.backup-selector-group label {
font-size: 0.78rem;
color: var(--text-muted);
white-space: nowrap;
}
.backup-select {
padding: 6px 10px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-secondary);
color: var(--text-primary);
font-size: 0.8rem;
font-family: var(--font-mono);
max-width: 240px;
cursor: pointer;
}
.backup-select:focus {
outline: none;
border-color: var(--accent);
}
.backup-vs-label {
font-size: 0.75rem;
color: var(--text-muted);
font-weight: 600;
user-select: none;
}
.backup-restore-btn {
margin-left: auto;
padding: 6px 14px;
border: 1px solid var(--accent);
border-radius: 6px;
background: color-mix(in srgb, var(--accent) 10%, transparent);
color: var(--accent);
font-size: 0.8rem;
font-weight: 500;
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
transition: background 0.15s, opacity 0.15s;
white-space: nowrap;
}
.backup-restore-btn:hover {
background: color-mix(in srgb, var(--accent) 20%, transparent);
}
.backup-restore-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.backup-restore-btn .icon-sm {
width: 14px;
height: 14px;
}
.backup-diff-container {
flex: 1;
overflow-y: auto;
background: var(--bg-primary);
}
.backup-diff-loading,
.backup-diff-error,
.backup-diff-empty {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: var(--text-muted);
font-size: 0.85rem;
}
.backup-diff-error {
color: var(--danger, #ef4444);
}
.backup-diff-output {
padding: 0;
}
.backup-diff-table {
width: 100%;
border-collapse: collapse;
font-family: var(--font-mono, 'SF Mono', 'Fira Code', 'Cascadia Code', monospace);
font-size: 0.8rem;
line-height: 1.55;
table-layout: fixed;
}
.backup-diff-table td {
padding: 0;
}
.backup-diff-table td.diff-prefix {
width: 22px;
text-align: center;
user-select: none;
font-weight: 600;
padding: 1px 0;
vertical-align: top;
}
.backup-diff-table td.diff-content {
padding: 1px 8px;
vertical-align: top;
}
.backup-diff-table td.diff-content pre {
margin: 0;
white-space: pre-wrap;
word-break: break-all;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
.backup-diff-table tr.diff-add td {
background: rgba(34, 197, 94, 0.12);
}
.backup-diff-table tr.diff-add td.diff-prefix {
color: #22c55e;
}
.backup-diff-table tr.diff-del td {
background: rgba(239, 68, 68, 0.12);
}
.backup-diff-table tr.diff-del td.diff-prefix {
color: #ef4444;
}
.backup-diff-table tr.diff-hunk td {
background: color-mix(in srgb, var(--accent) 8%, transparent);
color: var(--accent);
font-weight: 600;
}
.backup-diff-table tr.diff-header-line td {
background: var(--bg-secondary);
color: var(--text-muted);
font-weight: 600;
}
.backup-diff-table tr.diff-context td {
color: var(--text-secondary);
}
.backup-body {
flex: 1;
display: flex;
flex-direction: column;
overflow: auto;
}
.backup-footer {
padding: 6px 18px;
border-top: 1px solid var(--border);
background: var(--bg-secondary);
flex-shrink: 0;
}
.backup-footer-hint {
font-size: 0.7rem;
color: var(--text-muted);
}
/* ── Side-by-side diff view ── */
.backup-diff-sidebyside .sidebyside {
table-layout: fixed;
}
.backup-diff-sidebyside td.sidebyside-left {
border-right: 1px solid var(--border);
}
.backup-diff-sidebyside td.sidebyside-right {
border-left: 1px solid var(--border);
}
.backup-diff-sidebyside td.diff-empty-cell {
background: var(--bg-tertiary);
}
.backup-diff-mode-btn {
padding: 6px 10px;
border: 1px solid var(--border);
border-radius: 6px;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 0.8rem;
transition: all 150ms ease;
}
.backup-diff-mode-btn:hover {
color: var(--accent);
border-color: var(--accent);
}
.backup-diff-mode-btn .icon-sm {
width: 14px;
height: 14px;
}
/* ── Backup Manager ── */
.backup-manager {
padding: 16px 24px;
max-width: 1000px;
margin: 0 auto;
}
.backup-manager-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
gap: 12px;
}
.backup-manager-header h2 {
margin: 0;
font-size: 1.1rem;
display: flex;
align-items: center;
gap: 8px;
}
.backup-manager-actions {
display: flex;
gap: 6px;
}
.backup-manager-filter {
padding: 6px 10px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-primary);
color: var(--text-primary);
font-size: 0.8rem;
min-width: 200px;
}
.backup-manager-btn {
width: 32px; height: 32px;
border: 1px solid var(--border);
border-radius: 6px;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
}
.backup-manager-btn:hover { color: var(--accent); border-color: var(--accent); }
.backup-manager-stats { display: flex; gap: 16px; margin-bottom: 14px; }
.bm-stat { font-size: 0.8rem; color: var(--text-muted); }
.bm-vault-group { margin-bottom: 16px; }
.bm-vault-name {
font-size: 0.85rem; font-weight: 600; margin: 0 0 6px 0;
display: flex; align-items: center; gap: 6px;
}
.bm-file-group {
border: 1px solid var(--border); border-radius: 6px;
margin-bottom: 8px; overflow: hidden;
}
.bm-file-header {
display: flex; align-items: center; gap: 12px;
padding: 8px 12px; background: var(--bg-secondary);
border-bottom: 1px solid var(--border);
}
.bm-file-name { font-size: 0.8rem; font-weight: 500; display: flex; align-items: center; gap: 4px; }
.bm-file-meta { font-size: 0.7rem; color: var(--text-muted); flex: 1; }
.bm-file-purge {
width: 28px; height: 28px; border: 1px solid var(--border); border-radius: 4px;
background: transparent; color: var(--text-muted); cursor: pointer;
display: flex; align-items: center; justify-content: center;
}
.bm-file-purge:hover { color: var(--danger); border-color: var(--danger); }
.bm-backup-list { padding: 2px 0; }
.bm-backup-item {
display: flex; align-items: center; gap: 12px;
padding: 4px 12px; font-size: 0.75rem;
}
.bm-backup-item:hover { background: var(--bg-secondary); }
.bm-backup-date { color: var(--text-secondary); min-width: 130px; font-family: var(--font-mono); }
.bm-backup-size { color: var(--text-muted); flex: 1; }
.bm-backup-delete {
width: 22px; height: 22px; border: none; border-radius: 4px;
background: transparent; color: var(--text-muted); cursor: pointer;
display: flex; align-items: center; justify-content: center;
opacity: 0;
}
.bm-backup-item:hover .bm-backup-delete { opacity: 1; }
.bm-backup-delete:hover { color: var(--danger); background: rgba(239,68,68,0.1); }
.backup-footer-manage-btn {
background: none; border: 1px solid var(--border);
border-radius: 4px; color: var(--accent);
font-size: 0.7rem; cursor: pointer; padding: 3px 10px;
transition: all 150ms ease;
}
.backup-footer-manage-btn:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.backup-manager-empty,
.backup-manager-error {
text-align: center; padding: 2rem; color: var(--text-muted); font-size: 0.85rem;
}
.backup-manager-error { color: var(--danger); }
/* ==========================================================================
Mermaid.js Diagrams
========================================================================== */
.mermaid-container {
margin: 12px 0;
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
background: var(--bg-secondary);
}
/* ── Header bar ── */
.mermaid-header {
display: flex; align-items: center; justify-content: space-between;
padding: 6px 10px;
background: var(--bg-hover);
border-bottom: 1px solid var(--border);
min-height: 34px;
}
.mermaid-diagram-type {
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
font-size: 0.75rem; font-weight: 600;
color: var(--text-secondary);
}
.mermaid-header-actions {
display: flex; align-items: center; gap: 2px;
}
/* ── Buttons ── */
.mermaid-btn {
width: 28px; height: 28px;
border: 1px solid transparent; border-radius: 4px;
background: transparent; color: var(--text-secondary);
cursor: pointer; display: flex; align-items: center; justify-content: center;
transition: background 0.12s, color 0.12s;
}
.mermaid-btn:hover { background: var(--bg-primary); color: var(--accent); border-color: var(--border); }
/* ── Code / Preview toggle ── */
.mermaid-toggle {
display: flex; margin-left: 8px;
border: 1px solid var(--border); border-radius: 5px;
overflow: hidden;
}
.mermaid-toggle-btn {
padding: 2px 10px; font-size: 0.7rem; font-weight: 500;
border: none; background: transparent;
color: var(--text-muted, #999); cursor: pointer;
transition: background 0.12s, color 0.12s;
}
.mermaid-toggle-btn.active {
background: var(--bg-primary); color: var(--text-primary);
box-shadow: 0 0 0 1px var(--border);
}
.mermaid-toggle-btn:first-child { border-right: 1px solid var(--border); }
/* ── Body ── */
.mermaid-body {
position: relative;
}
.mermaid-rendered {
padding: 16px;
overflow: hidden;
min-height: 80px;
display: flex;
justify-content: center;
}
.mermaid-rendered svg { max-width: 100%; height: auto; }
.mermaid-source { padding: 16px; overflow: auto; }
.mermaid-source pre {
margin: 0; padding: 12px;
background: var(--code-bg);
border-radius: 4px;
font-size: 0.78rem; line-height: 1.5;
color: var(--text-primary);
}
/* ── Error ── */
.mermaid-error {
margin: 12px 0; padding: 12px 16px;
border: 1px solid rgba(239,68,68,0.3); border-radius: 6px;
background: rgba(239,68,68,0.08); color: var(--danger);
font-size: 0.8rem; line-height: 1.5;
}
.mermaid-error strong { display: block; margin-bottom: 4px; }
/* ── Fullscreen ── */
.mermaid-fullscreen-overlay {
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
z-index: 10000;
display: flex; flex-direction: column;
}
/* Light theme — clean white like the example */
[data-theme="light"] .mermaid-fullscreen-overlay {
background: rgba(255,255,255,0.97);
}
[data-theme="light"] .mermaid-fullscreen-header {
background: rgba(0,0,0,0.03);
border-bottom: 1px solid rgba(0,0,0,0.08);
}
[data-theme="light"] .mermaid-fullscreen-header .mermaid-diagram-type {
color: rgba(0,0,0,0.5);
}
[data-theme="light"] .mermaid-fullscreen-header .mermaid-btn {
color: rgba(0,0,0,0.4);
}
[data-theme="light"] .mermaid-fullscreen-header .mermaid-btn:hover {
background: rgba(0,0,0,0.05);
color: rgba(0,0,0,0.8);
}
/* Dark theme */
[data-theme="dark"] .mermaid-fullscreen-overlay {
background: rgba(18,18,24,0.97);
}
[data-theme="dark"] .mermaid-fullscreen-header {
background: rgba(255,255,255,0.06);
border-bottom: 1px solid rgba(255,255,255,0.08);
}
[data-theme="dark"] .mermaid-fullscreen-header .mermaid-diagram-type {
color: rgba(255,255,255,0.7);
}
[data-theme="dark"] .mermaid-fullscreen-header .mermaid-btn {
color: rgba(255,255,255,0.6);
}
[data-theme="dark"] .mermaid-fullscreen-header .mermaid-btn:hover {
background: rgba(255,255,255,0.1);
color: #fff;
}
.mermaid-fullscreen-header {
display: flex; align-items: center; justify-content: space-between;
padding: 10px 16px;
min-height: 46px;
flex-shrink: 0;
}
.mermaid-fullscreen-content {
flex: 1;
display: flex; align-items: center; justify-content: center;
padding: 16px;
overflow: hidden;
}
.mermaid-fullscreen-content svg {
width: 100%; height: 100%;
max-width: 100%; max-height: 100%;
}
/* ── Dark mode overrides for beta diagrams that ignore themeVariables ── */
/* packet-beta */
[data-theme="dark"] .mermaid-rendered svg .row rect,
[data-theme="dark"] .mermaid-rendered svg g[id*="packet"] rect {
fill: #1e3a5f !important;
stroke: #4a7ab5 !important;
}
[data-theme="dark"] .mermaid-rendered svg .row text,
[data-theme="dark"] .mermaid-rendered svg g[id*="packet"] text {
fill: #c8daf0 !important;
}
[data-theme="dark"] .mermaid-fullscreen-content svg .row rect,
[data-theme="dark"] .mermaid-fullscreen-content svg g[id*="packet"] rect {
fill: #1e3a5f !important;
stroke: #4a7ab5 !important;
}
[data-theme="dark"] .mermaid-fullscreen-content svg .row text,
[data-theme="dark"] .mermaid-fullscreen-content svg g[id*="packet"] text {
fill: #c8daf0 !important;
}
/* xychart-beta — bar fills and line color */
[data-theme="dark"] .mermaid-rendered svg rect[class*="plot"],
[data-theme="dark"] .mermaid-rendered svg rect[id*="bar"] {
fill: #1e3a5f !important;
stroke: #4a7ab5 !important;
}
[data-theme="dark"] .mermaid-rendered svg path[class*="plot"],
[data-theme="dark"] .mermaid-rendered svg path[id*="line"] {
stroke: #6a9ad0 !important;
}
[data-theme="dark"] .mermaid-fullscreen-content svg rect[class*="plot"],
[data-theme="dark"] .mermaid-fullscreen-content svg rect[id*="bar"] {
fill: #1e3a5f !important;
stroke: #4a7ab5 !important;
}
[data-theme="dark"] .mermaid-fullscreen-content svg path[class*="plot"],
[data-theme="dark"] .mermaid-fullscreen-content svg path[id*="line"] {
stroke: #6a9ad0 !important;
}
.mermaid-focus-panel {
position: fixed; top: 0; right: 0; bottom: 0; width: 480px;
z-index: 9998; background: var(--bg-secondary);
border-left: 1px solid var(--border);
box-shadow: -4px 0 24px rgba(0,0,0,0.3);
display: flex; flex-direction: column;
}
.mermaid-focus-header {
display: flex; align-items: center; justify-content: space-between;
padding: 10px 14px; border-bottom: 1px solid var(--border);
font-size: 0.85rem; font-weight: 600;
}
.mermaid-focus-close {
width: 28px; height: 28px; border: 1px solid var(--border); border-radius: 4px;
background: transparent; color: var(--text-muted); cursor: pointer;
display: flex; align-items: center; justify-content: center;
}
.mermaid-focus-close:hover { color: var(--accent); }
.mermaid-focus-content { flex: 1; overflow: auto; padding: 16px; }
/* Mermaid editor live preview panel */
.mermaid-live-preview {
border-top: 1px solid var(--border);
background: var(--bg-secondary);
min-height: 100px; max-height: 300px;
overflow: auto; padding: 12px;
}
.mermaid-live-preview .mermaid-error { margin: 0; }
/* Manager body: list + preview side panel */
.backup-manager-body { display: flex; gap: 0; min-height: 400px; }
.backup-manager-list { flex: 1; min-width: 0; }
.backup-manager-preview {
width: 400px; flex-shrink: 0;
border-left: 1px solid var(--border);
background: var(--bg-primary);
display: flex; flex-direction: column;
}
.bm-preview-header {
display: flex; align-items: center; justify-content: space-between;
padding: 10px 14px; border-bottom: 1px solid var(--border);
}
.bm-preview-header h3 { margin: 0; font-size: 0.85rem; }
.bm-preview-content {
flex: 1; overflow: auto; padding: 12px 14px;
font-family: var(--font-mono); font-size: 0.75rem; line-height: 1.55;
white-space: pre-wrap; word-break: break-all;
color: var(--text-secondary); margin: 0;
}
/* Vault header with purge button */
.bm-vault-header {
display: flex; align-items: center; gap: 12px;
padding: 8px 0; border-bottom: 1px solid var(--border); margin-bottom: 8px;
}
.bm-vault-meta { font-size: 0.7rem; color: var(--text-muted); flex: 1; }
.bm-vault-purge {
padding: 3px 10px; border: 1px solid var(--border); border-radius: 4px;
background: transparent; color: var(--danger); cursor: pointer;
font-size: 0.7rem; display: flex; align-items: center; gap: 4px;
transition: all 150ms ease;
}
.bm-vault-purge:hover { background: rgba(239,68,68,0.08); border-color: var(--danger); }
/* Backup item actions */
.bm-backup-actions { display: flex; gap: 2px; opacity: 0; transition: opacity 0.12s; }
.bm-backup-item:hover .bm-backup-actions { opacity: 1; }
.bm-backup-preview,
.bm-backup-restore {
width: 22px; height: 22px; border: none; border-radius: 4px;
background: transparent; color: var(--text-muted); cursor: pointer;
display: flex; align-items: center; justify-content: center;
}
.bm-backup-preview:hover { color: var(--accent); background: rgba(59,130,246,0.1); }
.bm-backup-restore:hover { color: #22c55e; background: rgba(34,197,94,0.1); }
.bm-backup-item.active {
background: color-mix(in srgb, var(--accent) 10%, transparent);
border-radius: 4px;
}
/* ── About Modal ── */
.about-overlay {
position: fixed; inset: 0; z-index: 1000;
background: rgba(0,0,0,0.7); backdrop-filter: blur(6px);
display: none; align-items: center; justify-content: center;
}
.about-overlay.active { display: flex; }
.about-modal {
background: var(--bg-secondary);
border: 1px solid var(--border-md);
border-radius: 16px;
width: 540px; max-width: 94vw; max-height: 90vh;
overflow-y: auto;
position: relative;
box-shadow: 0 20px 60px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.05);
animation: about-in 0.35s ease;
}
@keyframes about-in {
from { opacity: 0; transform: translateY(20px) scale(0.97); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
.about-close {
position: absolute; top: 12px; right: 14px;
background: var(--bg-hover); border: none; color: var(--text-secondary);
width: 30px; height: 30px; border-radius: 8px; font-size: 18px;
cursor: pointer; display: flex; align-items: center; justify-content: center;
transition: background 0.15s, color 0.15s; z-index: 1;
}
.about-close:hover { background: var(--danger-bg); color: var(--danger); }
.about-hero {
text-align: center; padding: 22px 24px 16px;
background: linear-gradient(160deg, var(--accent-bg) 0%, transparent 60%);
border-bottom: 1px solid var(--border);
}
.about-logo { margin-bottom: 8px; display: inline-block; }
.about-title {
font-size: 1.4rem; font-weight: 700; color: var(--text-primary);
letter-spacing: -0.5px; margin-bottom: 4px;
}
.about-tagline {
font-size: 0.8rem; color: var(--text-secondary); line-height: 1.4;
margin-bottom: 8px;
}
.about-version {
display: inline-block; padding: 3px 12px;
background: var(--accent); color: #fff;
font-size: 0.7rem; font-weight: 600; font-family: var(--mono);
border-radius: 20px; letter-spacing: 0.5px;
}
.about-body { padding: 12px 28px 16px; }
.about-stats {
display: flex; gap: 0; justify-content: center;
margin-bottom: 10px;
}
.about-stat {
flex: 1; text-align: center; padding: 8px 8px;
border-right: 1px solid var(--border);
}
.about-stat:last-child { border-right: none; }
.about-stat-value {
display: block; font-size: 1.3rem; font-weight: 700;
color: var(--accent); font-family: var(--mono);
}
.about-stat-label {
font-size: 0.6rem; color: var(--text-muted);
text-transform: uppercase; letter-spacing: 0.6px; margin-top: 1px;
}
.about-stack { margin-bottom: 10px; }
.about-stack h3 {
font-size: 0.65rem; color: var(--text-muted); text-transform: uppercase;
letter-spacing: 0.8px; margin-bottom: 6px;
}
.about-stack-grid {
display: flex; flex-wrap: wrap; gap: 5px;
}
.about-stack-badge {
padding: 2px 8px; font-size: 0.65rem;
background: var(--bg-hover); color: var(--text-secondary);
border: 1px solid var(--border); border-radius: 6px;
font-family: var(--mono);
}
.about-footer { border-top: 1px solid var(--border); padding-top: 10px; }
.about-meta {
display: flex; gap: 16px; font-size: 0.65rem; color: var(--text-muted);
margin-bottom: 6px; flex-wrap: wrap;
}
.about-meta strong { color: var(--text-secondary); font-family: var(--mono); font-size: 0.65rem; }
.about-joke {
font-size: 0.68rem; color: var(--text-muted); font-style: italic;
margin-bottom: 6px; opacity: 0.7;
}
.about-copy {
font-size: 0.62rem; color: var(--text-muted); opacity: 0.5;
}
.about-copy code { font-family: var(--mono); font-size: 0.58rem; }
/* ── PDF Viewer ── */
.pdf-viewer-container {
display: flex;
flex-direction: column;
height: 100%;
}
.pdf-toolbar {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: var(--surface);
border-bottom: 1px solid var(--border);
font-size: 0.85rem;
flex-shrink: 0;
}
.pdf-info {
flex: 1;
color: var(--text-secondary);
}
.pdf-iframe {
flex: 1;
width: 100%;
border: none;
min-height: 70vh;
}
.pdf-body {
display: flex;
flex: 1;
min-height: 0;
}
.pdf-toc {
width: 240px;
flex-shrink: 0;
overflow-y: auto;
padding: 12px;
border-right: 1px solid var(--border);
background: var(--surface2);
font-size: 0.85rem;
}
.pdf-toc h3 {
margin: 0 0 8px 0;
font-size: 0.9rem;
color: var(--text-secondary);
}
.pdf-toc ul {
list-style: none;
padding: 0;
margin: 0;
}
.pdf-toc li {
padding: 2px 0;
}
.pdf-toc a {
color: var(--text);
text-decoration: none;
}
.pdf-toc a:hover {
color: var(--accent);
text-decoration: underline;
}
.toc-page {
color: var(--text-secondary);
font-size: 0.75rem;
margin-left: 4px;
}
/* ── Image Viewer ── */
.image-viewer-body {
display: flex;
align-items: center;
justify-content: center;
min-height: 200px;
background: var(--surface);
padding: 20px;
}
.image-viewer-body img {
border-radius: 4px;
box-shadow: 0 2px 12px rgba(0,0,0,0.15);
}
/* #108-D — dedicated image viewer: zoom, pan, filmstrip, metadata, lightbox */
/* #111 — the viewer owns the whole content box (no page scrolling): the image
is always resized to the available frame and the toolbar/filmstrip stay put. */
.content-area:has(> .image-viewer-container) {
padding: 0;
overflow: hidden;
}
.image-viewer-container {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
outline: none;
}
.image-toolbar {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
background: var(--surface);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.image-toolbar .image-title {
color: var(--text);
font-size: 0.85rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 40%;
}
.image-toolbar-spacer {
flex: 1;
}
.image-zoom-badge {
font-variant-numeric: tabular-nums;
font-size: 0.75rem;
color: var(--text-secondary);
min-width: 46px;
text-align: center;
}
.image-counter {
font-variant-numeric: tabular-nums;
font-size: 0.75rem;
color: var(--text-secondary);
padding: 0 6px;
white-space: nowrap;
}
.image-counter[hidden] {
display: none;
}
.image-viewer-body {
flex: 1;
display: flex;
/* #111 — stretch (not center) so .image-stage is capped to the body height and
the image can actually resolve max-height:100% against a definite frame. */
align-items: stretch;
padding: 0;
min-height: 0;
overflow: hidden;
}
.image-stage {
flex: 1;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
min-height: 0;
padding: 16px;
box-sizing: border-box;
background: var(--surface2);
cursor: grab;
touch-action: none;
}
.image-stage.panning {
cursor: grabbing;
}
.image-main {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
object-fit: contain;
transform-origin: center center;
user-select: none;
-webkit-user-drag: none;
will-change: transform;
}
.image-error {
color: var(--text-secondary);
font-size: 0.9rem;
}
/* #111 — translucent overlay arrows along the frame edges (revealed on hover) */
.image-nav-arrow {
position: absolute;
top: 0;
bottom: 0;
width: clamp(44px, 6vw, 84px);
display: flex;
align-items: center;
justify-content: center;
padding: 0;
border: none;
background: transparent;
color: #fff;
opacity: 0;
cursor: pointer;
z-index: 6;
transition: opacity 160ms ease, background 160ms ease;
}
.image-nav-arrow[hidden] {
display: none;
}
.image-nav-arrow-prev {
left: 0;
}
.image-nav-arrow-next {
right: 0;
}
.image-nav-arrow-prev:hover,
.image-nav-arrow-prev:focus-visible {
background: linear-gradient(to right, rgba(0, 0, 0, 0.42), transparent);
}
.image-nav-arrow-next:hover,
.image-nav-arrow-next:focus-visible {
background: linear-gradient(to left, rgba(0, 0, 0, 0.42), transparent);
}
.image-stage:hover .image-nav-arrow {
opacity: 0.4;
}
.image-stage .image-nav-arrow:hover,
.image-stage .image-nav-arrow:focus-visible {
opacity: 1;
outline: none;
}
.image-nav-arrow .icon {
filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.85));
}
@media (hover: none) {
.image-nav-arrow {
opacity: 0.55;
}
}
/* #112 — filmstrip wrapper so the scroll arrows stay fixed over the film */
.image-nav {
position: relative;
flex-shrink: 0;
background: var(--surface);
border-top: 1px solid var(--border);
}
.image-nav[hidden] {
display: none;
}
.image-nav-strip {
display: flex;
gap: 6px;
padding: 8px 40px;
overflow-x: auto;
scroll-behavior: smooth;
scrollbar-width: thin;
flex-shrink: 0;
}
.image-nav-strip[hidden] {
display: none;
}
/* Translucent arrows that scroll the film left/right (revealed on hover). */
.image-strip-arrow {
position: absolute;
top: 0;
bottom: 0;
width: 34px;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
border: none;
color: var(--text-primary);
opacity: 0;
cursor: pointer;
z-index: 2;
transition: opacity 160ms ease;
}
.image-strip-arrow-prev {
left: 0;
background: linear-gradient(to right, var(--surface) 55%, transparent);
}
.image-strip-arrow-next {
right: 0;
background: linear-gradient(to left, var(--surface) 55%, transparent);
}
.image-nav:hover .image-strip-arrow {
opacity: 0.6;
}
.image-strip-arrow:hover,
.image-strip-arrow:focus-visible {
opacity: 1;
outline: none;
}
@media (hover: none) {
.image-strip-arrow {
opacity: 0.55;
}
}
.image-thumb {
width: 72px;
height: 72px;
object-fit: cover;
border-radius: 4px;
border: 2px solid transparent;
cursor: pointer;
opacity: 0.65;
flex-shrink: 0;
}
.image-thumb:hover {
opacity: 1;
}
.image-thumb.active {
border-color: var(--accent);
opacity: 1;
}
.image-meta-panel {
width: 280px;
max-width: 40%;
overflow-y: auto;
padding: 10px 16px;
background: var(--surface);
border-left: 1px solid var(--border);
font-size: 0.8rem;
color: var(--text-secondary);
flex-shrink: 0;
}
.image-meta-panel[hidden] {
display: none;
}
.image-meta-panel dl {
display: grid;
grid-template-columns: auto 1fr;
gap: 4px 12px;
margin: 0;
}
.image-meta-panel dt {
color: var(--text-secondary);
}
.image-meta-panel dd {
margin: 0;
color: var(--text);
overflow-wrap: anywhere;
}
.image-viewer-container.lightbox {
position: fixed;
inset: 0;
z-index: 2000;
background: rgba(0, 0, 0, 0.9);
}
.image-viewer-container.lightbox .image-nav,
.image-viewer-container.lightbox .image-nav-strip {
display: none;
}
/* ── Audio / Video viewers (roadmap #109) ── */
.audio-viewer-container,
.video-viewer-container {
display: flex;
flex-direction: column;
height: 100%;
}
.media-toolbar {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
background: var(--surface);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.media-toolbar .media-title {
color: var(--text);
font-size: 0.85rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 40%;
}
.media-toolbar-spacer {
flex: 1;
}
.media-duration-badge {
font-variant-numeric: tabular-nums;
font-size: 0.75rem;
color: var(--text-secondary);
min-width: 46px;
text-align: center;
}
.media-meta {
font-size: 0.75rem;
color: var(--text-secondary);
}
.audio-stage {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
padding: 32px 24px;
min-height: 50vh;
background: var(--surface2);
}
.audio-artwork {
display: flex;
align-items: center;
justify-content: center;
width: 140px;
height: 140px;
border-radius: 12px;
background: var(--surface);
border: 1px solid var(--border);
color: var(--accent);
}
.audio-player {
width: min(560px, 100%);
}
.video-stage {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
background: #000;
overflow: hidden;
min-height: 60vh;
}
.video-player {
max-width: 100%;
max-height: calc(100vh - 180px);
object-fit: contain;
}
.media-fallback-actions {
display: flex;
gap: 8px;
margin-top: 12px;
}
/* ── Now Playing — persistent media dock (roadmap #110) ── */
.np-inline-slot {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
.np-inline-slot .np-media--audio {
width: min(560px, 100%);
}
.np-media--video {
max-width: 100%;
max-height: calc(100vh - 180px);
}
.np-host {
position: fixed;
inset: 0;
z-index: 950;
pointer-events: none;
}
.np-dock {
pointer-events: auto;
}
.np-ctrl {
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
padding: 0;
border: none;
border-radius: 50%;
background: transparent;
color: var(--text);
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease;
}
.np-ctrl:hover {
background: color-mix(in srgb, var(--accent) 18%, transparent);
color: var(--accent);
}
.np-ctrl:disabled {
opacity: 0.35;
cursor: default;
}
.np-ctrl:disabled:hover {
background: transparent;
color: var(--text);
}
.np-dock--audio {
position: fixed;
left: 50%;
bottom: 20px;
transform: translateX(-50%);
display: flex;
align-items: center;
gap: 10px;
width: min(720px, calc(100vw - 32px));
padding: 8px 12px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 14px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
backdrop-filter: blur(12px);
overflow: hidden;
}
.np-dock--audio .np-media {
display: none;
}
.np-dock-art {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
border: 1px solid var(--border);
border-radius: 10px;
background: var(--surface2);
color: var(--accent);
cursor: pointer;
}
.np-dock-info {
flex: 1 1 120px;
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
cursor: pointer;
}
.np-dock-title {
color: var(--text);
font-size: 0.85rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.np-dock-sub {
color: var(--text-secondary);
font-size: 0.72rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.np-dock-controls {
flex: 0 0 auto;
display: flex;
align-items: center;
gap: 2px;
}
.np-dock-progress {
flex: 1 1 160px;
min-width: 0;
display: flex;
align-items: center;
gap: 8px;
}
.np-time {
color: var(--text-secondary);
font-size: 0.7rem;
font-variant-numeric: tabular-nums;
min-width: 34px;
text-align: center;
}
.np-seek {
flex: 1;
-webkit-appearance: none;
appearance: none;
height: 4px;
border-radius: 2px;
background: var(--border);
cursor: pointer;
}
.np-seek::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--accent);
}
.np-seek::-moz-range-thumb {
width: 12px;
height: 12px;
border: none;
border-radius: 50%;
background: var(--accent);
}
.np-dock-actions {
flex: 0 0 auto;
display: flex;
align-items: center;
gap: 2px;
}
.np-volume {
display: flex;
align-items: center;
gap: 4px;
color: var(--text-secondary);
padding: 0 4px;
}
.np-volume-range {
width: 70px;
-webkit-appearance: none;
appearance: none;
height: 4px;
border-radius: 2px;
background: var(--border);
cursor: pointer;
}
.np-volume-range::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 11px;
height: 11px;
border-radius: 50%;
background: var(--accent);
}
.np-volume-range::-moz-range-thumb {
width: 11px;
height: 11px;
border: none;
border-radius: 50%;
background: var(--accent);
}
/* Video dock — floating, draggable, resizable mini-window */
.np-dock--video {
position: fixed;
background: #000;
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 14px 40px rgba(0, 0, 0, 0.5);
}
.np-dock-video-frame {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
}
.np-dock-video-slot {
flex: 1;
display: flex;
min-height: 0;
background: #000;
overflow: hidden;
}
.np-dock-video-slot .np-media--video {
width: 100%;
height: 100%;
object-fit: contain;
max-height: none;
}
.np-dock-video-bar {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 6px;
background: rgba(0, 0, 0, 0.62);
}
.np-dock-video-bar .np-ctrl,
.np-dock-video-bar .np-time {
color: #f5f5f5;
}
.np-dock-video-bar .np-seek {
background: rgba(255, 255, 255, 0.28);
}
.np-dock-video-bar .np-ctrl:hover {
background: rgba(255, 255, 255, 0.16);
color: #fff;
}
.np-video-grip {
display: inline-flex;
align-items: center;
color: rgba(255, 255, 255, 0.7);
cursor: grab;
touch-action: none;
}
.np-video-grip:active {
cursor: grabbing;
}
.np-video-resize {
position: absolute;
right: 0;
bottom: 0;
width: 18px;
height: 18px;
cursor: nwse-resize;
touch-action: none;
}
.np-video-resize::after {
content: "";
position: absolute;
right: 3px;
bottom: 3px;
width: 9px;
height: 9px;
border-right: 2px solid rgba(255, 255, 255, 0.55);
border-bottom: 2px solid rgba(255, 255, 255, 0.55);
}
.np-dock--error .np-dock-error-msg {
color: #fff;
font-size: 0.8rem;
padding: 24px 16px;
text-align: center;
}
/* Expanded audio panel (bottom sheet on mobile) */
.np-expanded {
position: fixed;
inset: 0;
z-index: 960;
pointer-events: auto;
}
.np-expanded[hidden] {
display: none;
}
.np-expanded-backdrop {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.35);
}
.np-exp-card {
position: absolute;
left: 50%;
bottom: 96px;
transform: translateX(-50%);
width: min(460px, calc(100vw - 32px));
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
padding: 22px 20px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 18px;
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.5);
}
.np-exp-art {
display: flex;
align-items: center;
justify-content: center;
width: 120px;
height: 120px;
border-radius: 14px;
background: var(--surface2);
border: 1px solid var(--border);
color: var(--accent);
}
.np-exp-title {
color: var(--text);
font-size: 1rem;
text-align: center;
overflow-wrap: anywhere;
}
.np-exp-sub {
color: var(--text-secondary);
font-size: 0.78rem;
}
.np-exp-seek {
width: 100%;
}
.np-exp-times {
width: 100%;
display: flex;
justify-content: space-between;
}
.np-exp-controls {
display: flex;
align-items: center;
gap: 14px;
}
.np-exp-controls .np-ctrl {
width: 44px;
height: 44px;
}
.np-exp-play {
background: var(--accent);
color: #fff;
}
.np-exp-play:hover {
background: var(--accent);
color: #fff;
filter: brightness(1.08);
}
.np-exp-extra {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
justify-content: center;
}
.np-rate {
background: var(--surface2);
color: var(--text);
border: 1px solid var(--border);
border-radius: 8px;
padding: 4px 6px;
font-size: 0.75rem;
}
/* Mid-size screens: drop the volume slider before the row gets cramped. */
@media (max-width: 1100px) {
.np-dock--audio .np-volume {
display: none;
}
}
@media (max-width: 768px) {
.np-dock--audio {
left: 8px;
right: 8px;
bottom: calc(64px + env(safe-area-inset-bottom, 0px) + 8px);
transform: none;
width: auto;
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto auto;
grid-template-areas:
"progress progress progress progress"
"art info controls actions";
align-items: center;
gap: 6px 8px;
padding: 8px 10px;
border-radius: 12px;
}
.np-dock--audio .np-dock-art {
grid-area: art;
width: 38px;
height: 38px;
}
.np-dock--audio .np-dock-info {
grid-area: info;
}
.np-dock--audio .np-dock-controls {
grid-area: controls;
}
.np-dock--audio .np-dock-progress {
grid-area: progress;
width: 100%;
min-width: 0;
}
.np-dock--audio .np-dock-actions {
grid-area: actions;
}
/* Compact mobile: keep play / return / close; expand via the artwork. */
.np-dock--audio [data-np="prev"],
.np-dock--audio [data-np="next"],
.np-dock--audio [data-np="expand"] {
display: none;
}
.np-dock--video {
left: 8px !important;
right: 8px;
top: auto !important;
bottom: calc(64px + env(safe-area-inset-bottom, 0px) + 8px) !important;
width: auto !important;
height: 200px !important;
border-radius: 12px;
}
.np-video-resize {
display: none;
}
.np-exp-card {
bottom: calc(64px + env(safe-area-inset-bottom, 0px) + 12px);
}
body.np-active .content-area {
/* Toolbar clearance is carried by .main-body (BUG-073): only the dock
zone (76px above the toolbar) remains here — same total as before. */
padding-bottom: 76px;
}
}
@media (prefers-reduced-motion: reduce) {
.np-ctrl,
.np-dock,
.np-exp-card {
transition: none;
}
}
/* ── Text / CSV Viewer ── */
.text-viewer-container {
display: flex;
flex-direction: column;
height: 100%;
}
.file-toolbar {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: var(--surface);
border-bottom: 1px solid var(--border);
font-size: 0.85rem;
flex-shrink: 0;
}
.file-info {
flex: 1;
color: var(--text-secondary);
}
.text-viewer-body {
flex: 1;
overflow: auto;
padding: 16px;
background: var(--surface2);
}
.text-viewer-body pre {
margin: 0;
font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
font-size: 0.85rem;
line-height: 1.5;
white-space: pre-wrap;
}
.text-viewer-body code {
color: var(--text);
}
/* ── CSV Table ── */
.csv-table-wrapper {
overflow: auto;
max-height: 70vh;
}
.csv-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
}
.csv-table th {
background: var(--surface);
color: var(--text-secondary);
font-weight: 600;
padding: 8px 12px;
text-align: left;
border-bottom: 2px solid var(--border);
position: sticky;
top: 0;
}
.csv-table td {
padding: 6px 12px;
border-bottom: 1px solid var(--border-light, var(--border));
}
.csv-table tr:hover td {
background: var(--surface);
}
/* ── XLSX Viewer ── */
.xlsx-toolbar {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
flex-wrap: wrap;
}
.xlsx-toolbar-actions {
margin-left: auto;
display: flex;
gap: 8px;
}
.xlsx-tabs {
display: flex;
gap: 4px;
flex-wrap: wrap;
}
.xlsx-tab {
border: 1px solid var(--border);
background: var(--surface);
color: var(--text-secondary);
border-radius: 4px;
padding: 4px 10px;
font-size: 0.8rem;
cursor: pointer;
}
.xlsx-tab.active {
background: var(--accent, #4a90d9);
border-color: var(--accent, #4a90d9);
color: #fff;
}
.xlsx-table th.xlsx-corner,
.xlsx-table th.xlsx-rownum {
background: var(--surface);
color: var(--text-secondary);
font-weight: 400;
text-align: right;
padding: 6px 8px;
border-bottom: 2px solid var(--border);
border-right: 1px solid var(--border-light, var(--border));
position: sticky;
left: 0;
z-index: 1;
}
.xlsx-table th.xlsx-corner {
left: 0;
top: 0;
z-index: 2;
}
.xlsx-table td[contenteditable] {
cursor: text;
min-width: 40px;
white-space: pre-wrap;
}
.xlsx-table td[contenteditable]:focus {
outline: 2px solid var(--accent, #4a90d9);
outline-offset: -2px;
}
.xlsx-table td.xlsx-dirty {
background: rgba(255, 196, 0, 0.18);
}
/* #153 A12 — last result Excel computed, shown under a formula cell.
Discreet by design: the formula is what the user edits, the cached value is
context (stale until Excel recalculates). */
.xlsx-cached {
display: block;
margin-top: 2px;
padding-left: 6px;
border-left: 2px solid var(--border, #d0d7de);
color: var(--text-muted);
font-size: 0.85em;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
/* #153 A1/A4 — lossy-save warning + formula toggle */
.xlsx-warning {
display: flex;
align-items: flex-start;
gap: 8px;
padding: 8px 10px;
margin-bottom: 8px;
border: 1px solid var(--warning, #e0a800);
border-left-width: 3px;
border-radius: 4px;
background: var(--surface);
color: var(--text-secondary);
font-size: 0.82rem;
line-height: 1.45;
}
.xlsx-warning-icon {
width: 16px;
height: 16px;
flex: 0 0 auto;
margin-top: 1px;
color: var(--warning, #e0a800);
}
.xlsx-warning-body {
display: flex;
flex-direction: column;
gap: 3px;
min-width: 0;
}
.xlsx-warning-body strong {
color: var(--text-primary);
font-weight: 600;
}
.xlsx-warning-list {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.xlsx-warning-tag {
padding: 1px 6px;
border: 1px solid var(--border);
border-radius: 10px;
background: var(--bg-secondary);
color: var(--text-secondary);
font-size: 0.75rem;
white-space: nowrap;
}
.xlsx-warning-hint {
color: var(--text-secondary);
opacity: 0.85;
}
.xlsx-formula-toggle {
font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
font-weight: 600;
}
.xlsx-formula-toggle.active {
background: var(--accent, #4a90d9);
border-color: var(--accent, #4a90d9);
color: #fff;
}
/* ── JSON Viewer ── */
.json-viewer {
font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
font-size: 0.85rem;
line-height: 1.5;
padding: 16px;
background: var(--surface2);
border-radius: 6px;
overflow: auto;
max-height: 70vh;
}
/* ── PaneManager — Split View ── */
.pane-grid {
display: grid;
height: 100%;
overflow: hidden;
}
.pane-container {
display: flex;
flex-direction: column;
overflow: hidden;
position: relative;
}
.pane-container.pane-active {
outline: 2px solid var(--accent);
outline-offset: -2px;
z-index: 1;
}
.pane-tab-bar { flex-shrink: 0; }
.pane-content { flex: 1; overflow-y: auto; }
.pane-resize-handle {
background: var(--border);
transition: background 150ms;
min-width: 4px;
min-height: 4px;
z-index: 2;
}
.pane-resize-handle:hover {
background: var(--accent);
}
.code-block-wrapper:hover .copy-code-btn {
opacity: 1;
}
.copy-code-btn {
position: absolute;
top: 8px;
right: 8px;
display: flex;
align-items: center;
gap: 4px;
padding: 4px 10px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text-secondary);
font-size: 11px;
font-family: var(--mono);
cursor: pointer;
opacity: 0;
transition: opacity 150ms ease, background 150ms ease, color 150ms ease;
z-index: 5;
}
.copy-code-btn:hover {
background: var(--accent);
color: #fff;
border-color: var(--accent);
}
.copy-code-btn.copied {
background: var(--accent-green);
color: #fff;
border-color: var(--accent-green);
}
/* Mobile : toujours visible (pas de hover sur tactile) */
@media (max-width: 768px) {
.copy-code-btn {
opacity: 1;
padding: 2px 8px;
font-size: 10px;
top: 4px;
right: 4px;
}
}
/* ── MFA (Multi-Factor Authentication) ────────────────────────────────── */
.mfa-challenge {
margin-top: 20px;
padding: 24px;
border-radius: 12px;
background: var(--surface, #1a1a2e);
border: 1px solid var(--border, #333);
text-align: center;
}
.mfa-challenge .mfa-icon { font-size: 48px; margin-bottom: 12px; }
.mfa-challenge h3 { margin: 0 0 8px; color: var(--text, #fff); }
.mfa-challenge p { color: var(--muted, #999); margin: 0 0 16px; }
.mfa-code-input {
width: 180px;
font-size: 28px;
text-align: center;
letter-spacing: 12px;
padding: 12px;
border: 2px solid var(--border, #444);
border-radius: 8px;
background: var(--bg, #0d0d1a);
color: var(--text, #fff);
font-family: monospace;
outline: none;
}
.mfa-code-input:focus { border-color: var(--accent, #7C3AED); }
.mfa-code-input-group { display: flex; gap: 8px; justify-content: center; align-items: center; margin-bottom: 12px; }
.mfa-code-input-group span { color: var(--muted, #999); font-size: 24px; }
.mfa-link-btn {
background: none; border: none; color: var(--accent, #7C3AED);
cursor: pointer; font-size: 13px; text-decoration: underline;
}
.mfa-link-btn:hover { opacity: 0.8; }
.mfa-error { color: #e74c3c; font-size: 13px; margin-top: 8px; }
/* MFA Settings (Security tab) */
.mfa-status-section { padding: 16px 0; }
.mfa-status-row { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.mfa-badge {
display: inline-flex; align-items: center; gap: 6px;
padding: 4px 12px; border-radius: 20px; font-size: 13px; font-weight: 600;
}
.mfa-badge-on { background: #1a3a2a; color: #4ade80; }
.mfa-badge-off { background: #3a2a1a; color: #f59e0b; }
.mfa-status-label { color: var(--text, #fff); font-weight: 500; }
/* MFA Setup card */
.mfa-setup-card {
padding: 20px; border-radius: 10px;
background: var(--surface2, #1e1e3a); border: 1px solid var(--border, #333);
}
.mfa-setup-card h4 { margin: 0 0 12px; color: var(--text, #fff); }
.mfa-qr-container { text-align: center; margin: 16px 0; }
.mfa-qr-code img, .mfa-qr-code canvas { max-width: 200px; border-radius: 8px; }
.mfa-secret-details { margin-top: 12px; }
.mfa-secret-code {
font-family: monospace; font-size: 14px; padding: 8px 12px;
background: var(--bg, #0d0d1a); border-radius: 6px;
color: var(--accent, #7C3AED); cursor: pointer; user-select: all;
display: inline-block;
}
.mfa-info-text { color: var(--muted, #999); font-size: 13px; margin: 8px 0; }
.mfa-subtitle { color: var(--muted, #999); font-size: 13px; margin: 0 0 16px; }
.mfa-verify-section { display: flex; gap: 8px; align-items: center; margin-top: 12px; }
.mfa-actions { margin-top: 16px; }
/* MFA Recovery codes display */
.mfa-recovery-card {
padding: 20px; border-radius: 10px;
background: var(--surface2, #1e1e3a); border: 1px solid var(--border, #333);
margin-top: 16px;
}
.mfa-recovery-card h4 { margin: 0 0 8px; color: var(--text, #fff); }
.mfa-recovery-list {
display: grid; grid-template-columns: 1fr 1fr; gap: 6px 24px;
margin: 12px 0; list-style: none; padding: 0;
}
.mfa-recovery-code {
font-family: monospace; font-size: 14px; padding: 4px 8px;
background: var(--bg, #0d0d1a); border-radius: 4px;
color: var(--text, #fff); letter-spacing: 1px;
}
.mfa-recovery-actions { display: flex; gap: 8px; margin-top: 12px; }
/* WebAuthn security keys (ROADMAP #64) */
.webauthn-settings { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border, #333); }
.webauthn-title { margin: 0 0 6px; color: var(--text, #fff); font-size: 0.95rem; }
.webauthn-key-list { list-style: none; margin: 10px 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.webauthn-key-item {
display: flex; align-items: center; gap: 10px; padding: 8px 10px;
background: var(--surface2, #1a1a2e); border-radius: 6px;
}
.webauthn-key-label { flex: 1; font-size: 0.9rem; color: var(--text, #fff); }
.webauthn-key-meta { font-size: 0.75rem; color: var(--text-muted, #888); }
.config-btn-sm { padding: 4px 10px; font-size: 0.78rem; }
/* MFA Disable card */
.mfa-disable-card {
padding: 16px; border-radius: 10px;
background: var(--surface2, #1e1e3a); border: 1px solid #e74c3c33;
margin-top: 16px;
}
.mfa-disable-card h4 { margin: 0 0 8px; color: #e74c3c; }
.mfa-disable-actions { display: flex; gap: 8px; margin-top: 12px; }
.mfa-warning {
color: #f59e0b; font-size: 13px; padding: 8px 12px;
background: #3a2a1a; border-radius: 6px; margin-top: 8px;
}
/* ── BooksLM Panel ──────────────────────────────────── */
.bookslm-panel { position: fixed; right: 0; top: 0; bottom: 0; width: 450px;
background: var(--bg-primary); border-left: 1px solid var(--border);
z-index: 100; display: flex; flex-direction: column;
transform: translateX(100%); transition: transform 300ms ease-out;
box-shadow: -4px 0 20px rgba(0,0,0,0.3);
color: var(--text-primary); }
.bookslm-panel.open { transform: translateX(0); }
/* The `.hidden` class is applied by the header toggle button to collapse the
panel while keeping it mounted (so the toggle icon stays usable). When
hidden, the panel is slid fully off-screen and the open animation no
longer overrides the translateX. */
.bookslm-panel.open.hidden { transform: translateX(100%); }
.bookslm-btn-toggle {
display: flex; align-items: center; justify-content: center;
background: none; border: none; cursor: pointer;
color: var(--text-secondary); padding: 4px;
border-radius: 4px; flex-shrink: 0;
transition: color 200ms ease, background 200ms ease;
}
.bookslm-btn-toggle:hover { color: var(--accent); background: var(--surface2); }
.bookslm-header { display: flex; align-items: center; gap: 8px;
padding: 10px 12px; border-bottom: 1px solid var(--border); }
.bookslm-header .bookslm-context-icon { display: flex; color: var(--accent); flex-shrink: 0; }
.bookslm-header-titles { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.bookslm-header-titles .bookslm-title { font-size: 13px; font-weight: 600;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bookslm-header-titles .bookslm-subtitle { font-size: 11px; color: var(--text-secondary);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bookslm-header-actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }
.bookslm-header button { background: none; border: none; cursor: pointer;
color: var(--text-secondary); padding: 5px; border-radius: 6px; display: flex; align-items: center; }
.bookslm-header button:hover { background: var(--surface2); color: var(--text-primary); }
/* Provider/model picker on its own row so the header actions never get hidden. */
.bookslm-toolbar { display: flex; align-items: center; justify-content: flex-end; gap: 8px;
flex-wrap: wrap; padding: 8px 12px; border-bottom: 1px solid var(--border);
background: var(--bg-secondary); }
.bookslm-toolbar-label { font-size: 11px; color: var(--text-secondary);
text-transform: uppercase; letter-spacing: .04em; flex-shrink: 0; }
.bookslm-toolbar .ai-picker { margin-left: 0; padding-left: 0; border-left: none;
flex-wrap: wrap; row-gap: 4px; }
.bookslm-toolbar .ai-picker select { max-width: 220px; }
/* `!important` is required: the panel width is also written inline by the
resize handle / persisted width, and an inline style would otherwise win. */
.bookslm-panel.fullscreen { width: 100vw !important; }
.bookslm-status { padding: 6px 16px; font-size: 12px; color: var(--text-secondary);
border-bottom: 1px solid var(--border); display: flex; gap: 12px; align-items: center; }
.bookslm-status .bookslm-status-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bookslm-status .bookslm-status-error { color: #f87171; }
.bookslm-status .bookslm-context-bar { flex: 1; height: 4px; border-radius: 2px;
background: var(--surface2); overflow: hidden; }
.bookslm-status .bookslm-context-fill { height: 100%; border-radius: 2px; background: var(--accent); transition: width 0.3s; }
/* Assistant activity — no loading bar above the composer anymore: in agent
mode the animated dots sit in the steps header (« ●●● 3 étapes ▶ »), in
plain chat they sit in the pending answer. Pure CSS, reduced-motion aware. */
.bookslm-dots { display: inline-flex; align-items: center; gap: 2px; }
.bookslm-dots i { width: 4px; height: 4px; border-radius: 50%; background: currentColor;
opacity: 0.25; animation: bookslm-dot 1.2s ease-in-out infinite; }
.bookslm-dots i:nth-child(2) { animation-delay: 0.15s; }
.bookslm-dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes bookslm-dot {
0%, 60%, 100% { opacity: 0.25; transform: translateY(0); }
30% { opacity: 1; transform: translateY(-2px); }
}
.bookslm-pending { display: flex; align-items: center; height: 20px; color: var(--text-secondary); }
/* Notion-style AI thread: only this zone scrolls; entries stack vertically
with generous spacing. The latest user post is anchored to the top of the
visible area on send: the post is anchored flush at the top (block:start,
and the bottom padding is grown so a short answer can still roll the post
all the way up). */
.bookslm-messages { flex: 1; overflow-y: auto; padding: 20px 16px; display: flex;
flex-direction: column; gap: 24px; overflow-anchor: none; }
.bookslm-msg { display: flex; flex-direction: column; gap: 4px; }
/* The user bubble is capped against the *thread* width, not against a
shrink-to-fit wrapper: capping both would compound (80% × 85% ≈ 68%) and
produced very short lines. Wrapper stretches, bubble carries the cap. */
.bookslm-msg.user { align-items: flex-end; }
.bookslm-msg.assistant { align-items: stretch; width: 100%; }
.bookslm-msg-meta { font-size: 11px; color: var(--text-secondary); opacity: 0.75;
padding: 0 2px; align-self: flex-start; user-select: none; }
/* Hover-revealed action bar (Copier / Ajouter). */
.bookslm-msg-actions { display: flex; gap: 6px; margin-top: 4px; opacity: 0;
transition: opacity 0.15s; }
.bookslm-msg.user .bookslm-msg-actions { justify-content: flex-end; }
.bookslm-msg:hover .bookslm-msg-actions,
.bookslm-msg-actions:focus-within { opacity: 1; }
.bookslm-msg-action { display: inline-flex; align-items: center; gap: 5px;
font-size: 11px; padding: 3px 9px; border-radius: 6px; border: 1px solid transparent;
background: transparent; color: var(--text-secondary); cursor: pointer; }
.bookslm-msg-action:hover { background: var(--surface2); color: var(--text-primary);
border-color: var(--border); }
.bookslm-bubble { max-width: 85%; padding: 10px 14px; border-radius: 18px; font-size: 14px; line-height: 1.5; word-wrap: break-word; }
.bookslm-bubble.user { align-self: flex-end; max-width: 90%; min-width: 0;
background: var(--surface2); color: var(--text-primary); border-bottom-right-radius: 6px; }
.bookslm-bubble.assistant { align-self: flex-start; background: transparent; padding: 0; width: 100%; max-width: 100%; color: var(--text-primary); }
.bookslm-bubble.assistant code { background: rgba(0,0,0,0.2); padding: 1px 4px; border-radius: 3px; font-size: 0.9em; }
.bookslm-bubble.assistant pre { background: rgba(0,0,0,0.3); padding: 10px; border-radius: 6px; overflow-x: auto; margin: 8px 0; }
/* #102 — per-code-block “Ajouter”: a discreet button in the block's corner,
revealed on hover/focus, that inserts only this section. */
.bookslm-code-block { position: relative; }
.bookslm-code-block .bookslm-code-insert { position: absolute; top: 6px; right: 6px;
z-index: 1; background: var(--surface2); border-color: var(--border); opacity: 0;
transition: opacity 0.15s; }
.bookslm-code-block:hover .bookslm-code-insert,
.bookslm-code-block:focus-within .bookslm-code-insert { opacity: 1; }
.bookslm-sources { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; }
.bookslm-source-badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px;
background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
font-size: 11px; color: var(--accent); cursor: pointer; }
.bookslm-source-badge:hover { background: var(--surface2); }
.bookslm-input-area { display: flex; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--border); align-items: flex-end; }
.bookslm-input-area textarea { flex: 1; resize: none; min-height: 36px; max-height: 120px;
padding: 8px 12px; border-radius: 8px; border: 1px solid var(--border);
background: var(--bg-primary); color: var(--text-primary); font-size: 14px; font-family: inherit; }
.bookslm-input-area textarea:focus { border-color: var(--accent); outline: none; }
.bookslm-input-area button { padding: 8px 16px; border-radius: 8px; border: none;
background: var(--accent); color: #fff; cursor: pointer; font-size: 14px; }
.bookslm-input-area button.bookslm-btn-send { width: 40px; height: 40px; padding: 0;
border-radius: 50%; font-size: 16px; line-height: 1; display: flex; align-items: center;
justify-content: center; flex-shrink: 0; }
.bookslm-input-area button:hover { opacity: 0.9; }
.bookslm-input-area button:disabled { opacity: 0.5; cursor: not-allowed; }
/* BUG-077 — the send button doubles as a Stop control while streaming. */
.bookslm-input-area button.bookslm-btn-send.is-stopping { background: var(--danger); }
.bookslm-input-area button.bookslm-btn-send.is-stopping:hover { opacity: 1; filter: brightness(1.08); }
.bookslm-input-hint { padding: 0 16px 10px; font-size: 10px; color: var(--text-secondary);
text-align: right; border-top: none; }
/* Action cards proposed by the General assistant (file/dir creation). */
.bookslm-actions { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.bookslm-action { display: flex; align-items: center; gap: 8px; padding: 8px 10px;
border: 1px solid var(--border); border-radius: 8px; background: var(--bg-primary); }
.bookslm-action.done { opacity: 0.65; }
.bookslm-action-meta { flex: 1; display: flex; align-items: center; gap: 6px; font-size: 12px;
color: var(--text-primary); word-break: break-word; }
.bookslm-action-icon { flex-shrink: 0; }
.bookslm-action-apply { padding: 5px 12px; border-radius: 6px; border: none;
background: var(--accent); color: #fff; cursor: pointer; font-size: 12px; flex-shrink: 0; }
.bookslm-action-apply:disabled { opacity: 0.6; cursor: default; }
.bookslm-action-apply:not(:disabled):hover { filter: brightness(1.08); }
/* Agent-mode toggle in the header. */
.bookslm-header button.bookslm-btn-agent.active { color: var(--accent); background: var(--surface2); }
/* Tool-call trace shown above an assistant answer (agent mode).
The header is the live indicator (« ●●● 3 étapes ▶ »); expanding it reveals
the chronological steps, thinking notes as « Réflexion » sub-sections and
web sources as clickable links. */
.bookslm-tool-trace { margin: 0 0 8px; }
.bookslm-tool-trace > summary { display: inline-flex; align-items: center; gap: 6px;
font-size: 11px; color: var(--text-secondary); cursor: pointer; user-select: none;
list-style: none; padding: 2px 0; }
.bookslm-tool-trace > summary::-webkit-details-marker { display: none; }
.bookslm-tool-trace > summary:hover { color: var(--text-primary); }
.bookslm-tool-trace[open] > summary { margin-bottom: 4px; }
.bookslm-steps-dots { color: var(--accent); }
/* BUG-074 — preview of the first action next to the step counter. */
.bookslm-steps-title { color: var(--text-secondary); max-width: 45vw; overflow: hidden;
text-overflow: ellipsis; white-space: nowrap; }
.bookslm-steps-body { display: flex; flex-direction: column; gap: 3px; }
.bookslm-chevron { font-size: 8px; line-height: 1; opacity: 0.7; }
.bookslm-chevron::before { content: '▶'; }
details[open] > summary .bookslm-chevron::before { content: '▼'; }
.bookslm-thought { margin-left: 12px; }
.bookslm-thought > summary { display: inline-flex; align-items: center; gap: 5px;
font-size: 11px; color: var(--text-secondary); cursor: pointer; user-select: none;
list-style: none; }
.bookslm-thought > summary::-webkit-details-marker { display: none; }
.bookslm-thought > summary:hover { color: var(--text-primary); }
.bookslm-thought-text { margin: 4px 0 6px 6px; padding-left: 9px;
border-left: 2px solid var(--border); font-size: 11.5px; line-height: 1.5;
color: var(--text-secondary); font-style: italic; white-space: pre-wrap;
word-break: break-word; }
.bookslm-web-sources { margin-left: 12px; }
.bookslm-web-sources > summary { display: inline-flex; align-items: center; gap: 5px;
font-size: 11px; color: var(--text-secondary); cursor: pointer; user-select: none;
list-style: none; }
.bookslm-web-sources > summary::-webkit-details-marker { display: none; }
.bookslm-web-sources > summary:hover { color: var(--text-primary); }
.bookslm-web-sources-list { list-style: none; margin: 4px 0 6px 6px; padding: 0;
display: flex; flex-direction: column; gap: 3px; border-left: 2px solid var(--border);
padding-left: 9px; }
.bookslm-web-sources-list a { font-size: 11px; color: var(--accent);
text-decoration: none; word-break: break-word; }
.bookslm-web-sources-list a::before { content: '↗ '; opacity: 0.7; }
.bookslm-web-sources-list a:hover { text-decoration: underline; }
.bookslm-tool-line { font-size: 11px; color: var(--text-secondary); padding-left: 12px; }
.bookslm-tool-line.failed { color: #f87171; }
@media (prefers-reduced-motion: reduce) {
.bookslm-dots i { animation: none; opacity: 0.6; }
}
/* Mutation confirmation card (two-step propose/apply). */
.bookslm-confirm { flex-wrap: wrap; }
.bookslm-confirm-diff { flex-basis: 100%; width: 100%; margin-top: 4px; }
/* BUG-075 — one row per action when the run batches several mutations. */
.bookslm-confirm-actions { flex-basis: 100%; width: 100%; display: flex;
flex-direction: column; gap: 4px; margin-top: 4px; }
.bookslm-confirm-action > summary { display: inline-flex; align-items: center; gap: 5px;
font-size: 12px; color: var(--text-secondary); cursor: pointer; list-style: none;
word-break: break-word; }
.bookslm-confirm-action > summary::-webkit-details-marker { display: none; }
.bookslm-confirm-action > summary:hover { color: var(--text-primary); }
.bookslm-confirm-action[open] > summary { color: var(--text-primary); }
.bookslm-diff-title { font-size: 11px; color: var(--text-secondary); margin-bottom: 4px; }
.bookslm-diff { background: rgba(0,0,0,0.25); border-radius: 6px; padding: 8px;
overflow-x: auto; font-size: 12px; line-height: 1.4; max-height: 240px; margin: 0; }
.bookslm-diff-add { color: #4ade80; display: block; }
.bookslm-diff-del { color: #f87171; display: block; }
.bookslm-diff-ctx { color: var(--text-secondary); display: block; }
/* #106 — Actions instantanées contextuelles de l'assistant. */
.bookslm-suggestions { display: flex; flex-direction: column; gap: 6px; padding: 8px 16px 0; }
.bookslm-suggestions.hidden { display: none; }
.bookslm-qa-badge { flex-shrink: 0; font-size: 10px; text-transform: uppercase;
letter-spacing: 0.5px; font-weight: 600; color: var(--accent-text, var(--accent));
background: var(--accent-bg);
border: 1px solid var(--border); border-radius: 999px; padding: 2px 8px; }
.bookslm-qa-badge.hidden { display: none; }
.bookslm-qa-hint { margin: 0 0 2px; font-size: 12px; color: var(--text-secondary); line-height: 1.45; }
.bookslm-qa-head { display: flex; align-items: center; justify-content: space-between; padding: 0 2px; }
.bookslm-qa-label { font-size: 10px; font-weight: 700; letter-spacing: 0.8px;
text-transform: uppercase; color: var(--text-muted, var(--text-secondary)); opacity: 0.85; }
.bookslm-qa-more { display: inline-flex; align-items: center; gap: 5px; background: none;
border: none; color: var(--accent); font-size: 12px; cursor: pointer; padding: 2px 4px;
border-radius: 6px; }
.bookslm-qa-more:hover { background: var(--bg-hover); }
.bookslm-qa-list { display: flex; flex-direction: column; gap: 6px; }
.bookslm-qa-btn { display: flex; align-items: center; gap: 10px; width: 100%;
text-align: left; padding: 9px 12px; border-radius: 10px; cursor: pointer;
background: var(--surface); border: 1px solid var(--border); color: var(--text-secondary);
font-size: 13px; transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; }
.bookslm-qa-btn:hover { background: var(--surface2); border-color: var(--accent); color: var(--text-primary); }
.bookslm-qa-btn .bookslm-qa-icon { color: var(--text-muted, var(--text-secondary)); flex-shrink: 0; }
.bookslm-qa-btn:hover .bookslm-qa-icon { color: var(--accent); }
.bookslm-qa-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
white-space: nowrap; font-weight: 500; }
.bookslm-qa-go { opacity: 0; transform: translateX(-3px); transition: opacity 0.15s ease,
transform 0.15s ease; color: var(--accent); flex-shrink: 0; }
.bookslm-qa-btn:hover .bookslm-qa-go { opacity: 1; transform: translateX(0); }
/* Tiroir catalogue ("Toutes les actions") : bottom-sheet dans le panneau. */
.bookslm-qa-drawer { position: absolute; inset: 0; z-index: 60; background: rgba(0, 0, 0, 0.45);
display: flex; align-items: flex-end; opacity: 0; transition: opacity 0.2s ease; }
.bookslm-qa-drawer.hidden { display: none; }
.bookslm-qa-drawer.open { opacity: 1; }
.bookslm-qa-sheet { width: 100%; max-height: 82%; display: flex; flex-direction: column;
background: var(--bg-primary); border-top: 1px solid var(--border);
border-radius: 14px 14px 0 0; padding: 12px 14px 10px; box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.35);
transform: translateY(100%); transition: transform 0.22s ease; }
.bookslm-qa-drawer.open .bookslm-qa-sheet { transform: translateY(0); }
.bookslm-qa-sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.bookslm-qa-sheet-title { display: inline-flex; align-items: center; gap: 7px; font-size: 14px;
font-weight: 600; color: var(--text-primary); }
.bookslm-qa-sheet-title i { color: var(--accent); }
.bookslm-qa-sheet-close { display: inline-flex; align-items: center; justify-content: center;
width: 26px; height: 26px; border-radius: 50%; border: none; cursor: pointer;
background: var(--surface); color: var(--text-secondary); }
.bookslm-qa-sheet-close:hover { background: var(--surface2); color: var(--text-primary); }
.bookslm-qa-search { position: relative; margin-bottom: 10px; }
.bookslm-qa-search i { position: absolute; left: 9px; top: 50%; transform: translateY(-50%);
color: var(--text-secondary); pointer-events: none; }
.bookslm-qa-search input { width: 100%; box-sizing: border-box; padding: 7px 10px 7px 30px;
border-radius: 8px; border: 1px solid var(--border); background: var(--surface);
color: var(--text-primary); font-size: 13px; outline: none; }
.bookslm-qa-search input:focus { border-color: var(--accent); }
.bookslm-qa-sheet-list { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 6px;
padding-bottom: 8px; }
.bookslm-qa-cat { margin: 8px 2px 2px; display: flex; align-items: center; gap: 6px;
font-size: 10px; font-weight: 700; letter-spacing: 0.8px; text-transform: uppercase;
color: var(--text-secondary); position: sticky; top: 0; background: var(--bg-primary);
padding: 4px 0; z-index: 1; }
.bookslm-qa-btn.compact { padding: 7px 10px; border-radius: 8px; font-size: 12.5px; }
.bookslm-qa-empty { padding: 18px 8px; text-align: center; font-size: 12px; color: var(--text-secondary); }
@media (prefers-reduced-motion: reduce) {
.bookslm-qa-drawer, .bookslm-qa-sheet, .bookslm-qa-btn, .bookslm-qa-go { transition: none; }
}
/* Formatted markdown inside assistant answers. */
.bookslm-bubble.assistant > *:first-child { margin-top: 0; }
.bookslm-bubble.assistant > *:last-child { margin-bottom: 0; }
.bookslm-bubble.assistant p { margin: 6px 0; }
.bookslm-bubble.assistant h1,
.bookslm-bubble.assistant h2,
.bookslm-bubble.assistant h3,
.bookslm-bubble.assistant h4,
.bookslm-bubble.assistant h5,
.bookslm-bubble.assistant h6 { margin: 10px 0 6px; line-height: 1.3; font-weight: 600; }
.bookslm-bubble.assistant h1 { font-size: 1.35em; }
.bookslm-bubble.assistant h2 { font-size: 1.2em; }
.bookslm-bubble.assistant h3 { font-size: 1.1em; }
.bookslm-bubble.assistant h4,
.bookslm-bubble.assistant h5,
.bookslm-bubble.assistant h6 { font-size: 1em; }
.bookslm-bubble.assistant ul,
.bookslm-bubble.assistant ol { margin: 6px 0; padding-left: 20px; }
.bookslm-bubble.assistant li { margin: 2px 0; }
.bookslm-bubble.assistant blockquote { margin: 8px 0; padding: 4px 10px;
border-left: 3px solid var(--accent); background: rgba(0,0,0,0.12);
border-radius: 0 4px 4px 0; color: var(--text-secondary); }
.bookslm-bubble.assistant hr { border: none; border-top: 1px solid var(--border); margin: 10px 0; }
.bookslm-bubble.assistant table { border-collapse: collapse; margin: 8px 0; width: 100%;
display: block; overflow-x: auto; }
.bookslm-bubble.assistant th,
.bookslm-bubble.assistant td { border: 1px solid var(--border); padding: 4px 8px;
font-size: 0.92em; text-align: left; }
.bookslm-bubble.assistant th { background: rgba(0,0,0,0.15); }
.bookslm-bubble.assistant pre { max-width: 100%; }
.bookslm-bubble.assistant a { color: var(--accent); }
.bookslm-path-link { color: var(--accent); cursor: pointer;
text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 2px; }
.bookslm-path-link:hover { text-decoration-style: solid; }
/* Session history dropdown. */
.bookslm-history-menu { position: absolute; top: 48px; right: 10px; z-index: 20;
width: min(320px, calc(100% - 20px)); max-height: 60vh; overflow-y: auto;
background: var(--bg-primary); border: 1px solid var(--border); border-radius: 10px;
box-shadow: 0 8px 24px rgba(0,0,0,0.35); padding: 6px; }
.bookslm-history-menu.hidden { display: none; }
.bookslm-history-item { display: flex; align-items: stretch; gap: 4px; border-radius: 8px; }
.bookslm-history-item:hover { background: var(--surface2); }
.bookslm-history-item.active { background: var(--surface2); outline: 1px solid var(--accent); }
.bookslm-history-open { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px;
background: none; border: none; cursor: pointer; text-align: left; padding: 7px 8px;
color: var(--text-primary); border-radius: 8px; }
.bookslm-history-title { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bookslm-history-date { font-size: 10px; color: var(--text-secondary); }
.bookslm-history-meta { font-size: 10px; color: var(--text-secondary);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bookslm-history-delete { background: none; border: none; cursor: pointer; color: var(--text-secondary);
padding: 0 8px; border-radius: 6px; display: flex; align-items: center; }
.bookslm-history-delete:hover { color: #f87171; background: rgba(248,113,113,0.12); }
.bookslm-history-empty { padding: 10px; font-size: 12px; color: var(--text-secondary); text-align: center; }
/* Resizable left edge. */
.bookslm-resize-handle { position: absolute; left: 0; top: 0; bottom: 0; width: 6px;
cursor: ew-resize; z-index: 30; background: transparent; }
.bookslm-resize-handle:hover { background: var(--accent); opacity: 0.4; }
.bookslm-panel.fullscreen .bookslm-resize-handle { display: none; }
body.bookslm-resizing { cursor: ew-resize; user-select: none; }
/* Attachment chips (ad-hoc context, skill, images). */
.bookslm-attachments { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 12px 0; }
.bookslm-attachments.empty { display: none; }
.bookslm-chip { display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
padding: 3px 6px 3px 8px; border: 1px solid var(--border); border-radius: 14px;
background: var(--surface2); font-size: 11px; color: var(--text-primary); }
.bookslm-chip-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
.bookslm-chip-remove { background: none; border: none; cursor: pointer; color: var(--text-secondary);
font-size: 14px; line-height: 1; padding: 0 2px; border-radius: 50%; }
.bookslm-chip-remove:hover { color: #f87171; }
.bookslm-chip-thumb { width: 18px; height: 18px; object-fit: cover; border-radius: 4px; }
.bookslm-chip-skill { border-color: var(--accent); }
.bookslm-chip-deep-research { border-color: var(--accent); }
/* Composer menus (`/` commands and `@` mentions). */
.bookslm-menu-layer { position: relative; }
.bookslm-command-menu, .bookslm-mention-menu { position: absolute; left: 12px; right: 12px; bottom: 4px;
max-height: 260px; overflow-y: auto; background: var(--bg-primary); border: 1px solid var(--border);
border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.35); padding: 4px; z-index: 40; }
.bookslm-command-menu.hidden, .bookslm-mention-menu.hidden { display: none; }
.bookslm-menu-item { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
background: none; border: none; cursor: pointer; padding: 7px 9px; border-radius: 7px;
color: var(--text-primary); font-size: 13px; }
.bookslm-menu-item:hover { background: var(--bg-hover); }
/* The active (keyboard) item needs a clearly visible highlight: --surface2 is
identical to --bg-primary in the default dark theme, so it was invisible. */
.bookslm-menu-item.active { background: var(--bg-hover); color: var(--text-primary);
box-shadow: inset 3px 0 0 var(--accent); }
.bookslm-menu-icon { flex-shrink: 0; }
.bookslm-menu-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bookslm-menu-desc, .bookslm-menu-usage { margin-left: auto; font-size: 11px; color: var(--text-secondary);
white-space: nowrap; }
.bookslm-menu-empty { padding: 10px; font-size: 12px; color: var(--text-secondary); text-align: center; }
/* Image attach button. */
.bookslm-input-area button.bookslm-btn-plus { display: flex; align-items: center; justify-content: center; flex-shrink: 0;
background: none; border: 1px solid var(--border); color: var(--text-secondary); cursor: pointer;
border-radius: 50%; width: 32px; height: 32px; padding: 0; }
.bookslm-input-area button.bookslm-btn-plus:hover { color: var(--accent); border-color: var(--accent); }
.bookslm-file-input { display: none; }
.bookslm-files-input { display: none; }
/* Extensible "+" panel (#97). */
.bookslm-ext-menu { position: absolute; left: 12px; right: 12px; bottom: 72px; z-index: 45;
max-height: 55vh; overflow-y: auto; background: var(--bg-primary); border: 1px solid var(--border);
border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,0.35); padding: 6px; }
.bookslm-ext-menu.hidden { display: none; }
.bookslm-ext-item { display: grid; grid-template-columns: 20px 1fr auto; align-items: center;
gap: 8px; width: 100%; text-align: left; background: none; border: none; cursor: pointer;
padding: 8px 9px; border-radius: 8px; color: var(--text-primary); font-size: 13px; }
.bookslm-ext-item:hover { background: var(--bg-hover); }
.bookslm-ext-item .bookslm-ext-hint { grid-column: 2 / 4; font-size: 11px; color: var(--text-secondary);
margin-top: -4px; }
.bookslm-ext-item.disabled { opacity: 0.55; cursor: not-allowed; }
.bookslm-ext-item.disabled:hover { background: none; }
.bookslm-ext-soon { font-size: 9px; text-transform: uppercase; letter-spacing: 0.4px;
color: var(--accent); border: 1px solid var(--accent); border-radius: 10px; padding: 1px 6px; }
.bookslm-ext-footer { padding: 7px 9px 4px; font-size: 10px; color: var(--text-secondary);
text-align: center; border-top: 1px dashed var(--border); margin-top: 4px; }
/* Create-skill modal. */
.bookslm-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 2000;
display: flex; align-items: center; justify-content: center; padding: 16px; }
.bookslm-modal { background: var(--bg-primary); border: 1px solid var(--border); border-radius: 12px;
padding: 18px; width: min(520px, 100%); box-shadow: 0 12px 40px rgba(0,0,0,0.45); }
.bookslm-modal-title { margin: 0 0 12px; font-size: 15px; }
.bookslm-modal-field { display: flex; flex-direction: column; gap: 4px; font-size: 12px;
color: var(--text-secondary); margin-bottom: 10px; }
.bookslm-modal-field input, .bookslm-modal-field textarea { padding: 8px 10px; border-radius: 8px;
border: 1px solid var(--border); background: var(--bg-secondary); color: var(--text-primary);
font-size: 13px; font-family: inherit; }
.bookslm-modal-error { color: #f87171; font-size: 12px; min-height: 14px; margin-bottom: 6px; }
.bookslm-modal-actions { display: flex; justify-content: flex-end; gap: 8px; }
.bookslm-modal-actions button { padding: 7px 14px; border-radius: 8px; border: 1px solid var(--border);
background: var(--surface); color: var(--text-primary); cursor: pointer; font-size: 13px; }
.bookslm-modal-actions button.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
/* ── Provider/model picker (shared by assistant + editor) ── */
.ai-picker { display: inline-flex; align-items: center; gap: 8px;
font-size: 0.8rem; color: var(--text-secondary); flex-shrink: 0; position: relative; }
.ai-picker-label { white-space: nowrap; }
.ai-picker select { font-size: 0.8rem; background: var(--surface); color: var(--text-primary);
border: 1px solid var(--border); border-radius: 6px; padding: 6px 10px; cursor: pointer;
min-height: 34px; }
.ai-picker select:hover { border-color: var(--accent); }
.ai-picker select:focus { border-color: var(--accent); outline: none; }
/* Searchable model combobox. */
.ai-picker-model-combo { position: relative; display: inline-flex; }
.ai-picker-model-trigger { display: inline-flex; align-items: center; justify-content: space-between;
gap: 6px; max-width: 240px; min-width: 120px; min-height: 34px;
font-size: 0.8rem; background: var(--surface); color: var(--text-primary);
border: 1px solid var(--border); border-radius: 6px; padding: 6px 10px; cursor: pointer; }
.ai-picker-model-trigger:hover, .ai-picker-model-trigger:focus { border-color: var(--accent); outline: none; }
.ai-picker-model-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ai-picker-model-chevron { opacity: 0.6; font-size: 0.7rem; flex-shrink: 0; }
.ai-picker-model-pop { position: absolute; top: calc(100% + 4px); right: 0; z-index: 60;
min-width: 220px; width: 340px; max-width: calc(100vw - 24px); background: var(--bg-primary);
border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,0.35);
padding: 6px; }
.ai-picker-model-pop.hidden { display: none; }
.ai-picker-model-search { width: 100%; box-sizing: border-box; font-size: 0.8rem;
background: var(--bg-secondary); color: var(--text-primary); border: 1px solid var(--border);
border-radius: 6px; padding: 7px 10px; margin-bottom: 4px; }
.ai-picker-model-search:focus { border-color: var(--accent); outline: none; }
.ai-picker-model-list { max-height: 260px; overflow-y: auto; display: flex; flex-direction: column; }
.ai-picker-model-option { display: block; width: 100%; text-align: left; font-size: 0.8rem;
line-height: 1.35; padding: 7px 10px; border-radius: 5px; background: none; border: none;
color: var(--text-primary); cursor: pointer; white-space: normal; overflow-wrap: anywhere; }
.ai-picker-model-option:hover { background: var(--bg-hover); }
.ai-picker-model-option.active { background: var(--bg-hover); box-shadow: inset 3px 0 0 var(--accent); }
.ai-picker-model-empty { font-size: 0.78rem; color: var(--text-secondary); padding: 8px 10px; text-align: center; }
.ai-picker-model-more { font-size: 0.78rem; color: var(--text-secondary); padding: 8px 10px; text-align: center; }
/* Capability info button (ⓘ) + informational bubble. */
.ai-picker-caps-host { position: relative; display: inline-flex; }
.ai-picker-info { background: none; border: none; cursor: pointer; color: var(--text-secondary);
font-size: 1rem; line-height: 1; padding: 5px 7px; border-radius: 6px; }
.ai-picker-info:hover, .ai-picker-info:focus { color: var(--accent); }
.ai-picker-info.hidden { display: none; }
.ai-picker-caps-pop { position: absolute; top: calc(100% + 4px); left: 0; z-index: 60;
min-width: 220px; max-width: 300px; background: var(--bg-primary);
border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,0.35);
padding: 8px 10px; }
.ai-picker-caps-pop.hidden { display: none; }
.ai-picker-caps-title { font-size: 0.7rem; font-weight: 600; color: var(--text-secondary);
text-transform: uppercase; letter-spacing: .04em; margin-bottom: 4px; }
.ai-picker-caps { display: flex; flex-wrap: wrap; gap: 4px 10px; margin-top: 4px; font-size: 10px;
color: var(--text-secondary); }
.ai-cap-item { white-space: nowrap; opacity: 0.65; }
.ai-cap-item.on { opacity: 1; color: var(--accent); }
@media (max-width: 768px) {
.bookslm-resize-handle { display: none; }
.bookslm-panel {
width: 100%;
/* Clear the fixed bottom toolbar so the input box and the send button
are not hidden behind it. The panel background still fills the area
behind the bar. */
padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px));
}
}
/* ── AI Floating Action Button ───────────────────────── */
.ai-fab {
position: fixed;
bottom: 24px;
right: 24px;
width: 52px;
height: 52px;
border-radius: 50%;
background: var(--accent);
color: #fff;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
z-index: 99;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
transition: transform 200ms ease, opacity 200ms ease;
padding: 0;
}
.ai-fab:hover {
transform: scale(1.08);
}
.ai-fab:active {
transform: scale(0.96);
}
.ai-fab[hidden] {
display: none;
}
/* ══════════════════════════════════════════
Mobile editor UX (ROADMAP #69)
Floating Markdown toolbar, paste helper,
pinch-zoom, adjustable height, swipe
shortcuts and distraction-free reading mode.
══════════════════════════════════════════ */
/* ── Obsidian-style editing ribbon (ROADMAP #83) ── */
.me-toolbar {
display: none;
}
.me-ribbon {
--kb-offset: 0px;
}
.me-ribbon-scroll {
display: flex;
align-items: center;
gap: 4px;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
padding: 2px 2px;
min-width: 0;
flex: 1;
}
.me-ribbon-scroll::-webkit-scrollbar {
display: none;
}
.me-ribbon-btn {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 42px;
height: 42px;
padding: 0 8px;
border: 1px solid transparent;
border-radius: 10px;
background: transparent;
color: var(--text-primary);
font-size: 14px;
font-weight: 600;
font-family: var(--font-mono);
cursor: pointer;
-webkit-tap-highlight-color: transparent;
transition: background 120ms ease, transform 120ms ease;
}
.me-ribbon-btn:active {
transform: scale(0.92);
background: rgba(128, 128, 128, 0.22);
}
.me-ribbon-gear {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
border: none;
border-left: 1px solid var(--border);
border-radius: 0;
background: transparent;
color: var(--text-muted);
font-size: 18px;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
.me-ribbon-gear:active {
color: var(--accent);
}
/* Ribbon customiser rows */
.me-ribbon-customizer-list {
max-height: 50vh;
overflow-y: auto;
}
.me-ribbon-cmd-row {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 10px;
border-bottom: 1px solid var(--border);
}
.me-ribbon-cmd-row.disabled {
opacity: 0.75;
}
.me-ribbon-cmd-label {
flex: 1;
font-size: 0.85rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.me-ribbon-cmd-move,
.me-ribbon-cmd-remove,
.me-ribbon-cmd-add {
flex: 0 0 auto;
width: 34px;
height: 34px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--bg-primary);
color: var(--text-primary);
font-size: 14px;
cursor: pointer;
}
.me-ribbon-cmd-move:disabled {
opacity: 0.35;
}
.me-ribbon-cmd-remove {
color: var(--danger);
}
.me-ribbon-cmd-divider {
padding: 10px;
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--text-muted);
}
.me-ribbon-customizer-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
padding: 10px;
border-top: 1px solid var(--border);
}
/* BUG-018: the in-editor AI toolbar was too dense on small screens. */
@media (max-width: 768px) {
.ai-toolbar {
gap: 4px !important;
padding: 6px 8px !important;
}
.ai-toolbar-btn {
min-height: 34px;
padding: 6px 10px !important;
font-size: 0.78rem !important;
}
}
@media (max-width: 768px) {
.editor-modal.active .me-ribbon {
display: flex;
position: fixed;
left: 8px;
right: 8px;
/* BUG-019: sit just above the on-screen keyboard. */
bottom: calc(var(--kb-offset, 0px) + 8px + env(safe-area-inset-bottom, 0));
z-index: 30;
align-items: center;
gap: 4px;
padding: 4px;
background: #1c1c1e;
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 14px;
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
}
.me-ribbon-btn {
color: #e8e8ea;
}
.me-ribbon-gear {
color: #b8b8bd;
}
[data-theme="light"] .me-ribbon {
background: #f1f1f4;
border-color: rgba(0, 0, 0, 0.08);
}
[data-theme="light"] .me-ribbon-btn {
color: #1c1c1e;
}
[data-theme="light"] .me-ribbon-gear {
color: #5a5a60;
}
}
/* ── Adjustable editor height handle ── */
.me-resize-handle {
display: none;
}
@media (max-width: 768px) {
.me-resize-handle {
display: block;
height: 14px;
margin: 0;
background: var(--bg-secondary);
border-top: 1px solid var(--border);
cursor: ns-resize;
touch-action: none;
position: relative;
flex-shrink: 0;
}
.me-resize-handle::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 40px;
height: 4px;
border-radius: 2px;
background: var(--border);
transform: translate(-50%, -50%);
}
}
/* ── Reading mode enter / exit buttons ── */
.me-reading-btn,
.me-reading-exit {
display: none;
}
/* Author `display: flex` would otherwise win over the `[hidden]` attribute. */
.me-reading-btn[hidden] {
display: none;
}
@media (max-width: 768px) {
.me-reading-btn {
display: flex;
position: fixed;
right: 16px;
bottom: calc(80px + env(safe-area-inset-bottom, 0));
z-index: 890;
width: 48px;
height: 48px;
align-items: center;
justify-content: center;
border: none;
border-radius: 50%;
background: var(--accent);
color: #fff;
font-size: 20px;
cursor: pointer;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
}
body.reading-mode .me-reading-btn {
display: none;
}
body.reading-mode .me-reading-exit {
display: flex;
position: fixed;
top: calc(12px + env(safe-area-inset-top, 0));
right: 12px;
z-index: 1100;
width: 40px;
height: 40px;
align-items: center;
justify-content: center;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--bg-secondary);
color: var(--text-primary);
font-size: 16px;
cursor: pointer;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
}
/* ── Distraction-free reading mode ── */
body.reading-mode .header,
body.reading-mode .sidebar,
body.reading-mode .sidebar-overlay,
body.reading-mode .right-sidebar,
body.reading-mode .right-sidebar-resize-handle,
body.reading-mode .mobile-toolbar,
body.reading-mode .vault-context-bar,
body.reading-mode .tab-bar {
display: none !important;
}
body.reading-mode .content-area {
max-width: 820px;
margin: 0 auto;
padding: clamp(20px, 6vw, 48px) clamp(18px, 6vw, 40px) 96px;
}
/* The bottom toolbar is hidden in reading mode: no clearance needed. */
body.reading-mode .main-body {
padding-bottom: 0;
}
body.reading-mode .breadcrumb,
body.reading-mode .file-toolbar,
body.reading-mode .file-actions {
display: none;
}
/* ── Bottom sheet (backlinks / table of contents) ── */
.me-sheet {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 1200;
max-height: 70vh;
display: flex;
flex-direction: column;
background: var(--bg-secondary);
border-top-left-radius: 16px;
border-top-right-radius: 16px;
box-shadow: 0 -6px 28px rgba(0, 0, 0, 0.4);
transform: translateY(110%);
transition: transform 220ms ease;
}
.me-sheet.open {
transform: translateY(0);
}
.me-sheet-overlay {
position: fixed;
inset: 0;
z-index: 1190;
background: var(--overlay-bg, rgba(0, 0, 0, 0.5));
opacity: 0;
pointer-events: none;
transition: opacity 220ms ease;
}
.me-sheet-overlay.visible {
opacity: 1;
pointer-events: auto;
}
.me-sheet-handle {
width: 40px;
height: 4px;
border-radius: 2px;
background: var(--border);
margin: 8px auto 4px;
flex-shrink: 0;
}
.me-sheet-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 16px 10px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.me-sheet-title {
font-size: 0.9rem;
font-weight: 600;
color: var(--text-primary);
}
.me-sheet-close {
width: 32px;
height: 32px;
border: none;
border-radius: 8px;
background: transparent;
color: var(--text-muted);
font-size: 16px;
cursor: pointer;
}
.me-sheet-list {
overflow-y: auto;
-webkit-overflow-scrolling: touch;
padding: 6px 8px calc(12px + env(safe-area-inset-bottom, 0));
}
.me-sheet-item {
display: block;
width: 100%;
padding: 12px 12px;
border: none;
border-radius: 8px;
background: transparent;
color: var(--text-primary);
font-size: 0.9rem;
text-align: left;
cursor: pointer;
}
.me-sheet-item:active {
background: var(--bg-hover, rgba(128, 128, 128, 0.18));
}
.me-sheet-empty {
padding: 24px 16px;
text-align: center;
color: var(--text-muted);
font-size: 0.85rem;
}