## Why

The metering slice (credits) blocks alerts when exhausted, and paid-gating blocks on lapsed orders — but the owner is never *told why* or what to do. The 2014 system had a `late_payment` flow ("your payments are suspended"); this change restores that: an **unlock notification** to the owner when a scan is gated, plus **renewal tracking** (a renews date with lazy expiry) so lapsed status is computed, not manually maintained.

## What Changes

- **`orders.renews_at`** (idempotent): admin sets the next renewal date. Gating treats a `paid` order with `renews_at` in the past as lapsed (lazy expiry — no background job needed).
- **Unlock notification**: when a scan is blocked because the order is lapsed **or** credits are exhausted, the owner receives a notice: *"Your Where Woof tag was scanned — your plan is lapsed / out of SMS credits. Renew to see the finder's details."* with the tag link.
- **Notify channel abstraction** (`internal/notify`): **ntfy** (self-hosted on .13 — free) by default, **SMS** optional via env (`NOTIFY_CHANNEL=ntfy|sms|both`). Email is a documented future channel (SMTP infra absent). Unlock notices are exempt from SMS metering (they're system notices).
- **Admin**: OrderResource gains `renews_at`; a lapsed badge on orders past renewal.

## Capabilities

### New Capabilities

- `renewal-unlock`: renewal date + lazy expiry + owner unlock notification when gated.

### Modified Capabilities

- `sms-alerting`: ADDED — gated scans notify the owner with the reason + renewal call-to-action.
- `database`: ADDED — `orders.renews_at`.

## Impact

- **Go**: `internal/notify` (ntfy + sms channels), scan.go gating calls notify on lapsed/credit blocks, orders query for renews_at, template/message builder.
- **Schema**: idempotent ALTER; `make db-up`.
- **Admin**: OrderResource renews_at + lapsed indicator.
- Config: `NOTIFY_CHANNEL` env (default ntfy), `NTFY_TOPIC` env.
