fix(canvas): restore text-white on saturated buttons + close zinc gaps

Independent code review of #2555 caught two contrast regressions left
by the bulk perl pass:

1. text-white → text-ink mass-substitution silently broke destructive
   and primary buttons. text-ink resolves to #15181c (warm-paper
   near-black) in light mode — dark text on bg-red-600 / bg-amber-600
   / bg-emerald-600 / bg-blue-600 / bg-accent / bg-accent-strong /
   bg-good / bg-bad fails WCAG contrast and looks broken. Per-line
   pass flips text-ink → text-white only when a saturated bg utility
   is present; tinted-state pills (bg-red-950/50 etc.) keep their
   intentionally-retained text-* literals.

2. Original mapping table was missing bg-zinc-600 (most-used
   hover-state literal for cancel buttons — caused them to JUMP from
   warm cream resting state to dark zinc on hover in light mode) and
   text-zinc-700/800/900 (separator dots and decorative dim text
   invisible on warm-paper light bg). Extended mapping fills these
   gaps with bg-surface-card / text-ink-soft.

Also: drop stale tailwind.config.ts reference from components.json
(file deleted by the v3→v4 migration); switch baseColor zinc →
neutral and enable cssVariables since v4 uses CSS-driven tokens.
Future shadcn-cli invocations would have failed or written malformed
components without this.

27 sites in 27 files affected by #1, ~20 sites in 20 files by #2.
1214/1214 unit tests still pass; build still clean.

Findings courtesy of multi-model review per code-review-and-quality
skill — different blind spots catch different bugs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hongming Wang 2026-05-03 02:04:20 -07:00
parent 052575d773
commit db48d1d261
38 changed files with 85 additions and 86 deletions

View File

@ -4,10 +4,9 @@
"rsc": true, "rsc": true,
"tsx": true, "tsx": true,
"tailwind": { "tailwind": {
"config": "tailwind.config.ts",
"css": "src/app/globals.css", "css": "src/app/globals.css",
"baseColor": "zinc", "baseColor": "neutral",
"cssVariables": false "cssVariables": true
}, },
"aliases": { "aliases": {
"components": "@/components", "components": "@/components",

View File

@ -283,7 +283,7 @@ function OrgCTA({ org }: { org: Org }) {
return ( return (
<a <a
href={href} href={href}
className="rounded bg-emerald-600 px-4 py-2 text-sm font-medium text-ink hover:bg-emerald-500" className="rounded bg-emerald-600 px-4 py-2 text-sm font-medium text-white hover:bg-emerald-500"
> >
Open Open
</a> </a>
@ -293,7 +293,7 @@ function OrgCTA({ org }: { org: Org }) {
return ( return (
<a <a
href={`/pricing?org=${encodeURIComponent(org.slug)}`} href={`/pricing?org=${encodeURIComponent(org.slug)}`}
className="rounded bg-amber-600 px-4 py-2 text-sm font-medium text-ink hover:bg-amber-500" className="rounded bg-amber-600 px-4 py-2 text-sm font-medium text-white hover:bg-amber-500"
> >
Complete payment Complete payment
</a> </a>
@ -303,7 +303,7 @@ function OrgCTA({ org }: { org: Org }) {
return ( return (
<a <a
href="mailto:support@moleculesai.app" href="mailto:support@moleculesai.app"
className="rounded bg-surface-card px-4 py-2 text-sm font-medium text-ink hover:bg-zinc-600" className="rounded bg-surface-card px-4 py-2 text-sm font-medium text-ink hover:bg-surface-card"
> >
Contact support Contact support
</a> </a>
@ -395,7 +395,7 @@ function CreateOrgForm({ onCreated }: { onCreated: (slug: string) => void }) {
<button <button
type="submit" type="submit"
disabled={submitting} disabled={submitting}
className="rounded bg-accent-strong px-4 py-2 text-sm font-medium text-ink hover:bg-accent disabled:opacity-50" className="rounded bg-accent-strong px-4 py-2 text-sm font-medium text-white hover:bg-accent disabled:opacity-50"
> >
{submitting ? "Creating…" : "Create organization"} {submitting ? "Creating…" : "Create organization"}
</button> </button>

View File

@ -87,7 +87,7 @@ export default function Home() {
setHydrationError(null); setHydrationError(null);
window.location.reload(); window.location.reload();
}} }}
className="px-4 py-2 bg-accent-strong hover:bg-accent text-ink rounded-md text-sm" className="px-4 py-2 bg-accent-strong hover:bg-accent text-white rounded-md text-sm"
> >
Retry Retry
</button> </button>
@ -129,7 +129,7 @@ brew services start redis`}</pre>
</p> </p>
<button <button
onClick={() => window.location.reload()} onClick={() => window.location.reload()}
className="px-4 py-2 bg-accent-strong hover:bg-accent text-ink rounded-md text-sm mt-2" className="px-4 py-2 bg-accent-strong hover:bg-accent text-white rounded-md text-sm mt-2"
> >
Reload Reload
</button> </button>

View File

@ -73,14 +73,14 @@ export function ApprovalBanner() {
<button <button
type="button" type="button"
onClick={() => handleDecide(approval, "approved")} onClick={() => handleDecide(approval, "approved")}
className="px-3 py-1.5 bg-emerald-600 hover:bg-emerald-500 text-xs rounded-lg text-ink font-medium transition-colors" className="px-3 py-1.5 bg-emerald-600 hover:bg-emerald-500 text-xs rounded-lg text-white font-medium transition-colors"
> >
Approve Approve
</button> </button>
<button <button
type="button" type="button"
onClick={() => handleDecide(approval, "denied")} onClick={() => handleDecide(approval, "denied")}
className="px-3 py-1.5 bg-surface-card hover:bg-zinc-600 text-xs rounded-lg text-ink-mid transition-colors" className="px-3 py-1.5 bg-surface-card hover:bg-surface-card text-xs rounded-lg text-ink-mid transition-colors"
> >
Deny Deny
</button> </button>

View File

@ -174,7 +174,7 @@ export function AuditTrailPanel({ workspaceId }: Props) {
{entries.length === 0 ? ( {entries.length === 0 ? (
/* Empty state */ /* Empty state */
<div className="flex flex-col items-center justify-center py-16 gap-3 text-center"> <div className="flex flex-col items-center justify-center py-16 gap-3 text-center">
<span className="text-4xl text-zinc-700" aria-hidden="true"></span> <span className="text-4xl text-ink-soft" aria-hidden="true"></span>
<p className="text-sm font-medium text-ink-mid">No audit events yet</p> <p className="text-sm font-medium text-ink-mid">No audit events yet</p>
<p className="text-[11px] text-ink-soft max-w-[200px] leading-relaxed"> <p className="text-[11px] text-ink-soft max-w-[200px] leading-relaxed">
Delegation, decision, gate, and human-in-the-loop events will appear here. Delegation, decision, gate, and human-in-the-loop events will appear here.

View File

@ -83,7 +83,7 @@ export function BatchActionBar() {
className="fixed bottom-6 left-1/2 -translate-x-1/2 z-[200] flex items-center gap-3 px-4 py-2.5 rounded-2xl bg-surface-sunken/95 border border-line/70 shadow-2xl shadow-black/50 backdrop-blur-md" className="fixed bottom-6 left-1/2 -translate-x-1/2 z-[200] flex items-center gap-3 px-4 py-2.5 rounded-2xl bg-surface-sunken/95 border border-line/70 shadow-2xl shadow-black/50 backdrop-blur-md"
> >
{/* Selection count badge */} {/* Selection count badge */}
<span className="text-[12px] font-semibold text-ink bg-accent-strong/80 px-2.5 py-0.5 rounded-full tabular-nums"> <span className="text-[12px] font-semibold text-white bg-accent-strong/80 px-2.5 py-0.5 rounded-full tabular-nums">
{count} selected {count} selected
</span> </span>

View File

@ -93,10 +93,10 @@ export function ConfirmDialog({
const confirmColors = const confirmColors =
confirmVariant === "danger" confirmVariant === "danger"
? "bg-red-600 hover:bg-red-500 text-ink" ? "bg-red-600 hover:bg-red-500 text-white"
: confirmVariant === "warning" : confirmVariant === "warning"
? "bg-amber-600 hover:bg-amber-500 text-ink" ? "bg-amber-600 hover:bg-amber-500 text-white"
: "bg-accent-strong hover:bg-accent text-ink"; : "bg-accent-strong hover:bg-accent text-white";
// Render via Portal so the fixed-position dialog escapes any containing block // Render via Portal so the fixed-position dialog escapes any containing block
// (e.g. parents with transform, filter, will-change that break position:fixed). // (e.g. parents with transform, filter, will-change that break position:fixed).

View File

@ -161,7 +161,7 @@ export function ConversationTraceModal({ open, workspaceId: _workspaceId, onClos
? "bg-cyan-500" ? "bg-cyan-500"
: isReceive : isReceive
? "bg-accent" ? "bg-accent"
: "bg-zinc-600" : "bg-surface-card"
}`} }`}
/> />
<div className="w-px flex-1 bg-surface-card min-h-[8px]" /> <div className="w-px flex-1 bg-surface-card min-h-[8px]" />

View File

@ -137,7 +137,7 @@ export function CookieConsent() {
<button <button
type="button" type="button"
onClick={() => decide("accepted")} onClick={() => decide("accepted")}
className="rounded border border-accent bg-accent-strong px-4 py-2 text-sm font-medium text-ink hover:bg-accent" className="rounded border border-accent bg-accent-strong px-4 py-2 text-sm font-medium text-white hover:bg-accent"
> >
Accept all Accept all
</button> </button>

View File

@ -310,7 +310,7 @@ export function CreateWorkspaceButton() {
return ( return (
<Dialog.Root open={open} onOpenChange={setOpen}> <Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger asChild> <Dialog.Trigger asChild>
<button type="button" className="fixed bottom-6 right-6 z-40 px-5 py-2.5 bg-accent-strong hover:bg-accent active:bg-accent-strong text-sm font-medium rounded-xl text-ink shadow-lg shadow-blue-600/20 hover:shadow-xl hover:shadow-blue-500/30 transition-all duration-200 flex items-center gap-2"> <button type="button" className="fixed bottom-6 right-6 z-40 px-5 py-2.5 bg-accent-strong hover:bg-accent active:bg-accent-strong text-sm font-medium rounded-xl text-white shadow-lg shadow-blue-600/20 hover:shadow-xl hover:shadow-blue-500/30 transition-all duration-200 flex items-center gap-2">
<svg <svg
width="14" width="14"
height="14" height="14"
@ -560,7 +560,7 @@ export function CreateWorkspaceButton() {
type="button" type="button"
onClick={handleCreate} onClick={handleCreate}
disabled={creating} disabled={creating}
className="px-5 py-2 bg-accent-strong hover:bg-accent active:bg-accent-strong text-sm rounded-lg text-ink disabled:opacity-50 transition-colors" className="px-5 py-2 bg-accent-strong hover:bg-accent active:bg-accent-strong text-sm rounded-lg text-white disabled:opacity-50 transition-colors"
> >
{creating ? "Creating..." : "Create"} {creating ? "Creating..." : "Create"}
</button> </button>

View File

@ -155,7 +155,7 @@ export function DeleteCascadeConfirmDialog({
disabled={!checked} disabled={!checked}
className={`px-3.5 py-1.5 text-[13px] rounded-lg transition-colors className={`px-3.5 py-1.5 text-[13px] rounded-lg transition-colors
${checked ${checked
? "bg-red-600 hover:bg-red-500 text-ink cursor-pointer" ? "bg-red-600 hover:bg-red-500 text-white cursor-pointer"
: "bg-red-900/30 text-bad/40 cursor-not-allowed" : "bg-red-900/30 text-bad/40 cursor-not-allowed"
}`} }`}
> >

View File

@ -169,9 +169,9 @@ export function EmptyState() {
<div className="mt-5 pt-4 border-t border-line/50"> <div className="mt-5 pt-4 border-t border-line/50">
<div className="flex items-center justify-center gap-6 text-[10px] text-ink-mid"> <div className="flex items-center justify-center gap-6 text-[10px] text-ink-mid">
<span>Drag to nest workspaces into teams</span> <span>Drag to nest workspaces into teams</span>
<span className="text-zinc-700">|</span> <span className="text-ink-soft">|</span>
<span>Right-click for actions</span> <span>Right-click for actions</span>
<span className="text-zinc-700">|</span> <span className="text-ink-soft">|</span>
<span>Press <kbd className="px-1 py-0.5 bg-surface-card rounded text-ink-soft font-mono">&#8984;K</kbd> to search</span> <span>Press <kbd className="px-1 py-0.5 bg-surface-card rounded text-ink-soft font-mono">&#8984;K</kbd> to search</span>
</div> </div>
</div> </div>

View File

@ -83,7 +83,7 @@ export class ErrorBoundary extends React.Component<
<button <button
type="button" type="button"
onClick={this.handleReload} onClick={this.handleReload}
className="rounded-lg bg-accent-strong hover:bg-accent px-5 py-2 text-sm font-medium text-ink transition-colors" className="rounded-lg bg-accent-strong hover:bg-accent px-5 py-2 text-sm font-medium text-white transition-colors"
> >
Reload Reload
</button> </button>

View File

@ -256,7 +256,7 @@ function SnippetBlock({
<button <button
type="button" type="button"
onClick={onCopy} onClick={onCopy}
className="text-xs px-2 py-1 rounded bg-accent-strong/80 hover:bg-accent text-ink" className="text-xs px-2 py-1 rounded bg-accent-strong/80 hover:bg-accent text-white"
> >
{copied ? "Copied!" : "Copy"} {copied ? "Copied!" : "Copy"}
</button> </button>

View File

@ -167,7 +167,7 @@ export function MemoryInspectorPanel({ workspaceId }: Props) {
className={[ className={[
"px-3 py-1 text-[11px] rounded transition-colors", "px-3 py-1 text-[11px] rounded transition-colors",
activeScope === scope activeScope === scope
? "bg-accent-strong text-ink" ? "bg-accent-strong text-white"
: "bg-surface-card text-ink-mid hover:bg-surface-card hover:text-ink", : "bg-surface-card text-ink-mid hover:bg-surface-card hover:text-ink",
].join(" ")} ].join(" ")}
> >
@ -269,7 +269,7 @@ export function MemoryInspectorPanel({ workspaceId }: Props) {
) : entries.length === 0 ? ( ) : entries.length === 0 ? (
debouncedQuery ? ( debouncedQuery ? (
<div className="flex flex-col items-center justify-center py-16 gap-3 text-center"> <div className="flex flex-col items-center justify-center py-16 gap-3 text-center">
<span className="text-4xl text-zinc-700" aria-hidden="true"></span> <span className="text-4xl text-ink-soft" aria-hidden="true"></span>
<p className="text-sm font-medium text-ink-mid"> <p className="text-sm font-medium text-ink-mid">
No memories match your search No memories match your search
</p> </p>
@ -290,7 +290,7 @@ export function MemoryInspectorPanel({ workspaceId }: Props) {
</div> </div>
) : ( ) : (
<div className="flex flex-col items-center justify-center py-16 gap-3 text-center"> <div className="flex flex-col items-center justify-center py-16 gap-3 text-center">
<span className="text-4xl text-zinc-700" aria-hidden="true"></span> <span className="text-4xl text-ink-soft" aria-hidden="true"></span>
<p className="text-sm font-medium text-ink-mid">No {activeScope} memories</p> <p className="text-sm font-medium text-ink-mid">No {activeScope} memories</p>
<p className="text-[11px] text-ink-soft max-w-[200px] leading-relaxed"> <p className="text-[11px] text-ink-soft max-w-[200px] leading-relaxed">
{activeScope === "LOCAL" {activeScope === "LOCAL"

View File

@ -451,7 +451,7 @@ function ProviderPickerModal({
<button <button
onClick={() => handleSaveKey(index)} onClick={() => handleSaveKey(index)}
disabled={!entry.value.trim() || entry.saving} disabled={!entry.value.trim() || entry.saving}
className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-[11px] rounded text-ink disabled:opacity-30 transition-colors shrink-0" className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-[11px] rounded text-white disabled:opacity-30 transition-colors shrink-0"
> >
{entry.saving ? "..." : "Save"} {entry.saving ? "..." : "Save"}
</button> </button>
@ -492,7 +492,7 @@ function ProviderPickerModal({
!selectorValue.providerId || !selectorValue.providerId ||
(showModelInput && model.trim() === "") (showModelInput && model.trim() === "")
} }
className="px-3.5 py-1.5 text-[12px] bg-accent-strong hover:bg-accent text-ink rounded-lg transition-colors disabled:opacity-40" className="px-3.5 py-1.5 text-[12px] bg-accent-strong hover:bg-accent text-white rounded-lg transition-colors disabled:opacity-40"
> >
{allSaved ? "Deploy" : entries.length > 1 ? "Add Keys" : "Add Key"} {allSaved ? "Deploy" : entries.length > 1 ? "Add Keys" : "Add Key"}
</button> </button>
@ -706,7 +706,7 @@ function AllKeysModal({
type="button" type="button"
onClick={() => handleSaveKey(index)} onClick={() => handleSaveKey(index)}
disabled={!entry.value.trim() || entry.saving} disabled={!entry.value.trim() || entry.saving}
className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-[11px] rounded text-ink disabled:opacity-30 transition-colors shrink-0" className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-[11px] rounded text-white disabled:opacity-30 transition-colors shrink-0"
> >
{entry.saving ? "..." : "Save"} {entry.saving ? "..." : "Save"}
</button> </button>
@ -748,7 +748,7 @@ function AllKeysModal({
type="button" type="button"
onClick={handleAddKeysAndDeploy} onClick={handleAddKeysAndDeploy}
disabled={!allSaved || anySaving} disabled={!allSaved || anySaving}
className="px-3.5 py-1.5 text-[12px] bg-accent-strong hover:bg-accent text-ink rounded-lg transition-colors disabled:opacity-40" className="px-3.5 py-1.5 text-[12px] bg-accent-strong hover:bg-accent text-white rounded-lg transition-colors disabled:opacity-40"
> >
{anySaving ? "Saving..." : allSaved ? "Deploy" : "Add Keys"} {anySaving ? "Saving..." : allSaved ? "Deploy" : "Add Keys"}
</button> </button>

View File

@ -181,7 +181,7 @@ export function OnboardingWizard() {
<button <button
type="button" type="button"
onClick={handleAction} onClick={handleAction}
className="flex-1 px-3 py-1.5 bg-accent-strong/90 hover:bg-accent rounded-lg text-[11px] font-medium text-ink transition-colors" className="flex-1 px-3 py-1.5 bg-accent-strong/90 hover:bg-accent rounded-lg text-[11px] font-medium text-white transition-colors"
> >
{step === "welcome" {step === "welcome"
? "Create Workspace" ? "Create Workspace"

View File

@ -308,7 +308,7 @@ export function OrgImportPreflightModal({
type="button" type="button"
onClick={onProceed} onClick={onProceed}
disabled={!canProceed} disabled={!canProceed}
className="px-4 py-1.5 text-[11px] font-semibold rounded bg-accent-strong hover:bg-accent text-ink disabled:bg-surface-card disabled:text-ink-soft disabled:cursor-not-allowed" className="px-4 py-1.5 text-[11px] font-semibold rounded bg-accent-strong hover:bg-accent text-white disabled:bg-surface-card disabled:text-white-soft disabled:cursor-not-allowed"
> >
Import Import
</button> </button>
@ -428,7 +428,7 @@ function StrictEnvRow({
type="button" type="button"
onClick={() => onSave(envKey)} onClick={() => onSave(envKey)}
disabled={d?.saving || !d?.value.trim()} disabled={d?.saving || !d?.value.trim()}
className="px-2 py-1 text-[10px] rounded bg-accent-strong hover:bg-accent text-ink disabled:opacity-40 disabled:cursor-not-allowed" className="px-2 py-1 text-[10px] rounded bg-accent-strong hover:bg-accent text-white disabled:opacity-40 disabled:cursor-not-allowed"
> >
{d?.saving ? "…" : "Save"} {d?.saving ? "…" : "Save"}
</button> </button>
@ -520,7 +520,7 @@ function AnyOfEnvGroup({
type="button" type="button"
onClick={() => onSave(m)} onClick={() => onSave(m)}
disabled={d?.saving || !d?.value.trim()} disabled={d?.saving || !d?.value.trim()}
className="px-2 py-1 text-[10px] rounded bg-accent-strong hover:bg-accent text-ink disabled:opacity-40 disabled:cursor-not-allowed" className="px-2 py-1 text-[10px] rounded bg-accent-strong hover:bg-accent text-white disabled:opacity-40 disabled:cursor-not-allowed"
> >
{d?.saving ? "…" : "Save"} {d?.saving ? "…" : "Save"}
</button> </button>

View File

@ -130,7 +130,7 @@ function PlanCard({
disabled={loading} disabled={loading}
className={`mt-6 rounded-lg px-4 py-3 text-sm font-medium ${ className={`mt-6 rounded-lg px-4 py-3 text-sm font-medium ${
plan.highlighted plan.highlighted
? "bg-accent-strong text-ink hover:bg-accent disabled:bg-blue-900" ? "bg-accent-strong text-white hover:bg-accent disabled:bg-blue-900"
: "border border-line bg-surface-sunken text-ink hover:bg-surface-card disabled:opacity-50" : "border border-line bg-surface-sunken text-ink hover:bg-surface-card disabled:opacity-50"
}`} }`}
> >

View File

@ -341,7 +341,7 @@ export function ProvisioningTimeout({
type="button" type="button"
onClick={() => handleRetry(entry.workspaceId)} onClick={() => handleRetry(entry.workspaceId)}
disabled={isRetrying || isCancelling || retryCooldown.has(entry.workspaceId)} disabled={isRetrying || isCancelling || retryCooldown.has(entry.workspaceId)}
className="px-3 py-1.5 bg-amber-600 hover:bg-amber-500 text-[11px] font-medium rounded-lg text-ink disabled:opacity-40 transition-colors" className="px-3 py-1.5 bg-amber-600 hover:bg-amber-500 text-[11px] font-medium rounded-lg text-white disabled:opacity-40 transition-colors"
> >
{isRetrying ? "Retrying..." : retryCooldown.has(entry.workspaceId) ? "Wait..." : "Retry"} {isRetrying ? "Retrying..." : retryCooldown.has(entry.workspaceId) ? "Wait..." : "Retry"}
</button> </button>
@ -389,7 +389,7 @@ export function ProvisioningTimeout({
<button <button
type="button" type="button"
onClick={handleCancelConfirm} onClick={handleCancelConfirm}
className="px-3.5 py-1.5 text-[12px] bg-red-600 hover:bg-red-500 text-ink rounded-lg transition-colors" className="px-3.5 py-1.5 text-[12px] bg-red-600 hover:bg-red-500 text-white rounded-lg transition-colors"
> >
Remove Workspace Remove Workspace
</button> </button>

View File

@ -476,7 +476,7 @@ export function TemplatePalette() {
onClick={() => setOpen(!open)} onClick={() => setOpen(!open)}
className={`fixed top-4 left-4 z-40 w-9 h-9 flex items-center justify-center rounded-lg transition-colors ${ className={`fixed top-4 left-4 z-40 w-9 h-9 flex items-center justify-center rounded-lg transition-colors ${
open open
? "bg-accent-strong text-ink" ? "bg-accent-strong text-white"
: "bg-surface-sunken/90 border border-line/50 text-ink-mid hover:text-ink hover:border-line" : "bg-surface-sunken/90 border border-line/50 text-ink-mid hover:text-ink hover:border-line"
}`} }`}
title="Template Palette" title="Template Palette"

View File

@ -105,7 +105,7 @@ export function TermsGate({ children }: { children: React.ReactNode }) {
type="button" type="button"
onClick={accept} onClick={accept}
disabled={submitting} disabled={submitting}
className="rounded bg-emerald-600 px-4 py-2 text-sm font-medium text-ink hover:bg-emerald-500 disabled:opacity-50" className="rounded bg-emerald-600 px-4 py-2 text-sm font-medium text-white hover:bg-emerald-500 disabled:opacity-50"
> >
{submitting ? "Saving…" : "I agree"} {submitting ? "Saving…" : "I agree"}
</button> </button>

View File

@ -154,7 +154,7 @@ export function Toolbar() {
{counts.failed > 0 && ( {counts.failed > 0 && (
<StatusPill color={statusDotClass("failed")} count={counts.failed} label="failed" /> <StatusPill color={statusDotClass("failed")} count={counts.failed} label="failed" />
)} )}
<span className="text-zinc-700" aria-hidden="true">·</span> <span className="text-ink-soft" aria-hidden="true">·</span>
<span className="text-[10px] text-ink-soft whitespace-nowrap"> <span className="text-[10px] text-ink-soft whitespace-nowrap">
{counts.roots} workspace{counts.roots !== 1 ? "s" : ""} {counts.roots} workspace{counts.roots !== 1 ? "s" : ""}
{counts.children > 0 && <span className="text-ink-soft"> + {counts.children} sub</span>} {counts.children > 0 && <span className="text-ink-soft"> + {counts.children} sub</span>}

View File

@ -165,7 +165,7 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
<Handle <Handle
type="target" type="target"
position={Position.Top} position={Position.Top}
className="!w-2.5 !h-1 !rounded-full !bg-zinc-600/80 !border-0 !-top-0.5 hover:!bg-blue-400 hover:!h-1.5 transition-all" className="!w-2.5 !h-1 !rounded-full !bg-surface-card/80 !border-0 !-top-0.5 hover:!bg-blue-400 hover:!h-1.5 transition-all"
/> />
<div className="relative px-3.5 py-2.5"> <div className="relative px-3.5 py-2.5">
@ -318,7 +318,7 @@ export function WorkspaceNode({ id, data }: NodeProps<Node<WorkspaceNodeData>>)
<Handle <Handle
type="source" type="source"
position={Position.Bottom} position={Position.Bottom}
className="!w-2.5 !h-1 !rounded-full !bg-zinc-600/80 !border-0 !-bottom-0.5 hover:!bg-blue-400 hover:!h-1.5 transition-all" className="!w-2.5 !h-1 !rounded-full !bg-surface-card/80 !border-0 !-bottom-0.5 hover:!bg-blue-400 hover:!h-1.5 transition-all"
/> />
</div> </div>
</> </>

View File

@ -130,7 +130,7 @@ export function OrgCancelButton({ rootId, rootName, workspaceCount }: Props) {
type="button" type="button"
onClick={() => setConfirming(false)} onClick={() => setConfirming(false)}
disabled={submitting} disabled={submitting}
className="px-2 py-0.5 rounded bg-surface-card/80 hover:bg-zinc-600 text-[10px] text-ink" className="px-2 py-0.5 rounded bg-surface-card/80 hover:bg-surface-card text-[10px] text-ink"
> >
No No
</button> </button>

View File

@ -111,7 +111,7 @@ export function ActivityTab({ workspaceId }: Props) {
</button> </button>
<button <button
onClick={loadActivities} onClick={loadActivities}
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[11px] rounded text-ink-mid" className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[11px] rounded text-ink-mid"
> >
Refresh Refresh
</button> </button>
@ -137,7 +137,7 @@ export function ActivityTab({ workspaceId }: Props) {
{!loading && !error && activities.length === 0 && ( {!loading && !error && activities.length === 0 && (
<div className="text-center py-8"> <div className="text-center py-8">
<div className="text-ink-soft text-xs">No activity recorded yet</div> <div className="text-ink-soft text-xs">No activity recorded yet</div>
<div className="text-zinc-700 text-[9px] mt-1"> <div className="text-ink-soft text-[9px] mt-1">
Activity logs appear when agents communicate or perform tasks Activity logs appear when agents communicate or perform tasks
</div> </div>
</div> </div>

View File

@ -243,7 +243,7 @@ export function BudgetSection({ workspaceId }: Props) {
onClick={handleSave} onClick={handleSave}
disabled={saving} disabled={saving}
data-testid="budget-save-btn" data-testid="budget-save-btn"
className="px-4 py-1.5 bg-accent-strong hover:bg-accent active:bg-accent-strong rounded-lg text-xs font-medium text-ink disabled:opacity-50 transition-colors" className="px-4 py-1.5 bg-accent-strong hover:bg-accent active:bg-accent-strong rounded-lg text-xs font-medium text-white disabled:opacity-50 transition-colors"
> >
{saving ? "Saving…" : "Save"} {saving ? "Saving…" : "Save"}
</button> </button>

View File

@ -366,7 +366,7 @@ export function ChannelsTab({ workspaceId }: Props) {
)} )}
<button <button
onClick={handleCreate} onClick={handleCreate}
className="w-full text-xs py-1.5 rounded bg-accent-strong hover:bg-accent text-ink transition" className="w-full text-xs py-1.5 rounded bg-accent-strong hover:bg-accent text-white transition"
> >
Connect Channel Connect Channel
</button> </button>
@ -392,7 +392,7 @@ export function ChannelsTab({ workspaceId }: Props) {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span <span
className={`w-2 h-2 rounded-full ${ className={`w-2 h-2 rounded-full ${
ch.enabled ? "bg-emerald-500" : "bg-zinc-600" ch.enabled ? "bg-emerald-500" : "bg-surface-card"
}`} }`}
/> />
<span className="text-xs font-medium text-ink"> <span className="text-xs font-medium text-ink">

View File

@ -901,7 +901,7 @@ function MyChatPanel({ workspaceId, data }: Props) {
<button <button
onClick={sendMessage} onClick={sendMessage}
disabled={(!input.trim() && pendingFiles.length === 0) || !agentReachable || sending || uploading} disabled={(!input.trim() && pendingFiles.length === 0) || !agentReachable || sending || uploading}
className="px-4 py-2 bg-accent-strong hover:bg-accent text-xs font-medium rounded-lg text-ink disabled:opacity-30 transition-colors shrink-0" className="px-4 py-2 bg-accent-strong hover:bg-accent text-xs font-medium rounded-lg text-white disabled:opacity-30 transition-colors shrink-0"
> >
{uploading ? "Uploading…" : "Send"} {uploading ? "Uploading…" : "Send"}
</button> </button>

View File

@ -65,11 +65,11 @@ function AgentCardSection({ workspaceId }: { workspaceId: string }) {
{error && <div className="px-2 py-1 bg-red-900/30 border border-red-800 rounded text-[10px] text-bad">{error}</div>} {error && <div className="px-2 py-1 bg-red-900/30 border border-red-800 rounded text-[10px] text-bad">{error}</div>}
<div className="flex gap-2"> <div className="flex gap-2">
<button type="button" onClick={handleSave} disabled={saving} <button type="button" onClick={handleSave} disabled={saving}
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink disabled:opacity-50"> className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-50">
{saving ? "Saving..." : "Save"} {saving ? "Saving..." : "Save"}
</button> </button>
<button type="button" onClick={() => setEditing(false)} <button type="button" onClick={() => setEditing(false)}
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid">Cancel</button> className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid">Cancel</button>
</div> </div>
</div> </div>
) : ( ) : (
@ -955,7 +955,7 @@ export function ConfigTab({ workspaceId }: Props) {
type="button" type="button"
onClick={() => handleSave(true)} onClick={() => handleSave(true)}
disabled={!isDirty || saving} disabled={!isDirty || saving}
className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-xs rounded text-ink disabled:opacity-30 transition-colors" className="px-3 py-1.5 bg-accent-strong hover:bg-accent text-xs rounded text-white disabled:opacity-30 transition-colors"
> >
{saving ? "Restarting..." : "Save & Restart"} {saving ? "Restarting..." : "Save & Restart"}
</button> </button>
@ -963,14 +963,14 @@ export function ConfigTab({ workspaceId }: Props) {
type="button" type="button"
onClick={() => handleSave(false)} onClick={() => handleSave(false)}
disabled={!isDirty || saving} disabled={!isDirty || saving}
className="px-3 py-1.5 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid disabled:opacity-30 transition-colors" className="px-3 py-1.5 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid disabled:opacity-30 transition-colors"
> >
Save Save
</button> </button>
<button <button
type="button" type="button"
onClick={loadConfig} onClick={loadConfig}
className="px-3 py-1.5 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid ml-auto" className="px-3 py-1.5 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid ml-auto"
> >
Reload Reload
</button> </button>

View File

@ -166,7 +166,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
type="button" type="button"
onClick={handleSave} onClick={handleSave}
disabled={saving} disabled={saving}
className="px-3 py-1 bg-accent-strong hover:bg-accent text-xs rounded text-ink disabled:opacity-50" className="px-3 py-1 bg-accent-strong hover:bg-accent text-xs rounded text-white disabled:opacity-50"
> >
{saving ? "Saving..." : "Save"} {saving ? "Saving..." : "Save"}
</button> </button>
@ -179,7 +179,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
setRole(data.role || ""); setRole(data.role || "");
setTier(data.tier); setTier(data.tier);
}} }}
className="px-3 py-1 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid" className="px-3 py-1 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid"
> >
Cancel Cancel
</button> </button>
@ -208,7 +208,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
type="button" type="button"
onClick={handleRestart} onClick={handleRestart}
disabled={restarting} disabled={restarting}
className="px-3 py-1 bg-green-700 hover:bg-green-600 text-xs rounded text-ink disabled:opacity-50" className="px-3 py-1 bg-green-700 hover:bg-green-600 text-xs rounded text-white disabled:opacity-50"
> >
{restarting ? "Restarting..." : data.status === "failed" ? "Retry" : "Restart"} {restarting ? "Restarting..." : data.status === "failed" ? "Retry" : "Restart"}
</button> </button>
@ -217,7 +217,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
<button <button
type="button" type="button"
onClick={() => setEditing(true)} onClick={() => setEditing(true)}
className="mt-2 px-3 py-1 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid" className="mt-2 px-3 py-1 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid"
> >
Edit Edit
</button> </button>
@ -322,7 +322,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
<button <button
type="button" type="button"
onClick={handleDelete} onClick={handleDelete}
className="px-3 py-1 bg-red-600 hover:bg-red-500 text-xs rounded text-ink" className="px-3 py-1 bg-red-600 hover:bg-red-500 text-xs rounded text-white"
> >
Confirm Delete Confirm Delete
</button> </button>
@ -334,7 +334,7 @@ export function DetailsTab({ workspaceId, data }: Props) {
// Return focus to the trigger so keyboard users aren't stranded // Return focus to the trigger so keyboard users aren't stranded
deleteButtonRef.current?.focus(); deleteButtonRef.current?.focus();
}} }}
className="px-3 py-1 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid" className="px-3 py-1 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid"
> >
Cancel Cancel
</button> </button>

View File

@ -65,7 +65,7 @@ export function EventsTab({ workspaceId }: Props) {
<span className="text-xs text-ink-mid">{events.length} events</span> <span className="text-xs text-ink-mid">{events.length} events</span>
<button <button
onClick={loadEvents} onClick={loadEvents}
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid" className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid"
> >
Refresh Refresh
</button> </button>

View File

@ -165,8 +165,8 @@ export function FilesTab({ workspaceId }: Props) {
<div className="mx-3 mt-2 px-3 py-2 bg-red-950/30 border border-red-800/40 rounded space-y-1.5"> <div className="mx-3 mt-2 px-3 py-2 bg-red-950/30 border border-red-800/40 rounded space-y-1.5">
<p className="text-xs text-bad">Delete all {files.filter((f) => !f.dir).length} files? This cannot be undone.</p> <p className="text-xs text-bad">Delete all {files.filter((f) => !f.dir).length} files? This cannot be undone.</p>
<div className="flex gap-2"> <div className="flex gap-2">
<button type="button" onClick={() => { handleDeleteAll(); setShowDeleteAll(false); }} className="px-2 py-0.5 bg-red-600 hover:bg-red-500 text-[10px] rounded text-ink">Delete All</button> <button type="button" onClick={() => { handleDeleteAll(); setShowDeleteAll(false); }} className="px-2 py-0.5 bg-red-600 hover:bg-red-500 text-[10px] rounded text-white">Delete All</button>
<button type="button" onClick={() => setShowDeleteAll(false)} className="px-2 py-0.5 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid">Cancel</button> <button type="button" onClick={() => setShowDeleteAll(false)} className="px-2 py-0.5 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid">Cancel</button>
</div> </div>
</div> </div>
)} )}
@ -179,8 +179,8 @@ export function FilesTab({ workspaceId }: Props) {
<div className="mx-3 mt-2 px-3 py-2 bg-amber-950/30 border border-amber-800/40 rounded space-y-1.5"> <div className="mx-3 mt-2 px-3 py-2 bg-amber-950/30 border border-amber-800/40 rounded space-y-1.5">
<p className="text-xs text-warm">Delete <span className="font-mono">{confirmDelete}</span>{files.find((f) => f.path === confirmDelete && f.dir) ? " and all its contents" : ""}?</p> <p className="text-xs text-warm">Delete <span className="font-mono">{confirmDelete}</span>{files.find((f) => f.path === confirmDelete && f.dir) ? " and all its contents" : ""}?</p>
<div className="flex gap-2"> <div className="flex gap-2">
<button type="button" onClick={confirmDeleteFile} className="px-2 py-0.5 bg-red-600 hover:bg-red-500 text-[10px] rounded text-ink">Delete</button> <button type="button" onClick={confirmDeleteFile} className="px-2 py-0.5 bg-red-600 hover:bg-red-500 text-[10px] rounded text-white">Delete</button>
<button type="button" onClick={() => setConfirmDelete(null)} className="px-2 py-0.5 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid">Cancel</button> <button type="button" onClick={() => setConfirmDelete(null)} className="px-2 py-0.5 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid">Cancel</button>
</div> </div>
</div> </div>
)} )}

View File

@ -137,14 +137,14 @@ export function MemoryTab({ workspaceId }: Props) {
<button <button
type="button" type="button"
onClick={() => setShowAwareness((prev) => !prev)} onClick={() => setShowAwareness((prev) => !prev)}
className="shrink-0 px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink" className="shrink-0 px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink"
> >
{showAwareness ? "Collapse" : "Expand"} {showAwareness ? "Collapse" : "Expand"}
</button> </button>
<button <button
type="button" type="button"
onClick={openAwareness} onClick={openAwareness}
className="shrink-0 px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink" className="shrink-0 px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink"
> >
Open Open
</button> </button>
@ -177,7 +177,7 @@ export function MemoryTab({ workspaceId }: Props) {
<button <button
type="button" type="button"
onClick={() => setShowAwareness(true)} onClick={() => setShowAwareness(true)}
className="shrink-0 px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink" className="shrink-0 px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white"
> >
Expand Expand
</button> </button>
@ -212,21 +212,21 @@ export function MemoryTab({ workspaceId }: Props) {
<button <button
type="button" type="button"
onClick={() => setShowAdvanced((prev) => !prev)} onClick={() => setShowAdvanced((prev) => !prev)}
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid" className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid"
> >
{showAdvanced ? "Hide Advanced" : "Advanced"} {showAdvanced ? "Hide Advanced" : "Advanced"}
</button> </button>
<button <button
type="button" type="button"
onClick={loadMemory} onClick={loadMemory}
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid" className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid"
> >
Refresh Refresh
</button> </button>
<button <button
type="button" type="button"
onClick={() => { setShowAdd(!showAdd); if (!showAdd) setShowAdvanced(true); }} onClick={() => { setShowAdd(!showAdd); if (!showAdd) setShowAdvanced(true); }}
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink" className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white"
> >
+ Add + Add
</button> </button>
@ -262,7 +262,7 @@ export function MemoryTab({ workspaceId }: Props) {
<button <button
type="button" type="button"
onClick={handleAdd} onClick={handleAdd}
className="px-3 py-1 bg-accent-strong hover:bg-accent text-xs rounded text-ink" className="px-3 py-1 bg-accent-strong hover:bg-accent text-xs rounded text-white"
> >
Save Save
</button> </button>
@ -272,7 +272,7 @@ export function MemoryTab({ workspaceId }: Props) {
setShowAdd(false); setShowAdd(false);
setError(null); setError(null);
}} }}
className="px-3 py-1 bg-surface-card hover:bg-zinc-600 text-xs rounded text-ink-mid" className="px-3 py-1 bg-surface-card hover:bg-surface-card text-xs rounded text-ink-mid"
> >
Cancel Cancel
</button> </button>
@ -340,7 +340,7 @@ export function MemoryTab({ workspaceId }: Props) {
<button <button
type="button" type="button"
onClick={() => setShowAdvanced(true)} onClick={() => setShowAdvanced(true)}
className="shrink-0 px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink" className="shrink-0 px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white"
> >
Show Show
</button> </button>

View File

@ -271,7 +271,7 @@ export function ScheduleTab({ workspaceId }: Props) {
<button <button
onClick={handleSubmit} onClick={handleSubmit}
disabled={!formCron || !formPrompt} disabled={!formCron || !formPrompt}
className="text-[11px] px-3 py-1 bg-accent-strong text-ink rounded hover:bg-accent disabled:opacity-40 transition-colors" className="text-[11px] px-3 py-1 bg-accent-strong text-white rounded hover:bg-accent disabled:opacity-40 transition-colors"
> >
{editId ? "Update" : "Create"} {editId ? "Update" : "Create"}
</button> </button>
@ -320,7 +320,7 @@ export function ScheduleTab({ workspaceId }: Props) {
? "bg-red-400" ? "bg-red-400"
: sched.last_status === "ok" : sched.last_status === "ok"
? "bg-emerald-400" ? "bg-emerald-400"
: "bg-zinc-600" : "bg-surface-card"
}`} }`}
title={sched.enabled ? "Click to disable" : "Click to enable"} title={sched.enabled ? "Click to disable" : "Click to enable"}
/> />

View File

@ -70,7 +70,7 @@ export function TracesTab({ workspaceId }: Props) {
<div className="text-center py-8"> <div className="text-center py-8">
<div className="text-2xl opacity-20 mb-2" aria-hidden="true">--</div> <div className="text-2xl opacity-20 mb-2" aria-hidden="true">--</div>
<p className="text-xs text-ink-soft">No traces yet</p> <p className="text-xs text-ink-soft">No traces yet</p>
<details className="mt-2 text-[10px] text-zinc-700"> <details className="mt-2 text-[10px] text-ink-soft">
<summary className="cursor-pointer text-ink-soft hover:text-ink-mid">How to enable tracing</summary> <summary className="cursor-pointer text-ink-soft hover:text-ink-mid">How to enable tracing</summary>
<p className="mt-1"> <p className="mt-1">
Set <code className="font-mono text-ink-mid">LANGFUSE_HOST</code>, <code className="font-mono text-ink-mid">LANGFUSE_PUBLIC_KEY</code>, <code className="font-mono text-ink-mid">LANGFUSE_SECRET_KEY</code> as workspace secrets to enable tracing. Set <code className="font-mono text-ink-mid">LANGFUSE_HOST</code>, <code className="font-mono text-ink-mid">LANGFUSE_PUBLIC_KEY</code>, <code className="font-mono text-ink-mid">LANGFUSE_SECRET_KEY</code> as workspace secrets to enable tracing.

View File

@ -58,7 +58,7 @@ export function AttachmentChip({
const toneClasses = const toneClasses =
tone === "user" tone === "user"
? "border-blue-400/30 bg-accent-strong/20 hover:bg-accent-strong/30 text-blue-100" ? "border-blue-400/30 bg-accent-strong/20 hover:bg-accent-strong/30 text-blue-100"
: "border-line/50 bg-surface-card/40 hover:bg-zinc-600/50 text-ink"; : "border-line/50 bg-surface-card/40 hover:bg-surface-card/50 text-ink";
return ( return (
<button <button
onClick={() => onDownload(attachment)} onClick={() => onDownload(attachment)}

View File

@ -131,7 +131,7 @@ function SecretRow({ label, secretKey, isSet, scope, globalMode, onSave, onDelet
<button type="button" <button type="button"
onClick={() => { onSave(value); setEditing(false); setValue(""); }} onClick={() => { onSave(value); setEditing(false); setValue(""); }}
disabled={!value} disabled={!value}
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink disabled:opacity-30" className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30"
>Save</button> >Save</button>
</div> </div>
)} )}
@ -184,7 +184,7 @@ function CustomSecretRow({ secretKey, scope, globalMode, onSave, onDelete }: {
<button type="button" <button type="button"
onClick={() => { onSave(value); setEditing(false); setValue(""); }} onClick={() => { onSave(value); setEditing(false); setValue(""); }}
disabled={!value} disabled={!value}
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink disabled:opacity-30" className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30"
>Save</button> >Save</button>
</div> </div>
)} )}
@ -298,7 +298,7 @@ export function SecretsSection({ workspaceId, requiredEnv }: { workspaceId: stri
<button <button
onClick={() => setGlobalMode(false)} onClick={() => setGlobalMode(false)}
className={`text-[10px] px-2 py-0.5 rounded transition-colors ${ className={`text-[10px] px-2 py-0.5 rounded transition-colors ${
!globalMode ? "bg-accent-strong/20 text-accent border border-accent/30" : "text-ink-soft hover:text-ink-mid" !globalMode ? "bg-accent-strong/20 text-accent border border-accent/30" : "text-white-soft hover:text-white-mid"
}`} }`}
> >
This Workspace This Workspace
@ -306,7 +306,7 @@ export function SecretsSection({ workspaceId, requiredEnv }: { workspaceId: stri
<button <button
onClick={() => setGlobalMode(true)} onClick={() => setGlobalMode(true)}
className={`text-[10px] px-2 py-0.5 rounded transition-colors ${ className={`text-[10px] px-2 py-0.5 rounded transition-colors ${
globalMode ? "bg-amber-600/20 text-warm border border-amber-500/30" : "text-ink-soft hover:text-ink-mid" globalMode ? "bg-amber-600/20 text-warm border border-amber-500/30" : "text-white-soft hover:text-white-mid"
}`} }`}
> >
Global (All Workspaces) Global (All Workspaces)
@ -356,11 +356,11 @@ export function SecretsSection({ workspaceId, requiredEnv }: { workspaceId: stri
className="w-full bg-surface-sunken border border-line rounded px-2 py-1 text-[10px] text-ink focus:outline-none focus:border-accent" /> className="w-full bg-surface-sunken border border-line rounded px-2 py-1 text-[10px] text-ink focus:outline-none focus:border-accent" />
<div className="flex gap-2"> <div className="flex gap-2">
<button type="button" onClick={() => { if (newKey && newValue) handleSave(newKey, newValue); }} disabled={!newKey || !newValue} <button type="button" onClick={() => { if (newKey && newValue) handleSave(newKey, newValue); }} disabled={!newKey || !newValue}
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-ink disabled:opacity-30"> className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30">
Save{globalMode ? " (Global)" : ""} Save{globalMode ? " (Global)" : ""}
</button> </button>
<button type="button" onClick={() => { setShowAdd(false); setNewKey(""); setNewValue(""); }} <button type="button" onClick={() => { setShowAdd(false); setNewKey(""); setNewValue(""); }}
className="px-2 py-1 bg-surface-card hover:bg-zinc-600 text-[10px] rounded text-ink-mid">Cancel</button> className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid">Cancel</button>
</div> </div>
</div> </div>
) : ( ) : (