Process timeline: a run of consecutive thinking and tool calls is one
block that folds to a single line ("思考 4 次 · 工具 6 次"; while running
it shows the current action) and opens into a compact timeline, one row
per thought or call. Visible text, a note or the next prompt closes the
block; history and the live stream follow the same rule. show_thinking
now also applies while streaming instead of forcing thoughts open.
Layout: the avatar gutter and the flex-wrap that dropped it under long
answers are gone, so answer, process blocks, notes and composer share one
left edge. The text column and composer are both 720px (--content); the
rail and run panel grow with clamp() on wide screens. A rebuild after
each turn no longer replays every entrance animation, and the turn time
survives it. Message actions are icon buttons and only appear under text.
Images: a prompt's images sit above the bubble, right-aligned (one keeps
its shape, several are 152px rounded tiles) and open in a lightbox (Esc,
arrow keys). Images uploaded from the page show as thumbnails over the
composer and appear on the prompt as soon as it is sent.
Also: ?theme= is no longer overridden by app.js, the user bubble is
visible in the light theme, and the narrow top bar no longer wraps.
924 lines
47 KiB
CSS
924 lines
47 KiB
CSS
/* CST-Agent WebUI - one stylesheet, no build step.
|
|
*
|
|
* Design rules
|
|
* - one fact, one home: sessions in the rail, model/approval/plan in the
|
|
* top bar, the run in the right panel, attachments in the composer;
|
|
* - settings open as popovers anchored to the control that owns them,
|
|
* with icon + label + one line of explanation + a check on the current
|
|
* value (the pattern all three reference apps use);
|
|
* - motion is short and eased: 120ms for feedback, 180ms for entrances,
|
|
* nothing bounces, and prefers-reduced-motion turns it all off. */
|
|
|
|
/* Tokens are named the way the reference desktop app names them: four text
|
|
* levels, three surfaces per zone (main / sidebar / composer), and borders
|
|
* mixed out of the foreground rather than hard-coded greys - which is what
|
|
* keeps the dark and the light sheet on the same visual rhythm. */
|
|
:root {
|
|
color-scheme: dark;
|
|
|
|
--text-primary: #f2f2f5;
|
|
--text-secondary: #a9a9b4;
|
|
--text-tertiary: #7d7d89;
|
|
--text-quaternary: #5e5e69;
|
|
--text-error: #f0616d;
|
|
--text-success: #3ecf95;
|
|
|
|
--main-surface-primary: #0d0d0f;
|
|
--main-surface-secondary: #141417;
|
|
--main-surface-tertiary: #1d1d22;
|
|
|
|
--sidebar-surface-primary: #111114;
|
|
--sidebar-surface-secondary: #18181c;
|
|
--sidebar-surface-tertiary: #202026;
|
|
|
|
--composer-surface-primary: #16161a;
|
|
--composer-surface-secondary: #202026;
|
|
|
|
--bg-code: #08080a;
|
|
--bubble-user: var(--main-surface-tertiary);
|
|
|
|
/* every hover/active tint is alpha, so it lands correctly on any surface */
|
|
--hover: color-mix(in srgb, var(--text-primary) 7%, transparent);
|
|
--hover-strong: color-mix(in srgb, var(--text-primary) 13%, transparent);
|
|
|
|
--accent-primary: #3ecf95;
|
|
--accent-fg: #04241a;
|
|
--accent-weak: color-mix(in srgb, var(--accent-primary) 14%, transparent);
|
|
--accent-line: color-mix(in srgb, var(--accent-primary) 55%, transparent);
|
|
--link: var(--accent-primary);
|
|
--violet: #8b7bff;
|
|
--warn: #e0b341;
|
|
--selection-bg: color-mix(in srgb, var(--accent-primary) 30%, transparent);
|
|
--selection-fg: var(--text-primary);
|
|
|
|
--border-light: color-mix(in srgb, var(--text-primary) 14%, transparent);
|
|
--border-medium: color-mix(in srgb, var(--text-primary) 24%, transparent);
|
|
--border-heavy: color-mix(in srgb, var(--text-primary) 34%, transparent);
|
|
|
|
/* short aliases: the rest of the sheet keeps reading the same way */
|
|
--bg: var(--main-surface-primary);
|
|
--bg-soft: var(--main-surface-secondary);
|
|
--bg-lift: var(--main-surface-tertiary);
|
|
--bg-hover: var(--hover);
|
|
--fg: var(--text-primary);
|
|
--fg-dim: var(--text-secondary);
|
|
--fg-faint: var(--text-tertiary);
|
|
--fg-quat: var(--text-quaternary);
|
|
--line: var(--border-light);
|
|
--line-strong: var(--border-medium);
|
|
--accent: var(--accent-primary);
|
|
--danger: var(--text-error);
|
|
|
|
/* the side columns grow with the screen so a wide window does not turn into
|
|
* one wide middle: the text stays near the run panel it is read against */
|
|
--rail: clamp(240px, 14vw, 280px);
|
|
--panel: clamp(296px, 20vw, 380px);
|
|
--content: 720px; /* text column and composer share this edge */
|
|
--radius: 12px;
|
|
--radius-lg: 22px;
|
|
--shadow: 0 16px 40px rgba(0, 0, 0, .45);
|
|
--shadow-sm: 0 6px 18px rgba(0, 0, 0, .3);
|
|
--mono: ui-monospace, SFMono-Regular, "JetBrains Mono", Menlo, Consolas, monospace;
|
|
--sans: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans CJK SC", sans-serif;
|
|
--ease: cubic-bezier(.22, .61, .36, 1);
|
|
--ease-pop: cubic-bezier(.2, .9, .3, 1.06); /* enters with a hint of overshoot */
|
|
--t-fast: 120ms;
|
|
--t: 180ms;
|
|
}
|
|
[data-theme="light"] {
|
|
color-scheme: light;
|
|
|
|
--text-primary: #14141a;
|
|
--text-secondary: #55555f;
|
|
--text-tertiary: #7c7c86;
|
|
--text-quaternary: #9c9ca6;
|
|
--text-error: #c8303f;
|
|
--text-success: #0f8f66;
|
|
|
|
--main-surface-primary: #ffffff;
|
|
--main-surface-secondary: #f7f7f9;
|
|
--main-surface-tertiary: #ffffff;
|
|
|
|
--sidebar-surface-primary: #fafafb;
|
|
--sidebar-surface-secondary: #f1f1f4;
|
|
--sidebar-surface-tertiary: #ffffff;
|
|
|
|
--composer-surface-primary: #ffffff;
|
|
--composer-surface-secondary: #f4f4f6;
|
|
|
|
--bg-code: #f5f5f7;
|
|
--bubble-user: #eef0f4;
|
|
|
|
--accent-primary: #0f9d70;
|
|
--accent-fg: #ffffff;
|
|
|
|
--border-light: color-mix(in srgb, var(--text-primary) 12%, transparent);
|
|
--border-medium: color-mix(in srgb, var(--text-primary) 20%, transparent);
|
|
--border-heavy: color-mix(in srgb, var(--text-primary) 30%, transparent);
|
|
|
|
--warn: #a9761a;
|
|
--shadow: 0 16px 40px rgba(20, 20, 35, .14);
|
|
--shadow-sm: 0 6px 18px rgba(20, 20, 35, .1);
|
|
}
|
|
|
|
* { box-sizing: border-box; }
|
|
html, body { height: 100%; margin: 0; }
|
|
body {
|
|
background: var(--bg); color: var(--fg);
|
|
font: 15px/1.62 var(--sans);
|
|
-webkit-font-smoothing: antialiased;
|
|
-webkit-text-size-adjust: 100%;
|
|
overflow: hidden; /* columns scroll, never the page */
|
|
}
|
|
button, textarea, input { font: inherit; color: inherit; }
|
|
button { cursor: pointer; background: none; border: 0; }
|
|
button:disabled { cursor: default; }
|
|
.grow { flex: 1 1 auto; }
|
|
.quiet, .muted { color: var(--fg-dim); }
|
|
.tiny { font-size: 12px; }
|
|
[hidden] { display: none !important; }
|
|
::selection { background: var(--selection-bg); color: var(--selection-fg); }
|
|
|
|
/* one icon system: everything is drawn on the same 24px grid, stroked with
|
|
* the current text colour, so header, rail, popovers and composer match */
|
|
svg.i {
|
|
width: 18px; height: 18px; flex: 0 0 auto; display: block;
|
|
fill: none; stroke: currentColor; stroke-width: 1.7;
|
|
stroke-linecap: round; stroke-linejoin: round;
|
|
}
|
|
svg.i .f { fill: currentColor; stroke: none; }
|
|
.icon svg.i { width: 18px; height: 18px; }
|
|
.icon.tiny svg.i { width: 15px; height: 15px; }
|
|
.chip svg.i { width: 15px; height: 15px; }
|
|
.chip .chev { width: 13px; height: 13px; opacity: .6; }
|
|
.new-task svg.i { width: 17px; height: 17px; }
|
|
.send svg.i { width: 19px; height: 19px; stroke-width: 2; }
|
|
svg.i.only-light { display: none; }
|
|
[data-theme="light"] svg.i.only-dark { display: none; }
|
|
[data-theme="light"] svg.i.only-light { display: block; }
|
|
|
|
/* the changed-file rows in the run panel: path, then +added / -removed */
|
|
.fstat { display: flex; align-items: center; gap: 8px; padding: 5px 0; font-size: 13px; animation: fade-in var(--t) var(--ease) both; }
|
|
.fstat .fimg { width: 15px; height: 15px; color: var(--text-quaternary); }
|
|
.fstat .p {
|
|
flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
|
|
white-space: nowrap; font-family: var(--mono); font-size: 12px;
|
|
}
|
|
.fstat .a, .fstat .d { font-variant-numeric: tabular-nums; font-size: 12px; }
|
|
.fstat .a { color: var(--text-success); }
|
|
.fstat .d { color: var(--text-error); }
|
|
|
|
::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
::-webkit-scrollbar-thumb {
|
|
background: var(--line-strong); border-radius: 99px;
|
|
border: 3px solid transparent; background-clip: content-box;
|
|
}
|
|
::-webkit-scrollbar-thumb:hover { background: var(--fg-faint); background-clip: content-box; }
|
|
|
|
/* --- frame ---------------------------------------------------------------- */
|
|
#app {
|
|
display: grid;
|
|
grid-template-columns: var(--rail) minmax(0, 1fr) var(--panel);
|
|
grid-template-rows: minmax(0, 1fr);
|
|
height: 100dvh;
|
|
/* the rail keeps its track and collapses to 0px, so the two states have the
|
|
* same track count and the column width can actually be interpolated */
|
|
transition: grid-template-columns 300ms var(--ease);
|
|
}
|
|
/* a zeroed track plus display:none used to slide #main into column one and
|
|
* crush it to nothing; the rail now stays in flow and is clipped instead */
|
|
body.no-side #app { grid-template-columns: 0px minmax(0, 1fr) var(--panel); }
|
|
body.no-panel #app { grid-template-columns: var(--rail) minmax(0, 1fr) 0px; }
|
|
body.no-side.no-panel #app { grid-template-columns: 0px minmax(0, 1fr) 0px; }
|
|
/* the expand control only exists while the rail is folded away, so exactly one
|
|
* toggle is ever on screen */
|
|
#btn-side { display: none; }
|
|
body.no-side #btn-side { display: inline-flex; }
|
|
|
|
.icon {
|
|
width: 32px; height: 32px; border-radius: 9px; flex: 0 0 auto;
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
color: var(--fg-dim); font-size: 15px;
|
|
transition: background var(--t-fast), color var(--t-fast), transform 90ms var(--ease);
|
|
}
|
|
.icon:hover { background: var(--bg-hover); color: var(--fg); }
|
|
.icon:active { transform: scale(.94); }
|
|
.icon.tiny { width: 26px; height: 26px; font-size: 13px; }
|
|
.round { border-radius: 50%; }
|
|
.chip {
|
|
display: inline-flex; align-items: center; gap: 5px; height: 30px;
|
|
padding: 0 11px; border-radius: 99px; border: 1px solid transparent;
|
|
background: none; color: var(--fg-dim); font-size: 13px;
|
|
max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast), transform 90ms var(--ease);
|
|
}
|
|
.chip:hover { background: var(--bg-hover); color: var(--fg); }
|
|
.chip:active { transform: scale(.97); }
|
|
.chip.model { color: var(--fg); font-weight: 600; background: var(--bg-lift); border-color: var(--line); }
|
|
.chip.model:hover { border-color: var(--line-strong); }
|
|
.chip.warn { color: var(--warn); }
|
|
.chip .chev { font-size: 11px; opacity: .65; }
|
|
.badge {
|
|
min-width: 18px; height: 18px; padding: 0 5px; border-radius: 99px;
|
|
background: var(--accent-weak); color: var(--accent);
|
|
font-size: 11px; font-weight: 700;
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
}
|
|
|
|
/* --- rail ----------------------------------------------------------------- */
|
|
#side {
|
|
background: var(--sidebar-surface-primary); border-right: 1px solid var(--border-light);
|
|
min-width: 0; overflow: hidden; /* clips the rail while its track collapses */
|
|
}
|
|
/* the contents keep their own width and slide out, so nothing reflows mid-flight
|
|
* and the exit reads as one movement instead of a squeeze */
|
|
.side-inner {
|
|
width: var(--rail); height: 100%; min-width: 0;
|
|
display: flex; flex-direction: column; padding: 12px 10px 10px;
|
|
transition: transform 300ms var(--ease-pop), opacity 200ms var(--ease);
|
|
}
|
|
body.no-side .side-inner { transform: translateX(-18px); opacity: 0; }
|
|
body.no-side #side { pointer-events: none; }
|
|
.side-head { display: flex; align-items: center; gap: 2px; margin-bottom: 14px; }
|
|
/* the wordmark is a label, not a control: no logo tile, nothing to click */
|
|
.brand { flex: 1 1 auto; display: flex; align-items: center; min-width: 0; padding: 6px 8px; }
|
|
.brand-name {
|
|
font-weight: 700; letter-spacing: .2px; font-size: 15px;
|
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
}
|
|
|
|
.new-task {
|
|
display: flex; align-items: center; gap: 9px; height: 40px; padding: 0 12px;
|
|
margin-bottom: 18px; border-radius: 12px; font-weight: 600;
|
|
background: var(--bg-lift); border: 1px solid var(--line);
|
|
transition: border-color var(--t-fast), background var(--t-fast), transform 90ms var(--ease);
|
|
}
|
|
.new-task:hover { border-color: var(--line-strong); background: var(--bg-hover); }
|
|
.new-task:active { transform: scale(.985); }
|
|
.new-task .plus { color: var(--accent); font-size: 16px; line-height: 1; }
|
|
|
|
.side-sec {
|
|
display: flex; align-items: center; gap: 6px; padding: 0 8px 6px;
|
|
color: var(--fg-faint); font-size: 11px; font-weight: 600;
|
|
letter-spacing: .7px; text-transform: uppercase;
|
|
}
|
|
.sessions { flex: 1 1 auto; overflow-y: auto; min-height: 40px; scrollbar-gutter: stable; }
|
|
.sess-item {
|
|
display: flex; align-items: baseline; gap: 8px; width: 100%;
|
|
padding: 7px 9px; border-radius: 9px; text-align: left;
|
|
color: var(--text-secondary); font-size: 13.5px;
|
|
animation: fade-in var(--t) var(--ease) both;
|
|
transition: background var(--t-fast), color var(--t-fast);
|
|
}
|
|
.sess-item:hover { background: var(--hover); color: var(--text-primary); }
|
|
.sess-item.on { background: var(--sidebar-surface-tertiary); color: var(--text-primary); font-weight: 600; }
|
|
.sess-item.on::before {
|
|
content: ""; width: 5px; height: 5px; border-radius: 50%;
|
|
background: var(--accent); flex: 0 0 auto; align-self: center;
|
|
}
|
|
.sess-item .t { flex: 1 1 auto; min-width: 0; overflow: hidden; }
|
|
.sess-item .ts { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
/* a title that does not fit fades at the edge and scrolls itself on hover, the
|
|
* way the reference sidebar handles long names (its data-marquee-text pattern) */
|
|
.sess-item .t.mq { mask-image: linear-gradient(90deg, #000 calc(100% - 18px), transparent); }
|
|
.sess-item:hover .t.mq { mask-image: none; }
|
|
.sess-item:hover .t.mq .ts {
|
|
width: max-content; text-overflow: clip;
|
|
animation: marquee 2.6s var(--ease) 160ms infinite alternate;
|
|
}
|
|
@keyframes marquee { from { transform: none; } to { transform: translateX(calc(-1 * var(--mq, 0px))); } }
|
|
.sess-item .n { font-size: 11px; color: var(--text-quaternary); font-weight: 400; white-space: nowrap; }
|
|
.side-foot {
|
|
display: flex; align-items: center; gap: 6px; padding-top: 10px;
|
|
margin-top: 6px; border-top: 1px solid var(--line);
|
|
}
|
|
.who { display: flex; align-items: center; gap: 9px; min-width: 0; flex: 1 1 auto; }
|
|
.avatar {
|
|
width: 28px; height: 28px; border-radius: 50%; flex: 0 0 auto;
|
|
background: linear-gradient(135deg, var(--violet), var(--accent));
|
|
color: #fff; font-weight: 800; font-size: 13px;
|
|
display: flex; align-items: center; justify-content: center;
|
|
}
|
|
.who-text { min-width: 0; display: flex; flex-direction: column; line-height: 1.3; }
|
|
.who-text b { font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.who-text i { font-size: 11px; color: var(--fg-faint); font-style: normal; }
|
|
|
|
/* --- top bar -------------------------------------------------------------- */
|
|
#main { display: flex; flex-direction: column; min-width: 0; position: relative; }
|
|
#topbar { display: flex; align-items: center; gap: 4px; padding: 9px 12px; border-bottom: 1px solid var(--line); }
|
|
.seg {
|
|
display: flex; background: var(--bg-soft); border: 1px solid var(--line);
|
|
border-radius: 99px; padding: 2px; position: relative;
|
|
}
|
|
.seg button {
|
|
height: 25px; padding: 0 12px; white-space: nowrap; border-radius: 99px; color: var(--fg-dim); font-size: 12.5px;
|
|
transition: color var(--t-fast), background var(--t);
|
|
}
|
|
.seg button.on { background: var(--bg-lift); color: var(--fg); font-weight: 600; }
|
|
.only-narrow { display: none; }
|
|
|
|
#scroll {
|
|
flex: 1 1 auto; overflow-y: auto; padding: 22px 0 10px;
|
|
scroll-behavior: smooth; scrollbar-gutter: stable;
|
|
}
|
|
#log { max-width: calc(var(--content) + 40px); margin: 0 auto; padding: 0 20px; }
|
|
#log:empty { display: none; }
|
|
|
|
/* --- empty state ---------------------------------------------------------- */
|
|
/* the first screen is one line: no logo, no suggestion wall. It goes away the
|
|
* moment the first message lands (see showEmpty). */
|
|
#empty { margin: 22vh auto 0; padding: 0 20px; text-align: center; }
|
|
#empty.gone { display: none; }
|
|
#empty .ready {
|
|
margin: 0; color: var(--text-tertiary); font-size: 15px; letter-spacing: .3px;
|
|
animation: fade-in 320ms var(--ease) both;
|
|
}
|
|
|
|
/* --- transcript ----------------------------------------------------------- */
|
|
/* one left edge for everything (answer, process block, notes), the same edge
|
|
* as the composer; prompts hang on the right edge with their images above */
|
|
.msg { display: flex; flex-direction: column; align-items: stretch; padding: 14px 0 0; animation: fade-up var(--t) var(--ease) both; }
|
|
.msg .body { min-width: 0; max-width: 100%; }
|
|
.msg.user { align-items: flex-end; padding-top: 24px; }
|
|
#log > .msg.user:first-child { padding-top: 6px; }
|
|
.msg.user .body {
|
|
background: var(--bubble-user); border-radius: 24px;
|
|
padding: 11px 18px; max-width: min(76%, 560px); white-space: pre-wrap; word-break: break-word;
|
|
}
|
|
.msg.error .body { color: var(--danger); white-space: pre-wrap; }
|
|
.msg.error .body::before {
|
|
content: "!"; display: inline-flex; align-items: center; justify-content: center;
|
|
width: 18px; height: 18px; margin-right: 8px; border-radius: 50%; vertical-align: 1px;
|
|
background: color-mix(in srgb, var(--danger) 18%, transparent); font-size: 12px; font-weight: 800;
|
|
}
|
|
.body > :first-child, .live-html > :first-child { margin-top: 0; }
|
|
.body > :last-child, .live-html > :last-child { margin-bottom: 0; }
|
|
.body h1, .body h2, .body h3, .body h4 { line-height: 1.35; margin: 1.1em 0 .5em; }
|
|
.body h1 { font-size: 1.45em; } .body h2 { font-size: 1.25em; } .body h3 { font-size: 1.1em; }
|
|
.body p, .body ul, .body ol { margin: .55em 0; }
|
|
.body ul, .body ol { padding-left: 1.4em; }
|
|
.body li { margin: .22em 0; }
|
|
.body a { color: var(--link); }
|
|
.body code {
|
|
font-family: var(--mono); font-size: .88em; background: var(--bg-code);
|
|
border: 1px solid var(--line); border-radius: 6px; padding: .1em .35em;
|
|
}
|
|
.body pre {
|
|
background: var(--bg-code); border: 1px solid var(--line);
|
|
border-radius: 12px; padding: 12px 14px; overflow-x: auto; margin: .75em 0;
|
|
}
|
|
.body pre code { background: none; border: 0; padding: 0; font-size: 13px; }
|
|
.body blockquote { margin: .75em 0; padding: .1em 0 .1em 12px; border-left: 3px solid var(--line-strong); color: var(--fg-dim); }
|
|
.body table { border-collapse: collapse; margin: .75em 0; font-size: 13.5px; display: block; overflow-x: auto; }
|
|
.body th, .body td { border: 1px solid var(--line); padding: 5px 9px; text-align: left; }
|
|
.body th { background: var(--bg-soft); }
|
|
.body img { max-width: 100%; border-radius: 10px; }
|
|
.body hr { border: 0; border-top: 1px solid var(--line); margin: 1.2em 0; }
|
|
/* a caret while tokens are still arriving */
|
|
.body.live > .live-html > :last-child::after {
|
|
content: ""; display: inline-block; width: 7px; height: 14px;
|
|
margin-left: 3px; vertical-align: -2px; border-radius: 2px;
|
|
background: var(--accent); animation: blink 1.1s steps(2, start) infinite;
|
|
}
|
|
|
|
/* a prompt's images: above the bubble and outside it, square tiles when there
|
|
* are several, the picture's own shape when there is one */
|
|
.attach-strip { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 12px; margin: 0 0 10px; max-width: 100%; }
|
|
.attach-strip .thumb {
|
|
display: block; width: 152px; height: 152px; padding: 0; overflow: hidden; cursor: zoom-in;
|
|
border-radius: 20px; border: 1px solid var(--line); background: var(--bg-soft);
|
|
animation: rise var(--t) var(--ease) both;
|
|
transition: border-color var(--t-fast), transform 90ms var(--ease);
|
|
}
|
|
.attach-strip .thumb:hover { border-color: var(--line-strong); }
|
|
.attach-strip .thumb:active { transform: scale(.985); }
|
|
.attach-strip .thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
|
|
.attach-strip.one .thumb { width: auto; height: auto; }
|
|
.attach-strip.one .thumb img {
|
|
width: auto; height: auto; min-width: 72px; min-height: 72px;
|
|
max-width: min(260px, 70vw); max-height: 260px; object-fit: contain;
|
|
}
|
|
|
|
.turn-meta { display: flex; align-items: center; gap: 10px; padding: 8px 0 2px; }
|
|
.turn-meta details > summary { cursor: pointer; list-style: none; color: var(--fg-faint); font-size: 12px; transition: color var(--t-fast); }
|
|
.turn-meta details > summary::-webkit-details-marker { display: none; }
|
|
.turn-meta details > summary:hover { color: var(--fg-dim); }
|
|
/* the actions take a row only under messages that have text to act on */
|
|
.msg-actions { display: flex; gap: 2px; padding-top: 4px; margin-left: -7px; opacity: 0; transition: opacity var(--t) var(--ease); }
|
|
.msg.user .msg-actions { margin: 0 -7px 0 0; }
|
|
.msg:hover .msg-actions, .msg-actions:focus-within { opacity: 1; }
|
|
.act {
|
|
width: 30px; height: 28px; border-radius: 8px; color: var(--fg-faint);
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
transition: background var(--t-fast), color var(--t-fast), transform 90ms var(--ease);
|
|
}
|
|
.act svg.i { width: 16px; height: 16px; }
|
|
.act:hover { background: var(--bg-hover); color: var(--fg); }
|
|
.act:active { transform: scale(.94); }
|
|
|
|
/* --- process block: a run of thinking and tool calls, folded to one line --- */
|
|
.proc { margin: 10px 0 0; }
|
|
.proc-sum {
|
|
display: inline-flex; align-items: center; gap: 7px; max-width: 100%; height: 28px;
|
|
margin-left: -7px; padding: 0 10px 0 6px; border-radius: 8px;
|
|
cursor: pointer; list-style: none; color: var(--fg-faint); font-size: 13px; user-select: none;
|
|
transition: background var(--t-fast), color var(--t-fast);
|
|
}
|
|
.proc-sum::-webkit-details-marker { display: none; }
|
|
.proc-sum:hover { background: var(--bg-hover); color: var(--fg-dim); }
|
|
.proc-chev { width: 14px; height: 14px; transform: rotate(-90deg); transition: transform var(--t) var(--ease); }
|
|
.proc[open] > .proc-sum .proc-chev { transform: none; }
|
|
.proc-lbl { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.proc-meta { flex: 0 0 auto; color: var(--fg-quat); font-size: 12px; white-space: nowrap; }
|
|
.proc-meta:empty { display: none; }
|
|
/* the running block's label shimmers instead of spinning */
|
|
.proc.run .proc-lbl {
|
|
background: linear-gradient(90deg, var(--fg-faint) 0%, var(--fg) 45%, var(--fg-faint) 90%);
|
|
background-size: 220% 100%; -webkit-background-clip: text; background-clip: text;
|
|
color: transparent; animation: shimmer 1.8s linear infinite;
|
|
}
|
|
|
|
/* the timeline: one hairline, one dot per entry */
|
|
.tl { position: relative; margin: 2px 0 0; padding: 2px 0 2px 20px; animation: fade-in var(--t) var(--ease) both; }
|
|
.tl::before {
|
|
content: ""; position: absolute; left: 4px; top: 14px; bottom: 14px; width: 1px;
|
|
background: var(--line);
|
|
}
|
|
.tl-item { position: relative; animation: fade-up var(--t) var(--ease) both; }
|
|
.tl-item > summary {
|
|
display: flex; align-items: center; gap: 8px; min-height: 28px; padding: 2px 0;
|
|
cursor: pointer; list-style: none; font-size: 13px; color: var(--fg-dim);
|
|
transition: color var(--t-fast);
|
|
}
|
|
.tl-item > summary::-webkit-details-marker { display: none; }
|
|
.tl-item > summary:hover { color: var(--fg); }
|
|
.tl-dot {
|
|
position: absolute; left: -20px; top: 9px; width: 9px; height: 9px; border-radius: 50%;
|
|
background: var(--bg); border: 1.5px solid var(--line-strong);
|
|
}
|
|
.tl-item.think .tl-dot { border-color: color-mix(in srgb, var(--violet) 75%, transparent); }
|
|
.tl-name { flex: 0 0 auto; font-size: 12.5px; color: var(--fg-dim); }
|
|
.tl-prev {
|
|
flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
color: var(--fg-faint); font-size: 12.5px;
|
|
}
|
|
.tl-item.think[open] .tl-prev { visibility: hidden; }
|
|
.think-text {
|
|
color: var(--fg-dim); font-size: 13px; line-height: 1.65; white-space: pre-wrap; word-break: break-word;
|
|
padding: 2px 0 8px; animation: fade-in var(--t) var(--ease) both;
|
|
}
|
|
|
|
/* tool calls: one line each, open for arguments and output */
|
|
.step-line .name { flex: 0 0 auto; font-family: var(--mono); font-size: 12.5px; color: var(--fg); }
|
|
.step-line .args { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--mono); font-size: 12px; color: var(--fg-faint); }
|
|
.step-line .phase { flex: 0 0 auto; font-size: 11.5px; color: var(--fg-faint); white-space: nowrap; }
|
|
.step-line.run .phase { color: var(--warn); }
|
|
.step-line.run .tl-dot { border-color: var(--warn); background: color-mix(in srgb, var(--warn) 30%, var(--bg)); animation: pulse 1.1s var(--ease) infinite; }
|
|
.step-line.done .tl-dot { border-color: var(--accent-line); background: var(--accent-weak); }
|
|
.step-line.bad .tl-dot { border-color: var(--danger); background: color-mix(in srgb, var(--danger) 20%, var(--bg)); }
|
|
.step-line.bad .phase, .step-line.bad .name { color: var(--danger); }
|
|
/* a sub-agent's latest steps, next to its task */
|
|
.step-line .step-detail {
|
|
flex: 0 1 40%; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
font-family: var(--mono); font-size: 11.5px; color: var(--fg-faint);
|
|
}
|
|
.step-line.done .step-detail { display: none; }
|
|
/* "[cst] plan mode is now ON" and other engine notes in the history */
|
|
.note-line {
|
|
padding: 8px 0 2px; font-size: 12px; color: var(--fg-faint);
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
}
|
|
.note-line::before { content: "· "; }
|
|
.step-body { padding: 0 0 6px; animation: fade-in var(--t) var(--ease) both; }
|
|
.step-out, .step-args-full {
|
|
font-family: var(--mono); font-size: 12px; background: var(--bg-code);
|
|
border: 1px solid var(--line); border-radius: 10px; padding: 9px 11px;
|
|
margin: 4px 0 0; max-height: 300px; overflow: auto; white-space: pre-wrap; word-break: break-word;
|
|
}
|
|
|
|
#to-bottom {
|
|
position: absolute; right: 26px; bottom: 172px; z-index: 5;
|
|
width: 38px; height: 38px; display: flex; align-items: center; justify-content: center;
|
|
background: var(--bg-lift); border: 1px solid var(--line-strong); color: var(--fg-dim);
|
|
box-shadow: var(--shadow-sm); font-size: 16px;
|
|
animation: fade-in var(--t) var(--ease) both;
|
|
transition: color var(--t-fast), transform 90ms var(--ease), background var(--t-fast);
|
|
}
|
|
#to-bottom:hover { color: var(--fg); background: var(--bg-hover); }
|
|
#to-bottom:active { transform: scale(.94); }
|
|
|
|
/* --- composer ------------------------------------------------------------- */
|
|
#composer { padding: 8px 20px 12px; }
|
|
#composer > * { max-width: var(--content); margin: 0 auto; }
|
|
.pending { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 6px 0 10px; }
|
|
.pending .chip { background: var(--bg-soft); border-color: var(--line); }
|
|
/* images waiting for the next prompt, the way they will look once sent */
|
|
.pend-thumb { position: relative; width: 56px; height: 56px; flex: 0 0 auto; animation: rise var(--t) var(--ease) both; }
|
|
.pend-thumb img {
|
|
display: block; width: 100%; height: 100%; object-fit: cover; cursor: zoom-in;
|
|
border-radius: 12px; border: 1px solid var(--line);
|
|
}
|
|
.pend-x {
|
|
position: absolute; top: -7px; right: -7px; width: 20px; height: 20px; border-radius: 50%;
|
|
display: flex; align-items: center; justify-content: center;
|
|
background: var(--main-surface-tertiary); border: 1px solid var(--line-strong); color: var(--fg-dim);
|
|
opacity: 0; transition: opacity var(--t-fast), color var(--t-fast);
|
|
}
|
|
.pend-x svg.i { width: 12px; height: 12px; stroke-width: 2.2; }
|
|
.pend-thumb:hover .pend-x, .pend-x:focus-visible { opacity: 1; }
|
|
.pend-x:hover { color: var(--fg); }
|
|
.edit-bar {
|
|
display: flex; align-items: center; gap: 8px; padding: 6px 10px; margin-bottom: 8px;
|
|
border-radius: 10px; border: 1px solid var(--line); background: var(--bg-soft);
|
|
color: var(--fg-dim); font-size: 12.5px;
|
|
}
|
|
.edit-bar[hidden] { display: none; }
|
|
.msg.user .msg-actions { justify-content: flex-end; padding-left: 0; }
|
|
.sess-search {
|
|
width: calc(100% - 8px); margin: 0 4px 8px; height: 30px; padding: 0 10px;
|
|
border-radius: 9px; border: 1px solid var(--line); background: var(--bg-soft);
|
|
color: var(--fg); font-size: 13px;
|
|
}
|
|
.sess-item { cursor: pointer; }
|
|
#modal-box .sess-list { max-height: min(56vh, 520px); overflow-y: auto; margin: 4px 0 10px; }
|
|
#modal-box .sess button { flex: 0 0 auto; }
|
|
.sess-item .more {
|
|
flex: 0 0 auto; align-self: center; width: 22px; height: 22px; border-radius: 6px;
|
|
display: grid; place-items: center; color: var(--fg-faint); opacity: 0;
|
|
transition: opacity var(--t-fast), background var(--t-fast);
|
|
}
|
|
.sess-item:hover .more, .sess-item .more:focus-visible { opacity: 1; }
|
|
.sess-item .more:hover { background: var(--bg-hover); color: var(--fg); }
|
|
.sess-item .more .i { width: 16px; height: 16px; }
|
|
#modal-box .sess button.danger { color: var(--danger, #e5484d); }
|
|
button.fstat { width: 100%; text-align: left; border-radius: 7px; transition: background var(--t-fast); }
|
|
button.fstat:hover { background: var(--bg-hover); }
|
|
.danger-text { color: var(--danger); }
|
|
#modal-box.wide { width: min(980px, 100%); }
|
|
#modal-box h4.sub { margin: 16px 0 6px; font-size: 13px; color: var(--fg-dim); font-weight: 650; }
|
|
#modal-box .field select, #modal-box .field input[type=number] {
|
|
flex: 1 1 auto; min-width: 150px; background: var(--bg-lift); color: var(--fg);
|
|
border: 1px solid var(--line); border-radius: 10px; padding: 7px 10px; outline: none;
|
|
}
|
|
#modal-box .field > span { width: 84px; }
|
|
#modal-box .checks { display: flex; flex-wrap: wrap; gap: 14px; }
|
|
#modal-box .check { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer; }
|
|
#modal-box .tool-list { max-height: 34vh; overflow-y: auto; border: 1px solid var(--line); border-radius: 10px; padding: 4px; }
|
|
#modal-box .tool-row {
|
|
display: flex; align-items: center; gap: 8px; padding: 5px 6px; border-radius: 7px;
|
|
font-size: 12.5px; cursor: pointer;
|
|
}
|
|
#modal-box .tool-row:hover { background: var(--bg-hover); }
|
|
#modal-box .tool-row.dim code { opacity: .55; }
|
|
#modal-box .tool-row code { font-family: var(--mono); font-size: 12px; flex: 0 0 auto; }
|
|
#modal-box .tool-row .perm { flex: 0 0 auto; color: var(--fg-faint); font-size: 11px; border: 1px solid var(--line); border-radius: 6px; padding: 0 5px; }
|
|
#modal-box .tool-row .desc { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg-dim); }
|
|
#modal-box .diff-files { display: flex; flex-direction: column; gap: 1px; max-height: 24vh; overflow-y: auto; margin-bottom: 10px; }
|
|
#modal-box .diff-file {
|
|
display: flex; gap: 10px; align-items: center; text-align: left; padding: 5px 8px;
|
|
border-radius: 7px; font-size: 12.5px;
|
|
}
|
|
#modal-box .diff-file:hover { background: var(--bg-hover); }
|
|
#modal-box .diff-file.on { background: var(--accent-weak); }
|
|
#modal-box .diff-file .st { flex: 0 0 52px; color: var(--fg-faint); font-size: 11.5px; }
|
|
#modal-box .diff-file .p { font-family: var(--mono); overflow-wrap: anywhere; }
|
|
pre.diff {
|
|
margin: 0; padding: 10px 0; max-height: 52vh; overflow: auto; border-radius: 10px;
|
|
background: var(--bg-soft); border: 1px solid var(--line);
|
|
font-family: var(--mono); font-size: 12px; line-height: 1.5;
|
|
}
|
|
pre.diff span { display: block; padding: 0 12px; white-space: pre; min-height: 1.5em; }
|
|
pre.diff .add { color: var(--text-success); background: color-mix(in srgb, var(--text-success) 10%, transparent); }
|
|
pre.diff .del { color: var(--text-error); background: color-mix(in srgb, var(--text-error) 10%, transparent); }
|
|
pre.diff .hunk { color: var(--accent); }
|
|
pre.diff .h { color: var(--fg-faint); font-weight: 600; }
|
|
|
|
.box {
|
|
border: 1px solid var(--border-medium); border-radius: var(--radius-lg);
|
|
background: var(--composer-surface-primary); padding: 11px 13px 9px;
|
|
transition: border-color var(--t), box-shadow var(--t), background var(--t);
|
|
}
|
|
.box:hover { border-color: var(--border-heavy); }
|
|
.box:focus-within {
|
|
border-color: var(--accent-line);
|
|
box-shadow: 0 0 0 3px var(--accent-weak);
|
|
}
|
|
.box textarea {
|
|
width: 100%; border: 0; background: none; resize: none; outline: none;
|
|
max-height: 240px; min-height: 26px; padding: 2px 2px 8px;
|
|
caret-color: var(--accent);
|
|
}
|
|
.box textarea::placeholder { color: var(--fg-faint); }
|
|
.box-row { display: flex; align-items: center; gap: 6px; }
|
|
.att { border: 1px solid var(--line); font-size: 17px; line-height: 1; }
|
|
.cost { color: var(--fg-faint); font-size: 12px; padding: 0 4px; white-space: nowrap; }
|
|
.cost:hover { color: var(--fg-dim); }
|
|
.send {
|
|
width: 36px; height: 36px; flex: 0 0 auto; font-size: 17px; font-weight: 800;
|
|
background: var(--accent); color: var(--accent-fg);
|
|
transition: filter var(--t-fast), transform 90ms var(--ease), opacity var(--t-fast);
|
|
}
|
|
.send:hover { filter: brightness(1.08); }
|
|
.send:active { transform: scale(.94); }
|
|
.send:disabled { opacity: .38; }
|
|
.icon.stop { border: 1px solid var(--line); font-size: 12px; }
|
|
.hint-line { display: flex; align-items: center; gap: 10px; padding: 7px 6px 0; font-size: 12px; color: var(--fg-faint); }
|
|
|
|
/* permission gate: inline, the turn really is waiting on it */
|
|
.gate {
|
|
border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
|
|
border-radius: var(--radius); padding: 11px 13px; margin-bottom: 10px;
|
|
background: color-mix(in srgb, var(--warn) 7%, var(--bg-soft));
|
|
animation: rise var(--t) var(--ease) both;
|
|
}
|
|
.gate-head { display: flex; align-items: center; gap: 8px; font-weight: 650; font-size: 14px; }
|
|
.gate-timer { color: var(--warn); font-size: 12.5px; font-variant-numeric: tabular-nums; }
|
|
.gate pre {
|
|
margin: 8px 0 0; background: var(--bg-code); border: 1px solid var(--line);
|
|
border-radius: 10px; padding: 9px 11px; max-height: 180px; overflow: auto;
|
|
font-family: var(--mono); font-size: 12.5px; white-space: pre-wrap; word-break: break-word;
|
|
}
|
|
.gate-keys { padding: 8px 0 2px; color: var(--fg-dim); font-size: 12.5px; }
|
|
.gate-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
|
|
.gate-row button {
|
|
height: 34px; padding: 0 14px; border-radius: 10px; font-weight: 600;
|
|
border: 1px solid var(--line-strong); background: var(--bg-lift);
|
|
transition: filter var(--t-fast), transform 90ms var(--ease), background var(--t-fast);
|
|
}
|
|
.gate-row button.ok { background: var(--accent); color: var(--accent-fg); border-color: transparent; }
|
|
.gate-row button.danger { color: var(--danger); }
|
|
.gate-row button:hover { filter: brightness(1.12); }
|
|
.gate-row button:active { transform: scale(.97); }
|
|
|
|
/* --- popovers: anchored, animated, and the only place settings live ------- */
|
|
.pop {
|
|
position: fixed; z-index: 45; min-width: 236px; max-width: 320px;
|
|
background: var(--main-surface-tertiary); border: 1px solid var(--border-medium);
|
|
border-radius: 14px; padding: 6px; box-shadow: var(--shadow);
|
|
animation: pop-in 160ms var(--ease) both;
|
|
}
|
|
.pop-item {
|
|
display: flex; align-items: flex-start; gap: 10px; width: 100%;
|
|
padding: 9px 10px; border-radius: 10px; text-align: left;
|
|
transition: background var(--t-fast);
|
|
}
|
|
.pop-item:hover { background: var(--bg-hover); }
|
|
.pop-item .pi { width: 18px; flex: 0 0 auto; text-align: center; color: var(--fg-dim); font-size: 14px; line-height: 1.4; }
|
|
/* title over description: two lines, never one run-on line */
|
|
.pop-item .pm { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; gap: 2px; }
|
|
.pop-item .pt { font-size: 13.5px; font-weight: 600; line-height: 1.35; }
|
|
.pop-item .pd { font-size: 11.5px; color: var(--fg-faint); line-height: 1.4; }
|
|
.pop-item .pk { flex: 0 0 auto; color: var(--accent); font-size: 13px; }
|
|
.pop-item.on { background: var(--accent-weak); }
|
|
.pop-item.on .pi, .pop-item.on .pt { color: var(--accent); }
|
|
.pop-item.danger .pi, .pop-item.danger .pt { color: var(--danger); }
|
|
.pop-sep { height: 1px; background: var(--line); margin: 5px 4px; }
|
|
.pop-title { padding: 8px 10px 4px; color: var(--fg-faint); font-size: 11.5px; font-weight: 600; letter-spacing: .4px; }
|
|
.pop-input { display: flex; gap: 6px; padding: 4px 6px 6px; }
|
|
.pop-input input {
|
|
flex: 1 1 auto; min-width: 0; background: var(--bg-soft); border: 1px solid var(--line);
|
|
border-radius: 9px; padding: 7px 9px; outline: none; font-size: 13px;
|
|
caret-color: var(--accent);
|
|
transition: border-color var(--t-fast);
|
|
}
|
|
.pop-input input:focus { border-color: var(--accent-line); }
|
|
.pop-input button {
|
|
height: 32px; padding: 0 12px; border-radius: 9px; font-weight: 600; font-size: 13px;
|
|
background: var(--accent); color: var(--accent-fg);
|
|
transition: filter var(--t-fast), transform 90ms var(--ease);
|
|
}
|
|
.pop-input button:active { transform: scale(.96); }
|
|
.kv { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 5px 10px; font-size: 13px; }
|
|
.kv span { color: var(--fg-dim); }
|
|
.kv b { font-variant-numeric: tabular-nums; font-weight: 600; min-width: 0; overflow-wrap: anywhere; text-align: right; }
|
|
.pop { max-height: calc(100vh - 16px); overflow-y: auto; }
|
|
.pop:has(.pop-list) { min-width: min(360px, 94vw); max-width: min(440px, 94vw); }
|
|
.pop-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
.pop-list { max-height: min(46vh, 420px); overflow-y: auto; }
|
|
.pop-list .pop-item .pt { overflow-wrap: anywhere; font-family: var(--mono); font-size: 12.5px; }
|
|
.pop-empty { padding: 10px; color: var(--fg-faint); font-size: 12.5px; }
|
|
.pop-note { padding: 2px 10px 6px; color: var(--fg-faint); font-size: 11.5px; line-height: 1.45; }
|
|
.pop-note:empty { display: none; }
|
|
.pop-note.bad { color: var(--danger); }
|
|
.pop-note.warn { color: var(--warn); }
|
|
.pop-item.dim { opacity: .55; }
|
|
button.link { color: var(--link); padding: 0 4px; font-size: inherit; text-decoration: underline; }
|
|
.ok-text { color: var(--text-success); }
|
|
.warn-text { color: var(--warn); }
|
|
|
|
/* providers and the key dialog */
|
|
#modal-box .prov {
|
|
display: flex; align-items: center; gap: 10px; padding: 9px 8px;
|
|
border-bottom: 1px solid var(--line); border-radius: 8px;
|
|
}
|
|
#modal-box .prov.on { background: var(--accent-weak); }
|
|
#modal-box .prov .pm { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
|
|
#modal-box .prov .pm span { overflow-wrap: anywhere; }
|
|
#modal-box .prov-acts button {
|
|
height: 30px; padding: 0 12px; border-radius: 9px; font-weight: 600; font-size: 13px;
|
|
border: 1px solid var(--line-strong); background: var(--bg-lift); white-space: nowrap;
|
|
}
|
|
#modal-box .prov-acts button.ok { background: var(--accent); color: var(--accent-fg); border-color: transparent; }
|
|
#modal-box .key-input {
|
|
width: 100%; margin-top: 12px; background: var(--bg-lift); border: 1px solid var(--line);
|
|
border-radius: 10px; padding: 9px 11px; outline: none; font-family: var(--mono);
|
|
}
|
|
#modal-box .key-input:focus { border-color: var(--accent-line); }
|
|
#modal-box .key-err { min-height: 18px; margin-top: 6px; color: var(--danger); font-size: 12.5px; }
|
|
|
|
/* one line of feedback for anything that failed or needs a look */
|
|
.toast {
|
|
position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 60;
|
|
max-width: min(560px, 92vw); padding: 10px 14px; border-radius: 12px;
|
|
background: var(--main-surface-tertiary); border: 1px solid var(--border-medium);
|
|
box-shadow: var(--shadow); font-size: 13px; line-height: 1.45; overflow-wrap: anywhere;
|
|
animation: fade-up 160ms var(--ease) both;
|
|
}
|
|
.toast.err { border-color: color-mix(in srgb, var(--danger) 55%, transparent); color: var(--danger); }
|
|
.toast.warn { border-color: color-mix(in srgb, var(--warn) 55%, transparent); color: var(--warn); }
|
|
.toast.ok { border-color: var(--accent-line); color: var(--accent); }
|
|
.toast[hidden] { display: none; }
|
|
|
|
/* --- right panel ---------------------------------------------------------- */
|
|
/* the right panel mirrors the rail: fixed-width contents, clipped by the track,
|
|
* so folding it in and out is one eased movement on each side */
|
|
#panel { background: var(--main-surface-secondary); border-left: 1px solid var(--border-light); min-width: 0; overflow: hidden; }
|
|
.panel-inner {
|
|
width: var(--panel); height: 100%; overflow-y: auto; padding: 12px;
|
|
transition: transform 300ms var(--ease-pop), opacity 200ms var(--ease);
|
|
}
|
|
body.no-panel .panel-inner { transform: translateX(18px); opacity: 0; }
|
|
body.no-panel #panel { pointer-events: none; }
|
|
.panel-head {
|
|
display: flex; align-items: center; gap: 6px; padding: 2px 4px 10px;
|
|
color: var(--fg-faint); font-size: 11px; font-weight: 600;
|
|
letter-spacing: .7px; text-transform: uppercase;
|
|
}
|
|
.card { border-top: 1px solid var(--line); padding: 12px 2px; }
|
|
.card:first-of-type { border-top: 0; }
|
|
.card h4 { margin: 0 0 8px; font-size: 12.5px; font-weight: 650; display: flex; align-items: center; gap: 6px; }
|
|
.card .kv { padding: 3px 0; }
|
|
.todo-list { margin: 0; padding: 0; list-style: none; font-size: 13.5px; }
|
|
.todo-list li { display: flex; gap: 8px; padding: 3px 0; animation: fade-in var(--t) var(--ease) both; transition: color var(--t-fast); }
|
|
.todo-list .boxmark { color: var(--fg-faint); }
|
|
.todo-list li.done { color: var(--fg-faint); text-decoration: line-through; }
|
|
.todo-list li.doing { color: var(--fg); font-weight: 600; }
|
|
/* --- modal sheet (session list) ------------------------------------------- */
|
|
#modal {
|
|
position: fixed; inset: 0; background: rgba(0, 0, 0, .5); z-index: 40;
|
|
display: flex; align-items: center; justify-content: center; padding: 16px;
|
|
animation: fade-in var(--t) var(--ease) both;
|
|
}
|
|
#modal-box {
|
|
width: min(560px, 100%); max-height: 82vh; overflow-y: auto;
|
|
background: var(--main-surface-tertiary); border: 1px solid var(--border-medium);
|
|
border-radius: 18px; padding: 16px 18px; box-shadow: var(--shadow);
|
|
animation: pop-in 180ms var(--ease) both;
|
|
}
|
|
#modal-box h3 { margin: 0 0 12px; font-size: 17px; }
|
|
#modal-box .field { display: flex; align-items: center; gap: 8px; margin: 9px 0; flex-wrap: wrap; }
|
|
#modal-box .field > span { width: 70px; color: var(--fg-dim); font-size: 13px; }
|
|
#modal-box .field input {
|
|
flex: 1 1 auto; min-width: 150px; background: var(--bg-lift);
|
|
border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; outline: none;
|
|
}
|
|
#modal-box .buttons { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 12px; }
|
|
#modal-box .buttons button {
|
|
height: 34px; padding: 0 14px; border-radius: 10px; font-weight: 600;
|
|
border: 1px solid var(--line-strong); background: var(--bg-lift);
|
|
transition: filter var(--t-fast), transform 90ms var(--ease);
|
|
}
|
|
#modal-box .buttons button:active { transform: scale(.97); }
|
|
#modal-box .buttons button.ok { background: var(--accent); color: var(--accent-fg); border-color: transparent; }
|
|
#modal-box .buttons button.danger { color: var(--danger); }
|
|
#modal-box .sess {
|
|
display: flex; align-items: center; gap: 8px; padding: 8px 6px;
|
|
border-bottom: 1px solid var(--line); border-radius: 8px;
|
|
transition: background var(--t-fast);
|
|
}
|
|
#modal-box .sess:hover { background: var(--bg-hover); }
|
|
#modal-box .sess .id { font-family: var(--mono); font-size: 11.5px; color: var(--fg-faint); }
|
|
#modal-box .sess .t { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13.5px; }
|
|
|
|
/* --- commands: the list over the composer, the palette, the help sheet ---- */
|
|
#composer { position: relative; }
|
|
.slash {
|
|
position: absolute; left: 20px; right: 20px; bottom: calc(100% - 6px); z-index: 20;
|
|
max-height: min(46vh, 360px); overflow-y: auto; padding: 5px;
|
|
background: var(--main-surface-tertiary); border: 1px solid var(--border-medium);
|
|
border-radius: 14px; box-shadow: var(--shadow); animation: pop-in 140ms var(--ease) both;
|
|
}
|
|
.slash[hidden] { display: none; }
|
|
.slash-item, .palette-item {
|
|
display: flex; align-items: baseline; gap: 10px; width: 100%; padding: 7px 10px;
|
|
border-radius: 9px; text-align: left; font-size: 13px;
|
|
}
|
|
.slash-item.on, .palette-item.on { background: var(--accent-weak); }
|
|
.slash-item:hover, .palette-item:hover { background: var(--bg-hover); }
|
|
.slash-item code, .palette-item code { font-family: var(--mono); font-size: 12.5px; color: var(--fg); flex: 0 0 auto; }
|
|
.slash-item.on code, .palette-item.on code { color: var(--accent); }
|
|
.slash-item .hint { font-family: var(--mono); font-size: 11.5px; color: var(--fg-faint); flex: 0 0 auto; }
|
|
.slash-item .desc, .palette-item .desc {
|
|
flex: 1 1 auto; min-width: 0; color: var(--fg-dim); font-size: 12.5px;
|
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
}
|
|
#modal-box .palette-list { max-height: min(52vh, 460px); overflow-y: auto; margin-top: 8px; }
|
|
kbd {
|
|
font-family: var(--mono); font-size: 11px; color: var(--fg-dim); white-space: nowrap;
|
|
border: 1px solid var(--line-strong); border-bottom-width: 2px; border-radius: 6px; padding: 1px 6px;
|
|
background: var(--bg-soft);
|
|
}
|
|
.palette-item kbd { flex: 0 0 auto; }
|
|
#modal-box .keys-grid {
|
|
display: grid; grid-template-columns: max-content 1fr; gap: 7px 14px; align-items: baseline;
|
|
font-size: 13px;
|
|
}
|
|
#modal-box .keys-grid kbd { justify-self: start; }
|
|
#modal-box .keys-grid.cmds code { font-family: var(--mono); font-size: 12.5px; }
|
|
#modal-box .keys-grid span { color: var(--fg-dim); }
|
|
#modal-box .ext-list { display: flex; flex-direction: column; gap: 2px; }
|
|
#modal-box .ext-row {
|
|
display: flex; align-items: center; gap: 10px; padding: 7px 8px; border-radius: 8px;
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
#modal-box .ext-row .pm { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
|
|
#modal-box .ext-row .pm > div:last-child:not(.ext-title) { overflow-wrap: anywhere; }
|
|
#modal-box .ext-title { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: 13.5px; }
|
|
#modal-box .ext-badge {
|
|
font-size: 11px; border: 1px solid var(--line-strong); border-radius: 6px; padding: 0 6px; color: var(--fg-dim);
|
|
}
|
|
#modal-box .ext-badge.ok { color: var(--accent); border-color: var(--accent-line); }
|
|
#modal-box .ext-badge.bad { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 55%, transparent); }
|
|
#modal-box .ext-row > button {
|
|
flex: 0 0 auto; height: 30px; padding: 0 12px; border-radius: 9px; font-weight: 600; font-size: 13px;
|
|
border: 1px solid var(--line-strong); background: var(--bg-lift); white-space: nowrap;
|
|
}
|
|
|
|
/* --- narrow screens: rail and panel become drawers ------------------------ */
|
|
#backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, .45); z-index: 30; display: none; animation: fade-in var(--t) var(--ease) both; }
|
|
body.drawer-open #backdrop { display: block; }
|
|
@media (max-width: 900px) {
|
|
#app { grid-template-columns: minmax(0, 1fr) !important; transition: none; }
|
|
#side, #panel {
|
|
position: fixed; top: 0; bottom: 0; width: min(310px, 86vw); z-index: 31;
|
|
display: block; transition: transform 260ms var(--ease-pop);
|
|
}
|
|
.side-inner { width: auto; transform: none !important; opacity: 1 !important; }
|
|
#side { overflow: visible; pointer-events: auto; }
|
|
#side { left: 0; transform: translateX(-102%); }
|
|
#panel { right: 0; transform: translateX(102%); }
|
|
body.side-open #side, body.panel-open #panel { transform: none; }
|
|
.only-narrow { display: inline-flex; }
|
|
#to-bottom { bottom: 150px; right: 16px; }
|
|
.msg.user .body { max-width: 88%; }
|
|
.attach-strip .thumb { width: 120px; height: 120px; }
|
|
#lightbox { padding: 56px 12px; }
|
|
}
|
|
@media (max-width: 560px) {
|
|
#chip-approval .lbl { display: none; }
|
|
.seg button { padding: 0 9px; }
|
|
}
|
|
@media (min-width: 901px) { #backdrop { display: none !important; } }
|
|
/* touch screens have no hover: the actions stay visible */
|
|
@media (hover: none) {
|
|
.msg-actions, .pend-x { opacity: 1; }
|
|
}
|
|
|
|
/* --- lightbox ------------------------------------------------------------- */
|
|
#lightbox {
|
|
position: fixed; inset: 0; z-index: 70; padding: 56px 72px;
|
|
display: flex; align-items: center; justify-content: center;
|
|
background: rgba(0, 0, 0, .84); animation: fade-in var(--t) var(--ease) both;
|
|
}
|
|
#lb-img {
|
|
max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 12px;
|
|
box-shadow: 0 20px 60px rgba(0, 0, 0, .5); animation: pop-in 180ms var(--ease) both;
|
|
}
|
|
.lb-btn {
|
|
position: absolute; width: 40px; height: 40px; border-radius: 50%;
|
|
display: flex; align-items: center; justify-content: center;
|
|
background: rgba(255, 255, 255, .1); color: #fff;
|
|
transition: background var(--t-fast), transform 90ms var(--ease);
|
|
}
|
|
.lb-btn:hover { background: rgba(255, 255, 255, .2); }
|
|
#lb-close { top: 14px; right: 14px; }
|
|
#lb-prev { left: 14px; top: calc(50% - 20px); }
|
|
#lb-next { right: 14px; top: calc(50% - 20px); }
|
|
#lb-count {
|
|
position: absolute; bottom: 18px; left: 50%; transform: translateX(-50%);
|
|
color: rgba(255, 255, 255, .75); font-size: 13px; font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
/* --- motion --------------------------------------------------------------- */
|
|
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
|
|
@keyframes fade-up { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
|
|
@keyframes rise { from { opacity: 0; transform: translateY(10px) scale(.99); } to { opacity: 1; transform: none; } }
|
|
@keyframes pop-in { from { opacity: 0; transform: translateY(-4px) scale(.97); } to { opacity: 1; transform: none; } }
|
|
@keyframes pulse { 0%, 100% { opacity: .3; transform: scale(.85); } 50% { opacity: 1; transform: scale(1); } }
|
|
@keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
|
|
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: -120% 0; } }
|
|
@media (prefers-reduced-motion: reduce) {
|
|
*, *::before, *::after { animation-duration: 1ms !important; transition-duration: 1ms !important; }
|
|
#scroll { scroll-behavior: auto; }
|
|
}
|