zcbot/web/static/ui.css

885 lines
14 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* zcbot UI foundation
*
* The application intentionally stays build-free. This file is the shared
* visual layer for the main SPA: tokens, control states and restrained
* workspace polish. Feature-specific layout remains next to dev.html until
* it is reused by a second surface.
*/
:root {
color-scheme: light;
/* Neutral workspace palette */
--bg: #ffffff;
--panel: #ffffff;
--panel-subtle: #fcfcfc;
--panel-muted: #f8f8f8;
--border: #e1e3e5;
--border-soft: #eceeef;
--list-divider: #d9dde0;
--text: #242424;
--text-strong: #171717;
--muted: #73777c;
/* Institute red is deliberately reserved for primary emphasis. */
--accent: #b83a31;
--accent-hover: #a9322a;
--accent-soft: #fbecea;
--accent-ring: rgba(184, 58, 49, 0.16);
--hover: #f7f7f7;
--code-bg: #f7f7f7;
--user-bg: #f6f8fa;
--asst-bg: #ffffff;
--c-green: #238653;
--c-green-bg: #eaf6ef;
--c-green-bd: #a9d9bd;
--c-blue: #2d6f9f;
--c-blue-bg: #edf5fa;
--c-blue-bd: #b5d5e7;
--c-purple: #7c5192;
--c-purple-bg: #f5eff8;
--c-purple-bd: #d8c4e1;
--c-orange: #bf6a20;
--c-orange-bg: #fdf3e8;
--c-orange-bd: #ebc79f;
--c-red: #b83a31;
--c-red-bg: #fbecea;
--c-red-bd: #e7b3ae;
/* One compact radius and spacing vocabulary. */
--r-sm: 4px;
--r-md: 6px;
--r-lg: 8px;
--r-xl: 10px;
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 24px;
--space-6: 32px;
--shadow-float: 0 10px 30px rgba(24, 32, 41, 0.12);
--shadow-card: 0 18px 48px rgba(24, 32, 41, 0.16);
--shadow-card-lg:
0 24px 72px rgba(24, 32, 41, 0.14),
0 2px 8px rgba(24, 32, 41, 0.06);
--mono: ui-monospace, "Cascadia Code", "SF Mono", Consolas, monospace;
--t: background-color 0.15s ease, border-color 0.15s ease,
color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
body {
font-size: 14px;
line-height: 1.55;
color: var(--text);
background: var(--bg);
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
button,
input,
textarea,
select {
transition: var(--t);
}
button {
min-height: 32px;
padding: 5px 11px;
font-weight: 500;
}
button.small {
min-height: 28px;
}
button:hover:not(:disabled) {
border-color: #cbd1d6;
}
button.primary {
background: var(--accent);
border-color: var(--accent);
box-shadow: 0 1px 2px rgba(73, 25, 21, 0.16);
}
button.primary:hover:not(:disabled) {
background: var(--accent-hover);
border-color: var(--accent-hover);
filter: none;
}
button:disabled {
opacity: 0.46;
}
button:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
textarea,
select {
min-height: 34px;
border-color: var(--border);
}
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):hover,
textarea:hover,
select:hover {
border-color: #c7cdd2;
}
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus,
textarea:focus,
select:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-ring);
}
::placeholder {
color: #999fa5;
}
/* Application shell */
#app.ready {
background: var(--bg);
}
header {
min-height: 48px;
padding: 9px 16px;
border-bottom-color: var(--border);
box-shadow: 0 1px 0 rgba(24, 32, 41, 0.02);
}
header .brand {
gap: 10px;
}
header .brand .logo {
width: 26px;
height: 26px;
box-shadow: 0 2px 8px rgba(184, 58, 49, 0.2);
}
header .title {
color: var(--text-strong);
font-size: 15px;
letter-spacing: 0.1px;
}
header .who {
color: var(--muted);
}
.pane {
border-color: var(--border);
}
#pane-left,
#pane-right {
background: var(--panel);
}
#pane-mid {
background: var(--panel);
}
.splitter {
background: var(--bg);
}
.splitter::before {
background: #d7dce0;
}
.pane-head {
min-height: 44px;
padding: 8px 12px;
background: var(--panel);
border-bottom-color: var(--border-soft);
}
.pane-head .label {
color: var(--text-strong);
font-size: 13px;
letter-spacing: 0.2px;
}
#btn-toggle-hidden[aria-pressed="true"] {
color: var(--accent);
border-color: var(--accent);
background: var(--accent-soft);
}
#pane-left .pane-head + .pane-head {
background: var(--panel);
}
#task-scroll,
#file-list {
scrollbar-color: #cbd1d6 transparent;
scrollbar-width: thin;
}
/* Task and resource navigation */
#channel-cards {
padding: 8px 10px 4px;
}
.channel-card {
border-color: rgba(7, 158, 82, 0.26);
background: rgba(7, 158, 82, 0.045);
}
#task-list {
padding: 0;
}
.task-row {
margin: 0;
padding: 10px 12px 10px 9px;
border: 0;
border-left: 3px solid transparent;
border-bottom: 1px solid var(--list-divider);
border-radius: 0;
}
.task-row:hover {
background: var(--hover);
box-shadow: none;
}
.task-row.active {
padding-left: 9px;
background: var(--accent-soft);
border-left: 3px solid var(--accent);
border-bottom-color: #e8c6c3;
box-shadow: none;
}
.task-row .desc {
color: var(--text-strong);
}
.task-row .meta {
color: var(--muted);
}
.task-row .badge,
.sk-badge {
border-radius: var(--r-sm);
}
#rail-resources {
padding: 8px;
border-top-color: var(--border-soft);
background: var(--panel);
}
#rail-resources > button {
min-height: 48px;
border-color: transparent;
color: #59616b;
background: transparent;
}
#rail-resources > button:hover {
color: var(--accent);
border-color: #f0d2cf;
background: var(--accent-soft);
}
/* Menus and lightweight cards */
#floating-menu,
#media-model-pop {
border-color: var(--border);
border-radius: var(--r-lg);
box-shadow: var(--shadow-float);
}
.dd-item {
padding: 7px 14px;
}
.dd-item:hover {
background: var(--panel-muted);
}
.sk-item {
padding: 9px 10px;
border-color: var(--border-soft);
background: var(--panel);
}
.sk-item:hover {
border-color: #d2a09b;
background: var(--accent-soft);
}
.sk-item.active {
border-color: var(--accent);
background: var(--accent-soft);
}
.empty,
.sk-empty {
color: var(--muted);
line-height: 1.7;
}
/* Conversation: one left-anchored reading rail, with each assistant turn grouped
as a document block rather than a floating chat label. */
#chat-meta {
min-height: 40px;
padding: 8px 16px;
background: var(--panel);
border-bottom-color: var(--border-soft);
}
#chat-stream {
gap: 16px;
padding: 20px clamp(16px, 3vw, 36px) 24px;
background: var(--panel);
scrollbar-color: #cbd1d7 transparent;
scrollbar-width: thin;
}
.msg {
padding: 10px 13px;
border-color: var(--border-soft);
border-radius: var(--r-lg);
}
.msg.user {
background: var(--user-bg);
border-color: #dce6f0;
}
.msg.assistant {
width: min(100%, 52rem);
max-width: min(100%, 52rem);
align-self: flex-start;
padding: 3px 0 18px;
border: 0;
border-bottom: 1px solid var(--border-soft);
border-radius: 0;
background: transparent;
}
.msg.assistant.live-run {
padding: 3px 0 18px;
border: 0;
border-bottom: 1px solid var(--border-soft);
border-radius: 0;
box-shadow: none;
}
.msg .role {
margin-bottom: 4px;
color: #7d858f;
font-family: inherit;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.2px;
}
.msg.assistant > .role {
display: none;
}
.msg.tool {
width: min(100%, 52rem);
max-width: min(100%, 52rem);
align-self: flex-start;
padding: 0;
border: 0;
background: transparent;
}
.msg.tool > .role {
display: none;
}
#task-progress-dock .task-progress {
width: min(100%, 52rem);
max-width: 52rem;
margin: 0;
}
.msg .body {
color: var(--text);
font-size: 15px;
line-height: 1.7;
}
.msg .body p {
margin: 0.65em 0;
}
.msg .body h1,
.msg .body h2,
.msg .body h3 {
color: var(--text-strong);
line-height: 1.35;
}
.mermaid-diagram {
margin: 14px 0;
padding: 14px;
overflow-x: auto;
border: 1px solid var(--border-soft);
border-radius: var(--r-lg);
background: #ffffff;
}
.mermaid-viewport {
min-width: min-content;
}
.mermaid-viewport svg {
display: block;
max-width: 100%;
height: auto;
margin: 0 auto;
}
.mermaid-notice {
margin: 10px 0 4px;
padding: 7px 9px;
color: var(--muted);
border-left: 3px solid var(--border);
background: var(--panel-muted);
font-size: 12px;
}
.mermaid-notice.error {
color: var(--c-red);
border-left-color: var(--c-red);
}
.msg-actions {
margin-top: 8px;
}
.tool-call,
.reasoning {
color: #555b60;
}
.reasoning summary {
padding: 6px 8px;
border: 1px solid var(--border-soft);
border-radius: var(--r-md);
background: var(--panel-muted);
}
.reasoning summary:hover {
background: var(--hover);
}
.tool-call.activity {
margin: 3px 0;
}
.tool-call.activity > summary {
display: flex;
align-items: center;
min-height: 28px;
gap: 7px;
padding: 3px 6px;
color: var(--muted);
border: 0;
border-radius: var(--r-md);
background: transparent;
list-style: none;
}
.tool-call.activity > summary::-webkit-details-marker {
display: none;
}
.tool-call.activity > summary::after {
content: "";
flex: none;
margin-left: 2px;
color: var(--muted);
font-size: 15px;
line-height: 1;
transform: rotate(0deg);
transition: transform 0.15s ease;
}
.tool-call.activity[open] > summary::after {
transform: rotate(90deg);
}
.tool-call.activity > summary:hover,
.tool-call.activity[open] > summary {
color: var(--text);
background: var(--hover);
}
.tool-call.activity .tool-state {
width: 16px;
flex: none;
color: var(--c-green);
font-family: var(--mono);
font-weight: 700;
text-align: center;
}
.tool-call.activity.running .tool-state {
color: var(--muted);
}
.tool-call.activity.failed > summary,
.tool-call.activity.failed .tool-state {
color: var(--c-red);
}
.tool-call.activity .tool-label {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tool-call.activity .tool-result-meta {
margin-left: auto;
color: var(--muted);
font-size: 11px;
white-space: nowrap;
}
.tool-call.activity > pre {
margin: 3px 0 5px 23px;
}
.tool-call pre {
border: 1px solid var(--border-soft);
background: var(--code-bg);
}
#chat-form {
gap: 8px;
padding: 12px 16px 14px;
border-top-color: var(--border-soft);
background: var(--panel);
box-shadow: 0 -8px 24px rgba(24, 32, 41, 0.035);
}
#chat-input {
min-height: 72px;
padding: 10px 12px;
line-height: 1.6;
border-radius: var(--r-lg);
background: #ffffff;
}
#chat-form .row {
align-items: center;
}
#chat-hint:empty {
display: none;
}
.composer-spacer {
flex: 1;
}
.composer-tool {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 5px;
}
.composer-tool svg {
width: 15px;
height: 15px;
flex: none;
}
#chat-action {
min-width: 64px;
}
/* File pane */
.crumbs {
min-height: 38px;
padding: 9px 12px;
background: var(--panel);
border-bottom-color: var(--border-soft);
}
.file-row {
min-height: 38px;
padding: 7px 12px;
border-bottom: 1px solid var(--list-divider);
}
.file-row:hover {
background: var(--hover);
}
.file-row .name {
color: #303438;
}
.storage-foot {
padding: 8px 12px;
border-top-color: var(--border-soft);
background: var(--panel);
}
.storage-foot .bar {
height: 5px;
background: #e5e8ea;
}
/* Dialogs and notifications */
.modal {
padding: 16px;
background: rgba(22, 28, 35, 0.46);
}
.modal > .card {
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.72);
box-shadow: var(--shadow-card);
}
#chpw-modal h3,
#app-dialog h3,
#changelog-modal h3,
#skills-modal h3,
#wechat-modal h3,
#crons-modal h3,
#memory-modal h3,
#kb-modal h3 {
min-height: 48px;
padding: 13px 18px;
color: var(--text-strong);
border-bottom-color: var(--border-soft);
}
#app-dialog .body,
#chpw-modal .body {
padding: 18px;
}
#app-dialog .actions,
#chpw-modal .actions,
#src-picker-modal .actions {
padding: 12px 18px;
border-top-color: var(--border-soft);
background: var(--panel-subtle);
}
.toast,
.app-msg {
border: 1px solid var(--border-soft);
border-radius: var(--r-lg);
box-shadow: var(--shadow-float);
}
/* Respect system motion preferences for polish-only transitions too. */
@media (prefers-reduced-motion: reduce) {
button,
input,
textarea,
select {
transition: none;
}
}
@media (max-width: 640px) {
header {
min-height: 42px;
padding: 5px 9px;
}
.pane-head {
min-height: 36px;
}
.mobile-tabs {
gap: 5px;
}
.mobile-tabs button {
min-height: 34px;
padding: 4px 7px;
font-size: 11.5px;
}
#hd-admin {
padding: 4px 8px;
font-size: 11px;
}
#pane-mid > .pane-head {
min-height: 34px;
padding: 4px 8px;
}
#pane-mid > .pane-head > button {
min-height: 28px;
padding: 3px 8px;
font-size: 11.5px;
}
#chat-meta {
min-height: auto;
padding: 5px 8px;
column-gap: 5px;
row-gap: 5px;
}
#chat-meta > .spacer {
flex: 1 0 100%;
height: 0;
}
#chat-meta .mdl-wrap {
flex: 1 1 auto;
min-width: 0;
}
#chat-meta.draft-meta .mdl-wrap {
flex: 0 1 auto;
}
#chat-meta.draft-meta select {
width: auto !important;
max-width: 48vw;
}
#chat-meta select {
width: 100% !important;
max-width: none;
min-height: 30px;
padding: 2px 6px;
font-size: 12px;
}
#chat-meta button {
min-height: 30px;
padding: 2px 7px;
font-size: 11.5px;
}
#task-progress-dock {
padding: 5px 8px;
}
#chat-stream {
gap: 11px;
padding: 10px 10px 12px;
}
.msg {
max-width: 100%;
}
.msg.assistant {
width: 100%;
max-width: 100%;
padding: 2px 0 14px;
}
.msg.tool {
width: 100%;
max-width: 100%;
padding: 0;
}
.msg .body {
font-size: 15px;
line-height: 1.68;
}
#chat-form {
padding: 8px 9px;
padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
}
#chat-input {
min-height: 52px;
}
#chat-form .row {
flex-wrap: wrap;
justify-content: flex-end;
gap: 6px;
}
#chat-hint {
order: -1;
flex: 1 0 100%;
line-height: 18px;
}
.composer-spacer {
display: none;
}
#chat-form .row .composer-tool {
width: 40px;
min-width: 40px;
height: 40px;
min-height: 40px;
padding: 0;
}
.composer-tool svg {
width: 18px;
height: 18px;
}
.composer-tool .composer-label {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
#chat-action {
width: 68px;
min-width: 68px;
height: 40px;
min-height: 40px;
padding: 5px 12px;
}
.modal {
padding: 12px;
}
}