diff --git a/apps/web/src/app.css b/apps/web/src/app.css
index 7180f16d5..e8ff19dc7 100644
--- a/apps/web/src/app.css
+++ b/apps/web/src/app.css
@@ -8,6 +8,7 @@
@import "./chat/styles.css";
@import "./bench/styles.css";
@import "./settings/styles.css";
+@import "./button-roles.css";
/* react-ui's `.corbits-toast` ships a hardcoded horizontal-center transform
(`left: 50%; transform: translateX(-50%) !important`) regardless of the
diff --git a/apps/web/src/button-roles.css b/apps/web/src/button-roles.css
new file mode 100644
index 000000000..8093c1af3
--- /dev/null
+++ b/apps/web/src/button-roles.css
@@ -0,0 +1,22 @@
+/* Button roles from DESIGN.md "Color roles". Primary is charcoal via the
+ `--primary` token; its icon carries the orange. Orange never fills. */
+[data-slot="button"].bg-primary svg {
+ color: var(--action);
+}
+
+/* Danger-ghost: text-only red for everyday refusals (Deny, Remove). */
+[data-slot="button"].btn-danger-ghost {
+ color: var(--danger);
+}
+[data-slot="button"].btn-danger-ghost:hover {
+ background: var(--danger-wash);
+ color: var(--danger);
+}
+[data-slot="button"].bg-destructive:hover {
+ background: var(--danger-hover);
+ opacity: 1;
+}
+[data-slot="button"].bg-destructive:focus-visible,
+[data-slot="button"].btn-danger-ghost:focus-visible {
+ outline-color: var(--danger);
+}
diff --git a/apps/web/src/chat/approval-row.tsx b/apps/web/src/chat/approval-row.tsx
index 19d4fd51a..e60177c67 100644
--- a/apps/web/src/chat/approval-row.tsx
+++ b/apps/web/src/chat/approval-row.tsx
@@ -59,6 +59,7 @@ export function ApprovalRow({
onDelete(role)}