-
+
+
RelyLoop
-
+ {/* Horizontal scroll below the breakpoint so the 9 items stay usable on
+ narrow screens instead of overflowing the viewport. */}
+
{NAV_ITEMS.map(({ href, label }) => {
const active = isActive(pathname, href);
return (
@@ -47,10 +50,10 @@ export function TopNav() {
data-active={active ? 'true' : 'false'}
aria-current={active ? 'page' : undefined}
className={cn(
- 'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
+ 'block whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
active
- ? 'bg-gray-900 text-white'
- : 'text-gray-700 hover:bg-gray-100 hover:text-gray-900',
+ ? 'bg-primary text-primary-foreground'
+ : 'text-muted-foreground hover:bg-muted hover:text-foreground',
)}
>
{label}
@@ -59,6 +62,7 @@ export function TopNav() {
);
})}
+
);
diff --git a/ui/src/components/proposals/proposal-error-alert.tsx b/ui/src/components/proposals/proposal-error-alert.tsx
index 8fdc4527..8c034bde 100644
--- a/ui/src/components/proposals/proposal-error-alert.tsx
+++ b/ui/src/components/proposals/proposal-error-alert.tsx
@@ -4,19 +4,17 @@
'use client';
+import { Alert } from '@/components/ui/alert';
+
export interface ProposalErrorAlertProps {
error: string;
}
export function ProposalErrorAlert({ error }: ProposalErrorAlertProps) {
return (
-
+
Open-PR worker reported an error
{error}
-
+
);
}
diff --git a/ui/src/components/studies/comparison/convergence-overlay.tsx b/ui/src/components/studies/comparison/convergence-overlay.tsx
index 0f70194b..839728ac 100644
--- a/ui/src/components/studies/comparison/convergence-overlay.tsx
+++ b/ui/src/components/studies/comparison/convergence-overlay.tsx
@@ -81,6 +81,9 @@ export function ConvergenceOverlay({ llmCurve, ubiCurve }: ConvergenceOverlayPro
dataKey="ubi"
name="UBI"
stroke="#16a34a"
+ // Dashed so the two series are distinguishable without relying
+ // on color alone (deuteranopia-safe).
+ strokeDasharray="5 4"
connectNulls
dot={false}
/>
diff --git a/ui/src/components/ui/alert.tsx b/ui/src/components/ui/alert.tsx
new file mode 100644
index 00000000..99b84023
--- /dev/null
+++ b/ui/src/components/ui/alert.tsx
@@ -0,0 +1,36 @@
+// SPDX-FileCopyrightText: 2026 soundminds.ai
+//
+// SPDX-License-Identifier: Apache-2.0
+
+import { cva, type VariantProps } from 'class-variance-authority';
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+/**
+ * Token-driven inline callout. Replaces the hand-rolled `border-*-200 bg-*-50`
+ * boxes scattered across the app (which were light-only and drifted in
+ * padding/weight). Variants keep the semantic color families but carry `dark:`
+ * pairs so they read correctly on a dark surface.
+ */
+const alertVariants = cva('rounded-md border p-3 text-sm', {
+ variants: {
+ variant: {
+ info: 'border-blue-200 bg-blue-50 text-blue-900 dark:border-blue-900 dark:bg-blue-950 dark:text-blue-200',
+ warning:
+ 'border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-900 dark:bg-amber-950 dark:text-amber-200',
+ destructive:
+ 'border-red-200 bg-red-50 text-red-900 dark:border-red-900 dark:bg-red-950 dark:text-red-200',
+ },
+ },
+ defaultVariants: { variant: 'info' },
+});
+
+export interface AlertProps
+ extends React.HTMLAttributes
, VariantProps {}
+
+export function Alert({ className, variant, ...props }: AlertProps) {
+ return ;
+}
+
+export { alertVariants };
diff --git a/ui/src/components/ui/badge.tsx b/ui/src/components/ui/badge.tsx
index e750d6d2..b57559e1 100644
--- a/ui/src/components/ui/badge.tsx
+++ b/ui/src/components/ui/badge.tsx
@@ -11,13 +11,19 @@ const badgeVariants = cva(
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
{
variants: {
+ // Light classes kept (semantic color families: blue=active, green=ok,
+ // amber=warn, red=fail); dark: variants added so chips read correctly on
+ // a dark surface instead of floating as light pastels.
variant: {
- default: 'border-transparent bg-blue-100 text-blue-900',
- secondary: 'border-transparent bg-gray-100 text-gray-700',
- destructive: 'border-transparent bg-red-100 text-red-900',
- outline: 'border-gray-200 text-gray-700',
- success: 'border-transparent bg-green-100 text-green-900',
- warning: 'border-transparent bg-amber-100 text-amber-900',
+ default: 'border-transparent bg-blue-100 text-blue-900 dark:bg-blue-950 dark:text-blue-200',
+ secondary:
+ 'border-transparent bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-200',
+ destructive: 'border-transparent bg-red-100 text-red-900 dark:bg-red-950 dark:text-red-200',
+ outline: 'border-gray-200 text-gray-700 dark:border-gray-700 dark:text-gray-200',
+ success:
+ 'border-transparent bg-green-100 text-green-900 dark:bg-green-950 dark:text-green-200',
+ warning:
+ 'border-transparent bg-amber-100 text-amber-900 dark:bg-amber-950 dark:text-amber-200',
},
},
defaultVariants: {
diff --git a/ui/src/components/ui/card.tsx b/ui/src/components/ui/card.tsx
index 9dd42820..0d328b76 100644
--- a/ui/src/components/ui/card.tsx
+++ b/ui/src/components/ui/card.tsx
@@ -10,7 +10,7 @@ const Card = React.forwardRef
>(({ className, ...props }, ref) => (
-
+
));
CardDescription.displayName = 'CardDescription';