diff --git a/.planning/phases/10-admin-vue-spa/10-CONTEXT.md b/.planning/phases/10-admin-vue-spa/10-CONTEXT.md
new file mode 100644
index 0000000..0b5f656
--- /dev/null
+++ b/.planning/phases/10-admin-vue-spa/10-CONTEXT.md
@@ -0,0 +1,149 @@
+# Phase 10: Admin Vue SPA - Context
+
+**Gathered:** 2026-09-26
+**Status:** Ready for planning (after Phase 9 plans 09-11 and 09-12 complete)
+
+
+## Phase Boundary
+
+Phase 10 delivers the framework's admin SPA: a Vue 3 + TypeScript single-page app, living in `summercms.go`, embedded in the binary and served at a configurable backend URI. It renders login, permission-gated plugin navigation, schema-driven lists and forms, the relation manager, the settings screen and the filter bar, consuming the Phase 9 `cabana` admin API. The five Płytarium controllers (Albums, Artists, Collections, Genres, Styles) are the acceptance targets; the Collections editors relation manager must search, link and unlink.
+
+The phase also carries the backend changes the SPA needs, all in `cabana` (framework) plus YAML/registry updates in `fonoteka.go`: a configurable admin prefix for both SPA and API, cookie transport for the admin JWT, a relation-field options endpoint, relation values in form saves, `messages:` and declarative `toolbar.buttons` in controller config, a server-served SPA string bundle, and a framework-owned admin OpenAPI document the SPA's types are generated from.
+
+Requirement: ADMIN-06. Not in scope: runtime plugin extensions (plugin JS/CSS assets, custom widget and partial field types), which are Phase 10.1; browser e2e tests.
+
+
+
+
+## Implementation Decisions
+
+### Packaging and serving
+- **D-01:** The SPA source lives in `summercms.go/admin` (Vite project). Its built `dist/` is embedded through `embed.FS` in a framework package and served by the binary. No separate deploy, no CORS.
+- **D-02:** The mount path is configurable (`backend.uri`, Winter-style), e.g. `/plytadmin`, `/manage`, `/horoadmin`, chosen per project so the admin location is not guessable. The committed build is path-agnostic: the Go server injects the configured base path into `index.html` at serve time. Client-side routes are handled by an SPA fallback under the prefix. — **Reversibility:** reversible
+- **D-03:** The admin API moves with the prefix: `{backend.uri}/api/v1/...` replaces the hardcoded `/_admin/api/v1` from Phase 9 (D-09 there). This is safe because nothing outside the SPA calls the admin API yet (Nuxt and fonoteka-mcp never touch it). The `api` segment under the prefix is reserved and never used as an SPA route. OpenAPI paths are written relative (`/navigation`, `/auth/login`) and the SPA client gets its base URL at runtime. — **Reversibility:** costly — every admin route, test and the OpenAPI document are keyed to the prefix scheme.
+- **D-04:** The built `dist/` is committed, with a check script that rebuilds and fails on drift (same pattern as `check-openapi.sh`). Rationale agreed with the user: everything an app plugin changes in the admin (YAML columns/fields, navigation, permissions, hooks, and in 10.1 partials and JS/CSS assets) is embedded in the plugin and needs only a Go binary rebuild; the Node build is needed only when the framework SPA itself changes (new built-in field type, layout). App developers never need Node.
+- **D-05:** Extension seam only: a field-type renderer registry (`FieldRenderer` maps `type` to component). Any unregistered type renders the design's `UnsupportedField` box ("Nieobsługiwany typ pola: ``") instead of breaking the form. The full extension point is Phase 10.1 (see Deferred).
+
+### Look and components
+- **D-06:** The design reference is Direction C v2 from claude.ai/design, stored at `.planning/phases/10-admin-vue-spa/design/` (README.md is the spec; `Direction C v2.dc.html` + `support.js` is the viewable reference). High fidelity: tokens, typography, radii, spacing, control heights, focus rings, copy, a11y roles, states (selected, empty, loading, 422, toast, modal), responsive rules (collapse below ~1100px, tablet width), light and dark mode. Build the generic components it lists (PluginRail, SectionPanel, SectionFlyout, AppShell, DataTable, ListToolbar, Pagination, FormTabs, FormGrid, FormField, FieldRenderer, RelationManager, RelationPickerModal, Toast, UserMenu).
+- **D-07:** Stack: Vue 3 + Vite + TypeScript + Tailwind + Reka UI primitives + lucide-vue-next icons (same family as `vue-fonoteka-app`). DM Sans and DM Mono are self-hosted inside `dist/`, not loaded from Google Fonts (works offline, no third-party requests from a hidden admin URL).
+- **D-08:** Real YAML only. Płytarium screens render exactly what their YAML declares (Albums: name, artists, format, genre, shelf; no tabs). The mock's extra fields, tabs and columns (Opis, Wypożyczony, Ulubiony, Utworzono, Szczegóły tab) are component fixtures for tests, not additions to Płytarium.
+- **D-09:** The SPA follows Phase 9's API contract where the mock differs: error envelope `{"error": {code, message, details}}` with 422 details as field → messages (not the mock's `{errors}`); list query and meta per Phase 9 D-11.
+- **D-10:** Routes derive from controller IDs: `golem15.fonoteka.albums` → `{backend.uri}/golem15/fonoteka/albums`, `/create`, `/:id`. The rail groups by plugin from `/navigation`; the active rail item comes from the route's owning plugin. Items the admin lacks permission for are absent (server-filtered), and a plugin whose side menu is empty after filtering is absent from the rail.
+- **D-11:** Navigation icons are lucide names in the registry. The SPA also carries a small map from Winter `icon-*` names to lucide so ported Winter plugins work unchanged; unknown names get a neutral fallback icon. `fonoteka.go` switches its navigation and settings icons to lucide names.
+- **D-12:** The Albums format column renders as plain text in Phase 10 (no icon pills).
+
+### Controller copy and toolbar
+- **D-13:** `config_list.yaml` and `config_form.yaml` accept an optional `messages:` block of phrasebook keys (e.g. `recordCount`, `searchPrompt`, `deleteConfirm`, `empty` on lists; `create`, `saved` on forms). Keys are resolved server-side in the admin's locale. Plural keys are served with all their CLDR forms (`{"one": ..., "few": ..., "many": ..., "other": ...}`) and the SPA picks the form with `Intl.PluralRules(locale)`, because only the client knows the count (e.g. selected rows). Placeholders `{count}`, `{name}`, `{term}` are interpolated by the SPA. Every key is optional; the framework ships generic defaults (e.g. "Nowy rekord", "Usunąć zaznaczone ({count})?", "Zapisano"). Unknown `messages` keys fail at boot (Phase 9 `DisallowUnknownField` rule).
+- **D-14:** Toolbar is declarative: `toolbar.buttons: [create, delete]` lists built-in actions in display order (`create` gated by create permission; `delete` is bulk delete, enabled with a selection, confirming with `deleteConfirm`), plus `toolbar.search`. A string value (Winter's `buttons: list_toolbar` partial) is a boot error pointing at the new syntax. The five Płytarium config files are updated accordingly. Custom actions are Phase 10.1. — **Reversibility:** costly — changes the YAML contract every ported controller writes.
+
+### Types and relations
+- **D-15:** The SPA's types come from a framework-owned admin OpenAPI document: swag v1 annotations on `cabana` handlers, generated in `summercms.go`, converted to OpenAPI 3 (reuse the `swagger2openapi.go` approach), committed, and fed to openapi-typescript, with a drift check. The framework SPA never reads an app repo's document. `fonoteka.go/docs/openapi.json` remains the parity API document.
+- **D-16:** Records are typed generically: generated types cover envelopes, form/list/filter/relation/navigation/settings schemas, list meta and errors; a record is `Record` read through its field schema. No per-controller TypeScript types and no hand-maintained duplicates of API shapes (success criterion 4).
+- **D-17:** Relation fields get their choices from a new endpoint, `GET {prefix}/api/v1/{vendor}/{plugin}/{controller}/fields/{field}/options?search=&page=&per_page=`, returning `{value, label}` with the label from `nameFrom`, on the Phase 9 D-11 list contract. An optional `RelationExtendOptionsQuery(ctx, field, *gorm.DB) *gorm.DB` hook on the admin controller lets apps scope options (e.g. to the active collection). Permission gating is the controller's. The `emptyOption` stays a schema property rendered by the SPA.
+- **D-18:** Form saves send relation values keyed by the YAML field name with ids: `{"genre": 3, "artists": [4, 9]}`. `cabana` maps belongs-to to the foreign key and syncs many-to-many through the Phase 5 join-table contract inside the save transaction, after `FormBeforeCreate`/`FormBeforeUpdate`. Record GET returns the same shape plus display labels so the form can show chips and the selected dropdown value without extra calls.
+
+### Session and UX
+- **D-19:** The admin JWT moves into an httpOnly, Secure, SameSite=Strict cookie scoped to `{backend.uri}`, set by login and refresh and cleared by logout. JS never reads the token (this matters once 10.1 lets plugin JS run in the admin origin). The `backend` guard accepts the cookie and still accepts `Authorization: Bearer` for CLI and tests. State-changing requests must carry a custom header (e.g. `X-Requested-With`) as CSRF defence in depth. It is still a JWT with the Phase 7 blacklist and sliding refresh; no session store. — **Reversibility:** costly — changes Phase 9's auth transport and the security matrix tests that pin it.
+- **D-20:** The SPA's own UI strings (Zapisz, Anuluj, Wyloguj, pagination, confirmations, defaults from D-13) live in the framework's phrasebook (`backend::lang`, pl and en) and are fetched as a resolved bundle for the admin's locale at startup. Projects can override or add locales without a Node rebuild.
+- **D-21:** The settings screen is in scope: the rail's "Ustawienia" lists `HasSettings` pages the admin may manage and renders each through the same form renderer against the Phase 9 settings endpoints (fonoteka: `search_use_typesense`).
+- **D-22:** The filter bar is in scope: it renders `config_filter.yaml` scopes of the three Phase 9 shapes (switch, daterange, model-backed) and drives `filter[]`. Płytarium has no filters, so it is verified with fixtures.
+- **D-23:** Testing follows the lean rules: Vitest component and unit tests as the phase's last plan; Go tests for every `cabana` change. Browser e2e (Playwright) is not part of Phase 10.
+
+### Claude's Discretion
+- SPA state management (Pinia or composables), router setup, HTTP client (openapi-fetch or a thin wrapper over generated types).
+- Dev loop: Vite dev server proxying the API vs rebuilding into the embedded path; recommended a Vite proxy to a running `summer serve` for development.
+- Exact `messages` key vocabulary beyond the examples, and the generic default wording.
+- Refresh timing (proactive before expiry plus one retry on 401, then redirect to login with the return URL).
+- Per-page options (design says 12/24/48/96; reconcile with `recordsPerPage` and the Phase 9 cap).
+- Unsaved-changes confirmation, create-then-redirect behaviour (use `config_form` `create.redirect`/`redirectClose` semantics mapped to SPA routes), toast queue.
+- Whether admin paths are removed from `fonoteka.go/docs/openapi.json` once the framework document exists (recommended: yes, one owner per path).
+- Package layout inside `summercms.go` for the embed/serve package, following beach-themed naming.
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Design
+- `.planning/phases/10-admin-vue-spa/design/README.md` — the full UI spec: tokens, screens, states, interactions, component list.
+- `.planning/phases/10-admin-vue-spa/design/Direction C v2.dc.html` (+ `support.js`) — viewable reference; props switch screens and states.
+
+### Roadmap and requirements
+- `.planning/ROADMAP.md` §Phase 10 — goal and success criteria.
+- `.planning/REQUIREMENTS.md` — ADMIN-06.
+- `.planning/PROJECT.md` — two-repo split (framework holds the admin SPA shell), stack constraints.
+- `.planning/research/STACK.md` — swag v1, openapi-typescript, goccy/go-yaml.
+
+### Phase 9 contract this phase consumes and amends
+- `.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-CONTEXT.md` — D-02 guard, D-06 typed schema, D-07 server-side labels, D-09/D-10/D-11 API paths, envelope and list contract, D-12 filters, D-13 hooks, D-15/D-16 relation manager, D-17 settings, D-18 navigation.
+- `.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-11-PLAN.md`, `09-12-PLAN.md` and their SUMMARYs once written — final state of navigation/settings endpoints, security matrix and OpenAPI generation.
+- `cabana/http.go` — route mounting (hardcoded `/_admin/api/v1` changed by D-03).
+- `cabana/auth.go` — login/refresh/logout/me (transport changed by D-19).
+- `cabana/form_schema.go`, `cabana/list_schema.go`, `cabana/filter_schema.go`, `cabana/relation.go`, `cabana/settings.go`, `cabana/navigation.go`, `cabana/schema_types.go` — the JSON the SPA renders.
+
+### OpenAPI tooling
+- `../fonoteka.go/scripts/check-openapi.sh` and `../fonoteka.go/scripts/swagger2openapi.go` — the generation/conversion/validation pattern to replicate for the framework document.
+
+### Płytarium config the SPA renders
+- `../fonoteka.go/plugins/golem15/fonoteka/controllers/{albums,artists,collections,genres,styles}/` — config_form/config_list (updated by D-13/D-14).
+- `../fonoteka.go/plugins/golem15/fonoteka/admin_navigation.go`, `admin_settings.go` — icons switched to lucide (D-11).
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/models/album/fields.yaml`, `columns.yaml` — PHP originals (real field set, D-08).
+
+### UI stack reference
+- `/media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/package.json` — the Vue/Tailwind/Reka/lucide versions the team already uses.
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `cabana` (~10k lines): complete admin API: auth, navigation, list/form/filter/relation schemas, CRUD, bulk delete, relation linked/candidates/link/unlink, settings. The SPA is its first client.
+- `bouncer.MintAudience` / `RefreshAudience` / blacklist: stay the token mechanism under cookie transport (D-19).
+- `phrasebook`: resolves labels and the new `messages` and SPA string bundle (D-13, D-20); CLDR plural data matches `Intl.PluralRules`.
+- `pact.DropdownOptionsProvider` and model-method options: pattern for the new relation options hook (D-17).
+- Phase 5 join-table contract: many-to-many sync on save (D-18).
+- `check-openapi.sh` pipeline (swag v1.16.6 → swagger2openapi → openapi-typescript 7.13.0).
+
+### Established Patterns
+- Optional capability interfaces type-asserted by the consumer (`RelationExtendOptionsQuery` follows Phase 9 D-13).
+- Fail-loud boot on malformed plugin YAML (`DisallowUnknownField`): applies to `messages` and `toolbar.buttons`.
+- Committed generated artifact + drift check (OpenAPI doc; now also `dist/` and the admin OpenAPI doc).
+- Framework stays app-agnostic: no Płytarium names in `summercms.go`, including SPA code.
+
+### Integration Points
+- `cabana` mount: prefix from config (D-03), SPA static serving + index.html base injection + history fallback (D-01, D-02), same prefix.
+- `backend` guard in the bouncer registry: cookie extraction + CSRF header check (D-19).
+- `/auth/me` already returns name/email; the user menu needs the role name too.
+- `fonoteka.go`: YAML toolbar/messages updates, lucide icons, optional `RelationExtendOptionsQuery` on Albums (scope to active collection, consistent with Phase 9 D-14).
+
+
+
+
+## Specific Ideas
+
+- The user wants the admin URL changeable per project for security ("/plytadmin", "/manage", "/horoadmin"), as in WinterCMS.
+- The user asked for "a best solution" to per-controller copy instead of Winter's `_list_toolbar.htm` partial: declarative actions plus translatable messages with proper Polish plurals.
+- The design was produced in claude.ai/design from a prompt listing three directions; the user chose Direction C v2 ("Generic modern dashboard", navy + sunny yellow) and treats it as the target.
+- The shell is multi-plugin by design (rail per registered main-menu item); Płytarium is one plugin among future ones (Użytkownicy, Media in the mock).
+
+
+
+
+## Deferred Ideas
+
+- **Phase 10.1: runtime admin extension point.** `AdminAssets()` on controllers (Winter `addJs`/`addCss`), served under the admin prefix and loaded when the controller opens; `type: widget` rendered as custom elements (plugins ship plain JS, no Vue coupling); `type: partial` rendered server-side via html/template; custom toolbar actions; a dev-mode switch serving plugin assets from disk. Needs a roadmap entry.
+- Ctrl+K command palette across all plugins' side menus.
+- Generic badge/icon column type (Albums format pills with disc/cassette icons).
+- Playwright browser e2e for the admin SPA (joins the Phase 8 carried-forward Playwright follow-up).
+- Admin navigation for the user and media plugins (shown in the mock) arrives with those ports.
+
+
+
+---
+
+*Phase: 10-admin-vue-spa*
+*Context gathered: 2026-09-26*
diff --git a/.planning/phases/10-admin-vue-spa/10-DISCUSSION-LOG.md b/.planning/phases/10-admin-vue-spa/10-DISCUSSION-LOG.md
new file mode 100644
index 0000000..2f9f63e
--- /dev/null
+++ b/.planning/phases/10-admin-vue-spa/10-DISCUSSION-LOG.md
@@ -0,0 +1,90 @@
+# Phase 10: Admin Vue SPA - 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-09-26
+**Phase:** 10-admin-vue-spa
+**Areas discussed:** Packaging & serving, UI kit & look, Types & relation options, Session & UX details
+
+---
+
+## Packaging & serving
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| summercms.go/admin, embedded | Vite project in framework repo, dist embedded and served by the binary | ✓ |
+| summercms.go/admin, served separately | Static deploy, CORS | |
+| fonoteka.go/admin | SPA in the app repo | |
+
+**User's choice:** Embedded, with the admin path configurable per project (e.g. /plytadmin, /manage) for security, as in WinterCMS.
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Commit dist | `go build` stays pure Go, drift check | ✓ |
+| Build via summer build | dist gitignored, Node needed at every build | |
+
+**User's choice:** Commit dist, after clarification. The user asked twice whether plugin changes (and Winter's `partial` field, `addJs`/`addCss`) need a rebuild. Resolved: they need a Go binary rebuild (plugin assets are embedded), never a framework SPA Node rebuild once the 10.1 extension point exists; Node is only for framework SPA changes.
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Both SPA and API move with backend.uri | Nothing reveals the admin location | ✓ |
+| Only the SPA moves | Fixed /_admin/api/v1 | |
+
+**User's choice:** Both move, conditional on it being safe; confirmed non-breaking (no external admin API consumer yet).
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Seam now, build later | Renderer registry + unsupported fallback now | ✓ |
+| Build it in Phase 10 | Assets, widgets, partials now | |
+| Only AdminAssets now | | |
+
+**User's choice:** Seam now, full implementation in Phase 10.1.
+
+---
+
+## UI kit & look
+
+The user generated three directions in claude.ai/design from a prompt Claude wrote, and chose Direction C v2 (handoff zip reviewed and copied to `design/`).
+
+| Question | Options | Selected |
+|----------|---------|----------|
+| Mock vs real YAML | Real YAML only / Extend Płytarium YAML | Real YAML only |
+| Nav icons | Lucide + Winter map / Lucide only / Winter names mapped | Lucide + Winter map |
+| Format badge icons | Plain text now / Badge column now | Plain text now |
+| Per-controller copy | Config keys + generic fallback / Generic only | User asked for the best solution beyond Winter's toolbar partial; Claude proposed `messages:` with CLDR plural forms chosen client-side via Intl.PluralRules plus declarative `toolbar.buttons`; locked |
+
+---
+
+## Types & relation options
+
+| Question | Options | Selected |
+|----------|---------|----------|
+| OpenAPI source | Framework-owned admin doc / Fonoteka's doc | Framework-owned admin doc |
+| Record typing | Generic schema-driven / Per-controller DTOs | Generic schema-driven |
+| Relation field options | Options endpoint / Embed in schema / Hybrid | Options endpoint |
+| Relation save payload | Field name with ids / Raw columns | Field name with ids |
+
+---
+
+## Session & UX details
+
+| Question | Options | Selected |
+|----------|---------|----------|
+| Token storage | httpOnly cookie / sessionStorage bearer / localStorage bearer | httpOnly cookie |
+| SPA chrome strings | Server phrasebook bundle / Bundled in SPA | Server phrasebook bundle |
+| Extras in scope | Settings screen / Filter bar / Playwright e2e | Settings screen, Filter bar |
+
+---
+
+## Claude's Discretion
+
+State management, router, HTTP client, dev loop, messages vocabulary and default wording, refresh timing, per-page options, dirty-form handling, redirects, removal of admin paths from the fonoteka OpenAPI doc, package layout.
+
+## Deferred Ideas
+
+- Phase 10.1 runtime extension point (AdminAssets, `type: widget`, `type: partial`, custom toolbar actions, dev-mode disk assets)
+- Ctrl+K command palette
+- Badge/icon column type
+- Playwright e2e for the admin SPA
+- User/media plugin admin navigation
diff --git a/.planning/phases/10-admin-vue-spa/design/Direction C v2.dc.html b/.planning/phases/10-admin-vue-spa/design/Direction C v2.dc.html
new file mode 100644
index 0000000..3fc8688
--- /dev/null
+++ b/.planning/phases/10-admin-vue-spa/design/Direction C v2.dc.html
@@ -0,0 +1,461 @@
+
+
+
Nie udało się zapisać. Popraw 2 pola oznaczone poniżej.
+
+
+
+
+
+
+
+
Pole Nazwa jest wymagane.
+
+
+
+
+ CNCzesław Niemen
+ AKAkwarium
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Pole Półka może mieć maksymalnie 12 znaków.
+
+
+
+
+
+
+
+
Wypożyczony
Płyta jest aktualnie poza domem
+
+
+
+
+
+
+
+
+
+
+
+
+ Kolor okładki
+
Nieobsługiwany typ pola: colorpicker
+
+
+
+
+
+
+
Redaktorzy
Osoby, które mogą edytować tę kolekcję
+
+
+
+
+
+
+
+
+
Imię i nazwisko
+
E-mail
+
Dodano
+
+
+
+
+
+
+
+
+
{{ e.ini }}{{ e.name }}
+
{{ e.email }}
+
{{ e.added }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
TW
Tomasz Wójcik
tomasz.wojcik@plytarium.pl
+
+
+
+
+
+
+
+
+ Album „Enigmatic” został zapisany
+
+
+
+
+
+
+
+
+
Dodaj redaktora
Wybierz osoby spoza obecnych redaktorów. Właściciel kolekcji nie jest wyświetlany.
+
+
+
+
+
+
+ {{ c.ini }}
+
{{ c.name }}
{{ c.email }}
+
+
+
+
+
+
+ 1–5 z 14
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.planning/phases/10-admin-vue-spa/design/README.md b/.planning/phases/10-admin-vue-spa/design/README.md
new file mode 100644
index 0000000..035daeb
--- /dev/null
+++ b/.planning/phases/10-admin-vue-spa/design/README.md
@@ -0,0 +1,387 @@
+# Handoff: SummerCMS Admin Panel — Direction C ("Generic modern dashboard")
+
+## Overview
+This is the admin panel for SummerCMS, a CMS framework. The mocks use data from one real app: **Płytarium**, a home catalogue of vinyl, CD and cassette releases. The panel is a **schema-driven Vue 3 SPA**. Every list and form is generated from YAML-defined `columns` and `fields`. Build generic components, not screens: one DataTable, one FormField row, one Tabs component, one RelationManager. The UI language is **Polish**, and all copy below is final.
+
+Screens covered: Login, Navigation shell (multi-plugin: Płytarium + Użytkownicy), List (Albumy) with its selected/empty/loading states, Form (Edycja albumu) with tabs and 422 errors, and the relation manager (Kolekcje → Redaktorzy) with its "Dodaj redaktora" modal. Light and dark mode are both included, plus tablet width.
+
+## About the Design Files
+`Direction C v2.dc.html` is a **design reference built in HTML**, not production code. Recreate it in the target Vue 3 codebase using its existing patterns. If the codebase has no UI setup yet, use Vue 3 + Vite + Tailwind with headless primitives (e.g. Radix Vue / Reka UI) and lucide-vue-next icons.
+
+To view it, open `Direction C v2.dc.html` in a browser. `support.js` must be in the same folder, and you need internet access for the fonts and icons. The component's props act as a state switcher:
+- `plugin`: `plytarium | users` (use `users` with `screen=list` to see the Users plugin list)
+- `flyout`: boolean; with `narrow`, shows the collapsed-rail flyout
+- `screen`: `login | list | form | relation`
+- `listState`: `default | selected | empty | loading`
+- `tab`: `basic | details`
+- `dark`, `narrow` (tablet), `errors` (422), `toast`, `modal`, `userMenu`: booleans
+
+All sample data sits in the `ALBUMS`, `EDITORS` and `CANDS` constants in the logic class.
+
+## Fidelity
+**High-fidelity.** Colours, type, spacing, radii and copy are final. Match them closely.
+
+---
+
+## Design Tokens
+
+### Colours
+| Token | Light | Dark | Use |
+|---|---|---|---|
+| bg | `#f4f6f9` | `#111726` | App background behind cards |
+| surface | `#ffffff` | `#182033` | Cards, header, inputs, footer bar |
+| subtle | `#f3f5f8` | `#1f283d` | Table header, search input fill, chips, avatar bg |
+| border | `#e6e9ef` | `#29334b` | Card borders, row dividers |
+| borderStrong | `#d2d8e2` | `#3a4661` | Input borders, unchecked checkbox, switch off |
+| text | `#141b2d` | `#eef1f6` | Primary text |
+| muted | `#566175` | `#a9b3c6` | Secondary text, column headers, icons |
+| placeholder | `#6b7588` | `#8a95ab` | Input placeholder |
+| primary | `#22304d` (navy) | `#fcd34d` (yellow) | Primary buttons, checked checkbox |
+| onPrimary | `#ffffff` | `#1b2540` | Text on primary |
+| danger | `#c62828` | `#f58a8a` | Destructive, errors |
+| dangerSoft | `#fdf0f0` | `#3a1d24` | Error banner bg, destructive hover |
+| okBg / okText | `#e3f4e8` / `#1c6b35` | `#173826` / `#8fdfa8` | "Tak" badge |
+| ring | `rgba(252,196,40,.55)` | `rgba(252,211,77,.45)` | Focus ring (3px) |
+| hover | `#f1f3f7` | `#212b42` | Hover bg for ghost buttons/rows |
+| sel | `#fdf3cf` | `#3a3622` | Selected row bg, current page button |
+| skel | `#eceff4` | `#263049` | Skeleton bars |
+| overlay | `rgba(20,27,45,.5)` | `rgba(5,8,16,.7)` | Modal backdrop |
+| side | `#1d2740` | `#0d1320` | Sidebar bg (sidebar is dark in both modes; dark mode adds a `#222b40` right border) |
+| accent | `#fcd34d` | same | Brand yellow: logo, active nav, avatar |
+| onAccent | `#1b2540` | same | Text on accent |
+| sidebar text | `#c3cbda` idle, `#9aa6bd` section label, `#ffffff` hover, `#fcd34d` active | | |
+| card shadow | `0 1px 2px rgba(20,27,45,.04), 0 4px 16px rgba(20,27,45,.05)` | `none` | |
+
+The brand is **dark navy + sunny yellow**. In light mode the primary is navy and yellow is only an accent. In dark mode yellow becomes the primary.
+
+### Typography
+- UI font: **DM Sans** (Google Fonts, opsz 9..40, weights 400/500/600/700). Base size 14px, line-height 1.5.
+- Mono: **DM Mono** 400/500. Used for the Półka shelf code and the `colorpicker` token.
+- Datetimes use DM Sans with `font-variant-numeric: tabular-nums`, 13px, muted colour.
+
+| Role | Size / weight / tracking |
+|---|---|
+| Page title (list) | 26px / 700 / -0.02em |
+| Record title (form) | 24px / 700 / -0.02em |
+| Login title | 22px / 700 / -0.02em |
+| Modal title | 20px / 700 / -0.01em |
+| Section title (Redaktorzy) | 17px / 700 |
+| Body / cell | 14px / 400 (Nazwa cell 600) |
+| Field label | 14px / 600 |
+| Column header | 12px / 600, muted (the sorted column uses the text colour) |
+| Helper / meta / error text | 13px |
+
+### Radii
+Inputs, buttons and selects: 10px. Cards: 16px. Login card: 16px. Modal: 20px. Inner table container and toggle cards: 12px. Tabs track: 12px, tab pill: 9px. Checkbox: 5px (6px in the form and modal). Pagination buttons: 8px. Badges, chips and switch: 999px. Avatars: 50%.
+
+### Spacing
+Page padding is 28px top/bottom and 32px left/right. Gaps between cards and blocks are 20px. Form card padding is 28px. The form grid gap is 22px (rows) × 24px (columns). Table cells use 14px horizontal padding, with 20px on the first and last columns.
+
+### Control heights
+- Primary/secondary buttons and search: **42px**
+- Form inputs, selects and login inputs: **44px**
+- Table header row: 44px. Body row: **54px** (56px in the relation manager). Modal option row: 54px.
+- Pagination buttons: 34px
+- Top header: 64px. Sidebar nav item: 40px.
+
+### Focus
+Every interactive element shows a visible **3px yellow ring** (`box-shadow: 0 0 0 3px var(--ring)`). Inputs also switch their border to `primary`. Buttons use `outline: 3px solid var(--ring); outline-offset: 2px`. Style `:focus-visible` this way and never remove it.
+
+---
+
+## Screens
+
+### 1. Login (`screen=login`)
+- Full-viewport background: `radial-gradient(ellipse at 50% 35%, #2b3a5c 0%, #1d2740 60%)`.
+- A centred column, max-width 400px, gap 24px:
+ - **Wordmark**: sun icon (lucide `sun`, 20px, yellow) in a 34px circle filled `rgba(252,211,77,.14)`, followed by "Summer**CMS**" at 18px/700 in white, with "CMS" in yellow. This is the only branding, because the admin URL is custom (e.g. `/plytadmin`).
+ - **Card**: white background, radius 16, padding 32, gap 18, shadow `0 24px 60px rgba(0,0,0,.35)`.
+ - Title: "Witaj ponownie"
+ - Field "Login lub e-mail" (input 44px)
+ - Field "Hasło" (password)
+ - Error state: the password input gets a danger border and `aria-invalid`. Below it sits an alert block (`role="alert"`, dangerSoft bg, danger text, radius 10, padding 12×14, `circle-alert` icon 18px) reading **"Nieprawidłowe dane logowania"**.
+ - Full-width primary button **"Zaloguj"** (44px).
+
+### 2. Navigation shell — multi-plugin (rail + section panel)
+SummerCMS replaces WinterCMS. It is a backend that hosts many plugins, and each plugin registers navigation the way Winter's `registerNavigation()` does: **one main-menu item** (label, icon, order, permissions) plus **its own side menu** (items, icons, permissions). Płytarium is just one of these plugins. The shell is built from that registry, and nothing in it is hardcoded per plugin.
+
+**Plugin rail (level 1 = Winter main menu)**
+- Always visible. Width 80px, colour `side` (`#1d2740` light / `#0d1320` dark), padding 14px 0 12px, column gap 6, centred.
+- Top: brand badge, a 40px rounded square (radius 12) filled `rgba(252,211,77,.14)` holding a `sun` icon (22px, yellow). `title="SummerCMS"`, bottom margin 14.
+- One item per registered main-menu entry, sorted by `order`:
+ - 68px wide, padding 8/6, radius 12, letter-spacing -0.01em.
+ - 20px icon, with the label below it at 11px (line-height 1.2, centred).
+ - Idle: `#c3cbda`. Hover: `rgba(255,255,255,.08)` with white text.
+ - Active: bg `rgba(252,211,77,.14)`, text/icon `#fcd34d`, weight 700, `aria-current="page"`.
+ - Focus: 3px ring.
+ - Mock entries: **Płytarium** (`disc-3`), **Użytkownicy** (`users`), **Media** (`image`).
+- A flex spacer, then **Ustawienia** (`settings`) pinned to the bottom. Settings is a separate area where plugins register settings pages, the same as Winter.
+- When the panel is collapsed, a 40px "Rozwiń menu" button (`panel-left-open`) appears above Ustawienia.
+- Wrap the rail in `