diff --git a/vibn-frontend/components/project/dashboard-ui.tsx b/vibn-frontend/components/project/dashboard-ui.tsx
new file mode 100644
index 0000000..d3e8bf9
--- /dev/null
+++ b/vibn-frontend/components/project/dashboard-ui.tsx
@@ -0,0 +1,690 @@
+"use client";
+
+/**
+ * Shared dashboard design system.
+ *
+ * Single source of truth for the project dashboard look-and-feel. Replaces the
+ * `INK` palette object that was copy-pasted into every page. The aesthetic is
+ * the house "ink & parchment" brand (warm neutrals, NO blue/purple chrome) but
+ * the LAYOUT patterns — settings-as-cards, label-left/action-right rows, a
+ * single primary action per area, generous spacing — are borrowed from the
+ * Base44 dashboard reference.
+ *
+ * Everything is inline-styled (matching the existing pages) so it drops into any
+ * page with zero CSS wiring. Swap the brand accent in ONE place: THEME.accent.
+ */
+
+import React, { useState } from "react";
+
+export const THEME = {
+ // Flowbite / Tailwind cool-grey ramp
+ ink: "#111827", // gray-900 (headings / primary text)
+ mid: "#4b5563", // gray-600 (body / secondary)
+ muted: "#9ca3af", // gray-400 (tertiary / meta / icons)
+ // Surfaces
+ canvas: "#f9fafb", // gray-50 page background (flat fallback)
+ // Subtle, color-free depth: a soft light at top-center easing down to gray-100.
+ // Barely-there — reads as "premium", not a colored gradient.
+ canvasGradient:
+ "radial-gradient(120% 80% at 50% 0%, #ffffff 0%, #f9fafb 52%, #f3f4f6 100%)",
+ cardBg: "#ffffff",
+ subtleBg: "#f3f4f6", // gray-100 hover / active nav pill / row stripe
+ // Lines
+ border: "#e5e7eb", // gray-200
+ borderSoft: "#f3f4f6", // gray-100
+ // Primary action — neutral graphite (gray-900) to match the grayscale chrome
+ // in the reference. For Flowbite's signature blue CTA instead, set
+ // accent/accentHover to "#1c64f2" / "#1a56db" — single-variable swap.
+ accent: "#111827",
+ accentHover: "#1f2937", // gray-800
+ accentText: "#ffffff",
+ // Destructive — Flowbite red
+ danger: "#e02424", // red-600
+ dangerBg: "#fdf2f2", // red-50
+ dangerBorder: "#f8b4b4", // red-300
+ // Shape, depth & type — Flowbite rounded-lg + soft shadow-sm, Inter type.
+ radius: 10,
+ radiusSm: 8,
+ shadow: "0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)",
+ font: '"Inter", ui-sans-serif, system-ui, -apple-system, sans-serif',
+} as const;
+
+// ── Page header ───────────────────────────────────────────────────────────
+export function PageHeader({
+ title,
+ subtitle,
+ actions,
+}: {
+ title: string;
+ subtitle?: string;
+ actions?: React.ReactNode;
+}) {
+ return (
+
+
+
+ {title}
+
+ {subtitle && (
+
+ {subtitle}
+
+ )}
+
+ {actions && (
+
{actions}
+ )}
+
+ );
+}
+
+// ── Card ────────────────────────────────────────────────────────────────────
+export function Card({
+ children,
+ style,
+ padding = 24,
+}: {
+ children: React.ReactNode;
+ style?: React.CSSProperties;
+ padding?: number;
+}) {
+ return (
+
+ {children}
+
+ );
+}
+
+// ── SettingCard — title + description left, action right (Base44 row pattern) ─
+export function SettingCard({
+ title,
+ description,
+ action,
+ danger,
+ children,
+}: {
+ title: string;
+ description?: string;
+ action?: React.ReactNode;
+ danger?: boolean;
+ children?: React.ReactNode;
+}) {
+ return (
+
+
+
+
+ {title}
+
+ {description && (
+
+ {description}
+
+ )}
+
+ {action &&
{action}
}
+
+ {children && {children}
}
+
+ );
+}
+
+// ── Section header (for grouping inside a page) ──────────────────────────────
+export function SectionHeader({
+ title,
+ count,
+}: {
+ title: string;
+ count?: number;
+}) {
+ return (
+
+
+ {title}
+
+ {typeof count === "number" && (
+
+ ({count})
+
+ )}
+
+ );
+}
+
+// ── Empty state (dashed card, centered) ────────────────────────────
+export function EmptyState({
+ icon,
+ title,
+ hint,
+ action,
+}: {
+ icon?: React.ReactNode;
+ title: string;
+ hint?: string;
+ action?: React.ReactNode;
+}) {
+ return (
+
+ {icon &&
{icon}
}
+
+ {title}
+
+ {hint && (
+
+ {hint}
+
+ )}
+ {action &&
{action}
}
+
+ );
+}
+
+// ── Buttons (icon + label; hover handled inline) ───────────────────────
+type BtnProps = {
+ children: React.ReactNode;
+ icon?: React.ReactNode;
+ onClick?: () => void;
+ type?: "button" | "submit";
+ disabled?: boolean;
+ danger?: boolean;
+};
+
+const btnBase: React.CSSProperties = {
+ display: "inline-flex",
+ alignItems: "center",
+ gap: 8,
+ padding: "9px 16px",
+ borderRadius: THEME.radiusSm,
+ fontSize: "0.875rem",
+ fontWeight: 600,
+ fontFamily: THEME.font,
+ cursor: "pointer",
+ transition: "background 0.15s ease, border-color 0.15s ease",
+ whiteSpace: "nowrap",
+};
+
+export function PrimaryButton({
+ children,
+ icon,
+ onClick,
+ type = "button",
+ disabled,
+}: BtnProps) {
+ const [hover, setHover] = useState(false);
+ return (
+
+ );
+}
+
+export function SecondaryButton({
+ children,
+ icon,
+ onClick,
+ type = "button",
+ disabled,
+ danger,
+}: BtnProps) {
+ const [hover, setHover] = useState(false);
+ const color = danger ? THEME.danger : THEME.ink;
+ const borderColor = danger ? THEME.dangerBorder : THEME.border;
+ return (
+
+ );
+}
+
+// ── List & Key-Value Rows ──────────────────────────────────────────────────
+export function ListCard({
+ children,
+ style,
+}: {
+ children: React.ReactNode;
+ style?: React.CSSProperties;
+}) {
+ return (
+
+ {children}
+
+ );
+}
+
+export function ListRow({
+ label,
+ value,
+ action,
+ icon,
+}: {
+ label: string | React.ReactNode;
+ value?: string | React.ReactNode;
+ action?: React.ReactNode;
+ icon?: React.ReactNode;
+}) {
+ return (
+
+
+ {icon &&
{icon}
}
+
+ {label}
+
+
+
+ {value && (
+
+ {value}
+
+ )}
+ {action &&
{action}
}
+
+
+ );
+}
+
+export function KvRow({
+ label,
+ value,
+ mono,
+ dot,
+}: {
+ label: string;
+ value: React.ReactNode;
+ mono?: boolean;
+ dot?: string;
+}) {
+ return (
+
+
+ {label}
+
+
+ {dot && (
+
+ )}
+ {value}
+
+
+ );
+}
+
+// ── Badges & Status ────────────────────────────────────────────────────────
+export function Badge({
+ children,
+ color = "default",
+}: {
+ children: React.ReactNode;
+ color?: "default" | "success" | "warning" | "danger" | "accent";
+}) {
+ const bg =
+ color === "success"
+ ? "#def7ec"
+ : color === "warning"
+ ? "#fdf6b2"
+ : color === "danger"
+ ? THEME.dangerBg
+ : color === "accent"
+ ? THEME.ink
+ : THEME.subtleBg;
+ const text =
+ color === "success"
+ ? "#03543f"
+ : color === "warning"
+ ? "#723b13"
+ : color === "danger"
+ ? THEME.danger
+ : color === "accent"
+ ? THEME.cardBg
+ : THEME.mid;
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function StatusDot({
+ status,
+}: {
+ status: "success" | "warning" | "danger" | "neutral";
+}) {
+ const color =
+ status === "success"
+ ? "#31c48d"
+ : status === "warning"
+ ? "#faca15"
+ : status === "danger"
+ ? THEME.danger
+ : THEME.muted;
+ return (
+
+ );
+}
+
+// ── Stat Card ──────────────────────────────────────────────────────────────
+export function StatCard({
+ label,
+ value,
+ onClick,
+}: {
+ label: string;
+ value: string | number;
+ onClick?: () => void;
+}) {
+ return (
+
+ );
+}
+
+// ── Text field (label + input/textarea) ──────────────────────────────────────
+export function TextField({
+ label,
+ defaultValue,
+ value,
+ onChange,
+ placeholder,
+ multiline,
+ rows = 3,
+}: {
+ label?: string;
+ defaultValue?: string;
+ value?: string;
+ onChange?: (v: string) => void;
+ placeholder?: string;
+ multiline?: boolean;
+ rows?: number;
+}) {
+ const [focus, setFocus] = useState(false);
+ const fieldStyle: React.CSSProperties = {
+ padding: "10px 14px",
+ border: `1px solid ${focus ? THEME.muted : THEME.border}`,
+ borderRadius: THEME.radiusSm,
+ fontSize: "0.9rem",
+ fontFamily: THEME.font,
+ color: THEME.ink,
+ background: THEME.cardBg,
+ outline: "none",
+ width: "100%",
+ boxSizing: "border-box",
+ resize: multiline ? "vertical" : undefined,
+ transition: "border-color 0.15s ease",
+ };
+ return (
+
+ {label && (
+
+ )}
+ {multiline ? (
+
+ );
+}