- Sidebar: New chat, search, Scheduled, Files, the chats of both kinds by day (Today, Earlier), Settings with the account at the foot; folds away (Ctrl+B), a drawer on a narrow window. - A new chat is the chat page empty: a greeting, Agent or Chat, and the composer. - The composer is a card: the text, then attach, the chips (folder and mode for an agent chat, model with its picture, effort as the model offers it, the team's size), and a round Send that Stop replaces while a reply is written. An open chat's chips change the chat. - Messages: the person's in a bubble on the right with attached pictures as thumbnails, a reply full width; thinking and tool calls as compact rows that unfold. - Activity: a chip above the composer for every open chat, the panel on the right as before. - The agent: a chip in the title bar opening its state and the one thing to do about it; "This computer is not linked yet" with Link this computer right above the composer of an agent chat, and "refused" only with the server's reason. - Files: a page with the two trees as tabs. Settings: grouped, the groups listed beside them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1504 lines
74 KiB
CSS
1504 lines
74 KiB
CSS
/* LLeMbas Desktop's page. Every colour, size, space and font is a token from tokens.css (the
|
||
server's, copied by scripts/fetch-tokens.sh and pinned); the few values of this page's own are
|
||
named in :root below, each derived from a token where one exists. Media queries cannot read a
|
||
custom property, so the two breakpoints are written out and named after the tokens they are:
|
||
48rem is --bp-narrow (the sidebar becomes a drawer), 64rem is --bp-wide (the panels go over the
|
||
chat instead of beside it).
|
||
|
||
The shape is the one people know from AI desktop apps: a slim sidebar (New chat, search, the
|
||
pages, the chats by day, Settings at the foot), and a chat page with the conversation in a
|
||
centred column and the composer under it, the chat's settings as chips in the composer.
|
||
Reading text is set in --font-body; the chrome's small print (chips, metadata, code) in the
|
||
brand's monospace.
|
||
|
||
Rows line up by construction: every row of controls sits on a grid with known tracks, a field
|
||
is always three parts (label, control, hint) on shared rows, and nothing is aligned by
|
||
`baseline` across text of unknown length. Spaces are the 4 px scale (--sp-*). */
|
||
|
||
* { box-sizing: border-box; }
|
||
|
||
:root {
|
||
/* The title bar's height: a fact of this page, not a token the server has. */
|
||
--titlebar-h: 36px;
|
||
/* The setup card's widest. */
|
||
--card-max: 40rem;
|
||
/* The sidebar's width, the server's. */
|
||
--side-w: var(--sidebar-width);
|
||
/* The softer corner of the composer and the message bubbles: twice the theme's largest. */
|
||
--radius-soft: calc(2 * var(--radius-xl));
|
||
/* The conversation's column and the composer under it: the server's thread width. */
|
||
--column: var(--thread-max-width);
|
||
/* A chip under the message box: a small control's height. */
|
||
--chip-h: var(--control-h-sm);
|
||
/* The round send and stop buttons. */
|
||
--round: var(--control-h);
|
||
/* A thumbnail of an attached picture. */
|
||
--thumb: calc(4 * var(--sp-12) / 3);
|
||
/* The activity panel's number columns: a token count or a share ("180k", "63.0%"), and an
|
||
elapsed time ("2h 03m"), in the panel's monospaced figures. */
|
||
--num-col: 4.5em;
|
||
--time-col: 5.5em;
|
||
}
|
||
|
||
html, body { margin: 0; height: 100%; overflow: hidden; }
|
||
|
||
body {
|
||
background: var(--bg);
|
||
color: var(--ink);
|
||
font: var(--text-base) / var(--leading-normal) var(--font-body);
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
[hidden] { display: none !important; }
|
||
|
||
.app { display: grid; grid-template-rows: var(--titlebar-h) minmax(0, 1fr); height: 100vh; }
|
||
|
||
h1, h2, h3, p { margin: 0; }
|
||
.muted { color: var(--ink-muted); font-size: var(--text-sm); }
|
||
.is-error { color: var(--warning); }
|
||
bdi { unicode-bidi: isolate; }
|
||
|
||
.icon { width: 16px; height: 16px; fill: currentColor; flex: none; }
|
||
|
||
/* --- Controls ------------------------------------------------------------------------------ */
|
||
|
||
.btn {
|
||
height: var(--control-h);
|
||
padding: 0 var(--sp-4);
|
||
display: inline-grid;
|
||
grid-auto-flow: column;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
justify-content: center;
|
||
font: 600 var(--text-sm) var(--font-body);
|
||
color: var(--ink);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-lg);
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
transition: background var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out);
|
||
}
|
||
.btn:hover { background: var(--surface-hover); border-color: var(--border-strong); }
|
||
.btn:disabled { opacity: var(--opacity-dim); cursor: default; }
|
||
.btn--primary { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }
|
||
.btn--primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
|
||
.btn--sm { height: var(--control-h-sm); padding: 0 var(--sp-3); font-size: var(--text-xs); }
|
||
.btn--ghost { background: transparent; border-color: transparent; color: var(--ink-muted); }
|
||
.btn--ghost:hover { color: var(--ink); background: var(--surface-hover); border-color: transparent; }
|
||
.btn--danger { color: var(--ink-inverse); background: var(--danger); border-color: var(--danger); }
|
||
.btn--danger:hover { background: var(--danger-hover); }
|
||
|
||
/* A square icon button: a header's tools, a pane's refresh, a panel's close. */
|
||
.tool, .pane__btn {
|
||
width: var(--control-h-sm);
|
||
height: var(--control-h-sm);
|
||
display: grid;
|
||
place-items: center;
|
||
padding: 0;
|
||
color: var(--ink-muted);
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: var(--radius-lg);
|
||
cursor: pointer;
|
||
}
|
||
.tool:hover, .pane__btn:hover { color: var(--ink); background: var(--surface-hover); }
|
||
.tool:disabled { opacity: var(--opacity-dim); cursor: default; }
|
||
|
||
input[type="text"], input[type="search"], input[type="number"], select, textarea {
|
||
min-width: 0;
|
||
font: var(--text-sm) var(--font-body);
|
||
color: var(--ink);
|
||
background: var(--bg);
|
||
border: var(--border-w) solid var(--border-strong);
|
||
border-radius: var(--radius-lg);
|
||
}
|
||
input[type="text"], input[type="search"], input[type="number"], select { height: var(--control-h); padding: 0 var(--control-px-sm); }
|
||
textarea { padding: var(--sp-2) var(--control-px-sm); resize: none; line-height: var(--leading-normal); }
|
||
:focus-visible { outline: var(--outline-w) solid var(--accent); outline-offset: var(--outline-offset); }
|
||
|
||
label, .label { font: var(--text-sm) / var(--leading-tight) var(--font-body); color: var(--ink-muted); }
|
||
.hint { font-size: var(--text-sm); color: var(--ink-muted); min-height: calc(var(--text-sm) * var(--leading-normal)); }
|
||
.status { font: var(--text-sm) / var(--leading-normal) var(--font-body); }
|
||
.status.is-ok { color: var(--leaf); }
|
||
.check { display: grid; grid-template-columns: var(--check-size) minmax(0, 1fr); gap: var(--sp-2); align-items: center; color: var(--ink); }
|
||
.check input { width: var(--check-size); height: var(--check-size); margin: 0; accent-color: var(--accent); }
|
||
|
||
.chip {
|
||
display: inline-block;
|
||
padding: 0 var(--sp-2);
|
||
font: var(--text-xs) / 1.6 var(--font-ui);
|
||
color: var(--ink-muted);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius);
|
||
white-space: nowrap;
|
||
}
|
||
.chip--leaf { color: var(--leaf); border-color: var(--leaf); }
|
||
|
||
.dot { width: var(--dot-size); height: var(--dot-size); border-radius: var(--radius-full); background: var(--ink-faint); flex: none; }
|
||
.dot.is-ok { background: var(--leaf); }
|
||
.dot.is-busy { background: var(--accent); }
|
||
.dot.is-new { background: var(--leaf); }
|
||
.dot.is-error { background: var(--warning); }
|
||
|
||
.kbd { font: var(--text-xs) / 1 var(--font-ui); color: var(--ink-faint); white-space: nowrap; }
|
||
|
||
/* A field is three stacked parts on fixed rows: label, control, hint -- always all three. */
|
||
.field { display: grid; grid-template-rows: auto var(--control-h) auto; gap: var(--sp-2); align-content: start; }
|
||
.fields {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
|
||
grid-auto-rows: auto var(--control-h) auto;
|
||
column-gap: var(--sp-4);
|
||
row-gap: var(--sp-2);
|
||
}
|
||
/* Each field spans three shared rows, so side-by-side controls sit on one line whatever their
|
||
labels and hints do. */
|
||
.fields .field { grid-row: span 3; grid-template-rows: subgrid; }
|
||
.row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-2); }
|
||
.row--buttons { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr)); gap: var(--sp-2); }
|
||
|
||
/* The setup card's headings in brackets, as on the server's screens: `[ SERVER ]`. */
|
||
.card h2 {
|
||
margin: 0 0 var(--sp-3);
|
||
font: 600 var(--text-sm) / var(--leading-tight) var(--font-ui);
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
color: var(--accent);
|
||
}
|
||
.card h2::before { content: "[ "; }
|
||
.card h2::after { content: " ]"; }
|
||
|
||
.code {
|
||
font: 700 var(--text-xl) / var(--leading-tight) var(--font-mono);
|
||
letter-spacing: 0.15em;
|
||
color: var(--leaf);
|
||
margin: var(--sp-2) 0 var(--sp-3);
|
||
}
|
||
|
||
/* --- The title bar ------------------------------------------------------------------------- */
|
||
|
||
.bar {
|
||
display: grid;
|
||
/* side · leaf · name · host (the rest, and the drag area) · update · agent · menu · sep · 3 controls */
|
||
grid-template-columns: var(--titlebar-h) var(--titlebar-h) auto minmax(0, 1fr) auto auto var(--titlebar-h) var(--border-w) repeat(3, 2.875rem);
|
||
align-items: center;
|
||
height: var(--titlebar-h);
|
||
border-bottom: var(--border-w) solid var(--border);
|
||
background: var(--bg-sunken);
|
||
font: 600 var(--text-sm) / 1 var(--font-ui);
|
||
user-select: none;
|
||
-webkit-user-select: none;
|
||
cursor: default;
|
||
}
|
||
.bar > button {
|
||
height: var(--titlebar-h);
|
||
margin: 0;
|
||
padding: 0;
|
||
font: inherit;
|
||
color: var(--ink-muted);
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: 0;
|
||
cursor: pointer;
|
||
}
|
||
.bar > button:hover { color: var(--ink); background: var(--surface-hover); }
|
||
.bar > button:focus-visible { outline-offset: calc(-1 * var(--outline-w)); }
|
||
.bar__leaf { justify-self: center; width: 18px; height: 18px; }
|
||
.bar__name b { color: var(--leaf); font-weight: 700; }
|
||
.bar__host {
|
||
padding: 0 var(--sp-3);
|
||
color: var(--ink-faint);
|
||
font-weight: 400;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
align-self: stretch;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.bar__btn { display: grid; place-items: center; }
|
||
/* The agent's chip: a dot and a short word, a pill inside the bar's height. */
|
||
.bar > .bar__agent {
|
||
display: grid;
|
||
grid-template-columns: var(--dot-size) auto;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
height: var(--chip-h);
|
||
margin: 0 var(--sp-2);
|
||
padding: 0 var(--sp-3);
|
||
font: var(--text-xs) / 1 var(--font-ui);
|
||
color: var(--ink-muted);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-full);
|
||
}
|
||
.bar > .bar__agent:hover, .bar > .bar__agent[aria-expanded="true"] { color: var(--ink); background: var(--surface-hover); }
|
||
.bar__agent[data-state="running"] .dot, .bar__agent[data-state="elsewhere"] .dot { background: var(--leaf); }
|
||
.bar__agent[data-state="starting"] .dot, .bar__agent[data-state="connecting"] .dot { background: var(--accent); }
|
||
.bar__agent[data-state="failed"] .dot, .bar__agent[data-state="not_linked"] .dot, .bar__agent[data-state="no_folders"] .dot,
|
||
.bar__agent[data-state="waiting"] .dot, .bar__agent[data-state="refused"] .dot, .bar__agent[data-state="elsewhere_waiting"] .dot { background: var(--warning); }
|
||
.bar__agent[data-state="refused"], .bar__agent[data-state="not_linked"] { color: var(--warning); border-color: var(--warning); }
|
||
.bar > .bar__update { height: var(--chip-h); margin: 0 var(--sp-1); padding: 0 var(--sp-3); color: var(--accent-ink); background: var(--accent); border-radius: var(--radius-full); font-size: var(--text-xs); }
|
||
.bar > .bar__update:hover { background: var(--accent-hover); color: var(--accent-ink); }
|
||
/* Hidden keeps its grid track (auto, so zero wide): the slots after it never move. */
|
||
.bar > .bar__update[hidden] { display: block !important; width: 0; margin: 0; padding: 0; overflow: hidden; visibility: hidden; }
|
||
.bar__sep { width: var(--border-w); height: var(--sp-5); background: var(--border); }
|
||
.bar > .bar__btn--close:hover { color: var(--ink-inverse); background: var(--danger); }
|
||
|
||
/* --- Popovers: the agent's panel, the team's size ------------------------------------------- */
|
||
|
||
.pop {
|
||
position: fixed;
|
||
z-index: var(--z-dropdown);
|
||
width: min(var(--w-menu-sm), calc(100vw - 2 * var(--sp-2)));
|
||
background: var(--surface-raised);
|
||
border: var(--border-w) solid var(--border-strong);
|
||
border-radius: var(--radius-soft);
|
||
box-shadow: var(--shadow-lg);
|
||
}
|
||
.pop__body { display: grid; gap: var(--sp-3); padding: var(--sp-4); }
|
||
.pop__title { font: 600 var(--text-xs) / var(--leading-tight) var(--font-ui); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); }
|
||
.pop__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: flex-end; }
|
||
|
||
/* The agent's state as a block: a dot beside its sentence, a line more, its one button. */
|
||
.agentbox {
|
||
display: grid;
|
||
grid-template-columns: var(--dot-size) minmax(0, 1fr);
|
||
column-gap: var(--sp-3);
|
||
row-gap: var(--sp-2);
|
||
align-items: start;
|
||
padding: var(--sp-3) var(--sp-4);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-soft);
|
||
}
|
||
.agentbox > :not(.agentbox__dot) { grid-column: 2; }
|
||
.agentbox__dot { width: var(--dot-size); height: var(--dot-size); margin-top: calc((var(--text-sm) * var(--leading-normal) - var(--dot-size)) / 2); border-radius: var(--radius-full); background: var(--ink-faint); }
|
||
.agentbox.is-ok .agentbox__dot { background: var(--leaf); }
|
||
.agentbox.is-busy .agentbox__dot { background: var(--accent); }
|
||
.agentbox.is-warn { border-color: var(--warning); background: var(--warning-soft); }
|
||
.agentbox.is-warn .agentbox__dot { background: var(--warning); }
|
||
.agentbox__text { font-size: var(--text-sm); font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
|
||
.agentbox__more { font-size: var(--text-sm); color: var(--ink-muted); }
|
||
.agentbox__code { margin: 0; }
|
||
.agentbox__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
|
||
.agentbox__actions .btn { height: var(--control-h-sm); }
|
||
.agentbox__error { font-size: var(--text-sm); color: var(--warning); }
|
||
|
||
/* --- Setup --------------------------------------------------------------------------------- */
|
||
|
||
.setup { overflow: auto; display: grid; place-items: center; padding: var(--sp-4); }
|
||
.card {
|
||
width: min(100%, var(--card-max));
|
||
display: grid;
|
||
gap: var(--sp-6);
|
||
padding: var(--sp-8);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-soft);
|
||
box-shadow: var(--shadow-lg);
|
||
}
|
||
.setup__body { display: grid; gap: var(--sp-6); }
|
||
.setup__body section { display: grid; gap: var(--sp-3); }
|
||
.brand { display: grid; grid-template-columns: var(--sp-10) minmax(0, 1fr); gap: var(--sp-3); align-items: center; }
|
||
.brand img { width: var(--sp-10); height: var(--sp-10); }
|
||
.brand h1 { font: 600 var(--text-xl) / var(--leading-tight) var(--font-ui); }
|
||
.brand h1 b { color: var(--leaf); font-weight: 700; }
|
||
|
||
/* --- The shell ----------------------------------------------------------------------------- */
|
||
/* Three tracks: the sidebar (zero wide when folded away), the page, and a panel beside it (the
|
||
activity panel or the viewer) while one is open. */
|
||
|
||
.shell {
|
||
position: relative;
|
||
min-height: 0;
|
||
display: grid;
|
||
--side-col: var(--side-w);
|
||
--panel-col: 0px;
|
||
grid-template-columns: var(--side-col) minmax(0, 1fr) var(--panel-col);
|
||
grid-template-areas: "side main panel";
|
||
}
|
||
.shell[data-side="false"] { --side-col: 0px; }
|
||
.shell[data-viewer="true"] { --panel-col: minmax(var(--inspector-width-min), 42%); }
|
||
.shell[data-activity="true"] { --panel-col: var(--inspector-width); }
|
||
|
||
/* --- The sidebar --------------------------------------------------------------------------- */
|
||
|
||
.side {
|
||
grid-area: side;
|
||
min-width: 0;
|
||
min-height: 0;
|
||
overflow: hidden;
|
||
display: grid;
|
||
grid-template-rows: auto auto minmax(0, 1fr) auto;
|
||
background: var(--bg-sunken);
|
||
border-right: var(--border-w) solid var(--border);
|
||
}
|
||
.shell[data-side="false"] .side { border-right: 0; visibility: hidden; }
|
||
.side__top { display: grid; gap: var(--sp-2); padding: var(--sp-3) var(--sp-3) var(--sp-2); width: var(--side-w); }
|
||
/* New chat: icon · words · its key, on known tracks. */
|
||
.side__new {
|
||
display: grid;
|
||
grid-template-columns: 16px minmax(0, 1fr) auto;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
height: var(--control-h);
|
||
padding: 0 var(--sp-3);
|
||
font: 600 var(--text-sm) var(--font-body);
|
||
color: var(--ink);
|
||
text-align: left;
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-lg);
|
||
cursor: pointer;
|
||
}
|
||
.side__new:hover { background: var(--surface-hover); border-color: var(--border-strong); }
|
||
.side__new .icon { color: var(--leaf); }
|
||
.side__new-label { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.search { position: relative; display: block; }
|
||
.search__icon { position: absolute; left: var(--sp-3); top: 50%; transform: translateY(-50%); display: grid; color: var(--ink-faint); pointer-events: none; }
|
||
.search input {
|
||
width: 100%;
|
||
height: var(--control-h-sm);
|
||
padding-left: calc(var(--sp-3) + 16px + var(--sp-2));
|
||
font-size: var(--text-sm);
|
||
background: var(--bg);
|
||
border-color: var(--border);
|
||
}
|
||
.search input::-webkit-search-cancel-button { display: none; }
|
||
.side__nav { display: grid; padding: 0 var(--sp-2) var(--sp-2); width: var(--side-w); border-bottom: var(--border-w) solid var(--border); }
|
||
|
||
/* A row of the sidebar's nav and of Settings' groups: icon · words, a control's height. */
|
||
.navrow {
|
||
display: grid;
|
||
grid-template-columns: 16px minmax(0, 1fr);
|
||
gap: var(--sp-3);
|
||
align-items: center;
|
||
width: 100%;
|
||
min-height: var(--control-h-sm);
|
||
padding: var(--sp-1) var(--sp-2);
|
||
font: var(--text-sm) / var(--leading-tight) var(--font-body);
|
||
color: var(--ink-muted);
|
||
text-align: left;
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: var(--radius-lg);
|
||
cursor: pointer;
|
||
}
|
||
.navrow:hover { color: var(--ink); background: var(--surface-hover); }
|
||
.navrow[aria-current="true"] { color: var(--ink); background: var(--surface-active); }
|
||
.navrow__icon { display: grid; place-items: center; }
|
||
|
||
/* The chats: by day, each row icon · title · folder · state, on known tracks. */
|
||
.list { list-style: none; margin: 0; padding: var(--sp-2) var(--sp-2) var(--sp-3); overflow: auto; min-height: 0; width: var(--side-w); }
|
||
.list__head { padding: var(--sp-3) var(--sp-2) var(--sp-1); font: 600 var(--text-xs) var(--font-ui); letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-faint); }
|
||
.list__head:first-child { padding-top: var(--sp-1); }
|
||
.list__note { padding: var(--sp-2); font-size: var(--text-sm); color: var(--ink-muted); }
|
||
.list__more { margin: var(--sp-2); }
|
||
.chatrow {
|
||
width: 100%;
|
||
display: grid;
|
||
grid-template-columns: 16px minmax(0, 1fr) auto var(--dot-size);
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
height: var(--control-h-sm);
|
||
padding: 0 var(--sp-2);
|
||
text-align: left;
|
||
font: var(--text-sm) / var(--leading-tight) var(--font-body);
|
||
color: var(--ink-muted);
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: var(--radius-lg);
|
||
cursor: pointer;
|
||
}
|
||
.chatrow:hover { color: var(--ink); background: var(--surface-hover); }
|
||
.chatrow[aria-current="true"] { color: var(--ink); background: var(--surface-active); }
|
||
.chatrow.is-unread { color: var(--ink); }
|
||
.chatrow.is-unread .chatrow__title { font-weight: 600; }
|
||
.chatrow__icon { display: grid; place-items: center; color: var(--ink-faint); }
|
||
.chatrow__icon.is-agent { color: var(--leaf); }
|
||
.chatrow__icon .icon { width: 14px; height: 14px; }
|
||
.chatrow__title { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.chatrow__where { max-width: calc(var(--w-field-xs) - var(--sp-4)); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--text-xs) var(--font-ui); color: var(--ink-faint); }
|
||
.chatrow__state { width: var(--dot-size); height: var(--dot-size); border-radius: var(--radius-full); }
|
||
.chatrow__state.is-busy { background: var(--accent); animation: pulse 1.4s var(--ease-in-out) infinite; }
|
||
.chatrow__state.is-new { background: var(--leaf); }
|
||
@keyframes pulse { 50% { opacity: 0.35; } }
|
||
@media (prefers-reduced-motion: reduce) { .chatrow__state.is-busy { animation: none; } }
|
||
|
||
.side__foot { padding: var(--sp-2); border-top: var(--border-w) solid var(--border); width: var(--side-w); }
|
||
.navrow--account { grid-template-columns: var(--control-h-sm) minmax(0, 1fr) 16px; min-height: var(--control-h); }
|
||
.navrow__avatar {
|
||
display: grid;
|
||
place-items: center;
|
||
width: var(--control-h-sm);
|
||
height: var(--control-h-sm);
|
||
font: 700 var(--text-sm) / 1 var(--font-ui);
|
||
color: var(--accent-ink);
|
||
background: var(--accent);
|
||
border-radius: var(--radius-full);
|
||
}
|
||
.navrow__two { display: grid; min-width: 0; }
|
||
.navrow__label { color: var(--ink); }
|
||
.navrow__sub { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: var(--text-xs); color: var(--ink-faint); }
|
||
|
||
.scrim { display: none; }
|
||
|
||
/* --- The chat ------------------------------------------------------------------------------ */
|
||
|
||
.main, .page { grid-area: main; min-width: 0; min-height: 0; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; background: var(--bg); }
|
||
.page { grid-template-rows: auto minmax(0, 1fr); }
|
||
|
||
.head {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, auto) minmax(0, 1fr) auto;
|
||
gap: var(--sp-3);
|
||
align-items: center;
|
||
min-height: var(--header-height);
|
||
padding: var(--sp-2) var(--sp-4);
|
||
border-bottom: var(--border-w) solid var(--border);
|
||
}
|
||
.head__title { font: 600 var(--text-base) / var(--leading-tight) var(--font-body); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.head__place { display: flex; gap: var(--sp-2); align-items: center; min-width: 0; }
|
||
.head__tools { display: flex; gap: var(--sp-1); align-items: center; justify-content: end; }
|
||
.main[data-new="true"] .head { display: none; }
|
||
.main > .head { grid-row: 1; }
|
||
.main > .thread { grid-row: 2; }
|
||
.main > .dock { grid-row: 3; }
|
||
|
||
/* Where an agent chat works: folder icon · its name · the device, one chip. */
|
||
.place {
|
||
display: inline-grid;
|
||
grid-template-columns: 16px minmax(0, auto) auto;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
min-width: 0;
|
||
height: var(--chip-h);
|
||
padding: 0 var(--sp-3);
|
||
font: var(--text-xs) var(--font-ui);
|
||
color: var(--ink-muted);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-full);
|
||
}
|
||
.place.is-here .icon { color: var(--leaf); }
|
||
.place__name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--ink); }
|
||
.place__where { color: var(--ink-faint); white-space: nowrap; }
|
||
|
||
.thread { overflow: auto; min-height: 0; padding: var(--sp-6) var(--sp-4) var(--sp-4); scroll-behavior: auto; }
|
||
.thread > * { max-width: var(--column); margin-left: auto; margin-right: auto; }
|
||
.thread__note { font-size: var(--text-sm); }
|
||
.thread__loading { padding: var(--sp-4) 0; }
|
||
.thread__earlier { display: block; margin: 0 auto var(--sp-4); }
|
||
.messages { display: grid; gap: var(--sp-6); }
|
||
|
||
/* A new chat is the same page, empty: the greeting low in the space above the composer, which
|
||
sits in the middle of the window rather than at its foot. */
|
||
.main[data-new="true"] { grid-template-rows: 0 minmax(0, 1fr) auto minmax(0, 0.8fr); }
|
||
.main[data-new="true"] .thread { display: grid; align-content: end; padding-bottom: var(--sp-6); }
|
||
.hello { display: grid; justify-items: center; gap: var(--sp-3); text-align: center; }
|
||
.hello__mark { width: var(--sp-10); height: var(--sp-10); }
|
||
@media (max-height: 40rem) { .hello__mark { display: none; } }
|
||
.hello__title { font: 600 var(--text-2xl) / var(--leading-tight) var(--font-body); letter-spacing: -0.01em; }
|
||
.hello__sub { max-width: var(--w-prose-sm); color: var(--ink-muted); font-size: var(--text-sm); }
|
||
/* Agent or Chat: two tabs of one width, one control. */
|
||
.kind {
|
||
display: inline-grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
margin-top: var(--sp-2);
|
||
padding: var(--sp-1);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-full);
|
||
}
|
||
.kind__tab {
|
||
display: inline-grid;
|
||
grid-template-columns: 16px auto;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: var(--chip-h);
|
||
padding: 0 var(--sp-4);
|
||
font: 600 var(--text-sm) var(--font-body);
|
||
color: var(--ink-muted);
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: var(--radius-full);
|
||
cursor: pointer;
|
||
}
|
||
.kind__tab:hover { color: var(--ink); }
|
||
.kind__tab[aria-selected="true"] { color: var(--ink); background: var(--surface-active); box-shadow: var(--shadow-sm); }
|
||
.kind__tab[aria-selected="true"] .icon { color: var(--leaf); }
|
||
|
||
/* Messages: the person's in a bubble on the right, a reply full width as the page's text. */
|
||
.msg { display: grid; gap: var(--sp-2); min-width: 0; }
|
||
.msg--user { justify-items: end; gap: var(--sp-1); }
|
||
.msg__bubble {
|
||
max-width: min(100%, var(--w-prose));
|
||
padding: var(--sp-3) var(--sp-4);
|
||
background: var(--bubble-user);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-soft);
|
||
}
|
||
.msg--user.is-queued .msg__bubble { opacity: var(--opacity-dim); }
|
||
.msg--user.is-machine { justify-items: stretch; }
|
||
.msg--user.is-machine .msg__bubble { max-width: none; font-size: var(--text-sm); color: var(--ink-muted); background: transparent; border-style: dashed; }
|
||
.msg__text { white-space: pre-wrap; overflow-wrap: anywhere; }
|
||
.msg__note { font-size: var(--text-sm); color: var(--ink-muted); }
|
||
.msg--assistant { font-size: var(--text-base); line-height: var(--leading-relaxed); }
|
||
.msg__foot { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); align-items: center; min-height: var(--control-h-sm); }
|
||
/* Under a message: small icon buttons, all one size, quiet until the message is pointed at. */
|
||
.msg__actions { display: grid; grid-auto-flow: column; grid-auto-columns: var(--control-h-sm); justify-content: start; }
|
||
/* The person's: shown on pointing, in the gap under the bubble rather than a row of their own. */
|
||
.msg--user .msg__actions { height: var(--sp-1); overflow: visible; align-items: start; opacity: 0; transition: opacity var(--dur-1) var(--ease-out); }
|
||
.msg--user:hover .msg__actions, .msg--user:focus-within .msg__actions { opacity: 1; }
|
||
.msg__act { display: grid; place-items: center; width: var(--control-h-sm); height: var(--control-h-sm); padding: 0; color: var(--ink-faint); background: none; border: 0; border-radius: var(--radius-lg); cursor: pointer; }
|
||
.msg__act:hover, .msg__act:focus-visible { color: var(--ink); background: var(--surface-hover); }
|
||
/* Regenerate: on the last reply only, and not while it is being written. */
|
||
.msg__regen { display: none; }
|
||
.messages > .msg--assistant:last-child:not(.is-live) .msg__regen { display: grid; }
|
||
.msg__editor { display: grid; gap: var(--sp-2); width: min(100%, var(--w-prose)); }
|
||
.msg__edit { width: 100%; min-height: var(--control-h); font: var(--text-base) / var(--leading-normal) var(--font-body); resize: vertical; border-radius: var(--radius-soft); }
|
||
.msg__editbar { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(min(100%, 6rem), auto); gap: var(--sp-2); justify-content: end; }
|
||
.msg__model { display: inline-grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-2); align-items: center; max-width: var(--w-chip); font: var(--text-xs) var(--font-ui); color: var(--ink-muted); }
|
||
.msg__model > span:last-child { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.msg__metrics { font: var(--text-xs) var(--font-ui); color: var(--ink-faint); }
|
||
.msg__steps { display: grid; gap: var(--sp-3); min-width: 0; }
|
||
.msg__status, .msg__thinking { font: var(--text-xs) var(--font-ui); color: var(--ink-muted); }
|
||
.msg__status.is-error { color: var(--warning); }
|
||
.is-live .msg__status::before { content: ""; display: inline-block; width: var(--dot-size); height: var(--dot-size); margin-right: var(--sp-2); border-radius: var(--radius-full); background: var(--accent); animation: pulse 1.4s var(--ease-in-out) infinite; vertical-align: middle; }
|
||
.msg__jobs { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--sp-1); font-size: var(--text-sm); }
|
||
.job { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-2); align-items: center; }
|
||
|
||
/* Attached files, as tiles: a picture's thumbnail, else its icon, name and size. */
|
||
.tiles { margin: 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: end; }
|
||
.tile {
|
||
position: relative;
|
||
display: grid;
|
||
grid-template-columns: 16px minmax(0, 1fr);
|
||
grid-template-rows: auto auto;
|
||
column-gap: var(--sp-2);
|
||
align-items: center;
|
||
width: var(--w-field-sm);
|
||
height: var(--thumb);
|
||
padding: var(--sp-2) var(--sp-3);
|
||
align-content: center;
|
||
font: var(--text-xs) / var(--leading-tight) var(--font-body);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-soft);
|
||
overflow: hidden;
|
||
}
|
||
.tile__icon { grid-row: 1 / 3; display: grid; color: var(--ink-faint); }
|
||
.tile__name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--ink); }
|
||
.tile__size { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--ink-faint); }
|
||
.tile.has-thumb { width: var(--thumb); padding: 0; }
|
||
.tile.has-thumb > :not(.tile__thumb):not(.file__remove) { display: none; }
|
||
.tile__thumb { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
|
||
|
||
/* A reply's steps: thinking and each tool call as one compact row that unfolds. */
|
||
.step__row, .call__head {
|
||
list-style: none;
|
||
display: grid;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
min-height: var(--control-h-sm);
|
||
padding: 0 var(--sp-2);
|
||
font: var(--text-sm) / var(--leading-tight) var(--font-body);
|
||
color: var(--ink-muted);
|
||
border-radius: var(--radius-lg);
|
||
cursor: pointer;
|
||
}
|
||
.step__row::-webkit-details-marker, .call__head::-webkit-details-marker { display: none; }
|
||
.step__row:hover, .call__head:hover { color: var(--ink); background: var(--surface-hover); }
|
||
.step__row { grid-template-columns: 16px minmax(0, auto) 16px; justify-content: start; }
|
||
.step__icon { display: grid; }
|
||
.step__meta { color: var(--ink-faint); }
|
||
.step__chev { display: grid; place-items: center; color: var(--ink-faint); }
|
||
.step__chev .icon { width: 12px; height: 12px; transition: transform var(--dur-1) var(--ease-out); }
|
||
details[open] > summary .step__chev .icon { transform: rotate(90deg); }
|
||
/* A row's hover box reaches out by its padding, so its icon stands on the text's left edge. */
|
||
.step--thinking { justify-self: start; max-width: calc(100% + var(--sp-2)); margin-left: calc(-1 * var(--sp-2)); }
|
||
.step--tools { margin-left: calc(-1 * var(--sp-2)); margin-right: calc(-1 * var(--sp-2)); }
|
||
.step__pre { margin: var(--sp-2) 0 0 var(--sp-4); padding-left: var(--sp-3); border-left: var(--border-w-thick) solid var(--border); white-space: pre-wrap; font-size: var(--text-sm); line-height: var(--leading-normal); color: var(--ink-muted); }
|
||
.step--tools { display: grid; gap: var(--sp-1); }
|
||
.step--steer { padding-left: var(--sp-3); border-left: var(--border-w-thick) solid var(--accent-soft); }
|
||
.steer__text { white-space: pre-wrap; font-size: var(--text-sm); }
|
||
|
||
.call { min-width: 0; border: var(--border-w) solid transparent; border-radius: var(--radius-lg); }
|
||
.call[open] { border-color: var(--border); background: var(--surface); }
|
||
.call.is-failed .call__name { color: var(--warning); }
|
||
/* The call's line: dot · tool · what it did · chips · chevron, on fixed tracks. */
|
||
.call__head { grid-template-columns: var(--dot-size) auto minmax(0, 1fr) auto 16px; }
|
||
.call__name { font: 600 var(--text-xs) var(--font-ui); color: var(--ink); white-space: nowrap; }
|
||
.call__title { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--text-xs) var(--font-mono); color: var(--ink-muted); }
|
||
.call__chips { display: flex; gap: var(--sp-1); }
|
||
.call__body { display: grid; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3) var(--sp-3); border-top: var(--border-w) solid var(--border); font-size: var(--text-sm); line-height: var(--leading-normal); }
|
||
.call__pre, .md-code pre {
|
||
margin: 0;
|
||
padding: var(--sp-3) var(--sp-4);
|
||
max-height: var(--h-list);
|
||
overflow: auto;
|
||
font: var(--text-xs) / var(--leading-normal) var(--font-mono);
|
||
background: var(--code-bg);
|
||
border: var(--border-w) solid var(--code-border);
|
||
border-radius: var(--radius-lg);
|
||
white-space: pre;
|
||
}
|
||
.call__open { justify-self: start; margin: 0 var(--sp-3) var(--sp-3); }
|
||
|
||
/* A model's avatar: its initial on its own colour. Only the hue is the model's (models.js, the
|
||
server's stable_hue); how strong it is comes from the theme, by mixing it into the surface. */
|
||
.avatar {
|
||
display: inline-grid;
|
||
place-items: center;
|
||
width: 1.25rem;
|
||
height: 1.25rem;
|
||
font: 700 var(--text-xs) / 1 var(--font-ui);
|
||
color: var(--ink);
|
||
background: color-mix(in oklab, hsl(var(--avatar-hue, 40) 100% 50%) 32%, var(--surface));
|
||
border-radius: var(--radius-sm);
|
||
flex: none;
|
||
}
|
||
.avatar--none { background: var(--surface-active); }
|
||
/* A model's own picture fills the same square, cut to it: the avatar's size does not depend on it. */
|
||
.avatar--image { overflow: hidden; background: var(--surface); }
|
||
.avatar--image img { display: block; width: 100%; height: 100%; object-fit: cover; }
|
||
/* The Thinking switch: a checkbox drawn as a switch, then its words, on two known tracks. The
|
||
label is the tap target; the whole of it is a control's height. */
|
||
.toggle {
|
||
display: inline-grid;
|
||
grid-template-columns: calc(2 * var(--check-size)) auto;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
height: var(--control-h);
|
||
color: var(--ink);
|
||
font: var(--text-sm) var(--font-ui);
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
}
|
||
.toggle--compact { height: var(--control-h-sm); }
|
||
.toggle input {
|
||
appearance: none;
|
||
position: relative;
|
||
width: calc(2 * var(--check-size));
|
||
height: var(--check-size);
|
||
margin: 0;
|
||
background: var(--surface-active);
|
||
border: var(--border-w) solid var(--border-strong);
|
||
border-radius: var(--radius-full);
|
||
cursor: pointer;
|
||
transition: background var(--dur-1) var(--ease-out);
|
||
}
|
||
.toggle input::after {
|
||
content: "";
|
||
position: absolute;
|
||
top: var(--border-w);
|
||
left: var(--border-w);
|
||
width: calc(var(--check-size) - 4 * var(--border-w));
|
||
height: calc(var(--check-size) - 4 * var(--border-w));
|
||
background: var(--ink-muted);
|
||
border-radius: var(--radius-full);
|
||
transition: transform var(--dur-1) var(--ease-out);
|
||
}
|
||
.toggle input:checked { background: var(--accent); border-color: var(--accent); }
|
||
.toggle input:checked::after { background: var(--accent-ink); transform: translateX(var(--check-size)); }
|
||
/* The team's size: two number fields of one width with a dash between them, and in the header
|
||
its word before them -- fixed tracks, so nothing moves when a number grows a digit. */
|
||
.agents {
|
||
display: inline-grid;
|
||
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
width: 100%;
|
||
height: var(--control-h);
|
||
}
|
||
.agents__dash { color: var(--ink-muted); }
|
||
.agents__input { width: 100%; min-width: 0; height: var(--control-h); padding: 0 var(--control-px-sm); }
|
||
.agents--compact {
|
||
grid-template-columns: auto calc(var(--w-field-xs) / 2) auto calc(var(--w-field-xs) / 2);
|
||
width: auto;
|
||
height: var(--control-h-sm);
|
||
font: var(--text-sm) var(--font-ui);
|
||
}
|
||
.agents--compact .agents__input { height: var(--control-h-sm); }
|
||
.agents__label { color: var(--ink-muted); white-space: nowrap; }
|
||
/* Markdown, drawn by markdown.js from model output (never as HTML). */
|
||
.md { overflow-wrap: anywhere; min-width: 0; }
|
||
.md > * + * { margin-top: var(--sp-3); }
|
||
.md h1, .md h2, .md h3, .md h4, .md h5, .md h6 { font-family: var(--font-ui); line-height: var(--leading-tight); }
|
||
.md h1 { font-size: var(--text-xl); }
|
||
.md h2 { font-size: var(--text-lg); }
|
||
.md h3 { font-size: var(--text-md); }
|
||
.md h4, .md h5, .md h6 { font-size: var(--text-base); }
|
||
.md ul, .md ol { margin: 0; padding-left: var(--sp-6); }
|
||
.md li + li { margin-top: var(--sp-1); }
|
||
.md-task { list-style: none; margin-left: calc(-1 * var(--sp-5)); }
|
||
.md-task input { margin: 0 var(--sp-2) 0 0; }
|
||
.md blockquote { margin: 0; padding-left: var(--sp-3); border-left: var(--border-w-thick) solid var(--border-strong); color: var(--ink-muted); }
|
||
.md hr { border: 0; border-top: var(--border-w) solid var(--border); }
|
||
.md code { font: 0.9em var(--font-mono); padding: 0 var(--sp-1); background: var(--code-bg); border-radius: var(--radius-sm); }
|
||
.md pre code { padding: 0; background: none; }
|
||
.md a { color: var(--accent); }
|
||
.md a.md-unsafe { color: var(--ink-muted); text-decoration: line-through dotted; }
|
||
.md-code { position: relative; display: grid; }
|
||
.md-lang { position: absolute; top: var(--sp-1); left: var(--sp-3); font: var(--text-xs) var(--font-ui); color: var(--ink-faint); }
|
||
.md-code:has(.md-lang) pre { padding-top: var(--sp-6); }
|
||
.md-copy {
|
||
position: absolute;
|
||
top: var(--sp-1);
|
||
right: var(--sp-1);
|
||
height: var(--control-h-sm);
|
||
padding: 0 var(--sp-2);
|
||
font: var(--text-xs) var(--font-ui);
|
||
color: var(--ink-muted);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-lg);
|
||
cursor: pointer;
|
||
}
|
||
/* A wide table scrolls by itself; the page does not. */
|
||
.md-table { overflow-x: auto; }
|
||
.md table { border-collapse: collapse; font-size: var(--text-sm); }
|
||
.md th, .md td { padding: var(--sp-1) var(--sp-3); border: var(--border-w) solid var(--border); text-align: left; vertical-align: top; }
|
||
.md [data-align="center"] { text-align: center; }
|
||
.md [data-align="right"] { text-align: right; }
|
||
.md th { background: var(--surface); }
|
||
|
||
/* Cards: what waits for an answer, above the composer. */
|
||
.cards { overflow: auto; max-height: 50vh; padding: var(--sp-3) var(--sp-4) 0; display: grid; gap: var(--sp-3); }
|
||
.ask {
|
||
width: 100%;
|
||
max-width: var(--thread-max-width);
|
||
margin: 0 auto;
|
||
display: grid;
|
||
gap: var(--sp-3);
|
||
padding: var(--sp-3) var(--sp-4);
|
||
background: var(--surface-raised);
|
||
border: var(--border-w-accent) solid var(--accent);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-block-accent);
|
||
}
|
||
.ask__item { display: grid; gap: var(--sp-2); }
|
||
.ask__header { font: 600 var(--text-xs) var(--font-ui); text-transform: uppercase; letter-spacing: 0.08em; color: var(--accent); }
|
||
.ask__title { font-weight: 600; }
|
||
.ask__edit { width: 100%; font-family: var(--font-mono); }
|
||
.ask__text { width: 100%; }
|
||
.ask__options { display: grid; gap: var(--sp-2); }
|
||
.opt {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) auto;
|
||
grid-template-rows: auto auto;
|
||
column-gap: var(--sp-2);
|
||
align-items: center;
|
||
min-height: var(--control-h);
|
||
padding: var(--sp-2) var(--sp-3);
|
||
text-align: left;
|
||
font: var(--text-sm) var(--font-body);
|
||
color: var(--ink);
|
||
background: var(--bg);
|
||
border: var(--border-w) solid var(--border-strong);
|
||
border-radius: var(--radius-lg);
|
||
cursor: pointer;
|
||
}
|
||
.opt[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); }
|
||
.opt__desc { grid-column: 1; font-size: var(--text-xs); color: var(--ink-muted); }
|
||
.opt .chip { grid-column: 2; grid-row: 1; }
|
||
.ask__actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 8rem), 1fr)); gap: var(--sp-2); }
|
||
.ask__said { font-size: var(--text-sm); color: var(--warning); }
|
||
.ask__said:empty { display: none; }
|
||
.plan { margin: 0; padding-left: var(--sp-5); display: grid; gap: var(--sp-2); font-size: var(--text-sm); }
|
||
.plan ul { margin: var(--sp-1) 0 0; padding-left: var(--sp-4); }
|
||
.plan__phase { font-weight: 600; }
|
||
.plan__task.is-done { text-decoration: line-through; color: var(--ink-muted); }
|
||
|
||
/* --- The viewer ---------------------------------------------------------------------------- */
|
||
|
||
.viewer {
|
||
grid-area: panel;
|
||
min-width: 0;
|
||
min-height: 0;
|
||
display: grid;
|
||
grid-template-rows: auto minmax(0, 1fr);
|
||
border-left: var(--border-w) solid var(--border);
|
||
background: var(--bg);
|
||
}
|
||
.viewer__head {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) auto var(--control-h-sm);
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
min-height: var(--header-height);
|
||
padding: 0 var(--sp-3);
|
||
border-bottom: var(--border-w) solid var(--border);
|
||
}
|
||
.viewer__id { min-width: 0; }
|
||
.viewer__name { font: 600 var(--text-sm) / var(--leading-tight) var(--font-ui); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.viewer__where { font: var(--text-xs) var(--font-ui); color: var(--ink-muted); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.viewer__modes { display: grid; grid-auto-flow: column; }
|
||
.seg {
|
||
height: var(--control-h-sm);
|
||
padding: 0 var(--sp-3);
|
||
font: var(--text-xs) var(--font-ui);
|
||
color: var(--ink-muted);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
cursor: pointer;
|
||
}
|
||
.seg + .seg { border-left: 0; }
|
||
.seg[aria-pressed="true"] { color: var(--ink); background: var(--surface-active); }
|
||
.viewer__body { min-height: 0; display: grid; }
|
||
.viewer__code { min-height: 0; overflow: hidden; }
|
||
.viewer__code .cm-editor { height: 100%; }
|
||
.viewer__md { overflow: auto; padding: var(--sp-4); }
|
||
.viewer__frame { width: 100%; height: 100%; border: 0; background: var(--surface); }
|
||
.viewer__note { padding: var(--sp-4); font-size: var(--text-sm); color: var(--ink-muted); }
|
||
.viewer__note.is-error { color: var(--warning); }
|
||
|
||
/* --- The activity panel -------------------------------------------------------------------------
|
||
Beside the chat, the inspector's width; while the viewer is open too, the viewer goes over the
|
||
chat (it was opened from here, and three columns of text beside the sidebar do not fit). Over
|
||
the chat from --bp-wide down, as the viewer is; at --bp-narrow that is a full-height sheet. */
|
||
|
||
.shell[data-activity="true"] .viewer { grid-area: main; z-index: var(--z-panel); border-left: 0; }
|
||
.activity {
|
||
grid-area: panel;
|
||
min-width: 0;
|
||
min-height: 0;
|
||
display: grid;
|
||
grid-template-rows: auto minmax(0, 1fr);
|
||
border-left: var(--border-w) solid var(--border);
|
||
background: var(--bg);
|
||
}
|
||
/* Title and close on two known tracks; with an agent's conversation open, Back before them. */
|
||
.activity__head { grid-template-columns: minmax(0, 1fr) var(--control-h-sm); }
|
||
.activity[data-view="agent"] .activity__head { grid-template-columns: var(--control-h-sm) minmax(0, 1fr) var(--control-h-sm); }
|
||
.activity__body { overflow: auto; min-height: 0; display: grid; align-content: start; font-size: var(--text-sm); }
|
||
.activity__section { padding: var(--sp-3); border-bottom: var(--border-w) solid var(--border); min-width: 0; }
|
||
.activity__section:last-child { border-bottom: 0; }
|
||
.activity__heading, .activity__subheading {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) auto;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
margin: 0;
|
||
font: 600 var(--text-sm) / var(--leading-tight) var(--font-ui);
|
||
color: var(--ink);
|
||
cursor: pointer;
|
||
}
|
||
.activity__heading::-webkit-details-marker { display: none; }
|
||
.activity__section[open] > .activity__heading { margin-bottom: var(--sp-3); }
|
||
.activity__subheading { margin: var(--sp-4) 0 var(--sp-2); cursor: default; }
|
||
.activity__count { font: var(--text-xs) var(--font-mono); color: var(--ink-muted); }
|
||
.activity__empty { margin: 0; padding: var(--sp-1) 0; color: var(--ink-faint); font-size: var(--text-sm); }
|
||
.activity__empty.is-error { color: var(--warning); padding: var(--sp-3); }
|
||
.activity__plan { min-width: 0; }
|
||
|
||
/* Context: the line, the bar, then one row per category on four fixed tracks -- swatch, the name
|
||
that gives, and two number columns -- so the numbers stand in columns in any language. The
|
||
categories' colours are tokens, one each. */
|
||
.ctx { display: grid; gap: var(--sp-2); }
|
||
.ctx__used { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-2); margin: 0; color: var(--ink); }
|
||
.ctx__of { font-family: var(--font-mono); color: var(--ink-muted); }
|
||
.ctx__bar { display: flex; height: var(--sp-2); overflow: hidden; background: var(--surface-active); border-radius: var(--radius-full); }
|
||
.ctx__seg { flex: none; width: var(--share, 0); background: var(--ctx, var(--ink-faint)); }
|
||
.ctx__rows { display: grid; margin: 0; padding: 0; list-style: none; }
|
||
.ctx__row {
|
||
display: grid;
|
||
grid-template-columns: var(--sp-3) minmax(0, 1fr) var(--num-col) var(--num-col);
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
min-height: var(--row-h);
|
||
}
|
||
.ctx__key { width: var(--sp-3); height: var(--sp-3); border-radius: var(--radius-sm); background: var(--ctx, var(--ink-faint)); }
|
||
.ctx--free.ctx__key { background: transparent; border: var(--border-w) solid var(--border-strong); }
|
||
.ctx__name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--ink-muted); }
|
||
.ctx__num { font: var(--text-xs) var(--font-mono); text-align: right; color: var(--ink-muted); }
|
||
.ctx__note { margin: 0; font-size: var(--text-xs); color: var(--ink-faint); }
|
||
.ctx--messages { --ctx: var(--accent); }
|
||
.ctx--system { --ctx: var(--ink-muted); }
|
||
.ctx--memory { --ctx: var(--warning); }
|
||
.ctx--instructions { --ctx: var(--success); }
|
||
.ctx--tools { --ctx: var(--ink); }
|
||
.ctx--mcp_tools { --ctx: var(--danger); }
|
||
.ctx--since { --ctx: var(--ink-faint); }
|
||
.ctx--buffer { --ctx: var(--border-strong); }
|
||
.ctx--free { --ctx: transparent; }
|
||
|
||
/* Outputs: icon, the name (cut, never wrapped), the lines added and removed. */
|
||
.outs { display: grid; margin: 0; padding: 0; list-style: none; }
|
||
.outs__row { display: grid; grid-template-columns: var(--sp-4) minmax(0, 1fr) auto; gap: var(--sp-2); align-items: center; min-height: var(--row-h); color: var(--ink-muted); }
|
||
.outs__name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 0; font: var(--text-sm) var(--font-ui); color: var(--ink); text-align: left; background: none; border: 0; cursor: pointer; }
|
||
.outs__name:hover { color: var(--accent); text-decoration: underline; }
|
||
.outs__diff { display: grid; grid-auto-flow: column; gap: var(--sp-2); font: var(--text-xs) var(--font-mono); }
|
||
.outs__add { color: var(--success); }
|
||
.outs__del { color: var(--danger); }
|
||
|
||
/* Background tasks. An agent's row is one grid of known tracks: state dot, what it is (the one
|
||
track that gives, cut), elapsed time in a column of its own width, the stop button at its size
|
||
(an empty box where there is none) -- so rows line up whatever each says. */
|
||
.tasks { display: grid; gap: var(--sp-2); min-width: 0; }
|
||
.tasks__summary, .tasks__team { margin: 0; color: var(--ink-muted); }
|
||
.tasks__goal { margin: 0; color: var(--ink); }
|
||
.tasks__list { display: grid; gap: var(--sp-1); }
|
||
.tasks__more > summary { cursor: pointer; padding: var(--sp-1) 0; color: var(--ink-muted); }
|
||
.tasks__more[open] > summary { margin-bottom: var(--sp-1); }
|
||
.agent { margin-left: calc(var(--depth, 0) * var(--sp-4)); background: var(--surface); border: var(--border-w) solid var(--border); border-radius: var(--radius-lg); min-width: 0; }
|
||
.agent__row {
|
||
display: grid;
|
||
grid-template-columns: var(--dot-size) minmax(0, 1fr) var(--time-col) var(--control-h-sm);
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
min-height: var(--control-h);
|
||
padding: 0 var(--sp-1) 0 var(--sp-3);
|
||
cursor: pointer;
|
||
list-style: none;
|
||
}
|
||
.agent__row::-webkit-details-marker { display: none; }
|
||
.agent__dot { width: var(--dot-size); height: var(--dot-size); border-radius: var(--radius-full); background: var(--ink-faint); }
|
||
.agent.is-working .agent__dot { background: var(--accent); }
|
||
.agent.is-queued .agent__dot, .agent.is-waiting .agent__dot { background: var(--warning); }
|
||
.agent.is-done .agent__dot { background: var(--leaf); }
|
||
.agent.is-error .agent__dot { background: var(--danger); }
|
||
.agent__what { display: grid; min-width: 0; }
|
||
.agent__name, .agent__role { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.agent__name { color: var(--ink); }
|
||
.agent__role { font-size: var(--text-xs); color: var(--ink-muted); }
|
||
.agent__time { font: var(--text-xs) var(--font-mono); text-align: right; color: var(--ink-muted); }
|
||
.agent__stop { width: var(--control-h-sm); height: var(--control-h-sm); }
|
||
.agent__body { display: grid; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3) var(--sp-3); border-top: var(--border-w) solid var(--border); min-width: 0; }
|
||
.agent__body > .btn { justify-self: start; }
|
||
.agent__facts { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); margin: 0; font-size: var(--text-xs); color: var(--ink-muted); }
|
||
.agent__state { color: var(--ink); }
|
||
.agent__model { font-family: var(--font-mono); overflow-wrap: anywhere; }
|
||
.agent__brief { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; color: var(--ink); }
|
||
.agent__step { display: grid; grid-template-columns: var(--dot-size) auto minmax(0, 1fr); gap: var(--sp-2); align-items: center; margin: 0; }
|
||
.agent__verb { color: var(--ink); white-space: nowrap; }
|
||
.agent__title { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--text-xs) var(--font-mono); color: var(--ink-muted); }
|
||
.agent__text { margin: 0; max-height: calc(6 * var(--row-h)); overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; font-size: var(--text-xs); color: var(--ink-muted); }
|
||
|
||
/* The team's room: who to whom, a report marked, the words as markdown. */
|
||
.room { display: grid; gap: var(--sp-2); margin: 0; padding: 0; list-style: none; }
|
||
.room__entry { display: grid; gap: var(--sp-1); padding: var(--sp-2) var(--sp-3); background: var(--surface); border: var(--border-w) solid var(--border); border-radius: var(--radius-lg); min-width: 0; }
|
||
.room__entry.is-report { border-left: var(--border-w-thick) solid var(--leaf); }
|
||
.room__meta { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--sp-2); align-items: center; font-size: var(--text-xs); color: var(--ink-muted); }
|
||
.room__n { font-family: var(--font-mono); }
|
||
.room__route { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.room__badge { color: var(--leaf); border-color: var(--leaf); }
|
||
|
||
/* One agent's conversation, read-only. */
|
||
.convo__head { display: grid; gap: var(--sp-2); padding: var(--sp-3); border-bottom: var(--border-w) solid var(--border); }
|
||
.convo__head > .btn { justify-self: start; }
|
||
.convo { display: grid; gap: var(--sp-3); padding: var(--sp-3); min-width: 0; }
|
||
.convo__turn { font-size: var(--text-sm); }
|
||
.convo__tools { display: grid; gap: var(--sp-1); margin: var(--sp-2) 0 0; padding: 0; list-style: none; }
|
||
.convo__tool { display: grid; grid-template-columns: var(--dot-size) auto minmax(0, 1fr); gap: var(--sp-2); align-items: center; font-size: var(--text-xs); }
|
||
|
||
/* --- Menus, dialogs and the palette ----------------------------------------------------------- */
|
||
|
||
.menu {
|
||
position: fixed;
|
||
z-index: var(--z-dropdown);
|
||
min-width: 12rem;
|
||
max-width: min(var(--w-menu), calc(100vw - 2 * var(--sp-2)));
|
||
max-height: min(var(--h-list), calc(100vh - 2 * var(--sp-2)));
|
||
overflow: auto;
|
||
padding: var(--sp-1) 0;
|
||
background: var(--surface-raised);
|
||
border: var(--border-w) solid var(--border-strong);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-lg);
|
||
}
|
||
/* Every item: lead · label · check, on the same tracks, so labels line up with or without a lead. */
|
||
.menu__item {
|
||
display: grid;
|
||
grid-template-columns: 1.25rem minmax(0, 1fr) 1rem;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
width: 100%;
|
||
min-height: var(--row-h);
|
||
padding: 0 var(--sp-3);
|
||
font: var(--text-sm) var(--font-ui);
|
||
color: var(--ink);
|
||
text-align: left;
|
||
background: none;
|
||
border: 0;
|
||
cursor: pointer;
|
||
}
|
||
/* A menu where no item has a lead: no lead track either. */
|
||
.menu--plain .menu__item { grid-template-columns: minmax(0, 1fr) 1rem; }
|
||
.menu--plain .menu__lead { display: none; }
|
||
.menu__item:hover, .menu__item:focus-visible { background: var(--surface-hover); outline: none; }
|
||
.menu__item:disabled { opacity: var(--opacity-dim); cursor: default; }
|
||
.menu__item.is-danger { color: var(--danger); }
|
||
.menu__label { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.menu__check { color: var(--accent); }
|
||
.menu__sep { height: var(--border-w); margin: var(--sp-1) 0; background: var(--border); }
|
||
|
||
.dialog {
|
||
width: min(var(--w-dialog), calc(100vw - 2 * var(--sp-4)));
|
||
padding: 0;
|
||
color: var(--ink);
|
||
background: var(--surface-raised);
|
||
border: var(--border-w) solid var(--border-strong);
|
||
border-radius: var(--radius-soft);
|
||
box-shadow: var(--shadow-lg);
|
||
}
|
||
.dialog::backdrop { background: var(--scrim); }
|
||
.dialog__body { display: grid; gap: var(--sp-3); padding: var(--sp-4); }
|
||
.dialog__title { font: 600 var(--text-md) / var(--leading-tight) var(--font-ui); }
|
||
/* A line to copy: as it is, on one line that scrolls on its own rather than the dialog. */
|
||
.dialog__code {
|
||
margin: 0;
|
||
padding: var(--sp-2) var(--sp-3);
|
||
overflow-x: auto;
|
||
white-space: pre;
|
||
font: var(--text-sm) var(--font-mono);
|
||
color: var(--ink);
|
||
background: var(--code-bg);
|
||
border: var(--border-w) solid var(--code-border);
|
||
border-radius: var(--radius-lg);
|
||
user-select: all;
|
||
}
|
||
.dialog__input { width: 100%; }
|
||
.dialog__actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); }
|
||
|
||
.palette { align-self: start; margin-top: 12vh; }
|
||
.palette__line { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-2); align-items: center; padding: 0 var(--sp-3); border-bottom: var(--border-w) solid var(--border); color: var(--ink-muted); }
|
||
.palette__input { height: var(--control-h-lg) !important; border: 0 !important; background: none !important; outline: none; font-size: var(--text-base); }
|
||
.palette__list { list-style: none; margin: 0; padding: var(--sp-1) 0; max-height: var(--h-list); overflow: auto; }
|
||
/* A result: icon · label · hint, the same tracks on every row. */
|
||
.palette__item {
|
||
display: grid;
|
||
grid-template-columns: 1rem minmax(0, 1fr) auto;
|
||
gap: var(--sp-3);
|
||
align-items: center;
|
||
min-height: var(--row-h);
|
||
padding: 0 var(--sp-3);
|
||
font: var(--text-sm) var(--font-ui);
|
||
cursor: pointer;
|
||
}
|
||
.palette__item[aria-selected="true"] { background: var(--surface-active); }
|
||
.palette__icon { display: grid; place-items: center; color: var(--ink-muted); }
|
||
.palette__label { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.palette__hint { font-size: var(--text-xs); color: var(--ink-faint); white-space: nowrap; }
|
||
.palette__none { padding: var(--sp-3); font-size: var(--text-sm); color: var(--ink-muted); }
|
||
|
||
|
||
/* --- Under the conversation: notes, cards, the agent's notice, the activity chip, the composer --
|
||
One column the conversation's width, so all of it lines up with the messages above. */
|
||
|
||
.dock { display: grid; gap: var(--sp-2); align-content: start; padding: 0 var(--sp-4) var(--sp-4); }
|
||
.dock > * { width: 100%; max-width: var(--column); margin: 0 auto; }
|
||
.dock .cards { padding: 0; max-height: 50vh; overflow: auto; }
|
||
.thread__note { padding: var(--sp-2) var(--sp-3); background: var(--warning-soft); border-radius: var(--radius-lg); }
|
||
|
||
/* The activity chip: what the agents are doing (or only "Activity"), and the way into the panel. */
|
||
.strip { display: flex; justify-content: start; }
|
||
.strip__btn {
|
||
display: inline-grid;
|
||
grid-template-columns: var(--dot-size) minmax(0, auto) 12px;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
max-width: 100%;
|
||
height: var(--chip-h);
|
||
padding: 0 var(--sp-3);
|
||
font: var(--text-xs) var(--font-ui);
|
||
color: var(--ink-muted);
|
||
text-align: left;
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-full);
|
||
cursor: pointer;
|
||
}
|
||
.strip__btn:hover, .strip__btn[aria-expanded="true"] { color: var(--ink); background: var(--surface-hover); }
|
||
.strip__btn .dot { background: var(--ink-faint); }
|
||
.strip__btn.is-active .dot { background: var(--accent); animation: pulse 1.4s var(--ease-in-out) infinite; }
|
||
.strip__btn .icon { width: 12px; height: 12px; }
|
||
.strip__text { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
|
||
/* The composer: a card with the files it carries, the text, and under them one row -- attach,
|
||
the chat's chips (the one track that gives, wrapping onto a second line if it must), then Stop
|
||
and Send at their own size. */
|
||
.composer {
|
||
position: relative;
|
||
display: grid;
|
||
grid-template-rows: auto auto auto;
|
||
gap: var(--sp-2);
|
||
padding: var(--sp-3) var(--sp-3) var(--sp-2);
|
||
background: var(--surface);
|
||
border: var(--border-w) solid var(--border-strong);
|
||
border-radius: var(--radius-soft);
|
||
box-shadow: var(--shadow);
|
||
transition: border-color var(--dur-1) var(--ease-out);
|
||
}
|
||
.composer:focus-within { border-color: var(--accent); }
|
||
.composer > * { min-width: 0; }
|
||
.composer textarea {
|
||
width: 100%;
|
||
min-height: calc(var(--text-base) * var(--leading-normal) + 2 * var(--sp-1));
|
||
max-height: 40vh;
|
||
padding: var(--sp-1) var(--sp-1);
|
||
font: var(--text-base) / var(--leading-normal) var(--font-body);
|
||
background: transparent;
|
||
border: 0;
|
||
outline: none;
|
||
}
|
||
.composer textarea::placeholder { color: var(--ink-faint); }
|
||
.composer__files { justify-content: start; }
|
||
.composer__bar {
|
||
display: grid;
|
||
grid-template-columns: var(--chip-h) minmax(0, 1fr) auto auto;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
}
|
||
.composer[data-attach="false"] .composer__bar { grid-template-columns: minmax(0, 1fr) auto auto; }
|
||
.composer__attach { width: var(--chip-h); height: var(--chip-h); border: var(--border-w) solid var(--border); border-radius: var(--radius-full); }
|
||
/* The chips stay on one line; where they do not fit, the line scrolls by itself. */
|
||
.composer__chips { display: flex; flex-wrap: nowrap; gap: var(--sp-1); min-width: 0; align-items: center; overflow-x: auto; scrollbar-width: none; }
|
||
.composer__chips::-webkit-scrollbar { display: none; }
|
||
.composer__chips > * { flex: none; }
|
||
/* Send and Stop: round, one size, side by side when both show (a message typed while a reply runs). */
|
||
.round {
|
||
display: grid;
|
||
place-items: center;
|
||
width: var(--round);
|
||
height: var(--round);
|
||
padding: 0;
|
||
color: var(--accent-ink);
|
||
background: var(--accent);
|
||
border: 0;
|
||
border-radius: var(--radius-full);
|
||
cursor: pointer;
|
||
transition: background var(--dur-1) var(--ease-out), opacity var(--dur-1) var(--ease-out);
|
||
}
|
||
.round:hover { background: var(--accent-hover); }
|
||
.round:disabled { opacity: var(--opacity-dim); cursor: default; }
|
||
.round--stop { color: var(--ink); background: var(--surface-active); border: var(--border-w) solid var(--border-strong); }
|
||
.round--stop:hover { background: var(--surface-hover); }
|
||
.composer:has(textarea:placeholder-shown) .round:not(.round--stop) { opacity: var(--opacity-dim); }
|
||
|
||
/* A chip under the text: icon or avatar · words · chevron, a small control's height. */
|
||
.cchip {
|
||
display: inline-grid;
|
||
grid-auto-flow: column;
|
||
grid-auto-columns: auto;
|
||
gap: var(--sp-1);
|
||
align-items: center;
|
||
max-width: var(--w-field);
|
||
height: var(--chip-h);
|
||
padding: 0 var(--sp-2);
|
||
font: var(--text-xs) / 1 var(--font-ui);
|
||
color: var(--ink-muted);
|
||
background: transparent;
|
||
border: var(--border-w) solid transparent;
|
||
border-radius: var(--radius-full);
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
}
|
||
.cchip:hover { color: var(--ink); background: var(--surface-hover); border-color: var(--border); }
|
||
.cchip:disabled { cursor: default; }
|
||
.cchip:disabled:hover { background: transparent; border-color: transparent; }
|
||
.cchip__label { overflow: hidden; text-overflow: ellipsis; }
|
||
.cchip__chev { display: grid; color: var(--ink-faint); }
|
||
.cchip__chev .icon { width: 12px; height: 12px; }
|
||
.cchip .avatar { width: 1rem; height: 1rem; font-size: 0.625rem; }
|
||
.cchip.is-dim { color: var(--ink-faint); }
|
||
.cchip.is-warn { color: var(--warning); border-color: var(--warning); }
|
||
|
||
/* Files dragged over the window: where they will go, over the whole composer. */
|
||
.composer__drop { display: none; }
|
||
.composer[data-drag="true"] .composer__drop {
|
||
display: grid;
|
||
place-items: center;
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: var(--z-raised);
|
||
font: 600 var(--text-sm) var(--font-ui);
|
||
color: var(--accent);
|
||
background: var(--accent-soft);
|
||
border: var(--border-w-thick) dashed var(--accent);
|
||
border-radius: var(--radius-soft);
|
||
}
|
||
/* A pending file's tile carries its remove button in its corner. */
|
||
.file .file__remove {
|
||
position: absolute;
|
||
top: var(--sp-1);
|
||
right: var(--sp-1);
|
||
display: grid;
|
||
place-items: center;
|
||
width: var(--sp-5);
|
||
height: var(--sp-5);
|
||
padding: 0;
|
||
color: var(--ink);
|
||
background: var(--surface-raised);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-full);
|
||
cursor: pointer;
|
||
}
|
||
.file .file__remove .icon { width: 12px; height: 12px; }
|
||
.file.is-failed { border-color: var(--warning); }
|
||
.file.is-failed .tile__size { color: var(--warning); }
|
||
.file.is-sending { opacity: var(--opacity-dim); }
|
||
|
||
/* The agent's notice above the composer: the block, the column's width. */
|
||
.notice .agentbox { box-shadow: var(--shadow-sm); }
|
||
|
||
/* --- Pages: Files, Scheduled ---------------------------------------------------------------- */
|
||
|
||
.page__body { overflow: auto; min-height: 0; padding: var(--sp-6) var(--sp-4); }
|
||
.page__body > * { width: 100%; max-width: var(--w-prose); margin-left: auto; margin-right: auto; }
|
||
.page__loading { padding: var(--sp-4) 0; }
|
||
|
||
.tabs { display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr; padding: var(--sp-half); background: var(--surface); border: var(--border-w) solid var(--border); border-radius: var(--radius-full); }
|
||
.tabs__tab {
|
||
display: inline-grid;
|
||
grid-template-columns: 16px auto;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: var(--chip-h);
|
||
padding: 0 var(--sp-3);
|
||
font: var(--text-xs) var(--font-ui);
|
||
color: var(--ink-muted);
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: var(--radius-full);
|
||
cursor: pointer;
|
||
}
|
||
.tabs__tab[aria-selected="true"] { color: var(--ink); background: var(--surface-active); }
|
||
|
||
.files { display: grid; align-content: start; }
|
||
.files__pane { display: grid; gap: var(--sp-2); background: var(--surface); border: var(--border-w) solid var(--border); border-radius: var(--radius-soft); padding: var(--sp-3); min-width: 0; }
|
||
.files__head { display: grid; grid-template-columns: minmax(0, 1fr) var(--control-h-sm); gap: var(--sp-2); align-items: center; }
|
||
.files__where { min-width: 0; }
|
||
.files__where select { width: 100%; height: var(--control-h-sm); }
|
||
.files__tree { min-height: 0; }
|
||
.pane__path { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; direction: rtl; text-align: left; font: var(--text-xs) var(--font-ui); color: var(--ink-muted); }
|
||
.pane__pick { width: 100%; }
|
||
.pane__note { padding: var(--sp-2) 0; font-size: var(--text-sm); color: var(--ink-muted); }
|
||
.files__tree > .btn { justify-self: start; }
|
||
|
||
.tree, .tree ul { list-style: none; margin: 0; padding: 0; }
|
||
.tree__row {
|
||
width: 100%;
|
||
height: var(--control-h-sm);
|
||
display: grid;
|
||
grid-template-columns: calc(var(--depth, 0) * var(--sp-4)) 1rem 1rem minmax(0, 1fr) auto;
|
||
gap: var(--sp-2);
|
||
align-items: center;
|
||
padding: 0 var(--sp-2);
|
||
text-align: left;
|
||
font: var(--text-sm) var(--font-body);
|
||
color: var(--ink);
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: var(--radius-lg);
|
||
cursor: pointer;
|
||
}
|
||
/* The indent's track needs an item of its own, or the chevron would sit in it. */
|
||
.tree__row::before { content: ""; }
|
||
.tree__row:hover { background: var(--surface-hover); }
|
||
.tree__row .icon { color: var(--ink-muted); }
|
||
.tree__chevron { display: grid; place-items: center; width: 1rem; }
|
||
.tree__chevron .icon { width: 12px; height: 12px; transition: transform var(--dur-1) var(--ease-out); }
|
||
.tree__row[aria-expanded="true"] .tree__chevron .icon { transform: rotate(90deg); }
|
||
.tree__name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.tree__size { font: var(--text-xs) var(--font-ui); color: var(--ink-faint); }
|
||
.tree__note { padding: var(--sp-1) var(--sp-3); font-size: var(--text-xs); color: var(--ink-muted); }
|
||
|
||
/* An empty page: an icon, a heading, a sentence, centred. */
|
||
.empty { display: grid; justify-items: center; gap: var(--sp-3); padding: var(--sp-12) var(--sp-4) var(--sp-4); text-align: center; }
|
||
.empty__icon { display: grid; place-items: center; width: var(--sp-12); height: var(--sp-12); color: var(--leaf); background: var(--leaf-soft); border-radius: var(--radius-full); }
|
||
.empty__icon .icon { width: 24px; height: 24px; }
|
||
.empty__title { font: 600 var(--text-lg) / var(--leading-tight) var(--font-body); }
|
||
.empty__text { max-width: var(--w-prose-sm); color: var(--ink-muted); font-size: var(--text-sm); }
|
||
.empty__actions { display: flex; justify-content: center; }
|
||
|
||
/* Scheduled: the list. One row per task on fixed tracks -- icon, title over its rule, the next
|
||
run, the last run's status, and the pause switch outside the row's button. */
|
||
.tasks-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
|
||
.task { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; background: var(--surface); border: var(--border-w) solid var(--border); border-radius: var(--radius-soft); }
|
||
.task:hover { border-color: var(--border-strong); }
|
||
.task.is-paused .task__title, .task.is-paused .task__icon { color: var(--ink-faint); }
|
||
.task__open {
|
||
display: grid;
|
||
grid-template-columns: var(--sp-8) minmax(0, 1fr) var(--w-field-sm) var(--w-field-sm);
|
||
gap: var(--sp-3);
|
||
align-items: center;
|
||
min-height: calc(2 * var(--control-h));
|
||
padding: var(--sp-2) var(--sp-3);
|
||
text-align: left;
|
||
font: inherit;
|
||
color: inherit;
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: var(--radius-soft) 0 0 var(--radius-soft);
|
||
cursor: pointer;
|
||
}
|
||
.task__icon { display: grid; place-items: center; width: var(--sp-8); height: var(--sp-8); color: var(--leaf); background: var(--leaf-soft); border-radius: var(--radius-full); }
|
||
.task__what, .task__next { display: grid; min-width: 0; }
|
||
.task__title { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-weight: 600; }
|
||
.task__rule, .task__value { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: var(--text-sm); color: var(--ink-muted); }
|
||
.task__label { font: var(--text-xs) var(--font-ui); color: var(--ink-faint); }
|
||
.task__toggle { padding: 0 var(--sp-4); height: auto; }
|
||
|
||
/* A run's status: a small chip coloured by what happened. */
|
||
.schip { display: inline-block; max-width: 100%; padding: 0 var(--sp-2); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--text-xs) / 1.8 var(--font-ui); color: var(--ink-muted); background: var(--surface-active); border-radius: var(--radius-full); }
|
||
.schip.is-ok { color: var(--success); background: var(--success-soft); }
|
||
.schip.is-failed, .schip.is-missed, .schip.is-skipped { color: var(--warning); background: var(--warning-soft); }
|
||
.schip.is-running, .schip.is-waiting { color: var(--accent); background: var(--accent-soft); }
|
||
|
||
/* A task's page: the facts on a grid of label and value, what it does, the next runs, history. */
|
||
.sched { display: grid; gap: var(--sp-6); }
|
||
.sched__h { font: 600 var(--text-xs) / var(--leading-tight) var(--font-ui); letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: var(--sp-2); }
|
||
.sched__facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--w-field)), 1fr)); gap: var(--sp-3) var(--sp-4); }
|
||
.fact { display: grid; gap: var(--sp-1); align-content: start; min-width: 0; }
|
||
.fact__label { font: var(--text-xs) var(--font-ui); color: var(--ink-faint); }
|
||
.fact__value { min-width: 0; overflow-wrap: anywhere; font-size: var(--text-sm); }
|
||
.fact__value select { width: 100%; }
|
||
.sched__model { display: inline-grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-2); align-items: center; }
|
||
.sched__instruction { white-space: pre-wrap; overflow-wrap: anywhere; padding: var(--sp-3) var(--sp-4); background: var(--surface); border: var(--border-w) solid var(--border); border-radius: var(--radius-soft); }
|
||
.sched__asked { margin-top: var(--sp-2); font-size: var(--text-sm); color: var(--ink-muted); }
|
||
.runs-next { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--sp-1); counter-reset: next; }
|
||
.runs-next li { display: grid; grid-template-columns: var(--sp-6) minmax(0, 1fr) auto; gap: var(--sp-2); align-items: center; min-height: var(--control-h-sm); font-size: var(--text-sm); counter-increment: next; }
|
||
.runs-next li::before { content: counter(next); font: var(--text-xs) var(--font-ui); color: var(--ink-faint); text-align: right; }
|
||
.sched__history { display: grid; gap: var(--sp-2); }
|
||
.runs { list-style: none; margin: 0; padding: 0; display: grid; }
|
||
.run {
|
||
display: grid;
|
||
grid-template-columns: var(--w-field-sm) minmax(0, 1fr) minmax(0, var(--w-field-sm)) auto;
|
||
gap: var(--sp-3);
|
||
align-items: center;
|
||
min-height: var(--control-h);
|
||
padding: var(--sp-1) 0;
|
||
font-size: var(--text-sm);
|
||
border-bottom: var(--border-w) solid var(--border);
|
||
}
|
||
.run__when { display: flex; gap: var(--sp-2); align-items: center; min-width: 0; }
|
||
.run__late { font: var(--text-xs) var(--font-ui); color: var(--warning); }
|
||
.run__model { display: inline-grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-2); align-items: center; min-width: 0; color: var(--ink-muted); }
|
||
.run__model > span:last-child { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||
.run__error { max-width: var(--w-field); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--warning); font-size: var(--text-xs); }
|
||
.sched--new { gap: var(--sp-3); }
|
||
.sched__words { width: 100%; font-size: var(--text-base); border-radius: var(--radius-soft); padding: var(--sp-3) var(--sp-4); }
|
||
.sched__preview { margin-top: var(--sp-3); }
|
||
.sched__card { display: grid; gap: var(--sp-4); padding: var(--sp-4); background: var(--surface); border: var(--border-w) solid var(--border); border-radius: var(--radius-soft); }
|
||
.sched__title { font: 600 var(--text-md) / var(--leading-tight) var(--font-body); }
|
||
/* A page's way back, before its title: "Scheduled ›". */
|
||
.crumb { display: inline-flex; gap: var(--sp-1); align-items: center; padding: 0; font: inherit; color: var(--ink-muted); background: none; border: 0; cursor: pointer; }
|
||
.crumb:hover { color: var(--ink); }
|
||
.crumb__sep { margin: 0 var(--sp-2); color: var(--ink-faint); font-weight: 400; }
|
||
|
||
/* --- Settings -------------------------------------------------------------------------------
|
||
The groups listed on the left, the groups themselves on the right, each a card of lines: words
|
||
(a label over a hint) on one track, the control on the other. */
|
||
|
||
.settings__layout { min-height: 0; display: grid; grid-template-columns: minmax(var(--w-field-sm), max-content) minmax(0, 1fr); }
|
||
.settings__nav { display: grid; align-content: start; gap: var(--sp-1); padding: var(--sp-6) var(--sp-2) var(--sp-4) var(--sp-4); }
|
||
.settings__body { overflow: auto; min-height: 0; padding: var(--sp-6) var(--sp-4) var(--sp-12); display: grid; gap: var(--sp-8); align-content: start; }
|
||
.set { width: 100%; max-width: var(--w-prose); display: grid; gap: var(--sp-3); scroll-margin-top: var(--sp-6); }
|
||
.set__title { font: 600 var(--text-lg) / var(--leading-tight) var(--font-body); }
|
||
.set__card { display: grid; gap: var(--sp-3); padding: var(--sp-4); background: var(--surface); border: var(--border-w) solid var(--border); border-radius: var(--radius-soft); }
|
||
.set__intro { font-size: var(--text-sm); color: var(--ink-muted); }
|
||
.set__line { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-4); align-items: center; padding-top: var(--sp-3); border-top: var(--border-w) solid var(--border); }
|
||
.set__card > .set__line:first-child { padding-top: 0; border-top: 0; }
|
||
.set__words { display: grid; gap: var(--sp-1); min-width: 0; }
|
||
.set__label { font-size: var(--text-sm); font-weight: 600; overflow-wrap: anywhere; }
|
||
.set__hint { font-size: var(--text-xs); color: var(--ink-muted); }
|
||
.set__hint:empty { display: none; }
|
||
.set__control { display: grid; justify-items: end; min-width: 0; max-width: var(--w-chip); }
|
||
.set__control select { max-width: 100%; }
|
||
.set__value { font: var(--text-sm) var(--font-ui); color: var(--ink-muted); overflow-wrap: anywhere; }
|
||
.set__buttons { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
|
||
.set .agentbox { background: var(--bg); }
|
||
.set .agentbox.is-warn { background: var(--warning-soft); }
|
||
/* A switch: a checkbox drawn as one, the label its tap target. */
|
||
.toggle:not(:has(.toggle__label)) { grid-template-columns: calc(2 * var(--check-size)); height: var(--control-h-sm); }
|
||
|
||
/* The folder list: every row the same three tracks, the path cut from the left (its end tells
|
||
folders apart), the full path in the title. */
|
||
.folders { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
|
||
.folders li {
|
||
display: grid;
|
||
grid-template-columns: 16px minmax(0, 1fr) auto;
|
||
gap: var(--sp-3);
|
||
align-items: center;
|
||
min-height: var(--control-h);
|
||
padding: var(--sp-1) var(--sp-1) var(--sp-1) var(--sp-3);
|
||
background: var(--bg);
|
||
border: var(--border-w) solid var(--border);
|
||
border-radius: var(--radius-lg);
|
||
}
|
||
.folders__icon { display: grid; color: var(--leaf); }
|
||
.folders .path { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; direction: rtl; text-align: left; font: var(--text-sm) var(--font-ui); }
|
||
.folders .empty { display: block; padding: var(--sp-3); color: var(--warning); font-size: var(--text-sm); text-align: left; }
|
||
|
||
/* --- Narrower windows ---------------------------------------------------------------------- */
|
||
|
||
/* 64rem (--bp-wide): a panel goes over the chat instead of beside it. */
|
||
@media (max-width: 64rem) {
|
||
.shell[data-viewer="true"], .shell[data-activity="true"] { --panel-col: 0px; }
|
||
.viewer, .activity, .shell[data-activity="true"] .viewer { grid-area: main; z-index: var(--z-panel); border-left: 0; }
|
||
.task__open { grid-template-columns: var(--sp-8) minmax(0, 1fr) var(--w-field-sm); }
|
||
.task__next { display: none; }
|
||
}
|
||
|
||
/* The chat's header and chips by the chat's own width, not the window's. */
|
||
.main { container: chat / inline-size; }
|
||
@container chat (max-width: 40rem) {
|
||
.head { grid-template-columns: minmax(0, 1fr) auto; }
|
||
.head__place { grid-column: 1 / -1; grid-row: 2; }
|
||
.head__place:empty { display: none; }
|
||
.cchip { max-width: var(--w-field-xs); }
|
||
}
|
||
|
||
/* 48rem (--bp-narrow): the sidebar is a drawer over the page, opened from the title bar. */
|
||
@media (max-width: 48rem) {
|
||
.shell, .shell[data-side="false"] { --side-col: 0px; }
|
||
.bar__host { display: none; }
|
||
.side {
|
||
position: absolute;
|
||
inset: 0 auto 0 0;
|
||
width: min(85vw, var(--side-w));
|
||
z-index: var(--z-panel);
|
||
transform: translateX(-100%);
|
||
transition: transform var(--dur-2) var(--ease-out);
|
||
box-shadow: var(--shadow-lg);
|
||
visibility: visible;
|
||
}
|
||
.shell[data-side="false"] .side { visibility: hidden; }
|
||
.shell[data-side="true"] .side { transform: none; visibility: visible; }
|
||
.side__top, .side__nav, .list, .side__foot { width: auto; }
|
||
.shell[data-side="true"] .scrim { display: block; position: absolute; inset: 0; z-index: calc(var(--z-panel) - 1); background: var(--scrim); }
|
||
.thread { padding: var(--sp-4) var(--sp-3) var(--sp-3); }
|
||
.dock { padding: 0 var(--sp-3) var(--sp-3); }
|
||
.page__body { padding: var(--sp-4) var(--sp-3); }
|
||
.card { padding: var(--sp-4); gap: var(--sp-4); }
|
||
.hello__title { font-size: var(--text-xl); }
|
||
.settings__layout { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); }
|
||
.settings__nav { grid-auto-flow: column; grid-auto-columns: max-content; overflow-x: auto; padding: var(--sp-2) var(--sp-3); border-bottom: var(--border-w) solid var(--border); }
|
||
.settings__body { padding: var(--sp-4) var(--sp-3) var(--sp-8); }
|
||
.set__line { grid-template-columns: minmax(0, 1fr); }
|
||
.set__control { justify-items: start; }
|
||
.run { grid-template-columns: minmax(0, 1fr) auto; }
|
||
.run__model { display: none; }
|
||
.run__status { grid-row: 1; }
|
||
.palette__hint { display: none; }
|
||
.palette__item { grid-template-columns: 1rem minmax(0, 1fr); }
|
||
.kbd { display: none; }
|
||
.side__new { grid-template-columns: 16px minmax(0, 1fr); }
|
||
}
|
||
|
||
/* Very narrow: the agent's words go, its dot stays; the row's button goes under its field. */
|
||
@media (max-width: 30rem) {
|
||
.bar__agent-text { display: none; }
|
||
.bar > .bar__agent { grid-template-columns: var(--dot-size); }
|
||
.setup .row { grid-template-columns: minmax(0, 1fr); }
|
||
.setup .field { grid-template-rows: auto auto auto; }
|
||
.task__open { grid-template-columns: var(--sp-8) minmax(0, 1fr); }
|
||
.task__last { display: none; }
|
||
}
|