@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; /* #154-A1 — data-grid tokens: the sheet reads slightly lighter than the chrome (toolbar/panels), headers are clearly distinct from cells. */ --grid-bg: #161b22; --grid-header-bg: #1f2430; --grid-header-text: #e6edf3; --grid-border: #3d444d; --grid-zebra: rgba(255, 255, 255, 0.025); } /* ===== 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; --grid-bg: #161b22; --grid-header-bg: #1f2430; --grid-header-text: #e6edf3; --grid-border: #3d444d; --grid-zebra: rgba(255, 255, 255, 0.025); } /* ===== 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; --grid-bg: #ffffff; --grid-header-bg: #eaeef2; --grid-header-text: #1f2328; --grid-border: #b6bec9; --grid-zebra: rgba(0, 0, 0, 0.025); } /* ===== THEME — HIGH-CONTRAST (generated mode, see themes.js) ===== */ :root[data-theme="high-contrast"] { --grid-bg: #000000; --grid-header-bg: #141414; --grid-header-text: #ffffff; --grid-border: #6b6b6b; --grid-zebra: rgba(255, 255, 255, 0.045); } /* ===== THEME — SEPIA (generated mode, see themes.js) ===== */ :root[data-theme="sepia"] { --grid-bg: #f5ecd5; --grid-header-bg: #e8dcc0; --grid-header-text: #3d2e1a; --grid-border: #b09a6d; --grid-zebra: rgba(61, 46, 26, 0.04); } /* ===== 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, spreadsheets) 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(.xlsx-viewer), .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; } /* Secret masks (#188) — click copies the real value to the clipboard */ .secret-mask { cursor: pointer; padding: 0 3px; border-radius: 3px; border-bottom: 1px dashed var(--text-muted); background: var(--bg-secondary); } .secret-mask:hover { background: var(--bg-hover); } /* 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; /* Par-dessus la barre d'outils mobile (.mobile-toolbar, z-index 900) pour ne pas masquer le bas du sidebar — BUG-103 */ z-index: 950; 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 .desktop-roots-item { flex-wrap: wrap; } #config-modal .desktop-roots-item .config-btn-sm { min-height: 44px; } #config-modal .desktop-roots-actions { flex-wrap: wrap; } #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); } /* Facette actuellement appliquée (filtre local — recherche et navigation) */ .search-facets__item.active { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 15%, transparent); color: var(--text-primary); } .search-facets__item .facet-count { font-size: 0.68rem; color: var(--text-muted); } .search-facets__toggle { display: inline-flex; align-items: center; justify-content: center; align-self: flex-start; /* mobile (colonne) : ne jamais s'étirer en pleine largeur */ padding: 2px 6px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-secondary); color: var(--text-muted); cursor: pointer; transition: border-color 120ms, color 120ms, background 120ms; } .search-facets__toggle:hover { border-color: var(--accent); color: var(--text-secondary); } /* Seule l'icône pivote — la boîte du bouton reste fixe */ .search-facets__toggle i, .search-facets__toggle svg { transition: transform 120ms; } .search-facets[data-collapsed="true"] .search-facets__toggle i, .search-facets[data-collapsed="true"] .search-facets__toggle svg { transform: rotate(-90deg); } .search-facets__body { display: flex; flex-wrap: wrap; gap: 12px; flex: 1 1 auto; min-width: 0; } .search-facets[data-collapsed="true"] .search-facets__body { display: none; } /* --------------------------------------------------------------------------- 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; } /* Icône des répertoires : même couleur que l'arbre de la sidebar (.tree-item .icon) */ .vault-home-dirs .icon { color: var(--accent); } .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)); } /* Google Sheets : le survol d'une ligne ne teinte rien (jamais de highlight de ligne entière au survol). */ /* ── XLSX Viewer ── */ /* #154-A1 — the viewer shell is a grouped command bar (edition commands), then a sheet strip (tabs on the left, File menu + Save on the right), then a status row stating the viewer's limits (read-only). #180 pins the bar to the top edge of the page, full content width. */ .xlsx-toolbar { display: flex; flex-direction: column; gap: 8px; position: sticky; /* #180 — stays on the top edge while the grid scrolls */ /* La marge haute négative (pleine largeur) tirait la barre 40 px sous sa position statique : `top: 0` la replaquait et elle recouvrait le contenu (en-tête A–Z, ligne 1) de 32 px. La contrainte reprend la même expression que la marge : aucun déplacement au repos, épinglage intact au scroll. */ top: calc(-1 * clamp(16px, 3vw, 40px)); z-index: 30; margin: calc(-1 * clamp(16px, 3vw, 40px)) calc(-1 * clamp(16px, 4vw, 40px)) 8px; padding: 8px clamp(16px, 4vw, 40px); border: 1px solid var(--border); border-left: none; border-right: none; border-top: none; border-radius: 0; background: var(--surface2); } .xlsx-cmdbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } /* #185 — the Google Sheets menu bar: a flat row of text buttons above the ribbon. No chrome, no borders: only the open menu gets a filled pill. */ .xlsx-menubar { display: flex; align-items: center; gap: 2px; flex-wrap: wrap; margin: -2px 0 -2px; } /* No `position: relative` here on purpose: the dropdown is positioned by anchorUnder() (viewer.js) relative to the sticky `.xlsx-toolbar`, exactly like the Structure / Mise en forme / ribbon menus. Making the wrapper a containing block would shift every dropdown by the button's offset. */ .xlsx-menuwrap { display: inline-flex; } .xlsx-menubtn { appearance: none; border: none; background: transparent; color: var(--text-secondary); font-family: inherit; font-size: 0.82rem; line-height: 1.4; padding: 5px 10px; border-radius: 4px; cursor: pointer; white-space: nowrap; } .xlsx-menubtn:hover { background: var(--bg-hover); color: var(--text-primary); } .xlsx-menubtn[aria-expanded="true"] { background: var(--accent-bg, var(--bg-hover)); color: var(--accent-text, var(--accent, #4a90d9)); } /* The Gemini entry keeps its own accent so it reads as the AI corner of the bar, like the themed icon in Google Sheets. */ .xlsx-menuwrap-gemini .xlsx-menubtn { color: var(--accent, #4a90d9); font-weight: 600; } .xlsx-menudrop { min-width: 260px; max-height: min(70vh, 560px); overflow-y: auto; z-index: 40; } /* Accordion section (Nombre, Thème, Zoom, Alignement, …). */ .xlsx-menu-sub { display: flex; flex-direction: column; gap: 2px; padding-left: 18px; border-left: 2px solid var(--border); margin: 2px 0 4px 8px; } .xlsx-menu-sub[hidden] { display: none; } .xlsx-menu-item { width: 100%; } .xlsx-menu-item-d2 { padding-left: 18px; } .xlsx-menu-caret { width: 14px; height: 14px; flex: 0 0 auto; margin-left: auto; color: var(--text-muted); transition: transform 0.12s ease; } .xlsx-menu-item[aria-expanded="true"] > .xlsx-menu-caret { transform: rotate(90deg); } /* An entry ObsiGate does not implement: dimmed but still clickable, so it answers instead of pretending. */ .xlsx-menu-item-na { opacity: 0.55; } .xlsx-menu-item-na:hover { opacity: 1; } .xlsx-menu-empty { padding: 6px 10px; font-size: 0.78rem; color: var(--text-muted); } /* #185 — Google Sheets' ribbon look: flat square icon buttons, no border and no resting background, grouped by thin vertical rules. The old rounded / bordered chrome fought with the theme of every one of the 15 themes. */ .xlsx-toolbar .btn-action { border: 1px solid transparent; border-radius: 4px; background: transparent; color: var(--text-secondary); min-width: 30px; height: 30px; padding: 0 6px; display: inline-flex; align-items: center; justify-content: center; } .xlsx-toolbar .btn-action:hover:not(:disabled) { background: var(--bg-hover); color: var(--text-primary); } .xlsx-toolbar .btn-action.active { background: var(--accent-bg, var(--bg-hover)); color: var(--accent-text, var(--accent, #4a90d9)); } .xlsx-toolbar .btn-action:disabled { opacity: 0.4; cursor: default; } .xlsx-toolbar .xlsx-cmd-sep { width: 1px; height: 22px; background: var(--border); } .xlsx-toolbar .xlsx-select { height: 30px; border-color: transparent; background: transparent; } .xlsx-toolbar .xlsx-select:hover { background: var(--bg-hover); } /* Save stays the one solid pill: it is the only command with a consequence outside the browser. */ .xlsx-toolbar .xlsx-save-primary { border-color: var(--accent); background: var(--accent); color: #fff; font-size: 0.8rem; } .xlsx-toolbar .xlsx-save-primary:hover:not(:disabled) { background: var(--accent); color: #fff; filter: brightness(1.08); } .xlsx-formula-bar[hidden] { display: none; } /* Wrapped command groups: every control stays visible, no scrollbar. */ .xlsx-cmdbar > .xlsx-toolbar-actions { display: flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; overflow: visible; } .xlsx-cmdbar .xlsx-cmd-group, .xlsx-cmdbar .xlsx-cmd-sep { flex: 0 0 auto; } /* Native selects (zoom, number format): no custom dropdown to dismiss. */ .xlsx-select { font-family: inherit; font-size: 0.75rem; color: var(--text-secondary); background: transparent; border: 1px solid var(--border); border-radius: 6px; padding: 4px 6px; cursor: pointer; max-width: 130px; } .xlsx-select:hover { color: var(--accent); border-color: var(--accent); } /* B/I/S/U letter buttons + decimal shorthands. */ .xlsx-fontstyle { font-family: Georgia, "Times New Roman", serif; min-width: 28px; } .xlsx-dec { font-family: "JetBrains Mono", monospace; } .xlsx-fontsize { min-width: 26px; text-align: center; font-size: 0.75rem; color: var(--text-secondary); } /* Colour pickers: a letter/swatch label wrapping the native input. */ .xlsx-colorpick { position: relative; overflow: hidden; } .xlsx-colorpick input[type="color"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%; padding: 0; border: none; } /* #182 — colour swatch under the picker: mirrors the chosen colour so applying one to a selection is visible on the button itself. Empty (transparent) until a colour is actually picked, so the default ribbon stays clean. */ .xlsx-color-swatch { width: 14px; height: 4px; border-radius: 2px; border: 1px solid var(--border); background: transparent; flex: 0 0 auto; } .xlsx-colorletter { font-family: Georgia, serif; font-weight: 700; border-bottom: 3px solid var(--accent); line-height: 1; padding: 0 2px; } /* Ribbon dropdown menus share the structure-menu look. */ .xlsx-ribbon-menu { min-width: 220px; } /* Floating contextual mini-bar (multi-cell selections). */ .xlsx-minibar { position: fixed; z-index: 10060; display: flex; align-items: center; gap: 2px; padding: 4px 6px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); box-shadow: 0 8px 24px var(--shadow, rgba(0, 0, 0, 0.25)); } .xlsx-minibar[hidden] { display: none; } .xlsx-minibar button { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 6px; background: transparent; color: var(--text-secondary); cursor: pointer; } .xlsx-minibar button:hover { background: var(--bg-hover); color: var(--accent); } .xlsx-minibar button svg, .xlsx-minibar button i[data-lucide] { width: 15px; height: 15px; } @media (pointer: coarse) { .xlsx-minibar button { width: 44px; height: 44px; } } .xlsx-toolbar-actions { margin-left: auto; display: flex; align-items: center; gap: 6px; } .xlsx-cmd-group { display: inline-flex; align-items: center; gap: 6px; } .xlsx-cmd-sep { width: 1px; height: 20px; flex: 0 0 auto; background: var(--border); } .xlsx-save-primary { background: var(--accent); border-color: var(--accent); color: #fff; } .xlsx-save-primary:disabled { opacity: 0.5; } .xlsx-tabs { display: flex; align-items: center; 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-tab-add { border: 1px dashed var(--border); background: transparent; color: var(--text-secondary); border-radius: 4px; padding: 4px 10px; font-size: 0.9rem; line-height: 1; cursor: pointer; } .xlsx-tab-add:hover { border-color: var(--accent); color: var(--accent); } /* #180 — sheet strip: tabs on the left, File menu + Save pinned right. */ .xlsx-sheetbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .xlsx-sheetbar .xlsx-tabs { flex: 1 1 auto; min-width: 0; } .xlsx-sheetbar-end { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; } .xlsx-file-dropdown { position: relative; display: inline-block; } .xlsx-file-item { text-align: left; } .xlsx-status-bar { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } .xlsx-status-pill { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border: 1px solid var(--border); border-radius: 999px; background: var(--bg-secondary); color: var(--text-secondary); font-size: 0.72rem; white-space: nowrap; } .xlsx-status-icon { width: 12px; height: 12px; flex: 0 0 auto; } .xlsx-status-readonly { border-color: var(--warning, #e0a800); color: var(--warning, #e0a800); } .xlsx-status-formula { color: var(--accent); } /* #154-A2 — unsaved-change feedback: the primary button and the owning tab. */ .xlsx-save-primary.is-dirty { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent); } .xlsx-tab-dirty::after { content: "•"; margin-left: 5px; color: var(--warning, #e0a800); } /* #154-A2 — non-blocking banners (conflict, …). */ .xlsx-banner-host { display: flex; flex-direction: column; gap: 8px; } .xlsx-banner { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: 4px; background: var(--surface); color: var(--text-secondary); font-size: 0.82rem; } .xlsx-banner-conflict { border-left-color: var(--warning, #e0a800); } .xlsx-banner-icon { width: 16px; height: 16px; flex: 0 0 auto; color: var(--warning, #e0a800); } .xlsx-banner-text { flex: 1; min-width: 0; } .xlsx-banner-dismiss { padding: 2px 8px; } .modal-confirm-text { color: var(--text-primary); font-size: 0.9rem; line-height: 1.5; white-space: pre-line; } .xlsx-table { background: var(--grid-bg, var(--surface)); } /* #185 — one uniform 1px grid line on EVERY side of every cell (header rows included), the way Sheets draws it. Previously only the bottom edge existed and its colour came from `--border`, which is far too close to the cell background on most themes: the grid read as a smear instead of a grid. `--grid-border` is now derived from the theme by themes.js (same token for every line, so the mesh stays perfectly regular). */ .xlsx-table td, .xlsx-table th { border: 1px solid var(--grid-border, var(--border)); } .xlsx-table td { border-bottom: 1px solid var(--grid-border, var(--border)); /* Cellules de données : une seule et même couleur (fond de grille). Pas de variante une-ligne-sur-deux ici : sa spécificité écraserait la teinte de sélection (une ligne sur deux non teintée). */ background: var(--grid-bg, var(--surface)); } /* Cellules fusionnées : couleur d'en-tête, sauf en sélection (la teinte de sélection gagne, uniforme sur toutes les cellules). */ .xlsx-table tbody td[rowspan]:not([rowspan="1"]):not(.xlsx-selected), .xlsx-table tbody td[colspan]:not([colspan="1"]):not(.xlsx-selected) { background: var(--grid-header-bg, var(--bg-hover)); color: var(--grid-header-text, var(--text-primary)); } /* Google Sheets : aucun survol teinté — ni la ligne entière, ni la cellule. Rien ne se met en couleur tant que l'utilisateur n'a pas sélectionné au moins 2 cellules (voir `.xlsx-range-multi`). */ .xlsx-table th.xlsx-corner, .xlsx-table th.xlsx-rownum { background: var(--grid-header-bg, var(--bg-hover)); color: var(--grid-header-text, var(--text-primary)); font-weight: 500; text-align: right; padding: 6px 8px; /* #185 — the same 1px line as the cells: the header is told apart by its fill, not by a heavier rule that broke the grid's regularity. */ border: 1px solid var(--grid-border, var(--border)); position: sticky; left: 0; /* #153 A8 — `top: auto` is load-bearing: `.csv-table th` pins EVERY `th` at `top: 0`, so a row number left sticky on both axes piles up in the top-left corner instead of tracking its own row. */ top: auto; z-index: 2; } .xlsx-table th.xlsx-corner { left: 0; /* Suit `--xlsx-stick` comme l'en-tête : mesuré en JS sur le recouvrement réel de la toolbar sticky, sinon la ligne A–Z glisse dessous. */ top: var(--xlsx-stick, 0px); z-index: 4; } /* #153 A8 — the column headers stay visible while the sheet scrolls down. Declared explicitly (and not inherited from `.csv-table th`) so the stacking order is intentional: thead (3) < row numbers (2) < corner (4). */ .xlsx-table thead th { position: sticky; top: var(--xlsx-stick, 0px); z-index: 3; background: var(--grid-header-bg, var(--bg-hover)); color: var(--grid-header-text, var(--text-primary)); border-bottom: 1px solid var(--grid-border, var(--border)); } /* #185 — Affichage ▸ Afficher ▸ Grille / En-têtes, and Outils ▸ Accessibilité: display concerns only, never a change to the file. */ .xlsx-viewer.xlsx-no-grid .xlsx-table td, .xlsx-viewer.xlsx-no-grid .xlsx-table th { border-width: 0; } .xlsx-viewer.xlsx-no-headers thead, .xlsx-viewer.xlsx-no-headers th.xlsx-rownum, .xlsx-viewer.xlsx-no-headers th.xlsx-corner { display: none; } .xlsx-viewer.xlsx-a11y .xlsx-table td { padding: 8px 10px; font-size: 0.95rem; } .xlsx-viewer.xlsx-a11y { --grid-border: color-mix(in srgb, var(--text-primary, #888) 42%, var(--surface, #000)); } /* #180 — while the pointer rides a header edge, the representative resize icon must win over the cell (`cell`) and header (`pointer`) cursors. The edge header itself is mirrored inline by the viewer (its inline `cursor:pointer` beats any stylesheet rule). */ .xlsx-table.xlsx-resize-col, .xlsx-table.xlsx-resize-col th, .xlsx-table.xlsx-resize-col td { cursor: col-resize; } .xlsx-table.xlsx-resize-row, .xlsx-table.xlsx-resize-row th, .xlsx-table.xlsx-resize-row td { cursor: row-resize; } .xlsx-table td[contenteditable] { /* #155 — Excel-style cross cursor over the cells. */ cursor: cell; min-width: 40px; white-space: pre-wrap; } .xlsx-table td[contenteditable]:focus { outline: 2px solid var(--accent, #4a90d9); outline-offset: -2px; } /* #181-A1 — SELECTION vs EDITION, like Google Sheets / Excel. A selected cell is outlined but must NOT show a text caret; the caret is only revealed in edit mode (double-click, F2 or the first keystroke). `caret-color: transparent` hides it without leaving `contenteditable`, so the click-to-select / type-to-replace flow stays native. */ .xlsx-table td.xlsx-cell { caret-color: transparent; } .xlsx-table td.xlsx-editing { caret-color: auto; cursor: text; } /* The editing cell also reads as "open": a solid accent frame plus a raised shadow, so the state is visible even on a row that is part of a range. */ .xlsx-table td.xlsx-editing { outline: 2px solid var(--accent, #4a90d9); outline-offset: -2px; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent); z-index: 1; position: relative; } /* #181-A2 — range indicator: the four edges of the selected block trace it exactly (Excel/Sheets draw a rectangle, not a flat wash), and the covered row/column headers are highlighted too. `outline` on inner edges would be overdrawn by the next cell, so the four borders are declared separately and win over `.xlsx-selected`'s background. */ .xlsx-table tbody td.xlsx-sel-top { border-top: 2px solid var(--accent, #4a90d9); } .xlsx-table tbody td.xlsx-sel-bottom { border-bottom: 2px solid var(--accent, #4a90d9); } .xlsx-table tbody td.xlsx-sel-left { border-left: 2px solid var(--accent, #4a90d9); } .xlsx-table tbody td.xlsx-sel-right { border-right: 2px solid var(--accent, #4a90d9); } /* A one-cell selection keeps its four accent edges (a framed box) but NO fill: `.xlsx-range-multi` is toggled on the viewer by applySelection() and gates the tint, which starts at 2 cells — Google Sheets behaviour. */ .xlsx-viewer.xlsx-range-multi .xlsx-table tbody td.xlsx-selected { background: var(--accent-bg); } .xlsx-table thead th.xlsx-hdr-selected, .xlsx-table th.xlsx-rownum.xlsx-hdr-selected { background: var(--accent-bg); color: var(--accent-text, var(--accent, #4a90d9)); font-weight: 700; } /* #153 A7 — the active cell keeps its outline even when focus moves to the formula bar, so the user never loses track of what the bar edits. #154-A1 — solid (not dashed) for a stronger active-cell affordance. */ .xlsx-table td.xlsx-active:not(:focus) { outline: 2px solid var(--accent, #4a90d9); outline-offset: -2px; } /* Barre d'édition de la cellule, juste au-dessus de la grille : [ position | champ d'édition ] + recherche. Bandeau distinct du fond pour rester identifiable dans tous les thèmes (le fond transparent la rendait invisible). Elle vit DANS la barre d'outils sticky (dernier rang) : la toolbar restait sinon peinte par-dessus au défilement. */ .xlsx-formula-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; padding: 6px 8px; background: var(--surface2, var(--surface)); border: 1px solid var(--border); border-radius: 8px; } /* Dernier rang de la toolbar sticky : l'écart est déjà géré par son `gap`. */ .xlsx-toolbar .xlsx-formula-bar { margin-bottom: 0; } /* Zone d'édition : position de la cellule | champ d'édition. */ .xlsx-editbar { display: flex; align-items: center; gap: 6px; flex: 1 1 auto; min-width: 0; } /* #156-A7 — the Name Box is editable (“Atteindre”): a plain input styled like the read-only badge it replaced. */ .xlsx-active-cell { width: 84px; flex: 0 0 auto; box-sizing: border-box; padding: 4px 8px; border: 1px solid var(--grid-border, var(--border)); border-radius: 4px; background: var(--surface); color: var(--text-primary); font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace; font-size: 0.8rem; font-weight: 700; text-align: center; font-variant-numeric: tabular-nums; } .xlsx-active-cell:focus { outline: 2px solid var(--accent, #4a90d9); outline-offset: -2px; } /* Pastille « fx » façon tableur : repère visuel du champ d'édition. */ .xlsx-edit-fx { flex: 0 0 auto; font-family: Georgia, 'Times New Roman', serif; font-style: italic; font-weight: 700; font-size: 0.85rem; color: var(--text-muted); padding: 0 2px; user-select: none; } .xlsx-formula-input { flex: 1; min-width: 0; padding: 5px 10px; border: 1px solid var(--grid-border, var(--border)); border-radius: 4px; background: var(--surface); color: var(--text-primary); font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace; font-size: 0.82rem; } .xlsx-formula-input:focus { outline: 2px solid var(--accent, #4a90d9); outline-offset: -2px; } .xlsx-formula-input:disabled { opacity: 0.55; } /* #153 A13 — find-in-sheet + filter/sort controls */ .xlsx-find-group { display: flex; align-items: center; gap: 4px; margin-left: auto; min-width: 0; } .xlsx-find-input { flex: 1; min-width: 120px; max-width: 220px; padding: 4px 8px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface); color: var(--text-primary); font-size: 0.8rem; } .xlsx-find-input:focus { outline: 2px solid var(--accent, #4a90d9); outline-offset: -2px; } .xlsx-find-count { color: var(--text-muted); font-size: 0.75rem; white-space: nowrap; } .xlsx-find-btn, .xlsx-find-case, .xlsx-sort-reset { padding: 3px 8px; font-size: 0.78rem; } .xlsx-find-hit { background: var(--warning, #e0a800); color: var(--text-primary); border-radius: 2px; } .xlsx-find-current { outline: 2px solid var(--accent, #4a90d9); outline-offset: 1px; } /* #156-A11 — export menu (CSV stays a button; MD/HTML/Print live here). */ .xlsx-export-dropdown { position: relative; display: inline-block; } .xlsx-export-menu { position: absolute; right: 0; top: 100%; z-index: 1000; min-width: 200px; max-width: 86vw; padding: 4px; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18); } .xlsx-export-menu .export-menu-item { display: block; width: 100%; padding: 8px 10px; border: none; border-radius: 4px; background: none; color: var(--text-primary); cursor: pointer; text-align: left; font-size: 13px; } .xlsx-export-menu .export-menu-item:hover { background: var(--surface-hover, rgba(127, 127, 127, 0.12)); } .xlsx-print-frame { position: fixed; width: 0; height: 0; border: 0; } /* #156-A8 — formatting menu: the colour rows pair a label with the native picker (data-driven colours, no hardcoded swatch). */ .xlsx-format-menu { min-width: 230px; max-height: 70vh; overflow-y: auto; } .xlsx-format-colour { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 10px; color: var(--text-primary); font-size: 13px; cursor: pointer; } .xlsx-format-colour input[type="color"] { width: 34px; height: 22px; padding: 0; border: 1px solid var(--border); border-radius: 4px; background: var(--surface); cursor: pointer; } /* #153 A15 — freeze panes: frozen rows sit UNDER the sticky thead, frozen columns stay left. z-index mirrors thead (3) without covering it. */ .xlsx-table tr.xlsx-frozen-row td, .xlsx-table tr.xlsx-frozen-row th { position: sticky; /* Hauteur de l'en-tête + décalage toolbar sticky (`--xlsx-stick`). */ top: calc(var(--xlsx-stick, 0px) + 33px); /* thead height — keeps the frozen row below the header */ z-index: 2; background: var(--grid-header-bg, var(--bg-hover)); } .xlsx-table td.xlsx-frozen-col { position: sticky; left: 44px; /* the row-number column width */ background: var(--grid-bg, var(--surface)); } /* #153 A14 — structure menu (sheets / rows / columns) */ /* #185 — the menu-bar dropdowns share the toolbar menus' look; the toolbar menus keep the `.xlsx-structure-menu` class to themselves so `.xlsx-structure-menu` queries (viewer, tests, E2E) only ever match the open toolbar menu. */ .xlsx-structure-menu, .xlsx-menudrop { position: absolute; z-index: 30; display: flex; flex-direction: column; gap: 2px; min-width: 240px; max-width: min(320px, 92vw); /* Positioned under its toggle by anchorUnder() (viewer.js), which already adds the 4px gap. */ padding: 6px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); box-shadow: 0 8px 24px var(--shadow, rgba(0, 0, 0, 0.25)); } .xlsx-structure-item { text-align: left; border: none; background: transparent; color: var(--text-primary); } /* #154-A3 — right-hand inspector (dashboard, assistant) beside the grid. */ .xlsx-body { display: flex; align-items: stretch; gap: 10px; } .xlsx-main { flex: 1 1 auto; min-width: 0; } .xlsx-inspector { flex: 0 0 340px; width: 340px; max-width: 45%; display: none; flex-direction: column; position: relative; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); max-height: 70vh; } .xlsx-inspector.open { display: flex; } .xlsx-inspector-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); } .xlsx-inspector-title { font-weight: 600; font-size: 0.85rem; color: var(--text-primary); } .xlsx-inspector-actions { display: inline-flex; align-items: center; gap: 6px; } .xlsx-inspector-body { flex: 1 1 auto; overflow: auto; padding: 10px; } /* #154-A5 — resize handle on the inspector's left edge. */ .xlsx-inspector-resize { position: absolute; left: -3px; top: 0; bottom: 0; width: 6px; cursor: col-resize; z-index: 2; } .xlsx-inspector-resize:hover { background: color-mix(in srgb, var(--accent) 40%, transparent); } .xlsx-range-row { cursor: pointer; } .xlsx-range-row:hover td { background: var(--bg-hover); } .xlsx-inspector .xlsx-dashboard { margin: 0; padding: 0; border: none; border-radius: 0; background: transparent; } @media (max-width: 900px) { .xlsx-body { flex-direction: column; } .xlsx-inspector { flex-basis: auto; width: auto; max-width: none; } } /* #153 A17 — workbook dashboard panel: named ranges table + KPI cards. Colors come from the existing CSS variables (no hardcoded values). */ .xlsx-dashboard { margin: 8px 0; padding: 10px 12px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); } .xlsx-dashboard-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; } .xlsx-dashboard-head h3 { display: flex; align-items: center; gap: 6px; margin: 0; font-size: 0.95rem; color: var(--text-primary); } .xlsx-dashboard-objects { font-size: 0.8rem; color: var(--text-muted); } .xlsx-ranges-table { margin-bottom: 10px; font-size: 0.82rem; } .xlsx-kpi-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 8px; } .xlsx-kpi-sheet { padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-secondary); } .xlsx-kpi-sheet h4 { margin: 0 0 4px; font-size: 0.85rem; color: var(--text-primary); } .xlsx-kpi-meta { margin: 0 0 6px; font-size: 0.75rem; color: var(--text-muted); } .xlsx-kpi-cards { display: flex; flex-wrap: wrap; gap: 6px; } .xlsx-kpi { display: inline-flex; flex-direction: column; min-width: 64px; padding: 4px 8px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); } .xlsx-kpi-label { font-size: 0.7rem; color: var(--text-muted); } .xlsx-kpi-value { font-family: 'JetBrains Mono', monospace; font-size: 0.85rem; color: var(--text-primary); } .xlsx-kpi-empty { color: var(--text-muted); font-size: 0.8rem; } .xlsx-dashboard-hint { margin: 10px 0 0; font-size: 0.78rem; color: var(--text-muted); } .xlsx-dashboard-loading { color: var(--text-muted); font-size: 0.8rem; } .xlsx-structure-item:hover { background: var(--bg-secondary); } .xlsx-structure-sep { height: 1px; margin: 4px 0; background: var(--border); } /* Resize ghost: fixed guide line following the pointer while dragging a header edge (column widths / row heights). */ .xlsx-resize-ghost { position: fixed; z-index: 10060; margin: 0; background: var(--accent, #4a90d9); pointer-events: none; } .xlsx-resize-ghost[data-kind="col"] { width: 2px; } .xlsx-resize-ghost[data-kind="row"] { height: 2px; } /* Comment marker: content-free so copy/export/save text stays clean. */ .xlsx-comment-dot::after { content: "\1F4AC"; font-size: 0.68em; margin-left: 3px; vertical-align: super; cursor: help; } /* Computed formula links behave like spreadsheet links. */ .xlsx-formula-link { color: var(--accent, #4a90d9); text-decoration: underline; } /* #179 — shared menu-entry icon (grid context menu, structure, format, export). */ .xlsx-menu-icon { width: 14px; height: 14px; flex: 0 0 auto; } .xlsx-menu-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; } .xlsx-context-item, .xlsx-structure-item, .xlsx-export-menu .export-menu-item { display: flex; align-items: center; gap: 8px; } .xlsx-context-item:focus:not(:disabled), .xlsx-structure-item:focus:not(:disabled), .xlsx-export-menu .export-menu-item:focus { background: var(--bg-hover); outline: 2px solid var(--accent, #4a90d9); outline-offset: -2px; } /* #155 — Excel-like range selection + right-click / long-press context menu. Le remplissage de la sélection est déclaré plus haut et conditionné par `.xlsx-range-multi` : pas de fond teinté pour une sélection d'une cellule. */ .xlsx-viewer.xlsx-selecting, .xlsx-viewer.xlsx-selecting td { user-select: none; } .xlsx-viewer.xlsx-selecting td[contenteditable] { cursor: crosshair; } .xlsx-context-menu { position: fixed; z-index: 10050; display: flex; flex-direction: column; min-width: 220px; max-width: min(320px, 86vw); max-height: 80vh; overflow-y: auto; padding: 6px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); box-shadow: 0 12px 32px var(--shadow, rgba(0, 0, 0, 0.35)); } /* #179 — touch-sized entries + viewport-bound menus on coarse pointers. */ @media (pointer: coarse) { .xlsx-context-item, .xlsx-structure-item, .xlsx-export-menu .export-menu-item { min-height: 44px; font-size: 0.9rem; } .xlsx-context-menu { min-width: min(260px, 86vw); } .xlsx-structure-menu, .xlsx-menudrop { max-width: 92vw; } } /* #189 — mise en page mobile : par défaut seuls restent la barre des feuilles (avec le basculeur) et la barre de formule. La barre de menus et le ruban sont repliés derrière #xlsx-tools-toggle ; le groupe Recherche, logé dans la barre de formule, suit le même état pour ne pas écraser le champ de saisie. */ .xlsx-tools-toggle { display: none; } @media (max-width: 768px) { .xlsx-tools-toggle { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; height: 44px; flex: 0 0 auto; } .xlsx-menubar, .xlsx-cmdbar, .xlsx-find-group { display: none; } .xlsx-toolbar.xlsx-tools-open .xlsx-menubar { display: flex; } .xlsx-toolbar.xlsx-tools-open .xlsx-cmdbar { display: flex; } .xlsx-toolbar.xlsx-tools-open .xlsx-find-group { display: flex; } /* La barre de formule ne déborde jamais : elle passe en 2 lignes quand le groupe Recherche réapparaît avec les outils ouverts. */ .xlsx-toolbar.xlsx-tools-open .xlsx-formula-bar { flex-wrap: wrap; } /* Une seule ligne de feuilles : les onglets défilent horizontalement au lieu d'enrouler et de grignoter la hauteur de la grille. */ .xlsx-sheetbar { flex-wrap: nowrap; } .xlsx-sheetbar .xlsx-tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; } .xlsx-sheetbar .xlsx-tabs::-webkit-scrollbar { display: none; } /* Cibles tactiles : le ruban replié n'existe que derrière le basculeur, mais une fois ouvert chaque commande reste atteignable au doigt. */ .xlsx-toolbar .btn-action { min-width: 44px; height: 44px; } /* À 44px un groupe (police, nombre…) dépasse la largeur d'un téléphone : il doit pouvoir se réduire ET s'enrouler plutôt que déborder. */ .xlsx-cmdbar .xlsx-cmd-group { flex: 0 1 auto; min-width: 0; flex-wrap: wrap; } .xlsx-menubtn { padding: 12px 14px; min-height: 44px; } .xlsx-tab, .xlsx-tab-add { padding: 10px 14px; min-height: 44px; } /* 16px minimum : en dessous iOS zoome automatiquement la page dès que le champ reçoit le focus, ce qui fait « sauter » l'interface. */ .xlsx-active-cell, .xlsx-formula-input, .xlsx-find-input { font-size: 16px; } } .xlsx-context-item { text-align: left; border: none; background: transparent; color: var(--text-primary); border-radius: 4px; padding: 6px 10px; font-size: 0.82rem; cursor: pointer; } .xlsx-context-item:hover:not(:disabled) { background: var(--bg-hover); } .xlsx-context-item:disabled { opacity: 0.5; cursor: default; } .xlsx-context-danger { color: var(--danger); } .xlsx-context-sep { height: 1px; margin: 4px 0; background: var(--border); } /* #183 — Sheets-like colour panel (text + fill). The chrome follows the active theme (variables only); the swatches carry their own colour inline, which is data, not decoration. */ .xlsx-colorpick-wrap { position: relative; display: inline-flex; } .xlsx-color-native { position: absolute; width: 0; height: 0; opacity: 0; pointer-events: none; border: none; padding: 0; } .xlsx-colour-panel { position: absolute; z-index: 40; display: flex; flex-direction: column; width: 236px; padding: 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); box-shadow: 0 6px 18px var(--shadow, rgba(0, 0, 0, 0.22)); font-size: 0.8rem; } .xlsx-colour-head { display: flex; align-items: center; margin-bottom: 8px; } .xlsx-colour-reset { display: inline-flex; align-items: center; gap: 6px; padding: 4px 8px; border: 1px solid var(--border); border-radius: 6px; background: transparent; color: var(--text-secondary); font-size: 0.8rem; cursor: pointer; } .xlsx-colour-reset:hover { color: var(--accent); border-color: var(--accent); } .xlsx-colour-icon { width: 14px; height: 14px; flex: 0 0 auto; } /* 8 columns x 10 rows = the 80 curated swatches. */ .xlsx-colour-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 4px; } .xlsx-colour-swatch-btn { position: relative; width: 100%; aspect-ratio: 1 / 1; min-width: 20px; padding: 0; border: 1px solid var(--border); border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; } .xlsx-colour-swatch-btn:hover { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 55%, transparent); } .xlsx-colour-swatch-btn.selected { box-shadow: 0 0 0 2px var(--accent); } .xlsx-colour-check { width: 12px; height: 12px; pointer-events: none; } .xlsx-colour-section { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border); } .xlsx-colour-title { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; color: var(--text-muted); font-size: 0.68rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; } .xlsx-colour-row { display: flex; align-items: center; gap: 6px; } .xlsx-colour-row .xlsx-colour-swatch-btn { width: 22px; height: 22px; } .xlsx-colour-add { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; padding: 0; border: 1px dashed var(--border); border-radius: 50%; background: transparent; color: var(--text-secondary); cursor: pointer; } .xlsx-colour-add:hover { color: var(--accent); border-color: var(--accent); } .xlsx-colour-edit { display: inline-flex; align-items: center; justify-content: center; padding: 2px; border: none; border-radius: 4px; background: transparent; color: var(--text-muted); cursor: pointer; } .xlsx-colour-edit:hover { color: var(--accent); background: var(--bg-hover); } .xlsx-colour-foot { margin-top: 10px; padding-top: 6px; border-top: 1px solid var(--border); } .xlsx-colour-foot-item { display: block; width: 100%; padding: 6px 4px; border: none; border-radius: 4px; background: none; color: var(--text-primary); font-size: 0.8rem; text-align: left; cursor: pointer; } .xlsx-colour-foot-item:hover { background: var(--bg-hover); } /* Mise en forme menu: the colour rows now carry a trigger + a live dot. */ .xlsx-format-colour { display: flex; align-items: center; gap: 8px; padding: 6px 10px; color: var(--text-primary); font-size: 13px; } .xlsx-format-colour-btn { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; padding: 2px 4px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface); cursor: pointer; } .xlsx-format-colour-btn:hover { border-color: var(--accent); color: var(--accent); } .xlsx-format-colour-dot { width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--border); background: linear-gradient(135deg, var(--accent) 0%, var(--accent-green, var(--accent)) 100%); } .xlsx-colour-panel { max-height: 70vh; overflow-y: auto; } /* JSDOM shims for the tests that click anchors */ mark { font: inherit; } /* #154-A1 — scoped to tbody so a dirty cell keeps its highlight even on the zebra/hover backgrounds (specificity beats the zebra + hover rules). */ .xlsx-table tbody 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; } /* #153 A8 — "feuille tronquée" notice. Deliberately NOT the `.xlsx-warning` look: that one is a data-loss alert, this one only says part of the sheet is out of view. */ .xlsx-truncated { display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; margin: 8px 0; border: 1px solid var(--border); border-left: 3px solid var(--accent, #4a90d9); border-radius: 4px; background: var(--bg-secondary); color: var(--text-secondary); font-size: 0.82rem; line-height: 1.45; } .xlsx-truncated-icon { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 1px; color: var(--accent, #4a90d9); } /* #153 A9bis — “charger la suite” footnote under a truncated sheet. Also the scroll sentinel target: clickable whole, disabled look once the sheet is fully loaded. */ .xlsx-load-more { display: block; margin: 6px 0 10px; padding: 6px 12px; border: 1px dashed var(--border); border-radius: 4px; background: var(--bg-secondary); color: var(--text-secondary); font-size: 0.82rem; text-align: center; cursor: pointer; user-select: none; } .xlsx-load-more:hover { border-color: var(--accent, #4a90d9); color: var(--text-primary); } .xlsx-load-more.done { display: none; } .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; } /* ── #160 : Section Configuration — Vaults & dossiers (Desktop) ──────────── */ .desktop-roots-list { display: flex; flex-direction: column; gap: 8px; } .desktop-roots-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; background: var(--surface2, #1a1a2e); border: 1px solid var(--border, transparent); border-radius: 6px; transition: border-color 150ms; } .desktop-roots-item:hover { border-color: var(--accent); } .desktop-roots-icon { width: 16px; height: 16px; flex-shrink: 0; color: var(--accent); } .desktop-roots-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; } .desktop-roots-name { font-size: 0.9rem; font-weight: 600; color: var(--text, #fff); } .desktop-roots-path { font-size: 0.75rem; color: var(--text-muted, #888); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .desktop-roots-item .config-btn-sm { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; white-space: nowrap; } .desktop-roots-btn-icon { width: 14px; height: 14px; } .desktop-roots-empty { padding: 12px; font-size: 0.85rem; color: var(--text-muted, #888); background: var(--surface2, #1a1a2e); border-radius: 6px; } .desktop-roots-actions { display: flex; justify-content: flex-end; gap: 8px; } .desktop-roots-actions .config-btn-sm { display: inline-flex; align-items: center; gap: 6px; } /* 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); } /* 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; } /* --------------------------------------------------------------------------- #169 — Chat intégré par fichier (panneau latéral) --------------------------------------------------------------------------- */ .file-chat-panel { position: fixed; top: 0; right: 0; width: 340px; max-width: 100vw; height: 100vh; display: flex; flex-direction: column; background: var(--bg-primary, #0d1117); border-left: 1px solid var(--border, #21262d); box-shadow: -8px 0 24px rgba(0, 0, 0, 0.35); z-index: 1500; } .file-chat-panel.hidden { display: none; } .file-chat-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--border, #21262d); } .file-chat-header h3 { margin: 0; font-size: 0.95rem; font-weight: 600; color: var(--text-primary, #e6edf3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .file-chat-close { border: none; background: transparent; color: var(--text-muted, #8b949e); font-size: 1rem; cursor: pointer; padding: 4px 8px; border-radius: 6px; flex-shrink: 0; } .file-chat-close:hover { background: var(--bg-hover, rgba(128, 128, 128, 0.18)); color: var(--text-primary, #e6edf3); } .file-chat-list { flex: 1; overflow-y: auto; padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; } .file-chat-empty { color: var(--text-muted, #8b949e); font-size: 0.85rem; text-align: center; padding: 24px 8px; } .file-chat-msg { background: var(--bg-secondary, #161b22); border: 1px solid var(--border, #21262d); border-radius: 10px; padding: 8px 10px; max-width: 92%; } .file-chat-msg.mine { align-self: flex-end; background: var(--bg-hover, rgba(88, 166, 255, 0.12)); border-color: var(--accent, #58a6ff); } .file-chat-meta { display: flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-muted, #8b949e); margin-bottom: 4px; } .file-chat-user { font-weight: 600; color: var(--accent, #58a6ff); } /* #192 — accusé de réception sur mes messages : ✓ envoyé, ✓✓ lu */ .file-chat-status { color: var(--text-muted, #8b949e); letter-spacing: -1px; } .file-chat-status.read { color: var(--accent, #58a6ff); } .file-chat-body { font-size: 0.88rem; color: var(--text-primary, #e6edf3); white-space: pre-wrap; word-break: break-word; } /* #193 — un post peut être rendu comme un document markdown (mistune côté serveur + hljs côté client) : on annule le `pre-wrap` hérité (sinon les retours à la ligne du HTML source deviennent des lignes vides) et on compacte la typographie `.md-content` pour une bulle de chat. */ .file-chat-body.file-chat-md { white-space: normal; word-break: normal; } .file-chat-body .md-content > :first-child { margin-top: 0; } .file-chat-body .md-content > :last-child { margin-bottom: 0; } .file-chat-body .md-content h1, .file-chat-body .md-content h2, .file-chat-body .md-content h3, .file-chat-body .md-content h4, .file-chat-body .md-content h5, .file-chat-body .md-content h6 { font-size: 1rem; margin: 0.7em 0 0.35em; border-bottom: none; padding-bottom: 0; } .file-chat-body .md-content p { margin: 0.4em 0; } .file-chat-body .md-content ul, .file-chat-body .md-content ol { padding-left: 1.3em; margin: 0.4em 0; } .file-chat-body .md-content pre { max-width: 100%; overflow-x: auto; margin: 0.5em 0; } .file-chat-body .md-content pre code { font-size: 0.78rem; line-height: 1.45; } .file-chat-body .md-content :not(pre) > code { font-size: 0.82rem; padding: 1px 4px; border-radius: 4px; background: var(--bg-hover, rgba(128, 128, 128, 0.15)); } .file-chat-body .md-content table { display: block; max-width: 100%; overflow-x: auto; border-collapse: collapse; font-size: 0.82rem; } .file-chat-body .md-content img { max-width: 100%; border-radius: 6px; } .file-chat-body .md-content .wikilink, .file-chat-body .md-content .wikilink-anchor { color: var(--accent, #58a6ff); cursor: pointer; } .file-chat-form { display: flex; gap: 8px; padding: 10px 14px; border-top: 1px solid var(--border, #21262d); } .file-chat-input { flex: 1; min-width: 0; padding: 8px 10px; font-size: 16px; /* anti-zoom iOS */ font-family: inherit; line-height: 1.4; border: 1px solid var(--border, #21262d); border-radius: 8px; background: var(--bg-secondary, #161b22); color: var(--text-primary, #e6edf3); } /* #192 — textarea auto-agrandie (hauteur pilotée en JS, plafond ci-dessous) */ textarea.file-chat-input { display: block; resize: none; overflow-y: auto; max-height: 160px; white-space: pre-wrap; word-break: break-word; } .file-chat-input:focus { outline: none; border-color: var(--accent, #58a6ff); } .file-chat-send { border: none; border-radius: 8px; padding: 8px 14px; font-size: 0.85rem; font-weight: 600; cursor: pointer; background: var(--accent, #58a6ff); color: #fff; flex-shrink: 0; } .file-chat-send:disabled { opacity: 0.6; cursor: default; } @media (max-width: 768px) { .file-chat-panel { width: 100vw; border-left: none; } } /* --------------------------------------------------------------------------- #191 — Chat : canaux, suppression, bouton compact, link preview --------------------------------------------------------------------------- */ .chat-channels { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 10px 0; } .chat-channel { border: 1px solid var(--border, #21262d); border-radius: 999px; background: var(--bg-secondary, #161b22); color: var(--text-muted, #8b949e); font-size: 0.78rem; padding: 4px 10px; cursor: pointer; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .chat-channel:hover { color: var(--text-primary, #e6edf3); border-color: var(--accent, #58a6ff); } .chat-channel.active { background: var(--accent, #58a6ff); border-color: var(--accent, #58a6ff); color: #fff; } /* Bouton d'envoi compact : une icône, la saisie garde la largeur */ .file-chat-send-icon { padding: 6px 8px; display: flex; align-items: center; justify-content: center; } /* Suppression d'un post */ .file-chat-del { border: none; background: var(--bg-hover, #1f2430); cursor: pointer; font-size: 0.72rem; padding: 2px 6px; border-radius: 4px; opacity: 0.6; transition: opacity 0.15s, background 0.15s; color: var(--danger, #ff7b72); line-height: 1; margin-left: auto; /* #110 — l'action se détache à droite de la ligne */ } .file-chat-msg:hover .file-chat-del { opacity: 1; } .file-chat-del:hover { opacity: 1 !important; background: var(--danger-bg, #3d1a18); } /* Link preview (#191) */ .file-chat-preview { display: flex; gap: 10px; margin-top: 8px; padding: 8px; border: 1px solid var(--border, #21262d); border-left: 3px solid var(--accent, #58a6ff); border-radius: 8px; background: var(--bg-secondary, #161b22); text-decoration: none; color: inherit; max-width: 100%; } .file-chat-preview:hover { border-color: var(--accent, #58a6ff); } .file-chat-preview-img { width: 72px; height: 72px; object-fit: cover; border-radius: 6px; flex-shrink: 0; background: var(--bg-hover, rgba(128, 128, 128, 0.12)); } .file-chat-preview-meta { min-width: 0; display: flex; flex-direction: column; gap: 2px; } .file-chat-preview-site { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--accent, #58a6ff); } .file-chat-preview-title { font-size: 0.85rem; font-weight: 600; color: var(--text-primary, #e6edf3); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } .file-chat-preview-desc { font-size: 0.75rem; color: var(--text-muted, #8b949e); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } /* --------------------------------------------------------------------------- #190 — Chat : en-tête ciblé, onglet sidebar, pièces jointes, badge --------------------------------------------------------------------------- */ .file-chat-titles { display: flex; flex-direction: column; gap: 2px; min-width: 0; } .file-chat-target { font-size: 0.72rem; color: var(--text-muted, #8b949e); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .sidebar-tab { position: relative; } /* #110 — point de couleur sur l'icône chat tant qu'il reste des non-lus */ .sidebar-tab#sidebar-tab-chat.chat-has-unread::after { content: ""; position: absolute; top: 3px; left: 6px; width: 8px; height: 8px; border-radius: 50%; background: var(--danger, #e5534b); animation: chat-dot-pulse 1.8s ease-out infinite; } @keyframes chat-dot-pulse { 0% { box-shadow: 0 0 0 0 rgba(229, 83, 75, 0.5); } 70% { box-shadow: 0 0 0 6px rgba(229, 83, 75, 0); } 100% { box-shadow: 0 0 0 0 rgba(229, 83, 75, 0); } } .chat-unread-badge { position: absolute; top: 2px; right: 2px; min-width: 15px; height: 15px; padding: 0 3px; border-radius: 8px; background: #e5534b; color: #fff; font-size: 0.62rem; font-weight: 700; line-height: 15px; text-align: center; pointer-events: none; } .sidebar-chat-panel { display: none; flex-direction: column; flex: 1; min-height: 0; } .sidebar-chat-panel.active { display: flex; } .sidebar-chat-list { flex: 1; min-height: 0; overflow-y: auto; padding: 10px; } .sidebar-chat-pending { padding: 0 10px; } .sidebar-chat-form { display: flex; gap: 6px; padding: 8px 10px; border-top: 1px solid var(--border, #21262d); } .file-chat-attach { border: 1px solid var(--border, #21262d); border-radius: 8px; background: var(--bg-secondary, #161b22); color: var(--text-muted, #8b949e); cursor: pointer; padding: 6px; display: flex; align-items: center; flex-shrink: 0; } .file-chat-attach:hover { color: var(--accent, #58a6ff); border-color: var(--accent, #58a6ff); } .file-chat-pending { display: inline-flex; align-items: center; gap: 6px; margin: 4px 0; padding: 3px 8px; border: 1px dashed var(--border, #21262d); border-radius: 8px; font-size: 0.75rem; color: var(--text-muted, #8b949e); } .file-chat-pending button { border: none; background: transparent; color: inherit; cursor: pointer; } .file-chat-image-container { max-width: 100%; margin-top: 6px; } .file-chat-image-container .file-chat-image { display: block; max-width: 100%; max-height: 220px; border-radius: 8px; cursor: zoom-in; } /* Boutons discrets : icônes seules, sous l'image, alignés à droite */ .file-chat-image-actions { display: flex; justify-content: flex-end; gap: 2px; margin-top: 2px; } .file-chat-image-btn { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; border: none; border-radius: 4px; background: transparent; color: var(--text-muted, #8b949e); opacity: 0.55; cursor: pointer; transition: opacity 0.15s, color 0.15s, background 0.15s; } .file-chat-image-btn:hover { opacity: 1; color: var(--accent, #58a6ff); background: var(--bg-hover, rgba(128, 128, 128, 0.12)); } .file-chat-image-btn i { flex-shrink: 0; } .file-chat-video { max-width: 100%; max-height: 240px; border-radius: 8px; margin-top: 6px; display: block; }.file-chat-link { color: var(--accent, #58a6ff); word-break: break-all; } /* #110 — message supprimé avec bouton Undo */ .file-chat-deleted { opacity: 0.7; background: var(--bg-hover, #1f2430); border-left: 2px solid var(--text-muted, #484f58); padding: 4px 8px; border-radius: 4px; margin: 4px 0; } .file-chat-deleted-text { font-style: italic; color: var(--text-muted, #8b949e); font-size: 0.85rem; } .file-chat-undo { background: var(--accent, #58a6ff); color: #fff; border: none; border-radius: 4px; padding: 2px 8px; font-size: 0.72rem; cursor: pointer; margin-left: 6px; transition: background 0.15s; vertical-align: middle; } .file-chat-undo:hover { background: var(--accent-hover, #4494e6); } .file-chat-undo i { margin-right: 3px; }