{@html homeIcon}
{#if !data.authenticated} {:else}
{data.totalFams} Families
{data.totalMembers} Members
{data.totalChores} Chores completed
{data.subCount} Active subs
{data.gatedCount} Paused / gated
{data.codeCount} Active codes

Global feature flags (public read-only for fams; toggled here).

debug
rewardsTargets Multi-target reward rules (Competition / Collaboration)
{#if form?.error}

{form.error}

{/if}
Duration 0 = continuous. Trial days > 0 makes it a Stripe trial code instead of platform access.
{#each data.codes as c} {:else} {/each}
Code Name Type Status Used by Actions
{#if copied === c.value}copied!{/if} {c.name} {#if c.trialDays} {c.trialDays}-day trial {:else if c.duration} {c.duration} mo {:else} continuous {/if} {c.active ? 'active' : 'disabled'} {#if c.usedBy.length} {c.usedBy.length} fam{c.usedBy.length > 1 ? 's' : ''} {:else} — {/if}
{#if !c.usedBy.length}
{/if}
No codes yet — issue one above.
{#each data.fams as fam} {/each}
Name Parent Members Plan Claims Actions
{fam.name} /{fam.slug} {fam.parentEmail || '—'} {fam.memberCount} {modeLabel[fam.paymentMode] || fam.paymentMode}{fam.active ? '' : ' · paused'} {#if fam.requestedRewards > 0} {fam.requestedRewards} pending {:else} None {/if} View {@html chevronRightIcon}
{#each data.choreTemplates || [] as t}
{t.name}
{t.defaultFrequency} {t.defaultType}
{ return async ({ update }) => { update(); }; }} >
{/each} {#if (data.choreTemplates || []).length === 0}

No chore templates yet.

{/if}
{#each data.bonusTemplates || [] as t}
{t.name}
{t.type} {t.rewardType} {#if t.isPocketMoney}Pocket Money{/if}
{ return async ({ update }) => { update(); }; }} >
{/each} {#if (data.bonusTemplates || []).length === 0}

No reward templates yet.

{/if}
{#if showTplModal}
(showTplModal = false)} role="presentation">
{/if} {/if}