Index: src/config/database.js
===================================================================
--- src/config/database.js	(revision 50e80acd22affc07719af0f0ac1a35bbb6b23819)
+++ src/config/database.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
@@ -164,4 +164,16 @@
   // never even receives the thumbnail it is not allowed to see.
   ensureColumn('sites', 'external_embeds', 'INTEGER');
+  // De rest van de gate-familie (shaer-ahy.1, "maak ze allemaal functioneel",
+  // Barts opdracht 8-8). Zelfde drietal als external_embeds: NULL is de
+  // automatiek (dicht voor een ward, open voor de rest), 0/1 is een besluit
+  // van de guardians en wint van de automatiek.
+  ensureColumn('sites', 'external_threads', 'INTEGER');   // replies van vreemden onder een post (shaer-9y2)
+  ensureColumn('sites', 'gate_images', 'INTEGER');        // afbeeldingsbijlagen (shaer-6p5)
+  ensureColumn('sites', 'gate_messages', 'INTEGER');      // heel Messages (shaer-3ow)
+  ensureColumn('sites', 'gate_compose', 'INTEGER');       // zelf posten, de (+) kaart (shaer-qgev)
+  ensureColumn('sites', 'gate_music', 'INTEGER');         // audiobijlagen (shaer-rmz)
+  ensureColumn('sites', 'gate_quote_cards', 'INTEGER');   // ingebedde quote-kaarten (shaer-mls)
+  ensureColumn('sites', 'gate_custom_emoji', 'INTEGER');  // FEP-9098 emoji-plaatjes (shaer-ytw)
+  ensureColumn('sites', 'gate_account_move', 'INTEGER');  // FEP-7628 Move (shaer-tge)
   // The heavier sibling (FEP-633c 5.6): may a player from outside this app run
   // INSIDE it? A preview is a picture; playback hands the screen to a third
Index: src/routes/activitypub.js
===================================================================
--- src/routes/activitypub.js	(revision 50e80acd22affc07719af0f0ac1a35bbb6b23819)
+++ src/routes/activitypub.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
@@ -317,4 +317,17 @@
   const playbackAllowed = embedsAllowed
     && Guardianship.externalPlaybackAllowed(auth.site.external_playback, isWard);
+  // De rest van de familie (shaer-ahy.1, 8-8): zelfde regel, zelfde plek --
+  // de poort zit bij de serialisatie, wat dicht is wordt nooit geleverd.
+  const gate = (col) => Guardianship.wardGateAllowed(auth.site[col], isWard);
+  const imagesAllowed = gate('gate_images');
+  const musicAllowed = gate('gate_music');
+  const quotesAllowed = gate('gate_quote_cards');
+  const emojiAllowed = gate('gate_custom_emoji');
+  const messagesAllowed = gate('gate_messages');
+  const composeAllowed = gate('gate_compose');
+  const threadsAllowed = gate('external_threads');
+  // Emoji dicht raakt ook de bylines: de plaatjes in een naam komen net zo
+  // goed van een vreemde server. De naam zelf blijft, met :shortcode: als tekst.
+  const gateAuthor = (a) => (a && !emojiAllowed ? { ...a, emojis: undefined } : a);
   const rows = AP.getTimeline(auth.site.slug, 60);
   // Eén query voor de hele pagina (shaer-9e9 fase 2): shaer:liked komt uit de
@@ -338,5 +351,5 @@
       // Friends' media travels along (media_json → AS2 attachment), so the
       // client renders their images/audio like own outbox posts.
-      attachment: AP.timelineAttachments(t.media_json),
+      attachment: AP.gateAttachments(AP.timelineAttachments(t.media_json), { images: imagesAllowed, audio: musicAllowed }),
       // The note's preserved tags, so the client can render them: FEP-9098
       // Emoji tags (:shortcode: → image) and FEP-e232 Link tags (quotes /
@@ -344,5 +357,5 @@
       // when the note has neither.
       tag: (() => {
-        const tags = [...(AP.timelineEmojis(t.emoji_json) || []), ...(AP.timelineObjectLinks(t.link_json) || [])];
+        const tags = [...(emojiAllowed ? (AP.timelineEmojis(t.emoji_json) || []) : []), ...(AP.timelineObjectLinks(t.link_json) || [])];
         return tags.length ? tags : undefined;
       })(),
@@ -350,22 +363,22 @@
       // renders an embedded quote card instead of a bare link. Omitted when the
       // note has no quote or the quoted post could not be resolved.
-      'shaer:quote': AP.timelineQuote(t.quote_json),
+      'shaer:quote': quotesAllowed ? AP.timelineQuote(t.quote_json) : undefined,
       // The post author's display info (name / @handle / avatar), so every card
       // gets a byline header like the quote card. attributedTo stays the bare
       // actor URI; this is the resolved presentation Klonkt already stored.
-      'shaer:author': (t.author_name || t.author_handle || t.author_icon) ? {
+      'shaer:author': gateAuthor((t.author_name || t.author_handle || t.author_icon) ? {
         name: t.author_name || undefined, handle: t.author_handle || undefined,
         icon: t.author_icon || undefined, url: t.author_url || undefined,
         // FEP-9098: emojis in the display name (":shortcode:"), if any.
         emojis: (() => { try { return t.author_emoji_json ? JSON.parse(t.author_emoji_json) : undefined; } catch { return undefined; } })(),
-      } : undefined,
+      } : undefined),
       // When a followed account boosted this, who did ("X boosted"). Omitted for
       // ordinary posts.
-      'shaer:booster': (t.reblog_name || t.reblog_handle || t.reblog_icon) ? {
+      'shaer:booster': gateAuthor((t.reblog_name || t.reblog_handle || t.reblog_icon) ? {
         name: t.reblog_name || undefined, handle: t.reblog_handle || undefined,
         icon: t.reblog_icon || undefined,
         // FEP-9098: emojis in the booster's display name (":shortcode:"), if any.
         emojis: (() => { try { return t.reblog_emoji_json ? JSON.parse(t.reblog_emoji_json) : undefined; } catch { return undefined; } })(),
-      } : undefined,
+      } : undefined),
       // Whether THIS account already liked/boosted the note, so the app's
       // detail-view buttons show the current state (and can toggle/undo).
@@ -384,5 +397,12 @@
   const me = AP.actorId(base, auth.site.slug);
   const myHandle = (() => { try { return `@${auth.site.slug}@${new URL(base).host}`; } catch { return `@${auth.site.slug}`; } })();
-  const messages = AP.getDirectMessages(auth.site.slug, 60).map((m) => ({
+  // Messages dicht (shaer-3ow) sluit vreemden en vrienden, maar NOOIT het
+  // guardian-kanaal: de zwaai en het gesprek na een hulpvraag zijn precies
+  // het kanaal dat het kind veilig houdt, en een poort die dat afsnijdt
+  // beschermt niemand. De hulpvraag zelf gaat aan de innamekant al altijd voor.
+  const guardianUris = (() => { try { return new Set(Guardianship.listGuardians(auth.site.slug).map((g) => g.other_uri)); } catch { return new Set(); } })();
+  const messages = AP.getDirectMessages(auth.site.slug, 60)
+    .filter((m) => messagesAllowed || m.help_request || guardianUris.has(m.actor_uri))
+    .map((m) => ({
     id: `${m.object_uri}#create`,
     type: 'Create',
@@ -402,16 +422,16 @@
       // groups the note into a conversation. No FEP-e232 link tags here: a
       // mention row keeps the resolved quote, not the raw tags.
-      tag: [{ type: 'Mention', href: me, name: myHandle }, ...(AP.timelineEmojis(m.emoji_json) || [])],
-      attachment: AP.timelineAttachments(m.media_json),
+      tag: [{ type: 'Mention', href: me, name: myHandle }, ...(emojiAllowed ? (AP.timelineEmojis(m.emoji_json) || []) : [])],
+      attachment: AP.gateAttachments(AP.timelineAttachments(m.media_json), { images: imagesAllowed, audio: musicAllowed }),
       // FEP-633c: what kind of message this is. The wave is a gentle nudge from
       // a guardian; the help request is the buoy. Both render differently.
       'shaer:wave': m.wave ? true : undefined,
       'shaer:helpRequest': m.help_request ? true : undefined,
-      'shaer:quote': AP.timelineQuote(m.quote_json),
-      'shaer:author': (m.actor_name || m.actor_handle || m.actor_icon) ? {
+      'shaer:quote': quotesAllowed ? AP.timelineQuote(m.quote_json) : undefined,
+      'shaer:author': gateAuthor((m.actor_name || m.actor_handle || m.actor_icon) ? {
         name: m.actor_name || undefined, handle: m.actor_handle || undefined,
         icon: m.actor_icon || undefined, url: m.actor_url || undefined,
         emojis: (() => { try { return m.actor_emoji_json ? JSON.parse(m.actor_emoji_json) : undefined; } catch { return undefined; } })(),
-      } : undefined,
+      } : undefined),
       'shaer:embed': embedsAllowed ? AP.timelineEmbed(m.embed_json, { playback: playbackAllowed }) : undefined,
     },
@@ -475,4 +495,15 @@
       // and not just the picture over it.
       'shaer:externalLinks': playbackAllowed,
+      // De rest van de familie (8-8): de app hoort VOORAF te weten wat hij mag
+      // aanbieden in plaats van het bij de eerste weigering te ontdekken. De
+      // (+) kaart leest shaer:compose al (Barts gate); de rest is er voor de
+      // schermen die nog komen. Serveren wat waar is kost hier niets.
+      'shaer:compose': composeAllowed,
+      'shaer:messages': messagesAllowed,
+      'shaer:images': imagesAllowed,
+      'shaer:music': musicAllowed,
+      'shaer:quoteCards': quotesAllowed,
+      'shaer:customEmoji': emojiAllowed,
+      'shaer:externalThreads': threadsAllowed,
     },
     // Het merk van wat hierin zit. Geef hem terug als `since` om op het
@@ -721,6 +752,22 @@
   if (!/^https:\/\//i.test(objectUri)) return res.status(400).json({ error: 'object must be an https URI' });
   const isWard = (() => { try { return Guardianship.listGuardians(auth.site.slug).length > 0; } catch { return false; } })();
-  const uit = await AP.getThread(auth.site.slug, objectUri, { isWard });
+  const uit = await AP.getThread(auth.site.slug, objectUri);
   if (!uit.found) return res.status(404).json({ error: 'note not reachable' });
+  // De poortstand komt uit de kolom (shaer-9y2): expliciete 0/1 van de
+  // guardians wint, de automatiek is dicht-voor-een-ward. Dicht is de KRING,
+  // niet niets: antwoorden van al goedgekeurd volk blijven staan, en wat er
+  // buiten valt wordt geteld. Beeld, muziek en emoji gaan door dezelfde
+  // poorten als de tijdlijn -- per verzoek, buiten de threadcache om.
+  const threadsOpen = Guardianship.wardGateAllowed(auth.site.external_threads, isWard);
+  const gate2 = (col) => Guardianship.wardGateAllowed(auth.site[col], isWard);
+  const kring = threadsOpen ? { notes: uit.notes, hidden: 0 } : AP.filterThreadToCircle(auth.site.slug, uit.notes);
+  const imagesOk = gate2('gate_images'), musicOk = gate2('gate_music'), emojiOk = gate2('gate_custom_emoji');
+  uit.notes = kring.notes.map((n) => ({
+    ...n,
+    attachment: AP.gateAttachments(n.attachment, { images: imagesOk, audio: musicOk }),
+    tag: emojiOk ? n.tag : AP.stripEmojiTags(n.tag),
+    'shaer:author': (n['shaer:author'] && !emojiOk) ? { ...n['shaer:author'], emojis: undefined } : n['shaer:author'],
+  }));
+  uit.hidden = kring.hidden;
   // Liked/boosted per antwoord, BUITEN de cache om: de genormaliseerde notes
   // mogen twee minuten oud zijn, maar of JIJ iets geliked hebt hoort van nu te
Index: src/routes/guardian.js
===================================================================
--- src/routes/guardian.js	(revision 50e80acd22affc07719af0f0ac1a35bbb6b23819)
+++ src/routes/guardian.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
@@ -60,5 +60,5 @@
     // Het gate-paneel per ward (shaer-ahy.1): een rij per gate, met het soort en
     // de drempel erbij. De namen volgen de catalogus in gated.js.
-    'gate_externalEmbeds', 'gate_externalPlayback', 'gate_follows',
+    'gate_externalEmbeds', 'gate_externalPlayback', 'gate_externalThreads', 'gate_follows',
     'gate_kind_setting', 'gate_kind_perRequest', 'gate_kind_handover',
     'gate_unknown', 'gate_threshold', 'gate_threshold_unknown',
@@ -630,8 +630,7 @@
     // stond er in het paneel overal "onbekend". Wat een guardian wel heeft is de
     // uitslag van wat hij voorstelde.
-    settings: {
-      'shaer:externalEmbeds': Guardianship.gated.knownSetting(mySlug, wardUri, 'shaer:externalEmbeds'),
-      'shaer:externalPlayback': Guardianship.gated.knownSetting(mySlug, wardUri, 'shaer:externalPlayback'),
-    },
+    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) => ({
@@ -656,5 +655,12 @@
 // can move, and only a committed guardian of THAT ward may move it.
 router.post('/wards/embeds', requireAuth, express.json({ limit: '4kb' }), (req, res) => {
-  req.body = { ...req.body, feature: req.body?.feature === 'shaer:externalPlayback' ? 'shaer:externalPlayback' : 'shaer:externalEmbeds' };
+  // Niet meer alleen embeds/playback: elke gate uit de catalogus met een kolom
+  // is voorstelbaar (8-8, "maak ze allemaal functioneel"). De oude regel
+  // HERSCHREEF een onbekende feature stilletjes naar externalEmbeds -- een
+  // voorstel voor de ene poort dat op de andere landt is precies het soort
+  // fout dat een guardian nooit mag overkomen. Onbekend wordt nu geweigerd.
+  const feature = String(req.body?.feature || 'shaer:externalEmbeds');
+  if (!Guardianship.gated.featureColumn(feature)) return res.status(400).json({ error: 'unknown_feature' });
+  req.body = { ...req.body, feature };
   return proposeGated(req, res);
 });
Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 50e80acd22affc07719af0f0ac1a35bbb6b23819)
+++ src/services/ActivityPubService.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
@@ -2919,4 +2919,23 @@
       case 'Create': {
         if (!object || typeof object !== 'object') return { status: 400, error: 'missing_object' };
+        // Innamepoorten (shaer-ahy.1, 8-8): wat de ward niet mag versturen
+        // wordt HIER geweigerd, niet in de app verstopt -- een knop die de
+        // client alleen verbergt is geen poort. De reddingsboei gaat ALTIJD
+        // voor: een hulpvraag aan de guardians mag door elke dichte deur heen,
+        // anders sluit een messages-poort precies het kanaal af dat het kind
+        // veilig houdt.
+        {
+          const isWard = (() => { try { return Guardianship.listGuardians(site.slug).length > 0; } catch { return false; } })();
+          const isHelp = object['shaer:helpRequest'] === true || object.helpRequest === true;
+          const direct = c2sVisibility(object) === 'direct';
+          if (!isHelp) {
+            if (direct && !Guardianship.wardGateAllowed(site.gate_messages, isWard)) {
+              return { status: 403, error: 'gated_messages' };
+            }
+            if (!direct && !object.inReplyTo && !Guardianship.wardGateAllowed(site.gate_compose, isWard)) {
+              return { status: 403, error: 'gated_compose' };
+            }
+          }
+        }
         // Client sends `source` (plain/markdown) + `content` (HTML). deliverReply
         // re-escapes, so it needs plain text; a top-level post keeps sanitized HTML.
@@ -3385,13 +3404,13 @@
  * De directe antwoorden op één note, genormaliseerd voor de C2S-lezer.
  *
- * `circle` is de wachtwoord-vraag van shaer-vw4 in zijn veiligste stand: is de
- * lezer een ward, dan komen alleen antwoorden door van accounts die de
- * guardians al kennen (gevolgd of volgend). Wat er buiten valt wordt GETELD en
- * als aantal teruggegeven, nooit stil weggelaten -- maar het besluit of dat
- * aantal getoond wordt, en of dit de blijvende regel is, ligt bij Bart en
- * Robin (shaer-vw4). Geblokkeerde actors zijn een andere categorie: die
- * verdwijnen zonder telling, een blokkade is onzichtbaar.
+ * ALLEEN ophalen en normaliseren; de poorten zitten in de route. De
+ * kringfilter (de dichte stand van shaer:externalThreads) woont in
+ * filterThreadToCircle en de beeld/muziek/emoji-poorten in
+ * gateAttachments/stripEmojiTags -- per verzoek, buiten deze cache om, want de
+ * stand van een poort mag hier niet twee minuten bevriezen. Geblokkeerde
+ * actors zijn een andere categorie en verdwijnen WEL hier, zonder telling:
+ * een blokkade is onzichtbaar, ook als getal.
  */
-export async function getThread(slug, objectUri, { isWard = false } = {}) {
+export async function getThread(slug, objectUri) {
   const key = `${slug}|${objectUri}`;
   const hit = threadViewCache.get(key);
@@ -3434,12 +3453,4 @@
   }));
 
-  const circle = isWard ? (() => {
-    const s = new Set();
-    try { for (const r of db.prepare("SELECT actor_uri FROM ap_following WHERE slug = ? AND status = 'accepted'").all(slug)) s.add(r.actor_uri); } catch { /* geen tabel */ }
-    try { for (const r of db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ?').all(slug)) s.add(r.actor_uri); } catch { /* geen tabel */ }
-    return s;
-  })() : null;
-
-  let hidden = 0;
   const kept = [];
   for (const o of objs) {
@@ -3447,5 +3458,4 @@
     const actorUri = actorUriOf(o.attributedTo);
     if (!actorUri || isBlockedAny(actorUri)) continue;   // een blokkade telt niet mee
-    if (circle && !circle.has(actorUri)) { hidden += 1; continue; }
     kept.push({ o, actorUri });
   }
@@ -3489,5 +3499,5 @@
   })).sort((a, b) => String(a.published || '').localeCompare(String(b.published || '')));
 
-  const out = { notes, hidden, found: !!note };
+  const out = { notes, found: !!note };
   threadViewCache.set(key, { at: Date.now(), out });
   if (threadViewCache.size > THREAD_VIEW_CACHE_MAX) {
@@ -3495,4 +3505,24 @@
     if (oldest) threadViewCache.delete(oldest[0]);
   }
+  return out;
+}
+
+/**
+ * De thread gefilterd op de kring die de guardians al kennen (gevolgd of
+ * volgend) -- de dichte stand van shaer:externalThreads. PER VERZOEK, buiten de
+ * threadcache om: een poort die de guardians net dichtzetten mag niet nog twee
+ * minuten open nawerken uit een cache. Wat er buiten valt wordt GETELD, nooit
+ * stil weggelaten.
+ */
+export function filterThreadToCircle(slug, notes) {
+  const circle = new Set();
+  try { for (const r of db.prepare("SELECT actor_uri FROM ap_following WHERE slug = ? AND status = 'accepted'").all(slug)) circle.add(r.actor_uri); } catch { /* geen tabel */ }
+  try { for (const r of db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ?').all(slug)) circle.add(r.actor_uri); } catch { /* geen tabel */ }
+  const kept = [], out = { hidden: 0 };
+  for (const n of notes) {
+    if (circle.has(n.attributedTo)) kept.push(n);
+    else out.hidden += 1;
+  }
+  out.notes = kept;
   return out;
 }
@@ -3924,4 +3954,33 @@
   return emojis.length ? JSON.stringify(emojis) : null;
 }
+// ── Gate-filters voor de C2S-serialisatie (shaer-ahy.1, 8-8) ──────
+//
+// Dezelfde regel als bij de embeds: de poort zit bij de AFLEVERING. Een
+// bijlage die de client alleen verbergt is wel degelijk geleverd, dus wat
+// dicht is wordt hier nooit geserialiseerd. Puur, zodat de regels los van de
+// routes te toetsen zijn.
+
+/** Bijlagen door de beeld- en muziekpoort. Leeg wordt undefined, zoals de
+ *  serialisatie dat overal doet. */
+export function gateAttachments(atts, { images = true, audio = true } = {}) {
+  if (!Array.isArray(atts)) return atts;
+  const out = atts.filter((a) => {
+    const mt = String((a && a.mediaType) || '');
+    if (!images && mt.startsWith('image/')) return false;
+    if (!audio && (mt.startsWith('audio/') || (a && a.type === 'Audio'))) return false;
+    return true;
+  });
+  return out.length ? out : undefined;
+}
+
+/** Tag-array zonder de FEP-9098 Emoji-tags, voor een dichte emoji-poort. De
+ *  :shortcode: blijft als tekst staan -- dat is eerlijk: er STAAT iets, het
+ *  wordt alleen niet als plaatje van een vreemde server gerenderd. */
+export function stripEmojiTags(tags) {
+  if (!Array.isArray(tags)) return tags;
+  const out = tags.filter((t) => (Array.isArray(t && t.type) ? t.type[0] : (t && t.type)) !== 'Emoji');
+  return out.length ? out : undefined;
+}
+
 export function timelineEmojis(emojiJson) {
   try { const arr = emojiJson ? JSON.parse(emojiJson) : null; return (Array.isArray(arr) && arr.length) ? arr : undefined; }
@@ -4976,7 +5035,12 @@
   if (!base || !site || !site.slug) return { error: 'config' };
   try {
-    const guardians = Guardianship.listGuardians(site.slug);
-    if (guardians.length) {
-      console.warn('[AP] move refused: guarded account (shaer-tge):', site.slug, '→', String(targetRaw || ''));
+    // Was een harde weigering voor elk bewaakt account (shaer-tge); sinds 8-8
+    // een GATE met dezelfde standaard: de automatiek weigert voor een ward,
+    // maar de guardians kunnen shaer:accountMove expliciet openzetten -- en
+    // expliciet dichtzetten geldt dan ook voor een account dat net geen ward
+    // meer is, net als bij de embeds.
+    const isWard = Guardianship.listGuardians(site.slug).length > 0;
+    if (!Guardianship.wardGateAllowed(site.gate_account_move, isWard)) {
+      console.warn('[AP] move refused: gated (shaer-tge):', site.slug, '→', String(targetRaw || ''));
       return { error: 'guarded_account' };
     }
@@ -5700,5 +5764,5 @@
   getNotifications, listBlocks, isBlockedAny, blockTarget, unblock,
   deliverWithRetry, enqueueDelivery, processDeliveryQueue, startDeliveryWorker,
-  getReplyUris, getThread, markNotificationsSeen, countUnseenNotifications, hasPlayableAudio,
+  getReplyUris, getThread, filterThreadToCircle, gateAttachments, stripEmojiTags, markNotificationsSeen, countUnseenNotifications, hasPlayableAudio,
   linkifyBody, bakePostContent, bakePostContentWithMentions, listFollowers, removeFollower, listConnections,
   noteVisibility, belongsInTimeline, playerUrlFor, isRejectedObject, rejectInteraction, interactionReportTarget,
Index: src/services/guardianship/gated.js
===================================================================
--- src/services/guardianship/gated.js	(revision 50e80acd22affc07719af0f0ac1a35bbb6b23819)
+++ src/services/guardianship/gated.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
@@ -59,4 +59,12 @@
   'shaer:externalEmbeds': 'external_embeds',
   'shaer:externalPlayback': 'external_playback',
+  'shaer:externalThreads': 'external_threads',
+  'shaer:images': 'gate_images',
+  'shaer:messages': 'gate_messages',
+  'shaer:compose': 'gate_compose',
+  'shaer:music': 'gate_music',
+  'shaer:quoteCards': 'gate_quote_cards',
+  'shaer:customEmoji': 'gate_custom_emoji',
+  'shaer:accountMove': 'gate_account_move',
 };
 /**
@@ -80,34 +88,39 @@
 export const GATE_CATALOGUE = [
   // Werkend: er is een kolom, de tally kan erover beslissen en de server dwingt
-  // hem af bij het serveren.
+  // hem af bij het serveren (of, voor compose/messages/move, bij het INNEMEN:
+  // wat de ward niet mag versturen wordt aan de outbox geweigerd).
   { feature: 'shaer:externalEmbeds', kind: 'setting', reversible: true },
   { feature: 'shaer:externalPlayback', kind: 'setting', reversible: true, needs: 'shaer:externalEmbeds' },
+  // Sinds 8-8 ("maak ze allemaal functioneel", Bart): de hele setting-familie
+  // schakelt echt. De bead-nummers blijven staan, want elk van deze heeft nog
+  // een app-kant (wat de UI toont als de poort dicht is) en die woont daar.
+  { feature: 'shaer:externalThreads', kind: 'setting', reversible: true, bead: 'shaer-9y2' },
+  { feature: 'shaer:images', kind: 'setting', reversible: true, bead: 'shaer-6p5' },
+  { feature: 'shaer:messages', kind: 'setting', reversible: true, bead: 'shaer-3ow' },
+  { feature: 'shaer:compose', kind: 'setting', reversible: true, bead: 'shaer-qgev' },
+  { feature: 'shaer:music', kind: 'setting', reversible: true, bead: 'shaer-rmz' },
+  { feature: 'shaer:quoteCards', kind: 'setting', reversible: true, bead: 'shaer-mls' },
+  { feature: 'shaer:customEmoji', kind: 'setting', reversible: true, bead: 'shaer-ytw' },
+  { feature: 'shaer:accountMove', kind: 'setting', reversible: true, bead: 'shaer-tge' },
   // Altijd aan voor een ward (5.3): niet te verzetten, wel te tonen. Een paneel
   // dat alleen verstelbare dingen laat zien verzwijgt de helft van wat er geldt.
   { feature: 'shaer:follows', kind: 'perRequest', reversible: true, fixed: true },
 
-  // GEPLAND, nog niet afgedwongen. Deze staan in het paneel omdat een guardian
-  // hoort te zien wat er straks te beslissen valt -- en omdat de SOM van de
-  // gates iets anders is dan elke gate apart: elf poorten die elk dicht falen
-  // leveren samen een kind op dat vrijwel niets kan.
+  // GEPLAND, en dat is bij deze twee geen achterstand maar een besluit.
   //
-  // available: false is geen detail. featureColumn() kent deze namen niet, dus
-  // een voorstel zou stranden op unknown_feature. En ze als "uit" tonen zou
-  // ronduit onwaar zijn: plaatjes werken vandaag gewoon. Ze horen te lezen als
-  // "hier is nog niets van", niet als een gesloten poort.
+  // publicProfile is niet een veld dat je wegfiltert: het is het hele publieke
+  // web-oppervlak van een site (de Krant, de AP-objecten, de scrape-vraag van
+  // shaer-hj0). Dat dichtzetten zonder dat ontwerp is een half slot, en een
+  // half slot leest als een heel slot -- gevaarlijker dan geen.
   //
-  // `kind` is hier voorlopig. Of accountmigratie een stand is of een besluit per
-  // keer hoort bij het bouwen van shaer-tge beslist te worden, niet hier.
-  { feature: 'shaer:images', kind: 'setting', reversible: true, available: false, bead: 'shaer-6p5' },
-  { feature: 'shaer:messages', kind: 'setting', reversible: true, available: false, bead: 'shaer-3ow' },
-  { feature: 'shaer:compose', kind: 'setting', reversible: true, available: false, bead: 'shaer-qgev' },
-  { feature: 'shaer:music', kind: 'setting', reversible: true, available: false, bead: 'shaer-rmz' },
-  { feature: 'shaer:quoteCards', kind: 'setting', reversible: true, available: false, bead: 'shaer-mls' },
-  { feature: 'shaer:customEmoji', kind: 'setting', reversible: true, available: false, bead: 'shaer-ytw' },
+  // available: false is geen detail. featureColumn() kent deze naam niet, dus
+  // een voorstel strandt op unknown_feature, en de rij leest als "hier is nog
+  // niets van", niet als een gesloten poort.
   { feature: 'shaer:publicProfile', kind: 'setting', reversible: true, available: false, bead: 'shaer-hj0' },
-  { feature: 'shaer:accountMove', kind: 'setting', reversible: true, available: false, bead: 'shaer-tge' },
   // De enige die gezag OVERDRAAGT, en daarmee de enige die niet terug te draaien
   // is zodra het kind hem gebruikt (shaer-90v). Telt met de lapse-vorm: volle
-  // set, volle venster.
+  // set, volle venster. Die vorm hoort daar beslist te worden, niet hier
+  // geimproviseerd: een verkeerd gemaakte onafhankelijkheid is een kind zonder
+  // vangnet.
   { feature: 'shaer:independence', kind: 'handover', reversible: false, available: false, bead: 'shaer-90v' },
 ];
Index: src/services/guardianship/index.js
===================================================================
--- src/services/guardianship/index.js	(revision 50e80acd22affc07719af0f0ac1a35bbb6b23819)
+++ src/services/guardianship/index.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
@@ -16,5 +16,5 @@
  */
 export { SHAER_CONTEXT, GUARDIAN_RELATIONSHIP, GUARDIAN_RELATIONSHIP_COMPACT, isGuardianRelationship } from './context.js';
-export { helpRequestProps, isHelpRequest, waveProps, isWave, awayProps, hasGuardiansProps, objectHasGuardians, externalEmbedsAllowed, externalPlaybackAllowed } from './notes.js';
+export { helpRequestProps, isHelpRequest, waveProps, isWave, awayProps, hasGuardiansProps, objectHasGuardians, externalEmbedsAllowed, externalPlaybackAllowed, wardGateAllowed } from './notes.js';
 export { wireDelivery, c2sVisibility, deliverDirectNote } from './delivery.js';
 export { wireHandshake, handleOutbox as handleGuardianshipOutbox, handleInbox as handleGuardianshipInbox, parseRelationship, parseUndoRelationship, endGuardianship } from './handshake.js';
Index: src/services/guardianship/notes.js
===================================================================
--- src/services/guardianship/notes.js	(revision 50e80acd22affc07719af0f0ac1a35bbb6b23819)
+++ src/services/guardianship/notes.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
@@ -47,4 +47,17 @@
 }
 
+/**
+ * Dezelfde regel voor de hele gate-familie (8-8, "maak ze allemaal
+ * functioneel"): een expliciete 0/1 van de guardians wint, anders de
+ * automatiek -- dicht voor een ward, open voor de rest. EEN implementatie,
+ * zodat er geen tweede plek is die er anders over kan gaan denken; de twee
+ * benoemde varianten hierboven blijven bestaan omdat er tests en aanroepen
+ * aan hangen, en doen exact hetzelfde.
+ */
+export function wardGateAllowed(setting, isWard) {
+  if (setting === 0 || setting === 1) return setting === 1;
+  return !isWard;
+}
+
 /** True when an incoming object carries the ward hint (§2.2). Register-only for
  *  now; acted on later at reddings-boei / escalation routing. */
Index: src/services/i18n.js
===================================================================
--- src/services/i18n.js	(revision 50e80acd22affc07719af0f0ac1a35bbb6b23819)
+++ src/services/i18n.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
@@ -67,5 +67,5 @@
     'admin.b_paid': 'Betaalde posts', 'admin.b_push': 'Notificaties', 'admin.back': 'Terug naar Beheer',
     'push.t': 'Notificaties', 'push.intro': 'Krijg een melding op dit apparaat bij nieuwe volgers, reacties en berichten, ook als de site niet open staat. Versleuteld tot in je browser; wij sturen zo min mogelijk inhoud mee.', 'push.unavailable': 'Push is op deze server niet beschikbaar (sleutel kon niet worden aangemaakt of de dependency ontbreekt).', 'push.unsupported': 'Deze browser ondersteunt geen push-notificaties.', 'push.ios_hint': 'Op iPhone/iPad werkt dit alleen als de site op je beginscherm staat: deel-knop, dan "Zet op beginscherm", en open de site daarna vanaf daar.', 'push.this_device': 'Dit apparaat:', 'push.checking': 'controleren…', 'push.state_on': 'meldingen staan aan', 'push.state_off': 'meldingen staan uit', 'push.state_denied': 'geblokkeerd in de browserinstellingen', 'push.state_unknown': 'status onbekend', 'push.state_unsupported': 'niet ondersteund', 'push.enable': 'Zet aan op dit apparaat', 'push.disable': 'Zet uit', 'push.test': 'Stuur testmelding', 'push.what': 'Waarvoor wil je een melding?', 'push.a_follow': 'Nieuwe volger', 'push.a_reply': 'Reactie of vermelding', 'push.a_like': 'Waardering (ster)', 'push.a_boost': 'Boost', 'push.a_dm': 'Privébericht', 'push.saved': 'Opgeslagen.', 'push.devices': 'Gekoppelde apparaten', 'push.device': 'Apparaat', 'push.since': 'sinds', 'push.remove': 'Verwijder', 'push.enable_failed': 'aanzetten mislukt', 'push.on_short': 'Word supporter',
-    'push.n_follow_t': 'Nieuwe volger', 'push.n_follow_b': '{who} volgt je nu', 'push.n_reply_t': 'Reactie op "{title}"', 'push.n_mention_t': 'Vermelding', 'push.n_dm_t': 'Privébericht', 'push.n_dm_b': 'Nieuw bericht van {who}', 'push.n_like_t': 'Nieuwe waardering', 'push.n_like_b': '{who} waardeerde "{title}"', 'push.n_boost_t': 'Geboost', 'push.n_boost_b': '{who} boostte "{title}"', 'msg.guard_offer': 'wil je guardian worden. Bespreek dit met je ouders of verzorgers voordat je beslist.', 'msg.guard_accept': 'Accepteer', 'msg.guard_reject': 'Weiger', 'msg.guard_accepted': 'Guardian geaccepteerd. Jullie zijn nu verbonden.', 'msg.guard_rejected': 'Aanvraag geweigerd.', 'msg.guard_failed': 'Dat lukte niet; probeer het opnieuw.', 'msg.guardians_label': 'Jouw guardians', 'msg.waved_at_you': 'zwaaide naar je', 'msg.help_request': 'vroeg om hulp', 'msg.g_available': 'beschikbaar', 'msg.g_away': 'afwezig tot {date}', 'msg.g_offline': 'offline', 'msg.wave_r1': 'Wat leuk!', 'msg.wave_r2': 'Bel me even', 'msg.wave_back': '👋 Terug', 'msg.wave_sent': 'Zwaai verstuurd.', 'msg.reply_sent': 'Antwoord verstuurd.', 'msg.reply_failed': 'Het antwoord kon niet verstuurd worden.', 'msg.reply_empty': 'Een leeg antwoord versturen kan niet.', 'guardian.feed_title': 'Van je wards', 'guardian.feed_sub': 'Meelezen met wat je wards plaatsen. Alleen kijken.', 'guardian.follow_title': 'Volgverzoeken', 'guardian.follow_sub': 'Iemand wil een van je wards volgen. Jij beslist.', 'guardian.wave': '👋 Zwaai', 'guardian.waved': '👋 verstuurd', 'guardian.app_name': 'Klonkt Guardian', 'guardian.tagline': 'Wards beheren en hulpverzoeken opvangen.', 'guardian.acting_as': 'Je handelt als', 'guardian.help_title': 'Hulpverzoeken', 'guardian.help_sub': 'Als een ward de reddingsboei gebruikt, verschijnt het hier.', 'guardian.help_empty': 'Geen hulpverzoeken. Mooi zo.', 'guardian.adopt_title': 'Ward adopteren', 'guardian.adopt_sub': 'Vul de handle van het kind in (@kind@server.eu). Ze krijgen een aanvraag in hun Klonkt die ze accepteren.', 'guardian.adopt_label': 'Handle van de ward', 'guardian.adopt_btn': 'Verstuur aanvraag', 'guardian.pending_title': 'Verzonden aanvragen', 'guardian.pending_sub': 'Wacht tot de ward accepteert.', 'guardian.wards_title': 'Mijn wards', 'guardian.play_propose': 'Afspelen voorstellen', 'guardian.play_on': 'Afspelen: aan', 'guardian.play_off': 'Afspelen: uit', 'guardian.gated_title': 'Instelling voorgesteld', 'guardian.gated_line_on': '{who} wil linkvoorbeelden AANzetten voor {ward}.', 'guardian.gated_line_off': '{who} wil linkvoorbeelden UITzetten voor {ward}.', 'guardian.gated_agree': 'Eens', 'guardian.gated_disagree': 'Oneens', 'guardian.avail_available': 'Beschikbaar', 'guardian.avail_away': 'Afwezig tot {date}', 'guardian.avail_dormant': 'Offline', 'guardian.panel_guards': 'Guardians van dit kind', 'guardian.panel_guards_remote': 'Dit kind woont op een andere server; de beschikbaarheid wordt daar bijgehouden.', 'guardian.lapse_propose': 'Voorstel: loslaten bij afwezigheid', 'guardian.lapse_line': '{who} antwoordt niet meer als guardian van {ward}.', 'guardian.lapse_tally': '{n} van {need} akkoord; sluit {date}; het venster loopt altijd vol.', 'guardian.lapse_note': 'Elk teken van leven van hen annuleert dit meteen. Niets hier is straf.', 'guardian.lapse_agree': 'Eens', 'guardian.lapse_disagree': 'Oneens', 'guardian.voted': 'Je hebt gestemd', 'guardian.away_title': 'Even afwezig', 'guardian.away_sub': 'Meld je wards dat je er even niet bent. Besluiten wachten niet op je, en een enkel antwoord brengt je meteen terug.', 'guardian.away_week': 'Een week', 'guardian.away_month': 'Een maand', 'guardian.away_done': 'Je wards weten dat je afwezig bent tot {date}.', 'guardian.away_msg': 'Ik ben afwezig als je guardian tot {date}. Je andere guardians zijn er voor je.', 'guardian.release_title': '{who} loslaten?', 'guardian.release_effect': 'Je stopt als guardian. Je ziet hun berichten niet meer, je krijgt geen hulpvragen meer van ze, en je beoordeelt geen volgverzoeken meer voor ze. Terugkomen kan alleen met een nieuwe aanvraag die zij accepteren.', 'guardian.release_local': 'Hun server en de andere guardians krijgen dit door, dus daarna sta jij ook bij hen niet meer als guardian.', 'guardian.release_step_down': 'Zij houden hun andere guardians, dus zij blijven een ward.', 'guardian.release_last': 'Je bent hun laatste guardian. Dat is emancipatie, en volgens FEP-633c 3.4 is dat niet aan een guardian alleen: daar horen drie instemmende volwassenen bij, of een meerderheid met twee getuigen. Deze knop kan dat dus niet: je blijft hun guardian tot dat geregeld is.', 'guardian.release_unknown': 'We konden hun server niet bereiken, dus we weten niet of jij hun laatste guardian bent.', 'guardian.release_yes': 'Ja, loslaten', 'guardian.release_no': 'Nee, toch niet', 'guardian.settings_title': 'Instellingen', 'guardian.panel_open': 'Bekijken', 'guardian.panel_close': 'Sluiten', 'guardian.panel_help': 'Hulpvragen van dit kind', 'guardian.panel_help_empty': 'Nog geen hulpvragen.', 'guardian.panel_follow': 'Volgverzoeken', 'guardian.panel_follow_empty': 'Geen openstaande volgverzoeken.', 'guardian.panel_posts': 'Recente berichten', 'guardian.panel_posts_empty': 'Nog niets te zien.', 'guardian.panel_actions': 'Acties', 'guardian.badge_help': 'hulpvragen', 'guardian.badge_follow': 'volgverzoeken', 'guardian.badge_follow_one': 'volgverzoek', 'guardian.wards_empty': 'Nog geen wards. Adopteer er hierboven een.', 'guardian.push_title': 'Meldingen', 'guardian.push_sub': 'Ontvang een melding bij een hulpverzoek of voogdij-antwoord, ook als de app dicht is.', 'guardian.push_on': 'Zet meldingen aan', 'guardian.push_off': 'Meldingen staan aan; tik om uit te zetten', 'guardian.sent': 'Aanvraag verstuurd. Zie hieronder bij Verzonden aanvragen.', 'guardian.sent_retry': 'Aanvraag opgeslagen; we blijven proberen te bezorgen.', 'guardian.sending': 'Versturen…', 'guardian.not_found': 'Die handle konden we niet vinden.', 'guardian.failed': 'Mislukt', 'guardian.network': 'Netwerkfout.', 'guardian.pending': 'wacht op antwoord', 'guardian.active': 'actief', 'guardian.retract': 'Intrekken', 'guardian.release': 'Loslaten', 'guardian.embeds_on': 'Linkvoorbeelden: aan', 'guardian.embeds_off': 'Linkvoorbeelden: uit', 'guardian.embeds_propose': 'Linkvoorbeelden voorstellen', 'guardian.embeds_waiting': 'wacht op de andere guardians', 'guardian.prop_line': 'Voorstel {what} {value}: {status}', 'guardian.prop_embeds': 'linkvoorbeelden', 'guardian.prop_play': 'afspelen', 'guardian.prop_on': 'aan', 'guardian.prop_off': 'uit', 'guardian.prop_st_open': 'wacht op de andere guardians', 'guardian.prop_st_accepted': 'aangenomen', 'guardian.prop_st_rejected': 'afgewezen', 'guardian.prop_st_expired': 'verlopen zonder genoeg stemmen', 'guardian.panel_guards_far': 'Beschikbaarheid wordt op hun server bijgehouden.', 'guardian.release_confirm': '{who} loslaten?\n\nJe stopt dan als guardian. Je ziet hun berichten niet meer, je krijgt geen hulpverzoeken meer van ze, en je kunt volgverzoeken niet meer voor ze beoordelen.\n\nTerugkomen kan alleen met een nieuwe aanvraag die zij accepteren.', 'guardian.open': 'open', 'guardian.accept': 'Accepteer', 'guardian.reject': 'Weiger', 'guardian.complete': 'Voltooien', 'guardian.awaiting_others': 'wacht op de andere partijen', 'guardian.coguard': 'mede-voogdij-aanvraag', 'guardian.push_unavailable': 'Push niet beschikbaar', 'push.n_help_t': 'Hulpvraag', 'push.n_help_b': '{who} vraagt om je hulp', 'push.n_guard_offer_t': 'Voogdij-aanvraag', 'push.n_guard_offer_b': '{who} wil je guardian worden', 'push.n_guard_ward_t': 'Ward geaccepteerd', 'push.n_guard_left_t': 'Een guardian is gestopt', 'push.n_guard_left_b': '{who} is niet langer je guardian', 'push.n_guard_cogleft_t': 'Mede-guardian gestopt', 'push.n_guard_cogleft_b': '{who} heeft de guardianship beeindigd', 'push.n_guard_ward_b': '{who} accepteerde je als guardian', 'push.n_guard_cog_t': 'Mede-voogdij gevraagd', 'push.n_guard_cog_b': 'Er is een guardian-aanvraag voor {who}', 'guardian.panel_history': 'Geschiedenis ({n})', 'guardian.help_archive': '{n} afgehandeld', 'guardian.help_archive_hide': 'verbergen', 'guardian.help_former_ward': 'Niet meer jouw ward. Hun andere guardians zijn er nog voor ze.', 'guardian.warn_reversible': 'Wat hier doorheen komt, komt niet meer terug. Je kunt deze instelling later weer dichtzetten — wat je kind gezien heeft niet.', 'guardian.warn_irreversible': 'Dit is niet terug te draaien. Hierna beslist zij het zelf, en jullie kunnen dat niet meer terugnemen.', 'guardian.warn_unknown': 'Wij kennen deze instelling niet, dus we weten niet wat er doorheen komt of hoe ver het reikt. Vraag het degene die het voorstelde voordat je ja zegt.', 'guardian.warn_tally_elsewhere': 'Hoeveel guardians al geantwoord hebben zien wij niet — dat telt de server van het kind. Jouw ja kan de doorslag geven.', 'guardian.warn_go': 'Ja, stel dit voor', 'guardian.warn_back': 'Nee, toch niet', 'guardian.help_pick': 'Ik kijk hiernaar', 'guardian.help_close': 'Markeer als afgehandeld', 'guardian.help_picked_by': '{who} kijkt hiernaar', 'guardian.help_handled_by': 'Afgehandeld door {who}', 'guardian.help_handled_note': 'Dit blijft staan. Leeft de vraag nog, dan stelt het kind hem opnieuw.', 'guardian.help_close_ask': 'Weet je het zeker? Dit is niet terug te draaien. Speelt het toch nog, dan vraagt het kind opnieuw om hulp.', 'guardian.help_close_yes': 'Ja, afgehandeld', 'guardian.help_just_now': 'zojuist', 'guardian.help_hours': '{n} uur geleden', 'guardian.help_days': '{n} dagen geleden', 'guardian.gate_unavailable': 'nog niet beschikbaar', 'guardian.gate_planned_note': 'Dit bestaat nog niet op deze server.', 'guardian.gates_summary': '{n} poorten - {on} aan, {wait} wachten', 'guardian.gates_show': 'Toon poorten', 'guardian.gates_hide': 'Verberg poorten', 'guardian.gate_images': 'Plaatjes', 'guardian.gate_messages': 'Berichten', 'guardian.gate_compose': 'Zelf posten', 'guardian.gate_music': 'Muziek', 'guardian.gate_quoteCards': 'Quote-kaarten', 'guardian.gate_customEmoji': 'Eigen emoji', 'guardian.gate_publicProfile': 'Publiek zichtbaar', 'guardian.gate_accountMove': 'Verhuizen', 'guardian.gate_independence': 'Zelfstandig worden', 'guardian.gate_externalEmbeds': 'Linkvoorbeelden', 'guardian.gate_externalPlayback': 'Afspelen in de app', 'guardian.gate_follows': 'Volgverzoeken', 'guardian.gate_kind_setting': 'stand', 'guardian.gate_kind_perRequest': 'per verzoek', 'guardian.gate_kind_handover': 'draagt gezag over', 'guardian.gate_default_off': 'uit (nog niets over besloten)', 'guardian.gate_unknown': 'onbekend', 'guardian.gate_threshold': '{need} van {of} guardians', 'guardian.gate_threshold_unknown': 'drempel onbekend (ander domein)', 'guardian.gate_irreversible': 'niet terug te draaien', 'guardian.gate_waiting': '{n} wacht op jullie', 'guardian.gate_blocked': 'kan pas als {what} aanstaat', 'guardian.gate_propose_open': 'Voorstellen: openzetten', 'guardian.gate_propose_close': 'Voorstellen: dichtzetten', 'guardian.gate_propose': 'Voorstellen', 'push.n_gate_ask_t': 'Je antwoord is nodig', 'push.n_gate_ask_b': 'Voorstel voor {who}: {wat} {stand}', 'push.n_gate_done_t': 'Besluit genomen', 'push.n_gate_done_b': '{wat} {stand} voor {who}: {uitkomst}', 'push.n_test_t': 'Klonkt-testnotificatie', 'push.n_test_b': 'Werkt. Zo komen meldingen binnen op dit apparaat.',
+    'push.n_follow_t': 'Nieuwe volger', 'push.n_follow_b': '{who} volgt je nu', 'push.n_reply_t': 'Reactie op "{title}"', 'push.n_mention_t': 'Vermelding', 'push.n_dm_t': 'Privébericht', 'push.n_dm_b': 'Nieuw bericht van {who}', 'push.n_like_t': 'Nieuwe waardering', 'push.n_like_b': '{who} waardeerde "{title}"', 'push.n_boost_t': 'Geboost', 'push.n_boost_b': '{who} boostte "{title}"', 'msg.guard_offer': 'wil je guardian worden. Bespreek dit met je ouders of verzorgers voordat je beslist.', 'msg.guard_accept': 'Accepteer', 'msg.guard_reject': 'Weiger', 'msg.guard_accepted': 'Guardian geaccepteerd. Jullie zijn nu verbonden.', 'msg.guard_rejected': 'Aanvraag geweigerd.', 'msg.guard_failed': 'Dat lukte niet; probeer het opnieuw.', 'msg.guardians_label': 'Jouw guardians', 'msg.waved_at_you': 'zwaaide naar je', 'msg.help_request': 'vroeg om hulp', 'msg.g_available': 'beschikbaar', 'msg.g_away': 'afwezig tot {date}', 'msg.g_offline': 'offline', 'msg.wave_r1': 'Wat leuk!', 'msg.wave_r2': 'Bel me even', 'msg.wave_back': '👋 Terug', 'msg.wave_sent': 'Zwaai verstuurd.', 'msg.reply_sent': 'Antwoord verstuurd.', 'msg.reply_failed': 'Het antwoord kon niet verstuurd worden.', 'msg.reply_empty': 'Een leeg antwoord versturen kan niet.', 'guardian.feed_title': 'Van je wards', 'guardian.feed_sub': 'Meelezen met wat je wards plaatsen. Alleen kijken.', 'guardian.follow_title': 'Volgverzoeken', 'guardian.follow_sub': 'Iemand wil een van je wards volgen. Jij beslist.', 'guardian.wave': '👋 Zwaai', 'guardian.waved': '👋 verstuurd', 'guardian.app_name': 'Klonkt Guardian', 'guardian.tagline': 'Wards beheren en hulpverzoeken opvangen.', 'guardian.acting_as': 'Je handelt als', 'guardian.help_title': 'Hulpverzoeken', 'guardian.help_sub': 'Als een ward de reddingsboei gebruikt, verschijnt het hier.', 'guardian.help_empty': 'Geen hulpverzoeken. Mooi zo.', 'guardian.adopt_title': 'Ward adopteren', 'guardian.adopt_sub': 'Vul de handle van het kind in (@kind@server.eu). Ze krijgen een aanvraag in hun Klonkt die ze accepteren.', 'guardian.adopt_label': 'Handle van de ward', 'guardian.adopt_btn': 'Verstuur aanvraag', 'guardian.pending_title': 'Verzonden aanvragen', 'guardian.pending_sub': 'Wacht tot de ward accepteert.', 'guardian.wards_title': 'Mijn wards', 'guardian.play_propose': 'Afspelen voorstellen', 'guardian.play_on': 'Afspelen: aan', 'guardian.play_off': 'Afspelen: uit', 'guardian.gated_title': 'Instelling voorgesteld', 'guardian.gated_line_on': '{who} wil linkvoorbeelden AANzetten voor {ward}.', 'guardian.gated_line_off': '{who} wil linkvoorbeelden UITzetten voor {ward}.', 'guardian.gated_agree': 'Eens', 'guardian.gated_disagree': 'Oneens', 'guardian.avail_available': 'Beschikbaar', 'guardian.avail_away': 'Afwezig tot {date}', 'guardian.avail_dormant': 'Offline', 'guardian.panel_guards': 'Guardians van dit kind', 'guardian.panel_guards_remote': 'Dit kind woont op een andere server; de beschikbaarheid wordt daar bijgehouden.', 'guardian.lapse_propose': 'Voorstel: loslaten bij afwezigheid', 'guardian.lapse_line': '{who} antwoordt niet meer als guardian van {ward}.', 'guardian.lapse_tally': '{n} van {need} akkoord; sluit {date}; het venster loopt altijd vol.', 'guardian.lapse_note': 'Elk teken van leven van hen annuleert dit meteen. Niets hier is straf.', 'guardian.lapse_agree': 'Eens', 'guardian.lapse_disagree': 'Oneens', 'guardian.voted': 'Je hebt gestemd', 'guardian.away_title': 'Even afwezig', 'guardian.away_sub': 'Meld je wards dat je er even niet bent. Besluiten wachten niet op je, en een enkel antwoord brengt je meteen terug.', 'guardian.away_week': 'Een week', 'guardian.away_month': 'Een maand', 'guardian.away_done': 'Je wards weten dat je afwezig bent tot {date}.', 'guardian.away_msg': 'Ik ben afwezig als je guardian tot {date}. Je andere guardians zijn er voor je.', 'guardian.release_title': '{who} loslaten?', 'guardian.release_effect': 'Je stopt als guardian. Je ziet hun berichten niet meer, je krijgt geen hulpvragen meer van ze, en je beoordeelt geen volgverzoeken meer voor ze. Terugkomen kan alleen met een nieuwe aanvraag die zij accepteren.', 'guardian.release_local': 'Hun server en de andere guardians krijgen dit door, dus daarna sta jij ook bij hen niet meer als guardian.', 'guardian.release_step_down': 'Zij houden hun andere guardians, dus zij blijven een ward.', 'guardian.release_last': 'Je bent hun laatste guardian. Dat is emancipatie, en volgens FEP-633c 3.4 is dat niet aan een guardian alleen: daar horen drie instemmende volwassenen bij, of een meerderheid met twee getuigen. Deze knop kan dat dus niet: je blijft hun guardian tot dat geregeld is.', 'guardian.release_unknown': 'We konden hun server niet bereiken, dus we weten niet of jij hun laatste guardian bent.', 'guardian.release_yes': 'Ja, loslaten', 'guardian.release_no': 'Nee, toch niet', 'guardian.settings_title': 'Instellingen', 'guardian.panel_open': 'Bekijken', 'guardian.panel_close': 'Sluiten', 'guardian.panel_help': 'Hulpvragen van dit kind', 'guardian.panel_help_empty': 'Nog geen hulpvragen.', 'guardian.panel_follow': 'Volgverzoeken', 'guardian.panel_follow_empty': 'Geen openstaande volgverzoeken.', 'guardian.panel_posts': 'Recente berichten', 'guardian.panel_posts_empty': 'Nog niets te zien.', 'guardian.panel_actions': 'Acties', 'guardian.badge_help': 'hulpvragen', 'guardian.badge_follow': 'volgverzoeken', 'guardian.badge_follow_one': 'volgverzoek', 'guardian.wards_empty': 'Nog geen wards. Adopteer er hierboven een.', 'guardian.push_title': 'Meldingen', 'guardian.push_sub': 'Ontvang een melding bij een hulpverzoek of voogdij-antwoord, ook als de app dicht is.', 'guardian.push_on': 'Zet meldingen aan', 'guardian.push_off': 'Meldingen staan aan; tik om uit te zetten', 'guardian.sent': 'Aanvraag verstuurd. Zie hieronder bij Verzonden aanvragen.', 'guardian.sent_retry': 'Aanvraag opgeslagen; we blijven proberen te bezorgen.', 'guardian.sending': 'Versturen…', 'guardian.not_found': 'Die handle konden we niet vinden.', 'guardian.failed': 'Mislukt', 'guardian.network': 'Netwerkfout.', 'guardian.pending': 'wacht op antwoord', 'guardian.active': 'actief', 'guardian.retract': 'Intrekken', 'guardian.release': 'Loslaten', 'guardian.embeds_on': 'Linkvoorbeelden: aan', 'guardian.embeds_off': 'Linkvoorbeelden: uit', 'guardian.embeds_propose': 'Linkvoorbeelden voorstellen', 'guardian.embeds_waiting': 'wacht op de andere guardians', 'guardian.prop_line': 'Voorstel {what} {value}: {status}', 'guardian.prop_embeds': 'linkvoorbeelden', 'guardian.prop_play': 'afspelen', 'guardian.prop_on': 'aan', 'guardian.prop_off': 'uit', 'guardian.prop_st_open': 'wacht op de andere guardians', 'guardian.prop_st_accepted': 'aangenomen', 'guardian.prop_st_rejected': 'afgewezen', 'guardian.prop_st_expired': 'verlopen zonder genoeg stemmen', 'guardian.panel_guards_far': 'Beschikbaarheid wordt op hun server bijgehouden.', 'guardian.release_confirm': '{who} loslaten?\n\nJe stopt dan als guardian. Je ziet hun berichten niet meer, je krijgt geen hulpverzoeken meer van ze, en je kunt volgverzoeken niet meer voor ze beoordelen.\n\nTerugkomen kan alleen met een nieuwe aanvraag die zij accepteren.', 'guardian.open': 'open', 'guardian.accept': 'Accepteer', 'guardian.reject': 'Weiger', 'guardian.complete': 'Voltooien', 'guardian.awaiting_others': 'wacht op de andere partijen', 'guardian.coguard': 'mede-voogdij-aanvraag', 'guardian.push_unavailable': 'Push niet beschikbaar', 'push.n_help_t': 'Hulpvraag', 'push.n_help_b': '{who} vraagt om je hulp', 'push.n_guard_offer_t': 'Voogdij-aanvraag', 'push.n_guard_offer_b': '{who} wil je guardian worden', 'push.n_guard_ward_t': 'Ward geaccepteerd', 'push.n_guard_left_t': 'Een guardian is gestopt', 'push.n_guard_left_b': '{who} is niet langer je guardian', 'push.n_guard_cogleft_t': 'Mede-guardian gestopt', 'push.n_guard_cogleft_b': '{who} heeft de guardianship beeindigd', 'push.n_guard_ward_b': '{who} accepteerde je als guardian', 'push.n_guard_cog_t': 'Mede-voogdij gevraagd', 'push.n_guard_cog_b': 'Er is een guardian-aanvraag voor {who}', 'guardian.panel_history': 'Geschiedenis ({n})', 'guardian.help_archive': '{n} afgehandeld', 'guardian.help_archive_hide': 'verbergen', 'guardian.help_former_ward': 'Niet meer jouw ward. Hun andere guardians zijn er nog voor ze.', 'guardian.warn_reversible': 'Wat hier doorheen komt, komt niet meer terug. Je kunt deze instelling later weer dichtzetten — wat je kind gezien heeft niet.', 'guardian.warn_irreversible': 'Dit is niet terug te draaien. Hierna beslist zij het zelf, en jullie kunnen dat niet meer terugnemen.', 'guardian.warn_unknown': 'Wij kennen deze instelling niet, dus we weten niet wat er doorheen komt of hoe ver het reikt. Vraag het degene die het voorstelde voordat je ja zegt.', 'guardian.warn_tally_elsewhere': 'Hoeveel guardians al geantwoord hebben zien wij niet — dat telt de server van het kind. Jouw ja kan de doorslag geven.', 'guardian.warn_go': 'Ja, stel dit voor', 'guardian.warn_back': 'Nee, toch niet', 'guardian.help_pick': 'Ik kijk hiernaar', 'guardian.help_close': 'Markeer als afgehandeld', 'guardian.help_picked_by': '{who} kijkt hiernaar', 'guardian.help_handled_by': 'Afgehandeld door {who}', 'guardian.help_handled_note': 'Dit blijft staan. Leeft de vraag nog, dan stelt het kind hem opnieuw.', 'guardian.help_close_ask': 'Weet je het zeker? Dit is niet terug te draaien. Speelt het toch nog, dan vraagt het kind opnieuw om hulp.', 'guardian.help_close_yes': 'Ja, afgehandeld', 'guardian.help_just_now': 'zojuist', 'guardian.help_hours': '{n} uur geleden', 'guardian.help_days': '{n} dagen geleden', 'guardian.gate_unavailable': 'nog niet beschikbaar', 'guardian.gate_planned_note': 'Dit bestaat nog niet op deze server.', 'guardian.gates_summary': '{n} poorten - {on} aan, {wait} wachten', 'guardian.gates_show': 'Toon poorten', 'guardian.gates_hide': 'Verberg poorten', 'guardian.gate_images': 'Plaatjes', 'guardian.gate_messages': 'Berichten', 'guardian.gate_compose': 'Zelf posten', 'guardian.gate_music': 'Muziek', 'guardian.gate_quoteCards': 'Quote-kaarten', 'guardian.gate_customEmoji': 'Eigen emoji', 'guardian.gate_publicProfile': 'Publiek zichtbaar', 'guardian.gate_accountMove': 'Verhuizen', 'guardian.gate_independence': 'Zelfstandig worden', 'guardian.gate_externalThreads': 'Reacties van onbekenden', 'guardian.gate_externalEmbeds': 'Linkvoorbeelden', 'guardian.gate_externalPlayback': 'Afspelen in de app', 'guardian.gate_follows': 'Volgverzoeken', 'guardian.gate_kind_setting': 'stand', 'guardian.gate_kind_perRequest': 'per verzoek', 'guardian.gate_kind_handover': 'draagt gezag over', 'guardian.gate_default_off': 'uit (nog niets over besloten)', 'guardian.gate_unknown': 'onbekend', 'guardian.gate_threshold': '{need} van {of} guardians', 'guardian.gate_threshold_unknown': 'drempel onbekend (ander domein)', 'guardian.gate_irreversible': 'niet terug te draaien', 'guardian.gate_waiting': '{n} wacht op jullie', 'guardian.gate_blocked': 'kan pas als {what} aanstaat', 'guardian.gate_propose_open': 'Voorstellen: openzetten', 'guardian.gate_propose_close': 'Voorstellen: dichtzetten', 'guardian.gate_propose': 'Voorstellen', 'push.n_gate_ask_t': 'Je antwoord is nodig', 'push.n_gate_ask_b': 'Voorstel voor {who}: {wat} {stand}', 'push.n_gate_done_t': 'Besluit genomen', 'push.n_gate_done_b': '{wat} {stand} voor {who}: {uitkomst}', 'push.n_test_t': 'Klonkt-testnotificatie', 'push.n_test_b': 'Werkt. Zo komen meldingen binnen op dit apparaat.',
     'apaid.t': 'Betaalde posts', 'apaid.intro': 'Koppel je eigen Patreon-campagne. Supporters ontgrendelen betaalde posts met een passkey, zonder account en zonder cookie. Wij bewaren geen namen of e-mailadressen van supporters, alleen het versleutelde token van jouw campagne.', 'apaid.saved': 'Opgeslagen.', 'apaid.nokey': 'Let op: de encryptiesleutel kon niet worden aangemaakt of gelezen (schrijfrechten op de opslagmap?). Zonder sleutel kunnen secrets niet veilig worden opgeslagen.', 'apaid.status': 'Status:', 'apaid.connected': 'verbonden', 'apaid.campaign': 'campagne', 'apaid.configured': 'ingesteld, nog niet verbonden (vul een token in)', 'apaid.notyet': 'nog niet ingesteld', 'apaid.redirect_h': 'Zet deze redirect-URI in je Patreon-client', 'apaid.redirect_p': 'Bij je Patreon API-client, onder Redirect URIs, moet exact deze regel staan. Klopt hij niet, dan geeft Patreon een foutmelding in plaats van je supporters terug te sturen.', 'apaid.copy': 'Kopieer', 'apaid.copied': 'Gekopieerd', 'apaid.client_id': 'Patreon client id', 'apaid.client_secret': 'Patreon client secret', 'apaid.keep': 'Leeg laten = huidige waarde behouden.', 'apaid.campaign_id': 'Campagne-id', 'apaid.public_page': 'Openbare Patreon-pagina', 'apaid.public_help': 'De link waar bezoekers supporter kunnen worden. Getoond als "Word supporter" wanneer iemand nog niet doneert.', 'apaid.access': 'Creator access token', 'apaid.refresh': 'Creator refresh token', 'apaid.token_help': 'De access + refresh token krijg je op je Patreon API-clientpagina. Wij versleutelen ze en verversen automatisch.', 'apaid.min_eur': 'Standaard-steunbedrag voor een betaalde post (euro)', 'apaid.save': 'Opslaan', 'apaid.disconnect': 'Koppeling verwijderen', 'apaid.disconnect_confirm': 'Patreon-koppeling verwijderen?', 'apaid.unchanged': 'blijft ongewijzigd',
     'pgate.h': 'Voor supporters', 'pgate.sub': 'Deze post is voor supporters van deze site. Word supporter en ontgrendel hem daarna met een passkey. Geen account op deze site, geen cookie.', 'pgate.sub_cents': 'Deze post is voor supporters van deze site (vanaf €{eur} per maand op Patreon). Word supporter en ontgrendel hem daarna met een passkey. Geen account op deze site, geen cookie.', 'pgate.join': 'Word supporter op Patreon', 'pgate.unlock_have': 'Al supporter? Ontgrendelen', 'pgate.unlock': 'Ontgrendelen met Patreon', 'pgate.join_short': 'Word supporter', 'pgate.confirm': 'Bevestig met je passkey…', 'pgate.failed': 'Ontgrendelen mislukt. Probeer opnieuw.', 'pgate.error': 'Er ging iets mis. Probeer opnieuw.',
@@ -1017,5 +1017,5 @@
     'admin.b_paid': 'Paid posts', 'admin.b_push': 'Notifications', 'admin.back': 'Back to Admin',
     'push.t': 'Notifications', 'push.intro': 'Get a notification on this device for new followers, replies and messages, even when the site is closed. Encrypted all the way to your browser; we send as little content as possible.', 'push.unavailable': 'Push is unavailable on this server (the key could not be created or the dependency is missing).', 'push.unsupported': 'This browser does not support push notifications.', 'push.ios_hint': 'On iPhone/iPad this only works when the site is on your home screen: share button, then "Add to Home Screen", and open it from there.', 'push.this_device': 'This device:', 'push.checking': 'checking…', 'push.state_on': 'notifications are on', 'push.state_off': 'notifications are off', 'push.state_denied': 'blocked in the browser settings', 'push.state_unknown': 'status unknown', 'push.state_unsupported': 'not supported', 'push.enable': 'Turn on for this device', 'push.disable': 'Turn off', 'push.test': 'Send a test notification', 'push.what': 'What do you want to be notified about?', 'push.a_follow': 'New follower', 'push.a_reply': 'Reply or mention', 'push.a_like': 'Like (star)', 'push.a_boost': 'Boost', 'push.a_dm': 'Private message', 'push.saved': 'Saved.', 'push.devices': 'Linked devices', 'push.device': 'Device', 'push.since': 'since', 'push.remove': 'Remove', 'push.enable_failed': 'turning on failed',
-    'push.n_follow_t': 'New follower', 'push.n_follow_b': '{who} now follows you', 'push.n_reply_t': 'Reply to "{title}"', 'push.n_mention_t': 'Mention', 'push.n_dm_t': 'Private message', 'push.n_dm_b': 'New message from {who}', 'push.n_like_t': 'New like', 'push.n_like_b': '{who} liked "{title}"', 'push.n_boost_t': 'Boosted', 'push.n_boost_b': '{who} boosted "{title}"', 'msg.guard_offer': 'wants to become your guardian. Talk this over with your parents or carers before you decide.', 'msg.guard_accept': 'Accept', 'msg.guard_reject': 'Reject', 'msg.guard_accepted': 'Guardian accepted. You are now connected.', 'msg.guard_rejected': 'Offer rejected.', 'msg.guard_failed': 'That did not work; try again.', 'msg.guardians_label': 'Your guardians', 'msg.waved_at_you': 'waved at you', 'msg.help_request': 'asked for help', 'msg.g_available': 'available', 'msg.g_away': 'unavailable till {date}', 'msg.g_offline': 'offline', 'msg.wave_r1': 'Lovely!', 'msg.wave_r2': 'Call me', 'msg.wave_back': '👋 Back', 'msg.wave_sent': 'Wave sent.', 'msg.reply_sent': 'Reply sent.', 'msg.reply_failed': 'The reply could not be sent.', 'msg.reply_empty': 'An empty reply cannot be sent.', 'guardian.feed_title': 'Your wards', 'guardian.feed_sub': 'Read along with what your wards post. Watch only.', 'guardian.follow_title': 'Follow requests', 'guardian.follow_sub': 'Someone wants to follow one of your wards. You decide.', 'guardian.wave': '👋 Wave', 'guardian.waved': '👋 sent', 'guardian.app_name': 'Klonkt Guardian', 'guardian.tagline': 'Manage wards and catch calls for help.', 'guardian.acting_as': 'You act as', 'guardian.help_title': 'Help requests', 'guardian.help_sub': 'When a ward uses the help buoy, it shows up here.', 'guardian.help_empty': 'No help requests. Good.', 'guardian.adopt_title': 'Adopt a ward', 'guardian.adopt_sub': 'Enter the child handle (@kid@server.eu). They get an offer in their Klonkt to accept.', 'guardian.adopt_label': 'Ward handle', 'guardian.adopt_btn': 'Send offer', 'guardian.pending_title': 'Sent offers', 'guardian.pending_sub': 'Waiting for the ward to accept.', 'guardian.wards_title': 'My wards', 'guardian.play_propose': 'Propose in-app playback', 'guardian.play_on': 'Playback: on', 'guardian.play_off': 'Playback: off', 'guardian.gated_title': 'Setting proposed', 'guardian.gated_line_on': '{who} wants to turn link previews ON for {ward}.', 'guardian.gated_line_off': '{who} wants to turn link previews OFF for {ward}.', 'guardian.gated_agree': 'Agree', 'guardian.gated_disagree': 'Disagree', 'guardian.avail_available': 'Available', 'guardian.avail_away': 'Unavailable till {date}', 'guardian.avail_dormant': 'Offline', 'guardian.panel_guards': 'Guardians of this child', 'guardian.panel_guards_remote': 'This child lives on another server; availability is tracked there.', 'guardian.lapse_propose': 'Propose release in absentia', 'guardian.lapse_line': '{who} has stopped answering as a guardian of {ward}.', 'guardian.lapse_tally': '{n} of {need} agreed; closes {date}; the window always runs in full.', 'guardian.lapse_note': 'Any sign of life from them cancels this outright. Nothing here is punishment.', 'guardian.lapse_agree': 'Agree', 'guardian.lapse_disagree': 'Disagree', 'guardian.voted': 'You voted', 'guardian.away_title': 'Step away', 'guardian.away_sub': 'Tell your wards you are unavailable for a while. Decisions will not wait for you, and one answer brings you straight back.', 'guardian.away_week': 'A week', 'guardian.away_month': 'A month', 'guardian.away_done': 'Your wards know you are unavailable until {date}.', 'guardian.away_msg': 'I am unavailable as your guardian until {date}. Your other guardians are there for you.', 'guardian.release_title': 'Release {who}?', 'guardian.release_effect': 'You stop being their guardian. You will no longer see their posts, no longer receive their calls for help, and no longer decide on follow requests for them. Coming back means a fresh offer that they accept.', 'guardian.release_local': 'Their server and the other guardians are told, so afterwards you are no longer listed as a guardian there either.', 'guardian.release_step_down': 'They keep their other guardians, so they stay a ward.', 'guardian.release_last': 'You are their last guardian. That is emancipation, and FEP-633c 3.4 is explicit that no single guardian decides it: it takes three consenting adults, or a majority plus two witnesses. So this button cannot do it: you stay their guardian until that is arranged.', 'guardian.release_unknown': 'We could not reach their server, so we do not know whether you are their last guardian.', 'guardian.release_yes': 'Yes, release', 'guardian.release_no': 'No, keep them', 'guardian.settings_title': 'Settings', 'guardian.panel_open': 'Open', 'guardian.panel_close': 'Close', 'guardian.panel_help': 'Calls for help from this child', 'guardian.panel_help_empty': 'No calls for help yet.', 'guardian.panel_follow': 'Follow requests', 'guardian.panel_follow_empty': 'No follow requests waiting.', 'guardian.panel_posts': 'Recent posts', 'guardian.panel_posts_empty': 'Nothing here yet.', 'guardian.panel_actions': 'Actions', 'guardian.badge_help': 'calls for help', 'guardian.badge_follow': 'follow requests', 'guardian.badge_follow_one': 'follow request', 'guardian.wards_empty': 'No wards yet. Adopt one above.', 'guardian.push_title': 'Notifications', 'guardian.push_sub': 'Get notified on a call for help or a guardianship answer, even with the app closed.', 'guardian.push_on': 'Turn on notifications', 'guardian.push_off': 'Notifications are on; tap to turn off', 'guardian.sent': 'Offer sent. See it below under Sent offers.', 'guardian.sent_retry': 'Offer saved; we keep trying to deliver it.', 'guardian.sending': 'Sending…', 'guardian.not_found': 'We could not find that handle.', 'guardian.failed': 'Failed', 'guardian.network': 'Network error.', 'guardian.pending': 'awaiting answer', 'guardian.active': 'active', 'guardian.retract': 'Retract', 'guardian.release': 'Release', 'guardian.embeds_on': 'Link previews: on', 'guardian.embeds_off': 'Link previews: off', 'guardian.embeds_propose': 'Propose link previews', 'guardian.embeds_waiting': 'waiting for the other guardians', 'guardian.prop_line': 'Proposal {what} {value}: {status}', 'guardian.prop_embeds': 'link previews', 'guardian.prop_play': 'playback', 'guardian.prop_on': 'on', 'guardian.prop_off': 'off', 'guardian.prop_st_open': 'waiting for the other guardians', 'guardian.prop_st_accepted': 'accepted', 'guardian.prop_st_rejected': 'rejected', 'guardian.prop_st_expired': 'expired without enough votes', 'guardian.panel_guards_far': 'Availability is tracked on their server.', 'guardian.release_confirm': 'Release {who}?\n\nYou stop being their guardian. You will no longer see their posts, no longer receive their calls for help, and no longer decide on follow requests for them.\n\nComing back means a fresh offer that they accept.', 'guardian.open': 'open', 'guardian.accept': 'Accept', 'guardian.reject': 'Reject', 'guardian.complete': 'Complete', 'guardian.awaiting_others': 'awaiting the other parties', 'guardian.coguard': 'co-guardianship offer', 'guardian.push_unavailable': 'Push unavailable', 'push.n_help_t': 'Call for help', 'push.n_help_b': '{who} is asking for your help', 'push.n_guard_offer_t': 'Guardianship offer', 'push.n_guard_offer_b': '{who} wants you as their guardian', 'push.n_guard_ward_t': 'Ward accepted', 'push.n_guard_left_t': 'A guardian has stepped down', 'push.n_guard_left_b': '{who} is no longer your guardian', 'push.n_guard_cogleft_t': 'Co-guardian stepped down', 'push.n_guard_cogleft_b': '{who} has ended their guardianship', 'push.n_guard_ward_b': '{who} accepted you as guardian', 'push.n_guard_cog_t': 'Co-guardianship asked', 'push.n_guard_cog_b': 'A guardian offer for {who} needs you', 'guardian.panel_history': 'History ({n})', 'guardian.help_archive': '{n} handled', 'guardian.help_archive_hide': 'hide', 'guardian.help_former_ward': 'No longer your ward. Their other guardians are still there for them.', 'guardian.warn_reversible': 'What comes through does not go back. You can close this setting again later — what your child has seen, you cannot.', 'guardian.warn_irreversible': 'This cannot be undone. From then on they decide for themselves, and you cannot take that back.', 'guardian.warn_unknown': 'We do not know this setting, so we cannot tell what comes through or how far it reaches. Ask whoever proposed it before you agree.', 'guardian.warn_tally_elsewhere': 'We cannot see how many guardians have answered — the child\u2019s server counts that. Your yes may be the deciding one.', 'guardian.warn_go': 'Yes, propose this', 'guardian.warn_back': 'No, go back', 'guardian.help_pick': 'I am on it', 'guardian.help_close': 'Mark as handled', 'guardian.help_picked_by': '{who} is looking into this', 'guardian.help_handled_by': 'Handled by {who}', 'guardian.help_handled_note': 'This stays. If it is still going on, the child asks again.', 'guardian.help_close_ask': 'Are you sure? This cannot be undone. If it is still going on, the child will ask for help again.', 'guardian.help_close_yes': 'Yes, handled', 'guardian.help_just_now': 'just now', 'guardian.help_hours': '{n}h ago', 'guardian.help_days': '{n}d ago', 'guardian.gate_unavailable': 'not available yet', 'guardian.gate_planned_note': 'This does not exist on this server yet.', 'guardian.gates_summary': '{n} gates - {on} on, {wait} waiting', 'guardian.gates_show': 'Show gates', 'guardian.gates_hide': 'Hide gates', 'guardian.gate_images': 'Images', 'guardian.gate_messages': 'Messages', 'guardian.gate_compose': 'Posting', 'guardian.gate_music': 'Music', 'guardian.gate_quoteCards': 'Quote cards', 'guardian.gate_customEmoji': 'Custom emoji', 'guardian.gate_publicProfile': 'Publicly visible', 'guardian.gate_accountMove': 'Moving account', 'guardian.gate_independence': 'Becoming independent', 'guardian.gate_externalEmbeds': 'Link previews', 'guardian.gate_externalPlayback': 'In-app playback', 'guardian.gate_follows': 'Follow requests', 'guardian.gate_kind_setting': 'setting', 'guardian.gate_kind_perRequest': 'per request', 'guardian.gate_kind_handover': 'hands over authority', 'guardian.gate_default_off': 'off (nothing decided yet)', 'guardian.gate_unknown': 'unknown', 'guardian.gate_threshold': '{need} of {of} guardians', 'guardian.gate_threshold_unknown': 'threshold unknown (other domain)', 'guardian.gate_irreversible': 'cannot be undone', 'guardian.gate_waiting': '{n} waiting on you', 'guardian.gate_blocked': 'needs {what} on first', 'guardian.gate_propose_open': 'Propose: open', 'guardian.gate_propose_close': 'Propose: close', 'guardian.gate_propose': 'Propose', 'push.n_gate_ask_t': 'Your answer is needed', 'push.n_gate_ask_b': 'Proposal for {who}: {wat} {stand}', 'push.n_gate_done_t': 'Decision reached', 'push.n_gate_done_b': '{wat} {stand} for {who}: {uitkomst}', 'push.n_test_t': 'Klonkt test notification', 'push.n_test_b': 'It works. This is how notifications arrive on this device.',
+    'push.n_follow_t': 'New follower', 'push.n_follow_b': '{who} now follows you', 'push.n_reply_t': 'Reply to "{title}"', 'push.n_mention_t': 'Mention', 'push.n_dm_t': 'Private message', 'push.n_dm_b': 'New message from {who}', 'push.n_like_t': 'New like', 'push.n_like_b': '{who} liked "{title}"', 'push.n_boost_t': 'Boosted', 'push.n_boost_b': '{who} boosted "{title}"', 'msg.guard_offer': 'wants to become your guardian. Talk this over with your parents or carers before you decide.', 'msg.guard_accept': 'Accept', 'msg.guard_reject': 'Reject', 'msg.guard_accepted': 'Guardian accepted. You are now connected.', 'msg.guard_rejected': 'Offer rejected.', 'msg.guard_failed': 'That did not work; try again.', 'msg.guardians_label': 'Your guardians', 'msg.waved_at_you': 'waved at you', 'msg.help_request': 'asked for help', 'msg.g_available': 'available', 'msg.g_away': 'unavailable till {date}', 'msg.g_offline': 'offline', 'msg.wave_r1': 'Lovely!', 'msg.wave_r2': 'Call me', 'msg.wave_back': '👋 Back', 'msg.wave_sent': 'Wave sent.', 'msg.reply_sent': 'Reply sent.', 'msg.reply_failed': 'The reply could not be sent.', 'msg.reply_empty': 'An empty reply cannot be sent.', 'guardian.feed_title': 'Your wards', 'guardian.feed_sub': 'Read along with what your wards post. Watch only.', 'guardian.follow_title': 'Follow requests', 'guardian.follow_sub': 'Someone wants to follow one of your wards. You decide.', 'guardian.wave': '👋 Wave', 'guardian.waved': '👋 sent', 'guardian.app_name': 'Klonkt Guardian', 'guardian.tagline': 'Manage wards and catch calls for help.', 'guardian.acting_as': 'You act as', 'guardian.help_title': 'Help requests', 'guardian.help_sub': 'When a ward uses the help buoy, it shows up here.', 'guardian.help_empty': 'No help requests. Good.', 'guardian.adopt_title': 'Adopt a ward', 'guardian.adopt_sub': 'Enter the child handle (@kid@server.eu). They get an offer in their Klonkt to accept.', 'guardian.adopt_label': 'Ward handle', 'guardian.adopt_btn': 'Send offer', 'guardian.pending_title': 'Sent offers', 'guardian.pending_sub': 'Waiting for the ward to accept.', 'guardian.wards_title': 'My wards', 'guardian.play_propose': 'Propose in-app playback', 'guardian.play_on': 'Playback: on', 'guardian.play_off': 'Playback: off', 'guardian.gated_title': 'Setting proposed', 'guardian.gated_line_on': '{who} wants to turn link previews ON for {ward}.', 'guardian.gated_line_off': '{who} wants to turn link previews OFF for {ward}.', 'guardian.gated_agree': 'Agree', 'guardian.gated_disagree': 'Disagree', 'guardian.avail_available': 'Available', 'guardian.avail_away': 'Unavailable till {date}', 'guardian.avail_dormant': 'Offline', 'guardian.panel_guards': 'Guardians of this child', 'guardian.panel_guards_remote': 'This child lives on another server; availability is tracked there.', 'guardian.lapse_propose': 'Propose release in absentia', 'guardian.lapse_line': '{who} has stopped answering as a guardian of {ward}.', 'guardian.lapse_tally': '{n} of {need} agreed; closes {date}; the window always runs in full.', 'guardian.lapse_note': 'Any sign of life from them cancels this outright. Nothing here is punishment.', 'guardian.lapse_agree': 'Agree', 'guardian.lapse_disagree': 'Disagree', 'guardian.voted': 'You voted', 'guardian.away_title': 'Step away', 'guardian.away_sub': 'Tell your wards you are unavailable for a while. Decisions will not wait for you, and one answer brings you straight back.', 'guardian.away_week': 'A week', 'guardian.away_month': 'A month', 'guardian.away_done': 'Your wards know you are unavailable until {date}.', 'guardian.away_msg': 'I am unavailable as your guardian until {date}. Your other guardians are there for you.', 'guardian.release_title': 'Release {who}?', 'guardian.release_effect': 'You stop being their guardian. You will no longer see their posts, no longer receive their calls for help, and no longer decide on follow requests for them. Coming back means a fresh offer that they accept.', 'guardian.release_local': 'Their server and the other guardians are told, so afterwards you are no longer listed as a guardian there either.', 'guardian.release_step_down': 'They keep their other guardians, so they stay a ward.', 'guardian.release_last': 'You are their last guardian. That is emancipation, and FEP-633c 3.4 is explicit that no single guardian decides it: it takes three consenting adults, or a majority plus two witnesses. So this button cannot do it: you stay their guardian until that is arranged.', 'guardian.release_unknown': 'We could not reach their server, so we do not know whether you are their last guardian.', 'guardian.release_yes': 'Yes, release', 'guardian.release_no': 'No, keep them', 'guardian.settings_title': 'Settings', 'guardian.panel_open': 'Open', 'guardian.panel_close': 'Close', 'guardian.panel_help': 'Calls for help from this child', 'guardian.panel_help_empty': 'No calls for help yet.', 'guardian.panel_follow': 'Follow requests', 'guardian.panel_follow_empty': 'No follow requests waiting.', 'guardian.panel_posts': 'Recent posts', 'guardian.panel_posts_empty': 'Nothing here yet.', 'guardian.panel_actions': 'Actions', 'guardian.badge_help': 'calls for help', 'guardian.badge_follow': 'follow requests', 'guardian.badge_follow_one': 'follow request', 'guardian.wards_empty': 'No wards yet. Adopt one above.', 'guardian.push_title': 'Notifications', 'guardian.push_sub': 'Get notified on a call for help or a guardianship answer, even with the app closed.', 'guardian.push_on': 'Turn on notifications', 'guardian.push_off': 'Notifications are on; tap to turn off', 'guardian.sent': 'Offer sent. See it below under Sent offers.', 'guardian.sent_retry': 'Offer saved; we keep trying to deliver it.', 'guardian.sending': 'Sending…', 'guardian.not_found': 'We could not find that handle.', 'guardian.failed': 'Failed', 'guardian.network': 'Network error.', 'guardian.pending': 'awaiting answer', 'guardian.active': 'active', 'guardian.retract': 'Retract', 'guardian.release': 'Release', 'guardian.embeds_on': 'Link previews: on', 'guardian.embeds_off': 'Link previews: off', 'guardian.embeds_propose': 'Propose link previews', 'guardian.embeds_waiting': 'waiting for the other guardians', 'guardian.prop_line': 'Proposal {what} {value}: {status}', 'guardian.prop_embeds': 'link previews', 'guardian.prop_play': 'playback', 'guardian.prop_on': 'on', 'guardian.prop_off': 'off', 'guardian.prop_st_open': 'waiting for the other guardians', 'guardian.prop_st_accepted': 'accepted', 'guardian.prop_st_rejected': 'rejected', 'guardian.prop_st_expired': 'expired without enough votes', 'guardian.panel_guards_far': 'Availability is tracked on their server.', 'guardian.release_confirm': 'Release {who}?\n\nYou stop being their guardian. You will no longer see their posts, no longer receive their calls for help, and no longer decide on follow requests for them.\n\nComing back means a fresh offer that they accept.', 'guardian.open': 'open', 'guardian.accept': 'Accept', 'guardian.reject': 'Reject', 'guardian.complete': 'Complete', 'guardian.awaiting_others': 'awaiting the other parties', 'guardian.coguard': 'co-guardianship offer', 'guardian.push_unavailable': 'Push unavailable', 'push.n_help_t': 'Call for help', 'push.n_help_b': '{who} is asking for your help', 'push.n_guard_offer_t': 'Guardianship offer', 'push.n_guard_offer_b': '{who} wants you as their guardian', 'push.n_guard_ward_t': 'Ward accepted', 'push.n_guard_left_t': 'A guardian has stepped down', 'push.n_guard_left_b': '{who} is no longer your guardian', 'push.n_guard_cogleft_t': 'Co-guardian stepped down', 'push.n_guard_cogleft_b': '{who} has ended their guardianship', 'push.n_guard_ward_b': '{who} accepted you as guardian', 'push.n_guard_cog_t': 'Co-guardianship asked', 'push.n_guard_cog_b': 'A guardian offer for {who} needs you', 'guardian.panel_history': 'History ({n})', 'guardian.help_archive': '{n} handled', 'guardian.help_archive_hide': 'hide', 'guardian.help_former_ward': 'No longer your ward. Their other guardians are still there for them.', 'guardian.warn_reversible': 'What comes through does not go back. You can close this setting again later — what your child has seen, you cannot.', 'guardian.warn_irreversible': 'This cannot be undone. From then on they decide for themselves, and you cannot take that back.', 'guardian.warn_unknown': 'We do not know this setting, so we cannot tell what comes through or how far it reaches. Ask whoever proposed it before you agree.', 'guardian.warn_tally_elsewhere': 'We cannot see how many guardians have answered — the child\u2019s server counts that. Your yes may be the deciding one.', 'guardian.warn_go': 'Yes, propose this', 'guardian.warn_back': 'No, go back', 'guardian.help_pick': 'I am on it', 'guardian.help_close': 'Mark as handled', 'guardian.help_picked_by': '{who} is looking into this', 'guardian.help_handled_by': 'Handled by {who}', 'guardian.help_handled_note': 'This stays. If it is still going on, the child asks again.', 'guardian.help_close_ask': 'Are you sure? This cannot be undone. If it is still going on, the child will ask for help again.', 'guardian.help_close_yes': 'Yes, handled', 'guardian.help_just_now': 'just now', 'guardian.help_hours': '{n}h ago', 'guardian.help_days': '{n}d ago', 'guardian.gate_unavailable': 'not available yet', 'guardian.gate_planned_note': 'This does not exist on this server yet.', 'guardian.gates_summary': '{n} gates - {on} on, {wait} waiting', 'guardian.gates_show': 'Show gates', 'guardian.gates_hide': 'Hide gates', 'guardian.gate_images': 'Images', 'guardian.gate_messages': 'Messages', 'guardian.gate_compose': 'Posting', 'guardian.gate_music': 'Music', 'guardian.gate_quoteCards': 'Quote cards', 'guardian.gate_customEmoji': 'Custom emoji', 'guardian.gate_publicProfile': 'Publicly visible', 'guardian.gate_accountMove': 'Moving account', 'guardian.gate_independence': 'Becoming independent', 'guardian.gate_externalThreads': 'Replies from strangers', 'guardian.gate_externalEmbeds': 'Link previews', 'guardian.gate_externalPlayback': 'In-app playback', 'guardian.gate_follows': 'Follow requests', 'guardian.gate_kind_setting': 'setting', 'guardian.gate_kind_perRequest': 'per request', 'guardian.gate_kind_handover': 'hands over authority', 'guardian.gate_default_off': 'off (nothing decided yet)', 'guardian.gate_unknown': 'unknown', 'guardian.gate_threshold': '{need} of {of} guardians', 'guardian.gate_threshold_unknown': 'threshold unknown (other domain)', 'guardian.gate_irreversible': 'cannot be undone', 'guardian.gate_waiting': '{n} waiting on you', 'guardian.gate_blocked': 'needs {what} on first', 'guardian.gate_propose_open': 'Propose: open', 'guardian.gate_propose_close': 'Propose: close', 'guardian.gate_propose': 'Propose', 'push.n_gate_ask_t': 'Your answer is needed', 'push.n_gate_ask_b': 'Proposal for {who}: {wat} {stand}', 'push.n_gate_done_t': 'Decision reached', 'push.n_gate_done_b': '{wat} {stand} for {who}: {uitkomst}', 'push.n_test_t': 'Klonkt test notification', 'push.n_test_b': 'It works. This is how notifications arrive on this device.',
     'apaid.t': 'Paid posts', 'apaid.intro': 'Connect your own Patreon campaign. Supporters unlock paid posts with a passkey, no account and no cookie. We store no supporter names or email addresses, only the encrypted token of your campaign.', 'apaid.saved': 'Saved.', 'apaid.nokey': 'Note: the encryption key could not be created or read (write permissions on the storage directory?). Without a key, secrets cannot be stored safely.', 'apaid.status': 'Status:', 'apaid.connected': 'connected', 'apaid.campaign': 'campaign', 'apaid.configured': 'configured, not connected yet (enter a token)', 'apaid.notyet': 'not configured yet', 'apaid.redirect_h': 'Put this redirect URI in your Patreon client', 'apaid.redirect_p': 'In your Patreon API client, under Redirect URIs, exactly this line must be present. If it does not match, Patreon shows an error instead of sending your supporters back.', 'apaid.copy': 'Copy', 'apaid.copied': 'Copied', 'apaid.client_id': 'Patreon client id', 'apaid.client_secret': 'Patreon client secret', 'apaid.keep': 'Leave empty = keep the current value.', 'apaid.campaign_id': 'Campaign id', 'apaid.public_page': 'Public Patreon page', 'apaid.public_help': 'The link where visitors can become a supporter. Shown as "Become a supporter" when someone does not pledge yet.', 'apaid.access': 'Creator access token', 'apaid.refresh': 'Creator refresh token', 'apaid.token_help': 'You get the access + refresh token on your Patreon API client page. We encrypt them and refresh automatically.', 'apaid.min_eur': 'Default support amount for a paid post (euro)', 'apaid.save': 'Save', 'apaid.disconnect': 'Remove connection', 'apaid.disconnect_confirm': 'Remove the Patreon connection?', 'apaid.unchanged': 'stays unchanged',
     'pgate.h': 'For supporters', 'pgate.sub': 'This post is for supporters of this site. Become a supporter and then unlock it with a passkey. No account on this site, no cookie.', 'pgate.sub_cents': 'This post is for supporters of this site (from €{eur} per month on Patreon). Become a supporter and then unlock it with a passkey. No account on this site, no cookie.', 'pgate.join': 'Become a supporter on Patreon', 'pgate.unlock_have': 'Already a supporter? Unlock', 'pgate.unlock': 'Unlock with Patreon', 'pgate.join_short': 'Become a supporter', 'pgate.confirm': 'Confirm with your passkey…', 'pgate.failed': 'Unlocking failed. Try again.', 'pgate.error': 'Something went wrong. Try again.',
@@ -1961,5 +1961,5 @@
     'admin.b_paid': 'Bezahlte Beiträge', 'admin.b_push': 'Benachrichtigungen', 'admin.back': 'Zurück zur Verwaltung',
     'push.t': 'Benachrichtigungen', 'push.intro': 'Erhalte auf diesem Gerät eine Meldung bei neuen Followern, Antworten und Nachrichten, auch wenn die Seite geschlossen ist. Verschlüsselt bis in deinen Browser; wir senden so wenig Inhalt wie möglich mit.', 'push.unavailable': 'Push ist auf diesem Server nicht verfügbar (Schlüssel konnte nicht erstellt werden oder die Abhängigkeit fehlt).', 'push.unsupported': 'Dieser Browser unterstützt keine Push-Benachrichtigungen.', 'push.ios_hint': 'Auf iPhone/iPad funktioniert das nur, wenn die Seite auf deinem Home-Bildschirm liegt: Teilen-Knopf, dann "Zum Home-Bildschirm", und öffne sie danach von dort.', 'push.this_device': 'Dieses Gerät:', 'push.checking': 'prüfen…', 'push.state_on': 'Benachrichtigungen sind an', 'push.state_off': 'Benachrichtigungen sind aus', 'push.state_denied': 'in den Browser-Einstellungen blockiert', 'push.state_unknown': 'Status unbekannt', 'push.state_unsupported': 'nicht unterstützt', 'push.enable': 'Auf diesem Gerät einschalten', 'push.disable': 'Ausschalten', 'push.test': 'Testmeldung senden', 'push.what': 'Wofür möchtest du eine Meldung?', 'push.a_follow': 'Neuer Follower', 'push.a_reply': 'Antwort oder Erwähnung', 'push.a_like': 'Like (Stern)', 'push.a_boost': 'Boost', 'push.a_dm': 'Private Nachricht', 'push.saved': 'Gespeichert.', 'push.devices': 'Verbundene Geräte', 'push.device': 'Gerät', 'push.since': 'seit', 'push.remove': 'Entfernen', 'push.enable_failed': 'Einschalten fehlgeschlagen',
-    'push.n_follow_t': 'Neuer Follower', 'push.n_follow_b': '{who} folgt dir jetzt', 'push.n_reply_t': 'Antwort auf "{title}"', 'push.n_mention_t': 'Erwähnung', 'push.n_dm_t': 'Private Nachricht', 'push.n_dm_b': 'Neue Nachricht von {who}', 'push.n_like_t': 'Neues Like', 'push.n_like_b': '{who} gefällt "{title}"', 'push.n_boost_t': 'Geboostet', 'push.n_boost_b': '{who} hat "{title}" geboostet', 'msg.guard_offer': 'möchte dein Guardian werden. Besprich das mit deinen Eltern oder Betreuern, bevor du entscheidest.', 'msg.guard_accept': 'Annehmen', 'msg.guard_reject': 'Ablehnen', 'msg.guard_accepted': 'Guardian angenommen. Ihr seid jetzt verbunden.', 'msg.guard_rejected': 'Angebot abgelehnt.', 'msg.guard_failed': 'Das hat nicht geklappt; versuch es erneut.', 'msg.guardians_label': 'Deine Guardians', 'msg.waved_at_you': 'hat dir zugewinkt', 'msg.help_request': 'hat um Hilfe gebeten', 'msg.g_available': 'verfuegbar', 'msg.g_away': 'abwesend bis {date}', 'msg.g_offline': 'offline', 'msg.wave_r1': 'Wie schön!', 'msg.wave_r2': 'Ruf mich an', 'msg.wave_back': '👋 Zurück', 'msg.wave_sent': 'Winken gesendet.', 'msg.reply_sent': 'Antwort gesendet.', 'msg.reply_failed': 'Die Antwort konnte nicht gesendet werden.', 'msg.reply_empty': 'Eine leere Antwort kann nicht gesendet werden.', 'guardian.feed_title': 'Deine Wards', 'guardian.feed_sub': 'Lies mit, was deine Wards posten. Nur schauen.', 'guardian.follow_title': 'Follow-Anfragen', 'guardian.follow_sub': 'Jemand möchte einem deiner Wards folgen. Du entscheidest.', 'guardian.wave': '👋 Winken', 'guardian.waved': '👋 gesendet', 'guardian.app_name': 'Klonkt Guardian', 'guardian.tagline': 'Wards verwalten und Hilferufe auffangen.', 'guardian.acting_as': 'Du handelst als', 'guardian.help_title': 'Hilferufe', 'guardian.help_sub': 'Wenn ein Ward die Rettungsboje nutzt, erscheint es hier.', 'guardian.help_empty': 'Keine Hilferufe. Gut so.', 'guardian.adopt_title': 'Ward adoptieren', 'guardian.adopt_sub': 'Gib das Handle des Kindes ein (@kind@server.eu). Es bekommt ein Angebot in seinem Klonkt zum Annehmen.', 'guardian.adopt_label': 'Ward-Handle', 'guardian.adopt_btn': 'Angebot senden', 'guardian.pending_title': 'Gesendete Angebote', 'guardian.pending_sub': 'Warten, bis der Ward annimmt.', 'guardian.wards_title': 'Meine Wards', 'guardian.play_propose': 'Abspielen vorschlagen', 'guardian.play_on': 'Abspielen: an', 'guardian.play_off': 'Abspielen: aus', 'guardian.gated_title': 'Einstellung vorgeschlagen', 'guardian.gated_line_on': '{who} moechte Link-Vorschauen fuer {ward} EINschalten.', 'guardian.gated_line_off': '{who} moechte Link-Vorschauen fuer {ward} AUSschalten.', 'guardian.gated_agree': 'Einverstanden', 'guardian.gated_disagree': 'Nicht einverstanden', 'guardian.avail_available': 'Verfuegbar', 'guardian.avail_away': 'Abwesend bis {date}', 'guardian.avail_dormant': 'Offline', 'guardian.panel_guards': 'Guardians dieses Kindes', 'guardian.panel_guards_remote': 'Dieses Kind lebt auf einem anderen Server; die Verfuegbarkeit wird dort gefuehrt.', 'guardian.lapse_propose': 'Vorschlag: Freigabe in Abwesenheit', 'guardian.lapse_line': '{who} antwortet nicht mehr als Guardian von {ward}.', 'guardian.lapse_tally': '{n} von {need} einverstanden; schliesst {date}; das Fenster laeuft immer voll.', 'guardian.lapse_note': 'Jedes Lebenszeichen von ihnen bricht dies sofort ab. Nichts hier ist Strafe.', 'guardian.lapse_agree': 'Einverstanden', 'guardian.lapse_disagree': 'Nicht einverstanden', 'guardian.voted': 'Du hast abgestimmt', 'guardian.away_title': 'Kurz abwesend', 'guardian.away_sub': 'Sag deinen Wards, dass du eine Weile nicht da bist. Entscheidungen warten nicht auf dich, und eine einzige Antwort bringt dich sofort zurueck.', 'guardian.away_week': 'Eine Woche', 'guardian.away_month': 'Ein Monat', 'guardian.away_done': 'Deine Wards wissen, dass du bis {date} abwesend bist.', 'guardian.away_msg': 'Ich bin als dein Guardian bis {date} abwesend. Deine anderen Guardians sind fuer dich da.', 'guardian.release_title': '{who} loslassen?', 'guardian.release_effect': 'Du bist dann nicht mehr Guardian. Du siehst ihre Beitraege nicht mehr, erhaeltst keine Hilferufe mehr von ihnen und entscheidest nicht mehr ueber Folgeanfragen fuer sie. Zurueck geht nur mit einem neuen Angebot, das sie annehmen.', 'guardian.release_local': 'Ihr Server und die anderen Guardians werden benachrichtigt, danach stehst du auch dort nicht mehr als Guardian.', 'guardian.release_step_down': 'Sie behalten ihre anderen Guardians und bleiben also Ward.', 'guardian.release_last': 'Du bist ihr letzter Guardian. Das ist Emanzipation, und FEP-633c 3.4 sagt ausdruecklich, dass darueber kein einzelner Guardian entscheidet: dafuer braucht es drei zustimmende Erwachsene oder eine Mehrheit plus zwei Zeugen. Dieser Knopf kann das also nicht: du bleibst ihr Guardian, bis das geregelt ist.', 'guardian.release_unknown': 'Wir konnten ihren Server nicht erreichen und wissen daher nicht, ob du ihr letzter Guardian bist.', 'guardian.release_yes': 'Ja, loslassen', 'guardian.release_no': 'Nein, doch nicht', 'guardian.settings_title': 'Einstellungen', 'guardian.panel_open': 'Ansehen', 'guardian.panel_close': 'Schliessen', 'guardian.panel_help': 'Hilferufe dieses Kindes', 'guardian.panel_help_empty': 'Noch keine Hilferufe.', 'guardian.panel_follow': 'Folgeanfragen', 'guardian.panel_follow_empty': 'Keine offenen Folgeanfragen.', 'guardian.panel_posts': 'Neueste Beitraege', 'guardian.panel_posts_empty': 'Noch nichts zu sehen.', 'guardian.panel_actions': 'Aktionen', 'guardian.badge_help': 'Hilferufe', 'guardian.badge_follow': 'Folgeanfragen', 'guardian.badge_follow_one': 'Folgeanfrage', 'guardian.wards_empty': 'Noch keine Wards. Adoptiere oben eins.', 'guardian.push_title': 'Meldungen', 'guardian.push_sub': 'Erhalte eine Meldung bei einem Hilferuf oder einer Vormundschafts-Antwort, auch bei geschlossener App.', 'guardian.push_on': 'Meldungen einschalten', 'guardian.push_off': 'Meldungen sind an; tippen zum Ausschalten', 'guardian.sent': 'Angebot gesendet. Siehe unten bei Gesendete Angebote.', 'guardian.sent_retry': 'Angebot gespeichert; wir versuchen weiter zuzustellen.', 'guardian.sending': 'Senden…', 'guardian.not_found': 'Dieses Handle konnten wir nicht finden.', 'guardian.failed': 'Fehlgeschlagen', 'guardian.network': 'Netzwerkfehler.', 'guardian.pending': 'wartet auf Antwort', 'guardian.active': 'aktiv', 'guardian.retract': 'Zurückziehen', 'guardian.release': 'Loslassen', 'guardian.embeds_on': 'Linkvorschauen: an', 'guardian.embeds_off': 'Linkvorschauen: aus', 'guardian.embeds_propose': 'Linkvorschauen vorschlagen', 'guardian.embeds_waiting': 'wartet auf die anderen Guardians', 'guardian.prop_line': 'Vorschlag {what} {value}: {status}', 'guardian.prop_embeds': 'Link-Vorschauen', 'guardian.prop_play': 'Abspielen', 'guardian.prop_on': 'an', 'guardian.prop_off': 'aus', 'guardian.prop_st_open': 'wartet auf die anderen Guardians', 'guardian.prop_st_accepted': 'angenommen', 'guardian.prop_st_rejected': 'abgelehnt', 'guardian.prop_st_expired': 'abgelaufen ohne genug Stimmen', 'guardian.panel_guards_far': 'Verfuegbarkeit wird auf ihrem Server gefuehrt.', 'guardian.release_confirm': '{who} loslassen?\n\nDu bist dann nicht mehr Guardian. Du siehst ihre Beitraege nicht mehr, erhaeltst keine Hilferufe mehr von ihnen und entscheidest nicht mehr ueber Follow-Anfragen fuer sie.\n\nZurueck geht nur mit einem neuen Angebot, das sie annehmen.', 'guardian.open': 'öffnen', 'guardian.accept': 'Annehmen', 'guardian.reject': 'Ablehnen', 'guardian.complete': 'Abschließen', 'guardian.awaiting_others': 'wartet auf die anderen Parteien', 'guardian.coguard': 'Mit-Vormundschaftsangebot', 'guardian.push_unavailable': 'Push nicht verfügbar', 'push.n_help_t': 'Hilferuf', 'push.n_help_b': '{who} bittet um deine Hilfe', 'push.n_guard_offer_t': 'Vormundschaftsangebot', 'push.n_guard_offer_b': '{who} möchte dich als Guardian', 'push.n_guard_ward_t': 'Ward akzeptiert', 'push.n_guard_left_t': 'Ein Guardian ist zurueckgetreten', 'push.n_guard_left_b': '{who} ist nicht mehr dein Guardian', 'push.n_guard_cogleft_t': 'Mit-Guardian zurueckgetreten', 'push.n_guard_cogleft_b': '{who} hat die Guardianship beendet', 'push.n_guard_ward_b': '{who} hat dich als Guardian akzeptiert', 'push.n_guard_cog_t': 'Mit-Vormundschaft gefragt', 'push.n_guard_cog_b': 'Ein Guardian-Angebot für {who} braucht dich', 'guardian.panel_history': 'Verlauf ({n})', 'guardian.help_archive': '{n} erledigt', 'guardian.help_archive_hide': 'ausblenden', 'guardian.help_former_ward': 'Nicht mehr dein Ward. Ihre anderen Guardians sind weiterhin fuer sie da.', 'guardian.warn_reversible': 'Was hier durchkommt, kommt nicht zurueck. Du kannst diese Einstellung spaeter wieder schliessen — was dein Kind gesehen hat, nicht.', 'guardian.warn_irreversible': 'Das laesst sich nicht rueckgaengig machen. Danach entscheidet sie selbst, und ihr koennt das nicht zuruecknehmen.', 'guardian.warn_unknown': 'Wir kennen diese Einstellung nicht, wissen also nicht, was durchkommt oder wie weit es reicht. Frag die Person, die es vorgeschlagen hat, bevor du zustimmst.', 'guardian.warn_tally_elsewhere': 'Wir sehen nicht, wie viele Guardians schon geantwortet haben — das zaehlt der Server des Kindes. Dein Ja kann den Ausschlag geben.', 'guardian.warn_go': 'Ja, das vorschlagen', 'guardian.warn_back': 'Nein, doch nicht', 'guardian.help_pick': 'Ich kuemmere mich', 'guardian.help_close': 'Als erledigt markieren', 'guardian.help_picked_by': '{who} kuemmert sich darum', 'guardian.help_handled_by': 'Erledigt von {who}', 'guardian.help_handled_note': 'Das bleibt stehen. Geht es noch weiter, fragt das Kind erneut.', 'guardian.help_close_ask': 'Sicher? Das laesst sich nicht rueckgaengig machen. Geht es noch weiter, bittet das Kind erneut um Hilfe.', 'guardian.help_close_yes': 'Ja, erledigt', 'guardian.help_just_now': 'gerade eben', 'guardian.help_hours': 'vor {n} Std.', 'guardian.help_days': 'vor {n} Tagen', 'guardian.gate_unavailable': 'noch nicht verfuegbar', 'guardian.gate_planned_note': 'Das gibt es auf diesem Server noch nicht.', 'guardian.gates_summary': '{n} Tore - {on} an, {wait} warten', 'guardian.gates_show': 'Tore zeigen', 'guardian.gates_hide': 'Tore ausblenden', 'guardian.gate_images': 'Bilder', 'guardian.gate_messages': 'Nachrichten', 'guardian.gate_compose': 'Selbst posten', 'guardian.gate_music': 'Musik', 'guardian.gate_quoteCards': 'Zitatkarten', 'guardian.gate_customEmoji': 'Eigene Emojis', 'guardian.gate_publicProfile': 'Oeffentlich sichtbar', 'guardian.gate_accountMove': 'Umziehen', 'guardian.gate_independence': 'Selbststaendig werden', 'guardian.gate_externalEmbeds': 'Link-Vorschauen', 'guardian.gate_externalPlayback': 'Abspielen in der App', 'guardian.gate_follows': 'Folgeanfragen', 'guardian.gate_kind_setting': 'Einstellung', 'guardian.gate_kind_perRequest': 'pro Anfrage', 'guardian.gate_kind_handover': 'gibt Zustaendigkeit ab', 'guardian.gate_default_off': 'aus (noch nichts entschieden)', 'guardian.gate_unknown': 'unbekannt', 'guardian.gate_threshold': '{need} von {of} Guardians', 'guardian.gate_threshold_unknown': 'Schwelle unbekannt (andere Domain)', 'guardian.gate_irreversible': 'nicht rueckgaengig', 'guardian.gate_waiting': '{n} wartet auf euch', 'guardian.gate_blocked': 'geht erst, wenn {what} an ist', 'guardian.gate_propose_open': 'Vorschlagen: oeffnen', 'guardian.gate_propose_close': 'Vorschlagen: schliessen', 'guardian.gate_propose': 'Vorschlagen', 'push.n_gate_ask_t': 'Deine Antwort wird gebraucht', 'push.n_gate_ask_b': 'Vorschlag fuer {who}: {wat} {stand}', 'push.n_gate_done_t': 'Entscheidung gefallen', 'push.n_gate_done_b': '{wat} {stand} fuer {who}: {uitkomst}', 'push.n_test_t': 'Klonkt-Testmeldung', 'push.n_test_b': 'Funktioniert. So kommen Meldungen auf diesem Gerät an.',
+    'push.n_follow_t': 'Neuer Follower', 'push.n_follow_b': '{who} folgt dir jetzt', 'push.n_reply_t': 'Antwort auf "{title}"', 'push.n_mention_t': 'Erwähnung', 'push.n_dm_t': 'Private Nachricht', 'push.n_dm_b': 'Neue Nachricht von {who}', 'push.n_like_t': 'Neues Like', 'push.n_like_b': '{who} gefällt "{title}"', 'push.n_boost_t': 'Geboostet', 'push.n_boost_b': '{who} hat "{title}" geboostet', 'msg.guard_offer': 'möchte dein Guardian werden. Besprich das mit deinen Eltern oder Betreuern, bevor du entscheidest.', 'msg.guard_accept': 'Annehmen', 'msg.guard_reject': 'Ablehnen', 'msg.guard_accepted': 'Guardian angenommen. Ihr seid jetzt verbunden.', 'msg.guard_rejected': 'Angebot abgelehnt.', 'msg.guard_failed': 'Das hat nicht geklappt; versuch es erneut.', 'msg.guardians_label': 'Deine Guardians', 'msg.waved_at_you': 'hat dir zugewinkt', 'msg.help_request': 'hat um Hilfe gebeten', 'msg.g_available': 'verfuegbar', 'msg.g_away': 'abwesend bis {date}', 'msg.g_offline': 'offline', 'msg.wave_r1': 'Wie schön!', 'msg.wave_r2': 'Ruf mich an', 'msg.wave_back': '👋 Zurück', 'msg.wave_sent': 'Winken gesendet.', 'msg.reply_sent': 'Antwort gesendet.', 'msg.reply_failed': 'Die Antwort konnte nicht gesendet werden.', 'msg.reply_empty': 'Eine leere Antwort kann nicht gesendet werden.', 'guardian.feed_title': 'Deine Wards', 'guardian.feed_sub': 'Lies mit, was deine Wards posten. Nur schauen.', 'guardian.follow_title': 'Follow-Anfragen', 'guardian.follow_sub': 'Jemand möchte einem deiner Wards folgen. Du entscheidest.', 'guardian.wave': '👋 Winken', 'guardian.waved': '👋 gesendet', 'guardian.app_name': 'Klonkt Guardian', 'guardian.tagline': 'Wards verwalten und Hilferufe auffangen.', 'guardian.acting_as': 'Du handelst als', 'guardian.help_title': 'Hilferufe', 'guardian.help_sub': 'Wenn ein Ward die Rettungsboje nutzt, erscheint es hier.', 'guardian.help_empty': 'Keine Hilferufe. Gut so.', 'guardian.adopt_title': 'Ward adoptieren', 'guardian.adopt_sub': 'Gib das Handle des Kindes ein (@kind@server.eu). Es bekommt ein Angebot in seinem Klonkt zum Annehmen.', 'guardian.adopt_label': 'Ward-Handle', 'guardian.adopt_btn': 'Angebot senden', 'guardian.pending_title': 'Gesendete Angebote', 'guardian.pending_sub': 'Warten, bis der Ward annimmt.', 'guardian.wards_title': 'Meine Wards', 'guardian.play_propose': 'Abspielen vorschlagen', 'guardian.play_on': 'Abspielen: an', 'guardian.play_off': 'Abspielen: aus', 'guardian.gated_title': 'Einstellung vorgeschlagen', 'guardian.gated_line_on': '{who} moechte Link-Vorschauen fuer {ward} EINschalten.', 'guardian.gated_line_off': '{who} moechte Link-Vorschauen fuer {ward} AUSschalten.', 'guardian.gated_agree': 'Einverstanden', 'guardian.gated_disagree': 'Nicht einverstanden', 'guardian.avail_available': 'Verfuegbar', 'guardian.avail_away': 'Abwesend bis {date}', 'guardian.avail_dormant': 'Offline', 'guardian.panel_guards': 'Guardians dieses Kindes', 'guardian.panel_guards_remote': 'Dieses Kind lebt auf einem anderen Server; die Verfuegbarkeit wird dort gefuehrt.', 'guardian.lapse_propose': 'Vorschlag: Freigabe in Abwesenheit', 'guardian.lapse_line': '{who} antwortet nicht mehr als Guardian von {ward}.', 'guardian.lapse_tally': '{n} von {need} einverstanden; schliesst {date}; das Fenster laeuft immer voll.', 'guardian.lapse_note': 'Jedes Lebenszeichen von ihnen bricht dies sofort ab. Nichts hier ist Strafe.', 'guardian.lapse_agree': 'Einverstanden', 'guardian.lapse_disagree': 'Nicht einverstanden', 'guardian.voted': 'Du hast abgestimmt', 'guardian.away_title': 'Kurz abwesend', 'guardian.away_sub': 'Sag deinen Wards, dass du eine Weile nicht da bist. Entscheidungen warten nicht auf dich, und eine einzige Antwort bringt dich sofort zurueck.', 'guardian.away_week': 'Eine Woche', 'guardian.away_month': 'Ein Monat', 'guardian.away_done': 'Deine Wards wissen, dass du bis {date} abwesend bist.', 'guardian.away_msg': 'Ich bin als dein Guardian bis {date} abwesend. Deine anderen Guardians sind fuer dich da.', 'guardian.release_title': '{who} loslassen?', 'guardian.release_effect': 'Du bist dann nicht mehr Guardian. Du siehst ihre Beitraege nicht mehr, erhaeltst keine Hilferufe mehr von ihnen und entscheidest nicht mehr ueber Folgeanfragen fuer sie. Zurueck geht nur mit einem neuen Angebot, das sie annehmen.', 'guardian.release_local': 'Ihr Server und die anderen Guardians werden benachrichtigt, danach stehst du auch dort nicht mehr als Guardian.', 'guardian.release_step_down': 'Sie behalten ihre anderen Guardians und bleiben also Ward.', 'guardian.release_last': 'Du bist ihr letzter Guardian. Das ist Emanzipation, und FEP-633c 3.4 sagt ausdruecklich, dass darueber kein einzelner Guardian entscheidet: dafuer braucht es drei zustimmende Erwachsene oder eine Mehrheit plus zwei Zeugen. Dieser Knopf kann das also nicht: du bleibst ihr Guardian, bis das geregelt ist.', 'guardian.release_unknown': 'Wir konnten ihren Server nicht erreichen und wissen daher nicht, ob du ihr letzter Guardian bist.', 'guardian.release_yes': 'Ja, loslassen', 'guardian.release_no': 'Nein, doch nicht', 'guardian.settings_title': 'Einstellungen', 'guardian.panel_open': 'Ansehen', 'guardian.panel_close': 'Schliessen', 'guardian.panel_help': 'Hilferufe dieses Kindes', 'guardian.panel_help_empty': 'Noch keine Hilferufe.', 'guardian.panel_follow': 'Folgeanfragen', 'guardian.panel_follow_empty': 'Keine offenen Folgeanfragen.', 'guardian.panel_posts': 'Neueste Beitraege', 'guardian.panel_posts_empty': 'Noch nichts zu sehen.', 'guardian.panel_actions': 'Aktionen', 'guardian.badge_help': 'Hilferufe', 'guardian.badge_follow': 'Folgeanfragen', 'guardian.badge_follow_one': 'Folgeanfrage', 'guardian.wards_empty': 'Noch keine Wards. Adoptiere oben eins.', 'guardian.push_title': 'Meldungen', 'guardian.push_sub': 'Erhalte eine Meldung bei einem Hilferuf oder einer Vormundschafts-Antwort, auch bei geschlossener App.', 'guardian.push_on': 'Meldungen einschalten', 'guardian.push_off': 'Meldungen sind an; tippen zum Ausschalten', 'guardian.sent': 'Angebot gesendet. Siehe unten bei Gesendete Angebote.', 'guardian.sent_retry': 'Angebot gespeichert; wir versuchen weiter zuzustellen.', 'guardian.sending': 'Senden…', 'guardian.not_found': 'Dieses Handle konnten wir nicht finden.', 'guardian.failed': 'Fehlgeschlagen', 'guardian.network': 'Netzwerkfehler.', 'guardian.pending': 'wartet auf Antwort', 'guardian.active': 'aktiv', 'guardian.retract': 'Zurückziehen', 'guardian.release': 'Loslassen', 'guardian.embeds_on': 'Linkvorschauen: an', 'guardian.embeds_off': 'Linkvorschauen: aus', 'guardian.embeds_propose': 'Linkvorschauen vorschlagen', 'guardian.embeds_waiting': 'wartet auf die anderen Guardians', 'guardian.prop_line': 'Vorschlag {what} {value}: {status}', 'guardian.prop_embeds': 'Link-Vorschauen', 'guardian.prop_play': 'Abspielen', 'guardian.prop_on': 'an', 'guardian.prop_off': 'aus', 'guardian.prop_st_open': 'wartet auf die anderen Guardians', 'guardian.prop_st_accepted': 'angenommen', 'guardian.prop_st_rejected': 'abgelehnt', 'guardian.prop_st_expired': 'abgelaufen ohne genug Stimmen', 'guardian.panel_guards_far': 'Verfuegbarkeit wird auf ihrem Server gefuehrt.', 'guardian.release_confirm': '{who} loslassen?\n\nDu bist dann nicht mehr Guardian. Du siehst ihre Beitraege nicht mehr, erhaeltst keine Hilferufe mehr von ihnen und entscheidest nicht mehr ueber Follow-Anfragen fuer sie.\n\nZurueck geht nur mit einem neuen Angebot, das sie annehmen.', 'guardian.open': 'öffnen', 'guardian.accept': 'Annehmen', 'guardian.reject': 'Ablehnen', 'guardian.complete': 'Abschließen', 'guardian.awaiting_others': 'wartet auf die anderen Parteien', 'guardian.coguard': 'Mit-Vormundschaftsangebot', 'guardian.push_unavailable': 'Push nicht verfügbar', 'push.n_help_t': 'Hilferuf', 'push.n_help_b': '{who} bittet um deine Hilfe', 'push.n_guard_offer_t': 'Vormundschaftsangebot', 'push.n_guard_offer_b': '{who} möchte dich als Guardian', 'push.n_guard_ward_t': 'Ward akzeptiert', 'push.n_guard_left_t': 'Ein Guardian ist zurueckgetreten', 'push.n_guard_left_b': '{who} ist nicht mehr dein Guardian', 'push.n_guard_cogleft_t': 'Mit-Guardian zurueckgetreten', 'push.n_guard_cogleft_b': '{who} hat die Guardianship beendet', 'push.n_guard_ward_b': '{who} hat dich als Guardian akzeptiert', 'push.n_guard_cog_t': 'Mit-Vormundschaft gefragt', 'push.n_guard_cog_b': 'Ein Guardian-Angebot für {who} braucht dich', 'guardian.panel_history': 'Verlauf ({n})', 'guardian.help_archive': '{n} erledigt', 'guardian.help_archive_hide': 'ausblenden', 'guardian.help_former_ward': 'Nicht mehr dein Ward. Ihre anderen Guardians sind weiterhin fuer sie da.', 'guardian.warn_reversible': 'Was hier durchkommt, kommt nicht zurueck. Du kannst diese Einstellung spaeter wieder schliessen — was dein Kind gesehen hat, nicht.', 'guardian.warn_irreversible': 'Das laesst sich nicht rueckgaengig machen. Danach entscheidet sie selbst, und ihr koennt das nicht zuruecknehmen.', 'guardian.warn_unknown': 'Wir kennen diese Einstellung nicht, wissen also nicht, was durchkommt oder wie weit es reicht. Frag die Person, die es vorgeschlagen hat, bevor du zustimmst.', 'guardian.warn_tally_elsewhere': 'Wir sehen nicht, wie viele Guardians schon geantwortet haben — das zaehlt der Server des Kindes. Dein Ja kann den Ausschlag geben.', 'guardian.warn_go': 'Ja, das vorschlagen', 'guardian.warn_back': 'Nein, doch nicht', 'guardian.help_pick': 'Ich kuemmere mich', 'guardian.help_close': 'Als erledigt markieren', 'guardian.help_picked_by': '{who} kuemmert sich darum', 'guardian.help_handled_by': 'Erledigt von {who}', 'guardian.help_handled_note': 'Das bleibt stehen. Geht es noch weiter, fragt das Kind erneut.', 'guardian.help_close_ask': 'Sicher? Das laesst sich nicht rueckgaengig machen. Geht es noch weiter, bittet das Kind erneut um Hilfe.', 'guardian.help_close_yes': 'Ja, erledigt', 'guardian.help_just_now': 'gerade eben', 'guardian.help_hours': 'vor {n} Std.', 'guardian.help_days': 'vor {n} Tagen', 'guardian.gate_unavailable': 'noch nicht verfuegbar', 'guardian.gate_planned_note': 'Das gibt es auf diesem Server noch nicht.', 'guardian.gates_summary': '{n} Tore - {on} an, {wait} warten', 'guardian.gates_show': 'Tore zeigen', 'guardian.gates_hide': 'Tore ausblenden', 'guardian.gate_images': 'Bilder', 'guardian.gate_messages': 'Nachrichten', 'guardian.gate_compose': 'Selbst posten', 'guardian.gate_music': 'Musik', 'guardian.gate_quoteCards': 'Zitatkarten', 'guardian.gate_customEmoji': 'Eigene Emojis', 'guardian.gate_publicProfile': 'Oeffentlich sichtbar', 'guardian.gate_accountMove': 'Umziehen', 'guardian.gate_independence': 'Selbststaendig werden', 'guardian.gate_externalThreads': 'Antworten von Fremden', 'guardian.gate_externalEmbeds': 'Link-Vorschauen', 'guardian.gate_externalPlayback': 'Abspielen in der App', 'guardian.gate_follows': 'Folgeanfragen', 'guardian.gate_kind_setting': 'Einstellung', 'guardian.gate_kind_perRequest': 'pro Anfrage', 'guardian.gate_kind_handover': 'gibt Zustaendigkeit ab', 'guardian.gate_default_off': 'aus (noch nichts entschieden)', 'guardian.gate_unknown': 'unbekannt', 'guardian.gate_threshold': '{need} von {of} Guardians', 'guardian.gate_threshold_unknown': 'Schwelle unbekannt (andere Domain)', 'guardian.gate_irreversible': 'nicht rueckgaengig', 'guardian.gate_waiting': '{n} wartet auf euch', 'guardian.gate_blocked': 'geht erst, wenn {what} an ist', 'guardian.gate_propose_open': 'Vorschlagen: oeffnen', 'guardian.gate_propose_close': 'Vorschlagen: schliessen', 'guardian.gate_propose': 'Vorschlagen', 'push.n_gate_ask_t': 'Deine Antwort wird gebraucht', 'push.n_gate_ask_b': 'Vorschlag fuer {who}: {wat} {stand}', 'push.n_gate_done_t': 'Entscheidung gefallen', 'push.n_gate_done_b': '{wat} {stand} fuer {who}: {uitkomst}', 'push.n_test_t': 'Klonkt-Testmeldung', 'push.n_test_b': 'Funktioniert. So kommen Meldungen auf diesem Gerät an.',
     'apaid.t': 'Bezahlte Beiträge', 'apaid.intro': 'Verbinde deine eigene Patreon-Kampagne. Unterstützer entsperren bezahlte Beiträge mit einem Passkey, ohne Konto und ohne Cookie. Wir speichern keine Namen oder E-Mail-Adressen von Unterstützern, nur das verschlüsselte Token deiner Kampagne.', 'apaid.saved': 'Gespeichert.', 'apaid.nokey': 'Achtung: der Verschlüsselungsschlüssel konnte nicht erstellt oder gelesen werden (Schreibrechte auf dem Speicherordner?). Ohne Schlüssel können Secrets nicht sicher gespeichert werden.', 'apaid.status': 'Status:', 'apaid.connected': 'verbunden', 'apaid.campaign': 'Kampagne', 'apaid.configured': 'eingerichtet, noch nicht verbunden (Token eintragen)', 'apaid.notyet': 'noch nicht eingerichtet', 'apaid.redirect_h': 'Trage diese Redirect-URI in deinen Patreon-Client ein', 'apaid.redirect_p': 'In deinem Patreon-API-Client muss unter Redirect URIs genau diese Zeile stehen. Stimmt sie nicht, zeigt Patreon eine Fehlermeldung statt deine Unterstützer zurückzuschicken.', 'apaid.copy': 'Kopieren', 'apaid.copied': 'Kopiert', 'apaid.client_id': 'Patreon Client-ID', 'apaid.client_secret': 'Patreon Client-Secret', 'apaid.keep': 'Leer lassen = aktuellen Wert behalten.', 'apaid.campaign_id': 'Kampagnen-ID', 'apaid.public_page': 'Öffentliche Patreon-Seite', 'apaid.public_help': 'Der Link, unter dem Besucher Unterstützer werden können. Wird als "Unterstützer werden" gezeigt, wenn jemand noch nicht spendet.', 'apaid.access': 'Creator Access-Token', 'apaid.refresh': 'Creator Refresh-Token', 'apaid.token_help': 'Access- und Refresh-Token bekommst du auf deiner Patreon-API-Client-Seite. Wir verschlüsseln sie und erneuern automatisch.', 'apaid.min_eur': 'Standard-Unterstützungsbetrag für einen bezahlten Beitrag (Euro)', 'apaid.save': 'Speichern', 'apaid.disconnect': 'Verbindung entfernen', 'apaid.disconnect_confirm': 'Patreon-Verbindung entfernen?', 'apaid.unchanged': 'bleibt unverändert',
     'pgate.h': 'Für Unterstützer', 'pgate.sub': 'Dieser Beitrag ist für Unterstützer dieser Seite. Werde Unterstützer und entsperre ihn danach mit einem Passkey. Kein Konto auf dieser Seite, kein Cookie.', 'pgate.sub_cents': 'Dieser Beitrag ist für Unterstützer dieser Seite (ab €{eur} pro Monat auf Patreon). Werde Unterstützer und entsperre ihn danach mit einem Passkey. Kein Konto auf dieser Seite, kein Cookie.', 'pgate.join': 'Unterstützer werden auf Patreon', 'pgate.unlock_have': 'Schon Unterstützer? Entsperren', 'pgate.unlock': 'Mit Patreon entsperren', 'pgate.join_short': 'Unterstützer werden', 'pgate.confirm': 'Bestätige mit deinem Passkey…', 'pgate.failed': 'Entsperren fehlgeschlagen. Versuch es erneut.', 'pgate.error': 'Etwas ist schiefgegangen. Versuch es erneut.',
Index: test/gates-family.test.js
===================================================================
--- test/gates-family.test.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
+++ test/gates-family.test.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
@@ -0,0 +1,105 @@
+// De gate-familie functioneel (shaer-ahy.1, Barts opdracht 8-8): niet alleen
+// een toets in het paneel, maar een poort die echt dichtkan -- bij de
+// AFLEVERING (wat dicht is wordt nooit geserialiseerd) of bij de INNAME (wat
+// de ward niet mag versturen wordt aan de outbox geweigerd).
+//
+// De twee dingen die hier stil kunnen breken: een poort die dicht lijkt maar
+// niets tegenhoudt (een guardian waant het kind beschermd), en een poort die
+// het hulpkanaal mee afsluit (de boei MOET door elke dichte deur heen).
+//
+// In-memory SQLite. Run: npm test
+import { test } from 'node:test';
+import assert from 'node:assert/strict';
+
+process.env.DATABASE_PATH = ':memory:';
+process.env.PUBLIC_BASE_URL = 'https://klonkt.test';
+
+const dbMod = await import('../src/config/database.js');
+const db = dbMod.default;
+dbMod.initializeDatabase();
+const AP = await import('../src/services/ActivityPubService.js');
+const Guardianship = await import('../src/services/guardianship/index.js');
+
+db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)')
+  .run('u1', 'u1', 'u1@test', 'x', 'god');
+db.prepare('INSERT INTO sites (id, slug, title, owner_id) VALUES (?,?,?,?)').run('s1', 'kind', 'Kind', 'u1');
+const site = () => db.prepare('SELECT * FROM sites WHERE id = ?').get('s1');
+const user = { id: 'u1', username: 'u1' };
+
+test('elke beschikbare gate in de catalogus heeft een kolom', () => {
+  // De bewaker van de bedrading: een catalogusrij zonder kolom is een toets
+  // die nergens op aangesloten is, en dat merkt pas iemand die erop drukt.
+  for (const g of Guardianship.gated.GATE_CATALOGUE.filter((x) => x.available !== false)) {
+    if (g.fixed) continue;   // shaer:follows is een stroom, geen stand
+    assert.ok(Guardianship.gated.featureColumn(g.feature), `${g.feature} mist een kolom`);
+  }
+});
+
+test('de generieke regel: expliciet wint, de automatiek sluit voor een ward', () => {
+  assert.equal(Guardianship.wardGateAllowed(null, false), true);
+  assert.equal(Guardianship.wardGateAllowed(null, true), false);
+  assert.equal(Guardianship.wardGateAllowed(1, true), true);    // guardians openden hem
+  assert.equal(Guardianship.wardGateAllowed(0, false), false);  // expliciete 0 wint ook zonder wardstatus
+});
+
+test('gateAttachments: beeld en muziek dicht laten de rest staan, leeg wordt undefined', () => {
+  const atts = [
+    { type: 'Document', mediaType: 'image/webp', url: 'https://x/p.webp' },
+    { type: 'Audio', mediaType: 'audio/mpeg', url: 'https://x/a.mp3' },
+    { type: 'Document', mediaType: 'video/mp4', url: 'https://x/v.mp4' },
+  ];
+  const zonderBeeld = AP.gateAttachments(atts, { images: false });
+  assert.deepEqual(zonderBeeld.map((a) => a.mediaType), ['audio/mpeg', 'video/mp4']);
+  const zonderMuziek = AP.gateAttachments(atts, { audio: false });
+  assert.deepEqual(zonderMuziek.map((a) => a.mediaType), ['image/webp', 'video/mp4']);
+  // Alles weg is undefined, zoals de serialisatie een leeg veld overal weglaat.
+  assert.equal(AP.gateAttachments([atts[0]], { images: false }), undefined);
+  // En de poort open verandert niets.
+  assert.equal(AP.gateAttachments(atts, {}).length, 3);
+});
+
+test('stripEmojiTags haalt alleen de Emoji-tags weg', () => {
+  const tags = [
+    { type: 'Emoji', name: ':hartje:', icon: { url: 'https://x/h.png' } },
+    { type: 'Mention', href: 'https://x/u', name: '@u' },
+    { type: 'Hashtag', name: '#muziek' },
+  ];
+  const uit = AP.stripEmojiTags(tags);
+  assert.deepEqual(uit.map((t) => t.type), ['Mention', 'Hashtag']);
+  assert.equal(AP.stripEmojiTags([tags[0]]), undefined);
+});
+
+test('compose dicht weigert een eigen post aan de outbox, maar geen antwoord', async () => {
+  db.prepare("UPDATE sites SET gate_compose = 0 WHERE slug = 'kind'").run();
+  const post = { type: 'Create', object: { type: 'Note', content: '<p>hoi</p>', to: ['https://www.w3.org/ns/activitystreams#Public'] } };
+  const uit = await AP.ingestOutboxActivity(site(), user, post);
+  assert.equal(uit.status, 403);
+  assert.equal(uit.error, 'gated_compose');
+  // Een antwoord is meedoen aan een gesprek, geen eigen podium: dat valt
+  // onder messages/het gesprek, niet onder compose.
+  const reply = { type: 'Create', object: { type: 'Note', content: '<p>ja!</p>', inReplyTo: 'https://elders/x', to: ['https://www.w3.org/ns/activitystreams#Public'] } };
+  const uit2 = await AP.ingestOutboxActivity(site(), user, reply);
+  assert.notEqual(uit2.error, 'gated_compose');
+  db.prepare("UPDATE sites SET gate_compose = NULL WHERE slug = 'kind'").run();
+});
+
+test('messages dicht weigert een direct bericht, maar NOOIT de reddingsboei', async () => {
+  db.prepare("UPDATE sites SET gate_messages = 0 WHERE slug = 'kind'").run();
+  const dm = { type: 'Create', object: { type: 'Note', content: '<p>psst</p>', to: ['https://elders/ap/users/vreemde'] } };
+  const uit = await AP.ingestOutboxActivity(site(), user, dm);
+  assert.equal(uit.status, 403);
+  assert.equal(uit.error, 'gated_messages');
+  // De boei gaat door elke dichte deur heen: een poort die het hulpkanaal
+  // afsnijdt beschermt niemand.
+  const hulp = { type: 'Create', object: { type: 'Note', content: '<p>🛟</p>', 'shaer:helpRequest': true, to: ['https://elders/ap/users/oma'] } };
+  const uit2 = await AP.ingestOutboxActivity(site(), user, hulp);
+  assert.notEqual(uit2.error, 'gated_messages');
+  db.prepare("UPDATE sites SET gate_messages = NULL WHERE slug = 'kind'").run();
+});
+
+test('accountMove dicht weigert de verhuizing voordat er iets vertrekt', async () => {
+  db.prepare("UPDATE sites SET gate_account_move = 0 WHERE slug = 'kind'").run();
+  const uit = await AP.moveAccount(site(), '@iemand@elders.example');
+  assert.equal(uit.error, 'guarded_account');
+  db.prepare("UPDATE sites SET gate_account_move = NULL WHERE slug = 'kind'").run();
+});
Index: test/thread.test.js
===================================================================
--- test/thread.test.js	(revision 50e80acd22affc07719af0f0ac1a35bbb6b23819)
+++ test/thread.test.js	(revision 3b43e4c42e059a39a2ea3ecd827e68d6c1d8a4e6)
@@ -65,5 +65,5 @@
 
 test('een gewone lezer krijgt alles behalve de geblokkeerde, oudste eerst, geschoond', async () => {
-  const uit = await AP.getThread('kind', BRON, { isWard: false });
+  const uit = await AP.getThread('kind', BRON);
   assert.equal(uit.found, true);
   assert.equal(uit.notes.length, 2);
@@ -74,6 +74,7 @@
   assert.ok(!uit.notes[1].content.includes('<script'), 'script weggeschoond');
   assert.ok(uit.notes[1].content.includes('Hoi!'));
-  // Een blokkade is onzichtbaar: niet in de lijst en NIET in de telling.
-  assert.equal(uit.hidden, 0);
+  // Een blokkade is onzichtbaar: niet in de lijst en NIET in een telling --
+  // getThread telt sindsdien niets meer, dat doet de kringfilter in de route.
+  assert.equal(uit.hidden, undefined);
   assert.ok(uit.notes.every((n) => n.attributedTo !== GEBLOKT));
   // FEP-9098: alleen de echte emoji komt door -- niet de hashtag, niet de
@@ -86,19 +87,20 @@
 });
 
-test('een ward ziet alleen de kring van de guardians, de rest wordt geteld', async () => {
-  // Eigen cache-sleutel per (slug, uri) zou hier de vorige uitkomst hergeven;
-  // een andere slug dwingt een verse opbouw af zonder aan de cache te morrelen.
+test('de kringfilter houdt goedgekeurd volk en telt de rest (de dichte stand van de gate)', async () => {
+  // Sinds de gate (shaer-9y2) zit de kring in de ROUTE, per verzoek en buiten
+  // de threadcache om -- een poort die net dichtging mag niet twee minuten
+  // open nawerken. Hier de functie zelf.
   db.prepare("INSERT INTO sites (id, slug, title, owner_id) VALUES ('s2', 'pupil', 'Pupil', 'u1')").run();
   db.prepare("INSERT INTO ap_following (slug, actor_uri, status) VALUES ('pupil', ?, 'accepted')").run(TANTE);
-  db.prepare("INSERT INTO ap_blocks (slug, kind, target) VALUES ('pupil', 'actor', ?)").run(GEBLOKT);
-  const uit = await AP.getThread('pupil', BRON, { isWard: true });
-  assert.equal(uit.notes.length, 1);
-  assert.equal(uit.notes[0]['shaer:author'].name, 'tante');
+  const uit = await AP.getThread('kind', BRON);
+  const kring = AP.filterThreadToCircle('pupil', uit.notes);
+  assert.equal(kring.notes.length, 1);
+  assert.equal(kring.notes[0]['shaer:author'].name, 'tante');
   // De vreemde is er, en dat mag gezegd: geteld, niet stil weggelaten.
-  assert.equal(uit.hidden, 1);
+  assert.equal(kring.hidden, 1);
 });
 
 test('een onbereikbare note zegt dat, in plaats van een lege thread te veinzen', async () => {
-  const uit = await AP.getThread('kind', 'https://203.0.113.99/weg', { isWard: false });
+  const uit = await AP.getThread('kind', 'https://203.0.113.99/weg');
   assert.equal(uit.found, false);
   assert.equal(uit.notes.length, 0);
@@ -126,5 +128,5 @@
     return vorige(url);
   };
-  const uit = await AP.getThread('kind', MPOST, { isWard: false });
+  const uit = await AP.getThread('kind', MPOST);
   globalThis.fetch = vorige;
   assert.equal(uit.notes.length, 1, 'het antwoord op de next-pagina is gevonden');
@@ -136,5 +138,5 @@
   const vorige = globalThis.fetch;
   globalThis.fetch = async (...a) => { calls += 1; return vorige(...a); };
-  const uit = await AP.getThread('kind', BRON, { isWard: false });
+  const uit = await AP.getThread('kind', BRON);
   assert.equal(uit.notes.length, 2);
   assert.equal(calls, 0, 'alles uit de cache, nul fetches');
