Design preview · Retreat Booking (TMPL-RTBK01) · beta · 2026-08-06
← Design HQ · HTML on GitHub ↗ · PRD ↗

Retreat Booking — every screen through the flow

Retreat Booking — Discover, set it up, go live, then the guest thread.

SizePortrait scrolls 375 · sideways is a slide deckNotes
Design brief — overview · scope · journey (closed)

The launch-wedge assistant's standing design contract — drawn FROM the shipped beta flow plus prd-as-retreat-booking.md, for Peyton sign-off. Companion to the template-agnostic master assistant-flows/assistant-lifecycle.html — this file inherits it and must not contradict it. Full framing in 1 · Design overview and 2 · Scope below.

8-section shape · card → live → monitored · desktop + mobile relay payment model — MystFlo never touches the money amber = action/pending · emerald = live/paid only

Widths here sample a fluid continuum — content scales continuously; structure steps only at sm 640 · md 768 · lg 1024. Kit: design-canon.md U8. Reading order (kit-locked 2026-07-31): § Desktop screens first, then § Mobile screens — 375, then the 768 tablet sample. 375 is still designed and scored FIRST in real work.

Every $ figure drawn here ($1.75/run, deposit and balance amounts) is illustrative — prices arrive from props/the DB at runtime, never authored literals (single-source pricing). Demo persona: Salt & Stone Retreats (host Lena), consistent with the on-brand-support.html exemplar. Program: Bali Spring Retreat · Apr 12–19 · 12 spots · 30% deposit.

1 · Design overview what this is, in plain language

Retreat Booking takes the payment chase off a retreat host's plate. Guests already ask to book in WhatsApp — this assistant holds the spot, relays the host's own payment link, nudges the deposit, chases the balance at T-30/14/7 in the host's voice, and confirms the booking the moment the money is seen in the host's roster, Stripe, or a one-tap "Mark paid". The host watches it all from one Pulse card and makes every overdue call herself — Mark paid, extend, or release. It is the launch wedge: the retreat-persona card on the shared Program Booking Engine, and the first assistant a retreat host meets. MystFlo never touches the money — it chases, tracks, and confirms only.

2 · Scope what this build is — and what is explicitly out
In this build
  • TMPL-RTBK01 · beta · $1.75 per confirmed booking — renamed from Cohort Booking by migration 20260802012707_rtbk01_rename_cohort_to_retreat.sql; price renders from price_per_run, never authored.
  • Relay payment model (BINDING) — every pay moment relays the HOST'S own link or instruction; no MystFlo checkout appears anywhere. Copy implying MystFlo takes money is a blocker.
  • The retreat lens of the shared Program Booking Enginepayment_mode: deposit_balance is the DEFAULT here (hidden on the workshop card); engine mechanics live in the RTBK01 PRD (the engine home). Sibling card: workshop-booking.html (TMPL-WSBK01).
  • The full founder flow (Explore card → detail → Personalize → Connect → Try → Activated → Pulse → overdue verdict → post detail sheet) plus the guest WhatsApp phase — drawn to SHIPPED gating, no invented actions.
Explicitly out
  • The workshop lens — lives entirely in the sibling workshop-booking.html.
  • Attendees records surface · mirror write-back · booking-invite founder field — deferred, drawn as compact cards in 8 · Future design only.
  • A pre-overdue "nudge" action — not built; deliberately not drawn (gap 1).
  • BYOK AI provider picker — gated by BYOK_AI_HIDDEN; the AI Model row has no caret (kit lock 2026-08-05).
  • sec-2 Personalize payment-plan direction — ON HOLD pending a Peyton ruling (gap 6); the drawn content is frozen, do NOT build Personalize from this file yet.
3 · Content structure the data/copy shape every screen below is built from
Catalog copy — from the PRD, verbatim
  • description (card one-liner) · details.tldr · long_description · 4 details.benefits cards (typographic, no icons — T1203) — all VERBATIM from the PRD Catalog Copy table; screens never paraphrase the DB.
  • details.flow "How it works" chart — 6 nodes · 1 branch, deterministic seed; the live seed lags this contract on two counts (gap 5: "cohort" rename + missing chase node).
Setup shape (Personalize + Connect)
  • Roster binding via roster_sources (sheet | airtable | stripe + column map) — a read SOURCE, not a storage destination; read at send time, never stored (AC-COHB-06 ↗). No storage role declared (Required storage | — |).
  • Payment relay instruction — the host's link or bank/Wise text, relayed word for word (AC-COHB-03 ↗).
  • Sign-off name — asked ONCE across the booking family (AC-SIGNOFF-06 ↗); hidden when no name known (AC-SIGNOFF-07 ↗).
  • payment_mode: deposit_balance default — 30% deposit confirms the hold, balance due T-14.
Chase schedule + booking states
  • Balance reminders at T-30 / T-14 / T-7 — a FIXED engine rhythm, not a founder setting; roster re-read before every send (AC-COHB-06 ↗). Exactly ONE overdue notice, then reminders HOLD and the host is pinged (AC-COHB-07 ↗).
  • Booking rows live in MystFlo's own cohort_bookings — never written back to the host's file. States: held → deposit paid → confirmed · overdue → host verdict; ambiguous roster values stay pending, never accidentally paid (AC-COHB-05 ↗).
  • Overdue host-verdict set — exactly Mark paid · Extend due date · Release spot (AC-COHB-08 ↗), gated to overdue; read + verdict, never edit (Records-Layer rule); never a unilateral release (AC-COHB-07 ↗).
  • Billing shape: exactly ONE $1.75 meter, fired on the paid → confirmed edge only (AC-BILL-01 ↗ / AC-BILL-02 ↗); skips and cancels are visibly free (AC-BILL-04 ↗); wallet-can't-cover holds the booking at 402 (AC-BILL-03 ↗).
4 · User journey — full the host sets the chase once, guests get walked to paid — phases in the PRD's own vocabulary (U10), diagram verbatim

Two journeys, one diagram. The founder's Activate step opens the guest's booking door; every guest payment event flows back as a Pulse row, and the ONLY money-moment MystFlo owns is the $1.75 meter on the paid → confirmed edge. Standard vocabulary: founder Discover → Evaluate → Activate → Monitor → Decide · guest Trigger → Interact → Outcome → Fallback.

FOUNDER JOURNEY ────────────────────────────────────────────────────────────
┌ DISCOVER & EVALUATE ────────────────────────────────────────────────────┐
│ Explore card (sec-1) → detail sheet: what/why/how (sec-1b)               │
└─────────────────────────────────┬────────────────────────────────────────┘
                                  ▼
┌ ACTIVATE ────────────────────────────────────────────────────────────────┐
│ Personalize — roster + round + payment relay + sign-off (sec-2)          │
│ → Connect — WhatsApp · roster source · Brain Check (sec-3)               │
│ → Try — readback + one real test reminder (sec-4) → Activated (sec-5)    │
└─────────────────────────────────┬────────────────────────────────────────┘
                                  ▼        ◄── guests book from here on
┌ MONITOR ─────────────────────────────────────────────────────────────────┐
│ Pulse card — bookings, chase activity, needs-attention rows (sec-6)      │
└─────────────────────────────────┬────────────────────────────────────────┘
                                  │ a due date passes unpaid
                                  ▼
┌ DECIDE — the host verdict moment ────────────────────────────────────────┐
│ Overdue row: Mark paid · Extend due date · Release spot (sec-6b)         │
│ — never a unilateral release (AC-COHB-07 ↗ / AC-COHB-08 ↗)               │
└──────────────────────────────────────────────────────────────────────────┘

GUEST JOURNEY ──────────────────────────────────────────────────────────────
┌ TRIGGER ─────────────────────────────────────────────────────────────────┐
│ Guest asks about the retreat in WhatsApp → capture gate: name + email    │
│ → spot held pending deposit (sec-7a) — sold-out waitlists instead        │
│   (AC-COHB-20 ↗), never a silent overbook                                │
└─────────────────────────────────┬────────────────────────────────────────┘
                                  ▼
┌ INTERACT — the chase, in the host's voice ───────────────────────────────┐
│ deposit nudge (sec-7a) → balance reminders T-30/14/7 with the HOST'S     │
│ payment link relayed (sec-7b, AC-COHB-03 ↗) → "I already paid" honest    │
│ re-check (sec-7c, AC-COHB-10 ↗)                                          │
└─────────────────────────────────┬────────────────────────────────────────┘
                                  ▼
┌ OUTCOME ─────────────────────────────────────────────────────────────────┐
│ payment learned (sheet tick · Stripe event · host Mark paid) →           │
│ WhatsApp + email confirmation <30s, booking = confirmed, ONE $1.75      │
│ meter (AC-COHB-04 ↗ · AC-BILL-01 ↗ · AC-BILL-02 ↗)                       │
└─────────────────────────────────┬────────────────────────────────────────┘
                                  ▼
┌ FALLBACK ────────────────────────────────────────────────────────────────┐
│ overdue → ONE notice, reminders HOLD, host pinged (sec-7d) · stale       │
│ roster ≥7d → guest sends HELD (AC-COHB-12 ↗) · cancel intent honoured,   │
│ no fee (AC-COHB-09 ↗ / AC-BILL-04 ↗)                                     │
└──────────────────────────────────────────────────────────────────────────┘
  
Money guardrail BINDING (PRD)
  • This assistant chases, tracks, and confirms — never handles payment. Every frame that shows a pay moment relays the HOST'S own link or instruction; no MystFlo checkout ever appears. Copy that implies MystFlo takes money is a blocker.
Active the 1:1 build contract (kit canon U9) — matched pixel for pixel; current/being-built state only. Acceptance ids cited in frame notes (AC-* ↗) live in docs/product/assistants/shared/prd-as-retreat-booking.md §Test Plan → Acceptance Criteria. This artifact cites ACs, never mints them.
Discover
Retreat Booking
Beta
Chases deposits and balances for your retreat — so every booked spot actually pays before it starts.
Get Paid$1.75/run
Google SheetsWhatsApp BusinessStripe
tap for detailsActivate
Frame 1 · Explore card [Discover]
  • Story — As a retreat host drowning in "did they pay yet?" spreadsheet checks, I see in one card that this chases the money for me, and what it costs.
  • Copy is VERBATIM from the PRD Catalog Copy table (`description`) — the card never paraphrases the DB.
  • Price renders from `price_per_run` — never an authored literal (AC-BILL-01 ↗ names the billable unit).
  • Beta badge is the amber status chip; app chips are the three `required_apps`.
  • Component: `AssistantSummaryCardPre` (pre-activation taxonomy — BINDING).
768 not yet drawn for this flow. Desktop and 375 are the contract.
This step is 1180. No 375 drawing — use the Desktop size.
Evaluate
Retreat Booking TMPL-RTBK01
Chases deposits and balances for your retreat — so every booked spot actually pays before it starts.
$1.75 per confirmed booking · pay only when it runs
Overview Personalize Connect Try
What it does

Retreat Booking reads your roster (Google Sheet or Airtable), then runs the entire payment chase on WhatsApp: deposit nudges, balance reminders at T-30/14/7, and overdue handling — all in your voice. It relays your own payment link and tracks who's paid from your roster or your "mark paid" tap — MystFlo never touches the money. You decide every release from Pulse.

How it works
01
You
Set up the retreat onceseats, price, your pay link
02
Guest
A guest asks to book"I want the June one" in WhatsApp
03
Assistant
Holds the seat + sends your linktakes the request, relays your pay link
no seats left → hands the guest to Waitlist + Launch (overflow)
04
Assistant
Chases the balance for youdeposit nudge, then T-30/14/7 reminders — in your voice
05
You
Mark paidone tap when the money lands
Assistant
Booking logged, you get the pingseat counted, on-brand confirmation sent
Key benefits
Balances stop leaking quietly
The T-30/14/7 reminder sequence fires automatically — the guests who forgot to pay before your retreat get nudged before the due date passes.
Re-checks your roster before every send
It reads your sheet live at the moment each reminder fires — so no duplicate chases on a spot that already paid.
Reminds them in your voice
Messages go out sounding like you — warm, on-brand — not like an automated payment chaser that damages the relationship before they even arrive.
You decide every spot change
Overdue spots don't get released automatically. You tap extend, mark paid, or release from Pulse — nothing changes without you.
Frame 1b · Detail sheet [Evaluate]
  • Story — Before I pay for anything, I want the what, the why-trust-it, and the price on one sheet.
  • `tldr` / `long_description` / 4 benefit cards VERBATIM from PRD Catalog Copy — benefits are typographic, no icons (T1203).
  • Tab strip is the pre STEPPER (archetype `assistant-detail-tabs.md` / T1147): Overview › Personalize › Connect › Try with chevron separators + ✓ on completed steps — opens on Overview, Try disabled until Connect + Personalize complete.
  • "How it works" chart nodes come from the DB `details.flow` seed (`20260610150000_T-HIW-SEED`, §5.5 contract, deterministic, NO ai tag) with exactly TWO contract deltas, both flagged in the gap list: (1) n1 "Set up the cohort once" → "retreat" (rename catch-up — the 2026-08-02 migration never touched `details.flow`); (2) a NEW node 04 "Chases the balance for you" (Peyton-ruled 2026-08-04 — the chase leg is the product's core and now shows in the public chart; cadence copy states the FIXED T-30/14/7 rhythm as fact, not a founder setting). Now 6 nodes · 1 branch — still inside the §5.5 4–6 node cap. Branch pill hangs off n3, never its own column; outcome stays the ONE lit tile.
  • Pre-activation modal `AssistantDetailModalPre` on `AssistantModalShell` — its post twin is drawn at sec-6c.
  • Money guardrail visible in copy: "relays your own payment link", never "takes payment".
768 not yet drawn for this flow. Desktop and 375 are the contract.
This step is 1180. No 375 drawing — use the Desktop size.
Activate
Retreat Booking TMPL-RTBK01
Set it up once — it runs every retreat after this.
Overview Personalize Connect Try
01 · Your retreat
Retreat name
Bali Spring Retreat
Dates & spots
Apr 12–19 · 12 spots
02 · Deposit & balance
Payment plan
30% deposit + balancePay in full to bookFree RSVP
Balance due
14 days before start · reminders at T-30 / T-14 / T-7
03 · How guests pay you
Your payment link or instruction — relayed word for word
pay.saltandstone.com/bali-spring · or paste bank / Wise details
04 · Who signs the messages
LenaSalt & Stone Retreats
05 · Chase channels — required
WhatsAppEmail

Which channels the deposit/balance chase can use — connect the app for each in Connect.

Live preview
Hi Maya — just a gentle nudge: the balance for Bali Spring Retreat is due Mar 29. Here's the link when you're ready: pay.saltandstone.com/bali-spring — Lena sample
Frame 2 · Personalize [Activate]
  • Story — I answer a handful of questions in my own words and immediately SEE what a guest will receive, signed the way I sign.
  • Roster + round fields feed `roster_sources` + reminder scheduling (AC-COHB-01 ↗).
  • Payment field is the RELAY instruction — helper copy says "relayed word for word"; no MystFlo checkout (money guardrail).
  • Sign-off picker shows a live-rendered greeting per option, asked ONCE across the booking family (AC-SIGNOFF-06 ↗); hidden when no name is known yet (AC-SIGNOFF-07 ↗).
  • Retreat lens: `deposit_balance` is the DEFAULT here (it is hidden on the workshop card — sibling contract).
  • NEW — "05 · Chase channels" (2026-08-07, Peyton): which channels the chase can use, WhatsApp + Email both on by default. This is a DECISION only — no app connects here. Connect (sec-3) is where the actual app for each picked channel gets connected; picking a channel here without connecting its app in Connect blocks activation (same gating pattern Waitlist+Launch uses for its email-capture check).
Retreat Booking TMPL-RTBK01
Everything it reads — nothing it can't explain.
Complete Setup
Overview Personalize Connect Try
Connect apps
Communication WhatsApp Business + Resend
Matches your Chase channels from Personalize — connect an app for each one you picked
Connected
WhatsApp
WhatsApp Business
Sends reminders from your number · +62 812 ···· 41
Email
Resend
Sends balance chases from your connected Resend account
Gmail coming soon
AI Model MystFlo AI
Writes the chase messages in your voice. Choosing your own AI model is coming later.
Connected
Storage Google Sheets
Bali Spring Retreat roster · read at send time, never stored — MystFlo knows nothing until it next reads · any column layout works, you map your headers once; a missing column pauses with its name, never a guess
Connected
Storage MystFlo Storage
Confirmed bookings live on MystFlo — visible on Pulse. Tapping the caret opens the platform's standard 3-destination picker (Google Sheet/Supabase are dead-end picks here — nothing routes them yet)
Connected
Payment Stripe
Optional — only if payments should be learned from your own Stripe
Reconnect
Brain check
Business name & voice
Salt & Stone Retreats · warm, direct
Edit in Brain →
Cancellation policy
Answers guest cancel questions from this (AC-COHB-09 ↗)
Edit in Brain →
Retreat dates & capacity
It needs your retreat dates before it can take a booking
Add in Brain →
! 2 of 3 ready — 1 needs you before it can take a booking
Ready to run Apps ✓ · Wallet ✓ · Brain ✕
Gap closed (2026-08-07)
  • This frame was already TOC'd under § Desktop screens but only ever drawn as a 560px .panel — no true 1180-width realization existed anywhere in this file (this file's own "desktop" convention tops out at .panel-wide, 720px — see sec-1b/sec-2). Re-drawn here at the file's own pre-defined .desktop 1180 class (present in the stylesheet, previously unused) using this file's own header chrome (.m-head/.ttabs.pre-stepper, not the foreign `.sheet-top`/`.reveal` pattern from other mockups) plus the master's two-column split (apps left flex-1, Brain Check right 400px — `assistant-lifecycle.html` sec-5). Same rows/copy as before, nothing invented.
Frame 3 · Connect [Activate]
  • Story — I see exactly which of my accounts it touches, as read-only rows I recognize — not blank fields to re-type.
  • Exactly two connection verbs platform-wide: Reconnect (host can fix) and Pending (waiting on provider) — never Verify/Refresh/Manage.
  • ONE Connect-apps list, no "Included" tier (kit ruling 2026-08-04, Option C): the AI row is label "AI Model" + badge "MystFlo AI", status Connected; the roster row carries the read-only clarity pair (no info until next read · map-your-own-columns). Master contract: `assistant-lifecycle.html` B3.
  • Caret is structural pre-activation too, on every row but AI Model (kit `design-decisions.md` 2026-08-05/06, caret scope amended 2026-08-07, Peyton-locked): the badge carries the ▾ whether or not a second option is real today — supersedes the earlier "no caret pre-activation" reading. AI Model is the one exception, no caret and no coming-soon row — `AiModelPicker.tsx` has no provider dropdown, and BYOK is gated by `BYOK_AI_HIDDEN` as a deliberate product decision, not an unbuilt roadmap item. Payment (Stripe) carries the caret pre-activation — tapping it opens the current pick as the sole selected option plus one disabled `⊘ More providers · coming soon` row, the same shape as Storage's disabled Supabase group. Communication is NO LONGER a placeholder caret (2026-08-07 amendment, same day as the Storage-label reversal below): Personalize's new "05 · Chase channels" field is a pure DECISION (which channels apply), and Communication's caret expands into one real pick-group per channel picked — WhatsApp (single provider, already connected) and Email (Resend real + connectable, Gmail `⊘ coming soon`), same T353 channels-mode grammar as `waitlist-launch.html` sec-3. Drawn expanded here. The roster row is not a Storage-role row at all (next bullet), so `DestinationPicker`'s create-new/link-existing choice does not apply to it and it carries no caret — the roster is already-chosen, read-only, and swapping it is a Personalize decision, not a Connect-row expansion. Master contract: `assistant-lifecycle.html` sec-5b. Post-activation, Communication/Payment's caret gains a third muted/live state instead — see the 6c frame note (build gap #3120).
  • Roster row is label "Storage" + badge "Google Sheets" (Peyton, 2026-08-07 — reverses this row's earlier "Roster source" naming, same day). One role vocabulary everywhere, no per-assistant invented label: every file's storage-flavored row reads "Storage," full stop, matching `assistant-lifecycle.html` sec-5/5b. Behavior is unchanged — this stays read-only (roster is bound through roster_sources: sheet | airtable | stripe + column map, read at send time, never written back — AC-COHB-06); the label change doesn't imply a write path was added. No caret — the source is bound in Personalize, not a Connect-tab picker.
  • Ruling (Peyton, 2026-08-08): "stay a separate concept." Resolves the "ripe since #3178" open question that stood here — cohort_bookings gets its OWN row (the new row above, badge "MystFlo Storage"), not merged into the roster row's badge. Read source and write destination are different mechanisms and now render as two distinct rows, matching WSBK01's own storage role shape byte-for-byte (providers: ["mystflo_storage"], single provider). Shipped: `required_roles` migration seeding `chat` + `storage` roles for TMPL-RTBK01 (previously `[]`, legacy-fallback-only) — this is the full cutover onto the required-roles schema, since `useRoleMode` is all-or-nothing; the legacy "Google Account" app requirement is dropped (no roster-picker UI exists to gate on it yet, zero live instances at migration time) and tracked as separate follow-up work, not silently lost.
  • Both rows drawn "Storage" here — a mockup-only overlap, not a real production one (found in PR #3269 review, 2026-08-08). `StorageRoleRow.tsx` hardcodes its rendered label to the literal word "Storage" (ignores the role's own `label` field — the migration sets `"Where bookings save"`, but it never renders) and always shows a caret + the full MystFlo/Google Sheet/Supabase picker, regardless of `providers.length` (2026-08-07 "ONE Storage row, THREE destinations" lock has no single-provider carve-out). Picking Google Sheet/Supabase here is a dead end today — no `configuration_schema` field routes that pick anywhere for either RTBK01 or WSBK01, so the engine keeps writing `cohort_bookings` regardless (no data loss, just a confusing tap). This is a pre-existing, already-live gap (WSBK01 has had it since 2026-08-07), not something this migration introduces — tracked separately, not fixed here. The roster row above it is mockup-only illustration (no real required_roles entry backs it — roster_sources has no frontend picker built), so today's real Connect tab shows only ONE row saying "Storage," not two.
  • Roster row states the trust contract: "read at send time, never stored" (AC-COHB-06 ↗ fire-time re-check).
  • Brain Check is compact (this assistant's scope), each row deep-links via the slide-over choreography — never a nested modal.
  • Missing Brain rows gate nothing here — Brain is never a gate (Option C); amber row + link, wizard continues.
  • Connect honesty (2026-08-15): Dates & capacity is a blocker, so the summary may say “before it can take a booking”. Attention-only (Offerings Optional / stale) must read “it can {verb} · K to review” — drawn on the master at assistant-lifecycle.html #sec-5c. Header is amber Complete Setup because Payment is Reconnect (Connect incomplete). Once Connect is done this slot becomes quiet Continue to Try — a Brain blocker does not keep the amber label. Ready-to-run bar: Apps · Wallet · Brain. Wallet pending (label, no glyph) while the card hook loads — not drawn here; see master #sec-5c.
Retreat Booking TMPL-RTBK01
One real reminder, to you — before any guest sees it.
Overview Personalize Connect Try
What you set up
RetreatBali Spring Retreat · Apr 12–19 · 12 spots
Payment plan30% deposit + balance, due T-14
Guests pay viapay.saltandstone.com/bali-spring
RosterBali Spring Retreat roster · Google Sheets
SignedLena
Test it
Sent to YOUR WhatsApp just now — no guest saw this
Hi Maya — just a gentle nudge: the balance for Bali Spring Retreat is due Mar 29. Here's the link when you're ready: pay.saltandstone.com/bali-spring — Lena
If your roster changes shapeColumns reordered? It heals itself. A column missing? It pauses and tells you which one — it never guesses at money data.
Activate · $1.75 per confirmed booking
Frame 4 · Try [Activate]
  • Story — I get proof it sounds like me and reads my real sheet BEFORE I commit — the test lands on my own phone.
  • Try owns the preview (Personalize-vs-Try separation, BINDING) — Personalize only echoes a sample bubble.
  • The amber notice is the schema-resilience contract in founder words (AC-COHB-13 ↗ auto-heal reorder / pause on missing).
  • Price is restated ON the activate button — price visible before commitment, always.
Activating "Bali Spring Retreat"
Reading your roster — 9 rows found
Scheduling reminders from your due dates
Connecting your WhatsApp number
Final check
"Bali Spring Retreat" is live

3 guests already owe a balance — the first reminders are scheduled for tomorrow 9am, their time.

View in Pulse
Frame 5 · Activation outcomes [Activate]
  • Story — The loader tells me what it's actually doing with MY data, and "live" tells me the first concrete thing that will happen.
  • Loader steps name real pipeline stages, in founder words — no spinner-only state.
  • Success state ALWAYS names the next event ("first reminders tomorrow 9am") — no dead ends.
  • Wallet-can't-cover at a later Mark-paid returns 402 `topup_required` and HOLDS the booking (AC-BILL-03 ↗) — drawn in sec-6b, not invented here.
768 not yet drawn for this flow. Desktop and 375 are the contract.
Explore dims behind the sheet
Retreat Booking
Personalize · step 2 of 4 — the stepper strip scrolls horizontally at 375
01 · Your retreat
Retreat name
Bali Spring Retreat
Dates & spots
Apr 12–19 · 12 spots
02 · Deposit & balance
30% deposit + balancePay in full
Your payment link — relayed word for word
pay.saltandstone.com/bali-spring
Continue → Connect
Pulse, mobile
Active
Bali Spring Retreat ASST-7R2
Retreat Booking
1 booking needs your attention
This retreat
9 booked · 6 paid · 2 on deposit · 1 overdue
Maya K Balance overdue · $1,680Mark paid
Frame 8 · 375 tier [Activate + Monitor]
  • Wizard is a full-height bottom sheet over the dimmed page (sheet standard, PR #2346 chrome) — single column, groups stack in order.
  • All touch targets ≥ 44px; verdict buttons full-row on phones.
  • Same content as desktop frames — content scales fluidly, structure collapses at named breakpoints only (U8).
Active
Bali Spring Retreat ASST-7R2
Retreat Booking
1 booking needs your attention
This retreat
9 booked · 6 paid · 1 overdue
Needs your attention
Maya K Overdue · $1,680Mark paid
Recent activity
Payment learned — Aria S Confirmed · WhatsApp + email$1.75
Frame 9 · 768 tier [Monitor]
  • At md the card and its attention/activity panel sit side by side — the grid gains a column; nothing else changes (structure steps only at named breakpoints, U8).
  • This is a SAMPLE of the continuum, not a third design — a build that snaps awkwardly at 700 or 900 fails the tier contract even if 375/768/desktop all pass.
7 · Components the reusable parts library this surface draws from — reference only; every part listed here is proven in context in sections 5/6, never introduced here alone (8-section core rule).
  • Explore / Team card: `AssistantSummaryCardPre` (pre-activation taxonomy, BINDING) — sec-1.
  • Detail sheets (twins, archetype `../../archetypes/assistant-detail-tabs.md`): `AssistantDetailModalPre` (sec-1b, stepper tabs) and `AssistantDetailModalPost` (sec-6c, plain-nav tabs — Pulse · Overview · Personalize · Connect, R30) — both on `AssistantModalShell` (never `ModalWrapper` for the detail modal); `AssistantSummaryCardPost` carries the Pulse card that opens the post sheet — sec-6.
  • Wizard steps: `ConfigureStep` → `ConfigFieldRenderer` (config-schema-driven Personalize, sec-2/8), Connect rows + compact Brain Check module (sec-3), Try readback + test panel (sec-4).
  • Cross-reference choreography: "Edit in Brain →" rows use `PageSlideOver` / the 60/40 split — never a nested modal (overlays.html contract).
  • Attention + verdicts: `AttentionPanel` booking rows — Mark paid always; Extend due date / Release spot gated on overdue (sec-6/6b); Release styled as text-only destructive (`ConfirmDialog` convention).
  • Guest thread frames: the WhatsApp chat vocabulary (`.wa-*`/`.bub`, locked-template dashed bubbles) shared verbatim with on-brand-support.html / workshop-booking.html — sec-7.
  • Records component (future): the Attendees surface inherits `RecordsTable`/`RecordRow` per `../../archetypes/records-surface.md` — one component, noun is a prop.
Master contract + sources
  • assistant-flows/assistant-lifecycle.html is the primary structural contract; assistant-flows/workshop-booking.html is the engine sibling AND the canonical structural reference (design-canon.md § "Assistant-flow mockup structure — 8-section shape", Peyton-locked 2026-08-06); token block borrowed verbatim from on-brand-support.html.
  • Sources: prd-as-retreat-booking.md §Test Plan (AC-COHB-* / AC-BILL-* / AC-SIGNOFF-*) · rename migration 20260802012707_rtbk01_rename_cohort_to_retreat.sql · _shared/chat-handler.ts booking engine · AttentionPanel.tsx verdict gating · ledger ../parity/parity-retreat-booking.md.
Live
Active
Bali Spring Retreat ASST-7R2
Retreat Booking
1 booking needs your attention
This retreat
9 booked · 6 paid in full · 2 on deposit · 1 overdue
Needs your attention
Maya K Balance overdue — was due Mar 29 · $1,680 outstandingMark paid
Recent activity
Balance reminder sent — Jonas P T-14 · re-checked roster first, still unpaidApr 1 · 9:00
Payment learned from your sheet — Aria S Confirmation sent · WhatsApp + emailMar 30 · $1.75
Reminder skipped — Tomas B Roster showed paid at send time · skipped_paidMar 30
Frame 6 · Pulse card + feed [Monitor]
  • Story — One glance tells me who's paid, who's owing, and the single thing waiting on me.
  • Card shell is `AssistantSummaryCardPost` — identical shell across Pulse, sub-status drives visuals (BINDING lifecycle model). Status stays a dot + Active; the amber line is a meta line, not a status. Tapping the card opens the post detail sheet (sec-6c) on its Pulse tab.
  • The $1.75 rows make billing legible in the feed — the meter fires ONLY on paid → confirmed (AC-BILL-01 ↗), skips/cancels are visibly free (AC-BILL-04 ↗).
  • `skipped_paid` row surfaces the fire-time re-check promise (AC-COHB-06 ↗).
  • Not-yet-overdue rows offer ONLY Mark paid — extend/release appear at overdue (sec-6b), matching shipped `AttentionPanel` gating.
Maya K — balance overdue since Mar 29One overdue notice was sent Mar 30. Reminders are on hold. Nothing changes until you decide.
Booked2 spots · deposit paid Feb 12
Outstanding$1,680 balance
Last reply"traveling, will pay next week" · Mar 27
Mark paid Extend due date Release spot

Mark paid confirms her and sends the confirmation · Extend picks a new date and resumes reminders · Release frees the spot and tells her kindly.

Frame 6b · Overdue verdict [Decide]
  • Story — When money is on the line, I make the call in one tap — the assistant holds everything until I do.
  • Exactly the shipped verdict set: Mark paid · Extend due date · Release spot (AC-COHB-08 ↗) — never a unilateral release (AC-COHB-07 ↗). Read + verdict, never edit (Records-Layer rule).
  • Release is a text-only destructive action (no filled red button) — overlays.html confirm-dialog convention.
  • Each verb's consequence is written under the buttons — no mystery taps.
  • If the wallet can't cover the $1.75 at Mark paid: 402 → "Top up to confirm" state, booking stays held, nothing lost (AC-BILL-03 ↗).

Tapping the Pulse card (sec-6) opens the full detail sheet — `AssistantDetailModalPost` on `AssistantModalShell`, the visual TWIN of the pre sheet (same shell, same tab family, same language — shell-language #7). Tabs are PLAIN NAV, not a stepper: Pulse · Overview · Personalize · Connect, Pulse first and default, no Try tab (a live assistant's real runs are the proof — R30). Four states below.

Bali Spring Retreat ASST-7R2
Retreat Booking · Active since Feb 2
Pulse Overview Personalize Connect
This retreat
StatusActive
Bookings9 booked · 6 paid in full · 2 on deposit · 1 overdue
Needs your attention
Maya K Balance overdue — was due Mar 29 · $1,680Mark paid
Recent activity
Balance reminder sent — Jonas P T-14 · re-checked roster firstApr 1 · 9:00
Payment learned — Aria S Confirmed · WhatsApp + emailMar 30 · $1.75
Bali Spring Retreat ASST-7R2
Retreat Booking · Active since Feb 2
Pulse Overview Personalize Connect
What it does

Retreat Booking reads your roster (Google Sheet or Airtable), then runs the entire payment chase on WhatsApp: deposit nudges, balance reminders at T-30/14/7, and overdue handling — all in your voice. It relays your own payment link and tracks who's paid from your roster or your "mark paid" tap — MystFlo never touches the money. You decide every release from Pulse.

How it works
01
Set up the retreat once
Seats, price, your pay link.
02
A guest asks to book
"I want the June one" in WhatsApp.
03
Holds the seat + sends your link
Takes the request, relays your pay link. No seats left → hands the guest to Waitlist + Launch.
04
Chases the balance for you
Deposit nudge, then T-30/14/7 reminders — in your voice.
05
Mark paid
One tap when the money lands.
Booking logged, you get the ping
Seat counted, on-brand confirmation sent.

Word-for-word the pre-activation Overview (R28 — one product description, pre and post): same "What it does", same flow nodes. No "Your setup" block here — that lives on Personalize (R29).

Bali Spring Retreat ASST-7R2
Retreat Booking · Active since Feb 2
Pulse Overview Personalize Connect
Your setup
RetreatBali Spring Retreat · Apr 12–19 · 12 spots
Payment plan30% deposit + balance, due T-14
Guests pay viapay.saltandstone.com/bali-spring
SignedLena
Changes take effect on the next run — nothing already sent gets rewritten.
Bali Spring Retreat ASST-7R2
Retreat Booking · Active since Feb 2
Pulse Overview Personalize Connect
Connect apps
Communication WhatsApp Business
+62 812 ···· 41
Connected
AI Model MystFlo AI
Writes the chase messages in your voice. Choosing your own AI model is coming later.
Connected
Storage Google Sheets
Bali Spring Retreat roster · read at send time — no info until it next reads
Connected
Storage MystFlo Storage
Confirmed bookings live on MystFlo — visible on Pulse. Tap the badge to send them somewhere else.
Connected
Payment Stripe
Learns payments from your Stripe
Connected
Brain check
Business name & voice
Salt & Stone Retreats · warm, direct
Edit in Brain →
Cancellation policy
Answering guest questions from this
Edit in Brain →
Frame 6c · Post detail sheet — four tab states [Monitor]
  • Story — Six weeks after activating, I tap into the live assistant and land on what matters NOW (Pulse), with everything I set one tab away — and it feels like the same room I set it up in.
  • Twins rule (shell-language #7): same shell (`AssistantModalShell`), same tab family, same language as the pre sheet — plain nav here vs stepper there is the ONE sanctioned difference (T1147).
  • R30: tabs are Pulse · Overview · Personalize · Connect — Pulse FIRST and selected on open; NO Try tab, no "Activity" label.
  • R28: Overview copy is word-for-word the pre Overview — including the same 5 "How it works" nodes (drawn as the compact numbered rail at this panel width; the pre sheet's wide chart and this rail are the same content per the archetype's two wireframes).
  • R29: "Your setup" read-back lives on Personalize, never Overview.
  • Personalize edits apply on the next run — nothing already sent gets rewritten; the Mark-paid verdict on the Pulse tab is the same `AttentionPanel` row as sec-6/6b.
  • Connect tab's Communication/Payment rows carry the muted-caret mechanic here (B9/A6 amendment, 2026-08-06): this instance is Active, so the caret is dimmed — tapping it explains the pause-or-new-instance choice rather than opening a picker. Master contract: `assistant-lifecycle.html` sec-9d. Build gap — NOT BUILT, pending #3120 (`RoleRow.tsx`'s own TODO): drawn as the intended target, not shipped behavior.
768 not yet drawn for this flow. Desktop and 375 are the contract.
This step is 1180. No 375 drawing — use the Desktop size.
Guest
This step is 375. No 1180 drawing — use the Mobile size.
768 not yet drawn for this flow. Desktop and 375 are the contract.
Guest phase — WhatsApp mobile-only by nature, inside the Mobile journey. Four beats: capture & deposit (7a) · balance chase (7b) · "I already paid" (7c) · overdue & hold (7d).
Frame 7a · Capture + sold-out [Guest · Trigger]
  • Story — As a guest I book in the same thread I asked in — no form link unless WhatsApp's native form is available.
  • Name + email are the real capture gate — no booking row without both; seats re-checked at submit.
  • Over-capacity requests are refused and waitlisted (AC-COHB-20 ↗) — never a silent overbook.
  • The AI discloses itself in the sender line; deposit ask relays the HOST'S link (AC-COHB-03 ↗ relay model).
Frame 7b · Balance reminder → paid → confirmed [Guest · Interact/Outcome]
  • Story — The nudge reads like Lena, not like a bank — and the second I pay, I KNOW I'm in.
  • Outside the 24h window only approved Meta templates send — the dashed bubble marks locked template copy (AC-COHB-14 ↗).
  • Payment learned (sheet tick / Stripe event / Mark paid) → WhatsApp + email confirmation within 30s (AC-COHB-04 ↗); exactly ONE $1.75 meter, deduped (AC-BILL-01 ↗ / AC-BILL-02 ↗).
  • Sign-off follows the host's stored preference on every channel (AC-SIGNOFF-01 ↗).
Frame 7c · Claimed payment [Guest · Interact]
  • Story — When I say I've paid, I'm believed enough to stop the chasing — but the host's ledger stays the truth.
  • Roster re-read on the spot; found → confirm + meter; not found → honest "flagged for Lena" + host ping — NEVER auto-confirmed on the guest's word (AC-COHB-10 ↗).
  • Ambiguous roster values stay `pending`, never accidentally paid (AC-COHB-05 ↗).
Frame 7d · Overdue notice [Guest · Fallback]
  • Story — Even overdue, I'm treated like a guest, not a debtor — and there's always a human path.
  • Exactly ONE overdue notice; then reminders HOLD and the host is pinged with a Pulse deep-link (AC-COHB-07 ↗) — the verdict is sec-6b's, never the engine's.
  • Stale roster ≥7d holds guest sends entirely and nudges the host instead (AC-COHB-12 ↗) — no chase fires off stale money data.
8 · Future design never a build target Part II · Future under its plain-language name (kit canon U9) — deferred scope with PRD anchors, compact cards only, no drawn screens. Sections 1–7 collectively are the Active build contract.
Attendees — the records surface AC-COHB-17 ↗ / AC-COHB-18 ↗ · not built
  • A Pulse row opening a full-screen list of every booking with status + CSV export, under the record noun Attendees. Read + verdict only — the verdict set stays exactly Mark paid · Extend · Release; no editable cells ever (an editable row is a CRM).
Mirror write-back AC-COHB-19 ↗ · not built, M2
  • The existing roster READ is not a mirror. When write-back ships it is offered at activation, defaults OFF, never auto-provisioned.
Booking-invite line as a founder field AC-COHB-16 ↗ · not built
  • `copy_flow_intro` inherits from the shared engine unchanged — same Personalize textarea as the workshop card, one text for every entry path.
Known deltas between this contract and shipped code — for the parity ledger, not guesses
  1. Verdict gating is drawn as shipped: a not-yet-overdue row offers only Mark paid; Extend due date + Release spot appear at overdue (`AttentionPanel.tsx` gating). A pre-overdue "nudge" action is NOT built and is deliberately not drawn.
  2. Meta template names (`retreat_balance_reminder`, `retreat_overdue_notice`) are illustrative labels for the locked-template convention — exact production template names/bodies live in the workshop-templates/engine layer and are graded by the parity ledger, not asserted here.
  3. Detail-sheet tab set (Overview · How it works · Apps) follows the master `assistant-lifecycle.html` pre-detail contract — if that master changes, this file inherits, never forks.
  4. Sold-out waitlist copy (7a right phone) is the AC-COHB-20 ↗ behaviour in Brain voice — shipped fallback wording should be graded against it at render-check.
  5. The LIVE `details.flow` seed lags this contract on two counts — n1 still says "cohort" (the 2026-08-02 rename migration never touched `details.flow`), and it has no chase node (5 nodes vs the 6 drawn here — the chase leg was ruled INTO the public chart by Peyton, 2026-08-04). ONE catalog-copy sync migration (+ PRD same-PR per the guard) closes both.
  6. sec-2 Personalize payment-plan content is ON HOLD pending a Peyton ruling (2026-08-04). DB + spec verification found the drawn "Payment plan" selector and editable-looking reminder copy are NOT in the live `configuration_schema`, and the chase cadence is fixed, not founder-configurable; the spec'd-but-unbuilt gap is a roster-source picker + column map (build-spec:389). Direction TBD (build the drawn UI / build the spec'd roster picker / match what's live) — the drawn content is deliberately frozen as-is until the ruling; do NOT build Personalize from this frame yet.

Parity ledger: ../parity/parity-retreat-booking.md · PRD: docs/product/assistants/shared/prd-as-retreat-booking.md · Engine sibling: workshop-booking.html · Master: assistant-lifecycle.html