Index: src/routes/guardian.js
===================================================================
--- src/routes/guardian.js	(revision cf5073b552c7838fa094219d78e0171228901205)
+++ src/routes/guardian.js	(revision f3a2556ad5919c65a0ce1e55e8f050154d1dfa8e)
@@ -123,5 +123,5 @@
       embeds: wardEmbedSetting(w.other_uri),
       playback: wardPlaybackSetting(w.other_uri),
-      guardians: wardGuardianStatuses(w.other_uri),
+      guardians: Guardianship.queues.wardGuardianStatuses(w.other_uri),
       // What THIS guardian proposed for this ward and how it stands (5.6):
       // open, accepted, rejected, or expired when the window ran out and the
@@ -135,5 +135,5 @@
       // de drempel (shaer-ahy.1). Losse knoppen lieten een guardian zelf
       // uitzoeken wat er allemaal geldt; wat niet verstelbaar is stond nergens.
-      gates: wardGates(site.slug, w.other_uri),
+      gates: Guardianship.queues.wardGates(site.slug, w.other_uri),
     })),
     offers: Guardianship.offersCollection(`${me}/queues/offers`, site.slug, me).orderedItems,
@@ -155,25 +155,4 @@
 }
 
-/** The guardians of a ward WE host, with availability (3.6.1: owner-only in
- *  spirit; the co-guardians are among the owners of the relationship). Null
- *  for a remote ward: its server tracks availability, not us. */
-function wardGuardianStatuses(wardUri) {
-  const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
-  if (!base || !String(wardUri || '').startsWith(`${base}/`)) return null;
-  const slug = String(wardUri).trim().replace(/\/+$/, '').split('/').pop();
-  try {
-    const uris = Guardianship.listGuardians(slug).map((g) => ({ uri: g.other_uri, handle: g.other_handle }));
-    const st = Object.fromEntries(
-      Guardianship.availability.statusesFor(slug, uris.map((u) => u.uri), Date.now()).map((s) => [s.id, s]),
-    );
-    return uris.map((u) => ({
-      uri: u.uri,
-      handle: u.handle,
-      availability: (st[u.uri] || {})['shaer:availability'] || 'active',
-      awayUntil: (st[u.uri] || {})['shaer:awayUntil'] || null,
-      lapse: (st[u.uri] || {})['shaer:lapse'] || null,
-    }));
-  } catch { return null; }
-}
 
 // ── The PWA page ─────────────────────────────────────────────────────────
@@ -578,5 +557,5 @@
     return res.status(403).json({ error: 'not_my_ward' });
   }
-  const local = wardGuardianStatuses(uri);
+  const local = Guardianship.queues.wardGuardianStatuses(uri);
   if (local) return res.json({ local: true, guardians: local });
   const doc = await AP.fetchActor(uri).catch(() => null);
@@ -613,31 +592,4 @@
 /** The playback gate of a ward we host (5.6): the heavier sibling. */
 function wardPlaybackSetting(uri) { return wardGateSetting(uri, 'external_playback'); }
-/**
- * De gate-rijen van een ward voor het paneel.
- *
- * De standen komen uit onze eigen kolommen als we het kind hosten; bij een ward
- * elders weten we ze niet en blijft het NULL -- onbekend, niet uit. Het aantal
- * guardians idem: dat wordt op de server van die ward bijgehouden, en zonder dat
- * getal wordt er geen drempel verzonnen.
- */
-function wardGates(mySlug, wardUri) {
-  const statuses = wardGuardianStatuses(wardUri);
-  const wachtend = Guardianship.follows.listReviewsByDirection(mySlug, 'incoming')
-    .filter((r) => r.ward_uri === wardUri).length;
-  return Guardianship.gated.gateRows({
-    // Uit de BESLUITEN, niet uit onze eigen kolom. Er zijn geen lokale accounts:
-    // elke ward woont elders, dus wardEmbedSetting() gaf voor iedere ward null en
-    // stond er in het paneel overal "onbekend". Wat een guardian wel heeft is de
-    // uitslag van wat hij voorstelde.
-    settings: Object.fromEntries(Guardianship.gated.GATE_CATALOGUE
-      .filter((g) => g.available !== false && Guardianship.gated.featureColumn(g.feature))
-      .map((g) => [g.feature, Guardianship.gated.knownSetting(mySlug, wardUri, g.feature)])),
-    guardianCount: statuses ? statuses.length : null,
-    proposals: Guardianship.gated.listSent(mySlug, wardUri).map((p) => ({
-      feature: p.feature, value: !!p.value, status: Guardianship.gated.sentStatus(p, Date.now()),
-    })),
-    waiting: { 'shaer:follows': wachtend || undefined },
-  });
-}
 
 function wardGateSetting(uri, column) {
Index: src/services/guardianship/index.js
===================================================================
--- src/services/guardianship/index.js	(revision cf5073b552c7838fa094219d78e0171228901205)
+++ src/services/guardianship/index.js	(revision f3a2556ad5919c65a0ce1e55e8f050154d1dfa8e)
@@ -32,4 +32,5 @@
 // §5.6 gated settings (decided by the guardians, enforced by the ward's server)
 export * as gated from './gated.js';
+export * as queues from './queues.js';
 // 5.2.1: wie er op een hulpvraag af is en wanneer hij is afgesloten (shaer-lgo)
 export * as help from './help.js';
Index: src/services/guardianship/queues.js
===================================================================
--- src/services/guardianship/queues.js	(revision cf5073b552c7838fa094219d78e0171228901205)
+++ src/services/guardianship/queues.js	(revision f3a2556ad5919c65a0ce1e55e8f050154d1dfa8e)
@@ -14,4 +14,5 @@
 import * as outgoing from './outgoing.js';
 import * as follows from './follows.js';
+import * as gated from './gated.js';
 import * as handshake from './handshake.js';
 
@@ -94,5 +95,14 @@
 export function wardsCollection(id, slug) {
   const items = relations.listWards(slug)
-    .map((r) => ({ id: r.other_uri, 'shaer:handle': r.other_handle || undefined, since: r.created_at }));
+    .map((r) => ({
+      id: r.other_uri,
+      'shaer:handle': r.other_handle || undefined,
+      since: r.created_at,
+      // Alles wat voor dit kind gated is, met soort, drempel en lopend voorstel
+      // (shaer-ahy.1). Zonder dit kon een app wel een ward TONEN maar niets over
+      // hem zeggen -- en dat is precies de helft van het antwoord op "wat mag
+      // dit kind". Dezelfde rijen als het PWA-paneel, uit dezelfde functie.
+      'shaer:gates': wardGates(slug, r.other_uri),
+    }));
   return collection(id, items);
 }
@@ -105,3 +115,59 @@
 }
 
-export default { offersCollection, followsCollection, outgoingFollowsCollection, wardsCollection, guardiansCollection };
+export default { offersCollection, followsCollection, outgoingFollowsCollection, wardsCollection, guardiansCollection, wardGates, wardGuardianStatuses };
+
+// ── Wat er voor een ward gated is (shaer-ahy.1) ─────────────────────────
+//
+// STOND IN routes/guardian.js, en daar kon alleen de PWA erbij. De Shaer-apps
+// lezen dezelfde toestand via de wards-queue, en een tweede berekening naast
+// deze zou vroeg of laat een ander antwoord geven op dezelfde vraag -- dat is
+// hier geen schoonheidsfoutje maar twee guardians die een verschillend beeld
+// van hetzelfde kind krijgen. Een plek dus, en beide schermen lezen eruit.
+/** The guardians of a ward WE host, with availability (3.6.1: owner-only in
+ *  spirit; the co-guardians are among the owners of the relationship). Null
+ *  for a remote ward: its server tracks availability, not us. */
+export function wardGuardianStatuses(wardUri) {
+  const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
+  if (!base || !String(wardUri || '').startsWith(`${base}/`)) return null;
+  const slug = String(wardUri).trim().replace(/\/+$/, '').split('/').pop();
+  try {
+    const uris = relations.listGuardians(slug).map((g) => ({ uri: g.other_uri, handle: g.other_handle }));
+    const st = Object.fromEntries(
+      availability.statusesFor(slug, uris.map((u) => u.uri), Date.now()).map((s) => [s.id, s]),
+    );
+    return uris.map((u) => ({
+      uri: u.uri,
+      handle: u.handle,
+      availability: (st[u.uri] || {})['shaer:availability'] || 'active',
+      awayUntil: (st[u.uri] || {})['shaer:awayUntil'] || null,
+      lapse: (st[u.uri] || {})['shaer:lapse'] || null,
+    }));
+  } catch { return null; }
+}
+/**
+ * De gate-rijen van een ward voor het paneel.
+ *
+ * De standen komen uit onze eigen kolommen als we het kind hosten; bij een ward
+ * elders weten we ze niet en blijft het NULL -- onbekend, niet uit. Het aantal
+ * guardians idem: dat wordt op de server van die ward bijgehouden, en zonder dat
+ * getal wordt er geen drempel verzonnen.
+ */
+export function wardGates(mySlug, wardUri) {
+  const statuses = wardGuardianStatuses(wardUri);
+  const wachtend = follows.listReviewsByDirection(mySlug, 'incoming')
+    .filter((r) => r.ward_uri === wardUri).length;
+  return gated.gateRows({
+    // Uit de BESLUITEN, niet uit onze eigen kolom. Er zijn geen lokale accounts:
+    // elke ward woont elders, dus wardEmbedSetting() gaf voor iedere ward null en
+    // stond er in het paneel overal "onbekend". Wat een guardian wel heeft is de
+    // uitslag van wat hij voorstelde.
+    settings: Object.fromEntries(gated.GATE_CATALOGUE
+      .filter((g) => g.available !== false && gated.featureColumn(g.feature))
+      .map((g) => [g.feature, gated.knownSetting(mySlug, wardUri, g.feature)])),
+    guardianCount: statuses ? statuses.length : null,
+    proposals: gated.listSent(mySlug, wardUri).map((p) => ({
+      feature: p.feature, value: !!p.value, status: gated.sentStatus(p, Date.now()),
+    })),
+    waiting: { 'shaer:follows': wachtend || undefined },
+  });
+}
