# multi-surface-fanout.screen The fan-out approval centerpiece — one decision, N adapter dispatches across the 24-surface roster (brief O). Pairs with brief H §H4 (multi-surface card pattern) and §H5 (density: H5a accordion · H5b compact · H5c anchor-and-rest · H5d cross-cutting rules · H5e split-card). Voice register: working (`00-system-voice.md` §V2b); plain on failures and high-stakes elevation. Sibling to `approval-card.screen.md` (single-surface). Where the single-surface card is *one diff, one approve*, this is *one diff, many surfaces, one approve* — and at Quinn's actual roster size, density is the design. ## Layout Four variants rendered below. Picker is automatic per H5 thresholds, never Quinn-toggleable. Approve button stays pinned to card bottom in every variant; internal scroll only inside the body. ### Flat (≤5 surfaces) — full ASCII card ``` ┌─────────────────────────────────────────────────┐ │ ┃ ▢ Update about-me on 4 surfaces ⋯ menu │ │ ┃ [profile-copy] · medium · 0.81 │ │ ┃ │ │ ┃ ◉ [Tryst] "Independent escort…" 142c │ │ ┃ ◉ [TS4Rent] "Independent escort,…" 138c │ │ ┃ ◉ [Slixa] "SF-based independent…" 165c │ │ ┃ ◉ [tqftw.com] "Independent escort…" 320c │ │ ┃ │ │ ┃ Why: dropping "corporate" everywhere. │ │ ┃ │ │ ┃ [ Edit ] [ Set aside ] [ Approve 4 ] │ └─────────────────────────────────────────────────┘ ``` ### Accordion (6–12 surfaces) — H5a, grouped by O categories Collapsed-default state when total > 8: ``` ┌─────────────────────────────────────────────────┐ │ ┃ ▢ Update about-me on 10 surfaces ⋯ │ │ ┃ [profile-copy] · medium · 0.78 │ │ ┃ │ │ ┃ Escort directories · 8 [6/8 ▾] │ │ ┃ Brand sites · 2 [2/2 ▴] │ │ ┃ ◉ [tqftw.com] "Independent escort…" │ │ ┃ ◉ [a.t.t.com] "Tour-focused…" │ │ ┃ │ │ ┃ Why: dropping "corporate" everywhere. │ │ ┃ │ │ ┃ [ Edit ] [ Set aside ] [ Approve 8 ] │ └─────────────────────────────────────────────────┘ ``` Expanded state of directories group (H5a per-group bulk toggle visible): ``` │ ┃ Escort directories · 8 [6/8 ▴] │ │ ┃ All on · All off · Custom │ │ ┃ ◉ [Tryst] "Independent escort…" │ │ ┃ ◉ [TS4Rent] "Independent escort,…" │ │ ┃ ◉ [Slixa] "SF-based indep…" │ │ ┃ ◉ [PD] "Indep. companion…" │ │ ┃ ◉ [Seeking] "Independent comp…" │ │ ┃ ◉ [TSEscorts] "Indep. SF escort…" │ │ ┃ ○ [Eros] (blocked — name change) │ │ ┃ ○ [AdultSearch] "Indep. SF escort…" │ ``` ### Compact rows (≥8 in one group) — H5b, one-line-per-surface When the directories group alone has ≥8 (the canonical N2 case from brief O): ``` │ ┃ Escort directories · 12 [10/12 ▴] │ │ ┃ filter surfaces… │ │ ┃ ◉ [Tryst] · 142c · ✓ │ │ ┃ ◉ [TS4Rent] · 138c · ✓ │ │ ┃ ◉ [Slixa] · 165c · ✓ │ │ ┃ ◉ [PD] · 144c · ✓ │ │ ┃ ◉ [Seeking] · 220c · ⓘ longer │ │ ┃ ◉ [TSEscorts] · 158c · ✓ │ │ ┃ ◉ [AdultSearch] · 410c · ✓ │ │ ┃ ◉ [AdultLook] · 488c · ⓘ near cap │ │ ┃ ◉ [EroticMonkey] · 142c · ✓ │ │ ┃ ◉ [SkipTheGames] · 144c · ✓ │ │ ┃ ○ [Eros] · blocked │ │ ┃ ○ [MegaPers] · not started │ ``` Tap a row → that row expands inline (others collapse) to show full preview + inline edit. One row expanded at a time. ### Anchor-and-rest (tours per H5c) ``` ┌─────────────────────────────────────────────────┐ │ ┃ ▢ Add Berlin tour · Oct 3–7 ⋯ │ │ ┃ [tour] · medium · 0.84 │ │ ┃ │ │ ┃ Anchors [3/3] │ │ ┃ ◉ [Tryst] "in Berlin Oct 3–7" │ │ ┃ ◉ [TS4Rent] "Berlin · Oct 3–7" │ │ ┃ ◉ [tqftw.com] "tour: Berlin · Oct" │ │ ┃ │ │ ┃ Other directories · 9 [7/9 ▾] │ │ ┃ Brand sites · 1 [1/1 ▾] │ │ ┃ │ │ ┃ Why: anchors always expanded; rest curated. │ │ ┃ │ │ ┃ [ Edit ] [ Set aside ] [ Approve 11 ] │ └─────────────────────────────────────────────────┘ ``` Anchors never collapse. Rest stays collapsed until Quinn taps to curate. ## Components | Component | Notes | |---|---| | Stakes color band | 4pt left edge per `00-system-visual-system.md` §F1. Aggregate band; escalates per H5d if any row is high-stakes standalone. | | Header | Verb + N-surfaces count + ⋯ menu (see-full-reasoning · talk-to-{specialist} · split-this-card · report). | | Chip row | Action-kind chip (profile-copy / tour / availability-policy) · stakes label · aggregate confidence (enabled rows only, per H5d). | | Group header | Category label + count + aggregate state glyph (✓ N · ⓘ M · ⚠ K · ○ blocked) + per-group bulk-toggle (All on / All off / Custom) + caret. | | Surface row (full) | Surface chip (F5 iconography) · per-surface preview · checkbox · char count vs cap. | | Surface row (compact, H5b) | Single line: `[chip] name · Nc · status-glyph`. Tap-to-expand. | | Filter input | Appears above accordion when total ≥ 12 (H5d). Filters across groups; never hides approve. | | "Why" line | Aggregate rationale; tap expands per-surface rationales stacked. | | Action bar | Edit · Set aside · Approve N. Pinned bottom safe-area. Approve label always shows enabled-row count. | | Split connector | When H5e applies, a hairline + caption ties two stacked cards together. | ## States ### Flat Default for ≤5 surfaces. All rows visible, no accordion chrome. Approve enabled when ≥1 row checked. ### Accordion-collapsed Default for >8 total. Group headers visible; bodies hidden. Per-group counts let Quinn approve without expanding ("6/8 looks right · approve"). Caret ▾ on collapsed, ▴ on expanded. ### Accordion-expanded (single group) Tapping a group caret expands that group only; siblings stay in their current state. Bulk-toggle row appears at top of expanded body. Internal scroll bound to body, not card. ### Compact-row-expanded H5b only. Tapping a compact row expands it inline to a full row (preview + char cap visualization + inline-edit affordance). Tapping another compact row collapses the prior — one-at-a-time. ### Search-filtered H5d. Filter input typed; non-matching rows hide; group counts update to `(matching / total)`. Approve count reflects all enabled rows including hidden — clear caption: "Approve 10 (3 hidden by filter)". ### Split-card (H5e + K3i) When the specialist splits at draft time, two stacked cards appear in chat with a connector: ``` ┌─ routine ───────────────────────────────────┐ │ ▢ Update about-me on 8 surfaces │ │ [ Edit ] [ Set aside ] [ Approve 8 ] │ └─────────────────────────────────────────────┘ │ These 8 go together │ This 1 wants your eyes ┌─ brand-sensitive ───────────────────────────┐ │ ▢ Update about-me on tqftw.com │ │ (single-surface diff card — H2 shape) │ │ [ Edit ] [ Set aside ] [ Approve ] │ └─────────────────────────────────────────────┘ ``` The split is the specialist's call (brief H5e), surfaced to Quinn as one visual unit. ### Dispatch-in-progress (per-row) Approve tapped → action bar replaced by a progress strip ("Pushing to 10 surfaces · 4 done"). Each enabled row shows its own state: spinner → ✓ or ✗. Failed rows stay in card; succeeded rows fade slightly. Card cannot be dismissed mid-dispatch. ### Post-dispatch with 2/8 failed After all rows resolve, card transforms into a receipt with a per-group failure banner per H5d (one banner per group with failures, not per row): ``` │ ┃ ✓ 8 surfaces updated · 2 failed │ │ ┃ Escort directories · 6 of 8 ⚠ │ │ ┃ 2 failed — tap to retry │ │ ┃ Brand sites · 2 of 2 ✓ │ │ ┃ │ │ ┃ [ Retry 2 ] [ See details ] [ Dismiss ] │ ``` Tap retry → just the failed rows re-dispatch; tap details → row-by-row in audit drawer (brief I). ### Stakes-escalated (all-high) Per H5d, any single row at high stakes elevates the whole card. Visual: stakes band → rose; Approve button gets a confirm step ("Approve 10 — high stakes"). Voice shifts to plain register: "Ten surfaces. High stakes from Eros's name-change flag. Approve all, or split out Eros?" ## Gestures - **Tap group caret** → expand/collapse that group only. - **Tap compact row** → inline expand; auto-collapses any other expanded compact row. - **Long-press surface row** → quick actions (skip · edit just this · open surface settings). - **Long-press group header** → bulk action menu (All on · All off · Skip this group). - **Right-swipe card** → Approve N (haptic confirm threshold per F §F4); blocked when in dispatch-in-progress or stakes-escalated states. - **Left-swipe card** → Set aside (moves to pending-approvals). - **Two-finger swipe down** → minimize-to-inbox. - **Pinch-out on group header** → expands all groups at once (escape hatch from collapsed-default). - **Tap "Why"** → expand per-surface rationales stacked. ## In-the-wild copy Working register throughout except where noted. **H3 tour fan-out (anchor-and-rest header):** > Berlin Oct 3–7 ready on 11 surfaces. Anchors set. Eros is off — flip on if you want them included. **H5b compact-row with near-cap notice (ⓘ hover):** > AdultLook caps at 500 — this draft lands at 488. Tight but fits. **H5e split-card connector (K3i):** > These 8 go together · This 1 wants your eyes. **Post-dispatch 2/8 failed (plain — failure register):** > 8 surfaces updated. AdultSearch and Eros rejected the push. Retry, or set them aside. ## Edge cases - **Single group exceeds compact threshold but total is small** (e.g. 9 directories, no brand sites) — H5b activates for that group; the card still feels flat because there's only one group. Acceptable; predictability over polish. - **All surfaces in one group blocked** (e.g. all N2 pending verification after a coop-intel mass-flag per brief N) — group header shows ⚠ all-blocked; Approve count drops to 0; action bar reads "Nothing to approve · review blockers". - **Confidence below threshold on enabled-only average** — Approve disabled; "ask Cocotte to try again" surfaces beneath action bar (mirrors single-surface card edge case). - **Card stale (>24h)** — same gentle warning as single-surface card; re-draft re-runs the per-surface diff pass. - **Filter input typed during dispatch-in-progress** — input disabled; tap surfaces a one-line hint ("Pushing — filter unlocks when done"). - **VoiceOver order** — header → aggregate stakes/confidence → "Why" → group headers (with counts) → expanded rows → action bar. Group counts are critical: a blind user must hear "6 of 8 directories enabled" without expanding. - **Reduced motion** — accordion expand/collapse becomes instant; dispatch progress strip skips per-row spinner animation, jumps row-state on settle. - **Dynamic Type XXL** — compact rows force-promote to full rows (compact-format unreadable at largest sizes); accordion remains. - **Org-context (brief W)** — if active org has a surface subset enabled, disabled-by-org rows render with a tiny lock glyph; tap to see "disabled in {Org} context". - **Kill switch active (brief K)** — card greys; action bar replaced by "Auto-actions paused — resume to dispatch". ## Related - [brief H §H4](./H-recurring-chores.brief.md) — multi-surface approval-card pattern (anatomy). - [brief H §H5a–e](./H-recurring-chores.brief.md) — density rules (accordion / compact / anchor-and-rest / cross-cutting / split-card). - [brief A §approval](./A-chat-surface.brief.md) — chat-surface integration; this card appears inline. - [brief K §K3i](./K-safety-blocklist.brief.md) — split-card boundary (routine vs brand-sensitive). - [brief O](./O-surfaces-roster.brief.md) — the 24-surface roster that makes density mandatory. - [brief R §R3](./R-tours-events-hotels.brief.md) — tour fan-out is this card's H5c anchor-and-rest shape, used by the tours backbone. - [`approval-card.screen.md`](./approval-card.screen.md) — sibling single-surface pattern. - [brief I §3](./I-audit-trust-replay.brief.md) — per-row audit lineage post-dispatch. - [`00-system-voice.md`](./00-system-voice.md) §V2b + §V2c — working register for body, plain on failures/escalation.