Files
fusion/packages/dashboard/app/components/AgentsView.css
gsxdsm 826a7eea31 FN-6936: show agent model details on list cards
Agent list cards now surface model/runtime configuration alongside existing agent details.

- Add list-card model/runtime labeling with provider/model, legacy model, runtime hint, and Auto fallback handling.
- Style the new value badge for truncation and responsive wrapping.
- Cover configured, legacy, runtime, and automatic agent labels in AgentsView tests.
- Document the model/runtime field in the dashboard guide.

Files changed:
 docs/dashboard-guide.md                            |  1 +
 packages/dashboard/app/components/AgentsView.css   | 19 +++++++-
 packages/dashboard/app/components/AgentsView.tsx   | 38 ++++++++++++++++
 .../app/components/__tests__/AgentsView.test.tsx   | 50 ++++++++++++++++++++++
 4 files changed, 107 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-6936

Fusion-Task-Lineage: 7ce3591e-eae0-4968-8923-d9acab0f92c3
2026-06-23 00:15:38 -07:00

1578 lines
36 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.
/* === Agent Metrics Bar === */
.agent-metrics-bar {
display: flex;
gap: var(--space-md);
margin-bottom: var(--space-lg);
}
.agent-metric-card {
display: flex;
align-items: center;
gap: var(--space-md);
padding: var(--space-md) var(--space-lg);
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
transition: background var(--transition-fast), transform var(--transition-fast), box-shadow var(--transition-fast);
flex: 1;
}
.agent-metric-card:hover {
background: var(--card-hover);
transform: translateY(calc(var(--space-xs) * -0.25));
}
.agent-metric-card--active svg { color: var(--state-active-text); }
.agent-metric-card--tasks svg { color: var(--in-progress); }
.agent-metric-card--success svg { color: var(--color-success); }
.agent-metric-card--runs svg { color: var(--in-progress); }
.agent-metric-info {
display: flex;
flex-direction: column;
}
.agent-metric-value {
font-size: calc(var(--space-lg) + var(--space-xs) * 0.5);
font-weight: 700;
font-family: var(--font-mono);
line-height: 1.2;
}
.agent-metric-label {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.75);
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: calc(var(--space-xs) * 0.125);
}
/* === Agent List View === */
.agents-view {
position: relative;
display: flex;
flex-direction: column;
flex: 1;
height: 100%;
width: 100%;
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
}
/*
FNXC:Agents 2026-06-23-02:00:
Agents renders the shared ViewHeader (.view-header). Its chrome reads identically to the Missions inline header (.mission-manager__header--inline): same --space-lg/--space-xl padding, surface background, no bottom divider, and a --todo-colored leading icon.
FNXC:ViewHeader 2026-06-23-03:45:
The former scoped overrides (.agents-view .view-header padding/border/background and the --todo icon color) are removed: ViewHeader now supplies that canonical chrome by default, so the overrides were redundant. The legacy .agents-view-header/.agents-view-title rules below are retained only because the agents-view-mobile CSS string-match test asserts them; they no longer map to rendered DOM.
*/
.agents-view-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-lg);
border-bottom: 1px solid var(--border);
background: var(--surface);
}
.agents-view-title {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.agents-view-title h2 {
font-size: calc(var(--space-lg) + var(--space-xs) * 0.5);
font-weight: 600;
margin: 0;
}
.agents-view-controls {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.agents-view-primary-actions {
position: relative;
display: flex;
align-items: center;
gap: var(--space-sm);
}
.agent-controls-trigger {
white-space: nowrap;
}
.agent-controls-trigger--active {
border-color: var(--todo);
box-shadow: var(--focus-ring);
}
.agent-controls-panel {
position: absolute;
top: calc(100% + var(--space-sm));
right: 0;
width: min(calc(var(--space-2xl) * 16), calc(100vw - var(--space-2xl)));
max-width: calc(100vw - var(--space-2xl));
padding: var(--space-md);
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: var(--card);
box-shadow: var(--shadow-lg);
z-index: 20;
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.agent-controls-panel--scrollable {
max-height: 70vh;
overflow-y: auto;
}
.agent-controls-panel .agent-controls {
margin-bottom: 0;
align-items: stretch;
}
.agent-controls-panel .agent-controls-actions {
justify-content: flex-end;
}
.agent-controls-panel .agent-global-controls {
margin-bottom: 0;
padding: var(--space-md);
}
.agent-controls-mobile-actions {
display: flex;
flex-wrap: wrap;
gap: var(--space-sm);
}
.agent-controls-mobile-actions .btn {
flex: 1 1 calc(var(--space-2xl) * 4);
justify-content: center;
}
.agent-controls-bulk-actions {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-lg);
padding: var(--space-xs);
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
.agent-controls-bulk-actions__label {
display: inline-flex;
align-items: center;
gap: var(--space-sm);
}
.agent-detail-bulk-menu-item {
width: 100%;
border: 0;
border-radius: var(--radius-sm);
background: transparent;
color: var(--text);
text-align: left;
padding: var(--space-sm);
display: flex;
flex-direction: column;
gap: calc(var(--space-xs) * 0.5);
cursor: pointer;
}
.agent-detail-bulk-menu-item:hover:not(:disabled),
.agent-detail-bulk-menu-item:focus-visible {
outline: none;
background: var(--card-hover);
}
.agent-detail-bulk-menu-item:disabled {
color: var(--text-muted);
cursor: not-allowed;
}
.agent-detail-bulk-menu-item-hint {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
color: var(--text-muted);
}
.agents-org-full-view {
display: flex;
flex: 1;
min-height: 0;
}
.agents-view-content--org-full {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.agents-org-detail-view {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.agents-org-detail-back {
align-self: flex-start;
}
.agents-split-layout {
display: grid;
grid-template-columns: minmax(calc(var(--space-xl) * 11 + var(--space-xs)), calc(var(--space-xl) * 13 + var(--space-lg))) var(--space-sm) minmax(0, 1fr);
gap: 0;
flex: 1;
min-height: 0;
}
.agents-split-sidebar {
min-height: 0;
overflow: hidden;
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
}
.agents-split-resize-handle {
position: relative;
width: var(--space-sm);
min-width: var(--space-sm);
cursor: col-resize;
background: transparent;
touch-action: none;
transition: background var(--transition-fast);
}
/*
FNXC:AgentsView 2026-06-20-00:00:
The resize affordance must match MissionManager's accessible split-pane handle while preserving a token-only, no-mobile-shell layout.
The base grid keeps a token-sized handle column as the no-JS fallback, while the React inline grid width owns desktop/tablet persistence.
*/
.agents-split-resize-handle::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: var(--space-xs);
transform: translateX(-50%);
}
.agents-split-resize-handle:hover::before,
.agents-split-resize-handle:active::before {
background: color-mix(in srgb, var(--todo) 30%, transparent);
}
.agents-split-resize-handle:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
}
.agents-split-detail {
min-height: 0;
overflow: hidden;
display: flex;
flex-direction: column;
background: var(--surface);
}
/* FNXC:AgentsView 2026-06-22-01:00: ViewHeader supplies the top padding, so the scrollable body drops its top inset to avoid doubling the gap under the header (keeps horizontal + bottom padding). */
.agents-view-content {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 0 calc(var(--space-lg) + var(--space-xs)) calc(var(--space-lg) + var(--space-xs));
}
.agents-detail-empty-state {
display: flex;
flex: 1;
min-height: 0;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--space-md);
color: var(--text-muted);
text-align: center;
padding: var(--space-xl);
}
.agents-detail-empty-state h3,
.agents-detail-empty-state p {
margin: 0;
}
.agents-detail-empty-state svg {
opacity: 0.3;
}
.agents-view-loading {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: calc(var(--space-2xl) * 6);
gap: var(--space-sm);
color: var(--text-muted);
}
.agent-controls {
display: flex;
align-items: center;
gap: var(--space-md);
margin-bottom: var(--space-lg);
flex-wrap: wrap;
}
.agent-controls-filters {
display: flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-xs) var(--space-sm);
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
}
.agent-state-filter {
display: flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-xs) calc(var(--space-sm) + var(--space-xs));
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text-muted);
transition: border-color var(--transition-fast), color var(--transition-fast), background var(--transition-fast);
}
.agent-state-filter:hover {
border-color: var(--text-dim);
color: var(--text);
}
.agent-state-filter:focus-within {
border-color: var(--todo);
box-shadow: var(--focus-ring);
}
.agent-state-filter-select {
appearance: none;
background: transparent;
border: none;
color: var(--text);
font-size: calc(var(--space-sm) + var(--space-xs) + var(--space-xs) * 0.25);
font-family: var(--font-primary);
cursor: pointer;
outline: none;
padding-right: var(--space-xs);
}
.agent-system-filter {
font-size: calc(var(--space-sm) + var(--space-xs) + var(--space-xs) * 0.25);
color: var(--text-muted);
cursor: pointer;
display: flex;
align-items: center;
gap: var(--space-sm);
user-select: none;
padding: var(--space-xs) var(--space-sm);
border-radius: var(--radius-sm);
transition: color var(--transition-fast), background var(--transition-fast);
}
.agent-system-filter:hover {
color: var(--text);
}
.agent-system-filter input[type="checkbox"] {
width: calc(var(--space-sm) + var(--space-xs) * 2);
height: calc(var(--space-sm) + var(--space-xs) * 2);
accent-color: var(--todo);
cursor: pointer;
}
.agent-create-form {
display: flex;
gap: var(--space-md);
margin-bottom: var(--space-lg);
padding: var(--space-lg);
background: var(--bg-secondary);
border-radius: var(--radius-sm);
}
/* ── Agent Tree Node Styles (shared with AgentDetailView) ──────────────── */
.agent-tree__node {
position: relative;
display: flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-sm);
}
.agent-tree__icon {
font-size: calc(var(--space-md) + var(--space-xs));
line-height: 1;
flex-shrink: 0;
}
.agent-tree__name {
font-size: calc(var(--space-sm) + var(--space-xs) + var(--space-xs) * 0.25);
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.agent-tree__badge {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
font-weight: 600;
text-transform: uppercase;
padding: calc(var(--space-xs) * 0.5) calc(var(--space-xs) + var(--space-sm) * 0.25);
border-radius: var(--radius-sm);
flex-shrink: 0;
}
.agent-is-child {
background: color-mix(in srgb, var(--accent) 5%, transparent);
border-left: 2px solid var(--accent);
}
.agent-tree__children {
position: relative;
display: flex;
flex-direction: column;
gap: var(--space-xs);
margin-left: calc(var(--space-md) - var(--space-xs));
padding-left: var(--space-md);
border-left: 1px solid var(--border);
}
.agent-tree__children::before {
content: "";
position: absolute;
left: -1px;
top: 0;
bottom: 50%;
width: 1px;
background: var(--border);
}
.agent-board {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(calc(var(--space-xl) * 8 + var(--space-sm)), 1fr));
gap: var(--space-lg);
}
/*
FNXC:AgentsView 2026-06-20-03:25:
FN-6774 removes the saturated top-edge status stripe from agent board cards. Agent state remains legible through state chips, subtle card background tints, hover feedback, and the neutral card border.
*/
.agent-board-card {
display: flex;
flex-direction: column;
gap: var(--space-sm);
padding: var(--space-lg);
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
transition: background var(--transition-fast), border-color var(--transition-fast);
}
.agent-board-card:hover {
background: var(--card-hover);
border-color: var(--text-muted);
}
.agent-board-card--active:hover,
.agent-board-card--running:hover {
background: color-mix(in srgb, var(--state-active-border) 20%, var(--card-hover));
}
.agent-board-header {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.agent-board-icon {
font-size: calc(var(--space-lg) + var(--space-xs));
line-height: 1;
}
.agent-board-badge {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
font-weight: 600;
text-transform: uppercase;
padding: calc(var(--space-xs) * 0.5) calc(var(--space-sm) - var(--space-xs) * 0.25);
border-radius: var(--radius-sm);
margin-left: auto;
}
.agent-board-health {
display: flex;
align-items: center;
}
.agent-board-name {
font-weight: 600;
font-size: calc(var(--space-md) + var(--space-xs) * 0.5);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.agent-board-id {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.75);
font-family: var(--font-mono);
color: var(--text-muted);
}
.agent-board-clickable {
cursor: pointer;
}
.agent-board-clickable:hover .agent-board-name {
color: var(--todo);
}
.agent-board-clickable:focus-visible {
outline: none;
border-radius: var(--radius-sm);
box-shadow: var(--focus-ring-strong);
background: color-mix(in srgb, var(--todo) 8%, transparent);
}
.agent-board-clickable:focus-visible .agent-board-name {
color: var(--todo);
}
.agent-board-actions {
display: flex;
gap: var(--space-xs);
margin-top: var(--space-xs);
padding-top: var(--space-sm);
border-top: 1px solid var(--border);
}
.agent-board-actions .btn {
flex: 1;
justify-content: center;
}
.agent-list {
display: flex;
flex-direction: column;
gap: var(--space-md);
/*
FNXC:AgentsView 2026-06-22-14:45:
The split-sidebar agent list needs a small top inset so the first agent card does not press directly against the sidebar/header edge.
*/
padding-top: var(--space-sm);
}
/*
FNXC:AgentsView 2026-06-20-03:25:
FN-6774 removes the saturated left-edge status stripe from split-sidebar agent cards. Selection uses a full-card ring and state uses subtle backgrounds/status chips so no single edge becomes the status indicator.
*/
.agent-card {
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: var(--space-lg);
background: var(--surface);
}
.agent-card--selected {
background: color-mix(in srgb, var(--todo) 8%, transparent);
box-shadow: inset 0 0 0 calc(var(--space-xs) / 4) var(--todo);
}
.agent-card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: var(--space-md);
}
.agent-info {
display: flex;
align-items: center;
gap: var(--space-md);
}
.agent-info--clickable {
flex: 1;
display: flex;
align-items: center;
gap: var(--space-md);
cursor: pointer;
padding: var(--space-xs);
margin: calc(var(--space-xs) * -1);
border-radius: var(--radius-sm);
transition: background var(--transition-fast);
}
.agent-info--clickable:hover {
background: var(--card-hover);
}
.agent-info--clickable:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
background: color-mix(in srgb, var(--todo) 8%, transparent);
}
.agent-info--clickable:hover .agent-name,
.agent-info--clickable:focus-visible .agent-name {
color: var(--todo);
}
.agent-icon {
font-size: calc(var(--space-xl) + var(--space-xs));
}
.agent-icon--clickable {
cursor: pointer;
transition: opacity var(--transition-fast), transform var(--transition-fast);
user-select: none;
}
.agent-icon--clickable:hover {
opacity: 0.7;
transform: scale(1.1);
}
.agent-icon--clickable:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
border-radius: var(--radius-sm);
}
.agent-role-select {
font-size: calc(var(--space-md) + var(--space-xs) * 0.5);
padding: var(--space-xs) var(--space-sm);
min-width: calc(var(--space-2xl) * 3 + var(--space-lg));
width: auto;
cursor: pointer;
}
.agent-meta {
display: flex;
flex-direction: column;
}
.agent-name {
font-weight: 600;
font-size: var(--space-lg);
}
.agent-id {
font-size: var(--space-md);
font-family: var(--font-mono);
}
.agent-badges {
display: flex;
gap: var(--space-sm);
flex-wrap: wrap;
min-width: 0;
justify-content: flex-end;
}
.agent-approval-badge {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
color: var(--color-warning);
}
.agent-badges .badge-skill {
min-width: 0;
max-width: min(100%, calc(var(--space-2xl) * 6));
overflow: hidden;
text-overflow: ellipsis;
}
.agent-card-chevron {
color: var(--text-muted);
margin-left: auto;
opacity: 0;
transition: opacity var(--transition-fast);
}
.agent-info--clickable:hover .agent-card-chevron {
opacity: 1;
}
.agent-card-body {
display: flex;
flex-direction: column;
gap: var(--space-xs);
margin-bottom: var(--space-md);
padding: var(--space-sm);
background: var(--bg-secondary);
border-radius: var(--radius-sm);
font-size: calc(var(--space-md) + var(--space-xs) * 0.25);
}
.agent-card-error {
background: color-mix(in srgb, var(--color-error) 10%, transparent);
border-left: var(--btn-border-width) solid var(--color-error);
border-radius: var(--radius-sm);
padding: var(--space-sm);
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.agent-card-error-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--space-sm);
}
.agent-card-error-actions {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
}
.agent-card-error-preview {
min-width: 0;
flex: 1;
font-family: var(--font-mono);
font-size: var(--space-md);
color: var(--text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.agent-card-error-full {
margin: 0;
font-family: var(--font-mono);
font-size: var(--space-md);
color: var(--text);
white-space: pre-wrap;
word-break: break-word;
max-height: calc(var(--space-2xl) * 4);
overflow-y: auto;
}
.agent-card-error-copy-btn,
.agent-card-error-toggle {
width: calc(var(--space-lg) + var(--space-md));
height: calc(var(--space-lg) + var(--space-md));
min-width: calc(var(--space-lg) + var(--space-md));
min-height: calc(var(--space-lg) + var(--space-md));
color: var(--text-muted);
}
.agent-card-error-copy-btn[aria-label="Copied error to clipboard"] {
color: var(--color-success);
}
.agent-task,
.agent-heartbeat,
.agent-model-runtime {
display: flex;
gap: var(--space-sm);
}
.agent-model-runtime {
align-items: center;
min-width: 0;
}
.agent-model-runtime__value {
min-width: 0;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
.agent-heartbeat-control {
display: flex;
align-items: center;
gap: var(--space-sm);
flex-wrap: wrap;
}
.agent-heartbeat-select {
width: auto;
min-width: calc(var(--space-2xl) + var(--space-xl));
padding: var(--space-xs) var(--space-md);
font-size: var(--space-md);
}
.agent-heartbeat-last,
.agent-heartbeat-next,
.agent-heartbeat-saving {
font-size: var(--space-md);
line-height: 1;
display: inline-flex;
align-items: center;
}
.agent-card-actions {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: var(--space-sm);
align-items: start;
width: 100%;
min-width: 0;
container-type: inline-size;
container-name: agent-card-actions;
}
.agent-card-actions-group {
display: flex;
flex-wrap: wrap;
gap: var(--space-sm);
align-items: center;
min-width: 0;
}
.agent-card-actions-group--secondary {
justify-content: flex-end;
}
.agent-card-actions .btn {
flex: 0 0 auto;
white-space: nowrap;
}
.agents-split-sidebar .agent-card-actions {
gap: var(--space-xs);
}
.agents-split-sidebar .agent-card-actions-group {
gap: var(--space-xs);
}
.agents-split-sidebar .agent-card-actions .btn {
gap: var(--space-xs);
padding: var(--space-xs) var(--space-sm);
}
@container agent-card-actions (max-width: calc(var(--space-2xl) * 9)) {
.agents-split-sidebar .agent-card-actions {
grid-template-columns: minmax(0, 1fr);
}
.agents-split-sidebar .agent-card-actions-group--secondary {
justify-content: flex-start;
}
.agents-split-sidebar .agent-card-actions .agent-card-action-label {
display: none;
}
}
.agent-card--clickable {
cursor: pointer;
}
.agent-card--clickable:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
}
.agent-empty {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-sm);
padding: calc(var(--space-2xl) + var(--space-lg));
color: var(--text-muted);
text-align: center;
}
.agent-empty-state__icon {
color: var(--text-dim);
}
.agent-empty-state__title,
.agent-empty-state__description {
margin: 0;
}
.agent-empty .btn {
margin-top: var(--space-sm);
}
/* Agent state badge variants */
.agent-badge--idle {
background: var(--state-idle-bg);
color: var(--state-idle-text);
border: 1px solid var(--state-idle-border);
}
.agent-badge--running {
background: var(--state-active-bg);
color: var(--state-active-text);
border: 1px solid var(--state-active-border);
}
.agent-badge--active,
.agent-badge--paused {
background: var(--state-idle-bg);
color: var(--state-idle-text);
border: 1px solid var(--state-idle-border);
}
.agent-badge--error {
background: var(--state-error-bg);
color: var(--state-error-text);
border: 1px solid var(--state-error-border);
}
.agent-board-card--active {
background: color-mix(in srgb, var(--state-active-border) 6%, var(--surface));
}
.agent-board-card--paused {
background: var(--state-paused-bg);
}
.agent-board-card--running {
background: var(--state-active-bg);
}
.agent-board-card--error {
background: var(--state-error-bg);
}
.agent-card--active {
background: color-mix(in srgb, var(--state-active-border) 6%, var(--surface));
}
.agent-card--paused {
background: var(--state-paused-bg);
}
.agent-card--running {
background: var(--state-active-bg);
}
.agent-card--running:hover {
background: color-mix(in srgb, var(--state-active-border) 20%, var(--card-hover));
}
.agent-card--error {
background: var(--state-error-bg);
}
/* === FN-1167: Agent Org Chart + Chain of Command === */
.agent-org-chart-shell {
display: flex;
flex: 1;
min-height: 0;
flex-direction: column;
gap: var(--space-sm);
overflow: hidden;
}
.agent-org-chart-controls {
display: none;
}
.agent-org-chart-toolbar {
display: flex;
justify-content: flex-end;
gap: var(--space-sm);
}
.agent-org-chart-layout-toggle {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
padding: var(--space-xs);
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: var(--surface);
box-shadow: var(--shadow-sm);
}
.agent-org-chart-layout-toggle__button {
width: auto;
padding: var(--space-xs) var(--space-sm);
gap: var(--space-xs);
}
.agent-org-chart-layout-toggle__text {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
font-weight: 500;
}
.agent-org-chart-controls__zoom-label {
min-width: calc(var(--space-2xl) * 2);
font-family: var(--font-mono);
text-align: center;
color: var(--text-muted);
}
.agent-org-chart-controls__fit-btn {
margin-left: auto;
}
.agent-org-chart-viewport {
flex: 1;
min-height: 0;
overflow: hidden;
max-width: 100%;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
touch-action: none;
cursor: grab;
}
.agent-org-chart-viewport[data-panning="true"] {
cursor: grabbing;
}
.agent-org-chart-canvas {
--org-chart-connector-color: color-mix(in srgb, var(--text-muted) 60%, transparent);
width: max-content;
position: relative;
transform-origin: top left;
transition: transform var(--transition-fast);
}
.agent-org-chart-canvas[data-panning="true"] {
transition: none;
}
/*
FNXC:AgentsOrgChart 2026-06-22-03:05:
AgentsView uses the measured SVG overlay as the single connector system so parent-child lines remain non-zero and aligned across horizontal/vertical layouts, desktop/mobile sizing, and pan/zoom transforms. Explicitly size the absolute SVG to fill the chart canvas instead of relying on the browser's default 300×150 SVG viewport.
*/
.agent-org-chart-connectors {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
overflow: visible;
pointer-events: none;
}
.agent-org-chart-connectors path {
stroke: var(--org-chart-connector-color);
stroke-width: 1px;
fill: none;
shape-rendering: crispEdges;
}
.agent-org-chart {
--org-chart-node-width: calc(var(--space-xl) * 9 + var(--space-xs));
--org-chart-sibling-gap: var(--space-xl);
--org-chart-connector-gap: var(--space-sm);
--org-chart-children-offset: calc(var(--space-lg) + var(--space-sm));
--org-chart-root-gap: var(--space-xl);
display: flex;
align-items: flex-start;
justify-content: flex-start;
gap: var(--org-chart-root-gap);
padding: var(--space-xl);
min-height: var(--org-chart-node-width);
}
.agent-org-chart__loading,
.chain-of-command-loading {
display: inline-flex;
align-items: center;
gap: var(--space-sm);
color: var(--text-muted);
}
.org-chart-node {
--org-chart-subtree-leaves-number: var(--org-chart-subtree-leaves, 1);
position: relative;
display: flex;
flex-direction: column;
align-items: center;
width: max-content;
min-width: calc(
var(--org-chart-subtree-leaves-number) * var(--org-chart-node-width) +
(var(--org-chart-subtree-leaves-number) - 1) * var(--org-chart-sibling-gap)
);
flex: 0 0 auto;
}
.org-chart-node--has-children {
padding-bottom: var(--space-xs);
}
.org-chart-node-card {
width: var(--org-chart-node-width);
max-width: 100%;
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-sm);
padding: var(--space-md);
color: var(--text);
cursor: pointer;
transition:
border-color var(--transition-fast),
background-color var(--transition-fast),
box-shadow var(--transition-fast),
transform var(--transition-fast);
position: relative;
}
.org-chart-node-card:hover,
.org-chart-node-card:focus-visible {
border-color: var(--todo);
background: var(--card-hover);
box-shadow: var(--shadow-md);
transform: translateY(calc(var(--space-xs) * -0.25));
outline: none;
}
.org-chart-node-card:focus-visible {
box-shadow: var(--shadow-md), var(--focus-ring-strong);
}
.org-chart-node-card--running {
background: var(--state-active-bg);
border-color: color-mix(in srgb, var(--color-success) 40%, var(--border));
}
.org-chart-node__header {
display: flex;
align-items: center;
gap: var(--space-md);
margin-bottom: var(--space-md);
}
.org-chart-node__icon {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: var(--space-lg);
flex-shrink: 0;
}
.org-chart-node__name {
font-size: calc(var(--space-sm) + var(--space-xs) * 1.5);
font-weight: 600;
line-height: 1.2;
}
.org-chart-node__meta {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: var(--space-xs);
margin-top: var(--space-xs);
}
.org-chart-node__badge {
display: inline-flex;
align-items: center;
padding: calc(var(--space-xs) * 0.5) var(--space-sm);
border-radius: var(--radius-pill);
font-size: calc(var(--space-sm) + var(--space-xs) * 0.75);
text-transform: capitalize;
}
.org-chart-node__health {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
font-size: var(--space-md);
}
.org-chart-children {
position: relative;
display: flex;
align-items: flex-start;
justify-content: center;
width: 100%;
gap: var(--org-chart-sibling-gap);
padding-top: var(--org-chart-children-offset);
margin-top: var(--org-chart-connector-gap);
}
.agent-org-chart--vertical {
flex-direction: column;
gap: var(--space-md);
min-height: auto;
}
.agent-org-chart--vertical .org-chart-node {
width: 100%;
min-width: var(--org-chart-node-width);
align-items: flex-start;
}
.agent-org-chart--vertical .org-chart-node--has-children {
padding-bottom: 0;
}
.agent-org-chart--vertical .org-chart-node-card {
margin-left: 0;
}
.agent-org-chart--vertical .org-chart-children {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: var(--space-sm);
padding-top: var(--space-sm);
padding-left: calc(var(--space-lg) + var(--space-sm));
margin-top: 0;
}
@media (max-width: 768px) {
.agent-org-chart-shell {
min-height: 0;
overflow: hidden;
}
}
.chain-of-command-path {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-xs) var(--space-sm);
}
.chain-of-command-item {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
}
.chain-of-command-node {
display: inline-flex;
align-items: center;
padding: var(--space-xs) calc(var(--space-sm) + var(--space-xs) * 0.5);
border-radius: var(--radius-pill);
border: 1px solid var(--border);
background: var(--surface);
color: var(--text-muted);
font-size: calc(var(--space-sm) + var(--space-xs));
cursor: pointer;
}
.chain-of-command-node:hover:not(:disabled) {
border-color: var(--accent);
color: var(--text);
}
.chain-of-command-node:focus-visible {
outline: none;
border-color: var(--todo);
box-shadow: var(--focus-ring-strong);
color: var(--text);
}
.chain-of-command-node:disabled {
cursor: default;
opacity: 0.9;
}
.chain-of-command-node--current {
border-color: var(--accent);
color: var(--text);
font-weight: 600;
}
.chain-of-command-separator {
color: var(--text-muted);
}
@media (max-width: 768px) {
/* Stats cards: drop to a 2x2 grid with tighter padding so they
don't squeeze the labels off the card on narrow phones. */
.agent-metrics-bar {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--space-sm);
margin-bottom: var(--space-md);
}
.agent-metric-card {
padding: var(--space-sm) var(--space-md);
gap: var(--space-sm);
min-width: 0;
}
.agent-metric-value {
font-size: var(--space-lg);
}
.agent-metric-label {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
}
.agent-org-chart-shell {
min-height: 0;
flex: 1;
overflow: hidden;
}
.agent-org-chart-controls {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: var(--space-sm);
}
.agent-org-chart-toolbar {
display: none;
}
.agent-org-chart-controls .agent-org-chart-layout-toggle {
order: 1;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
width: 100%;
}
.agent-org-chart-controls .agent-org-chart-layout-toggle__button {
justify-content: center;
}
.agent-org-chart-controls__zoom-label {
order: 2;
}
.agent-org-chart-controls .agent-org-chart-controls__fit-btn {
margin-left: 0;
}
.agent-org-chart-viewport {
min-height: calc(var(--space-2xl) * 4);
flex: 1;
min-width: 0;
overflow: auto;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
}
.agent-org-chart-canvas {
min-width: max-content;
}
.agent-org-chart {
--org-chart-node-width: calc(var(--space-2xl) * 5);
--org-chart-sibling-gap: var(--space-sm);
--org-chart-children-offset: var(--space-lg);
padding: var(--space-sm);
padding-bottom: calc(var(--space-lg) + var(--space-sm));
gap: var(--space-sm);
}
.agent-org-chart--vertical {
min-width: 100%;
}
.agents-view-loading {
min-height: calc(var(--space-2xl) * 4);
}
.org-chart-node-card {
padding: var(--space-sm);
border-radius: var(--radius-md);
}
.org-chart-node__name {
font-size: var(--space-md);
}
.org-chart-node__badge {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.625);
}
.agent-model-runtime {
flex-wrap: wrap;
}
.agent-card-error {
width: 100%;
padding: var(--space-xs) var(--space-sm);
}
.agent-card-error-header {
align-items: center;
}
}
/* === AgentsView mobile header (cleaner stacked layout) ==================== */
@media (max-width: 768px) {
/* Single-row header: keep a compact textual title visible while lower-
priority actions move into the Controls popup so narrow phones keep a
stable single-row layout. */
/* FNXC:Agents 2026-06-23-02:00: Match the Missions inline header mobile padding (--space-md) on the rendered shared ViewHeader. */
.agents-view .view-header {
padding: var(--space-md);
}
.agents-view-header {
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
justify-content: flex-start;
gap: var(--space-xs);
padding: var(--space-sm) var(--space-md);
}
.agents-view-title {
flex: 0 0 auto;
gap: var(--space-xs);
flex-wrap: wrap;
white-space: nowrap;
min-width: 0;
}
.agents-view-title h2 {
display: block;
font-size: var(--space-lg);
line-height: 1;
}
/* Layout: compact title on the left, view-toggle right after it, then the
primary-actions group pinned to the far right of the row. The flex
container grows to fill remaining space, and `space-between` separates
the toggle (left side) from primary-actions (right side). */
.agents-view-controls {
flex: 1 1 auto;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--space-xs);
min-width: 0;
}
/* View toggle (List/Board/Tree/Org) — expand the pill and inner buttons to
the shared 36px mobile touch-target while preserving the compact grouped
chrome used elsewhere in the dashboard header. */
.agents-view-controls .view-toggle {
flex: 0 0 auto;
height: calc(var(--space-lg) * 2 + var(--space-sm));
padding: calc(var(--space-xs) / 2);
gap: calc(var(--space-xs) / 2);
}
.agents-view-controls .view-toggle .view-toggle-btn {
width: calc(var(--space-lg) * 2 + var(--space-xs));
height: calc(var(--space-lg) * 2 + var(--space-xs));
min-width: calc(var(--space-lg) * 2 + var(--space-xs));
min-height: calc(var(--space-lg) * 2 + var(--space-xs));
}
.agents-view-primary-actions {
display: flex;
align-items: center;
gap: var(--space-xs);
flex-wrap: nowrap;
flex: 0 0 auto;
}
/* Controls button: keep visible label on mobile with 36px touch target. */
.agent-controls-trigger {
padding: 0 var(--space-sm);
min-height: calc(var(--space-lg) * 2 + var(--space-xs));
font-size: var(--space-md);
display: inline-flex;
align-items: center;
justify-content: center;
}
.agents-view-primary-actions .btn-icon {
width: calc(var(--space-lg) * 2 + var(--space-xs));
height: calc(var(--space-lg) * 2 + var(--space-xs));
min-width: calc(var(--space-lg) * 2 + var(--space-xs));
min-height: calc(var(--space-lg) * 2 + var(--space-xs));
}
/* Title row: keep the Bot icon aligned with the compact control row. */
.agents-view-title {
height: calc(var(--space-lg) * 2);
align-items: center;
}
.agent-controls-mobile-actions .btn {
min-height: calc(var(--space-lg) * 2 + var(--space-xs));
}
.agent-controls-bulk-actions {
width: 100%;
}
.agents-org-full-view {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
.agents-split-layout {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
.agents-split-sidebar {
border-right: 0;
width: 100%;
flex: 1;
min-height: 0;
overflow: hidden;
}
.agents-split-sidebar--hidden-mobile {
display: none;
}
.agents-split-resize-handle {
display: none;
}
.agents-split-detail {
width: 100%;
height: 100%;
flex: 1;
min-height: 0;
overflow: hidden;
}
.agents-split-detail--hidden-mobile {
display: none;
}
.agents-view-content {
min-height: 0;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
padding: var(--space-md) var(--space-md) calc(var(--space-md) + env(safe-area-inset-bottom, 0px) + var(--standalone-bottom-gap));
}
}