Index: CHANGELOG.de.md
===================================================================
--- CHANGELOG.de.md	(revision 2abd3d2298692016e4857691d7085d151fbe9727)
+++ CHANGELOG.de.md	(revision fc229f55a683c877e6f7776cb2b31f8368235062)
@@ -40,4 +40,8 @@
 
 ### Behoben
+- **Erwähnungen, Hashtags und Links in Klammern funktionieren jetzt.** Eine Erwähnung wie
+  `(@benutzer@server)`, ein `(#hashtag)` oder eine URL in Klammern föderierte als reiner Text —
+  und die erwähnte Person wurde nie benachrichtigt. Sie verlinken (und benachrichtigen) jetzt wie
+  ohne Klammern.
 - **Nackte Webadressen werden im Fediverse zu Links.** Eine einfache URL in einem Beitrag oder einer
   Antwort föderiert jetzt als klickbarer Link statt als reiner Text.
Index: CHANGELOG.md
===================================================================
--- CHANGELOG.md	(revision 2abd3d2298692016e4857691d7085d151fbe9727)
+++ CHANGELOG.md	(revision fc229f55a683c877e6f7776cb2b31f8368235062)
@@ -35,4 +35,7 @@
 
 ### Fixed
+- **Mentions, hashtags and links inside brackets now work.** A mention like `(@user@server)`, a
+  `(#hashtag)` or a bracketed URL federated as plain text — and the mentioned person was never
+  notified. They now link (and notify) like their unbracketed forms.
 - **Plain web addresses become links on the fediverse.** A bare URL typed in a post or reply now
   federates as a clickable link instead of plain text.
Index: CHANGELOG.nl.md
===================================================================
--- CHANGELOG.nl.md	(revision 2abd3d2298692016e4857691d7085d151fbe9727)
+++ CHANGELOG.nl.md	(revision fc229f55a683c877e6f7776cb2b31f8368235062)
@@ -38,4 +38,7 @@
 
 ### Opgelost
+- **Vermeldingen, hashtags en links tussen haakjes werken nu.** Een vermelding als
+  `(@gebruiker@server)`, een `(#hashtag)` of een URL tussen haakjes federeerde als platte tekst —
+  en de genoemde persoon kreeg nooit een melding. Ze linken (en melden) nu net als zonder haakjes.
 - **Kale webadressen worden links op de fediverse.** Een losse URL in een post of reactie federeert
   nu als klikbare link in plaats van platte tekst.
Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 2abd3d2298692016e4857691d7085d151fbe9727)
+++ src/services/ActivityPubService.js	(revision fc229f55a683c877e6f7776cb2b31f8368235062)
@@ -1402,5 +1402,7 @@
 // Turn #hashtags in reply text into Mastodon-style hashtag links (clickable + federated).
 function linkHashtags(base, html) {
-  return String(html || '').replace(/(^|[\s>])#([\p{L}\p{M}\p{N}_]+)/gu, (m, pre, tag) =>
+  // Prefix: start / whitespace / '>' / opening bracket — "(#tag" is a tag too. NO quote
+  // chars in this class: a quote precedes attribute values (alt="#…"), which must not match.
+  return String(html || '').replace(/(^|[\s>([{])#([\p{L}\p{M}\p{N}_]+)/gu, (m, pre, tag) =>
     `${pre}<a href="${base}/tag/${encodeURIComponent(tag.toLowerCase())}" class="mention hashtag" rel="tag">#${tag}</a>`);
 }
@@ -1413,5 +1415,5 @@
   for (let i = 0; i < parts.length; i++) {
     if (/^<a\b/i.test(parts[i])) continue; // already a link → leave as-is
-    parts[i] = parts[i].replace(/(^|[\s>])(https?:\/\/[^\s<]+?)([.,;:!?)\]»]*)(?=$|[\s<])/g,
+    parts[i] = parts[i].replace(/(^|[\s>([{])(https?:\/\/[^\s<]+?)([.,;:!?)\]»]*)(?=$|[\s<])/g,
       (m, pre, url, trail) => `${pre}<a href="${url.replace(/"/g, '%22')}" rel="nofollow noopener" target="_blank">${url}</a>${trail}`);
   }
@@ -1485,5 +1487,7 @@
   const inboxes = [];
   const handles = new Set();
-  const re = /(^|[\s>])@([\p{L}\p{M}\p{N}_.-]+@[\p{L}\p{M}\p{N}.-]+)/gu;
+  // Prefix also allows opening brackets — "(@user@host + me)" is a mention too (real-world
+  // miss: a bracketed mention federated as plain text and its target was never notified).
+  const re = /(^|[\s>([{])@([\p{L}\p{M}\p{N}_.-]+@[\p{L}\p{M}\p{N}.-]+)/gu;
   let m;
   while ((m = re.exec(html || ''))) handles.add(m[2]);
@@ -1498,5 +1502,5 @@
     const profileUrl = actorInfo(actor, actorUri).url || actorUri; // human profile page → the link href
     const esc = h.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
-    out = out.replace(new RegExp('(^|[\\s>])@' + esc + '(?![\\p{L}\\p{M}\\p{N}_.-])', 'gu'),
+    out = out.replace(new RegExp('(^|[\\s>([{])@' + esc + '(?![\\p{L}\\p{M}\\p{N}_.-])', 'gu'),
       (full, pre) => `${pre}<a href="${profileUrl}" class="u-url mention" data-actor="${actorUri}">@${h}</a>`);
   }
Index: test/url-linkify.test.js
===================================================================
--- test/url-linkify.test.js	(revision 2abd3d2298692016e4857691d7085d151fbe9727)
+++ test/url-linkify.test.js	(revision fc229f55a683c877e6f7776cb2b31f8368235062)
@@ -40,4 +40,17 @@
 });
 
+test('a URL inside parentheses links, closing paren stays outside', () => {
+  const n = note('<p>site (https://example.com/a) hier</p>');
+  assert.match(n.content, /\(<a href="https:\/\/example\.com\/a"[^>]*>https:\/\/example\.com\/a<\/a>\)/);
+});
+
+test('a hashtag inside parentheses still links; quoted attribute values never match', () => {
+  const n = note('<p>leuk (#jazz) toch</p>');
+  assert.match(n.content, /\(<a [^>]*class="mention hashtag"[^>]*>#jazz<\/a>\)/);
+  // A quote precedes attribute values — the prefix class must NOT include quotes.
+  const n2 = note('<p>plaatje <a href="https://x.example/#frag">link</a></p>');
+  assert.equal((n2.content.match(/<a /g) || []).length, 1, 'href value untouched');
+});
+
 test('attribute values are untouched, standalone URLs still link (image stripped from content)', () => {
   const n = note('<p><img src="https://cdn.example.com/pic.png" alt=""> and https://example.org</p>');
