Files
kanban/public/styles.css
Gahow Wang e5d9799018 feat(ui): GPU + Live Agents dashboard, dark theme
- drop quota / repos / headless-task panels; page is now GPU board +
  Live Agents (frontend only, headless task API still available)
- Live Agents: grouped by tmux session, launch form (engine/session/cwd/
  window name), open-terminal link per agent
- compact GPU board: multi-column host cards, fixed 4-per-row GPU thumbs
  with status glow, expanded host spans full row
- permanent dark theme tuned for a monitoring dashboard; terminal-styled
  session group headers; refresh now polls three light endpoints instead
  of the full dashboard aggregate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 21:20:52 +08:00

1370 lines
29 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

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

:root {
color-scheme: dark;
--bg: #0a0e1a;
--bg-elev: #111827;
--panel: #101626;
--panel-soft: #151d31;
--ink: #e5eaf3;
--ink-soft: #c3cbdc;
--muted: #8b96ad;
--line: #1f2940;
--line-strong: #2c3854;
--accent: #7c8cf8;
--accent-strong: #a0adfc;
--accent-soft: rgba(124, 140, 248, 0.13);
--accent-ink: #c7d2fe;
--good: #34d399;
--good-soft: rgba(52, 211, 153, 0.14);
--warn: #fbbf24;
--warn-soft: rgba(251, 191, 36, 0.14);
--bad: #f87171;
--bad-soft: rgba(248, 113, 113, 0.14);
--chip: #1c2540;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 6px 24px rgba(0, 0, 0, 0.35);
--shadow-lg: 0 16px 50px rgba(0, 0, 0, 0.45);
--radius: 14px;
--radius-sm: 10px;
--radius-pill: 999px;
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }
html, body { height: 100%; }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font: 14px/1.5 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
min-height: 100vh;
position: relative;
overflow-x: hidden;
}
.bg-glow {
position: fixed;
inset: -10% -10% auto -10%;
height: 70vh;
pointer-events: none;
background:
radial-gradient(45% 65% at 12% 15%, rgba(99, 102, 241, 0.14), transparent 70%),
radial-gradient(38% 55% at 88% 8%, rgba(16, 185, 129, 0.10), transparent 70%),
radial-gradient(55% 65% at 50% 0%, rgba(56, 189, 248, 0.07), transparent 70%);
filter: blur(10px);
z-index: 0;
}
button, input, select, textarea {
font: inherit;
color: inherit;
}
button { cursor: pointer; }
.shell {
position: relative;
z-index: 1;
width: min(1440px, calc(100vw - 32px));
margin: 0 auto;
padding: 24px 0 24px;
}
h1, h2, h3, p { margin: 0; }
h1 {
font-size: 24px;
font-weight: 700;
letter-spacing: -0.01em;
line-height: 1.15;
}
h2 {
font-size: 14px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--muted);
}
h3 {
font-size: 13px;
font-weight: 600;
color: var(--ink-soft);
letter-spacing: 0.02em;
text-transform: uppercase;
}
.muted { color: var(--muted); }
/* Topbar */
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 22px;
}
.brand {
display: flex;
align-items: center;
gap: 14px;
}
.brand-mark {
width: 44px;
height: 44px;
border-radius: 12px;
display: grid;
place-items: center;
font-weight: 700;
font-size: 14px;
letter-spacing: 0.06em;
color: #fff;
background: linear-gradient(135deg, #6366f1, #8b5cf6 55%, #06b6d4);
box-shadow: 0 6px 18px rgba(99, 102, 241, 0.35);
}
.top-actions {
display: flex;
gap: 8px;
align-items: center;
}
.icon-button {
width: 40px;
height: 40px;
border-radius: 12px;
border: 1px solid var(--line);
background: var(--bg-elev);
color: var(--ink-soft);
display: grid;
place-items: center;
transition: transform 120ms ease, border-color 120ms ease, color 120ms ease, box-shadow 120ms ease;
box-shadow: var(--shadow-sm);
}
.icon-button svg { width: 18px; height: 18px; }
.icon-button:hover {
color: var(--accent);
border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
box-shadow: 0 6px 20px color-mix(in srgb, var(--accent) 22%, transparent);
}
.icon-button:active { transform: translateY(1px); }
.icon-button:disabled { opacity: 0.6; cursor: progress; }
.icon-button.loading svg { animation: spin 700ms linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.ghost-button {
height: 40px;
padding: 0 14px;
border-radius: 12px;
border: 1px solid var(--line);
background: var(--bg-elev);
color: var(--ink-soft);
transition: border-color 120ms ease, color 120ms ease, background 120ms ease;
box-shadow: var(--shadow-sm);
}
.ghost-button:hover {
color: var(--accent);
border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}
/* Grid layout */
.grid {
display: grid;
gap: 18px;
}
.dashboard-grid {
grid-template-columns: minmax(0, 2fr) minmax(340px, 1fr);
margin-bottom: 18px;
}
.work-grid {
grid-template-columns: minmax(260px, 1fr) minmax(0, 2.4fr);
align-items: start;
}
/* Panels */
.panel {
background: linear-gradient(180deg, color-mix(in srgb, var(--panel) 92%, #2a3554), var(--panel) 120px);
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 18px 18px 20px;
min-width: 0;
box-shadow: var(--shadow-md);
}
.panel + .panel { margin-top: 18px; }
.panel-heading {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 16px;
}
.panel-title {
display: flex;
align-items: center;
gap: 10px;
}
.badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
border-radius: var(--radius-pill);
background: var(--accent-soft);
color: var(--accent-ink);
font-size: 12px;
font-weight: 600;
letter-spacing: 0.01em;
}
/* Error banner */
.error-banner {
margin-bottom: 16px;
padding: 12px 14px;
border-radius: var(--radius-sm);
border: 1px solid color-mix(in srgb, var(--bad) 35%, transparent);
background: var(--bad-soft);
color: var(--bad);
font-size: 13px;
}
.error-banner ul { margin: 4px 0 0; padding-left: 20px; }
.error-banner li { line-height: 1.5; }
/* GPU board */
.gpu-board,
.quota-board,
.repo-board,
.task-board { display: grid; gap: 12px; }
.host-card,
.quota-card,
.repo-card,
.task-card {
border: 1px solid var(--line);
border-radius: var(--radius-sm);
padding: 14px;
background: var(--panel);
min-width: 0;
transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}
.host-card:hover,
.quota-card:hover { border-color: var(--line-strong); }
.host-title,
.repo-title {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 8px;
font-weight: 600;
}
.host-summary {
width: 100%;
display: grid;
grid-template-columns: minmax(160px, 1fr) minmax(120px, 2fr) auto;
align-items: center;
gap: 14px;
border: 0;
background: transparent;
color: var(--ink);
padding: 0;
text-align: left;
}
.host-summary > span:first-child {
display: grid;
gap: 3px;
}
.host-summary strong { font-weight: 650; }
.gpu-thumbs {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 4px;
}
.gpu-thumb {
height: 16px;
border-radius: 5px;
background: var(--chip);
border: 1px solid var(--line);
}
.gpu-thumb.idle {
background: color-mix(in srgb, var(--good) 22%, transparent);
border-color: color-mix(in srgb, var(--good) 45%, transparent);
}
.gpu-thumb.abnormal {
background: color-mix(in srgb, var(--warn) 22%, transparent);
border-color: color-mix(in srgb, var(--warn) 50%, transparent);
}
.gpu-thumb.busy {
background: color-mix(in srgb, var(--bad) 22%, transparent);
border-color: color-mix(in srgb, var(--bad) 50%, transparent);
}
.gpu-list { display: grid; gap: 10px; margin-top: 14px; }
.gpu-detail-card {
border: 1px solid var(--line);
border-radius: var(--radius-sm);
padding: 12px;
background: var(--panel-soft);
}
.metric-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-top: 6px;
font-size: 13px;
}
.metric-row strong { font-weight: 650; color: var(--ink); }
/* Meters */
.meter {
display: block;
width: 100%;
height: 8px;
appearance: none;
border: 0;
background: transparent;
margin-top: 4px;
}
.meter::-webkit-meter-bar {
height: 8px;
border: 0;
border-radius: var(--radius-pill);
background: var(--chip);
}
.meter::-webkit-meter-optimum-value {
border-radius: var(--radius-pill);
background: linear-gradient(90deg, var(--good), color-mix(in srgb, var(--good) 65%, var(--accent)));
}
.meter::-webkit-meter-suboptimum-value {
border-radius: var(--radius-pill);
background: linear-gradient(90deg, var(--warn), #f59e0b);
}
.meter::-webkit-meter-even-less-good-value {
border-radius: var(--radius-pill);
background: linear-gradient(90deg, var(--bad), #f87171);
}
.meter::-moz-meter-bar {
border-radius: var(--radius-pill);
background: linear-gradient(90deg, var(--good), color-mix(in srgb, var(--good) 65%, var(--accent)));
}
/* Status text */
.status-ok { color: var(--good); font-weight: 600; }
.status-warn { color: var(--warn); font-weight: 600; }
.status-bad { color: var(--bad); font-weight: 600; }
/* Chip */
.chip {
display: inline-flex;
align-items: center;
min-height: 22px;
padding: 2px 9px;
border-radius: var(--radius-pill);
background: var(--chip);
color: var(--muted);
font-size: 12px;
font-weight: 500;
white-space: nowrap;
}
/* Repos */
.project-panel {
position: sticky;
top: 16px;
max-height: calc(100vh - 32px);
display: flex;
flex-direction: column;
}
.project-panel > .panel-heading { flex: 0 0 auto; }
.project-panel .repo-board {
grid-template-columns: 1fr;
flex: 0 1 auto;
min-height: 0;
overflow: auto;
padding: 2px 6px 2px 2px;
scroll-padding-block: 4px;
}
.project-panel .repo-card {
display: grid;
gap: 6px;
padding: 12px 14px;
cursor: pointer;
}
.project-panel .repo-title { margin-bottom: 0; }
.repo-card.selected {
border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.repo-card:hover { border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); }
.repo-meta,
.task-meta {
color: var(--muted);
font-size: 12px;
overflow-wrap: anywhere;
}
/* Task form */
.task-form {
display: grid;
gap: 14px;
margin-bottom: 18px;
padding-bottom: 18px;
border-bottom: 1px solid var(--line);
}
.task-form label,
.inline-form label {
display: grid;
gap: 6px;
}
.field-label {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.02em;
color: var(--muted);
}
.task-controls {
display: grid;
grid-template-columns: repeat(3, minmax(160px, 1fr));
gap: 12px;
align-items: end;
}
.agent-context {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 14px;
margin-bottom: 14px;
border: 1px solid var(--line);
border-radius: var(--radius-sm);
background: linear-gradient(180deg, var(--accent-soft), transparent);
}
.agent-context-label {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--muted);
}
.agent-context-repo {
font-weight: 650;
color: var(--ink);
overflow-wrap: anywhere;
}
.agent-context-repo.empty { color: var(--muted); font-weight: 500; }
.prompt-field { max-width: 980px; }
.inline-form {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: end;
gap: 12px;
margin-bottom: 14px;
}
.gpu-hosts-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
margin-bottom: 14px;
}
.gpu-hosts-chips {
display: contents;
}
.host-chip {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 0 4px 0 10px;
height: 26px;
border-radius: var(--radius-pill);
background: var(--chip);
color: var(--ink-soft);
font-size: 12px;
font-weight: 500;
line-height: 1;
transition: background 120ms ease;
}
.host-chip:hover {
background: color-mix(in srgb, var(--ink) 6%, var(--chip));
}
.host-chip-dot {
width: 7px;
height: 7px;
border-radius: 999px;
background: var(--muted);
flex: 0 0 auto;
}
.host-chip.ok .host-chip-dot {
background: var(--good);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--good) 22%, transparent);
}
.host-chip.bad .host-chip-dot {
background: var(--bad);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--bad) 22%, transparent);
}
.host-chip-label {
white-space: nowrap;
display: inline-flex;
align-items: center;
height: 100%;
}
.host-chip-remove {
display: inline-flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
border-radius: 999px;
border: 0;
background: transparent;
color: var(--muted);
padding: 0;
flex: 0 0 auto;
transition: color 120ms ease, background 120ms ease;
}
.host-chip-remove svg {
width: 10px;
height: 10px;
display: block;
}
.host-chip-remove:hover {
color: var(--bad);
background: color-mix(in srgb, var(--bad) 18%, transparent);
}
.host-chip-empty {
color: var(--muted);
font-size: 13px;
}
.host-add-button {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 0 12px;
height: 26px;
border-radius: var(--radius-pill);
border: 1px dashed var(--line-strong);
background: transparent;
color: var(--muted);
font-size: 12px;
font-weight: 500;
line-height: 1;
transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}
.host-add-button > span:first-child {
font-size: 14px;
line-height: 1;
margin-top: -1px;
}
.host-add-button:hover {
color: var(--accent);
border-color: var(--accent);
background: var(--accent-soft);
}
.host-add-form {
display: inline-flex;
align-items: center;
gap: 6px;
}
.host-add-form input {
width: 160px;
height: 26px;
padding: 0 10px;
font-size: 12px;
line-height: 1;
}
.host-add-form .primary-button.small,
.host-add-form .secondary-button.small {
height: 26px;
padding: 0 12px;
line-height: 1;
}
.link-button {
border: 0;
background: transparent;
color: var(--muted);
font-size: 12px;
padding: 4px 8px;
border-radius: 6px;
transition: color 120ms ease, background 120ms ease;
}
.link-button:hover {
color: var(--accent);
background: var(--accent-soft);
}
.primary-button.small,
.secondary-button.small {
padding: 6px 10px;
font-size: 12px;
}
select, input, textarea {
width: 100%;
border: 1px solid var(--line);
border-radius: var(--radius-sm);
background: var(--bg-elev);
color: var(--ink);
padding: 10px 12px;
transition: border-color 120ms ease, box-shadow 120ms ease, background 120ms ease;
}
select:hover, input:hover, textarea:hover { border-color: var(--line-strong); }
select:focus, input:focus, textarea:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
select {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
padding-right: 36px;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%2394a3b8' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'><path d='M3 4.75l3 3 3-3'/></svg>");
background-repeat: no-repeat;
background-position: right 12px center;
background-size: 14px;
cursor: pointer;
text-overflow: ellipsis;
}
select::-ms-expand { display: none; }
select:disabled {
opacity: 0.6;
cursor: not-allowed;
}
select option {
background: var(--bg-elev);
color: var(--ink);
}
.select-field { position: relative; }
textarea {
resize: vertical;
min-height: 120px;
line-height: 1.55;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-size: 13px;
}
/* Buttons */
.primary-button,
.secondary-button {
border-radius: var(--radius-sm);
padding: 10px 16px;
font-weight: 600;
border: 1px solid transparent;
transition: transform 120ms ease, box-shadow 120ms ease, background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.primary-button {
background: linear-gradient(180deg, var(--accent), var(--accent-strong));
color: #fff;
box-shadow: 0 6px 14px color-mix(in srgb, var(--accent) 35%, transparent);
}
.primary-button:hover {
transform: translateY(-1px);
box-shadow: 0 10px 24px color-mix(in srgb, var(--accent) 40%, transparent);
}
.primary-button:active { transform: translateY(0); }
.primary-button:disabled,
.secondary-button:disabled {
opacity: 0.55;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.secondary-button {
background: var(--bg-elev);
color: var(--ink-soft);
border-color: var(--line);
}
.secondary-button:hover {
color: var(--accent);
border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}
.secondary-button.small { padding: 6px 10px; font-size: 12px; }
.inline-form button { justify-self: start; }
.form-actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
/* Task cards */
.task-board, .task-section, .task-list { display: grid; gap: 12px; }
.task-section-heading {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.task-card { padding: 14px 16px; }
article.task-card { display: grid; gap: 10px; }
details.task-card {
display: block;
padding: 0;
overflow: hidden;
}
details.task-card > summary {
list-style: none;
cursor: pointer;
padding: 12px 14px;
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto auto auto;
align-items: center;
gap: 12px;
min-width: 0;
}
details.task-card > summary::-webkit-details-marker { display: none; }
details.task-card > summary::marker { display: none; }
details.task-card[open] > summary {
border-bottom: 1px solid var(--line);
}
details.task-card > .task-body {
display: grid;
gap: 10px;
padding: 14px 16px;
}
.task-summary-main {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
flex: 1 1 auto;
}
.task-summary-title {
font-weight: 600;
font-size: 13px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.task-summary-prompt {
font-size: 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.task-summary-resume {
display: inline-flex;
align-items: center;
justify-content: flex-end;
min-width: 88px;
}
.task-summary-meta {
display: grid;
grid-template-columns: 92px 60px;
align-items: center;
column-gap: 10px;
font-size: 12px;
white-space: nowrap;
text-align: right;
}
.task-summary-duration { text-align: right; }
.task-summary-chevron {
width: 14px;
color: var(--muted);
font-size: 18px;
line-height: 1;
text-align: center;
transition: transform 120ms ease;
}
details.task-card[open] > summary .task-summary-chevron {
transform: rotate(90deg);
}
.active-task {
border-color: color-mix(in srgb, var(--accent) 50%, var(--line));
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 14%, transparent), var(--shadow-sm);
}
.history-task { background: var(--panel-soft); }
.history-task:hover { border-color: var(--line-strong); }
@media (max-width: 720px) {
details.task-card > summary {
grid-template-columns: auto minmax(0, 1fr) auto;
}
.task-summary-meta { display: none; }
.task-summary-resume { display: none; }
}
.task-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.task-head strong { font-weight: 650; font-size: 14px; }
.task-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
flex-wrap: wrap;
}
.task-facts {
display: flex;
flex-wrap: wrap;
gap: 6px;
color: var(--muted);
font-size: 12px;
}
.task-facts span {
min-height: 22px;
display: inline-flex;
align-items: center;
padding: 2px 9px;
border: 1px solid var(--line);
border-radius: var(--radius-pill);
background: var(--bg-elev);
}
.session-id { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; }
.workspace-path {
font-size: 12px;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
color: var(--muted);
}
.task-prompt {
color: var(--ink);
overflow-wrap: anywhere;
font-size: 13px;
line-height: 1.55;
padding: 10px 12px;
background: var(--panel-soft);
border: 1px solid var(--line);
border-radius: var(--radius-sm);
}
/* Status pill colors */
.status-chip {
padding: 3px 10px;
font-weight: 600;
letter-spacing: 0.02em;
}
.status-running .status-chip {
background: var(--accent-soft);
color: var(--accent-ink);
}
.status-completed .status-chip {
background: var(--good-soft);
color: var(--good);
}
.status-failed .status-chip {
background: var(--bad-soft);
color: var(--bad);
}
.status-running .status-chip::before,
.status-completed .status-chip::before,
.status-failed .status-chip::before {
content: "";
display: inline-block;
width: 6px;
height: 6px;
border-radius: 999px;
margin-right: 6px;
background: currentColor;
}
.status-running .status-chip::before {
animation: pulse 1.6s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.6); opacity: 0.4; }
}
/* Empty state */
.empty-state {
border: 1px dashed var(--line-strong);
border-radius: var(--radius-sm);
padding: 28px 20px;
color: var(--muted);
text-align: center;
background: var(--panel-soft);
}
/* Terminal */
.terminal {
margin: 10px 0 0;
border: 1px solid #1f2940;
border-radius: var(--radius-sm);
background: #0b1020;
overflow: hidden;
min-width: 0;
}
.terminal.stderr { border-color: #5b2b2b; }
.terminal-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 8px 12px;
border-bottom: 1px solid #1f2940;
background: linear-gradient(180deg, #131a2e, #0f1426);
color: #9ca3af;
font: 11px/1.3 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.terminal > summary.terminal-head { cursor: pointer; list-style: none; }
.terminal > summary.terminal-head::-webkit-details-marker { display: none; }
.terminal > summary.terminal-head::after {
content: "▸";
margin-left: 8px;
transition: transform 120ms ease;
}
.terminal[open] > summary.terminal-head::after { transform: rotate(90deg); }
.terminal.stderr .terminal-head {
border-bottom-color: #5b2b2b;
background: linear-gradient(180deg, #25131b, #1a0e14);
color: #fca5a5;
}
.terminal-body {
display: block;
width: 100%;
max-height: min(52vh, 520px);
margin: 0;
overflow: auto;
padding: 12px 14px;
background: #0b1020;
color: #e5e7eb;
font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
white-space: pre-wrap;
overflow-wrap: anywhere;
tab-size: 2;
}
.terminal-body:focus {
outline: 2px solid var(--accent);
outline-offset: -2px;
}
/* Toasts */
.toast-host {
position: fixed;
bottom: 24px;
right: 24px;
display: grid;
gap: 10px;
z-index: 50;
max-width: min(360px, calc(100vw - 32px));
}
.toast {
background: var(--panel);
border: 1px solid var(--line);
border-left: 4px solid var(--accent);
border-radius: var(--radius-sm);
padding: 12px 14px;
box-shadow: var(--shadow-lg);
font-size: 13px;
color: var(--ink-soft);
animation: slideIn 200ms ease;
}
.toast.error { border-left-color: var(--bad); color: var(--bad); }
.toast.success { border-left-color: var(--good); color: var(--good); }
.toast.warn { border-left-color: var(--warn); color: var(--warn); }
@keyframes slideIn {
from { transform: translateY(10px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
/* Login */
.login-shell {
min-height: 100vh;
display: grid;
place-items: center;
padding: 20px;
position: relative;
z-index: 1;
}
.login-panel {
width: min(420px, 100%);
display: grid;
gap: 18px;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 18px;
padding: 28px;
box-shadow: var(--shadow-lg);
}
.login-panel h1 {
font-size: 26px;
background: linear-gradient(135deg, var(--accent), #06b6d4);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.login-panel label {
display: grid;
gap: 6px;
color: var(--muted);
font-size: 13px;
}
.login-panel button {
border: 0;
border-radius: var(--radius-sm);
background: linear-gradient(180deg, var(--accent), var(--accent-strong));
color: #fff;
padding: 12px 14px;
font-weight: 600;
box-shadow: 0 6px 14px color-mix(in srgb, var(--accent) 35%, transparent);
transition: transform 120ms ease, box-shadow 120ms ease;
}
.login-panel button:hover {
transform: translateY(-1px);
box-shadow: 0 12px 28px color-mix(in srgb, var(--accent) 40%, transparent);
}
.login-panel p { min-height: 18px; font-size: 13px; }
/* Responsive */
@media (max-width: 1180px) {
.work-grid { grid-template-columns: 1fr; }
.project-panel {
position: static;
max-height: none;
display: block;
}
.project-panel .repo-board {
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
max-height: 320px;
min-height: 0;
flex: initial;
}
}
@media (max-width: 1024px) {
.task-controls { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 920px) {
.dashboard-grid { grid-template-columns: 1fr; }
.shell { width: min(100vw - 24px, 760px); padding-top: 18px; }
}
@media (max-width: 560px) {
.task-controls { grid-template-columns: 1fr; }
.topbar, .panel-heading, .task-head {
align-items: flex-start;
flex-direction: column;
}
.task-actions { justify-content: flex-start; }
.inline-form { grid-template-columns: 1fr; }
.inline-form button { justify-self: stretch; }
.agent-context { flex-wrap: wrap; }
}
.live-agent-panel { margin-top: 18px; }
/* status-dot glow for GPU thumbs */
.gpu-thumb.idle { box-shadow: 0 0 6px color-mix(in srgb, var(--good) 30%, transparent); }
.gpu-thumb.busy { box-shadow: 0 0 6px color-mix(in srgb, var(--bad) 30%, transparent); }
.gpu-thumb.abnormal { box-shadow: 0 0 6px color-mix(in srgb, var(--warn) 30%, transparent); }
/* Compact GPU board: hosts flow into columns, expanded host spans the row */
.gpu-board {
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 8px;
}
.gpu-board .host-card { padding: 8px 12px; }
.gpu-board .host-card.expanded { grid-column: 1 / -1; }
.gpu-board .host-summary {
grid-template-columns: minmax(110px, auto) minmax(80px, 1fr) auto;
gap: 10px;
}
.gpu-board .host-summary > span:first-child {
display: flex;
align-items: baseline;
gap: 8px;
white-space: nowrap;
}
.gpu-board .gpu-thumb { height: 12px; border-radius: 4px; }
.gpu-board .gpu-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 8px;
margin-top: 10px;
}
.live-agent-form {
display: grid;
grid-template-columns: minmax(110px, 0.6fr) minmax(150px, 0.9fr) minmax(240px, 1.8fr) minmax(150px, 1fr) auto;
gap: 12px;
align-items: end;
margin-bottom: 18px;
padding-bottom: 18px;
border-bottom: 1px solid var(--line);
}
.live-agent-form label {
display: grid;
gap: 6px;
}
.live-agent-form .primary-button { white-space: nowrap; }
.live-agent-board {
display: flex;
flex-direction: column;
gap: 10px;
}
.agent-card {
display: flex;
align-items: center;
gap: 14px;
padding: 12px 16px;
border: 1px solid var(--line);
border-radius: var(--radius-sm);
background: var(--panel-soft);
transition: border-color 120ms ease, box-shadow 120ms ease;
}
.agent-card:hover {
border-color: var(--line-strong);
box-shadow: var(--shadow-sm, 0 2px 8px rgba(0, 0, 0, 0.06));
}
.agent-chip {
display: inline-flex;
align-items: center;
padding: 2px 10px;
height: 24px;
border-radius: var(--radius-pill);
background: var(--chip);
color: var(--ink-soft);
font-size: 12px;
font-weight: 600;
text-transform: capitalize;
flex-shrink: 0;
}
.agent-chip.claude { color: #fbbf24; background: color-mix(in srgb, #f59e0b 14%, var(--chip)); }
.agent-chip.codex { color: #93c5fd; background: color-mix(in srgb, #3b82f6 14%, var(--chip)); }
.agent-card-main {
display: flex;
align-items: baseline;
gap: 8px;
min-width: 0;
flex-shrink: 0;
}
.agent-card-cwd {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-size: 12px;
}
.agent-card .secondary-button {
flex-shrink: 0;
border-color: color-mix(in srgb, var(--accent) 35%, var(--line));
color: var(--accent-ink);
}
.agent-card .secondary-button:hover {
background: var(--accent-soft);
border-color: var(--accent);
color: var(--accent-strong);
}
.agent-group {
border: 1px solid var(--line);
border-radius: var(--radius-sm);
background: var(--panel);
overflow: hidden;
}
.agent-group-heading {
display: flex;
align-items: center;
gap: 8px;
padding: 9px 16px;
background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 7%, var(--panel-soft)), var(--panel-soft));
border-bottom: 1px solid var(--line);
}
.agent-group-heading::before {
content: '';
color: var(--accent);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-weight: 700;
font-size: 12px;
}
.agent-group-heading strong {
font-weight: 650;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
letter-spacing: 0.01em;
}
.agent-group-heading .muted { font-size: 12px; }
.agent-group-list { display: flex; flex-direction: column; }
.agent-group-list .agent-card {
border: 0;
border-radius: 0;
background: transparent;
}
.agent-group-list .agent-card + .agent-card { border-top: 1px solid var(--line); }
.agent-group-list .agent-card:hover {
box-shadow: none;
background: var(--panel-soft);
}
@media (max-width: 1024px) {
.live-agent-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
.live-agent-form { grid-template-columns: 1fr; }
.agent-card { flex-wrap: wrap; }
.agent-card-cwd { flex-basis: 100%; }
}