* { margin: 0; padding: 0; box-sizing: border-box; } html, body { height: 100%; font-family: var(--font-ui); font-size: 14px; color: var(--text); background: var(--bg); overflow: hidden; user-select: none; } #app { display: flex; flex-direction: column; height: 100vh; } /* Toolbar */ #toolbar { height: var(--toolbar-height); background: var(--bg); border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; padding: 0 8px; flex-shrink: 0; z-index: 10; } .toolbar-left, .toolbar-right { display: flex; align-items: center; gap: 2px; } .toolbar-btn { display: flex; align-items: center; gap: 5px; padding: 6px 12px; border: none; background: transparent; color: var(--text-secondary); font-size: 13px; font-family: var(--font-ui); border-radius: var(--radius); cursor: pointer; transition: all 0.15s ease; white-space: nowrap; } .toolbar-btn:hover { background: var(--bg-tertiary); color: var(--text); } .toolbar-btn.active { background: var(--primary-light); color: var(--primary); } .toolbar-btn svg { flex-shrink: 0; } .toolbar-divider { width: 1px; height: 24px; background: var(--border); margin: 0 6px; } /* Workspace */ #workspace { flex: 1; display: flex; flex-direction: row; overflow: hidden; min-height: 0; } #main-content { flex: 1; display: flex; flex-direction: column; overflow: hidden; position: relative; min-width: 0; } #content-wrapper { flex: 1; display: flex; flex-direction: row; overflow: hidden; min-height: 0; } /* Editor Panel */ #editor-panel { flex: 1; display: flex; flex-direction: column; min-width: 0; border-right: 1px solid var(--border); } /* Editor Container */ .editor-container { flex: 1; display: flex; flex-direction: column; overflow: hidden; } /* Editor Toolbar */ .editor-toolbar { display: flex; align-items: center; gap: 2px; padding: 4px 8px; background: var(--bg-secondary); border-bottom: 1px solid var(--border-light); flex-shrink: 0; overflow-x: auto; } .editor-toolbar::-webkit-scrollbar { height: 0; } .toolbar-btn-sm { display: flex; align-items: center; justify-content: center; min-width: 28px; height: 26px; padding: 0 6px; border: none; background: transparent; color: var(--text-secondary); font-size: 12px; font-family: var(--font-ui); border-radius: 4px; cursor: pointer; transition: all 0.15s ease; white-space: nowrap; } .toolbar-btn-sm:hover { background: var(--bg-tertiary); color: var(--text); } .toolbar-divider-sm { width: 1px; height: 20px; background: var(--border); margin: 0 4px; } /* CodeMirror Wrapper */ .codemirror-wrapper { flex: 1; overflow: hidden; } .codemirror-wrapper .cm-editor { height: 100%; font-family: var(--font-mono); font-size: 13px; } .codemirror-wrapper .cm-editor .cm-scroller { overflow: auto; } .codemirror-wrapper .cm-editor .cm-content { padding: 12px 0; } .codemirror-wrapper .cm-editor .cm-line { padding: 0 16px; } .codemirror-wrapper .cm-editor .cm-gutters { background: var(--bg-secondary); border-right: 1px solid var(--border-light); color: var(--text-tertiary); font-size: 12px; min-width: 40px; } .codemirror-wrapper .cm-editor .cm-activeLineGutter { background: var(--bg-tertiary); color: var(--text-secondary); } .codemirror-wrapper .cm-editor .cm-activeLine { background: var(--bg-tertiary); } .codemirror-wrapper .cm-editor.cm-focused { outline: none; } /* ===== CodeMirror 搜索样式美化 ===== */ /* 搜索面板移到顶部 */ .cm-panels { top: 0 !important; bottom: auto !important; } .cm-panels-bottom { top: 0 !important; bottom: auto !important; border-bottom: 1px solid var(--border) !important; border-top: none !important; } /* 搜索面板整体 */ .cm-panel.cm-search { background: var(--bg) !important; border-bottom: 1px solid var(--border) !important; padding: 8px 12px !important; font-family: var(--font-ui) !important; font-size: 13px !important; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); } /* 搜索输入框 */ .cm-panel .cm-textfield { background: var(--bg-secondary) !important; border: 1px solid var(--border) !important; border-radius: 4px !important; padding: 4px 8px !important; font-size: 13px !important; font-family: var(--font-ui) !important; color: var(--text) !important; outline: none !important; transition: border-color 0.15s ease !important; height: 28px !important; } .cm-panel .cm-textfield:focus { border-color: var(--primary) !important; box-shadow: 0 0 0 2px rgba(26, 115, 232, 0.15) !important; } /* 搜索按钮 */ .cm-panel .cm-button { background: var(--bg-secondary) !important; border: 1px solid var(--border) !important; border-radius: 4px !important; color: var(--text-secondary) !important; font-size: 12px !important; font-family: var(--font-ui) !important; padding: 4px 10px !important; cursor: pointer !important; transition: all 0.15s ease !important; height: 28px !important; line-height: 1 !important; } .cm-panel .cm-button:hover { background: var(--bg-tertiary) !important; color: var(--text) !important; border-color: var(--text-tertiary) !important; } .cm-panel .cm-button:active { background: var(--primary-light) !important; color: var(--primary) !important; } /* 搜索选项复选框(区分大小写、正则、全字匹配) */ .cm-search label { display: inline-flex !important; align-items: center !important; gap: 5px !important; font-size: 13px !important; font-family: var(--font-ui) !important; color: var(--text-secondary) !important; cursor: pointer !important; user-select: none !important; vertical-align: middle !important; line-height: 1 !important; margin: 0 6px 0 0 !important; padding: 2px 0 !important; } .cm-search input[type="checkbox"] { -webkit-appearance: none !important; appearance: none !important; width: 18px !important; height: 18px !important; border: 1.5px solid var(--border) !important; border-radius: 4px !important; background: var(--bg) !important; cursor: pointer !important; position: relative !important; flex-shrink: 0 !important; vertical-align: middle !important; margin: 0 !important; transition: all 0.15s ease !important; } .cm-search input[type="checkbox"]:hover { border-color: var(--primary) !important; } .cm-search input[type="checkbox"]:checked { background: var(--primary) !important; border-color: var(--primary) !important; } .cm-search input[type="checkbox"]:checked::after { content: '' !important; position: absolute !important; left: 5px !important; top: 2px !important; width: 6px !important; height: 10px !important; border: solid white !important; border-width: 0 2px 2px 0 !important; transform: rotate(45deg) !important; } /* 搜索结果计数 */ .cm-panel .cm-search-info { color: var(--text-tertiary) !important; font-size: 11px !important; font-family: var(--font-ui) !important; padding: 0 8px !important; white-space: nowrap !important; } /* 关闭按钮 — 注意:CodeMirror 关闭按钮用的是 name="close",没有 cm-close class */ .cm-panel [name="close"] { position: absolute !important; top: 4px !important; right: 4px !important; color: var(--text-tertiary) !important; font-size: 22px !important; line-height: 1 !important; cursor: pointer !important; padding: 4px 6px !important; border-radius: 4px !important; border: none !important; background: transparent !important; transition: all 0.15s ease !important; z-index: 1 !important; } .cm-panel [name="close"]:hover { background: var(--bg-tertiary) !important; color: var(--text) !important; } /* 替换按钮组 */ .cm-panel .cm-replace, .cm-panel .cm-replaceAll { background: var(--bg-secondary) !important; border: 1px solid var(--border) !important; border-radius: 4px !important; color: var(--text-secondary) !important; font-size: 12px !important; padding: 4px 8px !important; cursor: pointer !important; transition: all 0.15s ease !important; } .cm-panel .cm-replace:hover, .cm-panel .cm-replaceAll:hover { background: var(--bg-tertiary) !important; color: var(--text) !important; } /* 搜索高亮匹配 */ .cm-searchMatch { background: rgba(255, 220, 0, 0.35) !important; border-radius: 2px !important; outline: 1px solid rgba(255, 220, 0, 0.5) !important; } .cm-searchMatch.cm-searchMatch-selected { background: rgba(255, 150, 0, 0.55) !important; outline: 2px solid rgba(255, 150, 0, 0.8) !important; } /* 暗色主题适配 */ :root.dark .cm-searchMatch { background: rgba(255, 220, 0, 0.2) !important; outline-color: rgba(255, 220, 0, 0.3) !important; } :root.dark .cm-searchMatch.cm-searchMatch-selected { background: rgba(255, 150, 0, 0.35) !important; outline-color: rgba(255, 150, 0, 0.6) !important; } :root.dark .cm-panel { background: var(--bg-secondary) !important; border-color: var(--border) !important; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3) !important; } :root.dark .cm-panel .cm-textfield { background: var(--bg-tertiary) !important; border-color: var(--border) !important; } :root.dark .cm-panel .cm-button, :root.dark .cm-panel .cm-replace, :root.dark .cm-panel .cm-replaceAll { background: var(--bg-tertiary) !important; border-color: var(--border) !important; color: var(--text-secondary) !important; } :root.dark .cm-panel .cm-button:hover, :root.dark .cm-panel .cm-replace:hover, :root.dark .cm-panel .cm-replaceAll:hover { background: var(--border) !important; color: var(--text) !important; } /* Fold gutter */ .cm-foldGutter .cm-gutterElement { cursor: pointer; opacity: 0.5; } .cm-foldGutter .cm-gutterElement:hover { opacity: 1; } /* Selection — 必须匹配oneDark主题的选择器特异性才能覆盖 */ .cm-selectionBackground { background: rgba(26, 115, 232, 0.25) !important; } .cm-editor.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-editor.cm-focused .cm-selectionBackground, .cm-content ::selection { background: rgba(26, 115, 232, 0.3) !important; } :root.dark .cm-selectionBackground { background: rgba(100, 160, 255, 0.25) !important; } :root.dark .cm-editor.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, :root.dark .cm-editor.cm-focused .cm-selectionBackground, :root.dark .cm-content ::selection { background: rgba(100, 160, 255, 0.35) !important; } .cm-editor .cm-content { user-select: text !important; -webkit-user-select: text !important; } .cm-editor .cm-cursor { border-left-color: var(--text); } /* Preview Panel */ #preview-panel { flex: 1; overflow-y: auto; min-width: 0; background: var(--bg); } #preview { padding: 24px 32px; user-select: text; cursor: text; } /* Tab Bar */ #tab-bar { height: 36px; background: var(--bg-secondary); border-bottom: 1px solid var(--border); display: flex; align-items: flex-end; padding: 0 4px; flex-shrink: 0; overflow: hidden; } #tab-list { display: flex; align-items: flex-end; gap: 1px; flex: 1; min-width: 0; overflow-x: auto; overflow-y: hidden; scroll-behavior: auto; } /* 滚动条样式 */ #tab-list::-webkit-scrollbar { height: 4px; } #tab-list::-webkit-scrollbar-thumb { background: var(--text-tertiary); border-radius: 2px; } #tab-list::-webkit-scrollbar-thumb:hover { background: var(--text-secondary); } #tab-list::-webkit-scrollbar-track { background: var(--bg-tertiary); } #tab-list::-webkit-scrollbar-thumb:hover { background: var(--text-tertiary); } #tab-list::-webkit-scrollbar-track { background: transparent; } .tab-item { display: flex; align-items: center; gap: 6px; padding: 6px 12px; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--text-secondary); font-size: 12px; font-family: var(--font-ui); cursor: pointer; white-space: nowrap; max-width: 180px; min-width: 60px; flex-shrink: 0; transition: all 0.15s ease; position: relative; } .tab-item:hover { color: var(--text); background: var(--bg-tertiary); } .tab-item.active { color: var(--text); background: var(--bg); border-bottom-color: var(--primary); } .tab-item.modified .tab-name::after { content: ' •'; color: var(--primary); } .tab-name { overflow: hidden; text-overflow: ellipsis; pointer-events: none; } .tab-close { display: flex; align-items: center; justify-content: center; width: 16px; height: 16px; border: none; background: transparent; color: var(--text-tertiary); border-radius: 3px; cursor: pointer; flex-shrink: 0; padding: 0; opacity: 0; transition: all 0.1s ease; } .tab-item:hover .tab-close, .tab-item.active .tab-close, .tab-item.modified .tab-close { opacity: 1; } .tab-close:hover { background: var(--border); color: var(--text); } .tab-add-btn { display: flex; align-items: center; justify-content: center; width: 28px; height: 28px; border: none; background: transparent; color: var(--text-secondary); border-radius: var(--radius); cursor: pointer; margin-left: 2px; margin-bottom: 4px; flex-shrink: 0; transition: all 0.15s ease; } .tab-add-btn:hover { background: var(--bg-tertiary); color: var(--text); } /* Tab Context Menu */ .tab-context-menu { position: fixed; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: 4px 0; min-width: 160px; z-index: 9999; font-size: 13px; font-family: var(--font-ui); } .tab-context-item { padding: 6px 16px; cursor: pointer; color: var(--text); white-space: nowrap; transition: background 0.1s ease; } .tab-context-item:hover { background: var(--primary-light); color: var(--primary); } .tab-context-divider { height: 1px; background: var(--border); margin: 4px 0; } /* Modified Banner */ #modified-banner { display: flex; align-items: center; gap: 12px; padding: 6px 12px; background: #fff3cd; border-bottom: 1px solid #ffc107; font-size: 13px; color: #856404; flex-shrink: 0; } :root.dark #modified-banner { background: #3a3000; border-bottom-color: #665500; color: #ffd54f; } .banner-btn { padding: 2px 10px; border: 1px solid #ffc107; border-radius: 4px; background: transparent; color: #856404; font-size: 12px; cursor: pointer; font-family: var(--font-ui); } :root.dark .banner-btn { border-color: #665500; color: #ffd54f; } .banner-btn:hover { background: #ffc107; color: #000; } :root.dark .banner-btn:hover { background: #665500; color: #ffd54f; } /* Status Bar */ #statusbar { height: var(--statusbar-height); background: var(--bg-secondary); border-top: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; padding: 0 12px; font-size: 12px; color: var(--text-secondary); flex-shrink: 0; } .status-left, .status-right { display: flex; align-items: center; gap: 8px; } .status-divider { color: var(--border); } /* Drop Overlay */ #drop-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(26, 115, 232, 0.1); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: 1000; border: 3px dashed var(--primary); margin: 8px; border-radius: 12px; } .drop-content { text-align: center; color: var(--primary); } .drop-content svg { margin-bottom: 12px; opacity: 0.7; } .drop-content p { font-size: 18px; font-weight: 500; } /* Welcome Screen */ #welcome-screen { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; background: var(--bg); z-index: 5; } .welcome-content { text-align: center; max-width: 480px; padding: 40px; animation: fadeIn 0.3s ease; } .welcome-icon { margin-bottom: 24px; } .welcome-content h1 { font-size: 28px; font-weight: 600; color: var(--text); margin-bottom: 8px; } .welcome-content > p { font-size: 16px; color: var(--text-secondary); margin-bottom: 32px; } .welcome-actions { display: flex; gap: 12px; justify-content: center; margin-bottom: 32px; } .welcome-btn { display: flex; align-items: center; gap: 8px; padding: 10px 24px; border: none; border-radius: var(--radius); font-size: 14px; font-family: var(--font-ui); font-weight: 500; cursor: pointer; transition: all 0.15s ease; } .welcome-btn.primary { background: var(--primary); color: white; } .welcome-btn.primary:hover { background: var(--primary-dark); box-shadow: var(--shadow-lg); } .welcome-btn.secondary { background: var(--bg-secondary); color: var(--text); border: 1px solid var(--border); } .welcome-btn.secondary:hover { background: var(--bg-tertiary); } /* 最近打开文件 */ .welcome-recent { text-align: left; margin-bottom: 24px; } .welcome-recent h3 { font-size: 13px; font-weight: 600; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 8px; } .recent-list { background: var(--bg-secondary); border: 1px solid var(--border-light); border-radius: var(--radius); overflow: hidden; max-height: 200px; overflow-y: auto; } .recent-item { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 12px; border: none; background: transparent; color: var(--text); font-size: 13px; font-family: var(--font-ui); cursor: pointer; text-align: left; transition: background 0.1s ease; border-bottom: 1px solid var(--border-light); } .recent-item:last-child { border-bottom: none; } .recent-item:hover { background: var(--bg-tertiary); } .recent-icon { flex-shrink: 0; color: var(--text-tertiary); } .recent-name { flex-shrink: 0; font-weight: 500; } .recent-path { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-tertiary); font-size: 11px; margin-left: auto; } .welcome-tips { text-align: left; background: var(--bg-secondary); border-radius: var(--radius); padding: 16px 20px; border: 1px solid var(--border-light); } .welcome-tips p { font-size: 13px; color: var(--text-secondary); margin-bottom: 6px; } .welcome-tips p:last-child { margin-bottom: 0; } /* Sidebar */ #sidebar { width: var(--sidebar-width); min-width: 180px; max-width: 500px; background: var(--sidebar-bg); border-right: 1px solid var(--sidebar-border); display: flex; flex-direction: column; flex-shrink: 0; overflow: hidden; user-select: none; position: relative; } #sidebar.collapsed { display: none; } #sidebar-header { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; border-bottom: 1px solid var(--sidebar-border); flex-shrink: 0; } #sidebar-title { font-size: 12px; font-weight: 600; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.5px; } .sidebar-header-btn { display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; border: none; background: transparent; color: var(--text-secondary); border-radius: 4px; cursor: pointer; transition: all 0.15s ease; } .sidebar-header-btn:hover { background: var(--sidebar-hover); color: var(--text); } #sidebar-tree { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 4px 0; } .tree-item { display: flex; align-items: center; padding: 3px 8px 3px 0; cursor: pointer; font-size: 13px; color: var(--text); white-space: nowrap; transition: background 0.1s ease; border-radius: 0; } .tree-item:hover { background: var(--sidebar-hover); } .tree-item.active { background: var(--sidebar-active); color: var(--primary); font-weight: 500; } .tree-indent { flex-shrink: 0; } .tree-arrow { display: flex; align-items: center; justify-content: center; width: 16px; height: 16px; flex-shrink: 0; color: var(--text-tertiary); transition: transform 0.15s ease; } .tree-arrow.expanded { transform: rotate(90deg); } .tree-icon { display: flex; align-items: center; justify-content: center; width: 16px; height: 16px; flex-shrink: 0; margin-right: 4px; } .tree-icon svg { width: 14px; height: 14px; } .tree-name { overflow: hidden; text-overflow: ellipsis; } /* Independent Files Section */ .independent-files-section { border-bottom: 1px solid var(--border); margin-bottom: 4px; padding-bottom: 4px; } .sidebar-section-header, .independent-files-header { font-size: 11px; font-weight: 600; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: 0.5px; padding: 8px 12px 4px 12px; } .independent-file-item .independent-modified-dot { color: var(--primary); font-size: 14px; margin-left: 4px; } .sidebar-resize-handle { position: absolute; top: 0; right: -2px; width: 4px; height: 100%; cursor: col-resize; z-index: 5; } .sidebar-resize-handle:hover, .sidebar-resize-handle:active { background: var(--primary); } /* View Modes */ #app.mode-preview #editor-panel { display: none; } #app.mode-editor #preview-panel { display: none; } /* Toast */ #toast-notification { position: fixed; bottom: 40px; left: 50%; transform: translateX(-50%) translateY(20px); background: var(--text); color: var(--bg); padding: 8px 20px; border-radius: 6px; font-size: 13px; font-family: var(--font-ui); box-shadow: var(--shadow-lg); opacity: 0; pointer-events: none; transition: opacity 0.3s ease, transform 0.3s ease; z-index: 9999; max-width: 480px; text-align: center; } #toast-notification.show { opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto; } /* Scrollbar */ ::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: var(--text-tertiary); } /* Animations */ @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } /* About Dialog */ .about-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; animation: fadeIn 0.2s ease; } .about-dialog { background: var(--bg); border-radius: 12px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2); padding: 32px; width: 360px; max-width: 90vw; text-align: center; animation: fadeIn 0.2s ease; } .about-header { margin-bottom: 20px; } .about-header h2 { margin: 12px 0 4px; font-size: 24px; font-weight: 600; color: var(--text); } .about-version { display: inline-block; background: var(--primary-light); color: var(--primary); padding: 2px 10px; border-radius: 12px; font-size: 13px; font-weight: 500; } .about-body { margin-bottom: 20px; } .about-body > p { color: var(--text-secondary); font-size: 14px; margin-bottom: 16px; } .about-features { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; } .about-features span { background: var(--bg-secondary); color: var(--text-secondary); padding: 4px 12px; border-radius: 6px; font-size: 12px; border: 1px solid var(--border-light); } .about-footer { padding-top: 16px; border-top: 1px solid var(--border-light); margin-bottom: 20px; } .about-link { display: inline-flex; align-items: center; gap: 6px; color: var(--primary); text-decoration: none; font-size: 13px; margin-bottom: 8px; padding: 6px 12px; border-radius: 6px; background: var(--primary-light); transition: all 0.15s ease; cursor: pointer; } .about-link:hover { background: var(--primary); color: white; } .about-footer p { color: var(--text-tertiary); font-size: 12px; margin: 4px 0; } .about-copyright { font-weight: 500; } .about-close-btn { width: 100%; padding: 10px; background: var(--primary); color: white; border: none; border-radius: 8px; font-size: 14px; font-family: var(--font-ui); font-weight: 500; cursor: pointer; transition: background 0.15s ease; } .about-close-btn:hover { background: var(--primary-dark); } /* ===== UX-01: ConfirmDialog ===== */ .confirm-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: 10001; animation: fadeIn 0.15s ease; } .confirm-dialog { background: var(--bg); border-radius: 12px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25); width: 380px; max-width: 90vw; overflow: hidden; animation: fadeIn 0.15s ease; } .confirm-header { padding: 20px 24px 0; } .confirm-header h3 { font-size: 16px; font-weight: 600; color: var(--text); margin: 0; } .confirm-header.confirm-danger h3 { color: #d93025; } .confirm-header.confirm-warning h3 { color: #e37400; } :root.dark .confirm-header.confirm-warning h3 { color: #fdd663; } .confirm-body { padding: 12px 24px 20px; } .confirm-body p { font-size: 14px; color: var(--text-secondary); margin: 0; line-height: 1.5; } .confirm-actions { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 24px 20px; } .confirm-btn { padding: 8px 20px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; font-family: var(--font-ui); font-weight: 500; cursor: pointer; transition: all 0.15s ease; background: var(--bg); color: var(--text); } .confirm-btn-cancel:hover { background: var(--bg-tertiary); } .confirm-btn-danger { background: #d93025; border-color: #d93025; color: white; } .confirm-btn-danger:hover { background: #b5271d; } .confirm-btn-warning { background: var(--primary); border-color: var(--primary); color: white; } .confirm-btn-warning:hover { background: var(--primary-dark); } .confirm-btn-info { background: var(--primary); border-color: var(--primary); color: white; } .confirm-btn-info:hover { background: var(--primary-dark); } .confirm-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; } /* ===== UX-02: LoadingSpinner ===== */ .loading-spinner { display: inline-flex; align-items: center; gap: 8px; color: var(--text-secondary); } .loading-spinner-svg { animation: spin 0.8s linear infinite; } .loading-spinner-label { font-size: 13px; font-family: var(--font-ui); color: var(--text-secondary); } .loading-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.8); display: flex; align-items: center; justify-content: center; z-index: 10; } :root.dark .loading-overlay { background: rgba(30, 30, 30, 0.8); } .preview-loading { display: flex; align-items: center; justify-content: center; padding: 40px 0; color: var(--text-tertiary); } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } /* Status bar loading indicator */ .status-loading { display: inline-flex; align-items: center; gap: 4px; color: var(--primary); font-size: 12px; } .status-loading .loading-spinner-svg { animation: spin 0.8s linear infinite; } /* ===== UX-05: Toast Container (升级版) ===== */ .toast-container { position: fixed; bottom: 44px; left: 50%; transform: translateX(-50%); display: flex; flex-direction: column-reverse; gap: 8px; z-index: 9999; pointer-events: none; max-width: 480px; width: 100%; padding: 0 16px; } .toast-item { display: flex; align-items: center; gap: 10px; padding: 10px 16px; border-radius: 8px; font-size: 13px; font-family: var(--font-ui); box-shadow: var(--shadow-lg); opacity: 0; transform: translateY(10px) scale(0.95); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); pointer-events: auto; max-width: 100%; } .toast-item.toast-visible { opacity: 1; transform: translateY(0) scale(1); } /* Toast 类型样式 */ .toast-success { background: #e6f4ea; color: #137333; border: 1px solid #a8dab5; } .toast-error { background: #fce8e6; color: #c5221f; border: 1px solid #f28b82; } .toast-warning { background: #fef7e0; color: #945700; border: 1px solid #fdd663; } .toast-info { background: var(--text); color: var(--bg); border: 1px solid transparent; } :root.dark .toast-success { background: #0d3a1a; color: #81c995; border-color: #1e5a2e; } :root.dark .toast-error { background: #3c1214; color: #f28b82; border-color: #5c1a1a; } :root.dark .toast-warning { background: #3a3000; color: #fdd663; border-color: #5a4a00; } :root.dark .toast-info { background: var(--bg-secondary); color: var(--text); border-color: var(--border); } .toast-icon { flex-shrink: 0; width: 18px; height: 18px; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700; } .toast-message { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .toast-close { flex-shrink: 0; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; border: none; background: transparent; color: inherit; opacity: 0.6; cursor: pointer; font-size: 12px; border-radius: 4px; padding: 0; transition: opacity 0.15s ease; } .toast-close:hover { opacity: 1; } .toast-close:focus-visible { outline: 2px solid currentColor; outline-offset: 1px; } /* ===== UX-07: 通用可访问性增强 ===== */ /* Focus visible 为所有交互元素提供清晰的焦点指示 */ button:focus-visible, [role="treeitem"]:focus-visible, [role="tab"]:focus-visible, [role="menuitem"]:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; } /* 确保 tab 上的关闭按钮也有焦点指示 */ .tab-close:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; } /* 确保上下文菜单项有焦点指示 */ .tab-context-item:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; } /* Skip to content 链接(可选,用于键盘导航) */ .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }