diff --git a/.planning/phases/35-mail-templates-and-layouts-editor/35-CONTEXT.md b/.planning/phases/35-mail-templates-and-layouts-editor/35-CONTEXT.md
new file mode 100644
index 00000000..1ed35b08
--- /dev/null
+++ b/.planning/phases/35-mail-templates-and-layouts-editor/35-CONTEXT.md
@@ -0,0 +1,187 @@
+# Phase 35: Mail templates and layouts editor - Context
+
+**Gathered:** 2026-11-06
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+Administrators edit the mail the application sends from the admin panel, as in WinterCMS's Mail templates screen:
+
+- Every template registered through `pact.HasMailTemplates` (and postcard's built-in mail) is listed.
+- Each template, layout and partial can get a database override, and the override can be reset to the file version.
+- Admins can create custom layouts.
+- A Branding page holds structured colours and a logo.
+- A shared image library holds uploaded images.
+- Drafts can be previewed and test-sent.
+
+postcard renders the override when one exists and the plugin's file otherwise, so mail that already works keeps working with no change to apps or plugins.
+
+Not in this phase: mail driver/SMTP settings screens, MailBlocker, newsletters/bulk mail, a WYSIWYG mail body.
+
+
+
+
+## Implementation Decisions
+
+### Placement and permissions
+- **D-01:** The screens live **inside cabana**, as an internal pseudo-plugin. This is the same pattern as Administrators/Roles in 19.6.1 (`modules/cabana/backend_screens.go`, `modules/cabana/backendscreens/`). Every app gets them with no setup. postcard stays free of admin and cabana code; cabana (or a thin glue layer) supplies postcard with the DB-backed layer through an interface postcard defines.
+- **D-02:** **Navigation: a "Mail" section in Settings**, with entries for Mail templates, Mail layouts, Mail partials, Mail branding and Mail images. Links use `pact.HasSettings`, as in 19.6.1 D-02. There is no top-level nav item.
+- **D-03:** **Two permission codes**, registered by the cabana pseudo-plugin:
+ - `system.manage_mail_templates` covers the templates list/form, template preview and test send.
+ - `system.manage_mail_layouts` covers layouts, partials, Branding and the image library, because these change every mail.
+
+ Neither code is granted to any role by default (as in 19.6.1 D-04). Only superusers reach the screens until someone grants a code. The image library and its insert picker must also be usable from the template form by holders of `system.manage_mail_templates`, either read/pick only or with upload too (planner's call, stated in the plan). — **Reversibility:** costly — the codes end up stored in `backend_user_roles.permissions` / `backend_users.permissions` JSON on every install that grants them.
+
+### Editing model: templates
+- **D-04:** **A template override stores subject + Markdown body + layout.**
+ - The body stays Markdown with Go `html/template` variables (`{{ .name }}`), the same format as the file.
+ - The plain-text part is still derived from the body; there is no hand-written text part.
+ - The layout is a dropdown over all layouts (file and custom).
+ - Description stays file-owned and read-only.
+- **D-05:** **Locale variants stay separate templates.** `activate.htm` and `activate-en.htm` are their own rows. The list has a locale column, parsed from the suffix convention postcard already uses, plus a locale filter. There is no grouping and no new locale model.
+- **D-06:** **Reset to the file version** deletes the override row, on templates, file layouts and file partials alike.
+- **D-07:** **Drift notice.** When an override is saved, it stores a hash of the file content it was based on. If the plugin file later changes (for example after a plugin upgrade), the override keeps winning, but the list and the form flag "file changed since override". The form offers a way to view the current file version (a diff if cheap) and the reset button. — **Reversibility:** costly — the hash column is part of the override table schema (migration).
+
+### Editing model: layouts, Branding, partials
+- **D-08:** **Layouts use the same override model as templates.**
+ - Every file layout is listed: postcard's built-in default plus plugin layouts such as sm-user-plugin `layouts/user.htm` and paymentgateway `layouts/paymentgateway.htm`.
+ - Each file layout can get a DB override with reset.
+ - Admins can also **create custom layouts** that exist only in the DB. Custom layouts can be deleted (not reset); deleting one still assigned to template overrides is refused, with a count of those templates.
+ - "Seeded predefined layouts" means a couple of framework-shipped file layouts, for example the existing default plus one or two more such as system/minimal (the planner picks the set). They are not rows copied into the DB at boot.
+- **D-09:** **Layouts are edited in a new `codeeditor` form field type**, Winter-style, with syntax highlighting for HTML/CSS/text. It is added to cabana's field registry and to the admin SPA. The layout form has tabs for the HTML wrapper, the text wrapper and the CSS/header. The field type is reusable by later phases. — **Reversibility:** costly — a published field type name in `fields.yaml` that plugins may start using.
+- **D-10:** **Branding page**, as in Winter's mail brand settings.
+ - It is a settings page (cabana settings model) with Winter's brand colour set: body/content background, text, link, the button primary/positive/negative colours, and header/footer colours.
+ - It also has a **logo** upload, exposed to layouts as `{{ .logoUrl }}`.
+ - The colours compile into the brand CSS slot that postcard already inlines.
+- **D-11:** **Precedence: Branding replaces config brandCss.** While no Branding record has been saved, `mail.brandCss` from config is used, so existing apps are unchanged. Once Branding is saved, its compiled CSS replaces `mail.brandCss`. `mail.css` is unaffected and still applied.
+- **D-12:** **Mail partials are in scope, with file + DB override like templates.**
+ - Files live at `views/mail/partials/.htm` and are named `::mail.partials.`.
+ - Plugins declare them through a **new additive optional pact capability**. `pact.HasMailTemplates` is not changed: core plugins must not break.
+ - Partials are used from template bodies and layouts through a Go template call (the planner picks the exact syntax or helper).
+ - A few built-in partials ship with postcard (button, panel, table).
+ - Admins override and reset partials; editing them needs `system.manage_mail_layouts`.
+
+ — **Reversibility:** costly — a published pact capability and naming convention that plugins implement.
+
+### Validation and send-time safety
+- **D-13:** **Saves are validated.** Saving a template, layout or partial override parses it, test-renders it with the sample vars (D-15) and runs postcard's existing safety checks (script/iframe/object/embed, inline handlers, `javascript:`/`vbscript:`/`data:` URLs, CR/LF in the subject). Failures are field validation errors.
+- **D-14:** **Fallback at send.** If an override still fails to render at send time (for example a variable missing at runtime), postcard logs the failure and sends the file version, so mail delivery doesn't stop. A template with no file (impossible for templates; custom layouts only) falls back to the default layout.
+
+### Preview and test send
+- **D-15:** **Sample variables**: plugins may add optional sample values to a template file. One option is a sample section in the INI header; another is an additive capability (planner's call). Variables without a sample render as a visible placeholder such as `[name]`. Existing template files work unchanged.
+- **D-16:** **Live preview of the unsaved draft.** The template, layout and partial forms render the current draft through postcard with sample vars. The HTML part is shown in a **sandboxed iframe**, and a tab shows the plain-text part. Rendering happens on the server through postcard, so preview matches real sends.
+- **D-17:** **Test send to my own address only.** A button sends the current draft (with sample vars) to the signed-in admin's email through the configured driver. It needs the same permission as editing that record and is rate-limited per admin. There is no free-text recipient field.
+
+### Images
+- **D-18:** **A shared mail image library.** A "Mail images" list stores images through `lagoon/attach` on the public disk. Any template, layout or partial can use them, and the Branding logo also uses this storage.
+- **D-19:** **Delivery via absolute public URLs.** `
` uses the attachment's absolute public URL, built from `storage.uploads.public_url` / `app.url`. No CID inline parts; postcard's `RenderedMessage` and drivers are unchanged.
+- **D-20:** **An insert button in the editors.** A picker next to the markdown editor (template bodies) and the codeeditor (layouts/partials) inserts `` or `
` for a chosen library image.
+
+### Quality gates
+- **D-21:** Unit tests are the last plan (project rule). They cover:
+ - override precedence and reset;
+ - drift detection;
+ - fallback at send;
+ - save validation;
+ - Branding precedence over config;
+ - the partial capability (boot errors, namespace rule);
+ - the permission split;
+ - the test-send recipient restriction and rate limit.
+
+ The postcard and cabana READMEs and the affected `docs/` pages are updated in the same commits as API/config/permission changes. The `admin/` changes regenerate `admin/openapi/admin.json` + `schema.d.ts` (`scripts/check-admin-openapi.sh`) and rebuild the committed `modules/boardwalk/dist` (`scripts/check-admin-dist.sh`).
+
+### Claude's Discretion
+- Table names and schema (one overrides table per kind, or a shared one), as long as it is Postgres/GORM with gormigrate migrations owned by the cabana pseudo-plugin, or by postcard if the planner justifies it.
+- Exact partial call syntax and the built-in partial set beyond button/panel/table.
+- Which extra predefined file layouts ship (D-08).
+- Whether the image picker on the template form needs `manage_mail_layouts` for uploads (D-03 note).
+- How postcard learns about overrides: a lookup interface checked per send, or a cache invalidated on save. It must be correct with several app instances, so per-send lookup or explicit invalidation, never a stale boot-time snapshot.
+- How the SPA codeeditor is built (the library choice needs a STACK.md/decision note per the dependency rule).
+- The plan split (lean planning: present the count before writing PLAN.md files).
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Mail layer
+- `modules/postcard/README.md` covers the current template/layout format, catalog, drivers, safety checks and config keys (`mail.css`, `mail.brandCss`).
+- `modules/postcard/templates.go` and `modules/postcard/mailer.go` hold `Catalog.Register`, `Mailer.Send`, `Activate` and `BootPlugin`, which are the integration point for the override layer.
+- `modules/postcard/assets/default.htm` is the built-in default layout (header `==` text `==` HTML).
+- `modules/pact/capabilities.go` §`HasMailTemplates` (around line 1271) must stay unchanged; partials and samples go in new additive capabilities.
+
+### Admin patterns
+- `.planning/phases/19.6.1-backend-administrators-screen/19.6.1-CONTEXT.md` covers the cabana internal pseudo-plugin, permission codes registered by cabana, Settings placement via `pact.HasSettings`, and no default role grant.
+- `modules/cabana/backend_screens.go` and `modules/cabana/backendscreens/` hold the internal pseudo-plugin and the YAML controllers to mirror.
+- `modules/cabana/settings.go` holds the settings model pattern for the Branding page.
+- `modules/cabana/field_markdown.go`, `modules/cabana/field_file.go` and `modules/cabana/field_type.go` are where the new `codeeditor` field and the image picker hook in.
+- `admin/src/components/form/fields/` holds the SPA field widgets (MarkdownField, FileuploadField); the new CodeEditorField goes here.
+- `.planning/notes/2026-10-07-embedded-admin-release-gate.md` is the dist rebuild gate for `admin/` changes.
+
+### Storage and URLs
+- `modules/lagoon/attach/bucket.go` provides `PublicURLBase` (`storage.uploads.public_url`) for absolute image URLs.
+- `.planning/research/STACK.md` holds the decided dependency set; a code-editor JS library must be added here or in a decision note.
+
+### Reference implementation (WinterCMS)
+- `../examples/golem15-wintercms-starter` covers Winter's System → Mail templates/layouts/partials/brand settings (`modules/system/models/MailTemplate.php`, `MailLayout.php`, `MailPartial.php`, `MailBrandSetting.php`) for field sets and behaviour parity.
+
+### Existing mail consumers (must keep working unchanged)
+- `../sm-user-plugin/views/mail/` (including `layouts/user.htm` and the locale variants) and `../sm-paymentgateway-plugin/views/mail/` (including `layouts/paymentgateway.htm`).
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `postcard.Catalog` already parses the INI header + `==` file format and resolves layout aliases. Overrides should reuse the same parser so DB content and files share one format.
+- postcard's safety checker (rendered-HTML rejection, header CR/LF) is reused for save validation (D-13) and preview.
+- The cabana internal pseudo-plugin (19.6.1) has permission registration, Settings links and YAML controllers.
+- The cabana settings model plus `settings_secret.go` patterns cover the Branding page.
+- `lagoon/attach` handles uploads, public disk storage and `PublicURLBase`.
+- The SPA's `PreviewView.vue` and `FormView.vue` are where the preview pane and test-send action go.
+
+### Established Patterns
+- Plugins can only register names in their own namespace (`::mail.*`). Partials follow the same rule.
+- Boot errors for missing files, duplicates and unknown aliases. The new partial capability fails the same way.
+- Postgres only, GORM + per-plugin gormigrate migrations; YAML via `goccy/go-yaml`.
+- Standard library first; any new dependency (code editor in the SPA) needs a research/decision note.
+- A docs checker enforces that README/docs identifiers exist.
+
+### Integration Points
+- postcard's render path (`Mailer.Send`) consults an override source before the file catalog, with fallback per D-14.
+- `postcard.Activate` / brand CSS resolution consults the Branding record (D-11).
+- The cabana field registry plus the SPA `FieldRenderer.vue` gain `codeeditor`.
+- `pact` gets an additive capability for partials (and possibly sample vars).
+
+
+
+
+## Specific Ideas
+
+- The user explicitly wants **both** Winter's structured Branding page (colours, logo) **and** codeeditor-based layouts, "as WinterCMS kind of has it".
+- Winter parity is the guide for field sets (brand colours, template/layout/partial forms) and for keeping `system.manage_mail_templates` as the code name.
+
+
+
+
+## Deferred Ideas
+
+- Hand-written plain-text template parts (Winter's `content_text`), not needed now.
+- A WYSIWYG/rich-editor mail body.
+- CID-embedded inline images (only absolute URLs in v1).
+- Test send to an arbitrary address.
+- Mail driver/SMTP configuration screen in the admin.
+
+### Reviewed Todos (not folded)
+- **Port MailBlocker and the block-mail checkbox** (`.planning/todos/pending/mailblocker-with-mailing.md`): kept separate. It is a send-path feature owned by sm-user-plugin (MailBlocker table, check before send, `block_mail` checkbox) and stays a todo for later mail work.
+
+
+
+---
+
+*Phase: 35-mail-templates-and-layouts-editor*
+*Context gathered: 2026-11-06*
diff --git a/.planning/phases/35-mail-templates-and-layouts-editor/35-DISCUSSION-LOG.md b/.planning/phases/35-mail-templates-and-layouts-editor/35-DISCUSSION-LOG.md
new file mode 100644
index 00000000..3147be8a
--- /dev/null
+++ b/.planning/phases/35-mail-templates-and-layouts-editor/35-DISCUSSION-LOG.md
@@ -0,0 +1,91 @@
+# Phase 35: Mail templates and layouts editor - Discussion Log
+
+> **Audit trail only.** Do not use as input to planning, research, or execution agents.
+> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
+
+**Date:** 2026-11-06
+**Phase:** 35-mail-templates-and-layouts-editor
+**Areas discussed:** Placement & permissions, Editing model, Preview & test send, Images
+
+---
+
+## Todo cross-reference
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Keep it separate | MailBlocker stays a todo for the later mail work | ✓ |
+| Fold it in | Widens the scope to sm-user-plugin and the send path | |
+
+## Placement & permissions
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Inside cabana | Internal pseudo-plugin, the 19.6.1 pattern | ✓ |
+| A new sm-mail-plugin | Opt-in plugin repo | |
+| Inside postcard | postcard would depend on cabana | |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Settings → Mail section | Winter-like, through pact.HasSettings | ✓ |
+| Settings → System section | Next to Administrators/Roles | |
+| Top-level nav item | | |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| One code | system.manage_mail_templates | |
+| Two codes | templates + layouts | ✓ |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| system.manage_mail_templates + system.manage_mail_layouts | Winter-compatible | ✓ |
+| mail.manage_templates + mail.manage_layouts | New namespace | |
+
+## Editing model
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Subject + Markdown body + layout | Same as the file format | ✓ |
+| Also a hand-written plain-text part | | |
+| HTML body (rich editor) | | |
+
+**Layout editing:** the options were a codeeditor field, a plain textarea, or structured fields. **User's choice (free text):** "I wonder if we could have both 3 and 1. WinterCMS kind of has it - it has 'Branding' section with structured fields for colors etc and codeeditor-based layouts." This became a Branding page plus codeeditor layouts.
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Defer partials | | |
+| Include partials, file + DB | | ✓ |
+
+| Question | Options | Selected |
+|----------|---------|----------|
+| Branding contents | Winter colours + logo / colours only / + free CSS | Winter colours + logo |
+| Branding vs config | Branding replaces brandCss once saved / config wins / concatenate | Branding replaces once saved |
+| Partials shape | Same pattern as templates / built-in only | Same pattern as templates |
+| Branding & partials perms | Under manage_mail_layouts / own branding code | Under manage_mail_layouts |
+| Plugin file layouts | Same override model / imported to DB at boot | Same override model |
+| Drift after file change | Override wins + notice / silently | Override wins + notice |
+| Locale variants | Own rows + locale column / grouped tabs | Own rows + locale column |
+| Validation | On save + fallback at send / save only, strict at send | On save + fallback at send |
+
+## Preview & test send
+
+| Question | Options | Selected |
+|----------|---------|----------|
+| Preview | Live draft in a sandboxed iframe + text tab / saved only | Live draft in a sandboxed iframe |
+| Sample vars | Optional file samples + placeholders / placeholders only / admin JSON | Optional file samples + placeholders |
+| Test send | Own address / any address / none | Own address |
+
+## Images
+
+| Question | Options | Selected |
+|----------|---------|----------|
+| Storage | Shared mail image library / per-record attachments | Shared library |
+| Delivery | Absolute public URLs / inline CID / per-image toggle | Absolute URLs |
+| Placing | Insert button in the editor / copy URL | Insert button |
+
+## Claude's Discretion
+
+- Schema layout, partial call syntax, extra predefined layouts, the image picker permission detail, the override lookup/caching mechanism (must be multi-instance safe), the SPA code-editor library (needs a decision note), the plan split.
+
+## Deferred Ideas
+
+- Plain-text template parts, a WYSIWYG body, CID images, test send to any address, a mail driver settings screen.