diff --git a/docs/cross-module-consistency-audit-2026-06-09.md b/docs/cross-module-consistency-audit-2026-06-09.md
new file mode 100644
index 0000000..7f774f8
--- /dev/null
+++ b/docs/cross-module-consistency-audit-2026-06-09.md
@@ -0,0 +1,180 @@
+# Cross-Module Consistency Report: Offers, Invoices, Orders
+
+> Generated 2026-06-09 by a multi-agent UI/UX audit (4 by-dimension examiners + synthesis)
+> across the Offers (nabídky), Invoices (faktury), and Orders (objednávky) modules.
+> Examination only — no code was changed. File:line refs are at the time of the audit.
+
+## 1. Executive Summary
+
+The three document modules (Offers, Invoices, Orders) share a strong common foundation — `PageEnter`/`PageHeader`/`Card`/`FilterBar`/`DataTable`/`StatusChip`/`Pagination`, a near-identical line-item editor (dnd-kit drag, mobile cards, monospace per-row totals, per-rate VAT breakdown), and a uniform totals layout — so the divergences are concentrated in a handful of presentational and behavioral details rather than the architecture. **No single module is canonical across the board:** Invoices is the most mature on list-level intelligence (KPI StatCards, overdue row tinting) and is the only one with a polished load pattern (ReceivedInvoices' `hasLoadedOnce` skeleton suppression); Issued Orders is the cleanest detail-page reference (single editable form with a `readOnly` prop, semantically correct status-transition button colors); and Offers is the best on list-level state richness (three-tier `rowSx` tinting, search-aware empty states) but the worst on detail-form fidelity (raw HTML checkboxes, action-icon overload). The highest-value work clusters into four buckets: bring Orders up to Invoices' list intelligence (KPIs, filters, row tinting), converge the three detail forms on shared MUI kit components (Autocomplete customer picker, MUI Checkbox, RichEditor notes), fix two genuine safety/feature bugs (delete-button guards and Orders' missing delete), and a long tail of cheap label/width/alignment unifications in the line-item tables.
+
+## 2. Recommended Canonical Patterns
+
+| Dimension | Standardize on | Why |
+| ------------------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
+| List KPI cards | **Invoices** (`Invoices.tsx:420-505`) | Only module with a 4-card metrics grid; gives business context Orders/Offers lack |
+| List load/skeleton | **ReceivedInvoices** (`hasLoadedOnce` ref, lines 325/688/784) | Skeleton only on first mount, suppressed on refetch — no full-page blocking jank |
+| List row state tinting | **Offers** (`Offers.tsx:650-684`) three-tier `rowSx` | Richest at-a-glance lifecycle signal; Invoices' single overdue tint is the minimal version |
+| List status filter | **Tabs** for ≤4 states (Offers/Invoices), **Select** for ≥5 (IssuedOrders) | Tabs show all options inline; Select scales — choose by option count |
+| Search-aware empty state | **Offers** (`Offers.tsx:840-855`) | Distinguishes search-empty (no CTA) from list-empty (with CTA) |
+| Detail read-only mode | **IssuedOrderDetail** (single form + `readOnly` prop, `:638`) | DRY; avoids InvoiceDetail's duplicate read-only JSX branch that must be hand-synced |
+| Status-transition button colors | **IssuedOrderDetail** (`:903-917`) | Destructive = `outlined`+`error`, positive = `contained`+`primary` (semantically correct) |
+| Save-button loading | **Invoice/Order** (CircularProgress + text) | Clearer visual signal than Offers' text-only swap |
+| Detail guard placement | **OfferDetail** (all guards top-level, `:1087-1091`) | Flattest; no `if (!dataReady)` buried inside render branches |
+| Customer/supplier picker | **MUI Autocomplete freeSolo** (as in `ReceivedInvoices.tsx:914-929`) | Keyboard-accessible, searchable, Material-standard |
+| Boolean fields | **MUI `CheckboxField` kit** (as in OrdersReceived modal) | Themed, accessible; replaces raw `` |
+| Notes fields | **RichEditor** (Offers/Orders already) | Uniform editing; future-proof for formatting |
+| `issued_by` | **Read-only, auto-filled** (Invoices, `:1881-1885`) | Immutable provenance tied to the issuing user |
+| Currency options | **Company settings** (Offers/Invoices) | Admin-configurable without code change |
+| Line-item labels/widths | **Invoices+Orders majority** ("Jedn. cena", qty `5.5rem`, remove `2.5rem`, `align="center"`) | 2-of-3 already agree; Offers is the lone outlier |
+| Amount column header | **"Celkem"** (all but ReceivedInvoices' "Částka") | Single label for the same concept |
+
+## 3. Inconsistencies by Dimension
+
+### A. Tables & Lists
+
+**HIGH — Orders lack KPI StatCards.** Invoices renders a 4-card metrics grid (`Invoices.tsx:420-505`; ReceivedInvoices `:687-761`); IssuedOrders, OrdersReceived, and Offers render none. Orders users lose pipeline visibility (count by status, total value). Fix: add a 4-StatCard grid to IssuedOrders/OrdersReceived mirroring the Invoices layout. Decide whether Offers warrants its own. Effort: **M**.
+
+**HIGH — Offers row-action overload (6-7 icons vs 3).** `Offers.tsx:540-641` renders View/Edit, Duplicate, Show/Create Order, Invalidate, PDF, Delete; Invoices/IssuedOrders/OrdersReceived keep 3. Fix: reduce Offers to 4 (View/Edit, Order toggle, PDF, Delete); move Duplicate/Invalidate into a row overflow menu or the detail page. Effort: **M**.
+
+**MED — Orders missing list features that Invoices/Offers have.**
+
+- _Row state tinting:_ Offers 3-tier (`:650-684`), Invoices 1-tier overdue (`:510-526`), all three Orders modules + ReceivedInvoices = none. Add `rowSx` (completed→success wash, overdue/expired→warning, voided→opacity) using the channel-alpha convention. Effort: **S** each.
+- _Status filter:_ OrdersReceived has none; add a Select like IssuedOrders (`:305-313`, `STATUS_OPTIONS` `:53`). Effort: **S**.
+- _Sortable columns:_ IssuedOrders/OrdersReceived expose only 3 `sortKey`s vs 5-6 in Invoices/Offers; add customer_name, total, status. Effort: **S**.
+
+**MED — Load pattern blocks the page on refetch.** Offers (`:453`), Invoices (`:402`), IssuedOrders (`:189`), OrdersReceived (`:328`) return a full `` whenever `isPending`; only ReceivedInvoices suppresses the skeleton after first load (`hasLoadedOnce`, `:325/688/784`). Adopt the `hasLoadedOnce` ref pattern everywhere. Effort: **S-M**.
+
+**MED — Amount column label split.** ReceivedInvoices uses "Částka"; everyone else "Celkem". Rename "Částka"→"Celkem". (supplier-vs-customer terminology "Dodavatel"/"Zákazník" is correctly domain-specific — leave it.) Effort: **S**.
+
+**LOW — Offers tabs not centered.** Invoices/Orders wrap Tabs in a centered Box (`Invoices.tsx:712-721`, `Orders.tsx:161-170`); Offers (`:717-726`) left-aligns. Effort: **S**.
+
+**LOW — Empty-state copy not search-aware.** Offers distinguishes search-empty vs list-empty (`:840-855`); the others show one message (+ stale CTA when filtered to empty). Effort: **S**.
+
+_Already fine: PageHeader, FilterBar layout, Pagination placement, StatusChip colors, search-placeholder copy, draft-banner presence (Offers/Invoices by design)._
+
+### B. Detail Buttons & Layout
+
+**HIGH — Delete-button safety bugs + Orders feature gap.**
+
+- OfferDetail (`:1191-1199`) allows delete even when invalidated/locked/completed.
+- InvoiceDetail (`:1167-1175`, `:1734-1742`) allows delete even when `paid`.
+- IssuedOrderDetail has **no delete at all** (no button/mutation/handler).
+ Fix: add `!readOnly`/status guards to Offers and Invoices; add a guarded delete to IssuedOrderDetail for parity. Effort: **M**.
+
+**HIGH — Detail read-only handling diverges.** IssuedOrderDetail uses one form with a `readOnly`/`editable` flag (`:638`); InvoiceDetail forks a whole separate read-only JSX branch for paid invoices (`:1104-1615`) that must be hand-synced; OfferDetail is always editable. Fix: refactor InvoiceDetail's paid view to the single-form-`readOnly`-prop model. Effort: **L**.
+
+**MED — Status-transition button styling inverted.** InvoiceDetail emphasizes positive ("paid"→`contained`+`primary`, `:1719-1733`); IssuedOrderDetail emphasizes danger ("cancelled"→`outlined`+`error`, `:903-917`). Standardize on the Order rule. Effort: **S**.
+
+**MED — Back-button target inconsistent.** OfferDetail→`/offers` (`:1108`), InvoiceDetail→`/invoices` (`:1124`/`:1639`), IssuedOrderDetail→`/orders?tab=vydane` (`:836`). Make tabbed-landing modules carry the tab param: Invoices→`/invoices?tab=issued`. Effort: **S**.
+
+**LOW — Save-button loading style.** Offers text-only (`:1187`); Invoice/Order spinner+text. Switch Offers to spinner+text. Effort: **S**.
+
+**LOW — Create-success invalidation scope.** OfferDetail invalidates `["offers","orders","projects","invoices"]` (`:927`); Invoice/Order invalidate only their own domain. Verify Invoice/Order touch no foreign domains, else widen. Effort: **S**.
+
+**LOW — Guard placement.** Hoist Invoice/Order `if (!dataReady)` guards to OfferDetail's top-level pattern when touching those files. Effort: **S**.
+
+_Already fine: PageEnter wrapper, header layout + `headerActionsSx`, StatusChip-in-header, mobile breakpoints, Card sectioning, items-table structure, totals block, permission guards._
+
+### C. Forms & Fields
+
+**HIGH — Customer/supplier picker: 3 different widgets.** Offers (`OfferDetail.tsx:1307-1373`) and Invoices (`InvoiceDetail.tsx:1816-1876`) use a hand-rolled searchable dropdown; IssuedOrders (`:935-948`) uses a plain non-searchable `