Index: src/routes/guardian.js
===================================================================
--- src/routes/guardian.js	(revision e84ce323dc022a50b67b2190764a08eff6302a1b)
+++ src/routes/guardian.js	(revision c26cc18be55079e31ab7f92b27f94d8de391003e)
@@ -31,5 +31,6 @@
 /** Everything the dashboard shows, one shape for page and API. */
 function uiStrings(L) {
-  const keys = ['sent', 'failed', 'network', 'pending', 'retract', 'release'];
+  const keys = ['sent', 'sent_retry', 'sending', 'not_found', 'failed', 'network',
+    'pending', 'active', 'retract', 'release', 'open', 'push_unavailable'];
   return Object.fromEntries(keys.map((k) => [k, i18nT(L, `guardian.${k}`)]));
 }
@@ -80,5 +81,5 @@
   if (!handle) return res.status(400).json({ error: 'empty_handle' });
   const wardUri = /^https?:\/\//i.test(handle) ? handle : await AP.webfingerResolve(handle).catch(() => null);
-  if (!wardUri) return res.status(404).json({ error: 'not_found' });
+  if (!wardUri) return res.status(404).json({ error: 'not_found' });   // the handle does not resolve to an account
   const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
   const me = AP.actorId(base, site.slug);
@@ -87,6 +88,8 @@
     object: { type: 'Relationship', subject: wardUri, relationship: 'shaer:Guardian', object: me },
   });
-  if (!r || r.status >= 400) return res.status(r?.status || 500).json({ error: r?.error || 'offer_failed' });
-  res.json({ ok: true, ward: wardUri });
+  // 403/400 = a real refusal (e.g. you are a ward yourself); anything else the
+  // offer is recorded and delivery is retried in the background.
+  if (!r || (r.status >= 400 && r.status !== 502)) return res.status(r?.status || 500).json({ error: r?.error || 'offer_failed' });
+  res.json({ ok: true, ward: wardUri, delivered: r.delivered !== false });
 });
 
