diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index ba6acab..d1bc766 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -150,22 +150,22 @@ DOM or live LiteGraph state.
the library and Node Assistant use `ui_material_application.js` for the same receipt.
- `ui_prompt_composer.js` owns the Prompt Studio Dual-Column Workbench (提示词工坊左右双分栏工作台);
provides a clean, professional studio workspace (`.anomalous-prompt-workbench`) stripped of gaudy neon effects, cyberpunk backgrounds, and pulsing glow animations;
+ features compact vertical spacing (tightened paddings, 28px single-line metadata inputs, and 6px grid gaps) maximizing functional workspace;
features responsive docked / sidebar adaptation with dedicated single-column collapse, generous vertical scrolling without arbitrary height clipping, and an inline responsive view switcher (`.anomalous-prompt-view-switcher`: `[🗃️ 词卡库 | 🎛️ 拼装台 | 📑 全部]`) for seamless navigation when docked as a sidebar (`#anomalous-container.anomalous-docked`) or on narrow screens;
the Left Column hosts the Ready-to-use Prompt Cards Library (成型提示词库), featuring restrained dark slate card backgrounds (`#24262E`)
with category-specific left accent borders (`border-left: 3.5px solid ...`, Base/Style/Subject/Trigger) eliminating color-palette clutter,
minimalist empty state container (`.anomalous-source-empty`) with subtle dashed borders,
- non-wrapping title layout, a dedicated sub-action bar with one-click canvas node prompt extraction (`🎯 从节点提取`,
- reading selected ComfyUI text nodes like `CLIPTextEncode` with downstream link connection traversal for accurate negative conditioning detection, auto-generating categorised cards) and one-click
- Material Library batch sync (`📥 从素材库导入`, cancellable fetch scoped to `category=prompts`), plus on-demand persistent card creation
- (`➕ 新建词卡`, with explicit positive/negative role radios and `/anomalous/save_prompt_plan` backend persistence; temporary cards
+ a streamlined col-header holding a unified action button group (`[🎯 提取]`, `[📥 导入]`, `[➕ 新建]`) that reclaims ~36px vertical height for the card list,
+ one-click canvas node prompt extraction (`🎯 提取`, reading selected ComfyUI text nodes like `CLIPTextEncode` with downstream link connection traversal for accurate negative conditioning detection, auto-generating categorised cards) and one-click
+ Material Library batch sync (`📥 导入`, cancellable fetch scoped to `category=prompts`), plus on-demand persistent card creation
+ (`➕ 新建`, with explicit positive/negative role radios and `/anomalous/save_prompt_plan` backend persistence; temporary cards
show `[未保存]` badge with one-click `💾 存入库`), completely eliminating default empty textareas; cards support native HTML5 drag-and-drop;
the Right Column hosts the expanded Assembler & Arranger Stage (顺序编排调音台, `minmax(460px, 1fr)`), featuring quick node reading
- (`🎯 读取选中节点`), compact modular Lego block cards (~56px height, expandable on focus) allowing generous top-to-bottom sequence stacking,
- a clean dropzone (`.anomalous-assembly-dropzone`) that ingests dragged cards into positive/negative tracks with strict role isolation,
+ (`🎯 读取选中节点`), quick final text toggle (`[📄 最终文本]`), compact modular Lego block cards (~56px height, expandable on focus) allowing generous top-to-bottom sequence stacking,
+ a large, high-clearance dropzone (`.anomalous-assembly-dropzone`, min-height 240px) that ingests dragged cards into positive/negative tracks with strict role isolation,
supports bidirectional drag-and-drop reordering with ghost indicator lines, role-aware up/down swapping, instant A/B bypass toggles (greyscale dimming without deleting),
interactive category pills, one-click Smart Sort (`🪄 按分类排序`, Base ➔ Style ➔ Subject ➔ Trigger), a target widget dropdown with sticky
- selection cache (`targetWidgetIndexByNodeId`), and a sticky floating frosted-glass output deck (`.anomalous-mixer-deck-output`, `position: sticky; bottom: 0; backdrop-filter: blur(12px)`)
- with real-time word/token counts, single-mount canvas dragging (`bindMaterialDrag` onto text nodes), direct target node injection toolbar, and seamless return to Material Library;
+ selection cache (`targetWidgetIndexByNodeId`), and an on-demand collapsible output deck (`.anomalous-mixer-deck-output`): completely hidden when 0 blocks, defaulting to a slim 32px pill summary bar (`✨ 最终正向文本 (X字符 · Y词组) [📋复制] [👁️查看最终文本 ▾]`) when cards exist to prevent premature clutter and screen squashing, and smoothly expandable into a full drawer containing the compiled textarea, whole-deck canvas drag dock (`bindMaterialDrag`), and target node direct write bar;
`prompt_composition.js` provides bidirectional schema mapping (`planToWorkbenchDraft` and `workbenchDraftToSavedPlan`) ensuring
100% roundtrip data integrity across `anomalous-prompt-plan-v1` and `version: 2`, lossless legacy dual-role splitting and trailing text retention,
`categorizePromptSnippet`, `smartSortPromptBlocks`, `assemblePromptBlocks`, as well as backward-compatible text joining;
diff --git a/web/modules/ui_prompt_composer.js b/web/modules/ui_prompt_composer.js
index 4b19f7e..ee096a4 100644
--- a/web/modules/ui_prompt_composer.js
+++ b/web/modules/ui_prompt_composer.js
@@ -267,6 +267,7 @@ function buildPromptComposer(owner, container, options = {}) {
let sourceFilterCategory = 'all';
let sourceFilterKeyword = '';
let draggedBlockId = null;
+ let isOutputExpanded = false;
// Local in-memory source prompt cards (merged starters + materials + user custom)
let sourceCards = [...STARTER_SOURCE_PROMPTS];
@@ -387,26 +388,26 @@ function buildPromptComposer(owner, container, options = {}) {
const leftPanel = text(workbenchGrid, 'section', '', 'anomalous-workbench-left-panel');
const leftHeader = text(leftPanel, 'div', '', 'anomalous-workbench-col-header');
const leftTitleWrap = text(leftHeader, 'div', '', 'anomalous-workbench-col-title');
- leftTitleWrap.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '词卡库' : 'Prompt Library'} ${window.anomalous_browser_lang === 'zh' ? '· 拖拽卡片至右侧' : '· Drag to mixer'}`;
+ leftTitleWrap.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '词卡库' : 'Prompt Library'} `;
- // Button: Create New Custom Card (placed in header right, never wraps)
- const newCardTriggerBtn = text(leftHeader, 'button', '', 'anomalous-btn-ghost anomalous-btn-sm');
- newCardTriggerBtn.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '新建词卡' : 'New Card'}`;
- newCardTriggerBtn.title = window.anomalous_browser_lang === 'zh' ? '新建并保存一张提示词卡片' : 'Create a new prompt card';
-
- // Sub-action bar: Node extract and Material Library import (full-width, balanced)
- const leftSubActions = text(leftPanel, 'div', '', 'anomalous-workbench-sub-actions');
+ // Action button group in leftHeader
+ const leftHeaderActions = text(leftHeader, 'div', '', 'anomalous-workbench-header-actions');
// Button 1: Extract Prompts from Selected Canvas Node
- const extractNodeBtn = text(leftSubActions, 'button', '', 'anomalous-btn-ghost anomalous-btn-sm anomalous-btn-extract-node');
- extractNodeBtn.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '从节点提取' : 'From Node'}`;
- extractNodeBtn.title = window.anomalous_browser_lang === 'zh' ? '读取 ComfyUI 画布当前选中节点的提示词文本并生成词卡' : 'Extract prompt text from selected canvas node into cards';
+ const extractNodeBtn = text(leftHeaderActions, 'button', '', 'anomalous-btn-ghost anomalous-btn-sm anomalous-btn-extract-node');
+ extractNodeBtn.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '提取' : 'Extract'}`;
+ extractNodeBtn.title = window.anomalous_browser_lang === 'zh' ? '从画布当前选中节点提取提示词并生成词卡' : 'Extract prompt text from selected canvas node into cards';
// Button 2: One-click Sync / Import from Material Library
- const importMaterialsBtn = text(leftSubActions, 'button', '', 'anomalous-btn-ghost anomalous-btn-sm');
- importMaterialsBtn.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '从素材库导入' : 'Import from Library'}`;
+ const importMaterialsBtn = text(leftHeaderActions, 'button', '', 'anomalous-btn-ghost anomalous-btn-sm');
+ importMaterialsBtn.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '导入' : 'Import'}`;
importMaterialsBtn.title = window.anomalous_browser_lang === 'zh' ? '读取素材库,一键把素材库里沉淀的提示词捞入当前工坊词库' : 'Read and import all prompts from Material Library into workbench';
+ // Button 3: Create New Custom Card (placed in header right, never wraps)
+ const newCardTriggerBtn = text(leftHeaderActions, 'button', '', 'anomalous-btn-ghost anomalous-btn-sm');
+ newCardTriggerBtn.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '新建' : 'New'}`;
+ newCardTriggerBtn.title = window.anomalous_browser_lang === 'zh' ? '新建并保存一张提示词卡片' : 'Create a new prompt card';
+
// Search and category filters bar
const leftFilterBar = text(leftPanel, 'div', '', 'anomalous-workbench-filter-bar');
const leftSearch = text(leftFilterBar, 'input', '', 'anomalous-workbench-search-input');
@@ -452,6 +453,11 @@ function buildPromptComposer(owner, container, options = {}) {
const rightActions = text(rightHeader, 'div', '', 'anomalous-mixer-actions');
+ // Right quick view final assembled text
+ const viewFinalBtn = text(rightActions, 'button', '', 'anomalous-btn-ghost anomalous-btn-sm anomalous-mixer-final-btn');
+ viewFinalBtn.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '最终文本' : 'Final Text'}`;
+ viewFinalBtn.title = window.anomalous_browser_lang === 'zh' ? '查看/展开最终合成的提示词文本' : 'View / Expand final assembled prompt text';
+
// Right quick extract: suck into right mixer directly
const rightSuckNodeBtn = text(rightActions, 'button', '', 'anomalous-btn-ghost anomalous-btn-sm');
rightSuckNodeBtn.innerHTML = `${t('promptReadSelectedNode')}`;
@@ -468,28 +474,83 @@ function buildPromptComposer(owner, container, options = {}) {
// Blocks Container & Dropzone
const blocksContainer = text(rightPanel, 'div', '', 'anomalous-mixer-blocks-container anomalous-assembly-track');
- // Bottom Live Assembled Output Deck
- const outputDeck = text(rightPanel, 'div', '', 'anomalous-mixer-deck-output');
- const outputHeader = text(outputDeck, 'div', '', 'anomalous-mixer-output-header');
- const outputTitle = text(outputHeader, 'div', '', 'anomalous-mixer-output-title');
- const outputStats = text(outputHeader, 'div', '', 'anomalous-mixer-output-stats');
+ // Bottom Live Assembled Output Deck (Collapsible on-demand)
+ const outputDeck = text(rightPanel, 'div', '', 'anomalous-mixer-deck-output is-collapsed');
- const outputBody = text(outputDeck, 'div', '', 'anomalous-mixer-output-body');
+ // 1. Slim Dock Summary Bar (32px high, always visible when blocks exist)
+ const outputSummary = text(outputDeck, 'div', '', 'anomalous-mixer-output-summary');
+ const summaryLeft = text(outputSummary, 'div', '', 'anomalous-mixer-summary-left');
+ const outputTitle = text(summaryLeft, 'div', '', 'anomalous-mixer-output-title');
+ const outputStats = text(summaryLeft, 'div', '', 'anomalous-mixer-output-stats');
+
+ const summaryRight = text(outputSummary, 'div', '', 'anomalous-mixer-summary-right');
+ const copyOutputBtn = text(summaryRight, 'button', `📋 ${t('copy')}`, 'anomalous-btn-ghost anomalous-btn-sm anomalous-btn-quick-copy');
+ copyOutputBtn.title = window.anomalous_browser_lang === 'zh' ? '复制当前合成的提示词' : 'Copy assembled prompt text';
+
+ const expandOutputBtn = text(summaryRight, 'button', '', 'anomalous-btn-ghost anomalous-btn-sm anomalous-btn-toggle-output');
+ expandOutputBtn.title = window.anomalous_browser_lang === 'zh' ? '展开/收起最终文本' : 'Expand/collapse full text';
+
+ // 2. Expandable Drawer (reveals full textarea, canvas drag dock, and target node write bar)
+ const outputDrawer = text(outputDeck, 'div', '', 'anomalous-mixer-output-drawer');
+ outputDrawer.style.display = 'none';
+
+ const outputBody = text(outputDrawer, 'div', '', 'anomalous-mixer-output-body');
const outputTextarea = text(outputBody, 'textarea', '', 'anomalous-mixer-output-textarea');
outputTextarea.readOnly = true;
outputTextarea.rows = 2;
- const outputFooter = text(outputDeck, 'div', '', 'anomalous-mixer-output-footer');
+ const outputFooter = text(outputDrawer, 'div', '', 'anomalous-mixer-output-footer');
const dragHint = text(outputFooter, 'div', '', 'anomalous-mixer-drag-hint');
dragHint.innerHTML = `🖐️ ${window.anomalous_browser_lang === 'zh' ? '按住此预览坞' : 'Drag this deck'} ${window.anomalous_browser_lang === 'zh' ? '直接丢入 ComfyUI 画布节点' : 'onto canvas node'}`;
- const outputActions = text(outputFooter, 'div', '', 'anomalous-mixer-output-actions');
- const copyOutputBtn = text(outputActions, 'button', `📋 ${t('copy')}`, 'anomalous-btn-ghost');
-
- // Target Node Direct Write Bar
- const targetBar = text(rightPanel, 'div', '', 'anomalous-prompt-target-bar');
+ // Target Node Direct Write Bar placed INSIDE outputDrawer so it collapses cleanly
+ const targetBar = text(outputDrawer, 'div', '', 'anomalous-prompt-target-bar');
const targetWidgetIndexByNodeId = {};
+ function updateOutputDeckState() {
+ const currentRoleParts = draft?.plan?.parts ? draft.plan.parts.filter(p => (p.role || 'positive') === activeTab) : [];
+ const compiledText = (draft?.plan?.[activeTab] || '').trim();
+ const hasContent = currentRoleParts.length > 0 && compiledText.length > 0;
+
+ if (!hasContent) {
+ outputDeck.style.display = 'none';
+ viewFinalBtn.style.display = 'none';
+ return;
+ }
+
+ outputDeck.style.display = 'flex';
+ viewFinalBtn.style.display = 'inline-flex';
+
+ if (isOutputExpanded) {
+ outputDeck.classList.remove('is-collapsed');
+ outputDrawer.style.display = 'flex';
+ expandOutputBtn.innerHTML = window.anomalous_browser_lang === 'zh' ? '收起 ▲' : 'Collapse ▲';
+ viewFinalBtn.classList.add('is-active');
+ } else {
+ outputDeck.classList.add('is-collapsed');
+ outputDrawer.style.display = 'none';
+ expandOutputBtn.innerHTML = window.anomalous_browser_lang === 'zh' ? '查看最终文本 ▾' : 'View Text ▾';
+ viewFinalBtn.classList.remove('is-active');
+ }
+ }
+
+ expandOutputBtn.onclick = (e) => {
+ e.stopPropagation();
+ isOutputExpanded = !isOutputExpanded;
+ updateOutputDeckState();
+ };
+
+ outputSummary.onclick = (e) => {
+ if (e.target.closest('button')) return;
+ isOutputExpanded = !isOutputExpanded;
+ updateOutputDeckState();
+ };
+
+ viewFinalBtn.onclick = () => {
+ isOutputExpanded = !isOutputExpanded;
+ updateOutputDeckState();
+ };
+
// Bind output deck drag once on mount
bindMaterialDrag(outputDeck, owner, {
payload: () => {
@@ -676,7 +737,7 @@ function buildPromptComposer(owner, container, options = {}) {
if (materialSyncController === controller) {
materialSyncController = null;
importMaterialsBtn.disabled = false;
- importMaterialsBtn.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '从素材库导入' : 'Import from Library'}`;
+ importMaterialsBtn.innerHTML = `${window.anomalous_browser_lang === 'zh' ? '导入' : 'Import'}`;
}
}
}
@@ -1275,15 +1336,16 @@ function buildPromptComposer(owner, container, options = {}) {
const compiledText = draft.plan[activeTab] || '';
outputTitle.innerHTML = activeTab === 'negative'
- ? `🚫 ${window.anomalous_browser_lang === 'zh' ? '实时合成负向文本' : 'Assembled Negative'}`
- : `✨ ${window.anomalous_browser_lang === 'zh' ? '实时合成正向文本' : 'Assembled Positive'}`;
+ ? `🚫 ${window.anomalous_browser_lang === 'zh' ? '最终负向文本' : 'Assembled Negative'}`
+ : `✨ ${window.anomalous_browser_lang === 'zh' ? '最终正向文本' : 'Assembled Positive'}`;
const words = compiledText.trim() ? compiledText.split(/[\s,,\n\r]+/).filter(Boolean).length : 0;
outputStats.textContent = window.anomalous_browser_lang === 'zh'
- ? `${compiledText.length} 字符 · 约 ${words} 个词组`
- : `${compiledText.length} chars · ~${words} tags`;
+ ? `(${compiledText.length} 字符 · 约 ${words} 词组)`
+ : `(${compiledText.length} chars · ~${words} tags)`;
outputTextarea.value = compiledText;
+ updateOutputDeckState();
}
// Smart Sort
@@ -1317,8 +1379,9 @@ function buildPromptComposer(owner, container, options = {}) {
};
// Copy preview text
- copyOutputBtn.onclick = async () => {
- const textToCopy = outputTextarea.value;
+ copyOutputBtn.onclick = async (e) => {
+ e?.stopPropagation?.();
+ const textToCopy = (draft.plan[activeTab] || outputTextarea.value || '').trim();
if (!textToCopy) return;
try {
await navigator.clipboard.writeText(textToCopy);
diff --git a/web/styles.css b/web/styles.css
index 0bc93b7..3557030 100644
--- a/web/styles.css
+++ b/web/styles.css
@@ -9522,8 +9522,8 @@ dialog.anomalous-gallery-viewer::backdrop {
.anomalous-prompt-composer {
display: flex;
flex-direction: column;
- gap: 16px;
- padding: 16px 20px 24px;
+ gap: 8px;
+ padding: 8px 12px 10px;
overflow-y: auto;
max-height: 100%;
color: #e2e8f0;
@@ -9534,20 +9534,20 @@ dialog.anomalous-gallery-viewer::backdrop {
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
- gap: 12px;
- padding-bottom: 12px;
+ gap: 8px;
+ padding-bottom: 6px;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.anomalous-prompt-topbar-left {
display: flex;
align-items: center;
- gap: 12px;
+ gap: 8px;
}
.anomalous-prompt-topbar-left h3 {
margin: 0;
- font-size: 1.05rem;
+ font-size: 0.98rem;
font-weight: 600;
color: #f8fafc;
letter-spacing: 0.02em;
@@ -9556,16 +9556,16 @@ dialog.anomalous-gallery-viewer::backdrop {
.anomalous-prompt-topbar-actions {
display: flex;
align-items: center;
- gap: 8px;
+ gap: 6px;
flex-wrap: wrap;
}
.anomalous-prompt-meta-strip {
display: flex;
align-items: center;
- gap: 10px;
- padding: 8px 12px;
- margin: 8px 14px 0;
+ gap: 8px;
+ padding: 4px 8px;
+ margin: 2px 10px 0;
border-radius: var(--amb-radius-control, 6px);
background: var(--amb-bg-panel, #1C1E24);
border: 1px solid var(--amb-border, rgba(255, 255, 255, 0.08));
@@ -9577,9 +9577,10 @@ dialog.anomalous-gallery-viewer::backdrop {
background: var(--amb-bg-input, #181a22);
border: 1px solid var(--amb-border, rgba(255, 255, 255, 0.12));
border-radius: var(--amb-radius-control, 6px);
- padding: 6px 12px;
+ padding: 3px 8px;
+ height: 28px;
color: var(--amb-text-main, #f1f5f9);
- font-size: 0.82rem;
+ font-size: 0.78rem;
outline: none;
transition: border-color 0.15s ease;
box-sizing: border-box;
@@ -10299,7 +10300,7 @@ dialog.anomalous-gallery-viewer::backdrop {
box-shadow: inset 0 0 0 1px rgba(220, 20, 60, 0.3);
}
-/* 4. Assembled Output Deck & Whole-Deck Canvas Drag (Sticky Floating Glass Deck) */
+/* 4. Assembled Output Deck & Whole-Deck Canvas Drag (Collapsible Glass Deck) */
.anomalous-mixer-deck-output {
position: sticky;
bottom: 0;
@@ -10310,19 +10311,27 @@ dialog.anomalous-gallery-viewer::backdrop {
-webkit-backdrop-filter: blur(12px);
border: 1px solid var(--amb-border, rgba(255, 255, 255, 0.12));
box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.35);
- padding: 8px 10px;
+ padding: 6px 10px;
display: flex;
flex-direction: column;
- gap: 6px;
+ gap: 4px;
cursor: grab;
user-select: none;
- transition: border-color 0.2s ease, box-shadow 0.2s ease;
+ transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
flex-shrink: 0 !important;
}
+.anomalous-mixer-deck-output.is-collapsed {
+ padding: 3px 8px;
+ background: rgba(22, 24, 30, 0.92);
+ border-radius: 6px;
+ cursor: pointer;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
+}
+
.anomalous-mixer-deck-output:hover {
border-color: #38bdf8;
- box-shadow: 0 0 12px rgba(56, 189, 248, 0.25);
+ box-shadow: 0 0 12px rgba(56, 189, 248, 0.2);
}
.theme-abyssal-scarlet .anomalous-mixer-deck-output {
@@ -10338,24 +10347,53 @@ dialog.anomalous-gallery-viewer::backdrop {
cursor: grabbing;
}
-.anomalous-mixer-output-header {
+.anomalous-mixer-output-summary {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
- border-bottom: 1px solid rgba(255, 255, 255, 0.08);
- padding-bottom: 4px;
+ min-height: 26px;
+ cursor: pointer;
+}
+
+.anomalous-mixer-summary-left {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.anomalous-mixer-summary-right {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ flex-shrink: 0;
}
.anomalous-mixer-output-title {
- font-size: 0.8rem;
+ font-size: 0.78rem;
color: #e2e8f0;
+ white-space: nowrap;
}
.anomalous-mixer-output-stats {
font-size: 0.7rem;
color: #94a3b8;
font-family: monospace;
+ white-space: nowrap;
+}
+
+.anomalous-mixer-output-drawer {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ border-top: 1px solid rgba(255, 255, 255, 0.08);
+ padding-top: 6px;
+ margin-top: 2px;
}
.anomalous-mixer-output-body {
@@ -10374,7 +10412,6 @@ dialog.anomalous-gallery-viewer::backdrop {
padding: 4px 8px;
outline: none;
box-sizing: border-box;
- pointer-events: none; /* allows deck drag seamlessly */
min-height: 34px;
max-height: 52px;
}
@@ -10402,10 +10439,22 @@ dialog.anomalous-gallery-viewer::backdrop {
color: #dc143c;
}
-.anomalous-mixer-output-actions {
- display: flex;
- align-items: center;
- gap: 6px;
+.anomalous-mixer-final-btn.is-active {
+ background: var(--amb-bg-card-hover, rgba(255, 255, 255, 0.15)) !important;
+ border-color: #38bdf8 !important;
+ color: #38bdf8 !important;
+}
+
+.anomalous-btn-toggle-output {
+ font-size: 0.72rem !important;
+ padding: 2px 7px !important;
+ color: #38bdf8 !important;
+ border-color: rgba(56, 189, 248, 0.25) !important;
+}
+
+.anomalous-btn-quick-copy {
+ font-size: 0.72rem !important;
+ padding: 2px 7px !important;
}
/* 5. Floating Toast Feedback */
@@ -10466,10 +10515,10 @@ dialog.anomalous-gallery-viewer::backdrop {
.anomalous-prompt-workbench-grid {
display: grid;
grid-template-columns: minmax(280px, 320px) minmax(460px, 1fr);
- gap: 14px;
+ gap: 10px;
flex: 1;
min-height: 0;
- padding: 10px 14px 14px;
+ padding: 6px 10px 8px;
overflow: hidden;
box-sizing: border-box;
}
@@ -10599,9 +10648,9 @@ dialog.anomalous-gallery-viewer::backdrop {
background: var(--amb-bg-panel, #1C1E24);
border: 1px solid var(--amb-border, rgba(255, 255, 255, 0.08));
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
- padding: 14px 14px 12px;
+ padding: 10px 10px 8px;
box-sizing: border-box;
- gap: 10px;
+ gap: 8px;
}
.anomalous-workbench-right-panel {
@@ -10613,8 +10662,8 @@ dialog.anomalous-gallery-viewer::backdrop {
display: flex;
align-items: center;
justify-content: space-between;
- gap: 8px;
- padding-bottom: 8px;
+ gap: 6px;
+ padding-bottom: 6px;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
flex-shrink: 0;
}
@@ -11005,7 +11054,8 @@ dialog.anomalous-gallery-viewer::backdrop {
-------------------------------------------------------------------------- */
.anomalous-assembly-track {
flex: 1 1 0 !important;
- min-height: 120px;
+ min-height: 200px;
+ height: 100%;
max-height: none !important;
overflow-y: auto;
overflow-x: hidden;
@@ -11026,7 +11076,8 @@ dialog.anomalous-gallery-viewer::backdrop {
.anomalous-assembly-dropzone {
flex: 1;
- min-height: 160px;
+ min-height: 240px;
+ height: 100%;
display: flex;
flex-direction: column;
align-items: center;