Public preference center and double opt-in

Recipients can manage their own subscription state via two public, no-login pages: a preference center for frequency and topic opt-out, and a double opt-in confirmation flow for new subscribers.

Preference center:
Every campaign footer includes both an "Unsubscribe" link and an "Update preferences" link. Clicking preferences opens /email/preferences?t=<token> with:
• Master subscribe toggle (on / off — equivalent to unsubscribe)
• Frequency radio:
◦ all — receive everything
◦ weekly-digest — only receive a weekly summary, not individual sends
◦ transactional-only — only critical/transactional sends, no marketing
• Per-tag opt-outs — checkboxes for each distribution tag (e.g. "newsletters", "events", "promotions")

What enforces preferences:
• At send time, recipient resolution applies the contact's preference filters
• Tag-based opt-outs remove the contact from any campaign whose target includes that tag
• "transactional-only" recipients receive only campaigns flagged as transactional in the composer
• "weekly-digest" recipients are pulled out of regular sends and into a separate weekly digest queue

Double opt-in (subscribe confirmation):
For form-based signups (Builder website forms or API enroll), you can require a confirmation click before the contact is fully subscribed.

Flow:
1. Visitor submits a form ("Sign up for our newsletter")
2. Contact is created in Firestore with status "pending_confirmation" — no campaigns will be sent
3. A confirmation email goes out with a signed token link ("Confirm your email")
4. Visitor clicks → /email/confirm?t=<token> → status flips to "subscribed"
5. Contact is now eligible for campaigns

Why double opt-in:
• Required by GDPR for EU recipients
• Reduces bounce rate (typo emails never confirm)
• Improves sender reputation — only verified recipients get sends
• Some industries (legal, financial) require it for compliance

To enable double opt-in for a form:
Builder → Sites → your site → form block → "Require email confirmation" toggle.

Tokens:
The preference center token is a separate "pref" kind from "unsub" or "trk" — different signing scope, different expiry. All tokens are HMAC-signed against UNSUBSCRIBE_SIGNING_KEY with 60-day expiry.