Index: src/routes/guardian2.js
===================================================================
--- src/routes/guardian2.js	(revision 5c373b8e846c6510a176f2fa06bfe3e2b6753102)
+++ src/routes/guardian2.js	(revision e62f65d51ce6e100e8c44bd84a06c8731f893a03)
@@ -40,5 +40,8 @@
     'pending', 'active', 'retract', 'release', 'open', 'push_unavailable',
     'accept', 'reject', 'complete', 'awaiting_others', 'coguard'];
-  return Object.fromEntries(keys.map((k) => [k, i18nT(L, `guardian.${k}`)]));
+  const s = Object.fromEntries(keys.map((k) => [k, i18nT(L, `guardian.${k}`)]));
+  s.wave = i18nT(L, 'guardian2.wave');
+  s.waved = i18nT(L, 'guardian2.waved');
+  return s;
 }
 
@@ -170,4 +173,20 @@
   } catch (e) { return res.status(502).json({ error: 'delivery', outcome: r.outcome }); }
   res.json({ ok: true, outcome: r.outcome });
+});
+
+// ── Wave (FEP-633c §5, shaer:wave): a gentle "thinking of you" from a
+//    guardian to a ward. A private direct note, never a feed post. Warmth
+//    without publishing (Robins besluit).
+router.post('/api/wave', requireAuth, express.json({ limit: '2kb' }), async (req, res) => {
+  const site = siteForUser(req);
+  if (!site) return res.status(404).json({ error: 'no_site' });
+  const wardUri = String(req.body?.ward || '').trim();
+  // Only wave at a ward you actually guard.
+  const isWard = Guardianship.listWards(site.slug).some((w) => w.other_uri === wardUri);
+  if (!wardUri || !isWard) return res.status(403).json({ error: 'not_your_ward' });
+  const text = String(req.body?.text || '').trim().slice(0, 200) || '👋 thinking of you';
+  const r = await AP.deliverDirectNote(site, { recipients: [wardUri], text, wave: true }).catch(() => null);
+  if (!r) return res.status(502).json({ error: 'delivery' });
+  res.json({ ok: true, delivered: r.delivered });
 });
 
