` with `@onclick` handlers. Screen readers cannot identify them as interactive. Keyboard users cannot Tab to them or activate with Enter/Space.
+
+**Example (CafeDesktop.razor):**
+```razor
+
+
AddToCart(product)">
+ ...
+
+
+
+
+```
+
+---
+
+### 3. No ARIA Labels on Interactive Icons — WCAG 2.1 §4.1.2
+
+**Files:** `Components/Auth/AuthButton.razor`, `Components/Auth/AuthInput.razor` (line 37), all layout files
+**Impact:** Icon-only buttons (close, toggle, back) have no accessible names — screen readers announce nothing or raw Unicode.
+
+**Example (AuthInput.razor ~line 37):**
+```razor
+
+
+
+
+
+```
+
+---
+
+### 4. Error/Success Messages Missing `role="alert"` — WCAG 2.1 §4.1.3
+
+**Files:** `Pages/Auth/LoginAdmin.razor` (lines 28–40), `Pages/Pos/Cafe/CafeDesktop.razor`
+**Impact:** Dynamic status changes (login error, payment success, cart update) are not announced to screen readers.
+
+**Example (LoginAdmin.razor ~line 29):**
+```razor
+
+
+ @_errorMessage
+
+
+
+
+ @_errorMessage
+
+```
+
+---
+
+### 5. Hardcoded Vietnamese Strings in POS UI — Localization Failure
+
+**File:** `Pages/Pos/Cafe/CafeDesktop.razor` and all POS vertical pages
+**Impact:** English-language users see Vietnamese text. App cannot support international merchants.
+
+**Examples found (CafeDesktop.razor):**
+| Line | Hardcoded String | Should Be |
+|------|-----------------|-----------|
+| 24 | `"Đang tải..."` | `@L["Common_Loading"]` |
+| 25 | `"Không thể tải dữ liệu"` | `@L["Common_LoadError"]` |
+| 66 | `"Đơn hàng"` | `@L["Pos_OrderPanel_Title"]` |
+| 67 | `"món"` | `@L["Pos_CartItem_Unit"]` |
+| 89 | `"Nhập mã voucher..."` | `@L["Pos_Voucher_Placeholder"]` |
+| 97 | `"Giảm giá"` | `@L["Pos_Discount_Label"]` |
+| 107 | `"Tổng cộng"` | `@L["Pos_Total_Label"]` |
+| 117 | `"Đang tạo đơn..."` | `@L["Pos_CreatingOrder"]` |
+| 122 | `"Thanh toán"` | `@L["Pos_Checkout_Button"]` |
+
+Also found in layouts:
+- `AdminLayout.razor` (line ~160): `"Có lỗi xảy ra"`, `"Vui lòng thử lại"`, `"Tải lại"`
+- `StaffLayout.razor` (line 148): Same error boundary text
+- `PosLayout.razor` (lines 29, 65, 115): `"GoodGo POS"`, `"Menu"`, `"Đơn hàng"`
+
+---
+
+### 6. Hardcoded Color Values Instead of CSS Variables
+
+**Files:** `Pages/Pos/Cafe/CafeDesktop.razor`, `Pages/Auth/LoginAdmin.razor`, multiple admin pages
+**Impact:** Theme overrides are impossible. Colors are not consistent with the design token system.
+
+**Examples:**
+```razor
+
+style="background:rgba(139,92,246,0.1);color:#8B5CF6;"
+style="background:rgba(239,68,68,0.12);color:#EF4444;"
+style="background-color:rgba(139,92,246,0.125);"
+
+
+class="status-purple"
+class="status-danger"
+```
+
+**Hardcoded colors to replace:**
+| Value | Should Be |
+|-------|-----------|
+| `#16A34A` | `var(--color-success)` |
+| `#EF4444` | `var(--color-danger)` |
+| `#8B5CF6` | `var(--color-purple)` |
+| `rgba(139,92,246,0.1)` | `var(--color-purple-subtle)` |
+| `rgba(239,68,68,0.12)` | `var(--color-danger-subtle)` |
+
+---
+
+## Warnings
+
+Issues that create significant technical debt or UX inconsistency.
+
+### 7. 2,316 Inline Style Attributes
+
+Inline styles are scattered across all pages — especially POS desktop views, admin shop pages, and dashboard. This makes CSS maintenance impossible and prevents design system enforcement.
+
+**Top offending patterns:**
+```razor
+style="display:flex;flex-direction:column;gap:24px;"
+style="padding:6px 12px;border-radius:8px;border:none;"
+style="position:absolute;left:@{X}px;top:@{Y}px;"
+```
+
+**Strategy:** Create CSS utility classes and component classes. Move inline styles to scoped `.razor.css` files.
+
+---
+
+### 8. Inconsistent Spacing Scale
+
+The design uses 10+ different spacing values without a defined scale:
+- Gaps: 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 48px
+- Padding: 6, 8, 10, 12, 16, 20, 24px
+- Border radius: 6, 8, 10, 12, 14, 20, 24px
+
+**Recommended scale:**
+```css
+/* Spacing: 4-point scale */
+--space-1: 4px; --space-2: 8px; --space-3: 12px;
+--space-4: 16px; --space-5: 20px; --space-6: 24px;
+--space-8: 32px; --space-12: 48px;
+
+/* Border radius: 3 values */
+--radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px;
+```
+
+---
+
+### 9. Missing Contrast Ratio for Secondary Text — WCAG 2.1 §1.4.3
+
+**File:** `wwwroot/css/admin.css`
+
+```css
+/* Current — MAY fail WCAG AAA */
+--admin-text-secondary: #ADADB0; /* ratio ~5.08:1 on #1A1A1D — FAILS AAA (7:1) */
+--admin-text-tertiary: #8B8B90; /* ratio ~4.13:1 on #1A1A1D — FAILS AA (4.5:1) */
+```
+
+`--admin-text-tertiary` likely **fails WCAG AA** for normal text. Needs contrast validation.
+
+---
+
+### 10. Cart Items Use `
` Instead of Semantic List
+
+**File:** `Pages/Pos/Cafe/CafeDesktop.razor`
+Cart items rendered as generic `
` elements. Should be `
/- ` structure for screen readers to announce list count and items.
+
+---
+
+### 11. No `.razor.css` Scoped Stylesheets Per Component
+
+All 8 reusable components (`AuthButton`, `AuthInput`, `OtpInput`, etc.) have zero scoped CSS files. Styles are defined globally in `auth.css`. This creates unintended style leakage and makes component refactoring dangerous.
+
+---
+
+### 12. OTP Input Missing ARIA Group Label
+
+**File:** `Components/Auth/OtpInput.razor` (lines 12–19)
+The 6-digit OTP input is a group of individual `` elements but lacks `role="group"` and `aria-label="One-time password"`. Screen readers will announce 6 separate unlabeled inputs.
+
+---
+
+### 13. No Focus Trap in Modal Overlays
+
+**Files:** `Layout/PosLayout.razor`, admin dialog pages
+When mobile overlays or modals open, focus is not trapped within them. Users pressing Tab will cycle through background content, violating WCAG 2.1 §2.1.2.
+
+---
+
+## Improvements
+
+Recommendations that would improve UX quality and developer experience.
+
+### A. Create Component-Scoped CSS Files
+
+For each component in `Components/`, create a matching `.razor.css` file:
+```
+Components/Auth/AuthButton.razor.css
+Components/Auth/AuthInput.razor.css
+Components/Pos/ResponsiveOrderPanel.razor.css
+```
+
+### B. Add Password Strength Indicator
+
+**File:** `Pages/Auth/Register.razor`
+Registration form has no visual password strength feedback. Add a 4-step strength bar (weak → fair → good → strong) using the existing `PasswordStrengthCalculator` pattern from Swift app.
+
+### C. Standardize Icon Sizes to 3 Tiers
+
+Currently uses: 12, 14, 16, 18, 20, 24, 28, 32px. Reduce to:
+```css
+--icon-sm: 16px; /* Inline, label */
+--icon-md: 20px; /* Button, nav */
+--icon-lg: 24px; /* Header, feature */
+```
+
+### D. Add `aria-expanded` to Expandable Sections
+
+**File:** `Pages/Admin/Shop/ShopRecipes.razor`
+Accordion-style expand/collapse sections lack `aria-expanded` and `aria-controls`. Screen readers cannot determine collapsed state.
+
+### E. Add `aria-busy` to Async Loading States
+
+Async data-fetch loading spinners don't set `aria-busy="true"` on the container, so screen readers don't know content is loading.
+
+### F. Introduce Design Token Documentation
+
+Create a living style guide page at `/admin/design-system` (dev only) that shows all color tokens, spacing, typography, and component variants. Reference: MudBlazor Theme Manager pattern.
+
+### G. Validate Table Semantics
+
+Admin tables (staff management, inventory, orders) should verify `
` on all headers. MudBlazor's `MudTable` typically handles this, but custom HTML tables may not.
+
+---
+
+## Action Items
+
+Prioritized next steps.
+
+| # | Priority | Effort | Item | Files |
+|---|----------|--------|------|-------|
+| 1 | 🔴 Critical | Small | Add `:focus-visible` styles globally | `wwwroot/css/app.css` |
+| 2 | 🔴 Critical | Large | Replace clickable `` with ` |