Design preview · not yet built

App shell — header, navigation, footer

The shell — rail, guest, and every failure stays inside it.

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

The chrome every page sits inside — 72px header, variant-B left rail, collapsed rail, mobile drawer, and flat footer (as-built from PlatformLayout.tsx, UnifiedSidebar.tsx, Footer.tsx) — plus the three surfaces that replace the shell when it fails to render: the boot watchdog, the ErrorBoundary, and the stale-chunk reload beat (frames 10–12).

variant B rail — Peyton-locked 2026-07-20 (#2576)quiet active = tint + lit edge, not solid-white pillUsage nav row = proposedcollapse toggle: far-left 64px header slotheader right = one quiet line — Peyton-locked 2026-07-24first-run coach = one header chip, next undone step only — built 2026-08-15MEMBER + GUEST badges retired — Preview is the only header badgeAbout + Legal live in the footer, not the rail — Peyton-locked 2026-07-24every error stays INSIDE the shell — Peyton-locked 2026-08-10destructive ⚠ icon retired from the crash screenone label: Reload, never "Reload Page"no escape link — the rail is the escape

Frames 10–12 — the error never takes the shell down (Peyton-locked 2026-08-10). There are three ways to fail — the boot watchdog (10) when React never mounted, the ErrorBoundary (11 / 11c) when React mounted and something threw, the reload beat (12) which is not an error at all — and in every one of them the header, rail, and footer stay on screen with the message sitting in the content column. Two bugs drove this: the layers had drifted into different visual and verbal registers, and ErrorBoundary claimed min-h-screen even when nested inside PlatformLayout, blanking a shell that was mounted the whole time.

The blast-radius ladder (frames 10–14). Every error sits at the smallest scope that actually failed, and the treatment shrinks with it: the whole app can't run → static shell (10, 11c) · one page crashed → real shell, message in the content column (11, 11b, 12) · one region's data failed → inline block inside that region, page untouched (14) · one action failed → toast or inline message under the control · the route doesn't exist → 404 in the shell (13). Rungs ③ and ④ are deliberately NOT the crash surface — a failed list wearing a 20px headline would misreport how much broke. The scale difference is the message.

Two shells, one appearance. Where React is healthy (11, 11b, 12) the real PlatformLayout renders. Where it is not — the watchdog (10) and the root boundary (11c), which can be catching PlatformLayout itself — the chrome is a hand-drawn static copy: markup only, nav rows as plain <a href> (a full page load needs no JavaScript), and no balance / name / sign-out, because neither case can know the auth state and neither may guess. Identical appearance, deliberately different implementation. Rendering the real layout in those two cases would risk re-crashing on the thing that just crashed.

The widths drawn here are samples of a fluid continuum, not the only states that exist — content (spacing, type, gaps, card/column widths) scales continuously between them, each clamp reading a named container. Structure (rail, row↔stack, grid columns) steps only at sm 640 · md 768 · lg 1024; radius, hairlines, and pills never scale. Kit: design-canon.md U8.

Reading order in this document: § Desktop journey first — every desktop frame, full flow, journey order — then § Mobile journey — 375 below it — every mobile frame, same order, laid out side by side as a wrapping grid (never a tall single-file column of phone screens). Two sections, never interleaved — a review-document convention only (this repo's design-canon.md § Mockup review reading order). Mobile 375px is still designed and scored FIRST in the /design ritual (kit canon U5/U8) — the two rules never conflate.

Part I · Active — build now

Review Feedback here. Save this file, open it locally, then jump: form · sent · guest · 375. V3: Thread under the title, Seal when sent, Mark only if you are not signed in. Header lantern stays the one gold. Do not open feedback.html.

1b · Desktop 1180 — Feedback page in the shell (the new look)
MystFlo Platform Private Beta Feedback
· Peyton
Workspace
Support
Account
Feedback
Tell me what’s off. Feedback — good or bad — helps me improve the product faster.
How’s this
Good
Off
Pick one — or a few
Broken Confusing Missing Slow Looks off Loved this
General
About an assistant
Anything to add
Optional. A thumb or a chip is enough.
0 / 10,000
Screenshot
invite.png×
Drop a screenshot — or click
Send
Signed-in form. Thumb first. Then chips (a note without typing). Then optional text. Then drop a screenshot — same attach as Wishlist, not a URL. Submit is white; lantern stays on the header badge. 375 is here.
1b · Desktop 1180 — Feedback sent
MystFlo Platform Private Beta Feedback
· Peyton
Workspace
Support
Account
Feedback
Tell me what’s off. Feedback — good or bad — helps me improve the product faster.
Thank you!
That helps. I appreciate it. Keep sending it in — good and bad. It helps me improve the product faster.
Send another
Sent. Same 560 column, same title + Thread as the form. Seal hangs from that line — not centered in leftover pane. No green disc.
1b · Desktop 1180 — Feedback guest
MystFlo Platform Private Beta Feedback
Workspace
Support
Account
Feedback
Tell me what’s off. Feedback — good or bad — helps me improve the product faster.
Sign in to send feedback.
Sign in
Guest. Same page top as the form. Full Mark left, under the Thread. Sign in only — no invite-only line, so this form stays the same after private beta. No fake disabled form.
Rail
1bMobile 375 — Feedback page
Feedback
Tell me what’s off. Feedback — good or bad — helps me improve the product faster.
How’s this
Good
Off
Pick one — or a few
Broken Confusing Missing Slow Looks off Loved this
Anything to add
Optional. A thumb or a chip is enough.
Screenshot
Drop a screenshot — or click
Send
Feedback at 375
  • Thumb → chips → optional note → drop a file. Send is full-width white.
  • No URL fields. Header is hamburger + Private Beta + Feedback + wallet.
MystFlo Platform Preview
· Peyton
Workspace
Support
Account
Page content renders here (Assistants / Brain / Pulse / Billing / …)
Nav content & order (UnifiedSidebar.tsx)
  • Workspace: Assistants · Brain (badge dot = no business profile yet) · Pulse · Team · Connects.
  • Support: Wishlist · Feedback · Support · FAQ (external links).
  • Account: Account · Billing · Usage (proposed own row — route /billing/usage exists, today reached only via in-page tab) · Sign Out.
  • About MystFlo + Legal removed from the rail (2026-07-24) — they're informational, not workspace destinations, and the footer already owns them (About · Privacy · Terms, the last two deep-linking into /legal). One home per link. FAQ stays in Support (a help resource in-rail; the footer FAQ serves the site-info context).
  • Eyebrows replace the old bare dividers; active = quiet tint + lit edge (solid-white pill retired).
Active-state anatomy
Tint fillrgba(255,255,255,.06) (surface-elevated) replaces the solid-white pill background across the whole row.
Lit left-edge thread — a 2px gradient bar (transparent → white → transparent) sitting 6px outside the item's left edge, with a soft white glow. This is what actually carries "you are here," not the fill.
Name set (default)
· Peyton
No name set → email fallback
· peyton@mystflo.com
Header identity — one quiet line (C4, amended 2026-07-24)
Balance · name · sign-out read as ONE de-boxed 13px text cluster — no wallet pill border, no Member chip. The balance is the tappable segment (hover tint → TopUpModal); interpuncts (· at white/30) separate; the C5 log-out glyph stays. Display name falls back to the account email only when no name is set. MEMBER badge retired — the signed-in cluster itself says "member"; Preview is the header's only badge.
MystFlo Platform Preview
· Peyton
Page content renders here — main column gains ~144px on collapse
Collapsed rail (SidebarEyebrow)
  • Eyebrow labels fall back to the lit hairline divider between groups (no room at 64px) — never hidden with no replacement.
  • Icons center in the 64px rail; hover/focus tooltip (desktop only) is the only label at this width.
  • Active keeps the same tint + lit edge, centered.
Collapsed rail — hover (C2)
Pointer over an icon-only item shows a tooltip badge to its right: elevated surface --surface-el, hairline border, 12px label — the page title, so nobody has to guess what an icon means. Same trigger fires on keyboard focus.
MystFlo Platform Preview
Building in public
Assistants aren't live yet — we're building MystFlo in the open.
Help build this →
· Peyton
Workspace
Support
Account
Page content renders here — the popover floats above it
C3 — PlatformStatusBadge
  • Only the preview stage is interactive — other stages render a plain muted label, no click target.
  • Opens on hover / keyboard focus (tabindex="0"), never click — cursor stays default.
  • Dot = genuine ping animation (amber ring expanding + fading behind a solid core).
  • Analytics: preview_banner_viewed on open; CTA deep-links to WhatsApp (pre-filled "help build" message) + preview_banner_cta_clicked.
1 · Away from Assistants
MystFlo Platform Preview
·Peyton
2 · Away from the wizard
MystFlo Platform Preview
·Peyton
3 · Away from Pulse
MystFlo Platform Preview
·Peyton
4 · Away from Brain
MystFlo Platform Preview
·Peyton
5 · Playbook required set is ready — Teach handoff
MystFlo Platform Preview
·Peyton
After they open Teach once: chip gone. Brain’s own rows own the forever work. Visiting /brain does not dismiss it.
The sequence — one chip, next undone step only
  • Read top to bottom. Each beat is the real header treatment (living mark + n of 5 + words), and the chip carries its own progress line — a chip-wide .12 track 7px under the caption, lit white to the playbook required-% — steps 1–3 draw a 6% "just started" sliver (no Brain queries yet), step 4 the real %, step 5 full. v4.1 (Peyton, 2026-08-16, production): the v4 full-header hairline echo read as a bar across the whole 1440 chrome — "just the progress line, not the full bar." The header's own bottom hairline stays dark; the line belongs to the chip. The line under each header is the on-page wording.
  • Beat 5 is the Teach handoff after the required playbook set is ready. One door: the share sheet. Our read and research are not numbered chips. The chip unmounts after they open Teach once — not at playbook ready, and not from visiting /brain. The progress line is chip anatomy, so it unmounts with it.
  • Tier rule (Peyton 2026-08-16): this desktop treatment holds at lg (1024px) and up only. Below that — tablet included — the chip renders as the 375 progress band (see the mobile frames), not a center caption. The old sm/640 switch left tablets a center chip that read as detached.
MystFlo Platform Preview
· Peyton
Workspace
Account
Assistants

Pre-built assistants. Connect what you need. Pay only when they run.

On-Brand Support
Answers DMs in your voice, 24/7.
Workshop Booking
Takes the booking. You teach the class.
Waitlist Launch
Collects signups. You hit send when ready.
Step 1 — no assistant yet (Peyton 2026-08-15, treatment v3: wayfinding kicker)
  • One guide line. The next undone step only. A tiny living mark (track + three shelves, Vitsoe-quiet) sits before a white STEP 1 kicker so the line is findable in the header. The words stay the guide. No fill, no ring, no pill. Motion is opacity/scale only; it stills under reduced-motion.
  • Why v1/v2 died: the filled 999px pill (v1) read as a patch button; the circled numeral (v2) still grouped ring + label + chevron into button anatomy — a ring around a number is button language regardless of fill. v3 has no fill, no border, no ring anywhere; the two typographic registers break the pressable-lockup gestalt.
  • Arrow when the chip opens a door, demoted to a whisper (12px, --fg-30). Hover reveals link-ness with a hairline underline on the words — never a background fill. Not a 3-step list, not a catalog banner, not a floating pill (2026-07-20). Preview stays the only amber badge.
  • Assistants-first: signup lands on this shelf. The chip coaches the action on the page (“Open one that fits →”) and scrolls to #assistants-shelf. Away from Assistants it reads STEP 1 “Pick an assistant →” and goes to /assistants.
  • Done when they start activation (Activate on a card / wizard opens). Then the chip advances to step 2 — no extra tap.
  • Catalog stays a shelf. No Start Here band. HelpFAB is unchanged.
MystFlo Platform Preview
· Peyton
Workspace
Assistants

You opened On-Brand Support. The wizard still needs a finish.

On-Brand Support
Continue where you left off — Personalize, Connect, Try.
Continue setup →
Step 2 — they picked one; it is not live yet
  • Chip advances the moment step 1 is done. Away from the wizard: 2 of 5 “Activate it →” reopens that assistant. On this page: “Finish setup to go live →” is the same door — ?continueActivation= reopens the wizard. A caption with no door is not the chip.
  • Brain and app connects live inside Activate — they are not their own header steps. Assistants-first stays the spine.
  • Done when one assistant is active. Chip advances to step 3 immediately.
MystFlo Platform Preview
· Peyton
Workspace
Pulse

Your active assistants

Runs this week
0
Health
MTD Cost
$0.00
Attention
Step 3 — an assistant is live; they have not seen Pulse yet
  • Away from Pulse: STEP 3 “See it on Pulse →” goes to /pulse. On Pulse: “Your first run lands here →” opens the Activity tab (/pulse?tab=activity) — the place runs land.
  • Done when they open Pulse after activation, or a run already exists. Chip then advances to the playbook — it does not disappear yet.
  • Pulse empty chrome stays the real tiles at zero (frame 2 on pulse.html) — the chip does not replace that page.
MystFlo Platform Preview
· Peyton
Workspace
Pulse

First run landed. The chip stays until the playbook is ready.

Step 4 — playbook first (Peyton 2026-08-16, writer Package A)
  • After Pulse, the same chip asks them to confirm the playbook so assistants sound like them. Not a visit-once step — the number is the playbook header’s % of required.
  • Away and on Brain: the chip opens the playbook via /brain#brain-landing-band. Away copy: “Make them sound like you · 38% →”. On Brain: “Every assistant reads this page” (no second %).
  • When the required playbook set is ready (threshold A), the chip advances to step 5 — it does not unmount here. Still after the first proof — Brain is not step 2. Opening /brain does not dismiss it.
MystFlo Platform Preview
· Peyton
Workspace
Brain

Playbook is ready. Drop what’s new — or re-read the site.

Step 5 — keep feeding the Brain (Peyton 2026-08-16)
  • After the four, the same chip points at the Teach share sheet: paste / file / screenshot / re-read the site. One door. Our read and research are not numbered chips.
  • Away: “Teach your Brain more →”. On Brain: “Drop what’s new — or re-read the site →”. Both open /brain?teach=1.
  • Unmounts after they open the Teach sheet once. Visiting /brain does not dismiss it. Never “learns” / “gets smarter.” On the Brain page itself: brain.html 9c (same file as the playbook — not a new mockup).
MystFlo Platform Preview
· Peyton
Header returns to the quiet identity line. Preview stays. No leftover coach.
Done
  • Members only. Guests never see the chip (they already have Get early access).
  • Chip is gone when pick → activate → Pulse → playbook are done and they have opened Teach once. Visiting /brain is not enough.
  • Not dismissible mid-path — it is one quiet line and it only shows the next hole.
Footer — flat (2026-06-07 lock · T444)
  • Single hairline top border, no edge-light, no glass ("light the perimeter, not the partitions").
  • Row 1 = signed-in view. Row 2 = guest: "Get early access" first in the link row, low-weight text link (never competes with the header CTA); members never see it.
MystFlo Platform Preview
· Peyton
768 uses the desktop header (shell at 768). Chip shortens if needed; name can drop before the chip does.
768 — same header row as desktop. Identity yields before the coach chip; Preview never yields.
Workspace
Support
Account
Mobile drawer
  • Header right slot = the wallet balance as quiet text (tap → TopUpModal) — the lone MEMBER badge is retired; badges never split left/right across the mobile header.
  • Rail never renders at mobile width — the drawer is the ONLY nav surface.
  • Full-width, slides in under the header (not over it); bg-black/80 backdrop closes on tap.
  • Labels always shown (no collapsed state); groups + Sign Out identical to desktop, full-width rows.
7Mobile 375 — guest state, CTA row + drawer (RS1, RS2 restore)
Page content scrolls here — the footer sits at the end
RS5 — footer at 375 (Footer.tsx)
  • Centered column: copyright line, then the link row wrapping centered — never desktop space-between squeezed narrow.
  • Same hairline-top-only treatment, no edge-light.
  • Guest variant shown (early-access link); members see the same stack minus that link.
10Boot watchdog — mobile 375, static shell (never mounted)
Assistants

Pre-built assistants. Pay only when they run.

On-Brand Support
Answers DMs in your voice, 24/7.
Workshop Booking
Takes the booking. You teach.
Below lg (1024) — coach is a PROGRESS BAND second header row (2026-08-16, supersedes the plain caption row)
  • Brand row stays 48px; the band gets its own 44px row — full-bleed --surface-el tone step (the "you are here" tone), single line mark · n of 5 · words · →, whole band is the tap. Band ≠ pill: full-bleed, zero radius, borderless, nothing pressable-looking.
  • The band's bottom edge is a real determinate line — lit white + glow to the required-% against a .12 track — and doubles as the header/page boundary (the header's own hairline is suppressed while the band lives). Steps 1–3 draw a 6% sliver; step 4 the real %; step 5 full-lit.
  • This tier runs from 375 up to lg (1024) — tablets use the band, not the desktop caption (Peyton 2026-08-16).
  • Preview and wallet stay on row 1. The chip never steals amber from Preview.
3cCoach step 2 — mobile 375
Assistants
On-Brand Support
Continue where you left off.
Step 2 at 375 — same row; copy swaps the moment activation starts.
3dCoach step 3 — mobile 375
Pulse

Your active assistants

Runs this week
0
Step 3 at 375 — tap opens the Activity tab, where runs land. After they land here, the row becomes the playbook.
3fCoach step 4 — mobile 375
Pulse

Chip stays. The number is the playbook %.

Step 4 at 375 — same second-row chip. Tap opens the playbook. The percent is the playbook header’s % of required. Visiting Brain does not dismiss it. When the required set is ready, the row becomes Teach.
3gCoach step 5 — mobile 375
Brain

Playbook is ready. Open Teach once, then the chip is gone.

Step 5 at 375 — same second-row chip. Tap opens the Teach sheet. Visiting Brain does not dismiss it. After one Teach open, the row is gone.
Guest
MystFlo Platform Preview
Workspace
Support
Account
Page content renders here (guest-visible pages only)
RS1 · RS3 — guest header + rail (BrandBlock / HeaderActions / UnifiedSidebar)
  • Guest has no balance or identity cluster — useWallet + name + sign-out render null while isGuest.
  • Header-right = the auth funnel: quiet "Sign in" text link + white "Get early access" pill (opens WaitlistModal) — the pill stays the surface's ONE lit object.
  • Brand badges: Preview only — the GUEST badge is retired (2026-07-24); the auth-funnel actions already say "guest", and one badge is the whole status axis.
  • Rail bottom Account-group row swaps Sign Out → Sign In (LogIn glyph, opens AuthModal) — same position and row shape (RS3). About MystFlo + Legal removed here too — the footer owns them for guests as well.
  • Footer link row carries "Get early access" first (guest-only, T444).
MystFlo Platform Preview
· Peyton
MystFlo Platform Preview
· Peyton
In context — the header band, low then empty
  • Row 1 = low balance in the live header slot; row 2 = empty. Healthy is the state every full frame above (1 · 2 · 3 · 6) already carries.
Healthy
Low
Empty
RS4 · #1956 — WalletBalancePill (now quiet text, no border/fill)
  • The bordered pill is retired — the balance renders as plain 13px tabular-nums text; hover tint is the tap affordance.
  • Stays monochrome in every state — low/empty = small amber status dot after the label only (color as accent, never surface fill).
  • Empty swaps the number for the literal label "Wallet empty".
  • Tapping any state opens TopUpModal — on desktop AND in the mobile header's right slot.
  • Hidden entirely under postpaid billing_mode and for guests/loading (no flash).
768 not yet drawn for this flow. Desktop and 375 are the contract.
Workspace
Support
Account
RS1 · RS2 — MobileActionBar
  • Guest-only second row under the brand row: same "Get early access" pill + "Sign in" link, compact.
  • The entire guest conversion surface on mobile; disappears when isGuest is false.
  • Drawer mirrors the desktop guest rail (Sign In replaces Sign Out at the bottom).
9Footer — mobile 375, stacked + centered (RS5 restore)
Failures
MystFlo Platform Preview
Workspace
Support
Account

Having trouble loading

This is on our side, not yours. We've been notified — reload this page, or pick another from the menu.

Boot watchdog — index.html inline <script> (#2908), shell restored 2026-08-10
  • Story: As a founder whose app never loaded, I want the menu and the way out still in front of me, so that a failed load costs me a click instead of stranding me on a dead page.
  • NEW (PRD debt) the watchdog has NO acceptance criterion in prd-pl-error-messages-self-recovery.md — it shipped in #2908 undocumented. Needs one: #root still empty 6s after load → static shell + message + one capped auto-report.
  • NEW (PRD debt) crash-surface parity is itself unspecified — nothing stops the layers drifting apart, which is what happened.
  • THE CHANGE — the shell is hand-drawn here, and that is what makes it possible. React never mounted, so this chrome cannot be the real PlatformLayout. The inline script paints a STATIC copy: wordmark, rail, footer. Every nav row is a plain <a href> — a full page load, which works with zero JavaScript. So the menu is not decorative; it genuinely navigates.
  • What the static shell deliberately omits: the balance / name / sign-out cluster, plus Usage and Sign In/Out. The watchdog has no auth state and must not guess — an empty header-right is honest, a fabricated one is not. The Preview badge is static (no popover — that is React). Wishlist and Feedback ARE shown (N6a, 2026-08-10): they are public routes present in both the guest and signed-in rail, so the omission rule — which covers only what this shell cannot know — never applied to them, and dropping them just shortened the fake menu for no honesty gain.
  • Cost, stated plainly: this grows the "deliberately dumb" inline script (#2908's founding principle was that it depends on nothing). Mitigation: one innerHTML template string, still zero imports, still inside the existing try/catch, still nothing that can throw. The mirror test covers the chrome values too.
  • Design: no icon; Reload not "Reload Page"; no "Send report" button (it already auto-reports silently, capped 1/session — a second control claiming to do what already happened is the dishonesty #2908 removed).
  • Design: no "Go to Explore" link — the rail carries navigation now, so the redundant escape is dropped. Escape-link rule holds: it appears only where there is no menu, which after this pass is nowhere.
MystFlo Platform Preview
· Peyton
Workspace
Support
Account

Something went wrong

This one's on us — your data is safe and we've been notified. Reload this page, or pick another from the menu.

Nested boundary — App.tsx:119, inside PlatformLayout (Peyton-locked 2026-08-10)
  • Story: As a founder whose page broke mid-task, I want the rest of the app to keep working, so that one bad page costs me a click instead of my whole session.
  • AC-ERRMSG-08 ↗ a React throw renders a recovery fallback with "your data is safe", never a blank page.
  • AC-ERRMSG-11 ↗ "Send report" carries the build id + the [DEPLOY-WINDOW] / [QA] Slack prefixes.
  • NEW (PRD debt) nothing in the PRD says the shell must survive a nested crash — the mount at App.tsx:119 exists to make that true but no criterion holds it. Needs one.
  • PRD drift ↗ AC-ERRMSG-08 still says "Go to Dashboard"; the code has said Go to Explore since #1114. Correct the PRD line in the same PR.
  • THE FIX — the boundary must stop claiming the viewport. Today it renders min-h-screen + centred flex unconditionally, so nested inside the content slot it paints a full-viewport block and reads as if it destroyed the shell — the header and rail were mounted the whole time, just shoved out of view. Nested renders .crash-inline (fills and centres in the content column, no viewport claim); only the root case keeps min-h-screen.
  • Nearly every page routes through this — Pulse, Brain, Billing, Assistants, Connects, Team all use WithLayout. This frame, not 11b, is the common case.
  • No "Go to Explore" here. The escape link exists to replace missing nav; the rail IS the nav. Rule: the escape appears only on a surface with no navigation (frames 10 and 11b). Copy shifts to "pick another from the menu" to point at the rail that is actually there.
  • Design: icon retired, one Reload label, one-sentence body — same three parity changes as the other layers.

Something went wrong

This one's on us — your data is safe and we've been notified. Reload this page, or pick another from the menu.

Want to tell us what happened? Opens a WhatsApp chat — remember to hit send.
Report-sent state — drawn as the content column alone
  • Only this region changes between idle and sent; the shell around it is frame 11 unchanged, so it is not redrawn.
  • Unchanged from today: "Send report" is the ONLY control that reports anything. WhatsApp appears only after a report succeeds — a failed report has no [ref:xxx] to anchor a chat to, so its honest fallback stays the support email. The copy still admits the chat needs you to hit send.
  • Emerald is the confirmation tick only (playbook §3 / C12) — the surface stays monochrome.
  • This is the tallest state, so it is the one scored against short viewports.
MystFlo Platform Preview
Workspace
Support
Account

Something went wrong

This one's on us — your data is safe and we've been notified. Reload this page, or pick another from the menu.

Root boundary — App.tsx:128, wraps the whole router
  • Story: As a founder whose crash landed outside any page, I want the same shell and the same menu, so that no failure in the product ever looks like a different product.
  • Catches what the nested boundary cannot: a throw in PlatformLayout itself, in a provider (Auth / QueryClient), or on a no-layout route (/auth/callback, /data-deletion-status, /s/:token).
  • ⚠ BUILD CONSTRAINT — read before implementing. This boundary must NOT render the real PlatformLayout: one of the things it catches is PlatformLayout (or a provider it depends on) throwing, and re-rendering the thing that just threw is an infinite crash loop. It renders the same hand-drawn static shell as frame 10 — markup only, no React layout component, no auth hooks, no useWallet. Identical chrome, different implementation, on purpose.
  • Same static-shell omissions as frame 10: no balance / name / sign-out (auth state may be exactly what broke), static Preview badge, nav rows as plain anchors.
  • This is the rarer of the two React cases — frame 11 is the common one.
  • Keeps "Send report" (React is running here, so the report button works); the watchdog does not (it auto-reports instead).
MystFlo Platform Preview
· Peyton
Workspace
Account
Updating to the latest version...
Stale-chunk beat — ErrorBoundary.tsx + @/lib/staleChunk.ts
  • Story: As a founder whose tab fell behind a deploy, I want the app to just fix itself without the page appearing to vanish, so that a routine release never looks like a crash.
  • AC-CORE-20 ↗ a replaced lazy chunk reloads once behind this line — not the error screen, no Sentry event, no Slack report.
  • AC-CORE-21 ↗ a second failure within 30s stops reloading and falls through to frame 11. The beat must never loop.
  • AC-ERRMSG-10 ↗ the version-skew interop signature gets ONE reload per session (it can match a genuine bug in prod), then reports.
  • Now inside the shell too. This branch is the nested boundary catching a stale chunk on a WithLayout page — the header and rail are mounted, so blanking them for a ~1s beat was the same min-h-screen bug in miniature, and the more jarring one because nothing was actually wrong. The full identity cluster stays live here (unlike frames 10 / 11c, React is healthy — only one chunk is stale).
  • Still deliberately NOT crash-surface language: no headline, no button, no report. A beat, not a screen. It now simply happens in the content column instead of over the whole app.
  • The root-boundary stale-chunk path keeps the shell-less treatment (nothing is mounted to sit inside).
MystFlo Platform Preview
· Peyton
Workspace
Support
Account
404

Page not found

This page doesn't exist — or it moved. Pick a destination from the menu.

404 — src/pages/NotFound.tsx, route path="*"
  • Story: As a founder who mistyped a URL or followed a dead link, I want to still be inside my workspace, so that a wrong address doesn't feel like being thrown out of the product.
  • THE FIX: today it renders min-h-screen centred with no shell, routed OUTSIDE WithLayout — the exact pattern retired in frames 10–12. It moves inside WithLayout and drops the viewport claim, same as the nested boundary.
  • Adopts the new language — the numeral keeps its extralight display treatment (it is the one place a big number is the point), but the headline, body, and control now match the crash surface. The old bordered "Back to home" pill in --hairline tokens goes.
  • ⚠ DECISION NEEDED — no refresh button here, and this is deliberate. A 404 is not a transient failure: refreshing re-requests the same missing route and returns the same 404, so a Reload control would be a button that visibly does nothing. The primary action is navigation, so the white pill carries Go to Assistants instead. If you want a refresh here anyway, say so and I'll swap it — but it would be the one control in this artifact that can't succeed.
  • Keeps the full identity cluster — React is healthy, nothing crashed, this is an ordinary page. Not a static shell.
  • NEW (PRD debt) no acceptance criterion covers the 404 surface at all.
MystFlo Platform Preview
· Peyton
Workspace
Account
Pulse
Your assistants and how they're running.
Active
On-Brand Support
Running · 12 runs this week
Retreat Booking
Running · 3 bookings taken
Recent runs

We couldn't load your recent runs. Nothing's wrong with your assistants — this is just the list.

Region scope — src/components/DataLoadError.tsx (currently ZERO consumers — dead code)
  • Story: As a founder whose runs list failed to load, I want to see that the LIST failed — not conclude I have no runs — so that a network blip never reads as lost work.
  • AC-ERRMSG-09 ↗ a failed data fetch shows a <DataLoadError> state with a "Try again" retry instead of silently rendering an empty state. This criterion does not currently ship — the component exists and nothing imports it.
  • THE REFRESH BUTTON. "Try again" with the refresh glyph is the control at this rung — it is the one place a refresh genuinely fixes the thing that failed (re-runs that one query, no page reload, nothing else disturbed).
  • Adopts the new language, one step down in scale — the scale difference IS the message. No 20px headline, no centred full column, no white pill: a 14px muted line and a quiet bordered retry, sitting inside the region that failed. A founder must be able to tell at a glance that the LIST broke, not the page. Matching the crash surface exactly here would be the bug, not the fix.
  • Its icon circle goes — the current component wraps RefreshCw in a bg-muted circle, the same retired pattern as the crash screen's ⚠. The glyph moves inline into the button, where it labels an action instead of decorating a state.
  • Copy names the blast radius explicitly ("Nothing's wrong with your assistants — this is just the list") — the empty-state confusion is the actual failure mode being designed against.
  • Scope note: the surrounding page renders normally — header, rail, page title, the sections that DID load. Only the failed region is replaced.
  • NOT in this PR. Adoption is a sweep across every read path and needs its own audit; this frame is the target so the sweep has a contract to build to.
MystFlo Platform Preview

Having trouble loading

This is on our side, not yours. We've been notified — reload this page, or pick another from the menu.

Tablet tier — the shell steps, the error column doesn't
  • Structure steps once: the rail collapses to the 64px icon-only variant at the shell's existing lg 1024 breakpoint (frame 2's behaviour — the crash surface inherits it, it does not invent its own).
  • The error column itself has no breakpoint: a 420px centred block at every width, from 375 up. Nothing collapses, nothing stacks inside it (kit canon U8 — structure steps only where the frames imply it, and here they imply nowhere).
  • What varies continuously: the content gutter, and the column's max-width:420px yielding to width:100% below ~420px.
  • Frames 11 / 11b / 11c inherit exactly this and are not redrawn per tier for that reason.

Having trouble loading

This is on our side, not yours. We've been notified — reload this page, or pick another from the menu.

Watchdog at 375 — static shell (index.html)
  • The mobile header + footer are hand-drawn too, same as desktop. The drawer toggle is the menu at this width — it must open a static list of anchors, NOT try to be the React drawer.
  • 375 is where the static-shell cost is worth re-checking: the rail is absent by design here, so the toggle is the only nav affordance. If the toggle cannot be made to work in plain DOM, the honest fallback at this width is the footer links, not a dead hamburger.
  • Reload holds its 44px touch target via padding, not type size.
  • Scored FIRST in the /design screenshot loop (kit canon U5) — desktop passing while this fails is a FAIL.
11Nested boundary — mobile 375, header survives (report sent)

Something went wrong

This one's on us — your data is safe and we've been notified. Reload this page, or pick another from the menu.

Want to tell us what happened? Opens a WhatsApp chat — remember to hit send.
Nested boundary at 375 (App.tsx:119)
  • The mobile header survives too — the drawer toggle stays reachable, so "pick another from the menu" is a real instruction at this width, not just on desktop.
  • Sent state drawn because it is the tallest — the one that can overflow a short phone viewport, so the one worth scoring.
  • The report button goes full-width below 420 (it already carries w-full sm:w-auto); everything above it stays centred.
  • Emerald is the confirmation tick only — the surface stays monochrome (playbook §3, C12).
3bCoach step 1 — mobile 375
Part II · Future — build later
No deferred frames — everything above is the current build (shipped #2597), except frames 10–12 which are the active build contract for the crash-surface parity pass (2026-08-10). The Usage nav row (frame 1) remains flagged "proposed" inline.