Clarity before change.

Independent website review

Big Picture Planner

Website review

A full source-code and hands-on review of what Big Picture Planner — our own product — ships, says and asks visitors to do.

Key judgement · Needs attention

None of this requires a redesign. It requires finishing the pivot, choosing one vocabulary, and cutting controls — the bones are good.

https://bigpictureplanner.app/

Inspected 13 July 2026

White-box review · full source access (our own product)

What we noticed

A clearer view of what the website is doing now.

A GreatInternet review of what Big Picture Planner says, shows and asks visitors to do—based on full source access and hands-on sessions: it is our own product, reviewed to the standard we sell.

Illustrative sampleFounder Strategy Review viewSave this view as PDF

What we looked at

Full source review (55 files, ~11,200 LOC) plus hands-on sessions in the live product as a first-time anonymous user, completed 13 July 2026 and accepted the same day. This pack translates that accepted audit and its implementation programme into our standard report contract; it is dated and presented as an assessment as of 13 July 2026, not a re-audit of the product as it stands today — the repository has moved on since. Sample pack authored under our own methodology, the same one we sell: it is our own product, reviewed to the same standard as a customer's.

The short version

Big Picture Planner has a genuinely strong foundation: the positioning is sharp, the landing page is disciplined and honest, the local-first architecture is the right call for a start-free funnel, and the planner contains more thoughtful engineering than most pre-seed products. The problems are not cosmetic, but they cluster into four fixable root causes — an unfinished repositioning, onboarding that competes with itself, controls that outnumber decisions, and an interaction grammar that changes per surface — sitting on architecture debt that makes every fix riskier than it should be.

None of this requires a redesign. It requires finishing the pivot, choosing one vocabulary, and cutting controls — the bones are good.

The first useful move

Restore the test suite as a deploy gate, then finish the pivot: remove founder-beta identity from the free path and sweep the vocabulary to one canonical set.

Overall signal

A directional view, not a grade.

needs attention

A genuinely strong foundation — sharp positioning, a disciplined landing page, real engineering craft — carrying meaningful, addressable gaps concentrated at exactly the activation moment: first-run onboarding, delete forgiveness, and interaction consistency.

What would strengthen it: Finish the pivot (identity, vocabulary), give onboarding one owner, and bring the interaction grammar to one rule per object — all scoped in the implementation programme below as a finishing pass, not a rebuild.

Meaningful gaps create friction or uncertainty and should be addressed deliberately.

The useful diagnosis

Biggest opportunity and biggest risk

Biggest opportunity

Four onboarding mechanisms compete for the same five seconds, and the tour intermittently eats the first click

medium confidence

A brand-new visitor sees an auto-starting spotlight tour, a "TRY THIS" card in the empty inbox, an empty-week prompt with three calls to action, and a dismissible save banner — all at once, in the first five seconds. Across two live sessions the spotlighted button and quick-add input repeatedly ignored the first trusted click or keystroke and accepted the second.

The pile-up itself (§6.1) was observed directly and is unambiguous; the click-swallowing sub-finding (§6.2) was reproduced repeatedly but the source audit flags it [verify by hand] pending reproduction on real hardware with a different pointing device.

Biggest risk

"FOUNDER BETA" badge and a dormant £40 paid flow still greet every free anonymous user

high confidence

The product pivoted from a paid founder-beta to free-while-we-build on 29 June 2026, but the old identity leaks everywhere: a hard-coded "FOUNDER BETA" badge greets every anonymous visitor, and a dormant £40 founding-access flow ("Your access needs renewing… £40 one-off founder price") remains reachable in code.

Directly evidenced by file:line citation and by the founder-decisions section explicitly asking whether early users should carry founder status.

Additional legacy finding

The "Life Inbox" rename never finished — four vocabularies for one concept, two for the product's core noun

high confidence

The panel was renamed app-wide to "Life Inbox", but the tour still says "Send it to Ready", Settings' replay copy says "add a task, send it to Ready", and the search placeholder reads "Search ready items...". Separately, block/task/item/event are used interchangeably for the one thing a user creates ("Add Task" FAB, "Add to Planner", "New Block", "Edit block", "your item").

Every instance is a direct file:line copy citation; this is a grep-verifiable class of finding.

Additional legacy finding

No edge-drag resize on calendar blocks — the single most-expected calendar gesture

high confidence

Scheduled blocks have no resize handle; duration can only be changed via keyboard +/- or the block editor's duration field, even though every mainstream calendar (Google, Apple, Outlook) has trained this gesture for over a decade.

Directly evidenced: the component has no resize logic and the underlying function already exists, unreachable by drag.

One immediate recommendation

  1. 01

    Restore the test suite so it can gate every later fix, then finish the pivot.

  2. 02

    Give onboarding exactly one owner and rebuild the tour so it never eats a click.

  3. 03

    Bring delete, resize and click behaviour to one predictable rule per object.

Full website audit

Everything we found, with the evidence behind it.

DimensionBandWhat we sawWhat would raise it
PositioningstrongThe landing page gives a 30-second answer to what this is, who it is for, what problem it solves and what to do first, and the FAQ pre-answers the account question.Nothing required — this is the strongest part of the product and should be left alone.
Journey & conversionneeds attentionThe promise of "start now, no account" is kept, but the arrival moment is chaotic (four competing onboarding surfaces) and anonymous cross-device users hit a silent data cliff.One onboarding owner, and a persistent (not one-shot) explanation of where data lives.
User experienceneeds attentionGenuinely thoughtful engineering underneath (overnight blocks, keyboard nudging, offline sync queue) sits alongside missing drag-resize, unconfirmed deletes, and inconsistent click grammar across surfaces.Ship the interaction-grammar and forgiveness (undo) work — the audit is explicit that none of this requires a redesign.
Trustneeds attentionA "FOUNDER BETA" badge and a dormant £40 paywall screen contradict the free positioning the landing page just promised.Finish the pivot: remove founder-beta artefacts from the free path and quarantine (not delete) the paid-access code.
Content & clarityneeds attentionA canonical vocabulary exists on paper (implementation-spec §7) but has not yet propagated everywhere — "Ready" vs "Life Inbox", "block" vs "task" vs "item", and a direct copy contradiction about whether calendar sync is enabled.Run the copy sweep already specced in §7.2 of the implementation plan; it is scoped as copy-only, zero behavioural risk.
Mobileneeds attentionTouch users cannot reach hover-only actions at all, and a separate responsive pass found column crowding on phones and a squeezed tablet mid-zone.Ship the action-bar (fixes touch-reachability) and the three responsive-integrity packets in the order the plan specifies.
needs attention
Meaningful gaps create friction or uncertainty and should be addressed deliberately.
strong
Clear, consistent evidence shows this area supports customer confidence and business goals.
Findings in severity order.
#SeverityFindingEffort
01highFour onboarding mechanisms compete for the same five seconds, and the tour intermittently eats the first clickhigh
02high"FOUNDER BETA" badge and a dormant £40 paid flow still greet every free anonymous userlow
03highThe "Life Inbox" rename never finished — four vocabularies for one concept, two for the product's core nounmedium
04highNo edge-drag resize on calendar blocks — the single most-expected calendar gesturemedium
05highDelete is instant, unconfirmed, and outside the undo systemmedium
06highThree unlabelled, overlapping size systems — the header "− 100% +" control is a text-scale masquerading as zoommedium
07highThe week toolbar packs five control groups and visibly truncates at common laptop widthsmedium
08highClick grammar changes per surface, and a slot click prefilled the wrong day/time in testinghigh
09mediumFilters don't carve reality at its joints, and Settings contradicts what the filters visibly domedium
10highA stale end-to-end suite means the funnel that matters is untested, sitting on five compounding debtshigh
11highAnonymous, cross-device users hit a silent data cliff with zero explanationmedium
12highNo focus trap in modals, and every hover-only action is unreachable on touch or keyboardmedium
13mediumThe Add-to-Planner modal offers five choices on first contact, one of them permanently disabledlow
14lowQuery fan-out and 672 droppable zones are fine today, a risk at scalelow
15mediumMobile week columns crowd and overlap; the 768-1000px tablet zone is squeezed by a fixed sidebarhigh
16mediumA failed drag paints native text selection across the whole grid; touch drag has no visible affordancelow
17highGoogle Calendar sync copy directly contradicts itself between the empty-week prompt and Settingslow

Strengths to preserve

  • The landing page is genuinely disciplined: one accent colour, generous spacing, consistent CTA styling, and a 30-second answer to what/who/why/what-next.
  • The local-first architecture (Dexie with a proper sync queue, retry/backoff, import-decision tracking) is the right call for a "start free, no account" funnel, and it is well engineered, not just present.
  • The planner contains real engineering craft most pre-seed products skip: overnight blocks, an all-day lane, keyboard nudging, a typed analytics taxonomy with an acquisition-to-activation funnel, and offline sync queueing.
  • The post-sign-in import-choice step (import local planner / keep device only / decide later) is genuinely well designed — the audit's main complaint is that almost no one will find it.
  • The drop-confirmation toast with Undo/Edit is excellent and is the exact pattern the delete-forgiveness fix reuses.

What to leave alone

  • The landing page's visual restraint and CTA discipline — the app should inherit it, not the other way around.
  • The local-first Dexie architecture and its sync queue.
  • The post-sign-in import-choice flow's design (only its discoverability needs work).
  • Existing keyboard shortcuts and the drop-confirmation toast pattern.

What we noticed · 1

medium confidence

Four onboarding mechanisms compete for the same five seconds, and the tour intermittently eats the first click

Severityhigh
Efforthigh
Confidencemedium
VerificationReproduced

Onboarding · Conversion · Onboarding

A brand-new visitor sees an auto-starting spotlight tour, a "TRY THIS" card in the empty inbox, an empty-week prompt with three calls to action, and a dismissible save banner — all at once, in the first five seconds. Across two live sessions the spotlighted button and quick-add input repeatedly ignored the first trusted click or keystroke and accepted the second.

What the evidence shows

Live testing sessions plus source review of the onboarding surfaces.

Evidence

OnboardingTour/component.tsx:283-301, 406-419, 443-444, 464-467; WeekGrid/component.tsx:439-481; ToSchedulePanel/component.tsx:181-195 (ux-audit-2026-07-13.md §6.1-6.3)

Likely root cause

Appears to be: Each onboarding mechanism was added to solve the same activation problem without retiring the previous one; the tour re-measures its spotlight every animation frame and toggles pointer-events per step instead of using one overlay that never intercepts.

Based on publicly available evidence; not verified.

Where it happens

First five seconds in the app, every new anonymous user

Why it matters

The single most important user moment — first activation — is also the most chaotic and least reliable one in the product; four overlapping mechanisms also make it impossible to attribute which one, if any, is doing the activating.

Worth doing next

Establish one onboarding owner (tour, then a single ambient empty-state card, then nothing); rebuild the tour spotlight as one masked overlay that never intercepts clicks inside its cut-out, replacing per-frame re-layout with ResizeObserver/scroll listeners.

medium confidence

The pile-up itself (§6.1) was observed directly and is unambiguous; the click-swallowing sub-finding (§6.2) was reproduced repeatedly but the source audit flags it [verify by hand] pending reproduction on real hardware with a different pointing device.

Verification · Reproduced

The behaviour was observed again on re-check.

How it was checked
Automated browser session: reloaded a fresh anonymous profile and interacted with the first spotlighted tour target and the quick-add input.
What was observed
The spotlighted "+ Add to Planner" button and the quick-add input ignored the first trusted click/keystroke and accepted the second, reproduced on 4 or more attempts; a programmatic .click() always worked, pointing at pointer-level interception rather than a broken handler.
Environment
Automated browser session (audit tooling). The source audit recommends reproducing by hand on real Chrome/Safari with a different pointing device before scheduling fixes.
Last checked
13 July 2026

What we noticed · 2

high confidence

"FOUNDER BETA" badge and a dormant £40 paid flow still greet every free anonymous user

Severityhigh
Effortlow
Confidencehigh

Trust · Positioning · Product strategy

The product pivoted from a paid founder-beta to free-while-we-build on 29 June 2026, but the old identity leaks everywhere: a hard-coded "FOUNDER BETA" badge greets every anonymous visitor, and a dormant £40 founding-access flow ("Your access needs renewing… £40 one-off founder price") remains reachable in code.

What the evidence shows

Source review of the header and access-gating components.

Evidence

PlannerHeader/component.tsx:63-69; AccessGate/component.tsx:335, 360-381 (ux-audit-2026-07-13.md §2 row 2, §4, §12.1)

Likely root cause

Appears to be: The free positioning shipped on the landing page and access gate while the user-visible founder-beta artefacts (badge, trial banners, the expired-access screen) were left in place rather than removed with the pivot.

Based on publicly available evidence; not verified.

Where it happens

Every anonymous session, from first load onward

Why it matters

A brand-new free user is labelled a founder-beta member and can, via the preserved-but-disabled trial/expired branches, be shown a £40 paywall screen that directly contradicts the "free while we build" promise the landing page just made.

Worth doing next

Remove the badge and trial-banner copy for free/anonymous users; quarantine the paid-access screens into a feature-flagged module that the free path never imports, rather than deleting the reference implementation outright.

high confidence

Directly evidenced by file:line citation and by the founder-decisions section explicitly asking whether early users should carry founder status.

What we noticed · 3

high confidence

The "Life Inbox" rename never finished — four vocabularies for one concept, two for the product's core noun

Severityhigh
Effortmedium
Confidencehigh

Ia copy · Ia copy

The panel was renamed app-wide to "Life Inbox", but the tour still says "Send it to Ready", Settings' replay copy says "add a task, send it to Ready", and the search placeholder reads "Search ready items...". Separately, block/task/item/event are used interchangeably for the one thing a user creates ("Add Task" FAB, "Add to Planner", "New Block", "Edit block", "your item").

What the evidence shows

Source review across tour, Settings, search and modal copy.

Evidence

OnboardingTour step copy; PlannerSetupPanel/component.tsx:107; ToSchedulePanel/component.tsx:145 (ux-audit-2026-07-13.md §2 row 3, §9.1, §9.2)

Likely root cause

Appears to be: The panel rename shipped in the primary surface but the copy sweep never propagated to satellite surfaces (tour, Settings replay text, search placeholder).

Based on publicly available evidence; not verified.

Where it happens

Any moment a user reads tour, Settings, or search copy

Why it matters

Users must learn that four different words mean one thing before the product feels coherent; a canonical vocabulary exists (implementation-spec §7) but nothing has enforced it yet.

Worth doing next

Sweep "Ready" → "Life Inbox" through tour copy, Settings replay copy, and the search placeholder; adopt one user-facing noun for the unit of work ("task") and reserve "block" for internal/code use only.

high confidence

Every instance is a direct file:line copy citation; this is a grep-verifiable class of finding.

What we noticed · 4

high confidence

No edge-drag resize on calendar blocks — the single most-expected calendar gesture

Severityhigh
Effortmedium
Confidencehigh

Interaction grammar · Interaction grammar

Scheduled blocks have no resize handle; duration can only be changed via keyboard +/- or the block editor's duration field, even though every mainstream calendar (Google, Apple, Outlook) has trained this gesture for over a decade.

What the evidence shows

Source review of the scheduled-block component and its duration-change paths.

Evidence

ScheduledBlock (734-line component, no resize logic); resizeBlockDuration reachable only via AppShell:389 keyboard path (ux-audit-2026-07-13.md §2 row 4, §6.6)

Likely root cause

Appears to be: The interaction budget went to dnd-kit move; resize was implemented for keyboard only and never extended to a drag handle.

Based on publicly available evidence; not verified.

Where it happens

Any moment a user wants to change how long a scheduled task takes

Why it matters

Every user coming from any mainstream calendar hits a missing gesture they expect to just work, on the core weekly-planning surface.

Worth doing next

Add top and bottom drag handles that map to the existing resizeBlockDuration function, with 15-minute snap and a live time label while resizing.

high confidence

Directly evidenced: the component has no resize logic and the underlying function already exists, unreachable by drag.

What we noticed · 5

high confidence

Delete is instant, unconfirmed, and outside the undo system

Severityhigh
Effortmedium
Confidencehigh

Interaction grammar · Trust · Interaction grammar

Hovering "×" on an inbox card deletes it immediately; Backspace/Delete removes the selected block immediately. The undo system explicitly scopes itself to movements only — deletes and edits are not undoable — and although deletion is a soft delete in the database, no UI ever lists or restores what was deleted.

What the evidence shows

Source review of delete handlers and the undo/history service.

Evidence

ToSchedulePanel:357-368; AppShell:366-369; blockHistory.ts:1-8 (scopes undo to movements); plannerActions.ts:72 (soft delete, no restore UI) (ux-audit-2026-07-13.md §2 row 5, §6.7)

Likely root cause

Appears to be: The undo/history model was built for block movement and never extended to cover the delete action, even though the underlying soft-delete data already exists to make an undo path possible.

Based on publicly available evidence; not verified.

Where it happens

Any delete action, from either the inbox or the scheduled week

Why it matters

Every user — and disproportionately the product's explicit ADHD/busy-mind audience — is one accidental keypress or hover-click from an unrecoverable-feeling loss, despite the data technically surviving in the database.

Worth doing next

Route every delete path through one handler that shows an 8-second "Deleted 'X' — Undo" toast (reusing the existing DropConfirmationToast pattern) and folds deletes/restores into the history stack alongside movements.

high confidence

Directly evidenced by file:line citation of both the delete paths and the history model's explicit movement-only scope.

What we noticed · 6

high confidence

Three unlabelled, overlapping size systems — the header "− 100% +" control is a text-scale masquerading as zoom

Severityhigh
Effortmedium
Confidencehigh

Ui controls · Ui controls

The header "− 100% +" control uses the universal glyph grammar for zoom but only scales font size (90-130%) via a CSS variable — grid geometry, block sizes and layout never change. It coexists with a second system (Compact/Comfortable/Spacious row density in the toolbar) and a third on mobile (real pixel zoom via pinch plus a separate ± stepper). None of the three is labelled with what it actually changes.

What the evidence shows

Source review of the header text-scale control, the toolbar density control, and the mobile zoom stepper.

Evidence

AppShell:34-36, 258-269 (--planner-text-scale); WeekGrid:29-33 (ZOOM_SCALE density); WeekGrid:23-27, 583-608 (MOBILE_HOUR_* pinch zoom) (ux-audit-2026-07-13.md §2 row 6, §7.1)

Likely root cause

Appears to be: Each size mechanism was added independently to answer a different, unstated question ("how big is the text", "how tall is a row", "how much fits on a small screen") using the same +/- visual grammar without anyone naming what each one changes.

Based on publicly available evidence; not verified.

Where it happens

Any moment a user reaches for a size control, on any surface

Why it matters

The founder's own flagged question — "why does the +/- feel disconnected from what I see happen" — has a precise, fixable answer: it changes something real but subtle, while looking like it should change everything.

Worth doing next

Decide the one thing "size" means per platform, label each control by what it changes ("Text size" / "Row height"), and collapse density and hours into a single "View" popover.

high confidence

Directly evidenced across three separate, cited implementations of size controls with no shared vocabulary.

What we noticed · 7

high confidence

The week toolbar packs five control groups and visibly truncates at common laptop widths

Severityhigh
Effortmedium
Confidencehigh

Ui controls · Ui controls

At 1280×720 the toolbar shows "Day/Week/Month | 7-day week/5+2 week | Compact/Con…" with the title truncated to "Fit your…" and the density control clipped mid-word; remaining controls sit off-screen in an unsignposted horizontal scroll. A duplicate, hidden density <select> ships to production.

What the evidence shows

Source review and viewport testing of the week toolbar at 1280×720.

Evidence

week-grid-controls, WeekGrid:278 (overflow); ZoomSelect duplicate, WeekGrid:483-494, class "hidden" (ux-audit-2026-07-13.md §2 row 7, §7.2)

Likely root cause

Appears to be: Every view option earned its own permanent segmented control over time, and CSS hides/swaps variants per breakpoint instead of the component tree deciding what to render.

Based on publicly available evidence; not verified.

Where it happens

Any visit at a common laptop width (1280px and below)

Why it matters

The app's own value statement is cut off at the most common laptop width, and shipping a hidden, non-functional duplicate control is dead weight in production.

Worth doing next

Extract the toolbar to its own component (pure refactor, unblocks the redesign), then consolidate week-span, density and hours into a single "View" popover so the resting toolbar fits at 320px.

high confidence

Directly evidenced by viewport testing plus file:line citation of the hidden duplicate control.

What we noticed · 8

medium confidence

Click grammar changes per surface, and a slot click prefilled the wrong day/time in testing

Severityhigh
Efforthigh
Confidencemedium
VerificationReproduced

Interaction grammar · Interaction grammar

A single click edits an inbox card, selects a scheduled block, and opens a month chip — three different outcomes for the same gesture depending on which object is clicked. Separately, clicking Wednesday ~10:00 on the week grid opened the block editor prefilled with Sunday 19/07/2026, 17:15-17:45.

What the evidence shows

Source review of click handlers across inbox, week and month surfaces, plus a live-session reproduction of the slot-click prefill.

Evidence

ToSchedulePanel:245-252 (inbox single-click = edit); ScheduledBlock:64-89 (block single-click = select); WeekGrid:825-831 (month chip single-click = edit) (ux-audit-2026-07-13.md §2 row 8, §6.8, §6.5)

Likely root cause

Appears to be: No single interaction grammar was ever specified across the inbox, week and month surfaces, so each was implemented independently; the slot-click prefill is suspected to be coordinate math that breaks when the grid has scrolled or when the text-scale variable is not 1.

Based on publicly available evidence; not verified.

Where it happens

Any click, on any of the three primary surfaces

Why it matters

Felt by every user as "sometimes it opens, sometimes it doesn't"; if the prefill mismatch reproduces on real hardware it silently schedules a task on the wrong day, which is a correctness failure, not just a UX one.

Worth doing next

Adopt one rule everywhere: single click = select (with a floating action bar), double-click/Enter = edit. Independently verify the slot-prefill mismatch by hand and write a dedicated regression test for it before scheduling the wider grammar fix.

medium confidence

The click-grammar inconsistency is directly evidenced by file:line citation across three components; the prefill mismatch is flagged [verify by hand] in the source audit because the reproducing session was interrupted before it could be re-verified.

Verification · Reproduced

The behaviour was observed again on re-check.

How it was checked
Live session: clicked the week grid at approximately Wednesday 10:00 and inspected the resulting block editor's prefilled date/time.
What was observed
The editor opened prefilled with Sunday 19/07/2026, 17:15-17:45 rather than the clicked day and time. Could not be re-verified in the same session due to tool interruptions.
Environment
Automated browser session. The source audit recommends manual verification across zoom levels and suspects coordinate math when the grid has scrolled or planner-text-scale is not 1.
Last checked
13 July 2026

What we noticed · 9

high confidence

Filters don't carve reality at its joints, and Settings contradicts what the filters visibly do

Severitymedium
Effortmedium
Confidencehigh

Ia copy · Ia copy

"Manual" matches sourceType === 'manual'; "Planner-created" matches manual OR template — for a user with no templates the two filters are functionally identical. Meanwhile Settings → Filters says "Full saved views and custom labels are not enabled yet", reading as if the visible filters don't exist at all.

What the evidence shows

Source review of the filter predicates and the Settings Filters section copy.

Evidence

plannerFilters.ts:30-36; PlannerSetupPanel:76 (ux-audit-2026-07-13.md §2 row 9, §9.3)

Likely root cause

Appears to be: The filter axis mixes provenance (how a task got here) with content-type (what kind of task it is) on one dimension, and the Settings copy was written for a different, earlier state of the feature.

Based on publicly available evidence; not verified.

Where it happens

Any moment a user opens filters or Settings → Filters

Why it matters

A user who tries "Manual" and "Planner-created" separately sees the same list twice and reasonably concludes the feature is broken, which Settings then appears to confirm.

Worth doing next

Replace the current filters with one provenance axis (Created here / Imported) plus a separate "Show travel time" display toggle, and make the Settings copy state truthfully what is and isn't configurable.

high confidence

Directly evidenced by the filter predicate source and the contradicting Settings copy, both file:line cited.

What we noticed · 10

high confidence

A stale end-to-end suite means the funnel that matters is untested, sitting on five compounding debts

Severityhigh
Efforthigh
Confidencehigh

Architecture · Architecture

e2e/access-flow.spec.ts asserts the previous funnel (an "I have a code" nav link, a "Log in" label, "Like Tetris for your real life" copy) — none of which exist on the current landing page. The suite cannot be green, so it isn't gating deploys. This sits alongside no router (view/drawer state is un-addressable, back button exits the app), a global window-event bus, five monolithic components (WeekGrid 1,079 lines, AppShell 982, ScheduledBlock 734), and CSS selectors coupled to DOM order via nth-of-type.

What the evidence shows

Source review of the e2e suite, routing approach, event architecture, component sizes, and CSS selectors.

Evidence

e2e/access-flow.spec.ts; App.tsx (pathname.endsWith string-matching); WeekGrid/AppShell/ScheduledBlock/OnboardingTour/BlockEditor line counts; index.css:426-427, 839-840 (nth-of-type) (ux-audit-2026-07-13.md §2 row 10, §11.1-11.6)

Likely root cause

Appears to be: Test and architecture debt accumulated incrementally without a restoring pass; each new UX fix now has to land inside one of five oversized components, guarded by a test suite that cannot currently fail honestly.

Based on publicly available evidence; not verified.

Where it happens

Every future change to the product; no single user-facing moment

Why it matters

Every fix recommended elsewhere in this audit lands on top of this debt and inherits its risk; specifically, the free→first-task funnel — the entire acquisition strategy — currently has no passing automated coverage.

Worth doing next

Restore the e2e suite to describe the current funnel before any other packet lands (it becomes the deploy gate for everything else); introduce a small overlay-history hook in place of a full router; replace nth-of-type CSS coupling with explicit classes; extract the toolbar and tour engine as the two enabling refactors that unblock the highest-value UX fixes.

high confidence

Directly evidenced by file:line citation and line counts across the cited components and test files.

What we noticed · 11

high confidence

Anonymous, cross-device users hit a silent data cliff with zero explanation

Severityhigh
Effortmedium
Confidencehigh

Onboarding · Trust · Onboarding

Two live sessions on fresh profiles each began from zero with the tour restarted, on a different browser/device or after cleared storage. Nothing in-product explains device-bound storage after the one-shot save banner is dismissed once (the dismissal is permanent).

What the evidence shows

Live session testing across two fresh anonymous profiles.

Evidence

bpp_save_banner_dismissed (permanent dismissal key) (ux-audit-2026-07-13.md §3, §6.9)

Likely root cause

Appears to be: The only explanation of local-first, device-bound storage is a dismissible banner shown once; there is no persistent, ambient indicator of where data lives once that banner is gone.

Based on publicly available evidence; not verified.

Where it happens

Any return visit on a new device or after cleared storage

Why it matters

To the user this reads as data loss, not as an explainable consequence of a local-first architecture — a serious trust cost for a product whose entire pitch depends on "start free, no account".

Worth doing next

Replace the one-shot banner with a persistent, subtle "Saved on this device — N items" indicator, and re-surface a login nudge at meaningful thresholds (task count, distinct days of use) rather than once and never again.

high confidence

Directly observed in two separate live sessions with a cited, verifiable mechanism (the permanent dismissal key).

What we noticed · 12

high confidence

No focus trap in modals, and every hover-only action is unreachable on touch or keyboard

Severityhigh
Effortmedium
Confidencehigh

Accessibility · Accessibility

Focus can Tab out of the Add-to-Planner modal and the block editor into the dimmed page behind them (both are plain fixed divs with only an initial .focus() call). Edit/duplicate/delete actions on cards and blocks are hover-only, making them unreachable on touch and invisible to keyboard users until a focus quirk happens to reveal them.

What the evidence shows

Source review and accessibility-tree inspection of the modal, editor, and card/block action clusters.

Evidence

(no focus trap: modal/editor are plain fixed divs); hover-only action clusters (ux-audit-2026-07-13.md §10)

Likely root cause

Appears to be: Modals were implemented without a shared focus-trap utility, and card/block actions were designed around hover discovery without a keyboard- or touch-visible equivalent.

Based on publicly available evidence; not verified.

Where it happens

Any modal/drawer interaction for a keyboard user; any card/block action for a touch or keyboard user

Why it matters

Screen-reader and keyboard users can lose their place entirely inside an open modal, and touch users — a majority of real-world usage — cannot reach edit/duplicate/delete at all without the alternate selected-state action bar this audit recommends.

Worth doing next

Apply a shared focus-trap hook to every modal/drawer/popover, and replace hover-only action clusters with a selected-state action bar reachable by tap, click, and keyboard alike (the mobile sheet component already prototypes this pattern).

high confidence

Directly evidenced by source review of the modal implementation and the hover-only action-cluster markup.

What we noticed · 13

high confidence

The Add-to-Planner modal offers five choices on first contact, one of them permanently disabled

Severitymedium
Effortlow
Confidencehigh

Ia copy · Conversion · Ia copy

Both entry points ("+ Add to Planner" sidebar, "Add Task" FAB — themselves two labels for one action) open a five-option modal: quick-add, "New Block", "Import from Source", "Import Calendar", and a permanently disabled "Templates (Coming Soon)" row. "Import from Source" is internal jargon for "paste a list"; "New Block" exposes an internal noun.

What the evidence shows

Source review of the Add-to-Planner modal and its two entry points.

Evidence

AddToPlannerModal (five options); FAB "Add Task" vs sidebar "+ Add to Planner" (ux-audit-2026-07-13.md §5)

Likely root cause

Appears to be: The modal accumulated one row per feature (quick add, new block, two import paths, templates) without anyone later collapsing it back down once templates were disabled and imports matured.

Based on publicly available evidence; not verified.

Where it happens

The very first "add something" action a new or returning user takes

Why it matters

A user who already chose "add" once (via FAB or sidebar) is asked to choose again from five options, one of them dead, before reaching the one thing most users want: quick capture.

Worth doing next

Reduce the modal to three options — quick add (first, autofocused), "New task with details", and a single "Import…" row that opens a two-tab view (Paste a list / Calendar) — and delete the disabled Templates row from the modal (it stays reachable in the sidebar panel).

high confidence

Directly evidenced by source review of the modal's option list and both entry-point labels.

What we noticed · 14

medium confidence

Query fan-out and 672 droppable zones are fine today, a risk at scale

Severitylow
Effortlow
Confidencemedium

Performance · Performance

Each day column runs its own live query (7×), on top of the week grid's, AppShell's, the Today panel's and the month panel's (roughly 11 concurrent live queries), and week view mounts 672 droppable zones (24 hours × 4 × 7 days).

What the evidence shows

Source review of the live-query usage and droppable-zone construction.

Evidence

DayColumn per-column useLiveQuery (×7); WeekGrid week query; ~11 concurrent live queries; 672 useDroppable slots (ux-audit-2026-07-13.md §11.7)

Likely root cause

Appears to be: Each component that needed live data queried independently rather than sharing a consolidated query, and the droppable-slot model is per-cell rather than pointer-math-based.

Based on publicly available evidence; not verified.

Where it happens

Any session with many imported calendar events, especially on low-end devices

Why it matters

Fine at today's typical usage (~50 blocks); a growing base of imported-calendar users on lower-end devices is where this would first be felt, as dropped frames during drag or scroll.

Worth doing next

Do not build a fix speculatively. Profile first with roughly 300 blocks plus a Google Calendar import on a throttled CPU; only pursue slot-droppable virtualisation or query consolidation if the profile shows a real problem.

medium confidence

The counts (queries, droppable zones) are directly evidenced by source review; the felt-impact-at-scale claim is a reasoned projection, not yet measured — which is exactly why the recommendation is "measure first".

What we noticed · 15

medium confidence

Mobile week columns crowd and overlap; the 768-1000px tablet zone is squeezed by a fixed sidebar

Severitymedium
Efforthigh
Confidencemedium

Mobile layout · Mobile layout

A later, separate responsive-integrity pass (9 widths, 320-1440px) found narrow, hard-to-read day columns and label overlap on mobile, the sticky day-header overlapping the first block row, floating controls (FAB, storage banner, Life Inbox tray) covering content or each other, and a 768-1000px tablet band where a fixed 240px Life Inbox sidebar squeezes the grid to unreadable column widths.

What the evidence shows

Documented directly in the implementation specification's Phase 11 (added 2026-07-20), which this pack treats as source; the underlying raw diagnostic (responsive-report.json) was not reviewed for this pack.

Evidence

implementation-spec-2026-07-13.md §"Phase 11 — Responsive integrity" (lines 641-667): defects M1-M5, T1

Likely root cause

Appears to be: Mobile layout was derived from the desktop column model rather than designed for its own constraints, and several floating UI elements (FAB, banner, tray) were positioned without checking for overlap against each other or against content.

Based on publicly available evidence; not verified.

Where it happens

Any session on a phone (320-430px) or a small tablet (768-1000px)

Why it matters

Mobile is a compressed desktop rather than a first-class surface, which directly works against a product whose target audience (parents, shift workers, busy minds) is disproportionately likely to reach for it on a phone.

Worth doing next

Fix the unambiguous overlap and crowding defects first (header/block overlap, floating-control collisions), then the column-width/snap change, then the tablet mid-zone — in that order, re-running the diagnostic after each, with desktop 1280/1440 verified unchanged throughout.

medium confidence

This finding is translated from the implementation specification's own description of a separate audit (its underlying diagnostic report was not itself reviewed for this pack), so confidence reflects secondhand sourcing rather than direct observation by this document's authors.

What we noticed · 16

medium confidence

A failed drag paints native text selection across the whole grid; touch drag has no visible affordance

Severitymedium
Effortlow
Confidencemedium
VerificationReproduced

Interaction grammar · Mobile layout · Interaction grammar

A failed or slow drag from the inbox painted a native browser text selection across the entire grid — hour gutter, day headers and toolbar all became selectable. Touch drag additionally requires a 420ms hold with no visible affordance teaching users it exists.

What the evidence shows

Live session testing of drag initiation from the inbox.

Evidence

Missing user-select: none guard on grid chrome during drag; 420ms long-press activation (ux-audit-2026-07-13.md §7.5)

Likely root cause

Appears to be: Grid chrome has no user-select: none guard applied during an active drag, and the long-press activation for touch has no accompanying visual cue.

Based on publicly available evidence; not verified.

Where it happens

Any drag-initiation attempt, especially a slow or interrupted one

Why it matters

A cosmetic-looking but disorienting failure mode right at the product's core gesture (drag from inbox to week), and touch users have no way to discover the hold-to-drag gesture exists.

Worth doing next

Apply user-select: none to grid chrome during any active drag (desktop and touch), and pair the long-press activation with a visible affordance.

medium confidence

Observed directly in a live session but flagged [verify by hand] in the source audit alongside the other automated-session findings.

Verification · Reproduced

The behaviour was observed again on re-check.

How it was checked
Live session: initiated a slow/failed drag from an inbox card across the week grid.
What was observed
A native text selection painted across the hour gutter, day headers and toolbar, none of which have a user-select: none guard applied during drag.
Environment
Automated browser session. Grouped with the audit's other [verify by hand] items pending reproduction on real hardware.
Last checked
13 July 2026

What we noticed · 17

high confidence

Google Calendar sync copy directly contradicts itself between the empty-week prompt and Settings

Severityhigh
Effortlow
Confidencehigh

Ia copy · Ia copy

The empty-week prompt states "Google Calendar syncs live. Apple Calendar imports via a .ics file." while Settings → Sources states "Calendar connections are not enabled yet." One of these is wrong; both are shipped.

What the evidence shows

Source review of the empty-week prompt copy and the Settings Sources section.

Evidence

WeekGrid:468-470; PlannerSetupPanel:360 (ux-audit-2026-07-13.md §9.4)

Likely root cause

Appears to be: The two copy locations were written at different times against different states of the sync feature and were never reconciled once sync actually shipped.

Based on publicly available evidence; not verified.

Where it happens

Any moment a user reads both the empty-week prompt and Settings → Sources

Why it matters

A user who reads Settings after seeing the empty-week prompt reasonably concludes the product is unreliable about what it can actually do.

Worth doing next

Resolve both locations to the true statement: Google Calendar syncs live, Apple Calendar imports via .ics.

high confidence

Directly evidenced by two contradicting file:line citations.

Accessibility note: This assessment identifies observed accessibility considerations from the tested evidence. It is not a formal accessibility conformance certification or legal opinion.

Technical note: Technical observations reflect the tested environment and evidence available during this assessment. Behaviour may vary by device, browser, session state or subsequent site changes.

Website Review & Implementation Pack

The plan, packets and tracking materials for the work.

Master implementation objective

Fix the four root causes behind the audit's ~45 symptoms — an unfinished repositioning, self-competing onboarding, control proliferation, and inconsistent interaction grammar, all sitting on architecture debt — in dependency order, so each symptom falls out of the root-cause fix it belongs to. This is a finishing pass on a product whose bones are good, not a redesign.

Guiding principles

  • One concept = one name. The canonical vocabulary is law; no synonym survives in user-facing copy, aria-labels, or analytics event names.
  • One interaction = one outcome. The interaction grammar applies to every object; deviations require a written reason in the packet.
  • Reduce cognitive load; prefer removal over explanation. If a control needs a tooltip essay, question the control.
  • Progressive disclosure over persistent chrome. Rarely-changed settings live behind one popover or in Settings, not the always-visible toolbar.
  • Destructive must be forgivable. Any action that removes user data gets an undo path; no confirmations-as-friction, undo-toasts instead.
  • Never regress accessibility. Each packet's checklist includes: keyboard path exists, focus visible, names announced.
  • Local-first stays sacred. No packet may make any core flow require a network call or an account.
  • Deployable at every commit. No packet may leave dead routes, half-renamed copy, or a red test suite "to be fixed in the next packet".

Preserve throughout

  • localStorage keys are never repurposed; new keys read old values once and migrate.
  • No Dexie schema version bump anywhere in this plan.
  • No Supabase RPC or table changes; restore-after-delete uses the existing upsert path.
  • Analytics only ever gains events — existing event names are never renamed or removed.
  • Code identifiers (ToSchedulePanel, PlannerBlock, the blocks table, localStorage keys, data-tour anchors) are never renamed — the user-facing vocabulary sweep is copy-only.
  • The landing page's visual system — the strongest asset in the product — is untouched by this entire plan.

Numbered work packets

Packet 0.1 · Phase 0 — Restore the safety net

Packet 0.1 — Rewrite stale funnel e2e specs

Make the Playwright suite describe the current free funnel so it can gate every later packet.

Exact implementation

  • Rewrite e2e/access-flow.spec.ts to assert the current free funnel.
  • Quick-audit other specs for stale copy assertions from the old funnel.

Acceptance criteria

  • Suite asserts: landing nav has "Start planning free" → /planner/.
  • Login nav link → /planner/sign-in.
  • Planner loads ungated with Life Inbox visible.
  • No assertions remain on removed copy.

Preserve

    Verification

    • npx playwright test green
    • preflight green including e2e

    Dependencies: None · Rollback: Revert; no product surface touched (this packet only changes test files).

    Packet 1.1 · Phase 1 — Vocabulary & copy sweep

    Packet 1.1 — Canonical vocabulary sweep (app)

    Apply the §7.2 table rows for all src/ surfaces (not landing).

    Exact implementation

    • Apply every §7.2 table row across the 9 named components (OnboardingTour, PlannerSetupPanel, ToSchedulePanel, AddToPlannerModal, BlockEditor, AppShell, WeekGrid, PlannerHeader, Sidebar).
    • Resolve the Google Calendar copy contradiction: Settings → Sources states sync truthfully.
    • Update any e2e copy assertions the sweep touches, in the same commit.

    Acceptance criteria

    • The §7.3 grep checklist passes (zero forbidden terms rendered).
    • Tour, modal, editor, inbox and settings read in canonical vocabulary.
    • Google Calendar copy contradiction resolved to the true statement.

    Preserve

    • data-tour anchors unchanged
    • Code identifiers (§7.4) unchanged — only user-facing copy moves

    Verification

    • grep checklist over src/ + landing/ for forbidden terms
    • manual read-through

    Dependencies: None · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

    Packet 1.2 · Phase 1 — Vocabulary & copy sweep

    Packet 1.2 — Canonical vocabulary sweep (landing)

    Apply the §7.2 landing rows: nav "Log in" (title keeps save framing), footer Refunds removal.

    Exact implementation

    • Landing nav: relabel "Save your planner" to "Log in" (title/aria keeps the save framing).
    • Remove the footer "Refunds" link until something is purchasable.
    • Apply the same nav block change to satellite pages sharing the nav.

    Acceptance criteria

    • All landing pages show "Log in" in nav.
    • No "Refunds" footer link remains live.
    • Existing src= params preserved.

    Preserve

    • bppTrack event names
    • waitlist/founder JS (dormant by design, untouched)
    • existing src= tracking params

    Verification

    • grep across landing/*.html
    • preflight green (build assembles landing into dist)

    Dependencies: None · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

    Packet 2.1 · Phase 2 — Identity & state cleanup

    Packet 2.1 — Remove founder-beta identity from free users

    Free/anonymous users see no founder/beta/trial identity; quarantine premium screens.

    Exact implementation

    • Delete the badge in PlannerHeader/component.tsx.
    • Replace TrialBanner copy with a neutral "Early access — your feedback shapes what's next", shown only for trial|comped.
    • Move SignInScreen, CodeEntryScreen, TrialExpiredScreen into src/components/AccessGate/premiumGating.tsx, imported only under PREMIUM_GATING.

    Acceptance criteria

    • Anonymous header shows no badge.
    • grep "Founder Beta" in rendered free-path code → 0.
    • Unit test matrix: each AccessStatus → expected banners.

    Preserve

    • PREMIUM_GATING flag and behaviour
    • RefundWindowBanner (applies to genuinely paid legacy users)

    Verification

    • screenshots signed-out header
    • new unit test file passes

    Dependencies: None · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

    Packet 3.1 · Phase 3 — Forgiveness: delete joins undo

    Packet 3.1 — Deletes join the undo system

    Every delete shows an undo toast; Cmd+Z restores deletes.

    Exact implementation

    • blockHistory.ts: snapshot gains deletedAt; recordMovement handles delete/restore entries.
    • plannerActions.ts: deleteBlock records history; add restoreBlock.
    • AppShell/component.tsx: a DeleteToast reusing the DropConfirmationToast pattern; wire all delete callsites through one handler.
    • Route ToSchedulePanel, ScheduledBlock and BlockEditor deletes through the shared handler.

    Acceptance criteria

    • Delete via hover ×, Backspace, action-menu, editor → toast with working Undo.
    • Cmd+Z after delete restores the block to its exact prior state (inbox or scheduled slot).
    • Redo re-deletes; extended undo-redo.spec.ts passes.

    Preserve

    • GCal cache blocks keep hard-delete semantics

    Verification

    • run extended undo-redo.spec.ts
    • manual signed-in delete→undo→sync-state check
    • grep deleteBlock( callsites to confirm none bypass the handler

    Dependencies: None · Rollback: Revert; soft-delete semantics unchanged underneath.

    Packet 4.1 · Phase 4 — Enabling refactors

    Packet 4a.1 — Extract WeekToolbar (pure refactor)

    Move the toolbar JSX and its controls from WeekGrid into src/components/WeekToolbar/component.tsx with identical rendering; delete the hidden ZoomSelect.

    Exact implementation

    • Extract the toolbar JSX into src/components/WeekToolbar/component.tsx.
    • Communicate via props only; persisted-setting hooks stay in WeekGrid and pass down.
    • Delete the hidden ZoomSelect duplicate (WeekGrid:483-494).

    Acceptance criteria

    • Pixel-identical toolbar at 375/768/1280/1536 (manual screenshot diff).
    • All view controls function.
    • ZoomSelect is gone.

    Preserve

    • Zero visual/behavioural change except the invisible dead select's removal

    Verification

    • screenshots before/after
    • suite green

    Dependencies: None · Rollback: Each Phase 4 packet reverts independently.

    Packet 4.2 · Phase 4 — Enabling refactors

    Packet 4b.1 — Remove nth-of-type responsive coupling

    Replace .week-grid-controls > div:nth-of-type(…) rules with explicit classes (.toolbar-density, .toolbar-hours, …) or useIsMobile() conditional rendering; delete the "must be a span" workarounds.

    Exact implementation

    • Replace the nth-of-type rules in index.css (412-440, 803-840 region) with explicit classes.
    • Update WeekToolbar and WeekGrid to render those explicit classes / use useIsMobile() conditionals.
    • Delete the DOM-order-dependent comments/workarounds.

    Acceptance criteria

    • grep nth-of-type in index.css scoped to toolbar → 0.
    • Breakpoint screenshots identical to before.
    • Month view still hides density/hours as before.

    Preserve

    • Month-view hide rules, via the new classes

    Verification

    • grep nth-of-type scoped check
    • breakpoint screenshot sweep

    Dependencies: 4.1 · Rollback: Each Phase 4 packet reverts independently.

    Packet 4.3 · Phase 4 — Enabling refactors

    Packet 4c.1 — Overlay/back handling hook

    Browser Back closes the top overlay instead of leaving the app.

    Exact implementation

    • New src/hooks/useOverlayHistory.ts using history.pushState/popstate with a state marker.
    • Wire into AddToPlannerModal, BlockEditor, PlannerSetupPanel, SyncStatusPanel popover; design the hook for N consumers (the future quick-create popover included).

    Acceptance criteria

    • Open editor → Back → editor closes, planner state intact, URL clean.
    • Back again → leaves the app.
    • Same behaviour for modal & setup panel.
    • iOS swipe-back manually verified.

    Preserve

    • Escape behaviour unchanged
    • deep-link restore (?p=) unaffected

    Verification

    • overlay-back.spec.ts green
    • hook unit tests
    • manual iOS swipe-back check

    Dependencies: None · Rollback: Each Phase 4 packet reverts independently.

    Packet 4.4 · Phase 4 — Enabling refactors

    Packet 4d.1 — Tour engine rebuild (same content)

    Eliminate first-click swallowing and clickable-dimmed-UI; keep step order/copy identical.

    Exact implementation

    • Replace the per-frame rAF re-measure loop with ResizeObserver + scroll/orientation listeners + a 250ms settle debounce.
    • One full-screen overlay using an SVG mask (cut-out = target); pointer-events auto everywhere except the cut-out; block outside interaction on every step.
    • Replace 150ms DOM polling with existing Dexie live counts plus a MutationObserver for modal-open detection.
    • If a step's target vanishes, regress to the previous step rather than stalling.
    • Keep ?tour=1, existing keys, and the planner:start-tour event.

    Acceptance criteria

    • Single-click test: each spotlit target responds to exactly one click, 20/20 repetitions in Playwright.
    • Dimmed-area clicks do nothing on every step.
    • No continuous rAF work while idle (performance trace).
    • Existing tour.spec.ts still passes.

    Preserve

    • Step order and copy identical (content changes are Phase 5)

    Verification

    • tour-reliability.spec.ts (20-click loop)
    • DevTools performance trace showing no idle rAF work

    Dependencies: None · Rollback: Each Phase 4 packet reverts independently.

    Packet 5.1 · Phase 5 — One onboarding

    Packet 5.1 — Onboarding single-owner + tour v3 content

    Implement §8 fully: exactly one onboarding surface visible at any moment.

    Exact implementation

    • OnboardingTour: intro card, step copy in canonical vocabulary, key bump to v3 with v2-read migration, mention the P-key placement shortcut.
    • WeekGrid: EmptyWeekPrompt → the single ambient card (§8.4), gated on tour state.
    • ToSchedulePanel: delete the TRY THIS card.
    • AccessGate: suppress the save banner while the tour is active (full retirement is Phase 8).
    • analytics.ts: add tour + suppression events.

    Acceptance criteria

    • At no point during the tour are EmptyWeekPrompt, TRY THIS, or the save banner visible.
    • Skipping the tour reveals exactly one ambient empty-state.
    • Tour completion sets the same suppression state as skip.
    • Playwright asserts only-one-surface across fresh, tour-active, skipped, completed and has-data states.

    Preserve

      Verification

      • manual first-run on desktop + iPhone viewport
      • Playwright: tour completes end-to-end by real interactions
      • analytics events verified in local console provider

      Dependencies: 1.1, 4.4 · Rollback: Revert to v2 tour (kept intact until Phase 9 cleanup).

      Packet 6.1 · Phase 6 — One interaction grammar

      Packet 6a.1 — Selection + BlockActionBar + unified click grammar

      Click = select, double-click = edit, everywhere; one action bar replaces hover buttons and MobileSelectedBlockControls.

      Exact implementation

      • New BlockActionBar/component.tsx: Edit · Duplicate · Delete · (Place | To Inbox contextual).
      • ScheduledBlock: remove the hover action cluster, keep the selection ring.
      • ToSchedulePanel: card click → select; remove the hover ×/⧉ cluster.
      • WeekGrid: unify month-chip and all-day-chip click handlers.
      • AppShell: render the bar for selectedBlockId (desktop anchored / mobile bottom sheet); delete MobileSelectedBlockControls.
      • Apply user-select: none to grid chrome during any active drag (desktop and touch).

      Acceptance criteria

      • The interaction-grammar table holds for inbox card, scheduled block, all-day chip and month chip.
      • No hover-only actions remain (grep group-hover:flex action clusters → 0).
      • Touch: tap selects and shows the sheet.
      • scheduled-block, life-inbox and month-view specs updated & green.

      Preserve

      • Existing wasDragging click-suppression pattern

      Verification

      • manual mouse/touch matrix
      • scheduled-block.spec.ts, life-inbox.spec.ts, month-view.spec.ts green

      Dependencies: 4.3, 4.4 · Rollback: Revert the commit. If activation metrics dip after this lands, the source is explicit that the mitigation is action-bar prominence, not reverting the grammar itself.

      Packet 6.2 · Phase 6 — One interaction grammar

      Packet 6b.1 — Edge-drag resize on scheduled blocks

      Top/bottom resize handles per the interaction grammar table.

      Exact implementation

      • ScheduledBlock: add top/bottom drag handles with their own pointer logic and pointer capture.
      • plannerActions.ts: resizeBlockDuration already exists — add a start-edge variant that shifts startTime and duration together.
      • Overnight head/tail: disable the head bottom handle at the midnight boundary (existing crossesMidnight semantics); tail is bottom-only.

      Acceptance criteria

      • Drag bottom edge 30m→60m updates endTime/duration.
      • Drag top edge moves start, keeps end.
      • Undo restores the prior duration; keyboard +/- unchanged.
      • New resize.spec.ts green.
      • No accidental block-move when grabbing a handle (20-repetition test).

      Preserve

      • Existing keyboard +/- resize path

      Verification

      • resize.spec.ts
      • 20-repetition handle-grab test

      Dependencies: 6.1 · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

      Packet 6.3 · Phase 6 — One interaction grammar

      Packet 6c.1 — Slot quick-create popover + keyboard place

      The §6.2 popover replaces full-drawer-on-slot-click; P places the selected inbox card.

      Exact implementation

      • New QuickCreatePopover/component.tsx: title input (autofocused), duration chips (15/30/60/custom), Add, "More options →" to the full editor prefilled.
      • DayColumn: route slot click to the popover.
      • AppShell: P-key handler using the existing findPastePlacement engine with the slot/selection as preferred slot; keep handleSlotClick fallback to the full editor via "More options".
      • analytics.ts: add quick_create_used, task_placed.method.

      Acceptance criteria

      • Clicking Wed 10:00 at every zoom/density/text-scale combination prefills Wed 10:00 (parameterised Playwright test).
      • Escape dismisses without creating anything.
      • "More options" opens the full editor with the same prefill.
      • P with an inbox item selected places it at the next free slot and fires the drop toast.

      Preserve

        Verification

        • parameterised Playwright slot-prefill test matrix

        Dependencies: 4.3, 6.1 · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

        Packet 7.1 · Phase 7 — One toolbar, one size system per platform

        Packet 7.1 — Toolbar consolidation + View popover

        Implement the §5.1/§9 final toolbar.

        Exact implementation

        • Rebuild WeekToolbar contents: Day/Week/Month stays visible; move week-span, density and hours into a single View ▾ popover.
        • Normalise selected-state colour to the standard accent tint (remove the green fill on span pills).
        • "N tasks this week" and the colour legend move into the popover footer.
        • Delete the overflow-scroll band styles in index.css.

        Acceptance criteria

        • No horizontal scrolling or truncation at 320-1536px (Playwright viewport assertions).
        • Every previous setting reachable in ≤2 clicks.
        • Settings survive reload.
        • Month view shows only Day|Week|Month + View ▾.

        Preserve

        • Persisted setting keys and values

        Verification

        • breakpoint sweep
        • settings persistence test

        Dependencies: 4.1, 4.2 · Rollback: Revert; persisted keys untouched.

        Packet 7.2 · Phase 7 — One toolbar, one size system per platform

        Packet 7.2 — Text-size relocation + header cleanup + drag-only edge rails

        Remove the header −%+ control; Appearance section gains "Planner text size"; edge rails render only during drag.

        Exact implementation

        • PlannerHeader: remove TextZoomControls.
        • PlannerSetupPanel: make the Appearance section real — "Planner text size" (A− / 100% / A+, live preview, same localStorage key planner.textScale, same clamp 0.9-1.3).
        • AppShell: change the edge-rail render condition to isDraggingBlock only; text-scale state stays in AppShell.

        Acceptance criteria

        • Header has no %-control.
        • Settings slider/steppers adjust scale live and persist.
        • Rails are absent at rest, present during drag with working drop/week-switch.
        • Keyboard week nav unaffected.

        Preserve

        • Same localStorage key and clamp for text scale
        • Existing keyboard week navigation (header arrows)

        Verification

        • manual verification: header has no control; Settings adjusts and persists; rails behave correctly during/after drag

        Dependencies: 7.1 · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

        Packet 8.1 · Phase 8 — Anonymous persistence & sign-in funnel

        Packet 8.1 — Storage chip + milestone nudges + banner retirement

        Replace the one-shot save banner with a truthful persistent indicator plus milestone nudges.

        Exact implementation

        • AccessGate: delete SavePlannerBanner.
        • SyncStatusPanel: chip states — "On this device" (anonymous) / sync labels (signed-in); update the panel headline copy.
        • Nudge component (toast-style, reusing existing toast primitives) fires at ≥5 placed tasks or a second distinct day of use.
        • analytics.ts: add nudge events.

        Acceptance criteria

        • The §8.6 state matrix holds (at most one onboarding/persistence surface visible at any time).
        • Banner code is deleted.
        • Nudge fires exactly once at ≥5 placed tasks (Playwright seeds data).

        Preserve

          Verification

          • state matrix Playwright coverage
          • Playwright: chip reflects task count, nudge appears once at threshold

          Dependencies: 5.1 · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

          Packet 9.1 · Phase 9 — IA & accessibility polish

          Packet 9.1 — Filters redesign

          Replace All/Imported/Planner-created/Manual/Travel with: Created here / Imported (provenance, multi-select) + Show travel time (display toggle) + implicit All when none active.

          Exact implementation

          • plannerFilters.ts: rewrite the predicates around one provenance axis.
          • AppShell PlannerSidePanel: update the filter UI.
          • PlannerSetupPanel: make the Filters section copy truthful.

          Acceptance criteria

          • No two filters have overlapping predicates.
          • Unit tests enumerate block fixtures × filters.
          • Side-panel count badge stays accurate.

          Preserve

            Verification

            • unit tests over block fixtures × filters

            Dependencies: None · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

            Packet 9.2 · Phase 9 — IA & accessibility polish

            Packet 9.2 — Settings cleanup + focus traps + contrast/type floor

            Delete placeholder Settings sections; apply a shared focus trap to modal/editor/setup/popovers; raise the minimum rendered font size and re-measure contrast.

            Exact implementation

            • PlannerSetupPanel: delete the Filters/Advanced placeholder cards; Appearance is now real (from 7.2); Sources becomes one truthful paragraph inside General.
            • New src/hooks/useFocusTrap.ts, applied to modal/editor/setup/popovers.
            • Raise the minimum rendered font size to an 11px-equivalent floor; re-measure text-muted contrast to ≥4.5:1, adjusting the token rather than per-use overrides.

            Acceptance criteria

            • Settings has no "Prepared for later" cards.
            • Tab cannot escape an open overlay.
            • axe-core Playwright pass on the planner and each overlay with zero serious/critical issues.
            • No rendered text below 11px at scale 1.0.

            Preserve

              Verification

              • axe-core Playwright pass
              • manual Tab-cannot-escape check on every overlay

              Dependencies: 7.2 · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

              Packet 9.3 · Phase 9 — IA & accessibility polish

              Packet 9.3 — Add-flow consolidation (§5.7)

              The Add modal's menu becomes exactly three options — Quick add · New task with details · Import… — with the two import rows collapsed behind one tabbed view and the disabled Templates row deleted.

              Exact implementation

              • AddToPlannerModal: render exactly three children in order — the unchanged quick-add form (still autofocused), "New task with details", "Import…".
              • Delete the disabled Templates (Coming Soon) button (Templates stay reachable via the sidebar TemplatePanel, unchanged).
              • Collapse Import from Source + Import Calendar into one "Import…" row opening the existing view === 'paste' view.
              • That view gains a two-tab strip: Paste a list (default, renders today's content unchanged) | Calendar (today's explanatory paragraph + <CalendarImport />).
              • Delete the 'importCalendar' view value; do NOT rename the 'paste' view value or the initialView prop type.
              • Demote the existing Quick Import | AI Import control visually (32px high, 12px text, no bordered card, label "Paste format") so two tab strips never stack.
              • Tabs get role="tablist"/role="tab" + aria-selected and arrow-key roving tabindex, matching WeekToolbar's segmented-control pattern.

              Acceptance criteria

              • Menu shows exactly three options; grep -r "Templates (Coming Soon)|Import from Source|Import Calendar" src/ → 0.
              • "Import…" opens the tabbed view; Paste a list reaches Review with a draft list identical to today's; Calendar reaches the Google connect + .ics upload controls.
              • initialView='paste' (the empty-week "Paste a list" CTA) still opens the import view on the Paste tab.
              • Back from the import view returns to the menu; Back from Review returns to the import view; Escape closes the modal; Tab cannot escape it.
              • Tabs operable by keyboard: arrows move focus, Enter/Space activates, aria-selected correct.
              • axe pass on the modal in both tabs: zero serious/critical.
              • New e2e/add-flow.spec.ts green; existing suite gains no net-new failures.

              Preserve

              • Templates remain reachable through the sidebar TemplatePanel
              • data-tour anchors untouched
              • No analytics event names added or changed

              Verification

              • e2e/add-flow.spec.ts
              • e2e/accessibility.spec.ts (extended)
              • manual Back/Escape/Tab walkthrough

              Dependencies: 4.3 · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

              Packet 10.1 · Phase 10 — Performance (conditional)

              Packet 10.1 — Performance measurement (gate packet)

              Produce the profile that decides whether Phase 10 work happens at all.

              Exact implementation

              • Seed 300 blocks via console/Dexie (scratch scripts only — no product files change).
              • Record traces (initial render, week nav, drag) at 4× CPU throttle, desktop + mobile viewport.

              Acceptance criteria

              • A written note (docs/perf-2026-07.md): frame times, dropped frames during drag, live-query counts.
              • An explicit go/no-go recommendation for virtualisation, backed by the evidence gathered.

              Preserve

                Verification

                • note committed; decision recorded

                Dependencies: None · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

                Packet 11.1 · Phase 11 — Responsive integrity (device-parity pass)

                Packet 11.1 — Mobile week: readable, snapping day columns

                Each mobile day column is readable and tappable; the week scrolls in intentional day steps; the page never scrolls horizontally; the first day is visible at rest. (Defects M1, M3.)

                Exact implementation

                • index.css: mobile .day-column / .week-day-heading / .week-grid-shell / .week-time-gutter rules.
                • Possibly WeekGrid/component.tsx if CSS alone cannot satisfy the acceptance criteria.

                Acceptance criteria

                • At 320/375/390/430px: every rendered day column ≥96px wide, showing a 2-line (not 1-char) title.
                • No day label overlaps another.
                • document.documentElement.scrollWidth === clientWidth (page fixed) while .week-grid-shell scrollWidth may exceed its clientWidth.
                • The time gutter stays pinned at the left edge after a horizontal scroll.
                • The first column's left edge sits at or after the gutter's right edge at rest.

                Preserve

                • Desktop columns unchanged

                Verification

                • scripts/responsive-diag.mjs at 320/375/390/430px
                • desktop columns re-checked unchanged

                Dependencies: 11.2 · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

                Packet 11.2 · Phase 11 — Responsive integrity (device-parity pass)

                Packet 11.2 — No header/block overlap; floating controls never cover content

                The sticky day-header never overlaps the first block row; the FAB, storage banner and Life Inbox tray never cover events, the time gutter, the now-marker, or each other. (Defects M2, M4, M5.)

                Exact implementation

                • index.css: .week-days-header, .mobile-add-fab, .mobile-life-inbox-tray, storage-chip/banner rules.
                • Possibly AppShell if CSS positioning alone cannot satisfy the acceptance criteria.

                Acceptance criteria

                • At 320-430px: day-header bottom ≤ first-block top (zero overlap).
                • FAB intersects 0 scheduled blocks, 0 now-marker, and does not intersect the storage-banner rect.
                • Storage-banner rect does not intersect the tray rect.

                Preserve

                • Tour dimming behaviour (body[data-tour-step])

                Verification

                • scripts/responsive-diag.mjs at 320-430px
                • manual check that tour dimming still works

                Dependencies: None · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

                Packet 11.3 · Phase 11 — Responsive integrity (device-parity pass)

                Packet 11.3 — Tablet mid-zone readable

                At 768-1000px the grid gets readable column width instead of being squeezed by the 240px Life Inbox sidebar. (Defect T1.)

                Exact implementation

                • AppShell/component.tsx: change the sidebar default-collapsed logic for the 768-1000px band (user can still reopen it).
                • index.css if needed alongside the logic change.

                Acceptance criteria

                • At 768/834px: the Life Inbox sidebar is collapsed by default, so grid width ≥ viewport − 60px and day columns ≥ ~90px.
                • 1024/1280/1440px layouts unchanged from baseline.

                Preserve

                • Desktop ≥1024px layout and column widths unchanged from baseline

                Verification

                • scripts/responsive-diag.mjs at 768/834px
                • re-check 1024/1280/1440 unchanged

                Dependencies: 11.1 · Rollback: Revert the commit. Packets are single-commit sized on purpose so rollback is always "revert the commit" (implementation-spec-2026-07-13.md §1, risk minimisation point 4).

                Implementation Tracker

                Current phase: Not started — sample pack authored 2026-08-29; no packet has begun execution against the live repository.

                Next packet: 0.1

                • 0.1 · not started · Planner implementation team
                • 1.1 · not started · Planner implementation team
                • 1.2 · not started · Planner implementation team
                • 2.1 · not started · Planner implementation team
                • 3.1 · not started · Planner implementation team
                • 4.1 · not started · Planner implementation team
                • 4.2 · not started · Planner implementation team
                • 4.3 · not started · Planner implementation team
                • 4.4 · not started · Planner implementation team
                • 5.1 · not started · Planner implementation team
                • 6.1 · not started · Planner implementation team
                • 6.2 · not started · Planner implementation team
                • 6.3 · not started · Planner implementation team
                • 7.1 · not started · Planner implementation team
                • 7.2 · not started · Planner implementation team
                • 8.1 · not started · Planner implementation team
                • 9.1 · not started · Planner implementation team
                • 9.2 · not started · Planner implementation team
                • 9.3 · not started · Planner implementation team
                • 10.1 · not started · Planner implementation team
                • 11.1 · not started · Planner implementation team
                • 11.2 · not started · Planner implementation team
                • 11.3 · not started · Planner implementation team

                Programme Decision Register

                • PDR-001 · Reject introducing a router; ship useOverlayHistory instead.

                  The app has two real paths and zero shareable-view requirements; useOverlayHistory delivers the actual user pain-fix (the back button) for roughly 5% of the cost. · Approved by Implementation plan (Sonnet-executed, packet-by-packet)

                • PDR-002 · Amend slot-tap semantics to a quick-create popover with inline placement suggestions, rather than making slot-tap primarily place the selected inbox item.

                  Slot-tap-places-selection creates a mode where behaviour depends on invisible selection state; the popover keeps one predictable outcome and offers placement inline. · Approved by Implementation plan (Sonnet-executed, packet-by-packet)

                • PDR-003 · Relocate the text-scale control to Settings → Appearance rather than labelling it in place.

                  Text scale is a set-once accessibility preference, not a per-session view control; removing it from the header eliminates the "zoom that doesn't zoom" confusion entirely rather than explaining it. · Approved by Implementation plan (Sonnet-executed, packet-by-packet)

                • PDR-004 · Accept undo for deletes; reject undo for editor field edits.

                  Explicit Save is its own confirmation for field edits; low observed need and real complexity for full field-level undo. · Approved by Implementation plan (Sonnet-executed, packet-by-packet)

                • PDR-005 · Narrow monolith decomposition to only what packets touch (toolbar, action bar, overlay hook, tour engine), not a wholesale AppShell/WeekGrid rewrite.

                  Wholesale decomposition is churn without demonstrated user value at this stage. · Approved by Implementation plan (Sonnet-executed, packet-by-packet)

                • PDR-006 · Defer replacing the four documented window events with a store; new code must not add new window events.

                  The four events are documented and work; replacing them mid-plan adds risk to Phases 5-6. · Approved by Implementation plan (Sonnet-executed, packet-by-packet)

                • PDR-007 · Quarantine the premium-gating screens into premiumGating.tsx, unreferenced by the free path, rather than deleting them.

                  Deleting loses a working reference implementation the founder may re-enable; keeping it inline keeps shipping £40 strings — quarantine is the middle path. · Approved by Implementation plan (Sonnet-executed, packet-by-packet)

                Pre-call strategic review pack

                Hypotheses to test with the founder—not conclusions from the website.

                This is a pre-seed product with a genuinely strong core loop and landing page, moving through an unfinished pivot from paid founder-beta to free-while-building. It is really selling calm control over a busy week to a self-selected "busy minds" audience, but currently presents a first five seconds that undermines exactly that promise.

                What is most in the way: The governing constraint is sequencing, not judgement: the product knows what it wants to be (free, calm, local-first) but has not yet removed every artefact of what it used to be (paid, founder-beta, import-first) or given first-run activation a single owner.

                Finish the pivot before building anything new

                Treat identity cleanup (Packet 2.1) and the vocabulary sweep (Packets 1.1/1.2) as the highest-leverage, lowest-risk work available, and sequence them ahead of any behavioural change.

                Both are copy-and-identity-only, carry near-zero regression risk, and remove the specific artefacts (the FOUNDER BETA badge, the £40 screen, four names for one concept) that most directly contradict the free positioning the landing page already promises.

                RequiresFounder agreement on whether early users should carry any founder status at all (audit §16.1) and ratification of the canonical glossary (audit §16.2, implementation-spec §7.1).

                Expected outcomeA free-positioned product that no longer contradicts itself in its own UI, at low implementation cost.

                RiskLegacy trial/comped accounts need a defined, sane fallback banner rather than simply disappearing — the plan addresses this in Packet 2.1 but it needs an explicit decision, not a default.

                high confidence — Both artefacts are directly evidenced by file:line citation and are explicitly named as founder decisions still outstanding.

                Make first-run activation the single highest-priority surface

                Sequence the tour-engine rebuild and one-onboarding-owner work (Packets 4d.1, 5.1) as the plan's largest single investment, ahead of toolbar and grammar polish that affects returning users more than new ones.

                The audit is explicit that the gap between the landing page's polish and the app's first-run chaos is itself the biggest conversion risk observed — a strong page over-promising relative to the first real interaction.

                RequiresAcceptance that this is the largest single packet in the plan (Complexity L) and that it depends on the vocabulary sweep and the tour-engine rebuild landing first.

                Expected outcomeA first five seconds that matches the promise the landing page makes, and — for the first time — attributable activation analytics across a single onboarding mechanism instead of four.

                RiskThis is the plan's highest-risk packet by the plan's own account (touches the activation funnel directly); a botched rebuild could make first-run worse before it gets better.

                high confidence — The audit's own root-cause analysis and phase sequencing independently arrive at the same priority ordering.

                Ratify one interaction grammar and one vocabulary before touching any more surface UI

                Treat "one interaction = one outcome" and "one concept = one name" (implementation-spec §2, principles 1-2) as load-bearing constraints on every subsequent packet, not aspirational guidance.

                The click-grammar inconsistency, the three unlabelled size systems, and the vocabulary drift are three symptoms of the same missing constraint — a written grammar and glossary that packets are required to satisfy or explicitly justify deviating from.

                RequiresFounder sign-off on the specific grammar table (implementation-spec §6) and glossary (§7.1) as binding, including the two places the plan explicitly amends the original audit recommendation (slot-tap semantics, text-size relocation) rather than following it literally.

                Expected outcomeEvery future UI decision has a default answer instead of being re-litigated per surface, which is what makes the later toolbar and grammar packets tractable in the first place.

                RiskA written grammar can ossify prematurely if treated as untouchable; the plan itself frames deviations as requiring "a written reason", which is the right level of rigidity.

                medium confidence — The grammar and glossary are well specified in the implementation plan; their durability under real founder review is not yet tested.

                Now

                • Restore the test suite as a deploy gate (Packet 0.1) before any other packet lands.
                • Finish the pivot: remove founder-beta identity and sweep the vocabulary (Packets 1.1, 1.2, 2.1).

                Next

                • Fold deletes into undo (Packet 3.1) and complete the four enabling refactors (Packets 4a.1-4d.1) that unblock everything after them.
                • Ship one onboarding owner and one interaction grammar (Phases 5-6), the plan's highest-risk, highest-value work.

                Not yet

                • A visual re-theme, a new colour system, or a landing-page redesign — The plan explicitly excludes this — the landing page is the strongest asset and this is a finishing pass, not a redesign.
                • A router, a state-management library, or component-library adoption — The plan explicitly rejects introducing a router (challenge C1) in favour of a much cheaper overlay-history hook that fixes the actual user pain (the back button).
                • Mobile-app (Capacitor) work — The plan freezes this explicitly until the web interaction grammar stabilises — the founder decision (audit §16.6) the plan defers to stands.
                • A monetisation build — Free-while-building is a legitimate stance the plan does not challenge; it accumulates the login-driven email asset (Phase 8) without committing to a specific offer.

                What not to change

                • The landing page's visual system — Called out repeatedly as the strongest asset in the product; every other surface should inherit its restraint, not the reverse.
                • The local-first Dexie architecture, its sync queue, and existing localStorage/Dexie key names — Solid foundations worth protecting (audit §11.9); the implementation plan's own compatibility rules forbid renaming keys or bumping the Dexie schema anywhere in this programme.
                • The post-sign-in import-choice flow's design — Genuinely good as designed; its only problem is that almost no one finds it, which is a discoverability fix, not a redesign.

                Open questions

                • Is a brand-new free user a "Founder Beta member" in any real sense, or is that wallpaper left over from the pivot? — Evidence that would answer it: A founder decision (audit §16.1): if early users should carry founder status, on what basis it is earned; if not, the badge and banner copy are simply removed.
                • Is the iOS/Capacitor app a now-priority, given it doubles the QA surface of every interaction fix in this plan? — Evidence that would answer it: A founder decision (audit §16.6) on mobile-app priority, which the implementation plan currently defers to and freezes pending an explicit answer.

                Included strategy conversation

                Want to talk through the choices?

                Your access includes one strategy conversation to discuss your report.

                Complete founder questionnaire

                Methodology & transparency

                Methodology, transparency & limitations

                This report has been generated with the assistance of artificial intelligence using the evidence available at the time of assessment. GreatInternet applies a defined assessment methodology and presents observations, judgements and recommendations based on that evidence. AI-assisted output should be reviewed by an appropriate human decision-maker before material reliance or implementation.

                Limitations

                • This is a white-box source-code and hands-on-session review, not a crawled-page evidence review; evidence citations are file:line references into the planner-v1 repository at audit time rather than captured page evidence.
                • Three findings (onboarding click-swallowing, the slot-click prefill mismatch, and drag ergonomics text-selection) were reproduced via an automated browser session that suffered periodic tool interruptions and are explicitly flagged [verify by hand] in the source audit pending reproduction on real hardware.
                • Not audited: Supabase RLS/policies, the iOS build, admin console security posture beyond noting it is public and OAuth-gated, and email deliverability.
                • The responsive-integrity finding (mobile/tablet layout) is translated from the implementation specification's own description of a separate, later diagnostic pass; the underlying raw report was not itself reviewed for this pack.