hyperhive/frontend/packages/dashboard/src/dashboard.css
iris b13a6911b7 feat(#1098): replace deployed:hash chip with config link in three-dot menu
Remove the deployed sha plain-text badge from the card head.
Add a forge-linked menu item to the three-dot menu instead:
'deployed:abc123def012 ↗' opens agent-configs/<name>/commit/<sha>
on the hive forge in a new tab.

Only shown when both c.deployed_sha and forgeBase are present.
buildAgentMenu now takes forgeBase as second arg; call site passes
the same forgeBase computed for nav-strip links.

CSS: add text-decoration: none + box-sizing to .agent-menu-item
so <a> link items render identically to the <button> items.
2026-06-03 01:11:56 +02:00

1522 lines
38 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.

/* Dashboard-specific styles. common.css must be loaded first —
it defines the CSS custom properties, typography, and shared
component rules that this file depends on. */
/* ─── tabbed dashboard chrome ──────────────────────────────────────
Top-of-page sticky header with banner + tab strip. SSE stays
alive across tab switches so count pills update live on inactive
tabs. See docs/web-ui.md::Chrome header + Tab strip for the
routing model. */
body.dashboard-shell {
/* Full-width layout — no max-width cap so wide screens don't
waste real estate on empty side margins. `padding: 0 1.5em
1.5em` keeps a small gutter on the left/right so cards don't
kiss the viewport edge; `.dashboard-chrome { margin: 0 -1.5em
... }` still pulls the chrome bar edge-to-edge through that
gutter. */
margin: 0;
padding: 0 1.5em 1.5em;
}
.dashboard-chrome {
position: sticky;
top: 0;
z-index: 25;
background: rgba(30, 30, 46, 0.86);
-webkit-backdrop-filter: blur(8px) saturate(120%);
backdrop-filter: blur(8px) saturate(120%);
border-bottom: 1px solid var(--purple-dim);
padding: 0.4em 0 0;
margin: 0 -1.5em 1em;
}
.banner-thin {
text-align: center;
margin: 0;
padding: 0 1em;
font-size: 0.78em;
color: var(--purple-dim);
letter-spacing: 0.15em;
white-space: pre;
overflow: hidden;
text-overflow: ellipsis;
}
.tabbar {
display: flex;
flex-wrap: nowrap;
align-items: center;
gap: 0.2em;
padding: 0.5em 1em 0;
border-bottom: 1px solid var(--purple-dim);
}
.tabbar .tab {
display: inline-flex;
align-items: center;
gap: 0.5em;
flex-shrink: 0;
padding: 0.55em 1em 0.45em;
margin-bottom: -1px; /* overlap the tabbar bottom border */
color: var(--muted);
font-family: inherit;
font-size: 0.92em;
letter-spacing: 0.08em;
text-decoration: none;
border: 1px solid transparent;
border-bottom: 0;
border-radius: 4px 4px 0 0;
cursor: pointer;
transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}
.tabbar .tab:hover {
color: var(--purple);
background: rgba(203, 166, 247, 0.06);
}
.tabbar .tab.active {
color: var(--purple);
border-color: var(--purple-dim);
background: var(--bg);
/* Lift the active tab visually — the bottom border of the tabbar
yields under it via the -1px margin above. */
box-shadow: 0 -2px 12px -4px rgba(203, 166, 247, 0.4);
}
.tab-label { font-weight: bold; white-space: nowrap; }
.tab-count {
display: inline-block;
background: var(--purple-dim);
color: var(--purple);
border-radius: 999px;
padding: 0 0.55em;
min-width: 1.6em;
text-align: center;
font-size: 0.82em;
font-variant-numeric: tabular-nums;
font-weight: bold;
}
.tab-count-attn {
/* Y3R C4LL — operator-action-required pill colour, harder to miss. */
background: rgba(243, 139, 168, 0.22);
color: var(--red);
}
/* Overflowed tabs are hidden from the bar (moved to the ⋮ dropdown). */
.tabbar .tab[data-overflow="default"],
.tabbar .tab.tab-overflowed {
display: none;
}
/* ── overflow ⋮ button + dropdown ────────────────────────── */
.tabbar-overflow {
position: relative;
flex-shrink: 0;
margin-left: auto; /* push to the far right */
align-self: stretch;
display: flex;
align-items: center;
}
.tabbar-overflow-btn {
display: flex;
align-items: center;
justify-content: center;
background: none;
border: 1px solid transparent;
border-radius: 4px 4px 0 0;
color: var(--muted);
font-size: 1.2em;
line-height: 1;
padding: 0.3em 0.5em;
cursor: pointer;
transition: color 0.15s, background 0.15s;
white-space: nowrap;
}
.tabbar-overflow-btn:hover {
color: var(--purple);
background: rgba(203, 166, 247, 0.06);
}
.tabbar-overflow-btn.tabbar-overflow-active {
color: var(--purple);
border-color: var(--purple-dim);
}
.tabbar-overflow-dropdown {
position: absolute;
right: 0;
top: calc(100% + 2px);
z-index: 100;
background: var(--bg-elev);
border: 1px solid var(--purple-dim);
border-radius: 6px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
list-style: none;
margin: 0;
padding: 0.3em 0;
min-width: 12em;
white-space: nowrap;
}
.tabbar-overflow-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.6em;
width: 100%;
background: none;
border: none;
color: var(--fg);
font-family: inherit;
font-size: 0.88em;
letter-spacing: 0.05em;
text-align: left;
text-decoration: none;
padding: 0.45em 1em;
cursor: pointer;
}
.tabbar-overflow-item:hover {
background: var(--border);
color: var(--purple);
}
.tabbar-overflow-item-active {
color: var(--purple);
}
.tabbar-overflow-badge {
display: inline-block;
background: var(--purple-dim);
color: var(--purple);
border-radius: 999px;
padding: 0 0.5em;
min-width: 1.4em;
text-align: center;
font-size: 0.82em;
font-variant-numeric: tabular-nums;
font-weight: bold;
}
.tabbar-overflow-badge.tab-count-attn {
background: rgba(243, 139, 168, 0.22);
color: var(--red);
}
/* Tab pane visibility — show only the active one. The .tab-pane-active
class is set by tabs.js based on the URL hash; default (no hash)
resolves to SW4RM. */
.tab-pane { display: none; }
.tab-pane.tab-pane-active { display: block; }
/* FL0W is a separate page (`/flow.html`) — its full-viewport
styling lives in flow.css. */
.banner {
text-align: center;
margin: 0 0 1em 0;
font-size: 0.95em;
overflow-x: auto;
background: linear-gradient(
90deg,
var(--purple-dim) 0%,
var(--purple) 50%,
var(--purple-dim) 100%
);
background-size: 200% 100%;
background-position: 50% 0;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
filter: drop-shadow(0 0 6px rgba(203, 166, 247, 0.45));
}
.banner.active {
animation: banner-shimmer 1.8s linear infinite;
}
@keyframes banner-shimmer {
from { background-position: 200% 0; }
to { background-position: -100% 0; }
}
.role {
display: inline-block;
margin-left: 0.4em;
padding: 0.05em 0.5em;
border: 1px solid;
border-radius: 2px;
font-size: 0.8em;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.role-m1nd { color: var(--pink); border-color: var(--pink); background: rgba(245, 194, 231, 0.08); }
.role-ag3nt { color: var(--amber); border-color: var(--amber); background: rgba(250, 179, 135, 0.08); }
/* Container rows: a full-height square agent icon on the left, the
identity / actions / drill-in lines stacked in the card body on the
right. Pending rows dim everything except the pending indicator. */
.containers { display: flex; flex-direction: column; gap: 0.4em; }
.container-row {
padding: 0.6em 0.8em;
border: 1px solid var(--border);
border-radius: 4px;
background: rgba(24, 24, 37, 0.55);
transition: opacity 200ms ease, border-color 200ms ease;
}
/* Topology indent ladder. See docs/web-ui.md::Topology tree (Indent
+ lane geometry paragraph) for the 1.8em-per-depth-level
rationale + CSS-attr()-not-yet-portable caveat. */
.container-row[data-depth] { position: relative; }
.container-row[data-depth="1"] { margin-left: 1.8em; }
.container-row[data-depth="2"] { margin-left: 3.6em; }
.container-row[data-depth="3"] { margin-left: 5.4em; }
.container-row[data-depth="4"] { margin-left: 7.2em; }
.container-row[data-depth="5"] { margin-left: 9em; }
.container-row[data-depth="6"] { margin-left: 10.8em; }
/* Tree prefix lanes — DOM-painted, not text-glyph-painted. */
.container-row .tree-prefix {
position: absolute;
top: 0;
bottom: -0.4em;
display: flex;
flex-direction: row;
pointer-events: none;
user-select: none;
color: var(--purple-dim);
}
.container-row[data-depth="1"] .tree-prefix { left: -1.8em; }
.container-row[data-depth="2"] .tree-prefix { left: -3.6em; }
.container-row[data-depth="3"] .tree-prefix { left: -5.4em; }
.container-row[data-depth="4"] .tree-prefix { left: -7.2em; }
.container-row[data-depth="5"] .tree-prefix { left: -9em; }
.container-row[data-depth="6"] .tree-prefix { left: -10.8em; }
.tree-prefix .tree-lane {
flex: 0 0 1.8em;
position: relative;
}
.tree-prefix .lane-line::before,
.tree-prefix .lane-joint::before {
content: '';
position: absolute;
left: 0.6em;
top: 0;
bottom: 0;
border-left: 1px solid currentColor;
}
.tree-prefix .lane-joint-last::before {
bottom: auto;
height: 3.1em;
}
.tree-prefix .lane-joint::after {
content: '';
position: absolute;
left: 0.6em;
top: 3.1em;
width: 2em;
border-top: 1px solid currentColor;
}
.container-row:not(.tombstone) {
display: flex;
align-items: flex-start;
gap: 0.7em;
}
.container-row:not(.tombstone) > .container-icon {
position: relative;
overflow: hidden;
flex: none;
width: 5em;
aspect-ratio: 1;
border-radius: 6px;
background-color: rgba(17, 17, 27, 0.6);
cursor: pointer;
transition: box-shadow 120ms ease, transform 120ms ease;
}
.container-row:not(.tombstone) > .container-icon:hover {
box-shadow: 0 0 0 2px var(--purple);
}
.container-row:not(.tombstone) > .container-icon:focus-visible {
outline: 2px solid var(--purple);
outline-offset: 2px;
}
.container-row.selected {
border-color: var(--purple);
box-shadow: inset 0 0 0 1px var(--purple);
background: rgba(203, 166, 247, 0.06);
}
.container-row.selected > .container-icon {
box-shadow: 0 0 0 2px var(--purple), 0 0 12px -4px var(--purple);
}
.container-row:not(.tombstone) > .container-icon > .container-icon-img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: contain;
}
.container-row:not(.tombstone) > .container-icon.icon-unreachable {
filter: grayscale(1);
opacity: 0.4;
}
.container-row .card-body {
flex: 1;
min-width: 0;
}
/* ── per-agent three-dot context menu ─────────────────────────────────────
Positioned after .card-body in the flex row. */
.agent-menu {
flex: none;
position: relative;
align-self: flex-start;
margin-top: 0.3em;
}
.agent-menu-btn {
display: block;
background: none;
border: none;
color: var(--subtext0);
font-size: 1.1em;
line-height: 1;
cursor: pointer;
padding: 0.1em 0.4em;
border-radius: 4px;
opacity: 0;
transition: opacity 120ms, background 120ms, color 120ms;
}
.container-row:hover .agent-menu-btn,
.agent-menu.open .agent-menu-btn {
opacity: 1;
}
.agent-menu-btn:hover,
.agent-menu-btn:focus-visible {
background: rgba(203, 166, 247, 0.1);
color: var(--purple);
outline: none;
}
.agent-menu-btn:focus-visible {
outline: 1px solid var(--purple);
}
.agent-menu-dropdown {
position: absolute;
right: 0;
top: calc(100% + 2px);
z-index: 50;
background: var(--bg-elev);
border: 1px solid var(--purple-dim);
border-radius: 6px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
list-style: none;
margin: 0;
padding: 0.3em 0;
min-width: 10em;
white-space: nowrap;
}
.agent-menu-item {
display: block;
width: 100%;
background: none;
border: none;
color: var(--fg);
font-family: inherit;
font-size: 0.88em;
letter-spacing: 0.04em;
text-align: left;
padding: 0.4em 0.9em;
cursor: pointer;
text-decoration: none;
box-sizing: border-box;
}
.agent-menu-item:hover {
background: var(--border);
color: var(--purple);
}
.agent-menu-sep {
height: 1px;
background: var(--purple-dim);
margin: 0.3em 0;
}
/* Pending state splits queued vs running. */
.container-row.pending .actions { opacity: 0.4; pointer-events: none; }
.container-row.pending-running {
border-color: var(--amber);
background: rgba(250, 179, 135, 0.05);
}
@keyframes container-icon-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.container-row.pending-running > .container-icon {
overflow: visible;
}
.container-row.pending-running > .container-icon::after {
content: '';
position: absolute;
inset: -5px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: var(--amber);
animation: container-icon-spin 0.9s linear infinite;
pointer-events: none;
}
.container-row .head {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.5em;
margin-bottom: 0.4em;
}
.container-row .head .name {
font-size: 1.05em;
font-weight: bold;
}
.container-row .head .meta { margin-left: auto; }
.container-row .head .nav-strip {
display: inline-flex;
align-items: center;
flex-wrap: wrap;
gap: 0.35em;
}
.nav-link {
color: var(--muted);
font-size: 0.95em;
line-height: 1;
padding: 0.15em 0.35em;
border-radius: 3px;
text-decoration: none;
transition: background 0.12s ease, color 0.12s ease;
}
.nav-link:hover {
background: rgba(203, 166, 247, 0.12);
color: var(--cyan);
text-shadow: 0 0 6px rgba(137, 220, 235, 0.5);
}
.container-row .actions {
display: flex;
flex-wrap: wrap;
gap: 0.4em;
}
.container-row .actions form.inline { display: inline-block; margin: 0; }
.agent-status {
font-size: 0.82em;
color: var(--subtext0, #a6adc8);
padding: 0.1em 0.3em 0.25em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.agent-status .status-icon { opacity: 0.65; }
.agent-status .status-age { opacity: 0.5; font-size: 0.9em; margin-left: 0.2em; }
.container-row.tombstone {
border-style: dashed;
background: rgba(24, 24, 37, 0.35);
opacity: 0.85;
}
.container-row.tombstone .name { color: var(--muted); }
/* Per-container journald viewer + applied-config viewer in the side
panel. The panel-body wrapper fills the height with a column flex
so the <pre> can grow into a single scrollable surface. */
.journal-body {
display: flex;
flex-direction: column;
height: 100%;
gap: 0.4em;
}
/* Notification controls — sit between the banner and the containers. */
.port-conflict {
background: rgba(243, 139, 168, 0.08);
border: 1px solid var(--red);
color: var(--red);
padding: 0.5em 0.8em;
margin-bottom: 0.6em;
border-radius: 4px;
text-shadow: 0 0 6px rgba(243, 139, 168, 0.4);
animation: questions-pulse 2.4s ease-in-out infinite;
}
.port-conflict strong { color: var(--red); }
.notif-row {
display: flex;
gap: 0.5em;
align-items: center;
margin: 0.5em 0;
font-size: 0.85em;
}
.btn-notif {
font-family: inherit;
font-size: 0.85em;
background: transparent;
color: var(--cyan);
border: 1px solid var(--cyan);
padding: 0.2em 0.7em;
border-radius: 999px;
cursor: pointer;
text-shadow: 0 0 4px currentColor;
}
.btn-notif:hover {
background: rgba(137, 220, 235, 0.1);
box-shadow: 0 0 10px -2px currentColor;
}
.pending-state {
color: var(--amber);
font-size: 0.85em;
letter-spacing: 0.08em;
text-transform: uppercase;
text-shadow: 0 0 6px rgba(250, 179, 135, 0.55);
animation: badge-pulse 1.6s ease-in-out infinite;
}
@keyframes badge-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
@keyframes questions-pulse {
0%, 100% { box-shadow: 0 0 12px -4px rgba(250, 179, 135, 0.55); }
50% { box-shadow: 0 0 22px -2px rgba(250, 179, 135, 0.95); }
}
/* Pending approval: a card with three stacked sections — identity
header, what-changed body, decision actions. */
.approvals { list-style: none; padding: 0; margin: 0.4em 0 0; }
.approval-card {
background: var(--bg-elev);
border: 1px solid var(--border);
border-left: 3px solid var(--purple);
border-radius: 4px;
padding: 0.6em 0.8em;
margin-bottom: 0.6em;
}
.approval-head {
display: flex;
align-items: baseline;
flex-wrap: wrap;
gap: 0.3em;
}
.approval-ts {
margin-left: auto;
color: var(--muted);
font-size: 0.85em;
}
.approval-ts.stale {
color: var(--amber);
text-shadow: 0 0 6px rgba(250, 179, 135, 0.5);
}
.approval-body {
margin: 0.45em 0;
padding-left: 1.3em;
}
.approval-description {
font-size: 0.9em;
color: var(--fg);
white-space: pre-wrap;
margin-bottom: 0.35em;
}
.approval-actions {
display: flex;
gap: 0.5em;
padding-top: 0.45em;
border-top: 1px solid var(--border);
}
.approval-actions form.inline { display: inline; }
/* Inline drill-in triggers (logs / config repo / view diff). */
.drill-ins {
display: flex;
flex-wrap: wrap;
gap: 0.15em 1.1em;
margin-top: 0.4em;
}
.drill-ins .panel-trigger { margin-top: 0; }
.approval-tabs {
display: flex;
gap: 0.4em;
margin: 0.6em 0 0.4em;
}
.approval-tab {
background: transparent;
border: 1px solid var(--border);
color: var(--muted);
font: inherit;
font-size: 0.85em;
letter-spacing: 0.08em;
padding: 0.25em 0.9em;
cursor: pointer;
transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.approval-tab:hover { color: var(--fg); }
.approval-tab.active {
color: var(--purple);
border-color: var(--purple);
background: rgba(203, 166, 247, 0.08);
text-shadow: 0 0 4px currentColor;
}
.approvals-history .status { font-size: 0.85em; padding: 0 0.5em; }
.status-approved { color: var(--green); }
.status-denied { color: var(--red); }
.status-failed { color: var(--amber); }
.status-cancelled { color: var(--muted); }
.glyph-approved { color: var(--green); }
.glyph-denied { color: var(--red); }
.glyph-failed { color: var(--amber); }
.glyph-cancelled { color: var(--muted); }
.meta-inputs {
list-style: none;
padding: 0;
margin: 0 0 0.8em;
display: grid;
gap: 0.2em;
}
.meta-inputs li {
padding: 0.25em 0.6em;
border: 1px solid var(--border);
background: rgba(24, 24, 37, 0.6);
}
.meta-inputs label {
display: flex;
align-items: baseline;
gap: 0.5em;
cursor: pointer;
font-size: 0.9em;
}
.meta-input-name { color: var(--amber); font-weight: bold; }
.meta-input-rev { color: var(--muted); }
.meta-input-ts { color: var(--muted); font-size: 0.85em; }
.meta-input-url {
color: var(--muted);
font-size: 0.85em;
margin-left: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.meta-inputs-bulk {
margin: 0 0 0.5em;
font-size: 0.8em;
color: var(--muted);
}
.meta-bulk-btn {
font: inherit;
font-size: 1em;
background: transparent;
border: 1px solid var(--purple-dim);
color: var(--cyan);
padding: 0.1em 0.6em;
margin-right: 0.2em;
cursor: pointer;
}
.meta-bulk-btn:hover {
border-color: var(--cyan);
text-shadow: 0 0 6px currentColor;
}
.meta-input-twig {
color: var(--purple-dim);
margin-right: 0.1em;
}
.btn-meta-update {
background: rgba(203, 166, 247, 0.12);
border: 1px solid var(--purple);
color: var(--purple);
text-shadow: 0 0 4px currentColor;
padding: 0.3em 1em;
font: inherit;
font-size: 0.85em;
letter-spacing: 0.08em;
cursor: pointer;
transition: box-shadow 0.15s ease, background 0.15s ease;
}
.btn-meta-update:hover:not([disabled]) {
background: rgba(203, 166, 247, 0.22);
box-shadow: 0 0 10px -2px currentColor;
}
.btn-meta-update[disabled] {
opacity: 0.35;
cursor: not-allowed;
}
.meta-update-running {
margin: 0 0 0.7em;
padding: 0.4em 0.7em;
border: 1px solid var(--purple);
background: rgba(203, 166, 247, 0.12);
color: var(--purple);
font-size: 0.85em;
animation: badge-pulse 1.6s ease-in-out infinite;
}
/* ─── rebuild queue panel ──────────────────────────────────────────────── */
.rebuild-queue {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 0.2em;
}
.rebuild-queue-entry {
padding: 0.3em 0.6em;
border: 1px solid var(--border);
background: rgba(24, 24, 37, 0.6);
font-size: 0.9em;
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.4em;
}
.rebuild-queue-entry.rqe-child { margin-left: 1.6em; border-color: var(--purple-dim); }
.rebuild-queue-entry.rqe-running {
border-color: var(--purple);
background: rgba(203, 166, 247, 0.12);
animation: badge-pulse 1.6s ease-in-out infinite;
}
.rebuild-queue-entry.rqe-failed { border-color: var(--red); color: var(--red); }
.rebuild-queue-entry.rqe-cancelled { opacity: 0.6; }
.rebuild-queue-entry.rqe-done { opacity: 0.7; color: var(--green); }
.rqe-state { font-weight: bold; min-width: 1.2em; text-align: center; }
.rqe-kind { color: var(--cyan); }
.rqe-agent { color: var(--amber); font-weight: bold; }
.rqe-source {
font-size: 0.75em;
padding: 0.05em 0.45em;
border-radius: 0.7em;
border: 1px solid var(--border);
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.rqe-source-manual { color: var(--cyan); border-color: var(--cyan); }
.rqe-source-meta_update { color: var(--purple); border-color: var(--purple); }
.rqe-source-auto_update { color: var(--muted); }
.rqe-source-startup_sweep { color: var(--muted); }
.rqe-source-crash_recover { color: var(--amber); border-color: var(--amber); }
.rqe-source-approval { color: var(--green); border-color: var(--green); }
.rqe-when { color: var(--muted); font-size: 0.85em; }
.rqe-reason { color: var(--muted); font-size: 0.85em; flex: 1 1 auto; }
.rqe-step {
flex-basis: 100%;
margin: 0.1em 0 0 1.8em;
color: var(--cyan);
font-size: 0.85em;
}
.rqe-error {
flex-basis: 100%;
margin: 0.3em 0 0;
padding: 0.3em 0.5em;
background: rgba(243, 139, 168, 0.1);
border-left: 2px solid var(--red);
color: var(--red);
font-size: 0.8em;
white-space: pre-wrap;
}
.rqe-cancel {
margin-left: auto;
}
.rqe-cancel-btn {
background: transparent;
border: 1px solid var(--purple-dim);
color: var(--muted);
border-radius: 999px;
width: 1.6em;
height: 1.6em;
font-size: 0.85em;
line-height: 1;
padding: 0;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
transition: color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.rqe-cancel-btn:hover:not(:disabled),
.rqe-cancel-btn:focus-visible {
color: var(--red);
border-color: var(--red);
box-shadow: 0 0 8px -2px var(--red);
outline: none;
}
.rqe-cancel-btn:disabled {
opacity: 0.5;
cursor: default;
}
.history-note {
margin-left: 1.8em;
margin-top: 0.2em;
color: var(--muted);
font-size: 0.85em;
white-space: pre-wrap;
word-break: break-word;
}
ul form.inline { display: inline-block; }
.spawnform { display: flex; gap: 0.6em; align-items: stretch; margin: 0.5em 0; }
.spawnform input {
font-family: inherit;
font-size: 1em;
background: var(--bg-elev);
color: var(--fg);
border: 1px solid var(--border);
padding: 0.4em 0.6em;
flex: 1;
}
.spawnform input::placeholder { color: var(--muted); }
.spawnform input:focus { outline: 1px solid var(--purple); }
.role-pending { color: var(--amber); border-color: var(--amber); }
.btn-inline {
font-family: inherit;
background: transparent;
cursor: pointer;
margin-left: 0.4em;
}
.btn-inline:hover { background: rgba(255, 184, 77, 0.1); }
.kind {
display: inline-block;
margin-left: 0.4em;
padding: 0.05em 0.5em;
border: 1px solid var(--purple-dim);
color: var(--purple-dim);
border-radius: 2px;
font-size: 0.75em;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.kind-spawn { color: var(--amber); border-color: var(--amber); }
.spinner {
display: inline-block;
animation: spin 1s linear infinite;
color: var(--amber);
}
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.talkform {
display: flex;
gap: 0.6em;
align-items: stretch;
margin-top: 0.5em;
}
.talkform select, .talkform input {
font-family: inherit;
font-size: 1em;
background: var(--bg-elev);
color: var(--fg);
border: 1px solid var(--border);
padding: 0.4em 0.6em;
}
.talkform select { color: var(--amber); }
.talkform input { flex: 1; }
.talkform input::placeholder { color: var(--muted); }
.talkform input:focus, .talkform select:focus { outline: 1px solid var(--purple); }
details { margin-top: 0.5em; }
summary {
cursor: pointer;
color: var(--muted);
font-size: 0.85em;
text-transform: uppercase;
letter-spacing: 0.1em;
}
summary:hover { color: var(--purple); }
.diff {
background: var(--bg-elev);
border: 1px solid var(--border);
padding: 0.8em;
margin-top: 0.4em;
overflow-x: auto;
font-size: 0.85em;
line-height: 1.4;
color: var(--muted);
white-space: pre;
}
.diff span { display: block; }
.diff .diff-add { color: var(--green); }
.diff .diff-del { color: var(--red); }
.diff .diff-hunk { color: var(--cyan); }
.diff .diff-file { color: var(--purple); font-weight: bold; }
.diff .diff-ctx { color: var(--fg); }
.questions {
background: var(--bg-elev);
border: 1px solid var(--amber);
box-shadow: 0 0 12px -4px var(--amber);
padding: 0.6em 0.9em;
animation: questions-pulse 2.4s ease-in-out infinite;
}
.reminders {
list-style: none;
padding: 0;
margin: 0;
}
.reminder-row {
padding: 0.4em 0;
border-bottom: 1px solid var(--border);
}
.reminder-row:last-child { border-bottom: 0; }
.reminder-head { font-size: 0.9em; }
.reminder-body {
color: var(--fg);
white-space: pre-wrap;
word-break: break-word;
margin: 0.3em 0;
}
.reminder-row.reminder-failed {
border-left: 2px solid var(--red, #f38ba8);
padding-left: 0.5em;
}
.reminder-error {
color: var(--red, #f38ba8);
background: rgba(243, 139, 168, 0.06);
border: 1px solid rgba(243, 139, 168, 0.25);
padding: 0.3em 0.5em;
font-size: 0.85em;
white-space: pre-wrap;
word-break: break-word;
margin: 0.2em 0;
}
.reminder-actions {
display: flex;
gap: 0.4em;
margin-top: 0.3em;
}
.questions-filters {
display: flex;
flex-wrap: wrap;
gap: 0.3em;
margin-bottom: 0.5em;
}
.q-filter-chip {
background: var(--bg);
color: var(--muted);
border: 1px solid var(--border);
border-radius: 999px;
padding: 0.15em 0.7em;
font: inherit;
font-size: 0.85em;
cursor: pointer;
}
.q-filter-chip:hover { color: var(--fg); }
.q-filter-chip.active {
color: var(--amber);
border-color: var(--amber);
}
.questions li.question-peer {
border-left: 2px solid var(--mauve, #cba6f7);
padding-left: 0.6em;
}
.questions .msg-to-peer { color: var(--mauve, #cba6f7); }
.btn-override { background: var(--mauve, #cba6f7) !important; color: var(--bg) !important; }
.questions li.question {
padding: 0.4em 0;
border-bottom: 1px solid var(--border);
}
.questions li.question:last-child { border-bottom: 0; }
.questions .q-head { font-size: 0.9em; }
.questions .q-ttl {
color: var(--amber);
margin-left: 0.4em;
font-size: 0.95em;
letter-spacing: 0.05em;
}
.questions .q-body {
color: var(--fg);
margin: 0.3em 0;
white-space: pre-wrap;
word-break: break-word;
}
.qform {
display: flex;
flex-direction: column;
gap: 0.5em;
margin-top: 0.4em;
}
.qform .q-options {
display: flex;
flex-direction: column;
gap: 0.25em;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 4px;
padding: 0.4em 0.6em;
}
.qform .q-option label { cursor: pointer; user-select: none; }
.qform .q-option input { margin-right: 0.4em; accent-color: var(--amber); }
.qform .q-free { display: flex; }
.qform .q-free textarea {
flex: 1;
font-family: inherit;
font-size: 1em;
background: var(--bg);
color: var(--fg);
border: 1px solid var(--border);
padding: 0.4em 0.6em;
resize: vertical;
line-height: 1.4;
}
.qform .q-free textarea::placeholder { color: var(--muted); }
.qform .q-free textarea:focus { outline: 1px solid var(--amber); }
.qform button { align-self: flex-start; }
.qform-cancel { margin-top: 0.3em; }
.q-history {
margin-top: 0.8em;
border: 1px solid var(--border);
border-radius: 4px;
padding: 0.4em 0.7em;
}
.q-history summary { cursor: pointer; color: var(--muted); font-size: 0.9em; user-select: none; }
.questions-answered {
border: none;
box-shadow: none;
animation: none;
padding: 0;
margin-top: 0.5em;
}
.question-answered { opacity: 0.7; }
.question-answered .q-body { color: var(--muted); margin-bottom: 0.15em; }
.q-answer { font-size: 0.9em; color: var(--green, #a6e3a1); padding: 0.1em 0 0.4em 0; }
.q-answer-text { font-style: italic; }
footer {
margin-top: 4em;
text-align: center;
color: var(--muted);
font-size: 0.9em;
}
footer a { color: var(--purple); }
footer .banner-thin {
margin-bottom: 0.8em;
}
/* ─── capabilities (permissions) table ─────────────────────────────
Agents × capabilities matrix in the P3RM1SS10NS tab. Same layout
as the tool-groups table below. Horizontally scrollable on narrow
viewports. */
.cap-table-wrap { overflow-x: auto; margin-top: 0.5em; }
.cap-table { border-collapse: collapse; font-size: 0.82em; min-width: 100%; }
.cap-table th,
.cap-table td {
padding: 0.35em 0.6em;
border: 1px solid var(--border);
text-align: center;
vertical-align: middle;
}
.cap-table thead th {
background: var(--bg-elev);
color: var(--muted);
letter-spacing: 0.05em;
white-space: nowrap;
}
.cap-agent-col {
text-align: left !important;
min-width: 8em;
}
.cap-col {
min-width: 5em;
}
.cap-save-col {
min-width: 4em;
}
.cap-agent-name {
color: var(--fg);
font-weight: 600;
}
.cap-cb {
cursor: pointer;
width: 1em;
height: 1em;
accent-color: var(--purple);
}
.cap-save-btn {
font-size: 0.78em;
padding: 0.2em 0.6em;
white-space: nowrap;
}
.cap-row:hover td {
background: var(--bg-elev);
}
/* ─── tool-groups (permissions) table ──────────────────────────────
Agents × tool-groups matrix in the P3RM1SS10NS tab. Same layout
as the capabilities table above. Horizontally scrollable on narrow
viewports. */
.tg-table-wrap { overflow-x: auto; margin-top: 0.5em; }
.tg-table { border-collapse: collapse; font-size: 0.82em; min-width: 100%; }
.tg-table th,
.tg-table td { padding: 0.35em 0.6em; border: 1px solid var(--border); text-align: center; vertical-align: middle; }
.tg-table thead th { background: var(--bg-elev); color: var(--muted); letter-spacing: 0.05em; white-space: nowrap; }
.tg-agent-col { text-align: left !important; min-width: 8em; }
.tg-group-col { min-width: 5em; }
.tg-save-col { min-width: 4em; }
.tg-agent-name { color: var(--fg); font-weight: 600; }
.tg-cb { cursor: pointer; width: 1em; height: 1em; accent-color: var(--purple); }
.tg-save-btn { font-size: 0.78em; padding: 0.2em 0.6em; white-space: nowrap; }
.tg-row:hover td { background: var(--bg-elev); }
/* ─── scheduled prompts tab ────────────────────────────────────────
Creation form at the top, list of queued schedule cards below. */
.schedule-edit-form {
display: flex;
flex-direction: column;
gap: 0.6em;
background: var(--bg-elev);
border: 1px solid var(--border);
border-radius: 4px;
padding: 0.8em 1em;
margin-bottom: 0.5em;
}
.schedule-edit-form-wrapper {
margin-top: 0.5em;
padding-left: 0.5em;
border-left: 2px solid var(--yellow, #f9e2af);
}
.schedule-edit-targets-note {
color: var(--muted);
font-style: italic;
font-size: 0.85em;
margin: 0.2em 0 0 0;
}
.schedule-field {
display: flex;
flex-direction: column;
gap: 0.2em;
}
.schedule-field-label {
color: var(--muted);
font-size: 0.85em;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.schedule-field input,
.schedule-field textarea {
font-family: inherit;
font-size: inherit;
background: var(--bg);
color: var(--fg);
border: 1px solid var(--border);
border-radius: 3px;
padding: 0.35em 0.5em;
}
.schedule-field textarea { resize: vertical; min-height: 4em; }
.schedule-targets {
display: flex;
flex-wrap: wrap;
gap: 0.4em;
}
.schedule-target-chip {
display: inline-flex;
align-items: center;
gap: 0.4em;
padding: 0.2em 0.6em;
border: 1px solid var(--border);
border-radius: 999px;
font-size: 0.85em;
cursor: pointer;
background: rgba(24, 24, 37, 0.4);
}
.schedule-target-chip:hover { border-color: var(--purple-dim); }
.schedule-target-chip:has(input:checked) {
border-color: var(--purple);
color: var(--purple);
background: rgba(203, 166, 247, 0.08);
}
.schedule-target-chip input { margin: 0; }
.schedule-actions {
display: flex;
gap: 0.5em;
justify-content: flex-end;
}
.schedule-interval-presets {
display: flex;
flex-wrap: wrap;
gap: 0.3em;
margin-top: 0.1em;
}
.btn-interval-preset {
color: var(--cyan);
border-color: var(--cyan);
font-size: 0.75em;
padding: 0.15em 0.55em;
letter-spacing: 0.05em;
}
.btn-interval-oneshot {
color: var(--muted);
border-color: var(--muted);
}
.schedule-interval-parts {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.35em;
margin-top: 0.4em;
}
.schedule-interval-num {
width: 4em;
text-align: right;
font-variant-numeric: tabular-nums;
}
.schedule-interval-unit {
color: var(--muted);
font-size: 0.85em;
margin-right: 0.2em;
}
.schedule-interval-preview {
margin-top: 0.4em;
color: var(--cyan);
font-size: 0.9em;
font-variant-numeric: tabular-nums;
}
.schedule-interval-preview-oneshot { color: var(--muted); font-style: italic; }
.schedules-table-wrap { overflow-x: auto; margin-top: 0.5em; }
.schedules-table {
min-width: 100%;
border-collapse: collapse;
font-size: 0.82em;
}
.schedules-table th,
.schedules-table td {
padding: 0.35em 0.6em;
border: 1px solid var(--border);
vertical-align: middle;
}
.schedules-table thead th {
background: var(--bg-elev);
color: var(--muted);
font-weight: normal;
text-transform: uppercase;
letter-spacing: 0.05em;
white-space: nowrap;
}
.schedules-table-id { width: 3em; text-align: center; }
.schedules-table-next-col { width: 8em; white-space: nowrap; }
.schedules-table-every-col { width: 7em; white-space: nowrap; }
.schedules-table-body-th { min-width: 12em; }
.schedules-table-actions-th { width: 7em; }
.schedules-table-agent-th {
width: 28px;
min-width: 28px;
height: 95px;
padding: 0 !important;
vertical-align: bottom;
white-space: nowrap;
text-transform: none !important;
letter-spacing: 0 !important;
position: relative;
}
.schedules-table-agent-th > div {
position: absolute;
bottom: 4px;
left: 14px;
transform-origin: left bottom;
transform: rotate(-45deg);
font-family: ui-monospace, 'JetBrains Mono', monospace;
font-size: 0.9em;
color: var(--fg);
}
.schedules-table-agent-th > div > span {
display: inline-block;
padding: 0 4px 1px;
}
.schedules-table-row-cancelled td { opacity: 0.55; }
.schedules-table-body-cell {
max-width: 30em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: ui-monospace, 'JetBrains Mono', monospace;
font-size: 0.9em;
}
.schedules-table-check {
width: 28px;
text-align: center;
padding: 0.3em 0 !important;
}
.schedules-table-check-btn {
background: transparent;
border: 0;
color: var(--green);
cursor: pointer;
padding: 0.1em 0.3em;
font-family: inherit;
font-size: 1em;
}
.schedules-table-check-btn:hover:not(:disabled) {
color: var(--red);
}
.schedules-table-check-btn:disabled {
cursor: default;
}
.schedules-table-check-cancelled {
color: var(--muted);
font-size: 0.9em;
}
.schedules-table-actions {
text-align: right;
white-space: nowrap;
}
.schedules-table-actions .btn-inline-small {
margin-left: 0.3em;
}
.schedules-table-edit-row > td {
background: rgba(38, 32, 60, 0.35);
padding: 0.5em 0.6em;
}
.schedules-table-create-row td {
background: rgba(38, 32, 60, 0.25);
border-top: 2px solid var(--border);
vertical-align: top;
padding: 0.4em 0.5em;
}
.schedules-table-create-cell {
padding: 0.35em 0.4em;
}
.schedules-table-inline-input,
.schedules-table-inline-textarea,
.schedules-table-inline-num {
background: var(--bg);
border: 1px solid var(--border);
color: var(--fg);
font-family: ui-monospace, 'JetBrains Mono', monospace;
font-size: 0.85em;
padding: 0.2em 0.4em;
border-radius: 2px;
}
.schedules-table-inline-input:focus,
.schedules-table-inline-textarea:focus,
.schedules-table-inline-num:focus {
border-color: var(--purple);
outline: none;
}
.schedules-table-inline-textarea {
display: block;
width: 100%;
min-height: 1.6em;
resize: vertical;
}
.schedules-table-create-body:focus-within .schedules-table-inline-textarea {
min-height: 4em;
}
.schedules-table-inline-desc {
display: block;
width: 100%;
margin-top: 0.25em;
}
.schedules-table-inline-datetime {
width: 100%;
font-size: 0.78em;
}
.schedules-table-inline-interval {
display: flex;
align-items: center;
gap: 0.1em;
white-space: nowrap;
}
.schedules-table-inline-num {
width: 2.4em;
text-align: right;
font-variant-numeric: tabular-nums;
-moz-appearance: textfield;
appearance: textfield;
}
.schedules-table-inline-num::-webkit-outer-spin-button,
.schedules-table-inline-num::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.schedules-table-inline-unit {
color: var(--muted);
font-size: 0.7em;
margin-right: 0.15em;
}
.schedules-table-inline-check {
width: 16px;
height: 16px;
cursor: pointer;
margin: 0;
}
.schedules-table-inline-check-lbl {
display: inline-flex;
cursor: pointer;
padding: 0.4em 0.6em;
}
.schedules-table-create-submit {
font-size: 1em;
padding: 0.15em 0.55em;
color: var(--green);
border-color: var(--green);
}
.schedules-table-create-reset {
font-size: 0.85em;
padding: 0.15em 0.45em;
color: var(--muted);
border-color: var(--border);
}
.btn-inline-small {
font-size: 0.7em;
padding: 0.1em 0.45em;
}
/* Selection bar — sticky-bottom strip for bulk actions. */
.selection-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 40;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.6em;
padding: 0.55em 1em;
background: var(--flow-frost-bg, rgba(30, 30, 46, 0.74));
-webkit-backdrop-filter: blur(12px) saturate(140%);
backdrop-filter: blur(12px) saturate(140%);
border-top: 1px solid var(--purple);
box-shadow: 0 -6px 18px rgba(0, 0, 0, 0.4);
}
.selection-bar[hidden] { display: none; }
.selection-count {
color: var(--purple);
font-weight: bold;
letter-spacing: 0.05em;
}
.selection-names {
color: var(--muted);
font-size: 0.85em;
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.selection-actions {
display: inline-flex;
flex-wrap: wrap;
gap: 0.4em;
align-items: center;
}
.selection-actions .btn {
font-size: 0.75em;
padding: 0.2em 0.7em;
}
.selection-clear {
color: var(--muted);
border-color: var(--purple-dim);
font-size: 0.75em;
padding: 0.2em 0.7em;
}
/* Pad the dashboard body so the sticky bar doesn't cover the
bottom of the agent list. Only applies when bar is visible. */
body.dashboard-shell.has-selection { padding-bottom: 4.5em; }
.move-picker {
display: inline-flex;
align-items: center;
gap: 0.3em;
margin-left: 0.6em;
}
.move-picker-select {
font-family: inherit;
font-size: 0.75em;
background: var(--bg);
color: var(--fg);
border: 1px solid var(--purple);
border-radius: 2px;
padding: 0.1em 0.3em;
max-width: 16em;
}
.move-picker-select:disabled {
opacity: 0.5;
cursor: default;
}