Files
fusion/packages/dashboard/app/components/TaskCard.css
Fusion 54ed639e3d feat(FN-4566): unify task card tracking retry timing chips
Unified the task card tracking retry timing chips in the dashboard, refactoring the display logic and styling for consistency across task states. The CSS was significantly simplified while tests were expanded to cover the new chip behavior.

Fusion-Task-Id: FN-4566
2026-05-15 00:48:45 -07:00

1322 lines
29 KiB
CSS

/* === Cards === */
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: var(--card-padding);
cursor: grab;
transition:
background var(--transition-fast),
border-color var(--transition-fast),
transform var(--transition-fast),
opacity var(--transition-normal);
user-select: none;
touch-action: pan-x pan-y;
container-type: inline-size;
container-name: task-card;
}
.card:hover {
background: var(--card-hover);
border-color: var(--text-muted);
}
.card:focus-visible {
box-shadow: var(--focus-ring-strong);
border-color: var(--todo);
outline: none;
}
.card:active {
cursor: grabbing;
}
.card.dragging {
opacity: 0.4;
transform: scale(0.98);
}
.card.file-drop-target {
border: 2px dashed var(--todo);
background: color-mix(in srgb, var(--todo) 8%, transparent);
}
/* Agent-active glow: animated border glow when an agent is actively working on a task.
Uses the in-progress column color to stay consistent with the theme. */
.card.agent-active {
border-color: var(--in-progress);
box-shadow:
0 0 8px color-mix(in srgb, var(--in-progress) 40%, transparent),
0 0 20px color-mix(in srgb, var(--in-progress) 15%, transparent);
animation: agent-glow 2.5s ease-in-out infinite;
}
@keyframes agent-glow {
0%,
100% {
box-shadow:
0 0 8px color-mix(in srgb, var(--in-progress) 40%, transparent),
0 0 20px color-mix(in srgb, var(--in-progress) 15%, transparent);
}
50% {
box-shadow:
0 0 12px color-mix(in srgb, var(--in-progress) 60%, transparent),
0 0 28px color-mix(in srgb, var(--in-progress) 25%, transparent);
}
}
.card-header {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: var(--space-xs);
}
.card-id {
display: inline-block;
font-size: 0.6875rem;
font-weight: 600;
color: var(--text-muted);
font-family: var(--font-mono);
}
.card-title {
font-size: 0.8125rem;
line-height: 1.4;
word-break: break-word;
}
.card-branch-row {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: var(--space-xs);
margin-top: var(--space-xs);
}
.card-branch-chip {
display: inline-flex;
align-items: center;
min-width: 0;
gap: var(--space-xs);
padding: calc(var(--space-xs) / 4) calc(var(--space-sm) - (var(--space-xs) / 4));
border-radius: var(--radius-pill);
border: var(--btn-border-width) solid color-mix(in srgb, var(--text-muted) 35%, transparent);
background: color-mix(in srgb, var(--text-muted) 14%, transparent);
color: var(--text-muted);
font-size: 0.625rem;
}
.card-branch-label {
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
flex-shrink: 0;
}
.card-branch-value {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: var(--font-mono);
color: var(--text);
}
/* z-index + position: relative so .card-dep-badge tooltip renders above .card-title */
.card-meta {
display: flex;
align-items: center;
gap: var(--space-sm);
margin-top: var(--space-sm);
font-size: 0.6875rem;
color: var(--text-dim);
position: relative;
z-index: 1;
}
.card-retry-badge {
cursor: pointer;
}
.card-retry-badge:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
}
.card-retry-badge--warning {
color: var(--color-warning);
background: color-mix(in srgb, var(--color-warning) 14%, transparent);
border-color: color-mix(in srgb, var(--color-warning) 45%, transparent);
}
.card-retry-badge--error {
color: var(--color-error);
background: color-mix(in srgb, var(--color-error) 14%, transparent);
border-color: color-mix(in srgb, var(--color-error) 45%, transparent);
}
.card-status-badge,
.card-priority-badge,
.card-size-badge,
.card-no-commits-expected-badge {
display: inline-flex;
align-items: center;
font-size: 0.625rem;
font-weight: 600;
line-height: 1;
text-transform: uppercase;
padding: calc(var(--space-xs) / 2) var(--space-sm);
border: var(--btn-border-width) solid transparent;
border-radius: var(--radius-pill);
}
.card-status-badge {
letter-spacing: 0.5px;
}
.card-no-commits-expected-badge {
background: color-mix(in srgb, var(--text-muted) 18%, transparent);
border-color: color-mix(in srgb, var(--text-muted) 35%, transparent);
color: var(--text-muted);
text-transform: lowercase;
}
.card-status-badge.stalled-review {
background: color-mix(in srgb, var(--color-warning) 18%, transparent);
color: var(--color-warning);
border-color: color-mix(in srgb, var(--color-warning) 30%, transparent);
}
.card-stalled-review-reason {
margin-top: var(--space-xs);
font-size: 0.6875rem;
line-height: 1.4;
color: var(--text-muted);
overflow: hidden;
white-space: normal;
word-break: break-word;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
}
.card-status-badge--triage {
background: var(--status-triage-bg);
color: var(--triage);
}
.card-status-badge--todo {
background: var(--status-todo-bg);
color: var(--todo);
}
.card-status-badge--in-progress {
background: var(--status-in-progress-bg);
color: var(--in-progress);
}
.card-status-badge--in-review {
background: var(--status-in-review-bg);
color: var(--in-review);
}
.card-status-badge--done {
background: var(--status-done-bg);
color: var(--done);
}
.card-status-badge--archived {
background: var(--status-archived-bg);
color: var(--text-muted);
}
.card-status-badge.pulsing {
animation: pulse 1.5s ease-in-out infinite;
}
.card-status-badge.failed {
background: var(--status-error-bg);
color: var(--color-error-dark);
}
.card-status-badge.stuck {
background: var(--status-triage-bg-deep);
color: var(--triage);
animation: stuck-pulse 2s ease-in-out infinite;
}
.card-status-badge.in-review-stall {
background: color-mix(in srgb, var(--color-warning) 14%, transparent);
color: var(--color-warning);
border-color: color-mix(in srgb, var(--color-warning) 45%, transparent);
}
.card-status-badge.in-review-stall.in-review-stall--merge-retries-exhausted {
background: color-mix(in srgb, var(--color-error) 14%, transparent);
color: var(--color-error);
border-color: color-mix(in srgb, var(--color-error) 45%, transparent);
}
.card-status-badge.stale-paused-review {
background: color-mix(in srgb, var(--color-error) 14%, transparent);
color: var(--color-error);
border-color: color-mix(in srgb, var(--color-error) 45%, transparent);
}
.card-status-badge.card-task-age-staleness-badge--warning {
background: color-mix(in srgb, var(--color-warning) 14%, transparent);
color: var(--color-warning);
border-color: color-mix(in srgb, var(--color-warning) 45%, transparent);
}
.card-status-badge.card-task-age-staleness-badge--critical {
background: color-mix(in srgb, var(--color-error) 14%, transparent);
color: var(--color-error);
border-color: color-mix(in srgb, var(--color-error) 45%, transparent);
}
.card-status-badge.paused {
background: var(--status-done-bg-deep);
color: var(--text-muted);
}
.card-status-badge.awaiting-approval {
background: var(--status-triage-bg-deep);
color: var(--triage);
}
.card.stuck {
border-left: 3px solid var(--triage);
background: color-mix(in srgb, var(--triage) 6%, transparent);
}
@keyframes stuck-pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.65;
}
}
/* Size badge: positioned in card header, subtle color coding for effort estimation */
.card-size-badge {
letter-spacing: 0.5px;
}
/* Size S: subtle green tint (low effort) */
.card-size-badge.size-s {
background: color-mix(in srgb, var(--color-success) 15%, transparent);
color: var(--color-success);
}
/* Size M: neutral tint (medium effort) */
.card-size-badge.size-m {
background: color-mix(in srgb, var(--text-muted) 15%, transparent);
color: var(--text-muted);
}
/* Size L: subtle amber tint (higher effort) */
.card-size-badge.size-l {
background: color-mix(in srgb, var(--triage) 15%, transparent);
color: var(--triage);
}
.card-priority-badge {
letter-spacing: 0.4px;
}
.card-priority-badge--low {
background: color-mix(in srgb, var(--color-info) 15%, transparent);
color: var(--color-info);
}
.card-priority-badge--high {
background: color-mix(in srgb, var(--color-warning) 18%, transparent);
color: var(--color-warning);
}
.card-priority-badge--urgent {
background: color-mix(in srgb, var(--color-error) 20%, transparent);
color: var(--color-error-dark);
}
.card-execution-mode-badge {
display: inline-flex;
align-items: center;
justify-content: center;
width: 1rem;
height: 1rem;
border-radius: var(--radius-pill);
}
.card-execution-mode-badge svg {
width: 0.75rem;
height: 0.75rem;
}
.card-execution-mode-badge--fast {
background: color-mix(in srgb, var(--color-warning) 20%, transparent);
color: var(--color-warning);
}
.card.failed {
border-left: 3px solid var(--color-error-dark);
}
/* Error display on failed task cards */
.card-error {
display: flex;
align-items: flex-start;
gap: var(--space-xs);
margin: var(--space-xs) 0;
padding: var(--space-xs) var(--space-sm);
background: color-mix(in srgb, var(--color-error) 10%, transparent);
border: var(--btn-border-width) solid color-mix(in srgb, var(--color-error-dark) 25%, transparent);
border-radius: var(--radius-sm);
font-size: 0.6875rem;
color: var(--color-error-dark);
line-height: 1.4;
}
.card-error-icon {
flex-shrink: 0;
font-size: 0.75rem;
}
.card-error-text {
word-break: break-word;
}
.card-error-retry-btn {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
flex-shrink: 0;
min-height: 24px;
padding: var(--space-xs) calc(var(--space-sm) - (var(--space-xs) / 2));
border-radius: var(--radius-sm);
border-color: color-mix(in srgb, var(--color-error-dark) 20%, transparent);
background: color-mix(in srgb, var(--color-error) 10%, transparent);
color: var(--color-error-dark);
}
.card-error-retry-btn:hover:not(:disabled) {
background: color-mix(in srgb, var(--color-error) 16%, transparent);
}
.card-error-retry-btn:focus-visible {
box-shadow: var(--focus-ring-strong);
}
.card-error-retry-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
@media (max-width: 768px) {
.card-error-retry-btn {
min-height: 36px;
}
}
/* Awaiting manual plan approval: amber left border + subtle pulsing background to signal human review needed.
Distinct from agent-active (purple glow), failed (red left border + error block), and paused (dimmed opacity). */
.card.awaiting-approval {
border-left: 3px solid var(--triage);
background: color-mix(in srgb, var(--triage) 6%, transparent);
animation: approval-pulse 3s ease-in-out infinite;
}
@keyframes approval-pulse {
0%,
100% {
background: color-mix(in srgb, var(--triage) 6%, transparent);
}
50% {
background: color-mix(in srgb, var(--triage) 12%, transparent);
}
}
.card.paused {
opacity: 0.55;
border-left: 3px solid var(--text-muted);
cursor: default;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.card-dep-badge {
display: inline-flex;
align-items: center;
gap: 3px;
font-size: 0.6875rem;
color: var(--triage);
position: relative;
cursor: default;
}
.card-dep-badge.clickable {
cursor: pointer;
transition: color var(--transition-fast), text-decoration var(--transition-fast);
}
.card-dep-badge.clickable:hover {
color: var(--todo);
text-decoration: underline;
}
.card-dep-list {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-xs);
}
.card-scope-badge {
display: inline-flex;
align-items: center;
gap: 3px;
font-size: 0.6875rem;
color: var(--in-progress);
position: relative;
cursor: default;
}
.card-fanout-badge {
display: inline-flex;
align-items: center;
gap: calc(var(--space-xs) / 2);
font-size: 0.6875rem;
position: relative;
cursor: default;
}
.card-fanout-count {
font-family: var(--font-mono);
}
.card-fanout-badge--stale {
color: var(--color-warning);
background: color-mix(in srgb, var(--color-warning) 12%, transparent);
border-radius: var(--radius-pill);
padding-inline: calc(var(--space-xs) / 2);
}
.card-scope-badge[data-tooltip]:hover::after,
.card-fanout-badge[data-tooltip]:hover::after {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: var(--card);
color: var(--text);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: var(--space-xs) var(--space-sm);
font-size: 0.6875rem;
white-space: nowrap;
z-index: 10;
pointer-events: none;
margin-bottom: var(--space-xs);
box-shadow: var(--shadow-md);
}
/* Mission badge: clickable link to mission from task card */
.card-mission-badge {
display: inline-flex;
align-items: center;
gap: 3px;
font-size: 0.625rem;
font-weight: 600;
font-family: var(--font-mono);
color: var(--badge-mission-text);
background: var(--badge-mission-bg);
padding: 2px 6px;
border-radius: var(--radius-pill);
cursor: pointer;
transition: color var(--transition-fast), background var(--transition-fast);
max-width: 110px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-mission-badge:hover {
color: var(--badge-mission-text-hover);
background: var(--badge-mission-bg-hover);
}
.card-agent-row {
display: flex;
align-items: center;
gap: var(--space-xs);
margin-top: var(--space-xs);
}
.card-bottom-row {
margin-top: var(--space-sm);
}
.card-bottom-left-row {
display: flex;
align-items: center;
min-width: 0;
}
.card-bottom-left-row:focus-within .card-send-back-btn {
opacity: 1;
}
.card-provider-icons {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
flex-shrink: 0;
}
.card-provider-icons .provider-icon {
display: inline-flex;
align-items: center;
}
.card-agent-badge {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
font-size: 0.625rem;
font-weight: 600;
color: var(--text-muted);
background: color-mix(in srgb, var(--text-muted) 18%, transparent);
border: var(--btn-border-width) solid color-mix(in srgb, var(--text-muted) 35%, transparent);
padding: calc(var(--space-xs) / 4) calc(var(--space-sm) - (var(--space-xs) / 4));
border-radius: var(--radius-pill);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-agent-created-badge {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
font-size: 0.625rem;
font-weight: 600;
color: var(--text-muted);
background: color-mix(in srgb, var(--text-muted) 18%, transparent);
border: var(--btn-border-width) solid color-mix(in srgb, var(--text-muted) 35%, transparent);
padding: calc(var(--space-xs) / 4) calc(var(--space-sm) - (var(--space-xs) / 4));
border-radius: var(--radius-pill);
line-height: 1;
}
.card-agent-badge-text {
min-width: 0;
flex: 0 1 auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@container task-card (max-width: 240px) {
.card-agent-badge-text {
display: none;
}
}
@media (max-width: 768px) {
.card-agent-badge-text {
display: none;
}
}
.card-agent-badge--loading {
animation: pulse 1.5s ease-in-out infinite;
}
.card-progress {
display: flex;
align-items: center;
gap: var(--space-sm);
margin-top: var(--space-sm);
}
.card-footer-row {
display: flex;
align-items: center;
gap: var(--space-sm);
margin-top: var(--space-sm);
min-width: 0;
flex-wrap: nowrap;
}
.card-session-files {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 0;
border: none;
background: transparent;
color: var(--text-muted);
font-size: 0.75rem;
cursor: pointer;
min-width: 0;
flex: 1 1 auto;
overflow: hidden;
}
.card-session-files svg {
flex-shrink: 0;
}
.card-session-files span {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-session-files:hover {
color: var(--text);
}
.card-session-files:disabled {
cursor: default;
opacity: 0.7;
}
.card-source-provenance {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--text-muted);
}
.card-footer-row > .card-source-provenance:first-of-type {
margin-left: auto;
}
.card-source-provenance + .card-source-provenance {
margin-left: 0;
}
.card-source-provenance .provider-icon {
display: inline-flex;
align-items: center;
}
.card-time-indicator,
.card-github-tracking-chip,
.card-retry-badge {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
flex-shrink: 0;
padding: var(--space-xs) var(--space-sm);
height: var(--card-chip-height);
min-height: var(--card-chip-height);
border: var(--btn-border-width) solid transparent;
border-radius: var(--radius-pill);
font-size: 0.6875rem;
font-weight: 600;
font-family: var(--font-mono);
line-height: 1;
white-space: nowrap;
}
.card-github-tracking-chip {
border-color: color-mix(in srgb, var(--text-muted) 30%, transparent);
background: color-mix(in srgb, var(--text-muted) 12%, transparent);
color: var(--text-muted);
text-decoration: none;
transition:
background-color var(--transition-fast),
color var(--transition-fast),
box-shadow var(--transition-fast);
}
.card-github-tracking-chip:hover {
background: var(--card-hover);
color: var(--text);
}
.card-github-tracking-chip:focus-visible {
box-shadow: var(--focus-ring-strong);
outline: none;
}
.card-github-tracking-link {
text-decoration: none;
}
.card-time-indicator {
margin-left: auto;
border-color: color-mix(in srgb, var(--text-muted) 30%, transparent);
background: color-mix(in srgb, var(--text-muted) 12%, transparent);
color: var(--text-muted);
}
.card-github-tracking-chip .provider-icon svg {
width: 12px;
height: 12px;
}
.card-progress-bar {
flex: 1;
height: 3px;
background: var(--border);
border-radius: 2px;
overflow: hidden;
}
.card-progress-fill {
height: 100%;
border-radius: 2px;
transition: width 0.3s;
}
.card-progress-label {
font-size: 0.6875rem;
font-weight: 600;
color: var(--text-muted);
font-family: var(--font-mono);
flex-shrink: 0;
}
/* Steps toggle and list */
.card-steps-toggle {
display: flex;
align-items: center;
gap: var(--space-xs);
margin-top: 6px;
min-height: calc(var(--space-xl) + var(--space-md));
padding: var(--space-xs) 0;
background: none;
border: none;
cursor: pointer;
font-size: 0.6875rem;
color: var(--text-muted);
transition: color var(--transition-fast);
}
.card-steps-toggle:hover {
color: var(--text);
}
.card-steps-toggle:focus-visible {
box-shadow: var(--focus-ring-strong);
border-radius: var(--radius-sm);
}
.card-steps-toggle-icon {
transition: transform var(--transition-normal);
}
.card-steps-toggle-icon.expanded {
transform: rotate(180deg);
}
.card-steps-list {
display: flex;
flex-direction: column;
gap: var(--space-xs);
margin-top: var(--space-sm);
max-height: 200px;
overflow-y: auto;
}
.card-step-item {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.75rem;
}
.card-step-dot {
width: 6px;
height: 6px;
border-radius: 50%;
flex-shrink: 0;
}
.card-step-dot--pending {
background: var(--border);
}
.card-step-dot--in-progress {
background: var(--todo);
}
.card-step-dot--done {
background: var(--color-success);
}
.card-step-dot--skipped {
background: var(--text-dim);
}
.card-step-dot--failed {
background: var(--color-error-dark);
}
.card-step-dot--workflow-failed {
background: var(--ws-warning);
}
.card-step-name {
flex: 1;
min-width: 0;
color: var(--text-muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-step-name.completed {
text-decoration: line-through;
opacity: 0.6;
}
.card-step-workflow-badge {
margin-left: auto;
padding: 0 var(--space-xs);
border-radius: var(--radius-pill);
border: 1px solid var(--border);
font-size: 0.5625rem;
color: var(--text-muted);
background: var(--surface);
white-space: nowrap;
}
.card-step-workflow-badge--pre-merge {
color: var(--in-review);
background: var(--status-in-review-bg);
border-color: color-mix(in srgb, var(--in-review) 35%, var(--border));
}
.card-step-workflow-badge--post-merge {
color: var(--done);
background: var(--status-done-bg);
border-color: color-mix(in srgb, var(--done) 35%, var(--border));
}
/* Animation for initializing spinner */
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.animate-spin {
animation: spin 1s linear infinite;
}
/* === Card Inline Editing === */
/* Card in edit mode - highlighted border matching column theme */
.card.card-editing {
border: 1px solid var(--todo);
border-left: 3px solid var(--todo);
background: var(--card);
cursor: default;
}
.card.card-editing[data-column="triage"] {
border-color: var(--triage);
border-left-color: var(--triage);
}
.card.card-editing[data-column="todo"] {
border-color: var(--todo);
border-left-color: var(--todo);
}
/* Edit content container */
.card-editing-content {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
/* Description textarea in edit mode - follows InlineCreateCard patterns */
.card-edit-desc-textarea {
width: 100%;
padding: 6px 8px;
background: transparent;
border: 1px solid transparent;
color: var(--text);
font-size: 0.8125rem;
font-family: inherit;
outline: none;
resize: none;
overflow: hidden;
line-height: 1.4;
min-height: 80px;
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.card-edit-desc-textarea:focus {
border-color: var(--todo);
box-shadow: var(--focus-ring);
border-radius: var(--radius-sm);
}
.card-edit-desc-textarea::placeholder {
color: var(--text-dim);
}
.card-edit-desc-textarea:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* Card header actions container - groups size badge and buttons on the right */
.card-header-actions {
display: flex;
align-items: center;
gap: 6px;
margin-left: auto;
}
/* Edit button - visible on hover */
.card-edit-btn {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
padding: 0;
background: transparent;
border: none;
border-radius: var(--radius-sm);
color: var(--text-muted);
cursor: pointer;
opacity: 0;
transition: opacity var(--transition-fast), background var(--transition-fast),
color var(--transition-fast);
}
.card:hover .card-edit-btn {
opacity: 1;
}
.card-edit-btn:hover {
background: var(--border);
color: var(--text);
}
.card-edit-btn:focus {
opacity: 1;
outline: 1px solid var(--todo);
outline-offset: 1px;
}
/* Delete button - visible on hover for triage column */
.card-delete-btn {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
padding: 0;
background: transparent;
border: none;
border-radius: var(--radius-sm);
color: var(--text-muted);
cursor: pointer;
opacity: 0;
transition: opacity var(--transition-fast), color var(--transition-fast);
}
.card:hover .card-delete-btn {
opacity: 1;
}
.card-delete-btn:hover {
color: var(--color-error);
}
.card-delete-btn:focus {
outline: 2px solid var(--accent);
outline-offset: 1px;
opacity: 1;
}
/* Archive/Unarchive buttons */
.card-archive-btn,
.card-unarchive-btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: calc(var(--space-xs) / 4)
calc(var(--space-sm) - (var(--space-xs) / 2));
margin-left: var(--space-xs);
font-size: 0.625rem;
font-weight: 500;
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text-muted);
cursor: pointer;
opacity: 0;
transition: opacity var(--transition-fast), background var(--transition-fast),
color var(--transition-fast), border-color var(--transition-fast);
}
.card:hover .card-archive-btn,
.card:hover .card-unarchive-btn {
opacity: 1;
}
.card-archive-btn:hover,
.card-unarchive-btn:hover {
background: var(--card-hover);
color: var(--text);
border-color: var(--border-hover);
}
.card-archive-btn:focus,
.card-unarchive-btn:focus {
opacity: 1;
outline: 1px solid var(--todo);
outline-offset: 1px;
}
/* Send Back button and dropdown */
.card-send-back {
position: relative;
}
.card-send-back-btn {
display: inline-flex;
align-items: center;
gap: calc(var(--space-xs) / 2);
padding: calc(var(--space-xs) / 4)
calc(var(--space-sm) - (var(--space-xs) / 2));
margin-left: var(--space-xs);
font-size: 0.625rem;
font-weight: 500;
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text-muted);
cursor: pointer;
opacity: 0;
transition: opacity var(--transition-fast), background var(--transition-fast),
color var(--transition-fast), border-color var(--transition-fast);
}
.card:hover .card-send-back-btn {
opacity: 1;
}
.card-send-back-btn:hover {
background: var(--card-hover);
color: var(--text);
border-color: var(--border-hover);
}
.card-send-back-btn:focus {
opacity: 1;
outline: 1px solid var(--todo);
outline-offset: 1px;
}
.card-send-back-menu {
position: absolute;
top: calc(100% + var(--space-xs));
right: 0;
z-index: 50;
min-width: 100px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-md);
overflow: hidden;
}
.card-bottom-left-row .card-send-back-menu {
top: auto;
right: auto;
bottom: calc(100% + var(--space-xs));
left: 0;
}
.card-send-back-menu-item {
display: block;
width: 100%;
padding: calc(var(--space-sm) - (var(--space-xs) / 4)) var(--space-md);
font-size: 0.75rem;
font-weight: 400;
color: var(--text);
background: transparent;
border: none;
cursor: pointer;
text-align: left;
transition: background var(--transition-instant);
}
.card-send-back-menu-item:hover {
background: var(--surface-hover, color-mix(in srgb, var(--text) 6%, transparent));
}
.card-send-back-menu-item:focus {
outline: none;
background: var(--surface-hover, color-mix(in srgb, var(--text) 6%, transparent));
}
/* Loading state during save */
.card-edit-loading {
display: flex;
align-items: center;
gap: var(--space-sm);
margin-top: var(--space-xs);
font-size: 0.6875rem;
color: var(--text-muted);
}
.card-edit-loading-spinner {
width: 12px;
height: 12px;
border: 2px solid var(--border);
border-top-color: var(--todo);
border-radius: 50%;
animation: spin 1s linear infinite;
}
.card-edit-loading-text {
font-size: 0.6875rem;
color: var(--text-muted);
}
/* === Mobile Responsive Overrides === */
@media (max-width: 768px) {
/* Card edit button: always visible on mobile (no hover) */
.card-edit-btn {
opacity: 1;
width: 28px;
height: 28px;
margin: -6px -6px -6px 0;
border-radius: var(--radius-md);
}
.card-edit-btn svg {
width: 16px;
height: 16px;
}
/* Card delete button: always visible on mobile (no hover) */
.card-delete-btn {
opacity: 1;
width: 28px;
height: 28px;
margin: -6px -6px -6px 0;
border-radius: var(--radius-md);
}
.card-delete-btn svg {
width: 16px;
height: 16px;
}
/* FN-4365/FN-4351: keep secondary actions compact and inline with the header title row on mobile. */
.card-header-actions {
gap: 4px;
flex-shrink: 0;
}
/* FN-4351/FN-3965: keep secondary actions visible on touch, but compact per WCAG 2.5.8 because the card tap surface is the primary target for opening task detail. */
.card-archive-btn,
.card-unarchive-btn {
opacity: 1;
}
.card-send-back-btn {
opacity: 1;
}
/* Card: compact progress bar on narrow cards */
.card-progress {
gap: var(--space-xs);
}
.card-progress-label {
font-size: 0.625rem;
min-width: 30px;
}
.card-steps-toggle {
padding: var(--space-xs) 0;
}
.card-footer-row {
margin-top: var(--space-xs);
gap: var(--space-xs);
}
.card-time-indicator,
.card-github-tracking-chip,
.card-retry-badge {
padding: var(--space-xs) var(--space-sm);
font-size: 0.625rem;
height: var(--card-chip-height-mobile);
min-height: var(--card-chip-height-mobile);
}
.card-bottom-row {
margin-top: var(--space-xs);
}
/* Card: smaller status badges for 280px width */
.card-status-badge,
.card-priority-badge,
.card-size-badge {
font-size: 0.5625rem;
padding: calc(var(--space-xs) / 4) calc((var(--space-xs) * 3) / 2);
}
.card-stalled-review-reason {
font-size: 0.625rem;
-webkit-line-clamp: 3;
line-clamp: 3;
}
.card-mission-badge {
max-width: 80px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-agent-created-badge {
font-size: 0.5625rem;
padding: calc(var(--space-xs) / 4) var(--space-sm);
}
.card-branch-row {
gap: calc(var(--space-xs) / 2);
}
.card-branch-chip {
max-width: 100%;
}
.card-branch-value {
max-width: 18ch;
}
/* Card: wrap dependency badges */
.card-dep-list {
flex-wrap: wrap;
}
}