diff --git a/frontend/src/components/ui/Combobox.tsx b/frontend/src/components/ui/Combobox.tsx
index aa87f9ee..5b1eebfc 100644
--- a/frontend/src/components/ui/Combobox.tsx
+++ b/frontend/src/components/ui/Combobox.tsx
@@ -1,7 +1,8 @@
import clsx from "clsx";
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
import { useTranslation } from "react-i18next";
-import { Check, ChevronDown } from "lucide-react";
+import { ChevronDown } from "lucide-react";
+import { MenuCheck } from "./MenuCheck";
import { PopoverSurface, PopoverItem } from "./AnchoredPopover";
import { useAnchoredPopover } from "./anchoredPopoverHooks";
import { useScrollFade } from "../../lib/useScrollFade";
@@ -285,13 +286,7 @@ export default function Combobox({
renderOption(o, on)
) : (
<>
-
- {on && }
-
+
{o.label ?? o.value}
{o.count != null && (
diff --git a/frontend/src/components/ui/FilterSelect.tsx b/frontend/src/components/ui/FilterSelect.tsx
index 49a821be..d310cc06 100644
--- a/frontend/src/components/ui/FilterSelect.tsx
+++ b/frontend/src/components/ui/FilterSelect.tsx
@@ -1,5 +1,5 @@
import { useState } from "react";
-import { Check } from "lucide-react";
+import { MenuCheck } from "./MenuCheck";
import { SelectTrigger } from "./SelectTrigger";
import { PopoverItem, PopoverSurface } from "./AnchoredPopover";
import { useAnchoredPopover } from "./anchoredPopoverHooks";
@@ -129,17 +129,7 @@ export default function FilterSelect({
on ? "text-fg" : "text-muted"
}`}
>
- {multiple ? (
-
- {on && }
-
- ) : (
-
- )}
+
{o.label}
{o.count != null && (
{o.count}
diff --git a/frontend/src/components/ui/menuCheck.contract.test.ts b/frontend/src/components/ui/menuCheck.contract.test.ts
new file mode 100644
index 00000000..3d9a97f0
--- /dev/null
+++ b/frontend/src/components/ui/menuCheck.contract.test.ts
@@ -0,0 +1,19 @@
+import { readdirSync, readFileSync } from "node:fs";
+import { describe, expect, it } from "vitest";
+
+// E28 review L2: `ui/MenuCheck` is the ONE drawn check box of a checkable row (S3e3b replaced seven
+// hand-drawn copies), yet FilterSelect and Combobox still painted their own — a 14px box beside the
+// menus' 16px one. The filled-box paint is the tell: it may live in MenuCheck only.
+describe("the drawn check box", () => {
+ it("is painted by MenuCheck alone", () => {
+ const root = new URL("../", import.meta.url);
+ const offenders = readdirSync(root, { recursive: true, encoding: "utf8" })
+ .filter((f) => f.endsWith(".tsx") && !f.includes(".test.") && !f.endsWith("MenuCheck.tsx"))
+ .filter((f) =>
+ /border-accent bg-accent text-accent-fg/.test(
+ readFileSync(new URL(f.replace(/\\/g, "/"), root), "utf8"),
+ ),
+ );
+ expect(offenders).toEqual([]);
+ });
+});