diff --git a/frontend/src/components/git/ForgejoIssuesTable.tsx b/frontend/src/components/git/ForgejoIssuesTable.tsx
index 431f63f..e43e74d 100644
--- a/frontend/src/components/git/ForgejoIssuesTable.tsx
+++ b/frontend/src/components/git/ForgejoIssuesTable.tsx
@@ -13,7 +13,44 @@ import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { DataTable } from "@/components/tables/DataTable";
import { CloseForgejoIssueDialog } from "@/components/git/CloseForgejoIssueDialog";
-import type { ForgejoIssue } from "@/lib/api-forgejo";
+import type { ForgejoIssue, ForgejoIssueLabel } from "@/lib/api-forgejo";
+
+/** Normalize a Forgejo label color to a valid 6-char hex string or null. */
+function normalizeLabelColor(raw: string | null | undefined): string | null {
+ if (!raw) return null;
+ const hex = raw.replace(/^#+/, "");
+ return /^[0-9a-fA-F]{3,6}$/.test(hex) ? `#${hex.padEnd(6, "0")}` : null;
+}
+
+/** Return white or dark text based on WCAG relative luminance of a hex background. */
+function labelTextColor(hex: string): string {
+ const h = hex.replace("#", "");
+ const r = parseInt(h.slice(0, 2), 16) / 255;
+ const g = parseInt(h.slice(2, 4), 16) / 255;
+ const b = parseInt(h.slice(4, 6), 16) / 255;
+ const lin = (c: number) =>
+ c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
+ const L = 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
+ return L > 0.179 ? "#1a1a1a" : "#ffffff";
+}
+
+function LabelChip({ label }: { label: ForgejoIssueLabel }) {
+ const bg = normalizeLabelColor(label.color);
+ return (
+