Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 73abbfd894337dbe548ee2838a190c2ebfbd91b7)
+++ src/services/ActivityPubService.js	(revision be5d86caaf66458e2775c9abc28272988f49406a)
@@ -949,5 +949,5 @@
 // Turn #hashtags in reply text into Mastodon-style hashtag links (clickable + federated).
 function linkHashtags(base, html) {
-  return String(html || '').replace(/(^|[\s>])#([A-Za-z0-9_]+)/g, (m, pre, tag) =>
+  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>`);
 }
@@ -955,5 +955,5 @@
 function hashtagTags(base, content) {
   const tags = [], seen = new Set();
-  const re = /class="[^"]*\bhashtag\b[^"]*"[^>]*>#([A-Za-z0-9_]+)</gi;
+  const re = /class="[^"]*\bhashtag\b[^"]*"[^>]*>#([\p{L}\p{M}\p{N}_]+)</giu;
   let m;
   while ((m = re.exec(content || ''))) {
@@ -979,5 +979,5 @@
 // slug/href stays lowercase ("livemusic").
 function tagParts(raw) {
-  const words = String(raw || '').trim().split(/[\s_]+/).map((w) => w.replace(/[^A-Za-z0-9]/g, '')).filter(Boolean);
+  const words = String(raw || '').trim().split(/[\s_]+/).map((w) => w.replace(/[^\p{L}\p{M}\p{N}]/gu, '')).filter(Boolean);
   if (!words.length) return null;
   const slug = words.join('').toLowerCase();
@@ -1019,5 +1019,5 @@
   const inboxes = [];
   const handles = new Set();
-  const re = /(^|[\s>])@([A-Za-z0-9_.-]+@[A-Za-z0-9.-]+)/g;
+  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]);
@@ -1032,5 +1032,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 + '(?![A-Za-z0-9_.-])', 'g'),
+    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>`);
   }
