refactor(theme): remove 184 var() fallbacks — every one was unreachable
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 16s
CI & Build / integration (push) Successful in 23s
CI & Build / TypeScript typecheck (push) Successful in 25s
CI & Build / Python tests (push) Successful in 57s
CI & Build / Build & push image (push) Successful in 43s

#2277 counted ~150 "raw colour literals bypassing the tokens". Measuring them
told a different story: 184 sat in `var(--token, #fallback)` position, and a
check against theme.css shows every one of those tokens IS declared. So the
fallbacks could not render. Not drift — vestigial.

They were also not this palette. The most common were Tailwind and Flat-UI
defaults — #6366f1 indigo, #22c55e green, #f59e0b amber, #3b82f6 blue,
#e74c3c and #27ae60 — a second, unsanctioned colour scheme sitting in the
codebase looking like the app's colours to anyone reading it.

Removing them is not tidying. #2319's lesson is that a fallback is WORSE than a
missing token: a missing token renders as nothing and someone eventually
notices, while a fallback renders something plausible forever. These 184 were
one token rename away from silently repainting the app in Tailwind. The design
token check would catch the rename — but the fallback is precisely the thing
that would make it invisible if the check were ever bypassed.

Literal count 152 -> 45, which matters beyond the number: a report that is
mostly unreachable noise is one people stop reading, and then it stops working
while still passing. What remains should be genuinely worth looking at.

Done with a paren-aware transform, not a regex — `var(--x, rgba(0,0,0,.5))`
nests parens and `[^)]+` would cut at the first one and leave `))` behind.
Verified after: every changed line is a fallback strip and nothing else, and
every var() reference still resolves.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs
This commit is contained in:
2026-08-03 11:52:04 -04:00
co-authored by Claude Opus 5
parent 174ec8af46
commit bd60d679d9
33 changed files with 176 additions and 176 deletions
+2 -2
View File
@@ -600,7 +600,7 @@ onUnmounted(() => {
.graph-page {
display: flex;
flex-direction: column;
height: calc(100vh - var(--header-height, 52px));
height: calc(100vh - var(--header-height));
overflow: hidden;
}
@@ -750,7 +750,7 @@ onUnmounted(() => {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
box-shadow: 0 4px 16px var(--color-shadow, rgba(0, 0, 0, 0.15));
box-shadow: 0 4px 16px var(--color-shadow);
padding: 0.5rem 0.75rem;
pointer-events: none;
z-index: 10;
+13 -13
View File
@@ -490,7 +490,7 @@ onUnmounted(() => {
.knowledge-root {
display: flex;
flex-direction: column;
height: calc(100vh - var(--header-height, 56px));
height: calc(100vh - var(--header-height));
overflow: hidden;
}
@@ -502,7 +502,7 @@ onUnmounted(() => {
gap: 12px;
padding: 8px 20px;
background: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border, rgba(255,255,255,0.06));
border-bottom: 1px solid var(--color-border);
flex-shrink: 0;
font-size: 0.82rem;
flex-wrap: wrap;
@@ -539,7 +539,7 @@ onUnmounted(() => {
width: var(--sidebar-width);
flex-shrink: 0;
padding: 16px 12px;
border-right: 1px solid var(--color-border, rgba(255,255,255,0.06));
border-right: 1px solid var(--color-border);
overflow-y: auto;
background: var(--color-bg-secondary);
}
@@ -683,7 +683,7 @@ onUnmounted(() => {
gap: 10px;
padding: 12px 20px;
flex-shrink: 0;
border-bottom: 1px solid var(--color-border, rgba(255,255,255,0.06));
border-bottom: 1px solid var(--color-border);
}
.search-wrap {
flex: 1;
@@ -701,8 +701,8 @@ onUnmounted(() => {
width: 100%;
padding: 7px 12px 7px 32px;
border-radius: 8px;
border: 1px solid var(--color-border, rgba(255,255,255,0.1));
background: var(--color-bg-tertiary, rgba(255,255,255,0.04));
border: 1px solid var(--color-border);
background: var(--color-bg-tertiary);
color: var(--color-text);
font-size: 0.88rem;
outline: none;
@@ -712,8 +712,8 @@ onUnmounted(() => {
.sort-select {
padding: 7px 10px;
border-radius: 8px;
border: 1px solid var(--color-border, rgba(255,255,255,0.1));
background: var(--color-bg-tertiary, rgba(255,255,255,0.04));
border: 1px solid var(--color-border);
background: var(--color-bg-tertiary);
color: var(--color-text);
font-size: 0.85rem;
cursor: pointer;
@@ -735,9 +735,9 @@ onUnmounted(() => {
.k-card {
position: relative;
background: var(--color-surface, rgba(255,255,255,0.03));
border: 1px solid var(--color-border, rgba(255,255,255,0.07));
border-radius: var(--radius-lg, 14px);
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: 14px;
cursor: pointer;
transition: border-color 0.15s, transform 0.12s, box-shadow 0.15s;
@@ -917,7 +917,7 @@ onUnmounted(() => {
.graph-panel {
width: 500px;
flex-shrink: 0;
border-left: 1px solid var(--color-border, rgba(255,255,255,0.06));
border-left: 1px solid var(--color-border);
display: flex;
flex-direction: column;
background: var(--color-bg-secondary);
@@ -933,7 +933,7 @@ onUnmounted(() => {
padding: 10px 14px;
font-size: 0.85rem;
font-weight: 500;
border-bottom: 1px solid var(--color-border, rgba(255,255,255,0.06));
border-bottom: 1px solid var(--color-border);
flex-shrink: 0;
}
/* Override GraphView's 100vh height so it fills the panel instead */
+3 -3
View File
@@ -709,8 +709,8 @@ onUnmounted(() => assist.clearSelection());
width: 100%;
padding: 5px 8px;
border-radius: var(--radius-sm);
border: 1px solid var(--color-input-border, rgba(255,255,255,0.12));
background: var(--color-bg-tertiary, rgba(255,255,255,0.04));
border: 1px solid var(--color-input-border);
background: var(--color-bg-tertiary);
color: var(--color-text);
font-size: 0.82rem;
font-family: inherit;
@@ -822,7 +822,7 @@ onUnmounted(() => assist.clearSelection());
background: var(--color-surface);
color: var(--color-text);
/* Prompts are plain markdown — a code-style editor, not rich text. */
font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
font-family: var(--font-mono);
font-size: 0.88rem;
line-height: 1.55;
tab-size: 2;
+1 -1
View File
@@ -563,7 +563,7 @@ function overallPct(project: Project): { total: number; pct: number } {
.modal-overlay {
position: fixed;
inset: 0;
background: var(--color-overlay, rgba(0,0,0,0.45));
background: var(--color-overlay);
display: flex;
align-items: center;
justify-content: center;
+12 -12
View File
@@ -847,9 +847,9 @@ async function confirmDelete() {
}
.page-header-actions { display: flex; gap: 0.5rem; align-items: center; }
.plan-title-input {
background: var(--color-bg, #111113);
background: var(--color-bg);
color: inherit;
border: 1px solid var(--color-border, #2a2a2e);
border: 1px solid var(--color-border);
border-radius: 6px;
padding: 0.4rem 0.6rem;
font: inherit;
@@ -932,8 +932,8 @@ async function confirmDelete() {
flex-shrink: 0;
}
.dot-todo { background: transparent; border: 2px solid var(--color-text-muted); }
.dot-inprogress { background: var(--color-status-in-progress, #3b82f6); }
.dot-done { background: var(--color-status-done, #22c55e); }
.dot-inprogress { background: var(--color-status-in-progress); }
.dot-done { background: var(--color-status-done); }
.stat-todo { background: color-mix(in srgb, var(--color-text-muted) 8%, transparent); color: var(--color-text-secondary); border-color: var(--color-border); }
.stat-inprogress { background: color-mix(in srgb, #3b82f6 10%, transparent); color: #3b82f6; border-color: color-mix(in srgb, #3b82f6 28%, transparent); }
@@ -1066,7 +1066,7 @@ async function confirmDelete() {
.ms-plan-rendered:hover { background: color-mix(in srgb, var(--color-primary) 4%, transparent); }
.ms-plan-editor {
width: 100%;
font-family: var(--font-mono, monospace);
font-family: var(--font-mono);
font-size: 0.8rem;
line-height: 1.5;
padding: 0.5rem;
@@ -1133,7 +1133,7 @@ async function confirmDelete() {
border-radius: var(--radius-sm);
}
.ms-action-btn:hover { background: var(--color-bg-card); color: var(--color-text); }
.ms-action-delete:hover { color: var(--color-danger, #e74c3c); }
.ms-action-delete:hover { color: var(--color-danger); }
.ms-rename-input {
flex: 1;
@@ -1168,8 +1168,8 @@ async function confirmDelete() {
border-top: 3px solid;
}
.col-todo { border-top-color: var(--color-border); }
.col-inprogress { border-top-color: var(--color-status-in-progress, #3b82f6); }
.col-done { border-top-color: var(--color-status-done, #22c55e); }
.col-inprogress { border-top-color: var(--color-status-in-progress); }
.col-done { border-top-color: var(--color-status-done); }
.kanban-col-header {
display: flex;
@@ -1230,7 +1230,7 @@ async function confirmDelete() {
transform: translateY(-2px);
}
/* Priority left-border colors */
.task-card.pri-high { border-left-color: var(--color-danger, #e74c3c); }
.task-card.pri-high { border-left-color: var(--color-danger); }
.task-card.pri-medium { border-left-color: #f59e0b; }
.task-card.pri-low { border-left-color: var(--color-success); }
@@ -1256,7 +1256,7 @@ async function confirmDelete() {
}
.task-card:hover .task-advance-btn { opacity: 1; }
.task-advance-btn:hover { background: var(--color-action-primary); border-color: var(--color-action-primary); color: var(--fs-text-on-action); }
.task-advance-btn--done:hover { background: var(--color-success, #22c55e); border-color: var(--color-success, #22c55e); color: var(--fs-text-on-action); }
.task-advance-btn--done:hover { background: var(--color-success); border-color: var(--color-success); color: var(--fs-text-on-action); }
.task-advance-btn:disabled { opacity: 0.4; cursor: default; }
.priority-dot {
@@ -1265,7 +1265,7 @@ async function confirmDelete() {
border-radius: 50%;
flex-shrink: 0;
}
.dot-pri-high { background: var(--color-danger, #e74c3c); }
.dot-pri-high { background: var(--color-danger); }
.dot-pri-medium { background: #f59e0b; }
.dot-pri-low { background: var(--color-success); }
@@ -1310,7 +1310,7 @@ async function confirmDelete() {
/* ── Modal ───────────────────────────────────────────────────── */
.modal-overlay {
position: fixed; inset: 0;
background: var(--color-overlay, rgba(0,0,0,0.45));
background: var(--color-overlay);
display: flex; align-items: center; justify-content: center;
z-index: 200;
}
+2 -2
View File
@@ -107,10 +107,10 @@ watch(() => route.query, syncFromRoute);
grid-template-columns: 280px 300px 1fr;
height: 100vh;
gap: 1px;
background: var(--color-border, #2a2a2e);
background: var(--color-border);
}
.pane.empty {
background: var(--color-surface, #18181b);
background: var(--color-surface);
padding: 1rem;
opacity: 0.6;
font-style: italic;
+10 -10
View File
@@ -2789,11 +2789,11 @@ function formatUserDate(iso: string): string {
color: var(--color-text-muted);
}
.perm-granted { background: color-mix(in srgb, var(--color-success) 15%, transparent); color: var(--color-success); }
.perm-denied { background: color-mix(in srgb, var(--color-danger, #e74c3c) 15%, transparent); color: var(--color-danger, #e74c3c); }
.perm-denied { background: color-mix(in srgb, var(--color-danger) 15%, transparent); color: var(--color-danger); }
.sub-active { background: color-mix(in srgb, var(--color-success) 15%, transparent); color: var(--color-success); }
.push-error {
font-size: 0.82rem;
color: var(--color-danger, #e74c3c);
color: var(--color-danger);
margin: 0.25rem 0 0;
}
@@ -3048,7 +3048,7 @@ function formatUserDate(iso: string): string {
.group-card {
border: 1px solid var(--color-border);
border-radius: var(--radius-md, 8px);
border-radius: var(--radius-md);
overflow: hidden;
}
@@ -3166,7 +3166,7 @@ function formatUserDate(iso: string): string {
padding: 0.15rem 0.4rem;
border-radius: 4px;
}
.role-owner { background: color-mix(in srgb, var(--color-warning, #f59e0b) 15%, transparent); color: var(--color-warning, #f59e0b); }
.role-owner { background: color-mix(in srgb, var(--color-warning) 15%, transparent); color: var(--color-warning); }
.role-member { background: color-mix(in srgb, var(--color-muted) 15%, transparent); color: var(--color-muted); }
.members-empty {
@@ -3278,7 +3278,7 @@ function formatUserDate(iso: string): string {
}
.api-key-value {
flex: 1;
background: var(--color-surface-2, var(--color-surface));
background: var(--color-surface-2);
padding: 0.4rem 0.6rem;
border-radius: var(--radius-sm);
font-size: 0.85rem;
@@ -3396,7 +3396,7 @@ function formatUserDate(iso: string): string {
.mcp-code-row .btn-sm { white-space: nowrap; }
.mcp-advanced {
margin-top: 1.25rem;
border-top: 1px solid var(--color-border, rgba(255, 255, 255, 0.1));
border-top: 1px solid var(--color-border);
padding-top: 0.75rem;
}
.mcp-advanced summary {
@@ -3470,7 +3470,7 @@ function formatUserDate(iso: string): string {
flex: 1;
}
.voice-library-id {
font-family: var(--font-mono, monospace);
font-family: var(--font-mono);
font-size: 0.9rem;
font-weight: 500;
}
@@ -3511,9 +3511,9 @@ function formatUserDate(iso: string): string {
border-radius: 999px;
}
.status-on {
background: color-mix(in srgb, var(--color-success, #22c55e) 15%, transparent);
color: var(--color-success, #22c55e);
border: 1px solid color-mix(in srgb, var(--color-success, #22c55e) 40%, transparent);
background: color-mix(in srgb, var(--color-success) 15%, transparent);
color: var(--color-success);
border: 1px solid color-mix(in srgb, var(--color-success) 40%, transparent);
}
.status-off {
background: color-mix(in srgb, var(--color-text-muted) 10%, transparent);
+1 -1
View File
@@ -244,7 +244,7 @@ onMounted(async () => {
}
.perm-viewer { background: color-mix(in srgb, var(--color-muted) 15%, transparent); color: var(--color-muted); }
.perm-editor { background: color-mix(in srgb, var(--color-primary) 15%, transparent); color: var(--color-primary); }
.perm-admin { background: color-mix(in srgb, var(--color-warning, #f59e0b) 15%, transparent); color: var(--color-warning, #f59e0b); }
.perm-admin { background: color-mix(in srgb, var(--color-warning) 15%, transparent); color: var(--color-warning); }
.empty-msg {
color: var(--color-muted);
+3 -3
View File
@@ -239,7 +239,7 @@ async function confirmDelete() {
}
.snippet-name {
margin: 0;
font-family: var(--font-mono, ui-monospace, "JetBrains Mono", monospace);
font-family: var(--font-mono);
font-size: 1.4rem;
word-break: break-word;
}
@@ -291,7 +291,7 @@ async function confirmDelete() {
}
.meta-grid code,
.tag-row + * code {
font-family: var(--font-mono, ui-monospace, "JetBrains Mono", monospace);
font-family: var(--font-mono);
font-size: 0.82rem;
background: color-mix(in srgb, var(--color-primary) 12%, transparent);
color: var(--color-primary);
@@ -379,7 +379,7 @@ async function confirmDelete() {
overflow-x: auto;
}
.code-block code {
font-family: var(--font-mono, ui-monospace, "JetBrains Mono", monospace);
font-family: var(--font-mono);
font-size: 0.85rem;
line-height: 1.6;
color: var(--color-text);
+2 -2
View File
@@ -447,7 +447,7 @@ function cancel() {
box-shadow: var(--focus-ring);
}
.mono {
font-family: var(--font-mono, ui-monospace, "JetBrains Mono", monospace);
font-family: var(--font-mono);
}
.code-area {
resize: vertical;
@@ -542,7 +542,7 @@ function cancel() {
gap: 0.4rem;
padding: 0.85rem 1rem;
border: 1px solid var(--color-border);
border-left: 3px solid var(--color-warning, var(--color-primary));
border-left: 3px solid var(--color-warning);
border-radius: 8px;
background: var(--color-bg-secondary);
}
+10 -10
View File
@@ -574,7 +574,7 @@ function usageTitle(s: SnippetListItem): string {
background: var(--color-bg);
color: var(--color-text);
font-size: 0.85rem;
font-family: var(--font-mono, ui-monospace, "JetBrains Mono", monospace);
font-family: var(--font-mono);
box-sizing: border-box;
}
.loc-input-wide {
@@ -633,7 +633,7 @@ function usageTitle(s: SnippetListItem): string {
color: var(--color-text-muted);
}
.empty-icon {
font-family: var(--font-mono, ui-monospace, "JetBrains Mono", monospace);
font-family: var(--font-mono);
font-size: 2rem;
margin-bottom: 0.75rem;
opacity: 0.35;
@@ -720,7 +720,7 @@ function usageTitle(s: SnippetListItem): string {
min-width: 0;
flex: 1;
word-break: break-word;
font-family: var(--font-mono, ui-monospace, "JetBrains Mono", monospace);
font-family: var(--font-mono);
}
/* Language tag — accent pill per the design system's tag treatment. */
@@ -770,7 +770,7 @@ function usageTitle(s: SnippetListItem): string {
padding: 0.85rem 1rem;
border: 1px solid var(--color-border);
border-radius: 8px;
background: var(--color-surface-alt, var(--color-surface));
background: var(--color-surface-alt);
}
.dup-empty,
@@ -828,8 +828,8 @@ function usageTitle(s: SnippetListItem): string {
padding: 0.1rem 0.4rem;
border-radius: 4px;
white-space: nowrap;
background: color-mix(in srgb, var(--color-danger, #b91c1c) 15%, transparent);
color: var(--color-danger, #b91c1c);
background: color-mix(in srgb, var(--color-danger) 15%, transparent);
color: var(--color-danger);
}
.usage-tag {
@@ -845,8 +845,8 @@ function usageTitle(s: SnippetListItem): string {
/* Dead weight is a nudge, not an error — it warns in the warning colour rather
than the danger one, because the record isn't broken, just unearned. */
.usage-tag.usage-dead {
background: color-mix(in srgb, var(--color-warning, #b45309) 18%, transparent);
color: var(--color-warning, #b45309);
background: color-mix(in srgb, var(--color-warning) 18%, transparent);
color: var(--color-warning);
}
/* Header + select-mode */
@@ -906,7 +906,7 @@ function usageTitle(s: SnippetListItem): string {
.modal-overlay {
position: fixed;
inset: 0;
background: var(--color-overlay, rgba(0, 0, 0, 0.45));
background: var(--color-overlay);
display: flex;
align-items: center;
justify-content: center;
@@ -955,7 +955,7 @@ function usageTitle(s: SnippetListItem): string {
.merge-choice-name {
flex: 1;
min-width: 0;
font-family: var(--font-mono, ui-monospace, "JetBrains Mono", monospace);
font-family: var(--font-mono);
font-size: 0.85rem;
word-break: break-word;
}
+12 -12
View File
@@ -874,7 +874,7 @@ useEditorGuards(dirty, save);
padding: 0 0.2rem;
flex-shrink: 0;
}
.btn-clear-parent:hover { color: var(--color-danger, #e74c3c); }
.btn-clear-parent:hover { color: var(--color-danger); }
.parent-dropdown {
position: absolute;
top: calc(100% + 4px);
@@ -1037,13 +1037,13 @@ useEditorGuards(dirty, save);
margin: 0.5rem 0 0.25rem;
}
.task-goal-label {
font-family: var(--font-display, "Fraunces", serif);
font-family: var(--font-display);
font-style: italic;
font-size: 0.78rem;
font-weight: 500;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--color-text-muted, rgba(255, 255, 255, 0.5));
color: var(--color-text-muted);
}
.task-goal-input {
width: 100%;
@@ -1053,14 +1053,14 @@ useEditorGuards(dirty, save);
font: inherit;
font-size: 0.95rem;
line-height: 1.4;
color: var(--color-text, inherit);
background: var(--color-input-bg, rgba(255, 255, 255, 0.03));
border: 1px solid var(--color-border, rgba(255, 255, 255, 0.08));
border-radius: var(--radius-md, 8px);
color: var(--color-text);
background: var(--color-input-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
}
.task-goal-input:focus {
outline: none;
border-color: var(--color-primary, #6366f1);
border-color: var(--color-primary);
}
/* ── Auto-summary banner + re-consolidate button ─────────────────────────── */
@@ -1072,13 +1072,13 @@ useEditorGuards(dirty, save);
margin-bottom: 0.5rem;
font-size: 0.82rem;
font-style: italic;
color: var(--color-text-muted, rgba(255, 255, 255, 0.6));
color: var(--color-text-muted);
background: rgba(99, 102, 241, 0.06);
border-left: 2px solid var(--color-primary, #6366f1);
border-radius: var(--radius-sm, 4px);
border-left: 2px solid var(--color-primary);
border-radius: var(--radius-sm);
}
.auto-summary-banner-editor .auto-summary-icon {
color: var(--color-primary, #6366f1);
color: var(--color-primary);
font-style: normal;
}
</style>
+10 -10
View File
@@ -561,7 +561,7 @@ const subTaskProgress = computed(() => {
}
.subtasks-fill {
height: 100%;
background: var(--color-status-done, #22c55e);
background: var(--color-status-done);
border-radius: 2px;
transition: width 0.3s ease;
}
@@ -602,13 +602,13 @@ const subTaskProgress = computed(() => {
border: 2px solid var(--color-text-muted);
}
.dot-in-progress {
background: var(--color-status-in-progress, #3b82f6);
background: var(--color-status-in-progress);
}
.dot-done {
background: var(--color-status-done, #22c55e);
background: var(--color-status-done);
}
.dot-cancelled {
background: var(--color-text-muted, #6b7280);
background: var(--color-text-muted);
}
.sub-title {
flex: 1;
@@ -749,26 +749,26 @@ const subTaskProgress = computed(() => {
/* ── Goal block + auto-summary banner ─────────────────────────────────────── */
.task-goal-display {
border-left: 2px solid var(--color-border, rgba(255, 255, 255, 0.12));
border-left: 2px solid var(--color-border);
padding: 0.4rem 0 0.4rem 0.9rem;
margin: 0.75rem 0 1.25rem;
background: rgba(255, 255, 255, 0.02);
}
.goal-label {
font-family: var(--font-display, "Fraunces", serif);
font-family: var(--font-display);
font-style: italic;
font-size: 0.78rem;
font-weight: 500;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--color-text-muted, rgba(255, 255, 255, 0.5));
color: var(--color-text-muted);
margin: 0 0 0.25rem;
}
.goal-text {
margin: 0;
font-size: 0.95rem;
line-height: 1.45;
color: var(--color-text, inherit);
color: var(--color-text);
white-space: pre-wrap;
}
.auto-summary-banner {
@@ -777,11 +777,11 @@ const subTaskProgress = computed(() => {
gap: 0.5rem;
font-size: 0.78rem;
font-style: italic;
color: var(--color-text-muted, rgba(255, 255, 255, 0.55));
color: var(--color-text-muted);
margin: 0 0 0.75rem;
}
.auto-summary-icon {
color: var(--color-primary, #6366f1);
color: var(--color-primary);
font-size: 0.85rem;
}
</style>
+1 -1
View File
@@ -68,7 +68,7 @@ onMounted(() => store.fetchTrash());
.batch-count { opacity: 0.6; font-weight: 400; font-size: 0.9em; margin-left: 0.35rem; }
.batch-meta { font-size: 0.82em; opacity: 0.6; margin-top: 0.25rem; }
.batch-actions { display: flex; gap: 0.5rem; flex-shrink: 0; }
.batch-actions button { border-radius: 6px; padding: 0.35rem 0.7rem; cursor: pointer; border: 1px solid var(--color-border, #2a2a2e); background: none; color: inherit; }
.batch-actions button { border-radius: 6px; padding: 0.35rem 0.7rem; cursor: pointer; border: 1px solid var(--color-border); background: none; color: inherit; }
.btn-restore:hover { border-color: var(--color-action-primary); color: var(--color-action-primary); }
.btn-purge:hover { border-color: var(--color-action-destructive); color: var(--color-action-destructive); }
</style>