Index: src/services/guardianship/queues.js
===================================================================
--- src/services/guardianship/queues.js	(revision 1a2d8ac96c0af0189037f8acd658b19b875be8b0)
+++ src/services/guardianship/queues.js	(revision 780a7c655af23759b03e276bc56d8be0bc5d44ff)
@@ -3,11 +3,11 @@
  *
  * Three OrderedCollections on the actor (shaer:queues), same contract as the
- * Shaer test daemon so the iOS/Android guardian dashboards read them as-is:
- *  - offers:  pending guardianship offers where I am a party (§3)
- *  - follows: pending follows for my wards (§5.3) — Klonkt has no gated
- *             follows yet, so this collection is empty for now
- *  - wards:   my wards, for the dashboard's wards list
+ * Shaer test daemon so the iOS/Android dashboards read them as-is:
+ *  - offers:  pending handshake offers where I am a party (§3), with the full
+ *             accept tally so the client shows the right action
+ *  - follows: pending gated follows for my wards (§5.3) — Fase 2, empty for now
+ *  - wards:   my committed wards
  */
-import { GUARDIAN_RELATIONSHIP_COMPACT } from './context.js';
+import * as offers from './offers.js';
 import * as relations from './relations.js';
 
@@ -16,47 +16,18 @@
 });
 
-/** Pending offers, reconstructed as Offer activities (either side). Each item
- *  also carries the daemon-contract helper fields (shaer:ward, candidate,
- *  needsMyAccept, iAmCandidate, …): the Shaer clients render their accept
- *  button from those, so the shapes must match the test daemon exactly. */
+/** Pending offers where the local site is a party, each with its accept tally. */
 export function offersCollection(id, slug, me) {
-  const items = relations.listOffers(slug).map((r) => {
-    const ward = r.role === 'guardian' ? r.other_uri : me;
-    const candidate = r.role === 'guardian' ? me : r.other_uri;
-    return {
-      id: r.offer_id || `${me}/offers/pending-${r.id}`,
-      type: 'Offer',
-      actor: candidate,
-      object: {
-        type: 'Relationship',
-        subject: ward,
-        relationship: GUARDIAN_RELATIONSHIP_COMPACT,
-        object: candidate,
-      },
-      'shaer:ward': ward,
-      'shaer:candidate': candidate,
-      'shaer:existingGuardians': relations.listGuardians(slug).map((g) => g.other_uri),
-      'shaer:acceptedBy': [],
-      // Klonkt's flow is single-phase: the ward's Accept commits at once, so
-      // only the ward-side owner has an action here.
-      'shaer:needsMyAccept': r.role === 'ward',
-      'shaer:readyToCommit': false,
-      'shaer:iAmCandidate': r.role === 'guardian',
-      'shaer:handle': r.other_handle || undefined,
-      published: r.created_at,
-    };
-  });
+  const items = offers.listForParty(slug, me).map((o) => offers.queueItem(o, me));
   return collection(id, items);
 }
 
-/** Gated follows awaiting guardian approval — not built in Klonkt yet. */
+/** Gated follows awaiting guardian approval — not built in Klonkt yet (Fase 2). */
 export function followsCollection(id) {
   return collection(id, []);
 }
 
-/** The guardian's wards (accepted), with cached handle for display. */
+/** The guardian's committed wards, with cached handle for display. */
 export function wardsCollection(id, slug) {
   const items = relations.listWards(slug)
-    .filter((r) => r.status === 'accepted')
     .map((r) => ({ id: r.other_uri, 'shaer:handle': r.other_handle || undefined, since: r.created_at }));
   return collection(id, items);
