From 77ae7ce8881cfbbd47e20a7f1b8beccbefc84f64 Mon Sep 17 00:00:00 2001 From: DemonGatanjieu <1027066412@qq.com> Date: Wed, 16 Sep 2026 11:27:19 +0800 Subject: [PATCH] fix(ui): keep update guide manual and clean sidebar styles Keep a persistent header guide button, restore upward label transitions, remove duplicate CSS and obsolete notice events, and move replay styling to CSS. Document proportional UX checks and interruption recovery checkpoints. Validated update_guide.mjs, 48-module parse/link check, diff check, and live ComfyUI manual open, Escape, replay, Help and sidebar keyboard labels. No backend behavior changed; mobile and alternate themes were not exercised. --- AGENTS.md | 16 + CHANGELOG.md | 2 +- docs/architecture/frontend.md | 4 +- docs/architecture/update-guide.md | 17 +- web/main.js | 3 +- web/modules/locales.js | 6 +- web/modules/ui_sidebar.js | 58 +--- web/modules/ui_update_guide.js | 5 +- web/styles.css | 473 +++++++++--------------------- 9 files changed, 177 insertions(+), 407 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 7b7f70e..9d49092 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,6 +12,22 @@ UX 请求默认允许调整布局、交互和文案,不代表允许改变文件存储位置、接口协议、工作流语义、模型识别依据或用户数据。 +### 小型 UX 修改快速流程 + +仅调整文案、图标、颜色、间距或局部交互时:查看相关差异 → 定位负责规则 → 最小修改 → 验证受影响界面 → 本地提交。 +同一任务已读过且未变化的规范不反复通读;只读相关专题,不做全仓审查,不顺手重构。 +按第 7 节选择相关检查,不默认运行全部 JS/Python 测试。检查通过后,除非又改了代码或出现新问题,不重复运行。 +没有改变职责、接口或持久化契约时,不更新架构文档或新增经验记录。提交说明由 AI 根据实际差异编写,无需用户代写。 + +### 任务中断后的接续与快照 + +- 开工先检查状态和差异。工作区干净时直接继续,不制造空提交。 +- 上次因额度或其他原因中断,存在属于该任务的改动时,先确认文件范围,再选择性暂存这些文件;不得使用无差别的 `git add .` 收入用户数据、凭据、临时文件或无关工作。 +- 已完成且有验证记录的改动可补正式提交;尚未验证或未完成的改动可先保存 `chore(checkpoint): <实际改动摘要>` 恢复快照,提交正文明确“未完成/验证待完成”、已做检查和下一步。快照是恢复点,不代表验收通过。 +- 后续修改和验证另作正式提交,不自动 amend、reset 或改写快照历史。若无法区分遗留文件归属,保留原状并说明,不猜测打包。 +- 长任务按可独立验证的完整阶段提交,避免把所有 Git 收尾留到最后。测试范围内检查完成后及时提交,不为额外润色拖延快照。 +- 上述快照和正式提交均只保存在本地,未经明确授权不推送。 + ## 2. 模块职责与规模 - `web/main.js` 负责注册和接线;`ui_sidebar.js` 的 `createDOM` 负责外壳装配。新工具的完整实现放在自己的模块,不继续塞进这两个入口。 diff --git a/CHANGELOG.md b/CHANGELOG.md index e03e7b2..cf10d80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Navigation and update guide - Sidebar icons reveal compact text labels on hover or keyboard focus while keeping their existing button size and actions. Detailed hints explain each tool; scan-state and language changes retain labels. Unclipped tooltips ensure explanations are fully readable. -- Added a non-intrusive update guide system: instead of an automatic popup on startup, an amber breathing badge (`!` + '新指引' / 'Guide') appears in the top-right header when a new guide version is unacknowledged. Clicking opens the polished obsidian-glass guide modal with step indicator, and dismissing smoothly hides the badge and stores persistent acknowledgment. The guide can also be replayed from the Help panel footer; see `docs/architecture/update-guide.md`. +- Update guide opens only from the persistent top-right exclamation button or Help. Dismissing never removes the entry. Sidebar labels slide upward on hover/focus; duplicate source-panel and obsolete notice styles were removed. See `docs/architecture/update-guide.md`. ### Model Source Hub (模型来源中控中心) - Added a unified Model Source Hub under Toolbox for dual-scope (current workflow and full library) model source URL inspection, one-click browser navigation to Civitai/HuggingFace/Liblib/ModelScope, custom source editing, workflow metadata synchronization (`extra.anomalous_model_sources`), and instant canvas `Note` node generation for non-intrusive workflow documentation. diff --git a/docs/architecture/frontend.md b/docs/architecture/frontend.md index c96f64a..c99aa70 100644 --- a/docs/architecture/frontend.md +++ b/docs/architecture/frontend.md @@ -25,8 +25,8 @@ Major UI panels live in `web/modules/ui_*.js`. Shared browser state remains on the `AnomalousBrowser` instance. Pure parsing, normalization, comparison, and transaction helpers remain in focused modules rather than acquiring DOM state. -Update-guide content and UI lifecycle are separate modules; the browser show/close -methods only wire them in. Help provides an explicit replay entry. Read +Update-guide content and UI lifecycle are separate modules. The header and Help +open it only on explicit user action; browser close disposes it. Read [update-guide.md](update-guide.md) before changing guide IDs, steps, persistence, or sidebar icon/label transitions. Do not embed guide logic in the main/sidebar bootstrap or reuse its content version as a feature flag. diff --git a/docs/architecture/update-guide.md b/docs/architecture/update-guide.md index 0ace2eb..6fc5ef4 100644 --- a/docs/architecture/update-guide.md +++ b/docs/architecture/update-guide.md @@ -12,27 +12,27 @@ | `web/modules/ui_update_guide.js` | 显示、翻页、关闭、焦点、版本记录;一般内容更新不要修改 | | `web/modules/sidebar_actions.js` | 六个底部按钮的短标签、完整名称和用途提示,不改变点击动作 | | `web/styles.css` | 引导布局和底部图标/文字切换的现有规则 | -| `web/main.js` / `ui_sidebar.js` | 仅在浏览器打开/关闭及帮助页重看时接线 | +| `web/main.js` / `ui_sidebar.js` | 父窗口关闭清理,以及上方按钮和帮助页的手动入口 | ## 后续 AI 更新步骤 1. 先确认功能已实现及真实入口。不要在引导里承诺未上线、暂停或验证失败的功能。 2. 在 `CURRENT_UPDATE_GUIDE.steps` 编写 1–5 个步骤,每项包含唯一 `id`、短 `icon`、`titleKey`、`bodyKey`。 3. 在 `locales.js` 补齐这些键的中文和英文。标题说明变化,正文说明入口和用户该怎么用。禁止 HTML、可执行回调、请求及文件写入。 -4. **只有需要所有用户重新看到时才换引导 `id`**,例如 `2026-10-library-navigation`。修改错字、翻译、样式时保持 ID。不使用时间戳、随机数、Git 提交号或普通版本号自动生成 ID。 +4. **只有引导内容属于新一轮功能变化时才换 `id`**,例如 `2026-10-library-navigation`。修改错字、翻译、样式时保持 ID。不使用时间戳、随机数、Git 提交号或普通版本号自动生成 ID;换 ID 也不能自动弹窗。 5. 配置校验会拒绝重复步骤、空步骤及缺失双语文案。配置错误只跳过引导,不应阻止插件打开;必须修正错误后再交付。 -6. 运行下方测试,再在浏览器验证首次打开、跳过后重开、帮助页重看、Esc 和中英文长文案。 +6. 运行下方相关测试,再在浏览器验证打开插件不弹窗、上方入口、跳过后手动重开、帮助页重看、Esc 和长文案。 7. 修改现有样式规则,不在文件末尾追加覆盖包。没有明确产品决策,不增加强制阅读、自动跳转、网络请求或额外追踪。 ## 生命周期与记录 -- 未确认的更新引导不再强制自动弹窗打扰用户,而是在面板右上角显示克制的暗色感叹号徽标(`#anomalous-update-notice-btn`);用户主动点击时才唤起引导。 +- 面板右上角常驻感叹号按钮(`#anomalous-update-notice-btn`),提供完整的用途提示和 accessible name。只有用户点击该按钮或帮助页入口才打开引导;初始化、打开插件、版本变化都不能触发弹窗。 - 使用原生 `dialog` 的顶层显示和焦点约束,关闭时尽可能恢复原焦点。 -- 完成、跳过、×、Esc、点击空白关闭会记录已读,并触发感叹号徽标平滑淡出消除;关闭父浏览器仅清理,不将未读引导标记为已读。 +- 完成、跳过、×、Esc、点击空白关闭会记录已读,上方入口仍然保留;关闭父浏览器仅清理,不将未读引导标记为已读。入口不需要全局事件或延时隐藏。 - 持久化键为 `anomalous_update_guide_seen:`,值为 `1`。只保存本地已读状态,不发送到服务端。 -- 存储不可用时,当前页面会话仍记住关闭状态;刷新页面后可能再次显示。 +- 存储不可用时,当前页面会话仍记住关闭状态;刷新后仍必须手动点击才能显示。 - 同一时刻只有一个引导。重复调用不叠加弹窗;所有关闭路径通过 `closeUpdateGuide` 释放资源。 -- 帮助页的“查看更新引导”使用 `force: true`,允许重看已确认版本。 +- 上方按钮和帮助页的“查看更新引导”均使用 `force: true`,允许重看已确认版本。 - 引导不自动点击对应功能,也不修改画布、模型、素材、导入导出限制。 ## 底部按钮约束 @@ -48,9 +48,8 @@ ```powershell node --experimental-vm-modules tests/update_guide.mjs -node --experimental-vm-modules tests/prompt_ui_lifecycle.mjs -node --experimental-vm-modules tests/export_availability.mjs ``` `update_guide.mjs` 加载真实模块,检查双语配置、版本记忆、重看、翻页、关闭清理、 父窗口关闭、存储失败及扫描图标替换后的标签。它不能代替实际浏览器的布局与焦点验证。 +只有同时修改工坊生命周期或导入导出行为时,才追加对应测试;纯引导样式不运行无关测试。 diff --git a/web/main.js b/web/main.js index afc612e..0571d8d 100644 --- a/web/main.js +++ b/web/main.js @@ -7,7 +7,7 @@ import { showRecipes, refreshRecipes, renderRecipeList, handleSaveRecipe } from import { showMaterials, refreshMaterials, openSavedMaterial, openMaterialLibrary } from './modules/ui_materials.js'; import { openPromptStudio } from './modules/ui_prompt_composer.js'; import { openPromptTranslator } from './modules/ui_prompt_translator.js'; -import { showUpdateGuide, closeUpdateGuide } from './modules/ui_update_guide.js'; +import { closeUpdateGuide } from './modules/ui_update_guide.js'; import { showImageWorkbench } from './modules/ui_gallery_detail.js'; import { initDoctorPanel, diagnoseNode, renderGlobalDashboard, initAssistantPanel, renderAssistantModelCard, _loadAssistantHistory, _openGalleryReplacer, openLoraInsertionPicker, runGlobalDoctorScan } from './modules/ui_doctor.js'; import { app } from "../../scripts/app.js"; @@ -283,7 +283,6 @@ class AnomalousBrowser { } else { this.loadModels(); } - this.refreshUpdateNotice?.(); } close() { diff --git a/web/modules/locales.js b/web/modules/locales.js index 75b0bcc..17200b5 100644 --- a/web/modules/locales.js +++ b/web/modules/locales.js @@ -19,8 +19,7 @@ export const i18n = { updateGuideNext: "下一步", updateGuideDone: "知道了", updateGuideProgress: "第 {current} / {total} 步", - updateGuideNoticeLabel: "新指引", - updateGuideNoticeTooltip: "新版本功能与界面改版指引 (点击查看)", + updateGuideNoticeTooltip: "查看更新引导", updateGuideNavigationTitle: "悬停,看懂每个入口", updateGuideNavigationBody: "左下角的按钮保持原来的大小。鼠标悬停或用键盘选中时,图标会切换成文字;稍作停留可以查看完整用途。依次为工具箱、扫描、模型医生、节点助手、素材库和设置。", updateGuideTransferTitle: "导入导出,统一到工具箱", @@ -1172,8 +1171,7 @@ export const i18n = { updateGuideNext: "Next", updateGuideDone: "Got it", updateGuideProgress: "Step {current} of {total}", - updateGuideNoticeLabel: "Guide", - updateGuideNoticeTooltip: "New features & interface guide (Click to view)", + updateGuideNoticeTooltip: "View update guide", updateGuideNavigationTitle: "Hover to identify each action", updateGuideNavigationBody: "The lower-left buttons keep their compact size. Hover or focus with the keyboard to replace an icon with a short label; pause for its full description. The actions are Toolbox, Scan, Model Doctor, Node Assistant, Material Library and Settings.", updateGuideTransferTitle: "Workflow sharing lives in Toolbox", diff --git a/web/modules/ui_sidebar.js b/web/modules/ui_sidebar.js index 3a620ab..9defe38 100644 --- a/web/modules/ui_sidebar.js +++ b/web/modules/ui_sidebar.js @@ -8,8 +8,7 @@ import { translate } from './locales.js'; import { escapeHtml } from './safe_dom.js'; import { updateScanProgress, finishScanProgress, failScanProgress } from './scan_progress.js'; import { openModelSourcesModal } from './ui_model_sources.js'; -import { showUpdateGuide, hasAcknowledged } from './ui_update_guide.js'; -import { CURRENT_UPDATE_GUIDE } from './update_guide_data.js'; +import { showUpdateGuide } from './ui_update_guide.js'; import { configureSidebarAction, configureSidebarActions } from './sidebar_actions.js'; const t = (key, params) => translate(key, params); @@ -1191,33 +1190,13 @@ export function createDOM() { updateNoticeBtn.setAttribute('data-tooltip', t('updateGuideNoticeTooltip')); updateNoticeBtn.setAttribute('data-tooltip-pos', 'bottom'); updateNoticeBtn.setAttribute('aria-label', t('updateGuideNoticeTooltip')); - updateNoticeBtn.innerHTML = `!${t('updateGuideNoticeLabel')}`; - updateNoticeBtn.onclick = () => { - showUpdateGuide(this, { force: true }); - }; - - const updateNoticeState = () => { - const isSeen = hasAcknowledged(CURRENT_UPDATE_GUIDE.id); - if (isSeen) { - updateNoticeBtn.style.display = 'none'; - } else { - updateNoticeBtn.style.display = 'inline-flex'; - updateNoticeBtn.style.opacity = '1'; - updateNoticeBtn.style.transform = 'none'; - } - }; - updateNoticeState(); - this.refreshUpdateNotice = updateNoticeState; - - window.addEventListener('anomalous-update-guide-acknowledged', (e) => { - if (e.detail?.id === CURRENT_UPDATE_GUIDE.id) { - updateNoticeBtn.style.opacity = '0'; - updateNoticeBtn.style.transform = 'scale(0.8)'; - setTimeout(() => { - updateNoticeBtn.style.display = 'none'; - }, 300); - } - }); + updateNoticeBtn.type = 'button'; + const updateNoticeIcon = document.createElement('span'); + updateNoticeIcon.className = 'anomalous-update-notice-icon'; + updateNoticeIcon.setAttribute('aria-hidden', 'true'); + updateNoticeIcon.textContent = '!'; + updateNoticeBtn.appendChild(updateNoticeIcon); + updateNoticeBtn.onclick = () => showUpdateGuide(this, { force: true }); rightGroup.appendChild(updateNoticeBtn); rightGroup.appendChild(dockBtn); @@ -1277,7 +1256,6 @@ export function createDOM() { if (updateNoticeBtn) { updateNoticeBtn.setAttribute('data-tooltip', t('updateGuideNoticeTooltip')); updateNoticeBtn.setAttribute('aria-label', t('updateGuideNoticeTooltip')); - updateNoticeBtn.innerHTML = `!${t('updateGuideNoticeLabel')}`; } // Reset dynamic panels so they re-render in new language @@ -2656,25 +2634,7 @@ export function showHelp() { const replayGuideBtn = document.createElement('button'); replayGuideBtn.id = 'anomalous-help-replay-guide-btn'; replayGuideBtn.textContent = t('updateGuideReplay'); - replayGuideBtn.style.padding = '8px 14px'; - replayGuideBtn.style.background = 'rgba(255, 255, 255, 0.05)'; - replayGuideBtn.style.color = '#cbd5e1'; - replayGuideBtn.style.border = '1px solid rgba(255, 255, 255, 0.16)'; - replayGuideBtn.style.borderRadius = '4px'; - replayGuideBtn.style.cursor = 'pointer'; - replayGuideBtn.style.fontSize = '12px'; - replayGuideBtn.style.fontWeight = '500'; - replayGuideBtn.style.transition = 'all 0.15s ease'; - replayGuideBtn.onmouseover = () => { - replayGuideBtn.style.background = 'rgba(255, 255, 255, 0.1)'; - replayGuideBtn.style.borderColor = 'rgba(255, 255, 255, 0.3)'; - replayGuideBtn.style.color = '#ffffff'; - }; - replayGuideBtn.onmouseout = () => { - replayGuideBtn.style.background = 'rgba(255, 255, 255, 0.05)'; - replayGuideBtn.style.borderColor = 'rgba(255, 255, 255, 0.16)'; - replayGuideBtn.style.color = '#cbd5e1'; - }; + replayGuideBtn.type = 'button'; replayGuideBtn.onclick = () => { this.helpModal?.remove(); showUpdateGuide(this, { force: true }); diff --git a/web/modules/ui_update_guide.js b/web/modules/ui_update_guide.js index 0f664ff..c5e0944 100644 --- a/web/modules/ui_update_guide.js +++ b/web/modules/ui_update_guide.js @@ -21,14 +21,11 @@ export function closeUpdateGuide(owner, acknowledge = false) { acknowledgedThisSession.add(current.id); try { localStorage.setItem(storageKey(current.id), '1'); } catch (error) { console.warn('[AMB] Update guide dismissal is saved for this session only.', error); } - if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function') { - window.dispatchEvent(new CustomEvent('anomalous-update-guide-acknowledged', { detail: { id: current.id } })); - } } current.scope.dispose(); } -/** Automatic on browser open; force replays from Help. No graph or file writes. */ +/** Opened only by explicit user action in the header or Help. No graph or file writes. */ export function showUpdateGuide(owner, { force = false, guide = CURRENT_UPDATE_GUIDE } = {}) { if (!owner.modal?.classList.contains('visible')) return false; if (!validateUpdateGuide(guide, i18n)) { diff --git a/web/styles.css b/web/styles.css index fc0fddd..778a8c2 100644 --- a/web/styles.css +++ b/web/styles.css @@ -11862,47 +11862,45 @@ button:hover .anomalous-btn-icon { filter: none; } -#anomalous-sidebar-actions { - display: flex; - align-items: center; - justify-content: space-around; - padding: 10px 8px; - gap: 4px; - box-sizing: border-box; -} - -#anomalous-sidebar-actions button { - display: inline-flex !important; - align-items: center !important; - justify-content: center !important; - width: 32px !important; - height: 32px !important; - border-radius: 6px !important; - box-sizing: border-box !important; - vertical-align: middle !important; - color: var(--amb-text-muted, #9ca3af) !important; - background: transparent !important; - border: 1px solid transparent !important; - transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1) !important; -} - -#anomalous-sidebar-actions button:hover { - color: #ffffff !important; - background: rgba(255, 255, 255, 0.08) !important; - border: 1px solid rgba(255, 255, 255, 0.16) !important; - transform: translateY(-1px); - box-shadow: none; -} - -#anomalous-sidebar-actions button svg { - transition: transform 0.2s ease, color 0.2s ease; -} - -#anomalous-sidebar-actions button:hover svg { - transform: scale(1.08); - color: #ffffff !important; -} - +#anomalous-sidebar-actions { + position: relative; + overflow: visible; + display: flex; + align-items: center; + justify-content: space-around; + padding: 10px 8px; + gap: 4px; + box-sizing: border-box; +} + +#anomalous-sidebar-actions button { + position: relative; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + width: 32px !important; + height: 32px !important; + border-radius: 6px !important; + box-sizing: border-box !important; + vertical-align: middle !important; + color: var(--amb-text-muted, #9ca3af) !important; + background: transparent !important; + border: 1px solid transparent !important; + transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease; +} + +#anomalous-sidebar-actions button:hover { + color: #ffffff !important; + background: rgba(255, 255, 255, 0.08) !important; + border: 1px solid rgba(255, 255, 255, 0.16) !important; + transform: none; + box-shadow: none; +} + +#anomalous-sidebar-actions button svg { + transition: opacity 0.15s ease; +} + /* Abyssal Scarlet Mode overrides for Task 8 icon buttons (Sharp Borders & Inner Shadow) */ .theme-abyssal-scarlet #anomalous-doctor-btn:hover { color: #f43f5e !important; @@ -11943,12 +11941,6 @@ button:hover .anomalous-btn-icon { /* 11. Task 9: Master Container Geometric Details, Watermarks & Floating Tooltips */ -/* Empty space watermark on sidebar bottom */ -#anomalous-sidebar-actions { - position: relative; - overflow: hidden; -} - #anomalous-sidebar-actions::before { display: none !important; } @@ -13956,296 +13948,102 @@ button:hover .anomalous-btn-icon { font-size: 0.9rem; } -/* ============================================================================= - UPDATE GUIDE NOTICE INDICATOR (RESTRAINED AMBER BREATH) - ============================================================================= */ -#anomalous-header button.anomalous-update-notice-btn { - background: rgba(245, 158, 11, 0.12) !important; - border-color: rgba(245, 158, 11, 0.38) !important; - color: #fbbf24 !important; - padding: 0 9px 0 6px !important; - font-weight: 600 !important; - letter-spacing: 0.3px !important; - transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease, transform 0.3s ease; - animation: anomalous-amber-breath 3.2s ease-in-out infinite; -} - -#anomalous-header button.anomalous-update-notice-btn:hover { - background: rgba(245, 158, 11, 0.22) !important; - border-color: rgba(245, 158, 11, 0.65) !important; - color: #ffffff !important; - transform: translateY(-1px); - box-shadow: 0 0 10px rgba(245, 158, 11, 0.35) !important; - animation: none; -} - -.anomalous-update-notice-icon { - display: inline-flex; - align-items: center; - justify-content: center; - width: 14px; - height: 14px; - border-radius: 50%; - background: #f59e0b; - color: #18181b; - font-size: 10px; - transition: border-color 0.15s ease; -} - -.anomalous-sources-search-input:focus { - border-color: #38bdf8; -} - -.anomalous-sources-body { - flex: 1; - overflow-y: auto; - padding: 14px 18px; - display: flex; - flex-direction: column; - gap: 10px; -} - -.anomalous-source-row-item { - background: rgba(255, 255, 255, 0.03); - border: 1px solid rgba(255, 255, 255, 0.07); - border-radius: 8px; - padding: 10px 14px; - display: flex; - flex-direction: column; - gap: 8px; - transition: border-color 0.15s ease, background 0.15s ease; -} - -.anomalous-source-row-item.has-url { - border-left: 3px solid #10b981; -} - -.anomalous-source-row-item.is-missing-url { - border-left: 3px solid #f59e0b; -} - -.anomalous-source-row-title { - display: flex; - align-items: center; - gap: 8px; - flex-wrap: wrap; -} - -.anomalous-source-node-tag { - font-size: 0.72rem; - padding: 1px 6px; - border-radius: 4px; - background: rgba(244, 63, 94, 0.15); - border: 1px solid rgba(244, 63, 94, 0.3); - color: #fb7185; - font-family: monospace; -} - -.anomalous-source-model-name { - font-size: 0.88rem; - color: #f1f5f9; - word-break: break-all; -} - -.anomalous-source-badge-danger { - font-size: 0.7rem; - padding: 1px 5px; - border-radius: 4px; - background: rgba(239, 68, 68, 0.2); - border: 1px solid rgba(239, 68, 68, 0.4); - color: #f87171; -} - -.anomalous-source-hash-chip { - font-size: 0.72rem; - color: #64748b; - margin-left: auto; - font-family: monospace; -} - -.anomalous-source-col-input-row { - display: flex; - align-items: center; - gap: 8px; -} - -.anomalous-source-input-wrap { - flex: 1; - position: relative; - display: flex; - align-items: center; -} - -.anomalous-source-url-input { - width: 100%; - background: rgba(0, 0, 0, 0.4); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 6px; - color: #e2e8f0; - font-size: 0.82rem; - padding: 6px 10px; - padding-right: 96px; - outline: none; - box-sizing: border-box; - font-family: monospace; -} - -.anomalous-source-url-input:focus { - border-color: #38bdf8; - background: rgba(0, 0, 0, 0.6); -} - -.anomalous-source-plat-badge { - position: absolute; - right: 6px; - font-size: 0.7rem; - font-weight: 500; - padding: 2px 7px; - border-radius: 4px; - border: 1px solid; - pointer-events: none; -} - -.anomalous-source-row-actions { - display: flex; - gap: 6px; - align-items: center; - flex-shrink: 0; -} - -.anomalous-btn-jump { - background: linear-gradient(135deg, #0284c7, #0369a1); - border: 1px solid rgba(56, 189, 248, 0.4); - color: #fff; -} - -.anomalous-btn-jump:disabled { - opacity: 0.4; - cursor: not-allowed; -} - -.anomalous-sources-footer { - padding: 10px 18px; - border-top: 1px solid rgba(255, 255, 255, 0.08); - background: rgba(18, 20, 28, 0.95); - display: flex; - align-items: center; - justify-content: space-between; - flex-shrink: 0; -} - -.anomalous-sources-footer-stats { - font-size: 0.82rem; - color: #94a3b8; -} - -.anomalous-sources-footer-actions { - display: flex; - gap: 8px; -} - -.anomalous-sources-empty { - padding: 40px 20px; - text-align: center; - color: #94a3b8; - font-size: 0.9rem; -} - /* ============================================================================= UPDATE GUIDE NOTICE INDICATOR (CLEAN MONOCHROME TECH) ============================================================================= */ +/* Header skin uses important padding/colors; keep this control square within that skin. */ #anomalous-header button.anomalous-update-notice-btn { - background: rgba(255, 255, 255, 0.06) !important; + width: 32px; + min-width: 32px; + padding: 0 !important; + background: transparent !important; border-color: rgba(255, 255, 255, 0.15) !important; - color: #e2e8f0 !important; - padding: 0 10px 0 7px !important; - font-weight: 500 !important; - letter-spacing: 0.2px !important; - transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease, transform 0.3s ease; + color: var(--amb-text-primary, #e2e8f0) !important; } - #anomalous-header button.anomalous-update-notice-btn:hover { - background: rgba(255, 255, 255, 0.12) !important; - border-color: rgba(255, 255, 255, 0.28) !important; - color: #ffffff !important; - transform: translateY(-1px); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35) !important; + background: rgba(255, 255, 255, 0.08) !important; } - .anomalous-update-notice-icon { display: inline-flex; align-items: center; justify-content: center; - width: 14px; - height: 14px; + width: 16px; + height: 16px; + border: 1px solid currentColor; border-radius: 50%; - background: rgba(255, 255, 255, 0.16); - color: #f1f5f9; - font-size: 10px; - font-weight: 700; - line-height: 1; - margin-right: 4px; + font: 700 12px/1 system-ui, sans-serif; +} +#anomalous-help-replay-guide-btn { + padding: 8px 14px; + background: rgba(255, 255, 255, 0.05); + color: #cbd5e1; + border: 1px solid rgba(255, 255, 255, 0.16); + border-radius: 4px; + cursor: pointer; + font-size: 12px; + font-weight: 500; +} +#anomalous-help-replay-guide-btn:hover { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.3); + color: #fff; +} +#anomalous-update-notice-btn:focus-visible, +#anomalous-help-replay-guide-btn:focus-visible, +.anomalous-update-guide button:focus-visible { + outline: 2px solid var(--amb-accent, #38bdf8); + outline-offset: 2px; } /* ============================================================================= SIDEBAR ACTIONS HOVER REVEAL & TOOLTIPS ============================================================================= */ -#anomalous-sidebar-actions { - overflow: visible !important; -} - -#anomalous-sidebar-actions button { - position: relative !important; -} - -#anomalous-sidebar-actions button .anomalous-action-label { - display: none; - font-size: 11px; - font-weight: 600; - line-height: 1; - letter-spacing: -0.2px; +#anomalous-sidebar-actions .anomalous-action-label { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + font: 600 10px/1.2 system-ui, sans-serif; color: inherit; pointer-events: none; white-space: nowrap; - text-align: center; + opacity: 0; + transform: translateY(5px); + transition: opacity 0.15s ease, transform 0.15s ease; } -#anomalous-sidebar-actions button:hover svg, -#anomalous-sidebar-actions button:focus-visible svg { - display: none !important; +#anomalous-sidebar-actions button:is(:hover, :focus-visible) > svg { opacity: 0; } +#anomalous-sidebar-actions button:is(:hover, :focus-visible) .anomalous-action-label { + opacity: 1; + transform: translateY(0); } - -#anomalous-sidebar-actions button:hover .anomalous-action-label, -#anomalous-sidebar-actions button:focus-visible .anomalous-action-label { - display: inline-flex !important; - align-items: center; - justify-content: center; - color: #ffffff !important; - animation: anomalous-action-label-in 0.15s ease; +#anomalous-sidebar-actions button:focus-visible { + outline: 2px solid var(--amb-accent, #38bdf8); + outline-offset: 2px; } - -@keyframes anomalous-action-label-in { - from { opacity: 0; transform: scale(0.92); } - to { opacity: 1; transform: scale(1); } +@media (hover: none) { + #anomalous-sidebar-actions button > svg { opacity: 0; } + #anomalous-sidebar-actions .anomalous-action-label { opacity: 1; transform: none; } } /* Sidebar action tooltips: wide horizontal layout with boundary safety */ #anomalous-sidebar-actions [data-tooltip]::after, #anomalous-sidebar-actions .anomalous-tooltip-target::after { - width: max-content !important; - min-width: 100px !important; - max-width: 220px !important; - white-space: pre-line !important; - text-align: center !important; - line-height: 1.45 !important; - font-size: 11.5px !important; - padding: 7px 11px !important; - border-radius: 6px !important; - word-break: normal !important; - overflow-wrap: break-word !important; - box-sizing: border-box !important; - pointer-events: none !important; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.75), 0 0 0 1px rgba(255, 255, 255, 0.12) !important; + width: max-content; + min-width: 100px; + max-width: 220px; + white-space: pre-line; + text-align: center; + line-height: 1.45; + font-size: 11.5px; + padding: 7px 11px; + border-radius: 6px; + word-break: normal; + overflow-wrap: break-word; + box-sizing: border-box; + pointer-events: none; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.75), 0 0 0 1px rgba(255, 255, 255, 0.12); } /* Align edge buttons so tooltips stay cleanly within the sidebar */ @@ -14253,56 +14051,56 @@ button:hover .anomalous-btn-icon { #anomalous-sidebar-actions button:first-child.anomalous-tooltip-target::after, #anomalous-sidebar-actions button:nth-child(2)[data-tooltip]::after, #anomalous-sidebar-actions button:nth-child(2).anomalous-tooltip-target::after { - left: 0 !important; - right: auto !important; - transform: translateY(4px) !important; + left: 0; + right: auto; + transform: translateY(4px); } -#anomalous-sidebar-actions button:first-child[data-tooltip]:hover::after, -#anomalous-sidebar-actions button:first-child.anomalous-tooltip-target:hover::after, -#anomalous-sidebar-actions button:nth-child(2)[data-tooltip]:hover::after, -#anomalous-sidebar-actions button:nth-child(2).anomalous-tooltip-target:hover::after { - transform: translateY(0) !important; +#anomalous-sidebar-actions button:first-child[data-tooltip]:is(:hover, :focus-visible)::after, +#anomalous-sidebar-actions button:first-child.anomalous-tooltip-target:is(:hover, :focus-visible)::after, +#anomalous-sidebar-actions button:nth-child(2)[data-tooltip]:is(:hover, :focus-visible)::after, +#anomalous-sidebar-actions button:nth-child(2).anomalous-tooltip-target:is(:hover, :focus-visible)::after { + transform: translateY(0); } #anomalous-sidebar-actions button:first-child[data-tooltip]::before, #anomalous-sidebar-actions button:first-child.anomalous-tooltip-target::before, #anomalous-sidebar-actions button:nth-child(2)[data-tooltip]::before, #anomalous-sidebar-actions button:nth-child(2).anomalous-tooltip-target::before { - left: 14px !important; - right: auto !important; - transform: translateY(4px) !important; + left: 14px; + right: auto; + transform: translateY(4px); } -#anomalous-sidebar-actions button:first-child[data-tooltip]:hover::before, -#anomalous-sidebar-actions button:first-child.anomalous-tooltip-target:hover::before, -#anomalous-sidebar-actions button:nth-child(2)[data-tooltip]:hover::before, -#anomalous-sidebar-actions button:nth-child(2).anomalous-tooltip-target:hover::before { - transform: translateY(0) !important; +#anomalous-sidebar-actions button:first-child[data-tooltip]:is(:hover, :focus-visible)::before, +#anomalous-sidebar-actions button:first-child.anomalous-tooltip-target:is(:hover, :focus-visible)::before, +#anomalous-sidebar-actions button:nth-child(2)[data-tooltip]:is(:hover, :focus-visible)::before, +#anomalous-sidebar-actions button:nth-child(2).anomalous-tooltip-target:is(:hover, :focus-visible)::before { + transform: translateY(0); } #anomalous-sidebar-actions button:last-child[data-tooltip]::after, #anomalous-sidebar-actions button:last-child.anomalous-tooltip-target::after { - left: auto !important; - right: 0 !important; - transform: translateY(4px) !important; + left: auto; + right: 0; + transform: translateY(4px); } -#anomalous-sidebar-actions button:last-child[data-tooltip]:hover::after, -#anomalous-sidebar-actions button:last-child.anomalous-tooltip-target:hover::after { - transform: translateY(0) !important; +#anomalous-sidebar-actions button:last-child[data-tooltip]:is(:hover, :focus-visible)::after, +#anomalous-sidebar-actions button:last-child.anomalous-tooltip-target:is(:hover, :focus-visible)::after { + transform: translateY(0); } #anomalous-sidebar-actions button:last-child[data-tooltip]::before, #anomalous-sidebar-actions button:last-child.anomalous-tooltip-target::before { - left: auto !important; - right: 14px !important; - transform: translateY(4px) !important; + left: auto; + right: 14px; + transform: translateY(4px); } -#anomalous-sidebar-actions button:last-child[data-tooltip]:hover::before, -#anomalous-sidebar-actions button:last-child.anomalous-tooltip-target:hover::before { - transform: translateY(0) !important; +#anomalous-sidebar-actions button:last-child[data-tooltip]:is(:hover, :focus-visible)::before, +#anomalous-sidebar-actions button:last-child.anomalous-tooltip-target:is(:hover, :focus-visible)::before { + transform: translateY(0); } /* ============================================================================= @@ -14334,12 +14132,14 @@ dialog.anomalous-update-guide { box-shadow: 0 24px 70px rgba(0, 0, 0, 0.8), 0 0 1px 1px rgba(255, 255, 255, 0.12); color: #f1f5f9; outline: none; - overflow: hidden; + overflow-y: auto; box-sizing: border-box; z-index: 1000000; animation: anomalous-guide-pop 0.25s cubic-bezier(0.16, 1, 0.3, 1); } +dialog.anomalous-update-guide > * { flex-shrink: 0; } + @keyframes anomalous-guide-pop { from { opacity: 0; @@ -14441,6 +14241,7 @@ dialog.anomalous-update-guide::backdrop { display: flex; align-items: center; justify-content: space-between; + flex-wrap: wrap; padding: 14px 20px; background: rgba(0, 0, 0, 0.28); border-top: 1px solid rgba(255, 255, 255, 0.06);