diff --git a/.agents/skills/flotilla-architecture/SKILL.md b/.agents/skills/flotilla-architecture/SKILL.md
index 627d9314..a6bb7b63 100644
--- a/.agents/skills/flotilla-architecture/SKILL.md
+++ b/.agents/skills/flotilla-architecture/SKILL.md
@@ -331,7 +331,8 @@ with `makeFeed` and filters them with the `classifieds.ts` helpers. `[address]/+
one listing with `$events.one(address, [url]).$`.
Articles are composed on a full page (`spaces/[relay]/articles/create`, built by
-`makeArticleCreatePath`) instead of in a modal.
+`makeArticleCreatePath`) instead of in a modal. The page reads `?h=` and `?shareToChat` and
+renders `ArticleForm`.
## Related skills
diff --git a/.agents/skills/flotilla-state/SKILL.md b/.agents/skills/flotilla-state/SKILL.md
index 72c94387..19bc34d6 100644
--- a/.agents/skills/flotilla-state/SKILL.md
+++ b/.agents/skills/flotilla-state/SKILL.md
@@ -121,6 +121,7 @@ they cache is itself a rebinding store. `commandsByUrl` holds `fromApp` stores.
| `SpaceManagement` (`management.ts`) | none | NIP-86 supported methods (5-minute TTL), admins and bans per URL |
| `Chats` (`chats.ts`) | none | DM conversations by chat id (`index`, `one`), and a fuzzy `search` |
| `LatestEvents` (`repository.ts`) | none | the most recent event held from an author (`forPubkey`) |
+| `GoalProgresses` (`goals.ts`) | none | one memoized NIP-75 progress store per goal and relay, behind `deriveGoalProgress` |
| `Hosting` (`hosting.ts`) | none | the hosting backend's plans, the tenant's relays and billing, shared by every hosting view |
Each is exposed with `usePlugin`. `Statuses` is the minimal shape:
diff --git a/.agents/skills/flotilla-views/SKILL.md b/.agents/skills/flotilla-views/SKILL.md
index 44262526..03ce225c 100644
--- a/.agents/skills/flotilla-views/SKILL.md
+++ b/.agents/skills/flotilla-views/SKILL.md
@@ -229,8 +229,8 @@ lives there:
`ModalSubtitle`, `ModalFooter`, `Confirm`
- controls: `Button`, `Link`, `Field`, `FieldInline`, `Input`, `InputList`, `ToggleInput`,
`DateTimeInput`, `ImagesInput`, `IconInput`, `EmojiPicker`, `MenuButton`, `SegmentedButtons`
-- display and lists: `Icon`, `Badge`, `Card`, `Divider`, `Spinner`, `Tooltip`, `Tippy`, `Cv`,
- `VirtualList`, `Masonry`, `DragList`, `ScrollToTop`
+- display and lists: `Icon`, `Badge`, `Card`, `Divider`, `Spinner`, `LoadingFallback`, `Tooltip`,
+ `Tippy`, `Cv`, `VirtualList`, `Masonry`, `DragList`, `ScrollToTop`
- the CSS component families (`button.css`, `card.css`, …) and the theme tokens
Anything that takes an identifier and reads a store, publishes, or knows a kind is an app
@@ -324,14 +324,13 @@ data every page needs lives in `src/app/sync.ts`.
lists before loading the author's outbox with `$network.loadLenient`.
**A detail page:** `$events.one(address, [url]).$` loads when nothing local matches. While it is
-empty, seven pages show a spinner that turns into a failure message:
+empty, seven pages show `LoadingFallback`, a spinner that turns into a failure message after
+five seconds:
```svelte
-{#await sleep(5000)}
- Loading listing...
-{:then}
-
Failed to load classified listing.
-{/await}
+
```
**Related events:** request them, abort on teardown, and read them back from the repository with
@@ -444,7 +443,9 @@ Create/edit pairs come in three shapes:
- **The form owns the mutation and a draft.** `ClassifiedForm` persists fields with `DraftKey`
and republishes the same `d` on edit. `ClassifiedCreate` passes a header, and `ClassifiedEdit`
turns a reader into `initialValues`. Its `Values` type stays local, so `ClassifiedEdit`
- restates the shape; export it instead.
+ restates the shape; export it instead, as `ArticleForm` does. `ArticleForm` is the same shape
+ on a full page: it renders the `SpaceBar` with its Publish button, takes the title as `header`,
+ and lands on the published article.
Rich text uses `makeEditor` from `src/app/editor` with `EditorContent`.
diff --git a/src/app/components/ArticleForm.svelte b/src/app/components/ArticleForm.svelte
new file mode 100644
index 00000000..b986bdba
--- /dev/null
+++ b/src/app/components/ArticleForm.svelte
@@ -0,0 +1,270 @@
+
+
+
+
+
+ {#snippet leading()}
+
+ {/snippet}
+ {#snippet title()}
+ {@render header()}
+ {/snippet}
+ {#snippet action()}
+
+ {/snippet}
+
+
+
+
+