studio: monochrome shell theme + Copilot chat, Enso default

De-purple the ComfyUI shell theme (hanzo-theme.css) and the Copilot sidebar
chat (hanzo-copilot.css) to the canonical monochrome design system — no color
accent. Accent tokens map to neutral (icons/links/active #ededed, primary
buttons white-on-dark with #111 text like the Home CTA, selected/checked
neutral gray, focus ring #8a8a8a). Semantic status colors are unaffected.

Copilot default model 'zen' -> 'enso' (the Hanzo flagship assistant) —
Enso default everywhere, including Studio.
This commit is contained in:
Hanzo AI
2026-07-24 17:14:30 -07:00
parent c20b6b6fa5
commit 49b8d1ad0f
3 changed files with 81 additions and 79 deletions
+24 -23
View File
@@ -1,6 +1,7 @@
/* Hanzo Studio Copilot — black + Hanzo-purple sidebar chat.
* Reuses the theme's CSS vars (hanzo-theme.css) so it tracks the shell palette;
* hard-coded fallbacks keep it on-brand if a var is ever absent.
/* Hanzo Studio Copilot — monochrome sidebar chat.
* Tracks the shell's neutral theme vars (hanzo-theme.css) with canonical Hanzo
* design-system fallbacks: surface #0a0a0a · raised #1a1a1a · border #1f1f1f ·
* text #ededed · dim #888 · brand/CTA #fff. No color accent — monochrome.
*/
.hanzo-copilot {
display: flex;
@@ -9,7 +10,7 @@
width: 100%;
box-sizing: border-box;
background: var(--comfy-menu-bg, #0a0a0a);
color: var(--fg-color, #fff);
color: var(--fg-color, #ededed);
font-size: 13px;
}
@@ -26,8 +27,7 @@
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--p-primary-color, #8b5cf6);
box-shadow: 0 0 8px var(--p-primary-color, #8b5cf6);
background: #ededed;
}
.hanzo-copilot .hz-messages {
@@ -50,12 +50,13 @@
white-space: normal;
}
.hanzo-copilot .hz-user .hz-bubble {
background: var(--p-button-primary-background, #7c3aed);
color: #fff;
background: #ffffff;
color: #111;
border-bottom-right-radius: 4px;
}
.hanzo-copilot .hz-assistant .hz-bubble {
background: #1a1a1f;
background: #1a1a1a;
color: var(--fg-color, #ededed);
border: 1px solid var(--border-color, #1f1f1f);
border-bottom-left-radius: 4px;
}
@@ -69,17 +70,18 @@
}
.hanzo-copilot .hz-chip {
background: transparent;
color: #c4b5fd;
border: 1px solid #2a2140;
color: #888;
border: 1px solid var(--border-color, #1f1f1f);
border-radius: 999px;
padding: 5px 10px;
font-size: 11.5px;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.hanzo-copilot .hz-chip:hover {
background: rgba(139, 92, 246, 0.16);
border-color: var(--p-primary-color, #8b5cf6);
background: #1a1a1a;
border-color: #333;
color: #ededed;
}
.hanzo-copilot .hz-input {
@@ -93,7 +95,7 @@
flex: 1 1 auto;
resize: none;
background: var(--comfy-input-bg, #0a0a0a);
color: var(--fg-color, #fff);
color: var(--fg-color, #ededed);
border: 1px solid var(--border-color, #1f1f1f);
border-radius: 8px;
padding: 8px 10px;
@@ -101,11 +103,11 @@
outline: none;
}
.hanzo-copilot .hz-input textarea:focus {
border-color: var(--p-primary-color, #8b5cf6);
border-color: #888;
}
.hanzo-copilot .hz-send {
background: var(--p-button-primary-background, #7c3aed);
color: #fff;
background: #ffffff;
color: #111;
border: none;
border-radius: 8px;
padding: 9px 14px;
@@ -113,7 +115,7 @@
cursor: pointer;
transition: background 0.15s;
}
.hanzo-copilot .hz-send:hover { background: #6d28d9; }
.hanzo-copilot .hz-send:hover { background: #e4e4e7; }
.hanzo-copilot .hz-send:disabled { opacity: 0.5; cursor: default; }
/* Fallback toast (used only when the app toast service is unavailable) */
@@ -122,10 +124,9 @@
bottom: 24px;
left: 50%;
transform: translate(-50%, 12px);
background: #17171c;
color: #fff;
border: 1px solid #2a2140;
border-left: 3px solid var(--p-primary-color, #8b5cf6);
background: #1a1a1a;
color: #ededed;
border: 1px solid var(--border-color, #1f1f1f);
border-radius: 8px;
padding: 10px 16px;
font-size: 13px;
+55 -54
View File
@@ -1,11 +1,12 @@
/* Hanzo Studio — black surface + Hanzo-purple accent theme.
/* Hanzo Studio — black surface + monochrome accent theme.
* Minimal override: only background/surface/accent tokens are touched so the
* rest of the frontend's dark palette (text, node colors, borders) is intact.
* Loaded LAST in index.html so it beats PrimeVue's runtime-injected tokens;
* every declaration is !important because those tokens are injected after this
* sheet at boot. Colors chosen for WCAG AA contrast on black:
* accent #8B5CF6 on #000 -> 6.2:1 (AA normal text)
* button #ffffff on #7C3AED -> 5.25:1 (AA normal text)
* sheet at boot. Monochrome — no color accent — matching the canonical Hanzo
* design system (page #000 · surface #0a0a0a · raised #1a1a1a · border #1f1f1f ·
* text #ededed · accent/brand #ededed/#fff). Contrast on black:
* accent #ededed on #000 -> ~18:1 · button #111 on #fff -> ~18:1
*/
:root {
@@ -36,23 +37,23 @@
--p-overlay-popover-background: #0a0a0a !important;
--p-mask-background: rgba(0, 0, 0, 0.72) !important;
/* --- Hanzo purple accent --- */
--p-primary-color: #8b5cf6 !important; /* icons/links/active — AA on black */
--p-primary-contrast-color: #ffffff !important;
--p-primary-400: #a78bfa !important;
--p-primary-500: #8b5cf6 !important;
--p-primary-600: #7c3aed !important;
--p-focus-ring-color: #8b5cf6 !important;
--p-highlight-background: rgba(124, 58, 237, 0.24) !important;
--p-highlight-focus-background: rgba(124, 58, 237, 0.32) !important;
--p-highlight-color: #ede9fe !important;
/* --- Monochrome accent (near-white on black — icons/links/active) --- */
--p-primary-color: #ededed !important;
--p-primary-contrast-color: #111111 !important;
--p-primary-400: #f5f5f5 !important;
--p-primary-500: #ededed !important;
--p-primary-600: #d4d4d4 !important;
--p-focus-ring-color: #8a8a8a !important;
--p-highlight-background: rgba(255, 255, 255, 0.14) !important;
--p-highlight-focus-background: rgba(255, 255, 255, 0.20) !important;
--p-highlight-color: #ffffff !important;
/* --- Primary buttons: white on deeper violet keeps AA (5.25:1) --- */
--p-button-primary-background: #7c3aed !important;
--p-button-primary-hover-background: #6d28d9 !important;
--p-button-primary-active-background: #5b21b6 !important;
--p-button-primary-border-color: #7c3aed !important;
--p-button-primary-color: #ffffff !important;
/* --- Primary buttons: brand/CTA white on black, dark text (matches Home) --- */
--p-button-primary-background: #ffffff !important;
--p-button-primary-hover-background: #e4e4e7 !important;
--p-button-primary-active-background: #d4d4d4 !important;
--p-button-primary-border-color: #ffffff !important;
--p-button-primary-color: #111111 !important;
}
/* Pure-black canvas gutter behind the litegraph <canvas>. */
@@ -65,31 +66,31 @@ body.litegraph,
/* ── hover/active states: dark surfaces, never light (fix white-on-white) ── */
:root, :root.dark-theme {
--p-content-hover-background: #1f1f23 !important;
--p-content-hover-background: #1a1a1a !important;
--p-content-hover-color: #ffffff !important;
--p-navigation-item-hover-background: #1f1f23 !important;
--p-list-option-focus-background: #26262b !important;
--p-select-option-focus-background: #26262b !important;
--p-button-text-secondary-hover-background: #1f1f23 !important;
--p-button-text-primary-hover-background: rgba(139,92,246,.16) !important;
--p-button-secondary-hover-background: #26262b !important;
--p-togglebutton-hover-background: #26262b !important;
--p-tab-hover-background: #1f1f23 !important;
--p-menubar-item-focus-background: #26262b !important;
--p-menu-item-focus-background: #26262b !important;
--p-tree-node-hover-background: #1f1f23 !important;
--p-surface-100: #26262b !important;
--p-surface-200: #1f1f23 !important;
--p-highlight-background: rgba(139,92,246,.20) !important;
--p-navigation-item-hover-background: #1a1a1a !important;
--p-list-option-focus-background: #242424 !important;
--p-select-option-focus-background: #242424 !important;
--p-button-text-secondary-hover-background: #1a1a1a !important;
--p-button-text-primary-hover-background: rgba(255,255,255,.10) !important;
--p-button-secondary-hover-background: #242424 !important;
--p-togglebutton-hover-background: #242424 !important;
--p-tab-hover-background: #1a1a1a !important;
--p-menubar-item-focus-background: #242424 !important;
--p-menu-item-focus-background: #242424 !important;
--p-tree-node-hover-background: #1a1a1a !important;
--p-surface-100: #242424 !important;
--p-surface-200: #1a1a1a !important;
--p-highlight-background: rgba(255,255,255,.14) !important;
--p-highlight-color: #ffffff !important;
}
.side-tool-bar-container .p-button:hover,
.side-bar-button:hover,
.comfyui-button:hover {
background: #1f1f23 !important;
background: #1a1a1a !important;
color: #fff !important;
}
.p-button-text:not(.p-button-danger):hover { background: #1f1f23 !important; color: #fff !important; }
.p-button-text:not(.p-button-danger):hover { background: #1a1a1a !important; color: #fff !important; }
/* ── the H logo menu button: keep the mark visible on hover/open ── */
button:has(> .comfyui-logo):hover,
@@ -97,7 +98,7 @@ button:has(.comfyui-logo):hover,
.p-button:has(.comfyui-logo):hover,
button:has(.comfyui-logo)[aria-expanded="true"],
.comfyui-logo-menu-trigger:hover {
background: #1f1f23 !important;
background: #1a1a1a !important;
}
button:has(.comfyui-logo):hover .comfyui-logo,
button:has(.comfyui-logo):hover svg,
@@ -106,37 +107,37 @@ button:has(.comfyui-logo):hover path {
fill: #ffffff !important;
}
/* ── active/selected/checked states: never white (white-box-under-H fix) ── */
/* ── active/selected/checked states: neutral gray, never white ── */
:root, :root.dark-theme {
--p-button-secondary-active-background: #26262b !important;
--p-togglebutton-checked-background: #2a2140 !important;
--p-togglebutton-checked-color: #c4b5fd !important;
--p-navigation-item-active-background: #26262b !important;
--p-button-secondary-active-background: #242424 !important;
--p-togglebutton-checked-background: #242424 !important;
--p-togglebutton-checked-color: #ededed !important;
--p-navigation-item-active-background: #242424 !important;
--p-tab-active-background: #0a0a0a !important;
--p-button-text-primary-active-background: rgba(139,92,246,.24) !important;
--p-button-text-primary-active-background: rgba(255,255,255,.16) !important;
}
.side-tool-bar-container .p-button.p-highlight,
.side-tool-bar-container .p-togglebutton.p-togglebutton-checked,
.side-tool-bar-container [aria-pressed="true"],
.side-tool-bar-container .p-button:active,
.p-selectbutton .p-button.p-highlight {
background: #2a2140 !important;
color: #c4b5fd !important;
background: #242424 !important;
color: #ededed !important;
}
.side-tool-bar-container .p-button.p-highlight svg,
.side-tool-bar-container [aria-pressed="true"] svg { color: #c4b5fd !important; fill: currentColor !important; }
.side-tool-bar-container [aria-pressed="true"] svg { color: #ededed !important; fill: currentColor !important; }
/* ── selected sidebar icon: purple-tinted dark, never white ── */
/* ── selected sidebar icon: neutral dark, never white ── */
:root, :root.dark-theme {
--interface-panel-selected-surface: #2a2140 !important;
--interface-menu-component-surface-selected: #2a2140 !important;
--interface-panel-selected-surface: #242424 !important;
--interface-menu-component-surface-selected: #242424 !important;
}
.side-bar-button-selected {
background-color: #2a2140 !important;
color: #c4b5fd !important;
background-color: #242424 !important;
color: #ededed !important;
}
.side-bar-button-selected svg, .side-bar-button-selected i { color: #c4b5fd !important; }
.side-bar-button-selected svg, .side-bar-button-selected i { color: #ededed !important; }
.selected:not(.p-galleria-thumbnail-item) {
background-color: #2a2140 !important;
background-color: #242424 !important;
color: #e5e5e5 !important;
}
+2 -2
View File
@@ -17,7 +17,7 @@ Env (all optional):
STUDIO_COPILOT_URL chat-completions URL. Default: the local engine at
http://127.0.0.1:1234/v1/chat/completions if that port
is open, else https://api.hanzo.ai/v1/chat/completions.
STUDIO_COPILOT_MODEL model id (default "zen").
STUDIO_COPILOT_MODEL model id (default "enso" — the Hanzo flagship assistant).
STUDIO_COPILOT_TOKEN bearer for the gateway. Falls back to
STUDIO_COMMERCE_TOKEN, then any bearer on the request.
@@ -144,7 +144,7 @@ class CopilotError(Exception):
def _resolve_target(request) -> tuple[str, str, str]:
"""(url, model, token) for this request."""
url = os.environ.get("STUDIO_COPILOT_URL", "").strip() or _DEFAULT_URL
model = os.environ.get("STUDIO_COPILOT_MODEL", "").strip() or "zen"
model = os.environ.get("STUDIO_COPILOT_MODEL", "").strip() or "enso"
token = (
os.environ.get("STUDIO_COPILOT_TOKEN", "").strip()
or os.environ.get("STUDIO_COMMERCE_TOKEN", "").strip()