diff --git a/AGENTS.md b/AGENTS.md
index 8445364..9939c6a 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -2565,8 +2565,10 @@ kind-10040 provider designation** (`useSetTrustProvider`: custom npub/hex +
`wss://` relay, or clear to fall back to the community provider). The local
(non-provider) ladder is computed **once per viewer** by `useViewerGraph` and
shared, so `TrustBadge` no longer fires a per-card `useTrustScore` graph query.
-Still open: a
-mute action (no NIP-51 kind-10000 hook exists yet), counterparty alerts, and the
+**Mute landed:** `useMuteList` + `useMuteUser` (NIP-51 kind-10000, optimistic via
+`lib/localMutes.ts`) feed `useAdminModeration`'s new `mutedPubkeys`, so the
+shared `filterAdminHidden` drops muted authors across every list; the flagged
+notice has a Mute action. Still open: counterparty alerts and the
confidence-gated scoring model. Check
`TRUST_SCORE.md` before touching `useTrustScore` / `useRelatrScore` /
`trustFilter`.
diff --git a/TRUST_SCORE.md b/TRUST_SCORE.md
index b5c0454..bf82c40 100644
--- a/TRUST_SCORE.md
+++ b/TRUST_SCORE.md
@@ -58,9 +58,21 @@ flagged notice's reporter breakdown, and Settings → Trust.
community provider — a signed action, so it prompts the signer. Link to
`/trust`.
-Still open: a mute action (there is no NIP-51 kind-10000 hook yet — Dismiss is
-the local equivalent for now), counterparty alerts, and the confidence-gated
-scoring model.
+## Fourth pass — mute (landed)
+
+- **`useMuteList`** reads the viewer's NIP-51 **kind-10000** mute list plus any
+ optimistic local mutes (`lib/localMutes.ts`, `skatespots:local-mutes-v1`).
+- **`useMuteUser`** republishes kind-10000 with the target added (preserving
+ existing entries), records it locally, and invalidates content queries.
+- The shared **`filterAdminHidden` / `filterAdminHiddenMixed`** now also drop
+ authors in `hidden.mutedPubkeys`, so every list hook that already filters
+ hidden content (spots/shops/events/tours/crews/marketplace/skaters/coaches/lab)
+ hides muted accounts with **no per-hook changes**. `useAdminModeration` carries
+ the mute set alongside the admin verdicts (it is the app-wide "drop this
+ content" layer; `includeHidden` admin tooling still bypasses it).
+- The flagged notice gains a **Mute** action (Report + Mute + Dismiss).
+
+Still open: counterparty alerts and the confidence-gated scoring model.
diff --git a/src/components/TrustFlaggedNotice.tsx b/src/components/TrustFlaggedNotice.tsx
index 2b9c012..2ebf136 100644
--- a/src/components/TrustFlaggedNotice.tsx
+++ b/src/components/TrustFlaggedNotice.tsx
@@ -6,6 +6,7 @@ import { ReportDialog } from '@/components/ReportDialog';
import { useTrustBucket } from '@/hooks/useTrustBucket';
import { useUserReports } from '@/hooks/useUserReports';
import { useBatchTrustScores } from '@/hooks/useBatchTrustScores';
+import { useMuteUser } from '@/hooks/useMuteUser';
import { FLAGGED_REPORTERS_THRESHOLD } from '@/lib/trustLadder';
import { useTranslation } from '@/contexts/language';
import { cn } from '@/lib/utils';
@@ -30,6 +31,7 @@ export function TrustFlaggedNotice({ pubkey, targetTitle, className }: TrustFlag
const { data: scores } = useBatchTrustScores(reporterPubkeys);
const [dismissed, setDismissed] = useState(false);
const [reportOpen, setReportOpen] = useState(false);
+ const muteUser = useMuteUser();
const flagged = bucket === 'flagged' || reporterCount >= FLAGGED_REPORTERS_THRESHOLD;
if (!flagged || dismissed) return null;
@@ -87,6 +89,15 @@ export function TrustFlaggedNotice({ pubkey, targetTitle, className }: TrustFlag
{t('walletUi.trust.flaggedReport')}
+