From 0b4ffb7146add8e719a2e4e3c46bc4a6c965b899 Mon Sep 17 00:00:00 2001 From: Jacek Pyziak Date: Tue, 28 Apr 2026 22:47:14 +0200 Subject: [PATCH] feat(110): statistics summary Phase 110 complete: - add Statistics -> Podsumowanie page - add monthly order count and value charts per integration plus total - use Chart.js with table fallback and 04-2026 default history start - update PAUL and DOCS technical documentation --- .paul/PROJECT.md | 10 +- .paul/ROADMAP.md | 17 +- .paul/STATE.md | 46 +- .paul/changelog/2026-04-28.md | 16 + .paul/codebase/architecture.md | 18 +- .paul/codebase/db_schema.md | 11 + .paul/codebase/tech_changelog.md | 15 + .../110-statistics-summary/110-01-PLAN.md | 266 ++++++ .../110-statistics-summary/110-01-SUMMARY.md | 197 ++++ DOCS/ARCHITECTURE.md | 175 ++++ DOCS/DB_SCHEMA.md | 863 ++++++++++++++++++ DOCS/TECH_CHANGELOG.md | 59 ++ public/assets/css/app.css | 2 +- .../js/modules/statistics-summary-charts.js | 119 +++ resources/lang/pl.php | 24 + resources/scss/app.scss | 68 ++ resources/views/layouts/app.php | 5 + resources/views/statistics/summary.php | 208 +++++ routes/web.php | 1 + .../Statistics/OrdersStatisticsController.php | 271 ++++++ .../Statistics/OrdersStatisticsRepository.php | 89 ++ 21 files changed, 2454 insertions(+), 26 deletions(-) create mode 100644 .paul/phases/110-statistics-summary/110-01-PLAN.md create mode 100644 .paul/phases/110-statistics-summary/110-01-SUMMARY.md create mode 100644 DOCS/ARCHITECTURE.md create mode 100644 DOCS/DB_SCHEMA.md create mode 100644 DOCS/TECH_CHANGELOG.md create mode 100644 public/assets/js/modules/statistics-summary-charts.js create mode 100644 resources/views/statistics/summary.php diff --git a/.paul/PROJECT.md b/.paul/PROJECT.md index 1916d26..1021325 100644 --- a/.paul/PROJECT.md +++ b/.paul/PROJECT.md @@ -12,8 +12,8 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów | Attribute | Value | |-----------|-------| -| Version | 3.3.0 | -| Status | v3.3 shipped - UI Filters complete | +| Version | 3.4.0 | +| Status | v3.4 shipped - Statistics Summary complete | | Last Updated | 2026-04-28 | ## Requirements @@ -113,6 +113,7 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów - [x] Idempotentna jednorazowa wysylka e-mail per zamowienie: tabela deduplikacji `automation_email_once_deliveries` (UNIQUE KEY rule_id+action_id+order_id), checkbox "Wyslij tylko raz" w konfiguracji akcji, markSent() tylko po sukcesie — Phase 107 - [x] Delivery Status Management: tabela `delivery_statuses` z CRUD panelem `/settings/delivery-statuses`, `DeliveryStatus::setRepository()` z DB fallbackiem, integracja DB-driven w dropdownach automatyzacji (warunek shipment_status + akcja update_shipment_status), osobna podstrona formularza CRUD (BREAKING: drop backward compat dla starych grupowych kluczy automatyzacji) — Phase 108 - [x] Checkbox dropdown multi-select filters: `/statistics/orders` korzysta z progresywnie ulepszanych selectow multiple z checkboxami, opcja "Wszystkie" i zachowanym kontraktem GET — Phase 109 +- [x] Podsumowanie statystyk: `Statystyki -> Podsumowanie` z miesiecznymi wykresami liczby i wartosci zamowien per integracja plus `Razem`, Chart.js i fallback tabelaryczny — Phase 110 ### Deferred @@ -121,7 +122,7 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów ### Active (In Progress) -- [ ] (brak — v3.3 zakonczony, oczekiwanie na kolejny milestone) +- [ ] (brak — v3.4 zakonczony, oczekiwanie na kolejny milestone) ### Planned (Next) @@ -198,6 +199,7 @@ PHP (XAMPP/Laravel), integracje z API marketplace'Ăłw (Allegro, Erli) oraz API | DeliveryStatus::setRepository() pattern: DB fallback dla static final class | Operator dodaje status w UI bez zmian kodu; `getAllOptions()`/`label()`/`getColor()` ladują z DB gdy repo ustawione, fallback na hardcoded ALL_STATUSES/LABEL_PL | 2026-04-27 | Active | | Drop backward compat dla starych grupowych kluczy automatyzacji (Phase 108-02) | Kolizja semantyczna: stary `picked_up` mapował na `delivered`, nowy klucz DB `picked_up` to "Odebrana przez kuriera" — odwrotne końce cyklu. Hybrid evaluation by silently dawała wrong matches | 2026-04-27 | Active | | Path params w controllerach via `$request->input('id')` (nie jako argumenty metody) | Konwencja routera projektu: handler wywoływany z jednym argumentem `$request`, params siedzą jako attributes — `ReceiptController::show()` jako wzorzec | 2026-04-27 | Active | +| Statistics Summary Chart.js CDN + start `2026-04-01` | Interaktywne wykresy bez zmiany build pipeline; historia podsumowania ma zaczynac sie od `04-2026` mimo starszych danych | 2026-04-28 | Active | ## Success Metrics @@ -229,6 +231,6 @@ Quick Reference: --- *PROJECT.md — Updated when requirements or context change* -*Last updated: 2026-04-28 after v3.3 UI Filters milestone completion (Phase 109)* +*Last updated: 2026-04-28 after v3.4 Statistics Summary milestone completion (Phase 110)* diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md index 4ed4ae2..fdaf8be 100644 --- a/.paul/ROADMAP.md +++ b/.paul/ROADMAP.md @@ -6,7 +6,7 @@ orderPRO to narzedzie do wielokanalowego zarzadzania sprzedaza. Projekt przechod ## Current Milestone -Brak aktywnego milestone - v3.3 zamkniety. Nastepny milestone do zaplanowania. +Brak aktywnego milestone - v3.4 zamkniety. Nastepny milestone do zaplanowania. ## Next Milestone @@ -19,6 +19,19 @@ Kandydaci w kolejce: ## Completed Milestones +
+v3.4 Statistics Summary - 2026-04-28 (1 phase, 1 plan) + +Dodano pierwsza pozycje `Statystyki -> Podsumowanie` z miesiecznymi wykresami liczby i wartosci zamowien. Kazda integracja ma osobna serie, a dodatkowa seria `Razem` sumuje miesiac. Domyslny start historii to `04-2026`. + +| Phase | Name | Plans | Status | +|-------|------|-------|--------| +| 110 | Statistics Summary | 1/1 | Complete | + +Archive: `.paul/phases/110-statistics-summary/` + +
+
v3.3 UI Filters - 2026-04-28 (1 phase, 1 plan) @@ -441,4 +454,4 @@ Archive: `.paul/milestones/v0.1-ROADMAP.md` --- *Roadmap created: 2026-03-12* -*Last updated: 2026-04-27 - v3.2 Delivery Status Management milestone closed (Phase 108, 2 plans)* +*Last updated: 2026-04-28 - v3.4 Statistics Summary milestone closed (Phase 110)* diff --git a/.paul/STATE.md b/.paul/STATE.md index 57fd7d4..b912483 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -5,42 +5,42 @@ See: .paul/PROJECT.md (updated 2026-04-28) **Core value:** Sprzedawca moze obslugiwac zamowienia ze wszystkich kanalow sprzedazy i nadawac przesylki bez przelaczania sie miedzy platformami. -**Current focus:** Brak aktywnego milestone - v3.3 zamkniety +**Current focus:** Brak aktywnego milestone - v3.4 zamkniety ## Current Position -Milestone: v3.3 - COMPLETE (UI Filters) -Phase: 109 of 109 - COMPLETE -Plan: 109-01 - COMPLETE -Version: 3.3.0 -Status: v3.3 shipped - gotowy do nastepnego milestone +Milestone: v3.4 Statistics Summary - COMPLETE +Phase: 110 of 110 - COMPLETE +Plan: 110-01 - COMPLETE +Version: 3.4.0 +Status: v3.4 shipped - gotowy do nastepnego milestone -Last activity: 2026-04-28 - UNIFY Phase 109 / v3.3 milestone complete +Last activity: 2026-04-28 - UNIFY Phase 110 / v3.4 milestone complete Progress: -- Milestone v3.3: [##########] 100% (1/1 phases, 1/1 plans) +- Milestone v3.4: [##########] 100% (1/1 phases, 1/1 plans) ## Loop Position Current loop state: ``` -v3.3 milestone: - Phase 109 (Checkbox Multiselect Filters): - Plan 109-01: PLAN done APPLY done UNIFY done - -> Phase 109 closed --> v3.3 milestone closed +v3.4 milestone: + Phase 110 (Statistics Summary): + Plan 110-01: PLAN done APPLY done UNIFY done + -> Phase 110 closed +-> v3.4 milestone closed ``` ## Session Continuity Last session: 2026-04-28 -Stopped at: v3.3 milestone closed +Stopped at: v3.4 milestone closed Next action: /paul:milestone - wybor i zaplanowanie nastepnego milestone -Resume file: .paul/phases/109-checkbox-multiselect-filters/109-01-SUMMARY.md +Resume file: .paul/phases/110-statistics-summary/110-01-SUMMARY.md ## Git State -Last commit: feat(109): checkbox multiselect filters +Last commit: feat(110): statistics summary Branch: main Feature branches merged: none @@ -61,4 +61,16 @@ Feature branches merged: none | Expected | Invoked | Notes | |----------|---------|-------| -| sonar-scanner (required) | o | Wymagany po APPLY 108-01 i 108-02 — odlozony | +| sonar-scanner (required) | o | Wymagany po APPLY 108-01 i 108-02 - odlozony | + +## Skill Audit (Phase 110) + +| Expected | Invoked | Notes | +|----------|---------|-------| +| sonar-scanner (required) | yes | Skan uruchomiony po APPLY; raport wyslany do SonarQube. | + +## Phase 110 Notes + +- Local HTTP verification blocked by MySQL/XAMPP connection refused. +- PHPUnit not run: `composer` unavailable in PATH and `vendor/` absent. +- Sonar issue import to `DOCS/todo.md` not performed because SonarQube MCP/resources are unavailable in this session. \ No newline at end of file diff --git a/.paul/changelog/2026-04-28.md b/.paul/changelog/2026-04-28.md index 27e6202..99bdefb 100644 --- a/.paul/changelog/2026-04-28.md +++ b/.paul/changelog/2026-04-28.md @@ -2,6 +2,10 @@ ## Co zrobiono +- [Phase 110, Plan 01] Dodano `Statystyki -> Podsumowanie` z miesiecznymi wykresami liczby i wartosci zamowien. +- Wykresy korzystaja z Chart.js 4.4.8 CDN, maja serie per integracja oraz linie `Razem`. +- Ustawiono domyslny poczatek historii na `2026-04-01` (`04-2026`) mimo starszych danych. +- Na desktopie wykresy sa obok siebie, a pod nimi dwie tabele fallback rowniez obok siebie. - [Phase 109, Plan 01] Wdrozono checkbox dropdown multi-select filters na `/statistics/orders`. - Zachowano kontrakt GET `channels[]` i `status_groups[]` przez synchronizacje z natywnym `` controls after `DOMContentLoaded`. - Keeps the original select in the form, synchronizes option `selected` state, and preserves native GET/POST names such as `channels[]` and `status_groups[]`. -- Used by `/statistics/orders` filters to display a compact trigger, checkbox dropdown, "Wszystkie" bulk toggle, and selected count. +- Used by `/statistics/orders` and `/statistics/summary` filters to display a compact trigger, checkbox dropdown, "Wszystkie" bulk toggle, and selected count. - Progressive enhancement: if JavaScript fails, the native multi-select remains visible. +### Statistics Summary Charts (`public/assets/js/modules/statistics-summary-charts.js`) +- Loaded globally from `resources/views/layouts/app.php` after Chart.js 4.4.8 CDN; activates only when `#js-statistics-summary-data` exists. +- Reads JSON produced by `OrdersStatisticsController::summary()` and renders two interactive Chart.js line charts on `/statistics/summary`. +- Chart 1 displays monthly order counts per selected integration plus a `Razem` line. +- Chart 2 displays monthly gross order values per selected integration plus a `Razem` line. +- The PHP view keeps table fallbacks under both charts, so the data remains visible if JavaScript fails. + ## Key Data Flows ### Order Lifecycle @@ -61,6 +68,13 @@ HTTP Request 2. **Status update** — `OrdersController::updateStatus()` → `OrdersRepository::updateStatus()` → automation check 3. **Status sync** — Cron → `AllegroStatusSyncService` / `ShopproStatusSyncService` → carrier API +### Statistics Summary +1. **Request** — `/statistics/summary` → `OrdersStatisticsController::summary()` +2. **Filters** — controller reuses statistics filter semantics: date range, `channels[]`, `status_groups[]`, default status groups excluding cancelled; default history starts at `2026-04-01`. +3. **Aggregation** — `OrdersStatisticsRepository::aggregateByMonth()` groups existing `orders` rows by `YYYY-MM` and channel key, using the same effective date/channel/status/gross amount SQL helpers as the daily report. +4. **View model** — controller builds per-integration series and total series for order count and gross value charts. +5. **Render** — `resources/views/statistics/summary.php` renders filters, chart JSON, two canvas targets, and table fallbacks. + ### Shipment Flow 1. **Create** — `ShipmentController::create()` → `ShipmentProviderRegistry` → carrier `ShipmentService::createShipment()` → `ShipmentPackageRepository::insert()` 2. **Track** — Cron `ShipmentTrackingHandler` → `ShipmentTrackingRegistry` → carrier tracking API → `ShipmentPackageRepository::updateDeliveryStatus()` diff --git a/.paul/codebase/db_schema.md b/.paul/codebase/db_schema.md index 3554783..839b05c 100644 --- a/.paul/codebase/db_schema.md +++ b/.paul/codebase/db_schema.md @@ -850,3 +850,14 @@ Default keys: `cron_run_on_web`, `cron_web_limit`, `gs1_api_login`, `gs1_prefix` | Audit via JSON | `payload_json` snapshots in orders, shipments, receipts | | Migrations | `database/migrations/YYYYMMDD_NNNNNN_description.sql` | | Deferred indexes | `idx_order_addresses_order_type`, `idx_shipment_packages_order_delivery` — apply at >50k orders | + +## Reporting Usage + +**Statistics Summary (`/statistics/summary`)** — no dedicated reporting tables. +- Reads existing `orders` rows and groups by month using the same effective order date used by `/statistics/orders`. +- Default summary history starts at April 2026 (`2026-04-01`), even if older rows exist. +- Splits series by channel key: Allegro as one series and each shopPRO integration by `orders.integration_id`. +- Uses `integrations.name` only for display labels when available. +- Filters by selected status groups through `order_status_groups` and `order_statuses`. +- Uses existing gross amount columns via `OrdersStatisticsRepository::grossAmountSql()`. +- No schema migration was introduced for Phase 110. diff --git a/.paul/codebase/tech_changelog.md b/.paul/codebase/tech_changelog.md index ab7500c..a9c5a13 100644 --- a/.paul/codebase/tech_changelog.md +++ b/.paul/codebase/tech_changelog.md @@ -1,5 +1,20 @@ # Technical Changelog +## 2026-04-28 - Phase 110 Plan 01: Statistics Summary + +**Co zrobiono:** +- `/statistics/summary` - nowy widok podsumowania w menu `Statystyki -> Podsumowanie`. +- `OrdersStatisticsController::summary()` - buduje miesieczny view-model dla wykresow liczby i wartosci zamowien. +- `OrdersStatisticsRepository::aggregateByMonth()` - agreguje istniejace zamowienia po miesiacu i kanale/integracji. +- `public/assets/js/modules/statistics-summary-charts.js` - renderer dwoch interaktywnych wykresow liniowych oparty o Chart.js 4.4.8 CDN. +- `resources/views/statistics/summary.php` - filtry zgodne z raportem dziennym, dwa wykresy obok siebie na desktopie oraz dwie tabele fallback pod nimi. +- Domyslny poczatek historii ustawiony na `2026-04-01` (`04-2026`) mimo starszych danych. + +**Dlaczego:** +- Operator potrzebuje szybkiego trendu miesiecznego przed przejsciem do szczegolowych dziennych statystyk. +- Wykresy uzywaja obecnych tabel `orders`, `integrations`, `order_status_groups` i `order_statuses`, wiec migracja DB nie jest potrzebna. +- Seria `Razem` jest liczona z tych samych danych co serie integracji, co ulatwia sprawdzenie sum miesiecznych. + ## 2026-04-28 - Phase 109 Plan 01: Checkbox Multiselect Filters **Co zrobiono:** diff --git a/.paul/phases/110-statistics-summary/110-01-PLAN.md b/.paul/phases/110-statistics-summary/110-01-PLAN.md new file mode 100644 index 0000000..0f23286 --- /dev/null +++ b/.paul/phases/110-statistics-summary/110-01-PLAN.md @@ -0,0 +1,266 @@ +--- +phase: 110-statistics-summary +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - src/Modules/Statistics/OrdersStatisticsController.php + - src/Modules/Statistics/OrdersStatisticsRepository.php + - routes/web.php + - resources/views/layouts/app.php + - resources/views/statistics/summary.php + - resources/lang/pl.php + - public/assets/js/modules/statistics-summary-charts.js + - resources/scss/app.scss + - public/assets/css/app.css + - DOCS/ARCHITECTURE.md + - DOCS/DB_SCHEMA.md + - DOCS/TECH_CHANGELOG.md + - .paul/codebase/architecture.md + - .paul/codebase/db_schema.md + - .paul/codebase/tech_changelog.md +autonomous: false +delegation: off +--- + + +## Goal +Add a new first submenu item `Statystyki -> Podsumowanie` with two monthly line charts: +- monthly order count per integration plus a total line, +- monthly order value per integration plus a total line. + +## Purpose +The operator needs a quick trend view before opening detailed daily order statistics. The summary should show how each sales integration contributes month by month and how the total business volume changes over time. + +## Output +- New authenticated endpoint `/statistics/summary`. +- Sidebar order: `Podsumowanie` first, existing `Zamowienia` second. +- New summary view with compact filters and two charts. +- Backend monthly aggregation using existing orders data, grouped by integration/channel. +- Technical documentation updates. No database migration is expected. + + + +## Project Context +@.paul/PROJECT.md +@.paul/ROADMAP.md +@.paul/STATE.md +@AGENTS.md +@.paul/codebase/architecture.md +@.paul/codebase/db_schema.md + +## Prior Work +@.paul/phases/105-orders-statistics/105-01-SUMMARY.md +@.paul/phases/109-checkbox-multiselect-filters/109-01-SUMMARY.md + +## Source Files +@src/Modules/Statistics/OrdersStatisticsController.php +@src/Modules/Statistics/OrdersStatisticsRepository.php +@resources/views/statistics/orders.php +@resources/views/layouts/app.php +@routes/web.php +@resources/lang/pl.php +@resources/scss/app.scss +@package.json + +## Notes +- `DOCS/DB_SCHEMA.md` and `DOCS/ARCHITECTURE.md` are required by `AGENTS.md`, but they are currently missing in the repo. APPLY should create them or reconcile them from `.paul/codebase/*` before documenting this feature. +- Existing statistics code already has filter parsing patterns, channel labels, status group defaults, collation handling, and amount fallback logic. Reuse those rather than creating a separate query style. +- `SPECIAL-FLOWS.md` requires `sonar-scanner` after APPLY and before UNIFY; frontend-design is optional for this UI work. + + + +## Required Skills (from SPECIAL-FLOWS.md) + +| Skill | Priority | When to Invoke | Loaded? | +|-------|----------|----------------|---------| +| sonar-scanner | required | After APPLY, before UNIFY | o | +| /frontend-design | optional | During chart UI implementation/review | o | + +**BLOCKING:** `sonar-scanner` must be run before UNIFY unless the environment blocks it. + + + + +## AC-1: Sidebar Navigation +```gherkin +Given the user is authenticated +When the sidebar statistics section is visible +Then the first item under "Statystyki" is "Podsumowanie" +And the second item remains "Zamowienia" +And clicking "Podsumowanie" opens `/statistics/summary` +And the active state highlights "Podsumowanie" on that page +``` + +## AC-2: Monthly Order Count Chart +```gherkin +Given orders exist across multiple months and integrations +When the user opens `/statistics/summary` +Then the page shows an order count chart grouped by month +And each integration has its own line +And an additional "Razem" line sums all selected integrations per month +``` + +## AC-3: Monthly Order Value Chart +```gherkin +Given orders exist across multiple months and integrations +When the user opens `/statistics/summary` +Then the page shows an order value chart grouped by month +And each integration has its own line +And an additional "Razem" line sums all selected integrations per month +And values are displayed as money with two decimal places +``` + +## AC-4: Existing Statistics Semantics Reused +```gherkin +Given the user changes the date range, channel selection, or status group selection +When the summary page reloads +Then both charts use the same selected filters +And channel labels match existing statistics labels +And default status groups still exclude the cancelled group +``` + +## AC-5: Empty and Degraded States +```gherkin +Given the selected filters return no orders +When the user opens `/statistics/summary` +Then the page shows a clear empty state instead of broken charts + +Given JavaScript fails to load +When the user opens `/statistics/summary` +Then the monthly data remains visible in an HTML table fallback +``` + + + + + + + Task 1: Add monthly statistics backend and route + src/Modules/Statistics/OrdersStatisticsController.php, src/Modules/Statistics/OrdersStatisticsRepository.php, routes/web.php + + Extend the existing Statistics module with a new summary action: + - Add `summary(Request $request): Response` to `OrdersStatisticsController`. + - Reuse or extract existing filter helpers for date range, channel options, selected channels, status groups, selected status groups, and status-code resolution. + - Use a useful monthly default range: first day of January of the current year through the current date, unless GET filters are supplied. + - Add repository method `aggregateByMonth(string $dateFrom, string $dateTo, array $channels, array $statusCodes): array`. + - The query must reuse the existing effective date, channel, gross amount, and status SQL semantics from `aggregateByDay()`. + - Group rows by `DATE_FORMAT(effective_date, "%Y-%m")` and channel key. + - Build a controller view-model with ordered month labels, per-channel count series, per-channel value series, and total series for both charts. + - Add route `GET /statistics/summary` behind `AuthMiddleware` using the existing controller instance. + + Avoid: no schema changes, no raw user input in SQL strings, no duplicate channel/status logic that can drift from `/statistics/orders`. + + + - `php -l src/Modules/Statistics/OrdersStatisticsController.php` + - `php -l src/Modules/Statistics/OrdersStatisticsRepository.php` + - `php -l routes/web.php` + - Manual check that `/statistics/summary` returns HTTP 200 for an authenticated session. + + AC-2, AC-3, and AC-4 satisfied at backend/view-model level. + + + + Task 2: Add summary UI, charts, menu item, and translations + resources/views/layouts/app.php, resources/views/statistics/summary.php, resources/lang/pl.php, public/assets/js/modules/statistics-summary-charts.js, resources/scss/app.scss, public/assets/css/app.css + + Create the visible statistics summary experience: + - Add `Podsumowanie` translation keys under navigation and `statistics.summary.*`. + - In the sidebar statistics group, place `Podsumowanie` before `Zamowienia`, link it to `/statistics/summary`, and use `activeStatistics='summary'`. + - Create `resources/views/statistics/summary.php` with compact filters matching `/statistics/orders`: date from/to, channels multiselect, status groups multiselect, submit/reset actions. + - Render two chart panels: order count and order value. Each panel must include a `` or SVG/chart container plus a table fallback with monthly rows and per-series columns. + - Add `public/assets/js/modules/statistics-summary-charts.js` to render the two charts from JSON embedded in the page after escaping through `json_encode(..., JSON_HEX_*)`. + - Keep chart rendering small and local. Do not add a package dependency unless implementation discovers existing project-approved chart tooling. + - Include the module in `resources/views/layouts/app.php` with `filemtime()` cache busting. + - Add compact SCSS in `resources/scss/app.scss`, then build `public/assets/css/app.css` with `npm run build:css`. + + Avoid: no inline CSS in PHP views, no native `alert()`/`confirm()`, no decorative oversized dashboard layout. The page should stay dense and operational. + + + - `php -l resources/views/layouts/app.php` + - `php -l resources/views/statistics/summary.php` + - `php -l resources/lang/pl.php` + - `npm run build:css` + - Browser/manual check confirms two non-empty charts render when data exists and fallback tables are present in the DOM. + + AC-1, AC-2, AC-3, and AC-5 satisfied at UI level. + + + + Task 3: Update technical documentation + DOCS/ARCHITECTURE.md, DOCS/DB_SCHEMA.md, DOCS/TECH_CHANGELOG.md, .paul/codebase/architecture.md, .paul/codebase/db_schema.md, .paul/codebase/tech_changelog.md + + Update documentation required by `AGENTS.md` and PAUL: + - If root `DOCS/` files are still missing, create `DOCS/ARCHITECTURE.md`, `DOCS/DB_SCHEMA.md`, and `DOCS/TECH_CHANGELOG.md` using the current `.paul/codebase/*` documents as the baseline where appropriate. + - Document the new `/statistics/summary` route, controller action, repository monthly aggregation method, chart frontend module, and sidebar change in architecture docs. + - Document that the feature uses existing `orders`, `integrations`, `order_status_groups`, and `order_statuses` tables without migration changes. + - Add a dated technical changelog entry explaining the new summary charts and why no DB schema change was needed. + - Keep `.paul/codebase/*` in sync with the same architecture/schema/changelog facts. + + + - `git diff -- DOCS .paul/codebase` shows architecture/changelog updates and no false DB migration claim. + - Documentation mentions `/statistics/summary`, `aggregateByMonth()`, and `statistics-summary-charts.js`. + + Documentation requirements from `AGENTS.md` and PAUL are satisfied. + + + + `Statystyki -> Podsumowanie` with two monthly charts + + 1. Open `/statistics/summary`. + 2. Confirm the sidebar shows `Podsumowanie` as the first item under `Statystyki`. + 3. Confirm chart 1 shows monthly order counts with one line per integration plus `Razem`. + 4. Confirm chart 2 shows monthly order values with one line per integration plus `Razem`. + 5. Change filters and confirm both charts update consistently. + + Type "approved" to continue to UNIFY, or describe visual/data issues to fix. + + + + + + +## DO NOT CHANGE +- Import/synchronization modules for Allegro/shopPRO. +- Existing `/statistics/orders` route contract and GET parameter names. +- Database migrations unless a blocker proves the existing schema cannot support the charts. +- Runtime DB env behavior: do not wire `DB_HOST_REMOTE` into application runtime. + +## SCOPE LIMITS +- This plan adds only summary charts for orders. It does not add exports, product charts, inventory charts, or accounting reports. +- Values chart uses the existing gross amount semantics from current order statistics unless the user explicitly asks for net values. +- Chart interactivity is limited to readable lines/legend/tooltips if implemented locally; advanced drill-down is out of scope. +- No new native alerts or confirms. + + + + +Before declaring plan complete: +- [ ] `php -l src/Modules/Statistics/OrdersStatisticsController.php` +- [ ] `php -l src/Modules/Statistics/OrdersStatisticsRepository.php` +- [ ] `php -l routes/web.php` +- [ ] `php -l resources/views/layouts/app.php` +- [ ] `php -l resources/views/statistics/summary.php` +- [ ] `php -l resources/lang/pl.php` +- [ ] `npm run build:css` +- [ ] Manual/browser check: `/statistics/summary` renders two charts and table fallbacks. +- [ ] Manual/browser check: sidebar order and active states are correct. +- [ ] Manual data check: monthly total equals sum of integration values for at least one month. +- [ ] Documentation updated in `DOCS/` and `.paul/codebase/`. +- [ ] `sonar-scanner` run before UNIFY, or blocker recorded if unavailable. +- [ ] All acceptance criteria met. + + + +- `Statystyki -> Podsumowanie` is the first statistics submenu item. +- `/statistics/summary` displays two monthly charts: order count and order value. +- Each chart includes separate integration series and a `Razem` series. +- Filters are consistent with existing order statistics behavior. +- No database schema change is introduced. +- Technical documentation is updated. + + + +After completion, create `.paul/phases/110-statistics-summary/110-01-SUMMARY.md`. + diff --git a/.paul/phases/110-statistics-summary/110-01-SUMMARY.md b/.paul/phases/110-statistics-summary/110-01-SUMMARY.md new file mode 100644 index 0000000..5da9bc3 --- /dev/null +++ b/.paul/phases/110-statistics-summary/110-01-SUMMARY.md @@ -0,0 +1,197 @@ +--- +phase: 110-statistics-summary +plan: 01 +subsystem: statistics +tags: [statistics, charts, chartjs, monthly-summary, ui, reporting] +requires: + - phase: 105-orders-statistics + provides: daily statistics filters, channel semantics, status group filtering + - phase: 109-checkbox-multiselect-filters + provides: reusable checkbox multiselect filter enhancement +provides: + - /statistics/summary monthly summary page + - monthly order count chart per integration plus total + - monthly order value chart per integration plus total + - DOCS baseline synchronized from .paul/codebase +affects: [statistics, reporting, sidebar-navigation] +tech-stack: + added: [Chart.js 4.4.8 CDN] + patterns: [monthly statistics aggregation, Chart.js view-model, table fallback] +key-files: + created: + - resources/views/statistics/summary.php + - public/assets/js/modules/statistics-summary-charts.js + - DOCS/ARCHITECTURE.md + - DOCS/DB_SCHEMA.md + - DOCS/TECH_CHANGELOG.md + modified: + - src/Modules/Statistics/OrdersStatisticsController.php + - src/Modules/Statistics/OrdersStatisticsRepository.php + - routes/web.php + - resources/views/layouts/app.php + - resources/lang/pl.php + - resources/scss/app.scss + - public/assets/css/app.css +key-decisions: + - "Default summary history starts at 2026-04-01 even if older orders exist." + - "Charts use Chart.js 4.4.8 from CDN for interactive legend and tooltips." + - "Gross order value uses existing statistics gross amount semantics." +patterns-established: + - "Monthly statistics use the same channel/status/effective-date helpers as daily statistics." + - "Charts are backed by HTML table fallbacks." +duration: ~90min +started: 2026-04-28T22:20:00+02:00 +completed: 2026-04-28T23:50:00+02:00 +--- + +# Phase 110 Plan 01: Statistics Summary + +Monthly statistics summary shipped with two interactive Chart.js line charts, compact filters, per-integration series, total series, and table fallbacks. + +## Performance + +| Metric | Value | +|--------|-------| +| Duration | ~90min | +| Started | 2026-04-28T22:20:00+02:00 | +| Completed | 2026-04-28T23:50:00+02:00 | +| Tasks | 3 auto tasks + 1 human verification checkpoint | +| Files modified | 18 | + +## Acceptance Criteria Results + +| Criterion | Status | Notes | +|-----------|--------|-------| +| AC-1: Sidebar Navigation | Pass | `Podsumowanie` added first under `Statystyki`; `/statistics/summary` route registered with active state. | +| AC-2: Monthly Order Count Chart | Pass | Count chart model contains one dataset per selected integration plus `Razem`; rendered by Chart.js. | +| AC-3: Monthly Order Value Chart | Pass | Value chart model contains one dataset per selected integration plus `Razem`; values formatted as money in tooltips/table. | +| AC-4: Existing Statistics Semantics Reused | Pass | Controller reuses channel/status filter flow; repository reuses effective date/channel/status/gross SQL helpers. | +| AC-5: Empty and Degraded States | Pass | Empty state shown when no data; tables remain visible as fallback below charts. | + +## Accomplishments + +- Added authenticated `/statistics/summary` page with monthly order count and order gross value charts. +- Added `OrdersStatisticsRepository::aggregateByMonth()` using prepared parameters and existing statistics SQL helper semantics. +- Added `OrdersStatisticsController::summary()` and a chart/table view-model with total lines. +- Updated sidebar navigation, translations, SCSS, compiled CSS, and Chart.js frontend module. +- Created root `DOCS/` technical documentation required by `AGENTS.md` and synchronized it with `.paul/codebase/`. + +## Task Commits + +Task-level atomic commits were not used in this inline APPLY. A single phase commit is created during transition. + +| Task | Commit | Type | Description | +|------|--------|------|-------------| +| Task 1: Add monthly statistics backend and route | phase commit | feat | Controller summary action, monthly aggregation, `/statistics/summary` route | +| Task 2: Add summary UI, charts, menu item, and translations | phase commit | feat | Summary view, sidebar link, Chart.js charts, SCSS/CSS | +| Task 3: Update technical documentation | phase commit | docs | `DOCS/` and `.paul/codebase/` updates | + +## Files Created/Modified + +| File | Change | Purpose | +|------|--------|---------| +| `src/Modules/Statistics/OrdersStatisticsController.php` | Modified | Added summary action, monthly default range from `2026-04-01`, chart/table view-model builders. | +| `src/Modules/Statistics/OrdersStatisticsRepository.php` | Modified | Added `aggregateByMonth()` with existing statistics SQL semantics. | +| `routes/web.php` | Modified | Registered authenticated `GET /statistics/summary`. | +| `resources/views/layouts/app.php` | Modified | Added `Podsumowanie` sidebar link and Chart.js/module scripts. | +| `resources/views/statistics/summary.php` | Created | Summary filters, two charts, and two fallback tables. | +| `resources/lang/pl.php` | Modified | Added navigation and `statistics.summary.*` translations. | +| `public/assets/js/modules/statistics-summary-charts.js` | Created | Chart.js renderer for count/value line charts. | +| `resources/scss/app.scss` | Modified | Added compact two-column desktop layout and chart/table styles. | +| `public/assets/css/app.css` | Modified | Compiled CSS output. | +| `DOCS/ARCHITECTURE.md` | Created | Root architecture docs baseline plus summary feature. | +| `DOCS/DB_SCHEMA.md` | Created | Root schema docs baseline plus reporting usage note. | +| `DOCS/TECH_CHANGELOG.md` | Created | Root technical changelog baseline plus phase 110 entry. | +| `.paul/codebase/architecture.md` | Modified | Documented route, controller flow, Chart.js module. | +| `.paul/codebase/db_schema.md` | Modified | Documented no-migration reporting usage. | +| `.paul/codebase/tech_changelog.md` | Modified | Added phase 110 technical changelog. | + +## Decisions Made + +| Decision | Rationale | Impact | +|----------|-----------|--------| +| Start history at `2026-04-01` | User requested `04-2026` as hard start despite older data. | Default summary excludes older months unless code changes later. | +| Use Chart.js 4.4.8 CDN | User requested an interactive JS library; project already uses CDN for Quill. | No npm dependency or build pipeline change. | +| Use gross order values | Existing statistics gross semantics are stable and already documented. | Value chart matches current order statistics totals. | +| Keep table fallback | Required degraded state and useful for verification. | Data remains visible without Chart.js/JS. | + +## Deviations from Plan + +| Type | Count | Impact | +|------|-------|--------| +| Scope adjustments from user feedback | 3 | Improved UI and changed default date semantics. | +| Environment blockers | 3 | Verification limits only; code/build checks passed. | + +**Total impact:** Controlled deviations; feature outcome matches latest user request. + +### Adjusted During APPLY + +**Chart renderer changed to Chart.js** +- Found during user feedback after APPLY. +- Fix: Added Chart.js CDN and rewrote `statistics-summary-charts.js` to use Chart.js legends/tooltips. +- Verification: `node --check`, PHP lint, CSS build, Sonar scan. + +**Desktop layout split** +- Found during user feedback after APPLY. +- Fix: Added two-column chart grid and two-column table grid from 1100px. +- Verification: PHP lint and CSS build. + +**Default history start** +- Found during user feedback after APPLY. +- Fix: Set summary default `date_from` to `2026-04-01`. +- Verification: PHP lint. + +### Deferred Items + +- SonarQube issue import into `DOCS/todo.md` was not performed because no SonarQube MCP resources/tools are available in this Codex session. +- Full authenticated HTTP verification was not possible locally because MySQL/XAMPP refused the DB connection. +- PHPUnit was not run because `composer` is not available in PATH and `vendor/` is absent. + +## Issues Encountered + +| Issue | Resolution | +|-------|------------| +| Local bootstrap failed with MySQL connection refused. | Started PHP dev server anyway; documented DB blocker. | +| `composer test` unavailable. | Documented test blocker; ran available lint/build/static checks. | +| Sonar MCP unavailable. | Ran `sonar-scanner` successfully and documented inability to fetch issue details. | + +## Verification Results + +| Check | Result | +|-------|--------| +| `php -l src/Modules/Statistics/OrdersStatisticsController.php` | Pass | +| `php -l src/Modules/Statistics/OrdersStatisticsRepository.php` | Pass | +| `php -l routes/web.php` | Pass | +| `php -l resources/views/layouts/app.php` | Pass | +| `php -l resources/views/statistics/summary.php` | Pass | +| `php -l resources/lang/pl.php` | Pass | +| `node --check public/assets/js/modules/statistics-summary-charts.js` | Pass | +| `npm run build:css` | Pass | +| `sonar-scanner` | Pass; report uploaded to SonarQube | +| Local `/statistics/summary` HTTP 200 | Blocked by local MySQL connection refused | +| `composer test` / PHPUnit | Blocked: `composer` not in PATH and `vendor/` absent | + +## Skill Audit + +| Expected | Invoked | Notes | +|----------|---------|-------| +| `sonar-scanner` | yes | Ran successfully after APPLY changes. | + +## Next Phase Readiness + +**Ready:** +- Statistics summary page exists and is wired into sidebar navigation. +- Monthly aggregation pattern can be reused for future reporting charts. +- Root `DOCS/` docs now exist for future AGENTS.md-compliant changes. + +**Concerns:** +- Chart.js is CDN-based; if offline operation becomes required, vendor locally or add npm build support. +- Local verification depends on XAMPP/MySQL being available. +- Sonar issue import still needs a working SonarQube MCP/tool path. + +**Blockers:** +- None for closing Phase 110. + +--- +*Phase: 110-statistics-summary, Plan: 01* +*Completed: 2026-04-28* diff --git a/DOCS/ARCHITECTURE.md b/DOCS/ARCHITECTURE.md new file mode 100644 index 0000000..35b9e54 --- /dev/null +++ b/DOCS/ARCHITECTURE.md @@ -0,0 +1,175 @@ +# Architecture + +## Request Flow + +``` +HTTP Request + → public/index.php + → bootstrap/app.php (loads config, registers PDO, services) + → Application::boot() (loads routes/web.php) + → Router::dispatch(Request) (matches URL, runs middleware pipeline) + → [Middleware] (AuthMiddleware, ApiKeyMiddleware) + → Controller::method() (parse input → call repository/service → render) + → Template::render() (PHP native, layout composition) + → Response::send() +``` + +## Layer Map + +| Layer | Location | Responsibility | +|-------|----------|----------------| +| Entry | `public/index.php` | Bootstrap only | +| Routes | `routes/web.php` (581 lines) | All ~80 routes; manual DI wiring | +| Core | `src/Core/` (25 files) | Framework infrastructure | +| Controllers | `src/Modules/*/Controller.php` | Request parsing → response | +| Services | `src/Modules/*/Service.php` | Business logic | +| Repositories | `src/Modules/*/Repository.php` | PDO data access (34+ repos) | +| Views | `resources/views/` | PHP templates with `$e()` / `$t()` | +| Components | `resources/views/components/` | Reusable UI blocks | +| Frontend modules | `public/assets/js/modules/` | Small vanilla JS enhancements loaded by layout | + +## Module Inventory (`src/Modules/`) + +| Module | Files | Key Classes | Purpose | +|--------|-------|-------------|---------| +| **Auth** | 3 | `AuthController`, `AuthMiddleware`, `AuthService` | Login/logout, session | +| **Users** | 2 | `UserController`, `UserRepository` | User CRUD | +| **Orders** | 3 | `OrdersController` (1187 LOC), `OrdersRepository` (1221 LOC) | Order list, detail, status, payment, correlated subquery for return-risk | +| **Shipments** | 17 | `ShipmentController`, provider services + tracking services | Shipment creation, label download, tracking polling | +| **Accounting** | 5 | `AccountingController`, `ReceiptService`, `ReceiptRepository` | Receipts, invoices, PDF, Excel export | +| **Email** | 3 | `EmailSendingService`, `VariableResolver`, `AttachmentGenerator` | Template-based email with PDF attachments | +| **Automation** | 6 | `AutomationService` (834 LOC), `AutomationRepository`, `AutomationExecutionLogRepository` | Event→condition→action rules, email triggers | +| **Settings** | 51+ | Integration controllers, OAuth clients, API clients, mappers | Allegro/shopPRO/Apaczka/InPost config, status mappings | +| **Cron** | 12 | `CronRepository`, `CronHandlerFactory`, handler classes | Scheduled imports, syncs, token refresh | +| **Printing** | 4 | `PrintApiController`, `PrintJobRepository`, `ApiKeyMiddleware` | REST API for Windows print client | +| **Statistics** | 3 | `OrdersStatisticsController`, `OrdersStatisticsRepository`, `statistics-summary-charts.js` | Daily order statistics and monthly summary charts | +| **Info** | 1 | `InfoController` | Health check | + +## Frontend Enhancement Modules + +### Checkbox Multiselect (`public/assets/js/modules/checkbox-multiselect.js`) +- Loaded globally from `resources/views/layouts/app.php`. +- Enhances native ``. +- `resources/views/layouts/app.php` - globalne podpiecie modulu z cache busting przez `filemtime()`. +- `resources/views/statistics/orders.php` - filtry `channels[]` i `status_groups[]` oznaczone do progresywnego ulepszenia bez zmiany nazw pol formularza. +- `resources/scss/app.scss` - kompaktowe style dropdownu z checkboxami i opcja "Wszystkie". + +**Dlaczego:** +- Natywne selecty multiple byly malo czytelne i zajmowaly za duzo miejsca w filtrach statystyk. +- Zachowanie oryginalnego selecta w DOM utrzymuje obecny kontrakt GET i fallback bez JavaScript. +- Brak zmian w schemacie DB i logice agregacji statystyk. + +> Chronologiczny log zmian technicznych — co i dlaczego. + +## 2026-04-27 — Phase 108 Plan 02: Automation Dropdowns z DB + +**Co zrobiono:** +- `AutomationController` — usunięto stałą `SHIPMENT_STATUS_OPTIONS` (8 grupowych kluczy) +- Dropdown statusów w warunku `shipment_status` i akcji `update_shipment_status` ładuje statusy z DB przez `DeliveryStatus::getAllOptions()` +- Walidacja w `parseConditionValue()` i `parseActionConfig()` używa `DeliveryStatus::getAllStatuses()` +- `AutomationService` — usunięto stałą `SHIPMENT_STATUS_OPTION_MAP`; ewaluacja `evaluateShipmentStatusCondition()` porównuje klucze bezpośrednio +- `resolveStatusFromActionKey()` — bezpośredni klucz statusu z DB jako target (zamiast pierwszego z grupy) + +**Dlaczego:** +- Zamknięcie integracji z Plan 01 — operator dodaje status w `/settings/delivery-statuses` i jest on od razu dostępny w dropdownach automatyzacji bez deploymentu +- Eliminacja kolizji semantycznej: stary klucz grupowy `picked_up` mapował na `delivered` (paczka odebrana przez klienta), nowy klucz DB `picked_up` to "Odebrana przez kuriera" (od nadawcy) +- BREAKING: stare reguły z grupowymi kluczami (`registered`, `courier_pickup`, `dropped_at_point`, `unclaimed`, `picked_up_return`, oraz `picked_up`/`ready_for_pickup`/`cancelled` w starym znaczeniu) nie matchują — wymagają ręcznego odtworzenia z nowymi kluczami DB + +## 2026-04-27 — Phase 108 Plan 01: Delivery Status Management + +**Co zrobiono:** +- Tabela `delivery_statuses` z seedem 11 statusów (migracja `20260427_000103`) +- `DeliveryStatusRepository` — CRUD + per-request cache +- `DeliveryStatus.php` — dynamiczne ładowanie statusów z DB (`setRepository()`) +- Panel `/settings/delivery-statuses` z CRUD (zakładka "Statusy") i mapowaniem (zakładka "Mapowanie dostawy") +- Sidebar: "Statusy" → "Statusy zamówień", nowe "Statusy przesyłek" z badge niezmapowanych +- Badge przesyłek: inline CSS custom property `--status-color` dla niestandardowych statusów + +**Dlaczego:** +- Dodanie nowego statusu wymagało zmiany kodu + deploymentu; teraz z UI +- Operator może definiować własne statusy znormalizowane bez ingerencji w kod diff --git a/public/assets/css/app.css b/public/assets/css/app.css index aca1dbe..eb6c4db 100644 --- a/public/assets/css/app.css +++ b/public/assets/css/app.css @@ -1 +1 @@ -:root{--c-primary: #6690f4;--c-primary-dark: #3164db;--c-action-primary: #0f766e;--c-action-primary-dark: #0b5f59;--c-bg: #f4f6f9;--c-surface: #ffffff;--c-text: #4e5e6a;--c-text-strong: #2d3748;--c-muted: #718096;--c-border: #b0bec5;--c-danger: #cc0000;--focus-ring: 0 0 0 3px rgba(102, 144, 244, 0.15);--focus-ring-action: 0 0 0 3px rgba(15, 118, 110, 0.18);--shadow-card: 0 1px 4px rgba(0, 0, 0, 0.06)}.btn{display:inline-flex;align-items:center;justify-content:center;min-height:34px;padding:6px 12px;border:1px solid rgba(0,0,0,0);border-radius:8px;font:inherit;font-weight:600;text-decoration:none;cursor:pointer;transition:background-color .2s ease,border-color .2s ease,color .2s ease,transform .1s ease}.btn--primary{color:#fff;background:var(--c-action-primary)}.btn--primary:hover{background:var(--c-action-primary-dark)}.btn--secondary{color:var(--c-text-strong);border-color:var(--c-border);background:var(--c-surface)}.btn--secondary:hover{border-color:#cbd5e0;background:#f8fafc}.btn--danger{color:#fff;border-color:#b91c1c;background:#dc2626}.btn--danger:hover{border-color:#991b1b;background:#b91c1c}.btn--sm{min-height:28px;padding:3px 10px;font-size:12px}.btn--block{width:100%}.btn--disabled{opacity:.3;cursor:not-allowed;pointer-events:none}.btn:active{transform:translateY(1px)}.btn:focus-visible{outline:none;box-shadow:var(--focus-ring-action);border-color:var(--c-action-primary)}.form-control{width:100%;min-height:30px;border:1px solid var(--c-border);border-radius:6px;padding:4px 8px;font:inherit;color:var(--c-text-strong);background:#fff;transition:border-color .2s ease,box-shadow .2s ease}.form-control:focus{outline:none;border-color:var(--c-primary);box-shadow:var(--focus-ring)}.input{min-height:34px;border:1px solid var(--c-border);border-radius:8px;padding:5px 10px;font:inherit;color:var(--c-text-strong);background:#fff}.input--sm{min-height:28px;padding:3px 8px;font-size:12px}.flash{padding:8px 12px;border-radius:6px;font-size:13px}.flash--success{border:1px solid #b7ebcf;background:#f0fff6;color:#0f6b39}.flash--error{border:1px solid #fed7d7;background:#fff5f5;color:var(--c-danger)}.alert{padding:12px 14px;border-radius:8px;border:1px solid rgba(0,0,0,0);font-size:13px;min-height:44px}.alert--danger{border-color:#fed7d7;background:#fff5f5;color:var(--c-danger)}.alert--success{border-color:#b7ebcf;background:#f0fff6;color:#0f6b39}.alert--warning{border-color:#f7dd8b;background:#fff8e8;color:#815500}.form-field{display:grid;gap:5px}.field-label{color:var(--c-text-strong);font-size:13px;font-weight:600}.table-wrap{width:100%;overflow-x:auto}.table-wrap--visible{overflow:visible !important;overflow-x:visible !important}.table{width:100%;border-collapse:collapse;background:var(--c-surface)}.table th,.table td{padding:10px 12px;border-bottom:1px solid var(--c-border);text-align:left}.table th{color:var(--c-text-strong);font-weight:700;background:#f8fafc}.table--details th{white-space:nowrap}.table--details th:first-child,.table--details td:first-child{width:36px;text-align:center}.pagination{display:flex;align-items:center;flex-wrap:wrap;gap:8px}.pagination__item{display:inline-flex;align-items:center;justify-content:center;min-width:36px;height:36px;padding:0 10px;border-radius:8px;border:1px solid var(--c-border);color:var(--c-text-strong);background:var(--c-surface);text-decoration:none;font-weight:600}.pagination__item:hover{border-color:#cbd5e0;background:#f8fafc}.pagination__item.is-active{border-color:var(--c-primary);color:var(--c-primary);background:#edf2ff}.receipt-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:16px;padding-bottom:12px;border-bottom:2px solid var(--c-text-strong)}.receipt-header__seller{flex:1}.receipt-header__seller strong{font-size:14px;display:block;margin-bottom:4px}.receipt-header__title{text-align:right}.receipt-header__title h1{font-size:18px;font-weight:700;margin-bottom:4px}.receipt-print{max-width:700px;margin:0 auto}@media print{.receipt-print{max-width:100%}}.copy-name-row{display:flex;align-items:center;gap:6px}.copy-btn-inline{display:inline-flex;align-items:center;justify-content:center;background:none;border:none;padding:2px;cursor:pointer;color:var(--c-text-muted, #999);border-radius:3px;transition:color .15s;flex-shrink:0}.copy-btn-inline:hover{color:var(--c-primary)}.copy-btn-inline .check-icon{color:var(--c-action-primary)}.email-send-overlay{position:fixed;inset:0;z-index:1000;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center}.email-send-modal{background:var(--c-card-bg, #fff);border-radius:8px;width:580px;max-width:95vw;max-height:90vh;display:flex;flex-direction:column;box-shadow:0 8px 32px rgba(0,0,0,.2)}.email-send-modal__header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--c-border, #e0e0e0)}.email-send-modal__header h3{margin:0;font-size:15px}.email-send-modal__close{background:none;border:none;font-size:20px;cursor:pointer;color:var(--c-text-muted, #888);padding:0 4px}.email-send-modal__close:hover{color:var(--c-text, #333)}.email-send-modal__body{padding:16px;overflow-y:auto;flex:1}.email-send-modal__field{margin-bottom:10px}.email-send-modal__field label{display:block;font-size:12px;font-weight:600;margin-bottom:4px;color:var(--c-text-muted, #666)}.email-send-modal__field .input{width:100%}.email-send-modal__actions-top{margin-bottom:10px}.email-send-modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--c-border, #e0e0e0)}.email-send-preview{border:1px solid var(--c-border, #e0e0e0);border-radius:4px;padding:12px;max-height:280px;overflow-y:auto;background:var(--c-bg, #fafafa)}.email-send-preview__subject{font-weight:600;font-size:13px;margin-bottom:8px;padding-bottom:8px;border-bottom:1px solid var(--c-border, #e0e0e0)}.email-send-preview__body{font-size:13px;line-height:1.5}.email-send-preview__body p{margin:0 0 8px}.email-send-preview__attachments{margin-top:8px;padding-top:8px;border-top:1px solid var(--c-border, #e0e0e0);font-size:12px;color:var(--c-text-muted, #666)}.section-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.automation-row{display:flex;align-items:flex-start;gap:8px;padding:10px 12px;background:var(--c-surface, #f8f9fa);border:1px solid var(--c-border, #dee2e6);border-radius:6px}.automation-row__fields{flex:1;display:flex;flex-direction:column;gap:6px}.automation-row__type{max-width:280px}.automation-row__config{display:flex;flex-wrap:wrap;gap:8px}.automation-row__config .form-control{min-width:200px;max-width:300px}.automation-row__remove{flex-shrink:0;margin-top:2px;line-height:1;font-size:16px;padding:2px 8px}.checkbox-group{display:flex;flex-wrap:wrap;gap:4px 16px}.checkbox-label{display:flex;align-items:center;gap:4px;font-size:13px;cursor:pointer;white-space:nowrap}.checkbox-label input[type=checkbox]{margin:0}.automation-actions-cell{white-space:nowrap}.automation-inline-form{display:inline}.automation-history-filters{display:grid;grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));gap:8px;align-items:end}.automation-history-filters .form-field{margin:0}.automation-history-filters .field-label{font-size:12px;margin-bottom:4px}.automation-history-filters .form-control{min-height:34px}.automation-history-filters__actions{display:flex;gap:6px;align-items:center;justify-content:flex-start;padding-bottom:1px}.print-status-badge{display:inline-block;padding:2px 8px;border-radius:3px;font-size:.75rem;font-weight:600;line-height:1.4}.print-status-badge--pending{background-color:#fff3cd;color:#856404}.print-status-badge--completed{background-color:#d4edda;color:#155724}.print-status-badge--failed{background-color:#f8d7da;color:#721c24}.print-queue-filters{display:flex;gap:4px}.print-queue-table td,.print-queue-table th{padding:6px 8px;font-size:.85rem}.print-queue-actions{display:inline-flex;align-items:center;gap:6px}.print-queue-delete-form{margin:0}.btn--outline-primary{background:rgba(0,0,0,0);border:1px solid var(--c-action-primary);color:var(--c-action-primary);cursor:pointer;border-radius:3px;font-size:.75rem;padding:3px 8px;transition:background-color .15s,color .15s}.btn--outline-primary:hover{background-color:var(--c-action-primary);color:#fff}.btn--outline-primary:disabled{opacity:.6;cursor:not-allowed}.btn--outline-primary.is-success{border-color:#28a745;color:#28a745}.shipment-presets{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:16px;margin-bottom:16px}.shipment-presets__btn{display:inline-flex;align-items:center;gap:4px;padding:6px 14px;border:none;border-radius:6px;background:var(--preset-color, #3b82f6);color:#fff;font-size:13px;font-weight:500;cursor:pointer;transition:opacity .15s;line-height:1.4}.shipment-presets__btn:hover{opacity:.85}.shipment-presets__add{display:inline-flex;align-items:center;gap:4px;padding:6px 14px;border:1px dashed #ccc;border-radius:6px;background:rgba(0,0,0,0);color:#666;font-size:13px;cursor:pointer;transition:border-color .15s,color .15s;line-height:1.4}.shipment-presets__add:hover{border-color:#999;color:#444}.preset-modal{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:1000;display:flex;align-items:center;justify-content:center}.preset-modal__content{background:#fff;border-radius:8px;padding:24px;min-width:360px;max-width:420px;box-shadow:0 8px 32px rgba(0,0,0,.2)}.preset-modal__content h3{margin:0 0 4px;font-size:16px}.preset-modal__colors{display:flex;gap:8px;flex-wrap:wrap}.preset-modal__color-swatch{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid rgba(0,0,0,0);transition:border-color .15s}.preset-modal__color-swatch:hover{border-color:#aaa}.preset-modal__color-swatch.is-selected{border-color:#333}.shipment-presets__btn-wrap{position:relative;display:inline-flex}.shipment-presets__btn-wrap:hover .shipment-presets__edit-icon{opacity:1}.shipment-presets__edit-icon{position:absolute;top:-6px;right:-6px;width:18px;height:18px;border-radius:50%;background:#fff;border:1px solid #ddd;font-size:10px;line-height:16px;text-align:center;cursor:pointer;opacity:0;transition:opacity .15s;padding:0;color:#666;z-index:2}.shipment-presets__edit-icon:hover{background:#f3f4f6;border-color:#999}.shipment-presets__dropdown{position:absolute;top:100%;left:0;margin-top:4px;background:#fff;border:1px solid #ddd;border-radius:6px;box-shadow:0 4px 16px rgba(0,0,0,.12);z-index:100;min-width:200px;padding:4px 0}.shipment-presets__dropdown-item{padding:6px 14px;font-size:13px;cursor:pointer;white-space:nowrap}.shipment-presets__dropdown-item:hover{background:#f3f4f6}.shipment-presets__dropdown-item.is-danger{color:#ef4444}.shipment-presets__dropdown-item.is-danger:hover{background:#fef2f2}.delivery-badge{display:inline-block;padding:2px 8px;border-radius:3px;font-size:.8em;font-weight:500;white-space:nowrap}.delivery-badge--unknown{background:#f5f5f5;color:#999}.delivery-badge--created{background:#e3f2fd;color:#1565c0}.delivery-badge--confirmed{background:#bbdefb;color:#0d47a1}.delivery-badge--picked_up{background:#e1f5fe;color:#01579b}.delivery-badge--in_transit{background:#fff3e0;color:#e65100}.delivery-badge--out_for_delivery{background:#ffe0b2;color:#bf360c}.delivery-badge--ready_for_pickup{background:#f3e5f5;color:#6a1b9a}.delivery-badge--delivered{background:#e8f5e9;color:#2e7d32}.delivery-badge--returned{background:#ffebee;color:#c62828}.delivery-badge--cancelled{background:#e0e0e0;color:#616161}.delivery-badge--problem{background:#fff8e1;color:#f57f17}.tracking-link{margin-left:4px;text-decoration:none;font-size:.85em}.delivery-status-swatch{display:inline-block;width:14px;height:14px;border-radius:2px;background:var(--status-color, #6c757d);vertical-align:middle}.delivery-status-system-badge{display:inline-block;padding:1px 6px;border-radius:3px;font-size:.75em;background:#e9ecef;color:#6c757d}.delivery-badge--custom{background:var(--status-color, #6c757d);color:#fff}.dsm-row--custom{background:rgba(59,130,246,.06)}.dsm-raw-status{font-size:.82rem;background:var(--surface-alt, #f1f5f9);padding:2px 6px;border-radius:3px;white-space:nowrap}.dsm-unmapped{border-left:4px solid #f59e0b}.dsm-unmapped .section-title{color:#b45309}.dsm-unmapped table tbody tr{background:rgba(245,158,11,.05)}.global-search{flex:1;max-width:500px;position:relative;margin:0 16px}.global-search__input{width:100%;padding:6px 12px;font-size:13px;border:1px solid var(--c-border);border-radius:4px;background:var(--c-bg);color:var(--c-text);outline:none;transition:border-color .15s}.global-search__input::placeholder{color:var(--c-text-muted, #94a3b8)}.global-search__input:focus{border-color:var(--c-primary, #3b82f6);box-shadow:0 0 0 2px rgba(59,130,246,.15)}.global-search__results{display:none;position:absolute;top:100%;left:0;right:0;margin-top:4px;background:var(--c-surface, #fff);border:1px solid var(--c-border);border-radius:6px;box-shadow:0 8px 24px rgba(0,0,0,.12);max-height:400px;overflow-y:auto;z-index:1000}.global-search__item{display:block;padding:8px 12px;cursor:pointer;text-decoration:none;color:var(--c-text);border-bottom:1px solid var(--c-border);transition:background-color .1s}.global-search__item:last-child{border-bottom:none}.global-search__item:hover,.global-search__item.is-highlighted{background:var(--c-bg, #f1f5f9)}.global-search__item-title{font-weight:600;font-size:13px;margin-bottom:2px}.global-search__item-details{font-size:11px;color:var(--c-text-muted, #64748b)}.global-search__empty{padding:12px;text-align:center;color:var(--c-text-muted, #94a3b8);font-size:13px}@media(max-width: 768px){.global-search{max-width:none;margin:0 8px}.global-search__input{font-size:12px;padding:5px 8px}}.order-preview-overlay{position:fixed;inset:0;z-index:1000;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;padding:20px}.order-preview-modal{background:var(--c-surface);border:1px solid var(--c-border);border-radius:10px;box-shadow:0 16px 48px rgba(0,0,0,.18);width:100%;max-width:960px;max-height:90vh;display:flex;flex-direction:column}.order-preview-modal__header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--c-border)}.order-preview-modal__title{font-size:18px;font-weight:600;margin:0}.order-preview-modal__close{background:none;border:none;font-size:22px;cursor:pointer;color:var(--c-muted);padding:0 4px;line-height:1}.order-preview-modal__close:hover{color:var(--c-text)}.order-preview-modal__body{padding:20px 24px;overflow-y:auto;flex:1}.order-preview-modal__footer{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:12px 20px;border-top:1px solid var(--c-border)}.order-preview-loading{text-align:center;padding:32px;color:var(--c-muted)}.order-preview-error{text-align:center;padding:32px;color:var(--c-danger, #e53e3e)}.order-preview-section{margin-bottom:14px}.order-preview-section__title{font-size:13px;font-weight:600;text-transform:uppercase;color:var(--c-muted);margin-bottom:8px;letter-spacing:.04em}.order-preview-kv{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;font-size:14px}.order-preview-kv dt{color:var(--c-muted);white-space:nowrap}.order-preview-kv dd{margin:0;display:flex;align-items:center;gap:4px}.order-preview-items{width:100%;font-size:14px;border-collapse:collapse}.order-preview-items th,.order-preview-items td{padding:6px 8px;text-align:left;vertical-align:top}.order-preview-items th{font-weight:600;font-size:12px;text-transform:uppercase;color:var(--c-muted)}.order-preview-items tbody tr+tr{border-top:1px solid var(--c-border)}.order-preview-item-cell{display:flex;align-items:flex-start;gap:8px}.order-preview-item-thumb{width:42px;height:42px;object-fit:cover;border-radius:4px;border:1px solid var(--c-border);flex-shrink:0}.order-preview-item-thumb--empty{background:var(--c-bg, #f5f5f5)}.order-preview-item-info{min-width:0}.order-preview-item-name{font-size:14px;line-height:1.3;word-break:break-word}.order-preview-personalization{margin-top:4px;font-size:12px;color:var(--c-muted);line-height:1.4}.order-preview-personalization__line{white-space:pre-wrap;word-break:break-word}.order-preview-notes{font-size:14px}.order-preview-notes__item{padding:6px 0}.order-preview-notes__item+.order-preview-notes__item{border-top:1px solid var(--c-border)}.order-preview-notes__type{font-size:11px;color:var(--c-muted);margin-bottom:2px}.order-preview-notes__text{white-space:pre-wrap;word-break:break-word}.copy-field__btn{background:none;border:none;cursor:pointer;font-size:13px;color:var(--c-muted);padding:0 2px;line-height:1;opacity:.6;transition:opacity .15s;display:inline-flex;align-items:center;gap:3px}.copy-field__btn:hover{opacity:1;color:var(--c-primary, #4f6ef7)}.copy-field__btn.is-copied{color:#22c55e;opacity:1}.btn-icon.js-order-preview-btn{background:none;border:none;cursor:pointer;font-size:14px;color:var(--c-muted);padding:2px 4px;line-height:1;opacity:.5;transition:opacity .15s;vertical-align:middle;margin-right:4px}.btn-icon.js-order-preview-btn:hover{opacity:1;color:var(--c-primary, #4f6ef7)}.pm-form__row{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap}.pm-form__field{flex:1;min-width:160px}.pm-form__actions{display:flex;align-items:flex-end;padding-bottom:2px}.pm-row--inactive{opacity:.5}.pm-row__actions{white-space:nowrap}.pm-row__actions .btn+.btn{margin-left:4px}.project-badge{display:inline-flex;align-items:center;gap:2px;font-size:10px;line-height:1;padding:1px 4px;border-radius:3px;vertical-align:middle;margin-left:4px}.project-badge--done{color:#16a34a;background:rgba(22,163,74,.1)}.project-badge--partial{color:#d97706;background:rgba(217,119,6,.1);font-weight:600}.project-badge--none{color:#9ca3af;background:rgba(156,163,175,.1)}.item-project-badge{display:inline-block;font-size:10px;padding:1px 6px;border-radius:3px;margin-left:6px;vertical-align:middle}.item-project-badge--done{color:#16a34a;background:rgba(22,163,74,.1)}.item-project-badge--pending{color:#9ca3af;background:rgba(156,163,175,.1)}.pm-modal{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center}.pm-modal__overlay{position:absolute;inset:0;background:rgba(0,0,0,.4)}.pm-modal__content{position:relative;width:100%;max-width:500px;z-index:1}.customer-risk-banner{display:flex;align-items:flex-start;gap:10px;padding:10px 12px;border-radius:6px;background:#fff0f0;border:1px solid #fecaca;border-left:4px solid #d64545;color:#6b1f1f;font-size:13px}.customer-risk-banner__icon{flex-shrink:0;font-size:18px;line-height:1;color:#d64545}.customer-risk-banner__body{flex:1;min-width:0}.customer-risk-banner__text{margin:0;font-weight:600;color:#6b1f1f}.customer-risk-banner__list{margin-top:6px}.customer-risk-banner__list summary{cursor:pointer;color:#9b2c2c;font-size:12px;user-select:none}.customer-risk-banner__table{width:100%;margin-top:6px;font-size:12px;border-collapse:collapse}.customer-risk-banner__table th,.customer-risk-banner__table td{padding:4px 6px;border-bottom:1px solid #f5d6d6;text-align:left;color:#3b0f0f}.customer-risk-banner__table thead th{font-size:11px;text-transform:uppercase;letter-spacing:.02em;color:#7a2323;background:#ffe3e3}.customer-risk-banner__table tbody tr:last-child th,.customer-risk-banner__table tbody tr:last-child td{border-bottom:0}.customer-risk-banner__table a{color:#b91c1c;font-weight:600}.risk-return-badge{display:inline-block;padding:1px 6px;background:#d64545;color:#fff;font-size:11px;font-weight:600;border-radius:3px;margin-left:4px;cursor:default;vertical-align:middle;line-height:1.4}.table-list-table tbody tr.is-risk-return>td:first-child{border-left:3px solid #d64545}*{box-sizing:border-box}html,body{min-height:100%}body{margin:0;font-family:"Roboto","Segoe UI",sans-serif;font-size:13px;color:var(--c-text);background:var(--c-bg)}a{color:var(--c-primary)}.app-shell{min-height:100vh;display:flex}.sidebar{width:260px;min-width:260px;flex-shrink:0;overflow:hidden;transition:width .22s ease,min-width .22s ease;border-right:1px solid #243041;background:#111a28;padding:18px 10px;display:flex;flex-direction:column}.sidebar.is-collapsed{width:52px;min-width:52px;padding:18px 0}.sidebar.is-collapsed .sidebar__brand-text{display:none}.sidebar.is-collapsed .sidebar__brand{justify-content:center;margin:4px 0 16px}.sidebar.is-collapsed .sidebar__label{display:none}.sidebar.is-collapsed .sidebar__toggle-arrow{display:none}.sidebar.is-collapsed .sidebar__link,.sidebar.is-collapsed .sidebar__group-toggle{justify-content:center;padding:9px;border-radius:8px;margin:0 6px}.sidebar.is-collapsed .sidebar__group-links{display:none}.sidebar.is-collapsed .sidebar__icon{margin:0}.sidebar__brand{display:flex;align-items:center;justify-content:space-between;margin:4px 4px 16px;gap:6px;min-width:0}.sidebar__brand-text{color:#e9f0ff;font-size:24px;font-weight:300;letter-spacing:-0.02em;white-space:nowrap;overflow:hidden;flex:1;min-width:0}.sidebar__brand-text strong{font-weight:700}.sidebar__collapse-btn{flex-shrink:0;width:28px;height:28px;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0);border:1px solid #2a3a54;border-radius:6px;color:#64748b;cursor:pointer;padding:0;transition:background .15s,color .15s}.sidebar__collapse-btn:hover{background:#1b2a3f;color:#cbd5e1}.sidebar__collapse-icon{display:block;transition:transform .22s ease;flex-shrink:0}.sidebar.is-collapsed .sidebar__collapse-icon{transform:rotate(180deg)}.sidebar__nav{display:grid;gap:4px}.sidebar__link{display:flex;align-items:center;gap:9px;white-space:nowrap;border-radius:8px;padding:9px 10px;text-decoration:none;color:#cbd5e1;font-weight:600}.sidebar__link:hover{color:#f8fafc;background:#1b2a3f}.sidebar__link.is-active{color:#fff;background:#2e4f93}.sidebar__group{display:grid;gap:2px}.sidebar__group-toggle{list-style:none;border-radius:8px;padding:9px 10px;color:#cbd5e1;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:9px;white-space:nowrap;user-select:none}.sidebar__group-toggle::-webkit-details-marker{display:none}.sidebar__group:hover .sidebar__group-toggle,.sidebar__group-toggle:hover{color:#f8fafc;background:#1b2a3f}.sidebar__group.is-active .sidebar__group-toggle{color:#fff;background:#2e4f93}.sidebar__icon{flex-shrink:0;width:18px;height:18px;display:flex;align-items:center;justify-content:center;opacity:.85}.sidebar__label{flex:1;min-width:0;overflow:hidden}.sidebar__toggle-arrow{flex-shrink:0;margin-left:auto;opacity:.5;transition:transform .18s ease}details[open]>.sidebar__group-toggle .sidebar__toggle-arrow{transform:rotate(180deg)}.sidebar__group-links{display:grid;gap:2px;padding-left:12px;overflow:hidden}.sidebar__sublink{border-radius:6px;padding:7px 10px 7px 8px;text-decoration:none;color:#94a3b8;font-size:12.5px;font-weight:500;display:flex;align-items:center;gap:8px;white-space:nowrap}.sidebar__sublink::before{content:"";flex-shrink:0;width:5px;height:5px;border-radius:50%;background:rgba(148,163,184,.3);transition:background .15s}.sidebar__sublink:hover{color:#e2e8f0;background:#1b2a3f}.sidebar__sublink:hover::before{background:rgba(148,163,184,.65)}.sidebar__sublink.is-active{color:#fff;background:rgba(46,79,147,.55)}.sidebar__sublink.is-active::before{background:#93c5fd}.sidebar__badge{margin-left:auto;background:#f59e0b;color:#1f2937;font-size:10.5px;font-weight:700;line-height:1;padding:2px 6px;border-radius:10px;min-width:18px;text-align:center}.app-main{flex:1;min-width:0}.topbar{height:50px;border-bottom:1px solid var(--c-border);background:var(--c-surface);display:flex;align-items:center;justify-content:space-between;padding:0 20px;position:sticky;top:0;z-index:100}.brand{font-size:22px;font-weight:300;letter-spacing:-0.02em;color:var(--c-text-strong)}.brand strong{font-weight:700}.container{max-width:none;width:calc(100% - 20px);margin:12px 10px;padding:0 4px 14px}.card{background:var(--c-surface);border-radius:10px;box-shadow:var(--shadow-card);padding:14px}.card h1{margin:0 0 10px;color:var(--c-text-strong);font-size:24px;font-weight:700}.muted{color:var(--c-muted)}.accent{color:var(--c-primary);font-weight:600}.users-form{display:grid;gap:14px;max-width:460px}.form-field{margin-bottom:12px}.section-title{margin:0;color:var(--c-text-strong);font-size:18px;font-weight:700}h2.section-title,h3.section-title,h4.section-title{display:flex;align-items:center;gap:6px;font-weight:600;padding:6px 0;margin-bottom:8px;border-bottom:1px solid #e2e8f0;color:var(--c-primary, #2563eb)}h2.section-title::before,h3.section-title::before,h4.section-title::before{content:"■";font-size:.55em;opacity:.5}h3.section-title,h4.section-title{font-size:15px}h3.section-title::before,h4.section-title::before{content:"◆";font-size:.5em}.mt-0{margin-top:0}.mt-4{margin-top:4px}.mt-12{margin-top:8px}.mt-16{margin-top:12px}.settings-grid{display:grid;grid-template-columns:repeat(3, minmax(0, 1fr));gap:12px}.settings-nav{display:flex;gap:8px;flex-wrap:wrap}.settings-nav__link{text-decoration:none;border:1px solid var(--c-border);border-radius:8px;padding:8px 12px;color:var(--c-text-strong);font-weight:600}.settings-nav__link:hover{background:#f8fafc}.settings-nav__link.is-active{border-color:var(--c-primary);color:var(--c-primary);background:#edf2ff}.settings-stat{border:1px solid var(--c-border);border-radius:8px;padding:12px;background:#f8fafc}.settings-stat__label{display:block;color:var(--c-muted);font-size:12px;margin-bottom:4px}.settings-stat__value{color:var(--c-text-strong);font-size:20px}.settings-logs{margin:0;padding:12px;border-radius:8px;border:1px solid var(--c-border);background:#0b1220;color:#d1d5db;font-size:12px;line-height:1.5;overflow:auto}.settings-allegro-callback{display:block;width:100%;padding:8px 10px;border:1px solid var(--c-border);border-radius:8px;background:#f8fafc;color:var(--c-text-strong);font-size:12px;line-height:1.45;word-break:break-all}.page-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.filters-grid{display:grid;grid-template-columns:repeat(3, minmax(0, 1fr));gap:12px}.filters-actions{display:flex;align-items:center;gap:8px}.product-form .form-control{width:100%}.form-grid{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:12px}.form-grid-2{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:12px;align-items:start}.form-grid-3{display:grid;grid-template-columns:repeat(3, minmax(0, 1fr));gap:12px;align-items:start}.form-grid-4{display:grid;grid-template-columns:repeat(4, minmax(0, 1fr));gap:12px;align-items:start}.form-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:flex-start}.form-actions .btn{align-self:flex-start}.statuses-form{display:grid;gap:8px;grid-template-columns:repeat(2, minmax(0, 1fr))}.statuses-form .form-actions{grid-column:1/-1}.statuses-color-input{min-height:32px;padding:2px}.statuses-hint{grid-column:1/-1;margin:0}.statuses-group-block{border:1px solid var(--c-border);border-radius:10px;padding:8px;background:#fbfdff}.statuses-group-block__head{display:flex;align-items:center;justify-content:space-between;gap:6px;flex-wrap:wrap}.statuses-group-block__title{margin:0;display:inline-flex;align-items:center;gap:6px;color:var(--c-text-strong);font-size:14px}.statuses-color-dot{width:12px;height:12px;border-radius:999px;border:1px solid rgba(15,23,42,.15)}.statuses-dnd-list{margin:6px 0 0;padding:0;list-style:none;display:grid;gap:6px}.statuses-dnd-item{display:grid;grid-template-columns:24px 1fr;gap:6px;border:1px solid #dce4f0;border-radius:8px;background:#fff;padding:6px}.statuses-dnd-item__content{display:flex;align-items:center;gap:6px;min-width:0}.statuses-dnd-item.is-dragging{opacity:.6}.statuses-dnd-item__drag{display:inline-flex;align-items:center;justify-content:center;border:1px dashed #cbd5e1;border-radius:6px;color:#64748b;cursor:grab;user-select:none;font-weight:700;font-size:12px}.statuses-dnd-item__drag:active{cursor:grabbing}.statuses-inline-form{display:grid;gap:6px}.statuses-inline-form--row{grid-template-columns:minmax(180px, 1.4fr) minmax(150px, 1fr) auto auto auto;align-items:center;flex:1 1 auto;min-width:0}.statuses-inline-form--row-group{grid-template-columns:minmax(180px, 1.5fr) 56px auto auto auto;align-items:center;flex:1 1 auto;min-width:0}.statuses-inline-form--row .form-control,.statuses-inline-form--row-group .form-control{min-height:30px;padding:4px 8px}.statuses-inline-form--row .btn,.statuses-inline-form--row-group .btn,.statuses-inline-delete .btn{min-height:30px;padding:4px 10px;font-size:12px}.statuses-inline-check{margin-top:0;white-space:nowrap;font-size:12px}.statuses-inline-delete{margin:0;flex:0 0 auto}.statuses-code-label{font-size:12px;color:var(--c-muted)}.statuses-code-readonly{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;font-size:12px}.statuses-code-readonly code{background:#eef2f7;border-radius:6px;padding:1px 6px;color:#1f2937;font-size:12px}.field-inline{display:flex;align-items:center;gap:8px;margin-top:2px}.modal-backdrop{position:fixed;inset:0;background:rgba(15,23,42,.5);display:flex;align-items:center;justify-content:center;padding:16px;z-index:200}.modal-backdrop[hidden]{display:none}.modal{width:min(560px,100%);background:#fff;border-radius:10px;box-shadow:0 20px 40px rgba(15,23,42,.35);overflow:hidden}.modal__header{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:16px 18px;border-bottom:1px solid var(--c-border)}.modal__header h3{margin:0;font-size:18px;color:var(--c-text-strong)}.modal__body{padding:16px 18px 18px}.status-pill{display:inline-flex;align-items:center;justify-content:center;border:1px solid #fed7d7;background:#fff5f5;color:#9b2c2c;padding:2px 8px;border-radius:999px;font-size:12px;font-weight:600}.status-pill.is-active{border-color:#b7ebcf;background:#f0fff6;color:#0f6b39}.table-row-actions{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}.table-row-actions form{margin:0}.table-list{display:grid;gap:14px}.table-list__header{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}.table-list__left{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}.table-list-header-actions{display:inline-flex;align-items:center;gap:10px;flex-wrap:wrap}.js-filter-toggle-btn.is-active{border-color:#cbd5e0;background:#edf2ff;color:var(--c-primary-dark)}.table-filter-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;font-size:11px;font-weight:700;color:#fff;background:var(--c-primary);border-radius:999px}.table-filters-wrapper{display:none}.table-filters-wrapper.is-open{display:block}.table-list-filters{display:grid;gap:12px;grid-template-columns:repeat(auto-fit, minmax(170px, 1fr));align-items:end}.table-col-toggle-wrapper{position:relative}.table-col-toggle-dropdown{display:none;position:absolute;right:0;top:calc(100% + 6px);z-index:30;width:260px;max-height:360px;overflow:auto;border:1px solid var(--c-border);border-radius:10px;background:#fff;box-shadow:0 10px 25px rgba(15,23,42,.12)}.table-col-toggle-dropdown.is-open{display:block}.table-col-toggle-header{padding:10px 12px;border-bottom:1px solid var(--c-border);font-size:12px;font-weight:700;color:var(--c-muted)}.table-col-toggle-item{display:flex;align-items:center;gap:10px;padding:8px 12px;font-size:13px;color:var(--c-text-strong)}.table-col-toggle-item:hover{background:#f8fafc}.table-col-toggle-footer{border-top:1px solid var(--c-border);padding:8px 12px}.table-col-hidden{display:none}.table-col-switch{position:relative;display:inline-block;width:34px;min-width:34px;height:18px}.table-col-switch input{opacity:0;width:0;height:0;position:absolute}.table-col-switch-slider{position:absolute;top:0;left:0;right:0;bottom:0;background:#cbd5e1;border-radius:999px;transition:background-color .2s ease}.table-col-switch-slider::before{content:"";position:absolute;height:14px;width:14px;left:2px;bottom:2px;background:#fff;border-radius:50%;transition:transform .2s ease}.table-col-switch input:checked+.table-col-switch-slider{background:#16a34a}.table-col-switch input:checked+.table-col-switch-slider::before{transform:translateX(16px)}.table-sort-link{display:inline-flex;align-items:center;gap:6px;color:var(--c-text-strong);text-decoration:none}.table-sort-link:hover{color:var(--c-primary-dark)}.table-sort-icon.is-muted{color:#a0aec0}.table-list__footer{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}.table-list-per-page-form{display:inline-flex;align-items:center;gap:8px}.table-list-per-page-form .form-control{min-width:90px}.table-select-col{width:44px;text-align:center}.table-select-toggle{display:inline-flex;align-items:center;justify-content:center}.table-select-toggle input[type=checkbox]{width:16px;height:16px}.orders-page .orders-head{background:linear-gradient(120deg, #f8fbff 0%, #eef5ff 100%);border:1px solid #dbe7fb}.orders-page .table-list{border:1px solid #dde5f2;border-radius:12px;box-shadow:0 6px 16px rgba(20,44,86,.08)}.orders-page .table-list__header{padding:10px 6px 2px}.orders-page .table-list-filters{padding:6px 6px 2px;border-top:1px solid #ebf0f7;border-bottom:1px solid #ebf0f7;background:#f9fbff}.orders-page .table-wrap{border-radius:10px;overflow:hidden;border:1px solid #e7edf6}.orders-page .table thead th{background:#f3f7fd;color:#30435f;font-size:12px;text-transform:uppercase;letter-spacing:.03em}.orders-page .table tbody td{vertical-align:middle;padding-top:10px;padding-bottom:10px;border-bottom-color:#edf2f8}.orders-page .table tbody tr:hover td{background:#f9fcff}.orders-list-page{padding:10px;margin-bottom:10px}.statistics-orders-page{padding:10px}.statistics-orders-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}.statistics-orders-filters{display:grid;grid-template-columns:repeat(auto-fit, minmax(170px, 1fr));gap:10px;align-items:end}.statistics-orders-filters__actions{align-self:end}.statistics-orders-multiselect{min-height:120px;height:120px;padding-top:6px;padding-bottom:6px}.checkbox-multiselect{position:relative;width:100%}.checkbox-multiselect select[data-checkbox-multiselect-enhanced]{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}.checkbox-multiselect__trigger{width:100%;min-height:30px;display:flex;align-items:center;justify-content:space-between;gap:8px;border:1px solid var(--c-border);border-radius:6px;padding:4px 8px;font:inherit;color:var(--c-text-strong);background:#fff;cursor:pointer;text-align:left;transition:border-color .2s ease,box-shadow .2s ease}.checkbox-multiselect__value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.checkbox-multiselect__arrow{flex:0 0 auto;width:7px;height:7px;border-right:1.5px solid #64748b;border-bottom:1.5px solid #64748b;transform:rotate(45deg) translateY(-2px)}.checkbox-multiselect__dropdown{display:none;position:absolute;z-index:40;top:calc(100% + 2px);left:0;right:0;max-height:200px;overflow-y:auto;padding:8px 8px 6px;border:1px solid var(--c-primary);border-radius:0 0 6px 6px;background:#fff;box-shadow:0 18px 38px rgba(45,55,72,.16)}.checkbox-multiselect.is-open .checkbox-multiselect__trigger{border-color:var(--c-primary);border-bottom-right-radius:0;border-bottom-left-radius:0;box-shadow:var(--focus-ring)}.checkbox-multiselect.is-open .checkbox-multiselect__dropdown{display:grid;gap:4px}.checkbox-multiselect.is-open .checkbox-multiselect__arrow{transform:rotate(225deg) translate(-2px, -1px)}.checkbox-multiselect__option{display:flex;align-items:center;gap:6px;min-height:20px;color:var(--c-text);font-size:13px;line-height:1.25;cursor:pointer}.checkbox-multiselect__option input{width:17px;height:17px;margin:0;flex:0 0 auto;accent-color:var(--c-primary)}.checkbox-multiselect__option--all{color:var(--c-text-strong);font-weight:700}.statistics-orders-table-wrap{overflow-x:auto}.statistics-orders-table{min-width:880px}.statistics-orders-table thead th{text-align:center;white-space:nowrap}.statistics-orders-table tbody td,.statistics-orders-table tfoot th{text-align:right;white-space:nowrap}.statistics-orders-table tbody td:first-child,.statistics-orders-table tfoot th:first-child{text-align:left}.statistics-orders-table tfoot th{border-top:2px solid #cbd5e1;background:#f8fafc}.orders-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}.orders-stats{display:inline-grid;grid-template-columns:repeat(3, minmax(86px, auto));gap:8px}.orders-stat{border:1px solid #d8e2f0;background:#f8fbff;border-radius:8px;padding:6px 8px;line-height:1.15}.orders-stat__label{display:block;color:#5f6f83;font-size:11px;margin-bottom:2px}.orders-stat__value{color:#12233a;font-size:16px;font-weight:700}.orders-ref{display:grid;gap:2px;min-width:170px}.orders-ref__main{font-weight:700;color:#0f1f35;font-size:14px}.orders-ref__meta{display:inline-flex;flex-wrap:wrap;gap:4px 10px;color:#64748b;font-size:12px}.orders-buyer{display:grid;gap:2px}.orders-buyer__name{color:#0f172a;font-weight:600;font-size:14px}.orders-buyer__meta{display:inline-flex;flex-wrap:wrap;gap:4px 10px;color:#64748b;font-size:12px}.orders-status-wrap{display:inline-flex;align-items:center;gap:5px;flex-wrap:wrap;cursor:pointer}.orders-status-wrap .order-tag{cursor:pointer}.orders-status-dropdown{position:fixed;z-index:9999;min-width:180px;max-height:280px;overflow-y:auto;background:#fff;border:1px solid #d8e1ef;border-radius:6px;box-shadow:0 4px 16px rgba(0,0,0,.12);padding:4px 0}.orders-status-dropdown__group-header{padding:6px 12px 2px;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:#94a3b8}.orders-status-dropdown__group-header:not(:first-child){border-top:1px solid #f1f5f9;margin-top:2px;padding-top:8px}.orders-status-dropdown__item{display:flex;align-items:center;gap:8px;padding:5px 12px;font-size:13px;color:#334155;cursor:pointer;white-space:nowrap}.orders-status-dropdown__item:hover{background:#f1f5f9}.orders-status-dropdown__item.is-current{font-weight:700;background:#f8fafc}.orders-status-dropdown__color-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}.order-tag{display:inline-flex;align-items:center;justify-content:center;border:1px solid #d8e1ef;background:#f8fafc;color:#334155;border-radius:999px;padding:2px 8px;font-size:12px;font-weight:700;line-height:1.1;white-space:nowrap}.order-tag.is-info{border-color:#bfdbfe;background:#eff6ff;color:#1d4ed8}.order-tag.is-success{border-color:#bbf7d0;background:#f0fdf4;color:#166534}.order-tag.is-danger{border-color:#fecaca;background:#fef2f2;color:#b91c1c}.order-tag.is-warn{border-color:#fde68a;background:#fffbeb;color:#92400e}.order-tag.is-cod{border-color:#f9a8d4;background:#fdf2f8;color:#9d174d}.order-tag.is-unpaid{border-color:#fca5a5;background:#fef2f2;color:#b91c1c}.orders-mini{font-size:14px;color:#223247;line-height:1.25}.orders-mini__delivery{font-size:12px;color:#64748b;margin-bottom:2px;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.orders-products{display:grid;gap:4px;min-width:240px}.orders-products__meta,.orders-products__more{font-size:12px;color:#64748b}.orders-product{display:grid;grid-template-columns:48px 1fr;gap:6px;align-items:center}.orders-product__thumb{width:48px;height:48px;border-radius:4px;border:1px solid #dbe3ef;object-fit:cover;background:#fff}.orders-product__thumb--empty{display:inline-block;background:#eef2f7;border-style:dashed}.orders-product__txt{min-width:0;display:grid;gap:1px}.orders-product__name{font-size:14px;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.orders-product__qty{font-size:12px;color:#64748b}.orders-image-hover-wrap{position:relative;display:inline-flex;align-items:center;justify-content:center;cursor:zoom-in}.orders-image-hover-popup{display:none;position:fixed;left:auto;top:auto;width:350px;max-height:350px;object-fit:contain;border-radius:8px;background:#fff;box-shadow:0 8px 24px rgba(0,0,0,.18);border:1px solid #dfe3ea;z-index:100;pointer-events:none}.orders-image-hover-wrap:hover .orders-image-hover-popup{display:block}.activity-type-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:12px;font-weight:500;white-space:nowrap;background:#e2e8f0;color:#334155}.activity-type-badge--status_change{background:#dbeafe;color:#1e40af}.activity-type-badge--payment{background:#dcfce7;color:#166534}.activity-type-badge--invoice{background:#fef3c7;color:#92400e}.activity-type-badge--shipment{background:#e0e7ff;color:#3730a3}.activity-type-badge--message{background:#f3e8ff;color:#6b21a8}.activity-type-badge--document{background:#fce7f3;color:#9d174d}.activity-type-badge--import{background:#f1f5f9;color:#475569}.activity-type-badge--note{background:#ecfdf5;color:#065f46}.text-nowrap{white-space:nowrap}.orders-money{display:grid;gap:2px}.orders-money__main{color:#0f172a;font-weight:700;font-size:14px}.orders-money__meta{color:#64748b;font-size:12px}.table-list[data-table-list-id=orders]{gap:8px}.table-list[data-table-list-id=orders] .table-list__header{padding:2px 0 0}.table-list[data-table-list-id=orders] .table-list-filters{gap:8px;grid-template-columns:repeat(auto-fit, minmax(150px, 1fr))}.table-list[data-table-list-id=orders] .table th,.table-list[data-table-list-id=orders] .table td{padding:6px 8px}.table-list[data-table-list-id=orders] .table thead th{font-size:12px;text-transform:uppercase;letter-spacing:.02em;white-space:nowrap}.table-list[data-table-list-id=orders] .table tbody td{vertical-align:top;font-size:14px;line-height:1.25}.order-show-layout{display:grid;grid-template-columns:220px minmax(0, 1fr);gap:12px;align-items:start}.order-statuses-side{position:sticky;top:60px;padding:10px}.order-statuses-side__title{font-size:13px;font-weight:700;color:#0f172a;margin-bottom:8px;display:flex;align-items:center;justify-content:space-between;list-style:none}.order-statuses-side__title::-webkit-details-marker{display:none}.order-statuses-side__arrow{display:none;flex-shrink:0;opacity:.5;transition:transform .2s ease}details[open]>.order-statuses-side__title .order-statuses-side__arrow{transform:rotate(180deg)}.order-status-group{margin-bottom:10px}.order-status-group__name{display:flex;align-items:center;justify-content:space-between;gap:6px;font-size:12px;color:#475569;font-weight:700;margin-bottom:5px;text-decoration:none;padding:3px 6px;border-radius:6px;border-left:3px solid rgba(0,0,0,0);cursor:pointer;transition:background .15s}.order-status-group__name:hover{background:#f1f5f9}.order-status-group__count{min-width:24px;text-align:center;border-radius:999px;background:var(--group-color, #64748b);padding:1px 6px;font-weight:700;font-size:11px;color:#fff}.order-status-group.is-active>.order-status-group__name{background:rgba(15,23,42,.06);color:#0f172a;border-left-color:var(--group-color, #64748b)}.order-status-row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:4px 6px;border-radius:6px;color:#334155;font-size:12px;text-decoration:none}.order-status-row__count{min-width:24px;text-align:center;border-radius:999px;background:var(--status-color, #64748b);padding:1px 6px;font-weight:700;font-size:11px;color:#fff}.order-status-row:hover{background:#f1f5f9}.order-status-row.is-active{background:rgba(15,23,42,.06);color:#0f172a;font-weight:700}.order-show-main{min-width:0}.order-details-actions{display:inline-flex;flex-wrap:wrap;justify-content:flex-end;gap:6px}.order-details-page{padding:12px}.order-details-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}.order-back-link{color:#475569;text-decoration:none;font-weight:600}.order-back-link:hover{color:#1d4ed8}.order-details-sub{display:inline-flex;gap:10px;flex-wrap:wrap;color:#64748b;font-size:12px}.order-details-pill{border-radius:999px;padding:5px 10px;background:#eef6ff;border:1px solid #cfe2ff;color:#1d4ed8;font-size:12px;font-weight:700}.order-status-change{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.order-status-change__form{display:flex;align-items:center;gap:6px}.order-status-change__select{min-width:180px}.order-details-tabs{display:flex;gap:6px;flex-wrap:wrap}.order-details-tab{border:1px solid #d6deea;border-radius:8px;padding:5px 10px;color:#475569;font-size:12px;background:#f8fafc;cursor:pointer}.order-details-tab.is-active{border-color:#bfdbfe;color:#1d4ed8;background:#eff6ff;font-weight:700}.order-item-cell{display:grid;grid-template-columns:44px 1fr;gap:8px;align-items:center;min-width:260px}.order-item-thumb{width:44px;height:44px;border-radius:6px;border:1px solid #dbe3ef;object-fit:cover}.order-item-thumb--empty{display:inline-block;background:#eef2f7;border-style:dashed}.order-item-name{font-weight:600;color:#0f172a}.item-personalization{margin-top:4px;padding:4px 8px;background:#f8fafc;border-left:2px solid #cbd5e1;border-radius:2px;font-size:.92em;color:#475569;line-height:1.4}.item-personalization__label{font-weight:600;color:#64748b;display:block;margin-bottom:2px}.item-personalization__line{white-space:pre-wrap;word-break:break-word}.order-grid-2{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:12px}.order-grid-3{display:grid;grid-template-columns:repeat(3, minmax(0, 1fr));gap:12px}.order-kv{margin:0;display:grid;grid-template-columns:150px 1fr;gap:6px 10px;font-size:12px}.order-payment-shipping .section-title-row{display:flex;align-items:center;justify-content:space-between;gap:8px}.order-payment-shipping .btn-edit-inline{background:rgba(0,0,0,0);border:1px solid rgba(0,0,0,0);color:#6b7280;padding:3px 5px;cursor:pointer;border-radius:4px;display:inline-flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s,background-color .15s,color .15s}.order-payment-shipping .btn-edit-inline:hover{background:#f3f4f6;color:#111827}.order-payment-shipping:hover .btn-edit-inline{opacity:1}.order-details-edit-form{margin-top:12px;padding:10px;background:#f9fafb;border:1px solid #e5e7eb;border-radius:6px;font-size:12px}.order-details-edit-form .form-row{margin-bottom:8px}.order-details-edit-form label{display:block;color:#374151;font-weight:500}.order-details-edit-form label input[type=text]{display:block;width:100%;margin-top:3px;padding:5px 7px;border:1px solid #d1d5db;border-radius:4px;font-size:12px;box-sizing:border-box}.order-details-edit-form label.checkbox-inline{display:flex;align-items:center;gap:6px;font-weight:400}.order-details-edit-form label.checkbox-inline input{margin:0}.order-details-edit-form label.checkbox-inline code{background:#eef2ff;padding:1px 4px;border-radius:3px;font-size:11px}.order-details-edit-form .form-actions{display:flex;gap:6px;margin-top:8px}.payment-summary{display:grid;gap:6px;max-width:420px}.payment-summary__row{display:flex;align-items:center;gap:10px;font-size:12px}.payment-summary__label{width:150px;flex-shrink:0;color:#64748b}.payment-summary__value{font-weight:600;color:#0f172a}.payment-add-form{background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;padding:12px;max-width:700px}.payment-add-form__row{display:flex;flex-wrap:wrap;gap:10px}.payment-add-form__field{display:flex;flex-direction:column;gap:3px;flex:1 1 140px;min-width:120px}.payment-add-form__field label{font-size:11px;color:#64748b;font-weight:500}.payment-add-form__field input,.payment-add-form__field select{font-size:12px;padding:4px 8px;border:1px solid #cbd5e1;border-radius:4px;height:30px}.payment-add-form__actions{display:flex;gap:8px;margin-top:12px}.order-kv dt{color:#64748b}.order-kv dd{margin:0;color:#0f172a;font-weight:600}.order-address{display:grid;gap:3px;font-size:12px;color:#0f172a}.order-events{display:grid;gap:8px}.order-event{border:1px solid #e2e8f0;border-radius:8px;padding:8px;background:#fbfdff}.order-event__head{color:#64748b;font-size:11px}.order-event__body{margin-top:4px;color:#0f172a;font-size:12px}.order-tab-panel{display:none}.order-tab-panel.is-active{display:block}.manual-tracking-form{display:flex;gap:8px;align-items:center}.manual-tracking-form .form-control{max-width:220px}.order-empty-placeholder{border:1px dashed #cbd5e1;border-radius:8px;min-height:180px;background:#f8fafc}.order-status-badge{display:inline-flex;align-items:center;justify-content:center;padding:4px 10px;border-radius:999px;font-size:12px;font-weight:700;border:1px solid #cbd5e1;color:#334155;background:#f8fafc}.order-status-badge.is-info{border-color:#bfdbfe;background:#eff6ff;color:#1d4ed8}.order-status-badge.is-success{border-color:#bbf7d0;background:#f0fdf4;color:#166534}.order-status-badge.is-danger{border-color:#fecaca;background:#fef2f2;color:#b91c1c}.order-status-badge.is-warn{border-color:#fde68a;background:#fffbeb;color:#92400e}.order-status-badge.is-empty{color:#94a3b8}.order-buyer{display:grid;gap:2px}.order-buyer__name{color:#0f172a;font-weight:600}.order-buyer__email{color:#64748b;font-size:12px}.table-inline-action{display:inline-block;margin-right:6px}.product-name-cell{display:inline-flex;align-items:center;gap:10px}.product-name-thumb{width:60px;height:60px;border-radius:6px;object-fit:cover;border:1px solid var(--c-border);background:#f8fafc}.product-name-thumb--empty{display:inline-block;width:60px;height:60px;border-radius:6px;border:1px dashed #cbd5e0;background:#f8fafc}.product-name-thumb-btn{border:0;padding:0;background:rgba(0,0,0,0);cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.product-name-thumb-btn:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:8px}.modal--image-preview{width:min(760px,100%)}.product-image-preview__img{display:block;width:100%;max-height:70vh;object-fit:contain;border-radius:8px;background:#f8fafc}.product-images-grid{display:grid;grid-template-columns:repeat(auto-fill, minmax(220px, 1fr));gap:12px}.product-image-card{border:1px solid #dfe3ea;border-radius:10px;padding:10px;background:#fff}.product-image-card__thumb-wrap{position:relative;border-radius:8px;overflow:hidden;background:#f2f5f8}.product-image-card__thumb{width:100%;height:160px;object-fit:cover;display:block}.product-image-card__thumb.is-empty{height:160px;display:grid;place-items:center;color:#6b7785;font-size:12px}.product-image-card__badge{display:none;position:absolute;top:8px;left:8px;background:#1f7a43;color:#fff;padding:3px 8px;border-radius:999px;font-size:11px}.product-image-card.is-main .product-image-card__badge{display:inline-block}.product-image-card__meta{margin-top:8px;font-size:11px;line-height:1.25;color:#5f6b79;overflow-wrap:anywhere}.product-image-card__actions{margin-top:10px;display:grid;grid-template-columns:1fr;gap:8px}.product-image-card__actions .btn{min-height:34px;font-size:12px;line-height:1.2;padding:6px 10px}.product-links-search-form{display:grid;gap:12px;grid-template-columns:minmax(220px, 320px) minmax(220px, 1fr) auto;align-items:end}.product-links-head{display:grid;gap:8px;grid-template-columns:repeat(3, minmax(0, 1fr))}.product-tabs-nav{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.product-links-inline-form{display:grid;gap:8px;grid-template-columns:minmax(140px, 1fr) minmax(140px, 1fr) auto;align-items:center}.product-links-actions-row{display:flex;align-items:center;gap:8px;flex-wrap:nowrap}.product-links-actions-row .product-links-relink-form{flex:1 1 auto}.product-links-unlink-form{margin:0;flex:0 0 auto}.product-link-status-cell{display:inline-flex;align-items:center;gap:6px}.product-link-alert-indicator{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:999px;border:1px solid #f59e0b;background:#fffbeb;color:#b45309;font-size:12px;font-weight:700;cursor:help}.product-link-events-list{margin:0;padding:0;list-style:none;display:grid;gap:4px}.product-link-events-list li{display:grid;gap:2px}.product-link-events-type{font-weight:600;color:var(--c-text-strong)}.product-link-events-date{color:var(--c-muted);font-size:12px}.product-show-images-grid{display:grid;grid-template-columns:repeat(auto-fill, minmax(220px, 1fr));gap:12px}.product-show-image-card{border:1px solid var(--c-border);border-radius:10px;background:#fff;padding:10px;overflow:hidden}.product-show-image-card__meta{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;min-width:0}.product-show-image-path{font-size:12px;min-width:0;overflow:hidden}.product-show-image-path summary{cursor:pointer;color:var(--c-muted, #888);list-style:none;user-select:none;white-space:nowrap}.product-show-image-path summary::-webkit-details-marker{display:none}.product-show-image-path summary::after{content:" ▾"}.product-show-image-path[open] summary::after{content:" ▴"}.product-show-image-path__url{margin-top:4px;word-break:break-all;overflow-wrap:break-word;font-size:11px}.product-show-image{width:100%;max-height:260px;object-fit:cover;border-radius:8px;border:1px solid #d9e0ea}.shipment-grid{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:12px}.searchable-select{position:relative}.searchable-select__trigger{display:flex;align-items:center;justify-content:space-between;cursor:pointer;user-select:none;min-height:34px}.searchable-select__trigger::after{content:"";width:0;height:0;border-left:4px solid rgba(0,0,0,0);border-right:4px solid rgba(0,0,0,0);border-top:5px solid var(--c-text-muted, #6b7280);margin-left:8px;flex-shrink:0}.searchable-select__trigger--placeholder{color:var(--c-text-muted, #6b7280)}.searchable-select__dropdown{display:none;position:absolute;left:0;right:0;top:100%;z-index:50;max-height:280px;overflow:auto;background:#fff;border:1px solid var(--c-border);border-top:0;border-radius:0 0 8px 8px;box-shadow:0 8px 20px rgba(15,23,42,.12)}.searchable-select__dropdown.is-open{display:block}.searchable-select__search{position:sticky;top:0;border:none !important;border-bottom:1px solid var(--c-border) !important;border-radius:0 !important;box-shadow:none !important;font-size:13px;background:#fff;z-index:1}.searchable-select__option{padding:7px 10px;font-size:13px;cursor:pointer;color:var(--c-text-strong)}.searchable-select__option:hover{background:#f1f5f9}.searchable-select__option.is-selected{background:#edf2ff;font-weight:600}.flash{padding:10px 14px;border-radius:8px;font-size:13px;font-weight:500}.flash--success{background:#f0fdf4;border:1px solid #bbf7d0;color:#166534}.flash--error{background:#fef2f2;border:1px solid #fecaca;color:#b91c1c}.content-tabs-card{margin-top:0}.content-tabs-nav{display:flex;gap:4px;border-bottom:2px solid var(--c-border);margin-bottom:16px;flex-wrap:wrap}.content-tab-btn{padding:8px 16px;border:none;background:none;cursor:pointer;font-size:14px;font-weight:500;color:var(--c-text-muted, #6b7280);border-bottom:2px solid rgba(0,0,0,0);margin-bottom:-2px;border-radius:4px 4px 0 0;transition:color .15s,border-color .15s}.content-tab-btn:hover{color:var(--c-text-strong, #111827)}.content-tab-btn.is-active{color:var(--c-primary, #2563eb);border-bottom-color:var(--c-primary, #2563eb)}.content-tab-panel{display:none}.content-tab-panel.is-active{display:block}.shoppro-tabs-toolbar{display:flex;align-items:flex-end;justify-content:space-between;gap:10px;margin-bottom:10px;flex-wrap:wrap}.shoppro-tabs-toolbar__field{margin:0;min-width:260px;max-width:420px;flex:1 1 320px}.shoppro-tabs-toolbar__field .form-control{width:100%}.shoppro-tabs-toolbar__actions{display:inline-flex;align-items:center;gap:8px}.dm-carrier-select{min-width:140px}.dm-service-wrap{min-width:200px}.dm-service-wrap .dm-inpost-panel .form-control,.dm-service-wrap .dm-apaczka-panel .form-control{width:100%}.integration-settings-group{grid-column:1/-1;border:1px solid var(--c-border);border-radius:10px;background:#f8fbff;padding:10px}.integration-settings-group__head{margin-bottom:8px;padding:4px 0;border-bottom:1px solid #e2e8f0}.integration-settings-group__title{margin:0;font-size:14px;font-weight:600;letter-spacing:.01em;color:var(--c-text-strong, #1e293b)}.integration-settings-group__desc{margin:4px 0 0;color:#4b5563}.integration-settings-group__grid{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:10px 12px;align-items:start}.integration-settings-group__full{grid-column:1/-1}.integration-settings-group__grid .form-field{margin:0;align-self:start}.integration-settings-group__grid .form-control{min-height:34px;height:34px}.integration-settings-group__grid input[type=date].form-control{line-height:1.2}.integration-settings-checkboxes{border:0;padding:0;margin:0}.integration-settings-checkboxes .field-label{display:block;margin-bottom:2px}.integration-settings-checkboxes__list{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:6px 12px}.integration-settings-checkboxes__item{display:inline-flex;align-items:center;gap:6px;font-size:13px;color:#334155}.topbar__hamburger{display:none;align-items:center;justify-content:center;width:36px;height:36px;padding:0;background:rgba(0,0,0,0);border:none;color:var(--c-text-strong);cursor:pointer;border-radius:6px;flex-shrink:0}.topbar__hamburger:hover{background:var(--c-bg-subtle, #f1f5f9)}.sidebar-backdrop{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:999;opacity:0;transition:opacity .25s ease}.sidebar-backdrop.is-visible{display:block;opacity:1}body.no-scroll{overflow:hidden}@media(max-width: 768px){.topbar__hamburger{display:flex}.sidebar{position:fixed;top:0;left:0;bottom:0;width:280px;min-width:280px;z-index:1000;transform:translateX(-100%);transition:transform .25s ease;border-right:1px solid #243041;overflow-y:auto}.sidebar.is-mobile-open{transform:translateX(0)}.sidebar__brand{margin:4px 4px 12px}.sidebar__collapse-btn{display:flex}.sidebar__collapse-icon{transform:rotate(180deg)}.sidebar__nav{display:grid;gap:4px}.topbar{padding:0 14px}.container{margin-top:16px;width:calc(100% - 16px);margin-left:8px;margin-right:8px;padding:0 3px 12px}.settings-grid{grid-template-columns:1fr}.page-head{flex-direction:column;align-items:flex-start}.orders-stats{grid-template-columns:1fr;width:100%}.order-show-layout{grid-template-columns:1fr}.order-statuses-side{position:static;top:auto}.order-statuses-side__title{cursor:pointer}.order-statuses-side__arrow{display:block}.order-details-actions{justify-content:flex-start}.order-grid-2,.order-grid-3{grid-template-columns:1fr}.order-kv{grid-template-columns:1fr;gap:2px}.filters-grid,.form-grid,.form-grid-2,.form-grid-3,.form-grid-4,.shipment-grid,.statuses-form,.statuses-inline-form,.table-list-filters,.product-links-search-form,.product-links-inline-form{grid-template-columns:1fr}.statuses-dnd-item__content{display:block}.statuses-inline-delete{margin-top:6px}.filters-actions{align-items:center}.table-list__header,.table-list__footer{align-items:flex-start}.product-links-head{grid-template-columns:1fr}.integration-settings-group__grid{grid-template-columns:1fr}.integration-settings-checkboxes__list{grid-template-columns:1fr}.card{padding:12px}.modal--image-preview{width:min(92vw,100%)}.email-tpl-editor-wrap{flex-direction:column}.email-tpl-var-panel{min-width:200px}.modal-box{width:95vw;max-height:90vh}}.email-tpl-editor-wrap{display:flex;flex-direction:column;border:1px solid var(--c-border);border-radius:6px;overflow:visible}.email-tpl-toolbar{display:flex;align-items:center;gap:6px;padding:6px 8px;background:var(--c-bg-subtle, #f8f9fa);border-bottom:1px solid var(--c-border)}.email-tpl-var-dropdown{position:relative}.email-tpl-var-panel{position:absolute;top:100%;left:0;z-index:300;min-width:260px;max-height:320px;overflow-y:auto;background:var(--c-bg);border:1px solid var(--c-border);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.12);padding:6px;margin-top:4px}.email-var-group:not(:first-child){margin-top:6px;padding-top:6px;border-top:1px solid var(--c-border)}.email-var-group__label{font-size:11px;font-weight:600;text-transform:uppercase;color:var(--c-text-muted);padding:2px 4px;letter-spacing:.03em}.email-var-item{display:block;width:100%;text-align:left;padding:3px 6px;margin:1px 0;border:none;background:none;font-size:12px;font-family:"Roboto Mono",monospace;color:var(--c-text);border-radius:3px;cursor:pointer}.email-var-item:hover{background:var(--c-primary);color:#fff}#js-quill-editor{min-height:200px}#js-quill-editor .ql-editor{min-height:200px;font-size:13px}.modal-overlay{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.45)}.modal-box{width:min(680px,90vw);max-height:80vh;background:var(--c-bg);border-radius:8px;box-shadow:0 8px 30px rgba(0,0,0,.2);display:flex;flex-direction:column;overflow:hidden}.modal-box__header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--c-border)}.modal-box__title{margin:0;font-size:15px;font-weight:600}.modal-box__close{background:none;border:none;font-size:22px;line-height:1;cursor:pointer;color:var(--c-text-muted);padding:0 4px}.modal-box__close:hover{color:var(--c-text)}.modal-box__body{padding:12px 16px;overflow-y:auto;flex:1}.table-list-table tbody tr.order-row-aged>td{border-top:2px solid rgba(0,0,0,0);border-bottom:2px solid rgba(0,0,0,0)}.table-list-table tbody tr.order-row-aged>td:first-child{border-left:2px solid rgba(0,0,0,0)}.table-list-table tbody tr.order-row-aged>td:last-child{border-right:2px solid rgba(0,0,0,0)}.table-list-table tbody tr.order-row-aged-4>td{border-color:#f8b4b4}.table-list-table tbody tr.order-row-aged-5>td{border-color:#f28282}.table-list-table tbody tr.order-row-aged-6>td{border-color:#e74c3c}.table-list-table tbody tr.order-row-aged-7>td{border-color:#991b1b} +:root{--c-primary: #6690f4;--c-primary-dark: #3164db;--c-action-primary: #0f766e;--c-action-primary-dark: #0b5f59;--c-bg: #f4f6f9;--c-surface: #ffffff;--c-text: #4e5e6a;--c-text-strong: #2d3748;--c-muted: #718096;--c-border: #b0bec5;--c-danger: #cc0000;--focus-ring: 0 0 0 3px rgba(102, 144, 244, 0.15);--focus-ring-action: 0 0 0 3px rgba(15, 118, 110, 0.18);--shadow-card: 0 1px 4px rgba(0, 0, 0, 0.06)}.btn{display:inline-flex;align-items:center;justify-content:center;min-height:34px;padding:6px 12px;border:1px solid rgba(0,0,0,0);border-radius:8px;font:inherit;font-weight:600;text-decoration:none;cursor:pointer;transition:background-color .2s ease,border-color .2s ease,color .2s ease,transform .1s ease}.btn--primary{color:#fff;background:var(--c-action-primary)}.btn--primary:hover{background:var(--c-action-primary-dark)}.btn--secondary{color:var(--c-text-strong);border-color:var(--c-border);background:var(--c-surface)}.btn--secondary:hover{border-color:#cbd5e0;background:#f8fafc}.btn--danger{color:#fff;border-color:#b91c1c;background:#dc2626}.btn--danger:hover{border-color:#991b1b;background:#b91c1c}.btn--sm{min-height:28px;padding:3px 10px;font-size:12px}.btn--block{width:100%}.btn--disabled{opacity:.3;cursor:not-allowed;pointer-events:none}.btn:active{transform:translateY(1px)}.btn:focus-visible{outline:none;box-shadow:var(--focus-ring-action);border-color:var(--c-action-primary)}.form-control{width:100%;min-height:30px;border:1px solid var(--c-border);border-radius:6px;padding:4px 8px;font:inherit;color:var(--c-text-strong);background:#fff;transition:border-color .2s ease,box-shadow .2s ease}.form-control:focus{outline:none;border-color:var(--c-primary);box-shadow:var(--focus-ring)}.input{min-height:34px;border:1px solid var(--c-border);border-radius:8px;padding:5px 10px;font:inherit;color:var(--c-text-strong);background:#fff}.input--sm{min-height:28px;padding:3px 8px;font-size:12px}.flash{padding:8px 12px;border-radius:6px;font-size:13px}.flash--success{border:1px solid #b7ebcf;background:#f0fff6;color:#0f6b39}.flash--error{border:1px solid #fed7d7;background:#fff5f5;color:var(--c-danger)}.alert{padding:12px 14px;border-radius:8px;border:1px solid rgba(0,0,0,0);font-size:13px;min-height:44px}.alert--danger{border-color:#fed7d7;background:#fff5f5;color:var(--c-danger)}.alert--success{border-color:#b7ebcf;background:#f0fff6;color:#0f6b39}.alert--warning{border-color:#f7dd8b;background:#fff8e8;color:#815500}.form-field{display:grid;gap:5px}.field-label{color:var(--c-text-strong);font-size:13px;font-weight:600}.table-wrap{width:100%;overflow-x:auto}.table-wrap--visible{overflow:visible !important;overflow-x:visible !important}.table{width:100%;border-collapse:collapse;background:var(--c-surface)}.table th,.table td{padding:10px 12px;border-bottom:1px solid var(--c-border);text-align:left}.table th{color:var(--c-text-strong);font-weight:700;background:#f8fafc}.table--details th{white-space:nowrap}.table--details th:first-child,.table--details td:first-child{width:36px;text-align:center}.pagination{display:flex;align-items:center;flex-wrap:wrap;gap:8px}.pagination__item{display:inline-flex;align-items:center;justify-content:center;min-width:36px;height:36px;padding:0 10px;border-radius:8px;border:1px solid var(--c-border);color:var(--c-text-strong);background:var(--c-surface);text-decoration:none;font-weight:600}.pagination__item:hover{border-color:#cbd5e0;background:#f8fafc}.pagination__item.is-active{border-color:var(--c-primary);color:var(--c-primary);background:#edf2ff}.receipt-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:16px;padding-bottom:12px;border-bottom:2px solid var(--c-text-strong)}.receipt-header__seller{flex:1}.receipt-header__seller strong{font-size:14px;display:block;margin-bottom:4px}.receipt-header__title{text-align:right}.receipt-header__title h1{font-size:18px;font-weight:700;margin-bottom:4px}.receipt-print{max-width:700px;margin:0 auto}@media print{.receipt-print{max-width:100%}}.copy-name-row{display:flex;align-items:center;gap:6px}.copy-btn-inline{display:inline-flex;align-items:center;justify-content:center;background:none;border:none;padding:2px;cursor:pointer;color:var(--c-text-muted, #999);border-radius:3px;transition:color .15s;flex-shrink:0}.copy-btn-inline:hover{color:var(--c-primary)}.copy-btn-inline .check-icon{color:var(--c-action-primary)}.email-send-overlay{position:fixed;inset:0;z-index:1000;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center}.email-send-modal{background:var(--c-card-bg, #fff);border-radius:8px;width:580px;max-width:95vw;max-height:90vh;display:flex;flex-direction:column;box-shadow:0 8px 32px rgba(0,0,0,.2)}.email-send-modal__header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--c-border, #e0e0e0)}.email-send-modal__header h3{margin:0;font-size:15px}.email-send-modal__close{background:none;border:none;font-size:20px;cursor:pointer;color:var(--c-text-muted, #888);padding:0 4px}.email-send-modal__close:hover{color:var(--c-text, #333)}.email-send-modal__body{padding:16px;overflow-y:auto;flex:1}.email-send-modal__field{margin-bottom:10px}.email-send-modal__field label{display:block;font-size:12px;font-weight:600;margin-bottom:4px;color:var(--c-text-muted, #666)}.email-send-modal__field .input{width:100%}.email-send-modal__actions-top{margin-bottom:10px}.email-send-modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--c-border, #e0e0e0)}.email-send-preview{border:1px solid var(--c-border, #e0e0e0);border-radius:4px;padding:12px;max-height:280px;overflow-y:auto;background:var(--c-bg, #fafafa)}.email-send-preview__subject{font-weight:600;font-size:13px;margin-bottom:8px;padding-bottom:8px;border-bottom:1px solid var(--c-border, #e0e0e0)}.email-send-preview__body{font-size:13px;line-height:1.5}.email-send-preview__body p{margin:0 0 8px}.email-send-preview__attachments{margin-top:8px;padding-top:8px;border-top:1px solid var(--c-border, #e0e0e0);font-size:12px;color:var(--c-text-muted, #666)}.section-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.automation-row{display:flex;align-items:flex-start;gap:8px;padding:10px 12px;background:var(--c-surface, #f8f9fa);border:1px solid var(--c-border, #dee2e6);border-radius:6px}.automation-row__fields{flex:1;display:flex;flex-direction:column;gap:6px}.automation-row__type{max-width:280px}.automation-row__config{display:flex;flex-wrap:wrap;gap:8px}.automation-row__config .form-control{min-width:200px;max-width:300px}.automation-row__remove{flex-shrink:0;margin-top:2px;line-height:1;font-size:16px;padding:2px 8px}.checkbox-group{display:flex;flex-wrap:wrap;gap:4px 16px}.checkbox-label{display:flex;align-items:center;gap:4px;font-size:13px;cursor:pointer;white-space:nowrap}.checkbox-label input[type=checkbox]{margin:0}.automation-actions-cell{white-space:nowrap}.automation-inline-form{display:inline}.automation-history-filters{display:grid;grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));gap:8px;align-items:end}.automation-history-filters .form-field{margin:0}.automation-history-filters .field-label{font-size:12px;margin-bottom:4px}.automation-history-filters .form-control{min-height:34px}.automation-history-filters__actions{display:flex;gap:6px;align-items:center;justify-content:flex-start;padding-bottom:1px}.print-status-badge{display:inline-block;padding:2px 8px;border-radius:3px;font-size:.75rem;font-weight:600;line-height:1.4}.print-status-badge--pending{background-color:#fff3cd;color:#856404}.print-status-badge--completed{background-color:#d4edda;color:#155724}.print-status-badge--failed{background-color:#f8d7da;color:#721c24}.print-queue-filters{display:flex;gap:4px}.print-queue-table td,.print-queue-table th{padding:6px 8px;font-size:.85rem}.print-queue-actions{display:inline-flex;align-items:center;gap:6px}.print-queue-delete-form{margin:0}.btn--outline-primary{background:rgba(0,0,0,0);border:1px solid var(--c-action-primary);color:var(--c-action-primary);cursor:pointer;border-radius:3px;font-size:.75rem;padding:3px 8px;transition:background-color .15s,color .15s}.btn--outline-primary:hover{background-color:var(--c-action-primary);color:#fff}.btn--outline-primary:disabled{opacity:.6;cursor:not-allowed}.btn--outline-primary.is-success{border-color:#28a745;color:#28a745}.shipment-presets{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:16px;margin-bottom:16px}.shipment-presets__btn{display:inline-flex;align-items:center;gap:4px;padding:6px 14px;border:none;border-radius:6px;background:var(--preset-color, #3b82f6);color:#fff;font-size:13px;font-weight:500;cursor:pointer;transition:opacity .15s;line-height:1.4}.shipment-presets__btn:hover{opacity:.85}.shipment-presets__add{display:inline-flex;align-items:center;gap:4px;padding:6px 14px;border:1px dashed #ccc;border-radius:6px;background:rgba(0,0,0,0);color:#666;font-size:13px;cursor:pointer;transition:border-color .15s,color .15s;line-height:1.4}.shipment-presets__add:hover{border-color:#999;color:#444}.preset-modal{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:1000;display:flex;align-items:center;justify-content:center}.preset-modal__content{background:#fff;border-radius:8px;padding:24px;min-width:360px;max-width:420px;box-shadow:0 8px 32px rgba(0,0,0,.2)}.preset-modal__content h3{margin:0 0 4px;font-size:16px}.preset-modal__colors{display:flex;gap:8px;flex-wrap:wrap}.preset-modal__color-swatch{width:28px;height:28px;border-radius:50%;cursor:pointer;border:2px solid rgba(0,0,0,0);transition:border-color .15s}.preset-modal__color-swatch:hover{border-color:#aaa}.preset-modal__color-swatch.is-selected{border-color:#333}.shipment-presets__btn-wrap{position:relative;display:inline-flex}.shipment-presets__btn-wrap:hover .shipment-presets__edit-icon{opacity:1}.shipment-presets__edit-icon{position:absolute;top:-6px;right:-6px;width:18px;height:18px;border-radius:50%;background:#fff;border:1px solid #ddd;font-size:10px;line-height:16px;text-align:center;cursor:pointer;opacity:0;transition:opacity .15s;padding:0;color:#666;z-index:2}.shipment-presets__edit-icon:hover{background:#f3f4f6;border-color:#999}.shipment-presets__dropdown{position:absolute;top:100%;left:0;margin-top:4px;background:#fff;border:1px solid #ddd;border-radius:6px;box-shadow:0 4px 16px rgba(0,0,0,.12);z-index:100;min-width:200px;padding:4px 0}.shipment-presets__dropdown-item{padding:6px 14px;font-size:13px;cursor:pointer;white-space:nowrap}.shipment-presets__dropdown-item:hover{background:#f3f4f6}.shipment-presets__dropdown-item.is-danger{color:#ef4444}.shipment-presets__dropdown-item.is-danger:hover{background:#fef2f2}.delivery-badge{display:inline-block;padding:2px 8px;border-radius:3px;font-size:.8em;font-weight:500;white-space:nowrap}.delivery-badge--unknown{background:#f5f5f5;color:#999}.delivery-badge--created{background:#e3f2fd;color:#1565c0}.delivery-badge--confirmed{background:#bbdefb;color:#0d47a1}.delivery-badge--picked_up{background:#e1f5fe;color:#01579b}.delivery-badge--in_transit{background:#fff3e0;color:#e65100}.delivery-badge--out_for_delivery{background:#ffe0b2;color:#bf360c}.delivery-badge--ready_for_pickup{background:#f3e5f5;color:#6a1b9a}.delivery-badge--delivered{background:#e8f5e9;color:#2e7d32}.delivery-badge--returned{background:#ffebee;color:#c62828}.delivery-badge--cancelled{background:#e0e0e0;color:#616161}.delivery-badge--problem{background:#fff8e1;color:#f57f17}.tracking-link{margin-left:4px;text-decoration:none;font-size:.85em}.delivery-status-swatch{display:inline-block;width:14px;height:14px;border-radius:2px;background:var(--status-color, #6c757d);vertical-align:middle}.delivery-status-system-badge{display:inline-block;padding:1px 6px;border-radius:3px;font-size:.75em;background:#e9ecef;color:#6c757d}.delivery-badge--custom{background:var(--status-color, #6c757d);color:#fff}.dsm-row--custom{background:rgba(59,130,246,.06)}.dsm-raw-status{font-size:.82rem;background:var(--surface-alt, #f1f5f9);padding:2px 6px;border-radius:3px;white-space:nowrap}.dsm-unmapped{border-left:4px solid #f59e0b}.dsm-unmapped .section-title{color:#b45309}.dsm-unmapped table tbody tr{background:rgba(245,158,11,.05)}.global-search{flex:1;max-width:500px;position:relative;margin:0 16px}.global-search__input{width:100%;padding:6px 12px;font-size:13px;border:1px solid var(--c-border);border-radius:4px;background:var(--c-bg);color:var(--c-text);outline:none;transition:border-color .15s}.global-search__input::placeholder{color:var(--c-text-muted, #94a3b8)}.global-search__input:focus{border-color:var(--c-primary, #3b82f6);box-shadow:0 0 0 2px rgba(59,130,246,.15)}.global-search__results{display:none;position:absolute;top:100%;left:0;right:0;margin-top:4px;background:var(--c-surface, #fff);border:1px solid var(--c-border);border-radius:6px;box-shadow:0 8px 24px rgba(0,0,0,.12);max-height:400px;overflow-y:auto;z-index:1000}.global-search__item{display:block;padding:8px 12px;cursor:pointer;text-decoration:none;color:var(--c-text);border-bottom:1px solid var(--c-border);transition:background-color .1s}.global-search__item:last-child{border-bottom:none}.global-search__item:hover,.global-search__item.is-highlighted{background:var(--c-bg, #f1f5f9)}.global-search__item-title{font-weight:600;font-size:13px;margin-bottom:2px}.global-search__item-details{font-size:11px;color:var(--c-text-muted, #64748b)}.global-search__empty{padding:12px;text-align:center;color:var(--c-text-muted, #94a3b8);font-size:13px}@media(max-width: 768px){.global-search{max-width:none;margin:0 8px}.global-search__input{font-size:12px;padding:5px 8px}}.order-preview-overlay{position:fixed;inset:0;z-index:1000;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;padding:20px}.order-preview-modal{background:var(--c-surface);border:1px solid var(--c-border);border-radius:10px;box-shadow:0 16px 48px rgba(0,0,0,.18);width:100%;max-width:960px;max-height:90vh;display:flex;flex-direction:column}.order-preview-modal__header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--c-border)}.order-preview-modal__title{font-size:18px;font-weight:600;margin:0}.order-preview-modal__close{background:none;border:none;font-size:22px;cursor:pointer;color:var(--c-muted);padding:0 4px;line-height:1}.order-preview-modal__close:hover{color:var(--c-text)}.order-preview-modal__body{padding:20px 24px;overflow-y:auto;flex:1}.order-preview-modal__footer{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:12px 20px;border-top:1px solid var(--c-border)}.order-preview-loading{text-align:center;padding:32px;color:var(--c-muted)}.order-preview-error{text-align:center;padding:32px;color:var(--c-danger, #e53e3e)}.order-preview-section{margin-bottom:14px}.order-preview-section__title{font-size:13px;font-weight:600;text-transform:uppercase;color:var(--c-muted);margin-bottom:8px;letter-spacing:.04em}.order-preview-kv{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;font-size:14px}.order-preview-kv dt{color:var(--c-muted);white-space:nowrap}.order-preview-kv dd{margin:0;display:flex;align-items:center;gap:4px}.order-preview-items{width:100%;font-size:14px;border-collapse:collapse}.order-preview-items th,.order-preview-items td{padding:6px 8px;text-align:left;vertical-align:top}.order-preview-items th{font-weight:600;font-size:12px;text-transform:uppercase;color:var(--c-muted)}.order-preview-items tbody tr+tr{border-top:1px solid var(--c-border)}.order-preview-item-cell{display:flex;align-items:flex-start;gap:8px}.order-preview-item-thumb{width:42px;height:42px;object-fit:cover;border-radius:4px;border:1px solid var(--c-border);flex-shrink:0}.order-preview-item-thumb--empty{background:var(--c-bg, #f5f5f5)}.order-preview-item-info{min-width:0}.order-preview-item-name{font-size:14px;line-height:1.3;word-break:break-word}.order-preview-personalization{margin-top:4px;font-size:12px;color:var(--c-muted);line-height:1.4}.order-preview-personalization__line{white-space:pre-wrap;word-break:break-word}.order-preview-notes{font-size:14px}.order-preview-notes__item{padding:6px 0}.order-preview-notes__item+.order-preview-notes__item{border-top:1px solid var(--c-border)}.order-preview-notes__type{font-size:11px;color:var(--c-muted);margin-bottom:2px}.order-preview-notes__text{white-space:pre-wrap;word-break:break-word}.copy-field__btn{background:none;border:none;cursor:pointer;font-size:13px;color:var(--c-muted);padding:0 2px;line-height:1;opacity:.6;transition:opacity .15s;display:inline-flex;align-items:center;gap:3px}.copy-field__btn:hover{opacity:1;color:var(--c-primary, #4f6ef7)}.copy-field__btn.is-copied{color:#22c55e;opacity:1}.btn-icon.js-order-preview-btn{background:none;border:none;cursor:pointer;font-size:14px;color:var(--c-muted);padding:2px 4px;line-height:1;opacity:.5;transition:opacity .15s;vertical-align:middle;margin-right:4px}.btn-icon.js-order-preview-btn:hover{opacity:1;color:var(--c-primary, #4f6ef7)}.pm-form__row{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap}.pm-form__field{flex:1;min-width:160px}.pm-form__actions{display:flex;align-items:flex-end;padding-bottom:2px}.pm-row--inactive{opacity:.5}.pm-row__actions{white-space:nowrap}.pm-row__actions .btn+.btn{margin-left:4px}.project-badge{display:inline-flex;align-items:center;gap:2px;font-size:10px;line-height:1;padding:1px 4px;border-radius:3px;vertical-align:middle;margin-left:4px}.project-badge--done{color:#16a34a;background:rgba(22,163,74,.1)}.project-badge--partial{color:#d97706;background:rgba(217,119,6,.1);font-weight:600}.project-badge--none{color:#9ca3af;background:rgba(156,163,175,.1)}.item-project-badge{display:inline-block;font-size:10px;padding:1px 6px;border-radius:3px;margin-left:6px;vertical-align:middle}.item-project-badge--done{color:#16a34a;background:rgba(22,163,74,.1)}.item-project-badge--pending{color:#9ca3af;background:rgba(156,163,175,.1)}.pm-modal{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center}.pm-modal__overlay{position:absolute;inset:0;background:rgba(0,0,0,.4)}.pm-modal__content{position:relative;width:100%;max-width:500px;z-index:1}.customer-risk-banner{display:flex;align-items:flex-start;gap:10px;padding:10px 12px;border-radius:6px;background:#fff0f0;border:1px solid #fecaca;border-left:4px solid #d64545;color:#6b1f1f;font-size:13px}.customer-risk-banner__icon{flex-shrink:0;font-size:18px;line-height:1;color:#d64545}.customer-risk-banner__body{flex:1;min-width:0}.customer-risk-banner__text{margin:0;font-weight:600;color:#6b1f1f}.customer-risk-banner__list{margin-top:6px}.customer-risk-banner__list summary{cursor:pointer;color:#9b2c2c;font-size:12px;user-select:none}.customer-risk-banner__table{width:100%;margin-top:6px;font-size:12px;border-collapse:collapse}.customer-risk-banner__table th,.customer-risk-banner__table td{padding:4px 6px;border-bottom:1px solid #f5d6d6;text-align:left;color:#3b0f0f}.customer-risk-banner__table thead th{font-size:11px;text-transform:uppercase;letter-spacing:.02em;color:#7a2323;background:#ffe3e3}.customer-risk-banner__table tbody tr:last-child th,.customer-risk-banner__table tbody tr:last-child td{border-bottom:0}.customer-risk-banner__table a{color:#b91c1c;font-weight:600}.risk-return-badge{display:inline-block;padding:1px 6px;background:#d64545;color:#fff;font-size:11px;font-weight:600;border-radius:3px;margin-left:4px;cursor:default;vertical-align:middle;line-height:1.4}.table-list-table tbody tr.is-risk-return>td:first-child{border-left:3px solid #d64545}*{box-sizing:border-box}html,body{min-height:100%}body{margin:0;font-family:"Roboto","Segoe UI",sans-serif;font-size:13px;color:var(--c-text);background:var(--c-bg)}a{color:var(--c-primary)}.app-shell{min-height:100vh;display:flex}.sidebar{width:260px;min-width:260px;flex-shrink:0;overflow:hidden;transition:width .22s ease,min-width .22s ease;border-right:1px solid #243041;background:#111a28;padding:18px 10px;display:flex;flex-direction:column}.sidebar.is-collapsed{width:52px;min-width:52px;padding:18px 0}.sidebar.is-collapsed .sidebar__brand-text{display:none}.sidebar.is-collapsed .sidebar__brand{justify-content:center;margin:4px 0 16px}.sidebar.is-collapsed .sidebar__label{display:none}.sidebar.is-collapsed .sidebar__toggle-arrow{display:none}.sidebar.is-collapsed .sidebar__link,.sidebar.is-collapsed .sidebar__group-toggle{justify-content:center;padding:9px;border-radius:8px;margin:0 6px}.sidebar.is-collapsed .sidebar__group-links{display:none}.sidebar.is-collapsed .sidebar__icon{margin:0}.sidebar__brand{display:flex;align-items:center;justify-content:space-between;margin:4px 4px 16px;gap:6px;min-width:0}.sidebar__brand-text{color:#e9f0ff;font-size:24px;font-weight:300;letter-spacing:-0.02em;white-space:nowrap;overflow:hidden;flex:1;min-width:0}.sidebar__brand-text strong{font-weight:700}.sidebar__collapse-btn{flex-shrink:0;width:28px;height:28px;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0);border:1px solid #2a3a54;border-radius:6px;color:#64748b;cursor:pointer;padding:0;transition:background .15s,color .15s}.sidebar__collapse-btn:hover{background:#1b2a3f;color:#cbd5e1}.sidebar__collapse-icon{display:block;transition:transform .22s ease;flex-shrink:0}.sidebar.is-collapsed .sidebar__collapse-icon{transform:rotate(180deg)}.sidebar__nav{display:grid;gap:4px}.sidebar__link{display:flex;align-items:center;gap:9px;white-space:nowrap;border-radius:8px;padding:9px 10px;text-decoration:none;color:#cbd5e1;font-weight:600}.sidebar__link:hover{color:#f8fafc;background:#1b2a3f}.sidebar__link.is-active{color:#fff;background:#2e4f93}.sidebar__group{display:grid;gap:2px}.sidebar__group-toggle{list-style:none;border-radius:8px;padding:9px 10px;color:#cbd5e1;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:9px;white-space:nowrap;user-select:none}.sidebar__group-toggle::-webkit-details-marker{display:none}.sidebar__group:hover .sidebar__group-toggle,.sidebar__group-toggle:hover{color:#f8fafc;background:#1b2a3f}.sidebar__group.is-active .sidebar__group-toggle{color:#fff;background:#2e4f93}.sidebar__icon{flex-shrink:0;width:18px;height:18px;display:flex;align-items:center;justify-content:center;opacity:.85}.sidebar__label{flex:1;min-width:0;overflow:hidden}.sidebar__toggle-arrow{flex-shrink:0;margin-left:auto;opacity:.5;transition:transform .18s ease}details[open]>.sidebar__group-toggle .sidebar__toggle-arrow{transform:rotate(180deg)}.sidebar__group-links{display:grid;gap:2px;padding-left:12px;overflow:hidden}.sidebar__sublink{border-radius:6px;padding:7px 10px 7px 8px;text-decoration:none;color:#94a3b8;font-size:12.5px;font-weight:500;display:flex;align-items:center;gap:8px;white-space:nowrap}.sidebar__sublink::before{content:"";flex-shrink:0;width:5px;height:5px;border-radius:50%;background:rgba(148,163,184,.3);transition:background .15s}.sidebar__sublink:hover{color:#e2e8f0;background:#1b2a3f}.sidebar__sublink:hover::before{background:rgba(148,163,184,.65)}.sidebar__sublink.is-active{color:#fff;background:rgba(46,79,147,.55)}.sidebar__sublink.is-active::before{background:#93c5fd}.sidebar__badge{margin-left:auto;background:#f59e0b;color:#1f2937;font-size:10.5px;font-weight:700;line-height:1;padding:2px 6px;border-radius:10px;min-width:18px;text-align:center}.app-main{flex:1;min-width:0}.topbar{height:50px;border-bottom:1px solid var(--c-border);background:var(--c-surface);display:flex;align-items:center;justify-content:space-between;padding:0 20px;position:sticky;top:0;z-index:100}.brand{font-size:22px;font-weight:300;letter-spacing:-0.02em;color:var(--c-text-strong)}.brand strong{font-weight:700}.container{max-width:none;width:calc(100% - 20px);margin:12px 10px;padding:0 4px 14px}.card{background:var(--c-surface);border-radius:10px;box-shadow:var(--shadow-card);padding:14px}.card h1{margin:0 0 10px;color:var(--c-text-strong);font-size:24px;font-weight:700}.muted{color:var(--c-muted)}.accent{color:var(--c-primary);font-weight:600}.users-form{display:grid;gap:14px;max-width:460px}.form-field{margin-bottom:12px}.section-title{margin:0;color:var(--c-text-strong);font-size:18px;font-weight:700}h2.section-title,h3.section-title,h4.section-title{display:flex;align-items:center;gap:6px;font-weight:600;padding:6px 0;margin-bottom:8px;border-bottom:1px solid #e2e8f0;color:var(--c-primary, #2563eb)}h2.section-title::before,h3.section-title::before,h4.section-title::before{content:"■";font-size:.55em;opacity:.5}h3.section-title,h4.section-title{font-size:15px}h3.section-title::before,h4.section-title::before{content:"◆";font-size:.5em}.mt-0{margin-top:0}.mt-4{margin-top:4px}.mt-12{margin-top:8px}.mt-16{margin-top:12px}.settings-grid{display:grid;grid-template-columns:repeat(3, minmax(0, 1fr));gap:12px}.settings-nav{display:flex;gap:8px;flex-wrap:wrap}.settings-nav__link{text-decoration:none;border:1px solid var(--c-border);border-radius:8px;padding:8px 12px;color:var(--c-text-strong);font-weight:600}.settings-nav__link:hover{background:#f8fafc}.settings-nav__link.is-active{border-color:var(--c-primary);color:var(--c-primary);background:#edf2ff}.settings-stat{border:1px solid var(--c-border);border-radius:8px;padding:12px;background:#f8fafc}.settings-stat__label{display:block;color:var(--c-muted);font-size:12px;margin-bottom:4px}.settings-stat__value{color:var(--c-text-strong);font-size:20px}.settings-logs{margin:0;padding:12px;border-radius:8px;border:1px solid var(--c-border);background:#0b1220;color:#d1d5db;font-size:12px;line-height:1.5;overflow:auto}.settings-allegro-callback{display:block;width:100%;padding:8px 10px;border:1px solid var(--c-border);border-radius:8px;background:#f8fafc;color:var(--c-text-strong);font-size:12px;line-height:1.45;word-break:break-all}.page-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.filters-grid{display:grid;grid-template-columns:repeat(3, minmax(0, 1fr));gap:12px}.filters-actions{display:flex;align-items:center;gap:8px}.product-form .form-control{width:100%}.form-grid{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:12px}.form-grid-2{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:12px;align-items:start}.form-grid-3{display:grid;grid-template-columns:repeat(3, minmax(0, 1fr));gap:12px;align-items:start}.form-grid-4{display:grid;grid-template-columns:repeat(4, minmax(0, 1fr));gap:12px;align-items:start}.form-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:flex-start}.form-actions .btn{align-self:flex-start}.statuses-form{display:grid;gap:8px;grid-template-columns:repeat(2, minmax(0, 1fr))}.statuses-form .form-actions{grid-column:1/-1}.statuses-color-input{min-height:32px;padding:2px}.statuses-hint{grid-column:1/-1;margin:0}.statuses-group-block{border:1px solid var(--c-border);border-radius:10px;padding:8px;background:#fbfdff}.statuses-group-block__head{display:flex;align-items:center;justify-content:space-between;gap:6px;flex-wrap:wrap}.statuses-group-block__title{margin:0;display:inline-flex;align-items:center;gap:6px;color:var(--c-text-strong);font-size:14px}.statuses-color-dot{width:12px;height:12px;border-radius:999px;border:1px solid rgba(15,23,42,.15)}.statuses-dnd-list{margin:6px 0 0;padding:0;list-style:none;display:grid;gap:6px}.statuses-dnd-item{display:grid;grid-template-columns:24px 1fr;gap:6px;border:1px solid #dce4f0;border-radius:8px;background:#fff;padding:6px}.statuses-dnd-item__content{display:flex;align-items:center;gap:6px;min-width:0}.statuses-dnd-item.is-dragging{opacity:.6}.statuses-dnd-item__drag{display:inline-flex;align-items:center;justify-content:center;border:1px dashed #cbd5e1;border-radius:6px;color:#64748b;cursor:grab;user-select:none;font-weight:700;font-size:12px}.statuses-dnd-item__drag:active{cursor:grabbing}.statuses-inline-form{display:grid;gap:6px}.statuses-inline-form--row{grid-template-columns:minmax(180px, 1.4fr) minmax(150px, 1fr) auto auto auto;align-items:center;flex:1 1 auto;min-width:0}.statuses-inline-form--row-group{grid-template-columns:minmax(180px, 1.5fr) 56px auto auto auto;align-items:center;flex:1 1 auto;min-width:0}.statuses-inline-form--row .form-control,.statuses-inline-form--row-group .form-control{min-height:30px;padding:4px 8px}.statuses-inline-form--row .btn,.statuses-inline-form--row-group .btn,.statuses-inline-delete .btn{min-height:30px;padding:4px 10px;font-size:12px}.statuses-inline-check{margin-top:0;white-space:nowrap;font-size:12px}.statuses-inline-delete{margin:0;flex:0 0 auto}.statuses-code-label{font-size:12px;color:var(--c-muted)}.statuses-code-readonly{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;font-size:12px}.statuses-code-readonly code{background:#eef2f7;border-radius:6px;padding:1px 6px;color:#1f2937;font-size:12px}.field-inline{display:flex;align-items:center;gap:8px;margin-top:2px}.modal-backdrop{position:fixed;inset:0;background:rgba(15,23,42,.5);display:flex;align-items:center;justify-content:center;padding:16px;z-index:200}.modal-backdrop[hidden]{display:none}.modal{width:min(560px,100%);background:#fff;border-radius:10px;box-shadow:0 20px 40px rgba(15,23,42,.35);overflow:hidden}.modal__header{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:16px 18px;border-bottom:1px solid var(--c-border)}.modal__header h3{margin:0;font-size:18px;color:var(--c-text-strong)}.modal__body{padding:16px 18px 18px}.status-pill{display:inline-flex;align-items:center;justify-content:center;border:1px solid #fed7d7;background:#fff5f5;color:#9b2c2c;padding:2px 8px;border-radius:999px;font-size:12px;font-weight:600}.status-pill.is-active{border-color:#b7ebcf;background:#f0fff6;color:#0f6b39}.table-row-actions{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}.table-row-actions form{margin:0}.table-list{display:grid;gap:14px}.table-list__header{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}.table-list__left{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}.table-list-header-actions{display:inline-flex;align-items:center;gap:10px;flex-wrap:wrap}.js-filter-toggle-btn.is-active{border-color:#cbd5e0;background:#edf2ff;color:var(--c-primary-dark)}.table-filter-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;font-size:11px;font-weight:700;color:#fff;background:var(--c-primary);border-radius:999px}.table-filters-wrapper{display:none}.table-filters-wrapper.is-open{display:block}.table-list-filters{display:grid;gap:12px;grid-template-columns:repeat(auto-fit, minmax(170px, 1fr));align-items:end}.table-col-toggle-wrapper{position:relative}.table-col-toggle-dropdown{display:none;position:absolute;right:0;top:calc(100% + 6px);z-index:30;width:260px;max-height:360px;overflow:auto;border:1px solid var(--c-border);border-radius:10px;background:#fff;box-shadow:0 10px 25px rgba(15,23,42,.12)}.table-col-toggle-dropdown.is-open{display:block}.table-col-toggle-header{padding:10px 12px;border-bottom:1px solid var(--c-border);font-size:12px;font-weight:700;color:var(--c-muted)}.table-col-toggle-item{display:flex;align-items:center;gap:10px;padding:8px 12px;font-size:13px;color:var(--c-text-strong)}.table-col-toggle-item:hover{background:#f8fafc}.table-col-toggle-footer{border-top:1px solid var(--c-border);padding:8px 12px}.table-col-hidden{display:none}.table-col-switch{position:relative;display:inline-block;width:34px;min-width:34px;height:18px}.table-col-switch input{opacity:0;width:0;height:0;position:absolute}.table-col-switch-slider{position:absolute;top:0;left:0;right:0;bottom:0;background:#cbd5e1;border-radius:999px;transition:background-color .2s ease}.table-col-switch-slider::before{content:"";position:absolute;height:14px;width:14px;left:2px;bottom:2px;background:#fff;border-radius:50%;transition:transform .2s ease}.table-col-switch input:checked+.table-col-switch-slider{background:#16a34a}.table-col-switch input:checked+.table-col-switch-slider::before{transform:translateX(16px)}.table-sort-link{display:inline-flex;align-items:center;gap:6px;color:var(--c-text-strong);text-decoration:none}.table-sort-link:hover{color:var(--c-primary-dark)}.table-sort-icon.is-muted{color:#a0aec0}.table-list__footer{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}.table-list-per-page-form{display:inline-flex;align-items:center;gap:8px}.table-list-per-page-form .form-control{min-width:90px}.table-select-col{width:44px;text-align:center}.table-select-toggle{display:inline-flex;align-items:center;justify-content:center}.table-select-toggle input[type=checkbox]{width:16px;height:16px}.orders-page .orders-head{background:linear-gradient(120deg, #f8fbff 0%, #eef5ff 100%);border:1px solid #dbe7fb}.orders-page .table-list{border:1px solid #dde5f2;border-radius:12px;box-shadow:0 6px 16px rgba(20,44,86,.08)}.orders-page .table-list__header{padding:10px 6px 2px}.orders-page .table-list-filters{padding:6px 6px 2px;border-top:1px solid #ebf0f7;border-bottom:1px solid #ebf0f7;background:#f9fbff}.orders-page .table-wrap{border-radius:10px;overflow:hidden;border:1px solid #e7edf6}.orders-page .table thead th{background:#f3f7fd;color:#30435f;font-size:12px;text-transform:uppercase;letter-spacing:.03em}.orders-page .table tbody td{vertical-align:middle;padding-top:10px;padding-bottom:10px;border-bottom-color:#edf2f8}.orders-page .table tbody tr:hover td{background:#f9fcff}.orders-list-page{padding:10px;margin-bottom:10px}.statistics-orders-page{padding:10px}.statistics-orders-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}.statistics-orders-filters{display:grid;grid-template-columns:repeat(auto-fit, minmax(170px, 1fr));gap:10px;align-items:end}.statistics-orders-filters__actions{align-self:end}.statistics-orders-multiselect{min-height:120px;height:120px;padding-top:6px;padding-bottom:6px}.checkbox-multiselect{position:relative;width:100%}.checkbox-multiselect select[data-checkbox-multiselect-enhanced]{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}.checkbox-multiselect__trigger{width:100%;min-height:30px;display:flex;align-items:center;justify-content:space-between;gap:8px;border:1px solid var(--c-border);border-radius:6px;padding:4px 8px;font:inherit;color:var(--c-text-strong);background:#fff;cursor:pointer;text-align:left;transition:border-color .2s ease,box-shadow .2s ease}.checkbox-multiselect__value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.checkbox-multiselect__arrow{flex:0 0 auto;width:7px;height:7px;border-right:1.5px solid #64748b;border-bottom:1.5px solid #64748b;transform:rotate(45deg) translateY(-2px)}.checkbox-multiselect__dropdown{display:none;position:absolute;z-index:40;top:calc(100% + 2px);left:0;right:0;max-height:200px;overflow-y:auto;padding:8px 8px 6px;border:1px solid var(--c-primary);border-radius:0 0 6px 6px;background:#fff;box-shadow:0 18px 38px rgba(45,55,72,.16)}.checkbox-multiselect.is-open .checkbox-multiselect__trigger{border-color:var(--c-primary);border-bottom-right-radius:0;border-bottom-left-radius:0;box-shadow:var(--focus-ring)}.checkbox-multiselect.is-open .checkbox-multiselect__dropdown{display:grid;gap:4px}.checkbox-multiselect.is-open .checkbox-multiselect__arrow{transform:rotate(225deg) translate(-2px, -1px)}.checkbox-multiselect__option{display:flex;align-items:center;gap:6px;min-height:20px;color:var(--c-text);font-size:13px;line-height:1.25;cursor:pointer}.checkbox-multiselect__option input{width:17px;height:17px;margin:0;flex:0 0 auto;accent-color:var(--c-primary)}.checkbox-multiselect__option--all{color:var(--c-text-strong);font-weight:700}.statistics-orders-table-wrap{overflow-x:auto}.statistics-orders-table{min-width:880px}.statistics-orders-table thead th{text-align:center;white-space:nowrap}.statistics-orders-table tbody td,.statistics-orders-table tfoot th{text-align:right;white-space:nowrap}.statistics-orders-table tbody td:first-child,.statistics-orders-table tfoot th:first-child{text-align:left}.statistics-orders-table tfoot th{border-top:2px solid #cbd5e1;background:#f8fafc}.statistics-summary-page{padding:10px}.statistics-summary-section{display:grid;gap:12px}.statistics-summary-chart-grid,.statistics-summary-table-grid{display:grid;gap:12px}@media(min-width: 1100px){.statistics-summary-chart-grid,.statistics-summary-table-grid{grid-template-columns:repeat(2, minmax(0, 1fr));align-items:start}}.statistics-summary-card{padding:10px}.statistics-summary-card__head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px}.statistics-summary-chart{position:relative;height:320px}.statistics-summary-chart canvas{display:block;width:100%;height:100%;border:1px solid #e2e8f0;border-radius:6px;background:#fff}.statistics-summary-fallback{margin-top:0}.statistics-summary-table{min-width:640px}.statistics-summary-table th,.statistics-summary-table td{white-space:nowrap;text-align:right}.statistics-summary-table th:first-child,.statistics-summary-table td:first-child{text-align:left}.orders-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}.orders-stats{display:inline-grid;grid-template-columns:repeat(3, minmax(86px, auto));gap:8px}.orders-stat{border:1px solid #d8e2f0;background:#f8fbff;border-radius:8px;padding:6px 8px;line-height:1.15}.orders-stat__label{display:block;color:#5f6f83;font-size:11px;margin-bottom:2px}.orders-stat__value{color:#12233a;font-size:16px;font-weight:700}.orders-ref{display:grid;gap:2px;min-width:170px}.orders-ref__main{font-weight:700;color:#0f1f35;font-size:14px}.orders-ref__meta{display:inline-flex;flex-wrap:wrap;gap:4px 10px;color:#64748b;font-size:12px}.orders-buyer{display:grid;gap:2px}.orders-buyer__name{color:#0f172a;font-weight:600;font-size:14px}.orders-buyer__meta{display:inline-flex;flex-wrap:wrap;gap:4px 10px;color:#64748b;font-size:12px}.orders-status-wrap{display:inline-flex;align-items:center;gap:5px;flex-wrap:wrap;cursor:pointer}.orders-status-wrap .order-tag{cursor:pointer}.orders-status-dropdown{position:fixed;z-index:9999;min-width:180px;max-height:280px;overflow-y:auto;background:#fff;border:1px solid #d8e1ef;border-radius:6px;box-shadow:0 4px 16px rgba(0,0,0,.12);padding:4px 0}.orders-status-dropdown__group-header{padding:6px 12px 2px;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:#94a3b8}.orders-status-dropdown__group-header:not(:first-child){border-top:1px solid #f1f5f9;margin-top:2px;padding-top:8px}.orders-status-dropdown__item{display:flex;align-items:center;gap:8px;padding:5px 12px;font-size:13px;color:#334155;cursor:pointer;white-space:nowrap}.orders-status-dropdown__item:hover{background:#f1f5f9}.orders-status-dropdown__item.is-current{font-weight:700;background:#f8fafc}.orders-status-dropdown__color-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}.order-tag{display:inline-flex;align-items:center;justify-content:center;border:1px solid #d8e1ef;background:#f8fafc;color:#334155;border-radius:999px;padding:2px 8px;font-size:12px;font-weight:700;line-height:1.1;white-space:nowrap}.order-tag.is-info{border-color:#bfdbfe;background:#eff6ff;color:#1d4ed8}.order-tag.is-success{border-color:#bbf7d0;background:#f0fdf4;color:#166534}.order-tag.is-danger{border-color:#fecaca;background:#fef2f2;color:#b91c1c}.order-tag.is-warn{border-color:#fde68a;background:#fffbeb;color:#92400e}.order-tag.is-cod{border-color:#f9a8d4;background:#fdf2f8;color:#9d174d}.order-tag.is-unpaid{border-color:#fca5a5;background:#fef2f2;color:#b91c1c}.orders-mini{font-size:14px;color:#223247;line-height:1.25}.orders-mini__delivery{font-size:12px;color:#64748b;margin-bottom:2px;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.orders-products{display:grid;gap:4px;min-width:240px}.orders-products__meta,.orders-products__more{font-size:12px;color:#64748b}.orders-product{display:grid;grid-template-columns:48px 1fr;gap:6px;align-items:center}.orders-product__thumb{width:48px;height:48px;border-radius:4px;border:1px solid #dbe3ef;object-fit:cover;background:#fff}.orders-product__thumb--empty{display:inline-block;background:#eef2f7;border-style:dashed}.orders-product__txt{min-width:0;display:grid;gap:1px}.orders-product__name{font-size:14px;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.orders-product__qty{font-size:12px;color:#64748b}.orders-image-hover-wrap{position:relative;display:inline-flex;align-items:center;justify-content:center;cursor:zoom-in}.orders-image-hover-popup{display:none;position:fixed;left:auto;top:auto;width:350px;max-height:350px;object-fit:contain;border-radius:8px;background:#fff;box-shadow:0 8px 24px rgba(0,0,0,.18);border:1px solid #dfe3ea;z-index:100;pointer-events:none}.orders-image-hover-wrap:hover .orders-image-hover-popup{display:block}.activity-type-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:12px;font-weight:500;white-space:nowrap;background:#e2e8f0;color:#334155}.activity-type-badge--status_change{background:#dbeafe;color:#1e40af}.activity-type-badge--payment{background:#dcfce7;color:#166534}.activity-type-badge--invoice{background:#fef3c7;color:#92400e}.activity-type-badge--shipment{background:#e0e7ff;color:#3730a3}.activity-type-badge--message{background:#f3e8ff;color:#6b21a8}.activity-type-badge--document{background:#fce7f3;color:#9d174d}.activity-type-badge--import{background:#f1f5f9;color:#475569}.activity-type-badge--note{background:#ecfdf5;color:#065f46}.text-nowrap{white-space:nowrap}.orders-money{display:grid;gap:2px}.orders-money__main{color:#0f172a;font-weight:700;font-size:14px}.orders-money__meta{color:#64748b;font-size:12px}.table-list[data-table-list-id=orders]{gap:8px}.table-list[data-table-list-id=orders] .table-list__header{padding:2px 0 0}.table-list[data-table-list-id=orders] .table-list-filters{gap:8px;grid-template-columns:repeat(auto-fit, minmax(150px, 1fr))}.table-list[data-table-list-id=orders] .table th,.table-list[data-table-list-id=orders] .table td{padding:6px 8px}.table-list[data-table-list-id=orders] .table thead th{font-size:12px;text-transform:uppercase;letter-spacing:.02em;white-space:nowrap}.table-list[data-table-list-id=orders] .table tbody td{vertical-align:top;font-size:14px;line-height:1.25}.order-show-layout{display:grid;grid-template-columns:220px minmax(0, 1fr);gap:12px;align-items:start}.order-statuses-side{position:sticky;top:60px;padding:10px}.order-statuses-side__title{font-size:13px;font-weight:700;color:#0f172a;margin-bottom:8px;display:flex;align-items:center;justify-content:space-between;list-style:none}.order-statuses-side__title::-webkit-details-marker{display:none}.order-statuses-side__arrow{display:none;flex-shrink:0;opacity:.5;transition:transform .2s ease}details[open]>.order-statuses-side__title .order-statuses-side__arrow{transform:rotate(180deg)}.order-status-group{margin-bottom:10px}.order-status-group__name{display:flex;align-items:center;justify-content:space-between;gap:6px;font-size:12px;color:#475569;font-weight:700;margin-bottom:5px;text-decoration:none;padding:3px 6px;border-radius:6px;border-left:3px solid rgba(0,0,0,0);cursor:pointer;transition:background .15s}.order-status-group__name:hover{background:#f1f5f9}.order-status-group__count{min-width:24px;text-align:center;border-radius:999px;background:var(--group-color, #64748b);padding:1px 6px;font-weight:700;font-size:11px;color:#fff}.order-status-group.is-active>.order-status-group__name{background:rgba(15,23,42,.06);color:#0f172a;border-left-color:var(--group-color, #64748b)}.order-status-row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:4px 6px;border-radius:6px;color:#334155;font-size:12px;text-decoration:none}.order-status-row__count{min-width:24px;text-align:center;border-radius:999px;background:var(--status-color, #64748b);padding:1px 6px;font-weight:700;font-size:11px;color:#fff}.order-status-row:hover{background:#f1f5f9}.order-status-row.is-active{background:rgba(15,23,42,.06);color:#0f172a;font-weight:700}.order-show-main{min-width:0}.order-details-actions{display:inline-flex;flex-wrap:wrap;justify-content:flex-end;gap:6px}.order-details-page{padding:12px}.order-details-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}.order-back-link{color:#475569;text-decoration:none;font-weight:600}.order-back-link:hover{color:#1d4ed8}.order-details-sub{display:inline-flex;gap:10px;flex-wrap:wrap;color:#64748b;font-size:12px}.order-details-pill{border-radius:999px;padding:5px 10px;background:#eef6ff;border:1px solid #cfe2ff;color:#1d4ed8;font-size:12px;font-weight:700}.order-status-change{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.order-status-change__form{display:flex;align-items:center;gap:6px}.order-status-change__select{min-width:180px}.order-details-tabs{display:flex;gap:6px;flex-wrap:wrap}.order-details-tab{border:1px solid #d6deea;border-radius:8px;padding:5px 10px;color:#475569;font-size:12px;background:#f8fafc;cursor:pointer}.order-details-tab.is-active{border-color:#bfdbfe;color:#1d4ed8;background:#eff6ff;font-weight:700}.order-item-cell{display:grid;grid-template-columns:44px 1fr;gap:8px;align-items:center;min-width:260px}.order-item-thumb{width:44px;height:44px;border-radius:6px;border:1px solid #dbe3ef;object-fit:cover}.order-item-thumb--empty{display:inline-block;background:#eef2f7;border-style:dashed}.order-item-name{font-weight:600;color:#0f172a}.item-personalization{margin-top:4px;padding:4px 8px;background:#f8fafc;border-left:2px solid #cbd5e1;border-radius:2px;font-size:.92em;color:#475569;line-height:1.4}.item-personalization__label{font-weight:600;color:#64748b;display:block;margin-bottom:2px}.item-personalization__line{white-space:pre-wrap;word-break:break-word}.order-grid-2{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:12px}.order-grid-3{display:grid;grid-template-columns:repeat(3, minmax(0, 1fr));gap:12px}.order-kv{margin:0;display:grid;grid-template-columns:150px 1fr;gap:6px 10px;font-size:12px}.order-payment-shipping .section-title-row{display:flex;align-items:center;justify-content:space-between;gap:8px}.order-payment-shipping .btn-edit-inline{background:rgba(0,0,0,0);border:1px solid rgba(0,0,0,0);color:#6b7280;padding:3px 5px;cursor:pointer;border-radius:4px;display:inline-flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s,background-color .15s,color .15s}.order-payment-shipping .btn-edit-inline:hover{background:#f3f4f6;color:#111827}.order-payment-shipping:hover .btn-edit-inline{opacity:1}.order-details-edit-form{margin-top:12px;padding:10px;background:#f9fafb;border:1px solid #e5e7eb;border-radius:6px;font-size:12px}.order-details-edit-form .form-row{margin-bottom:8px}.order-details-edit-form label{display:block;color:#374151;font-weight:500}.order-details-edit-form label input[type=text]{display:block;width:100%;margin-top:3px;padding:5px 7px;border:1px solid #d1d5db;border-radius:4px;font-size:12px;box-sizing:border-box}.order-details-edit-form label.checkbox-inline{display:flex;align-items:center;gap:6px;font-weight:400}.order-details-edit-form label.checkbox-inline input{margin:0}.order-details-edit-form label.checkbox-inline code{background:#eef2ff;padding:1px 4px;border-radius:3px;font-size:11px}.order-details-edit-form .form-actions{display:flex;gap:6px;margin-top:8px}.payment-summary{display:grid;gap:6px;max-width:420px}.payment-summary__row{display:flex;align-items:center;gap:10px;font-size:12px}.payment-summary__label{width:150px;flex-shrink:0;color:#64748b}.payment-summary__value{font-weight:600;color:#0f172a}.payment-add-form{background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;padding:12px;max-width:700px}.payment-add-form__row{display:flex;flex-wrap:wrap;gap:10px}.payment-add-form__field{display:flex;flex-direction:column;gap:3px;flex:1 1 140px;min-width:120px}.payment-add-form__field label{font-size:11px;color:#64748b;font-weight:500}.payment-add-form__field input,.payment-add-form__field select{font-size:12px;padding:4px 8px;border:1px solid #cbd5e1;border-radius:4px;height:30px}.payment-add-form__actions{display:flex;gap:8px;margin-top:12px}.order-kv dt{color:#64748b}.order-kv dd{margin:0;color:#0f172a;font-weight:600}.order-address{display:grid;gap:3px;font-size:12px;color:#0f172a}.order-events{display:grid;gap:8px}.order-event{border:1px solid #e2e8f0;border-radius:8px;padding:8px;background:#fbfdff}.order-event__head{color:#64748b;font-size:11px}.order-event__body{margin-top:4px;color:#0f172a;font-size:12px}.order-tab-panel{display:none}.order-tab-panel.is-active{display:block}.manual-tracking-form{display:flex;gap:8px;align-items:center}.manual-tracking-form .form-control{max-width:220px}.order-empty-placeholder{border:1px dashed #cbd5e1;border-radius:8px;min-height:180px;background:#f8fafc}.order-status-badge{display:inline-flex;align-items:center;justify-content:center;padding:4px 10px;border-radius:999px;font-size:12px;font-weight:700;border:1px solid #cbd5e1;color:#334155;background:#f8fafc}.order-status-badge.is-info{border-color:#bfdbfe;background:#eff6ff;color:#1d4ed8}.order-status-badge.is-success{border-color:#bbf7d0;background:#f0fdf4;color:#166534}.order-status-badge.is-danger{border-color:#fecaca;background:#fef2f2;color:#b91c1c}.order-status-badge.is-warn{border-color:#fde68a;background:#fffbeb;color:#92400e}.order-status-badge.is-empty{color:#94a3b8}.order-buyer{display:grid;gap:2px}.order-buyer__name{color:#0f172a;font-weight:600}.order-buyer__email{color:#64748b;font-size:12px}.table-inline-action{display:inline-block;margin-right:6px}.product-name-cell{display:inline-flex;align-items:center;gap:10px}.product-name-thumb{width:60px;height:60px;border-radius:6px;object-fit:cover;border:1px solid var(--c-border);background:#f8fafc}.product-name-thumb--empty{display:inline-block;width:60px;height:60px;border-radius:6px;border:1px dashed #cbd5e0;background:#f8fafc}.product-name-thumb-btn{border:0;padding:0;background:rgba(0,0,0,0);cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.product-name-thumb-btn:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:8px}.modal--image-preview{width:min(760px,100%)}.product-image-preview__img{display:block;width:100%;max-height:70vh;object-fit:contain;border-radius:8px;background:#f8fafc}.product-images-grid{display:grid;grid-template-columns:repeat(auto-fill, minmax(220px, 1fr));gap:12px}.product-image-card{border:1px solid #dfe3ea;border-radius:10px;padding:10px;background:#fff}.product-image-card__thumb-wrap{position:relative;border-radius:8px;overflow:hidden;background:#f2f5f8}.product-image-card__thumb{width:100%;height:160px;object-fit:cover;display:block}.product-image-card__thumb.is-empty{height:160px;display:grid;place-items:center;color:#6b7785;font-size:12px}.product-image-card__badge{display:none;position:absolute;top:8px;left:8px;background:#1f7a43;color:#fff;padding:3px 8px;border-radius:999px;font-size:11px}.product-image-card.is-main .product-image-card__badge{display:inline-block}.product-image-card__meta{margin-top:8px;font-size:11px;line-height:1.25;color:#5f6b79;overflow-wrap:anywhere}.product-image-card__actions{margin-top:10px;display:grid;grid-template-columns:1fr;gap:8px}.product-image-card__actions .btn{min-height:34px;font-size:12px;line-height:1.2;padding:6px 10px}.product-links-search-form{display:grid;gap:12px;grid-template-columns:minmax(220px, 320px) minmax(220px, 1fr) auto;align-items:end}.product-links-head{display:grid;gap:8px;grid-template-columns:repeat(3, minmax(0, 1fr))}.product-tabs-nav{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.product-links-inline-form{display:grid;gap:8px;grid-template-columns:minmax(140px, 1fr) minmax(140px, 1fr) auto;align-items:center}.product-links-actions-row{display:flex;align-items:center;gap:8px;flex-wrap:nowrap}.product-links-actions-row .product-links-relink-form{flex:1 1 auto}.product-links-unlink-form{margin:0;flex:0 0 auto}.product-link-status-cell{display:inline-flex;align-items:center;gap:6px}.product-link-alert-indicator{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:999px;border:1px solid #f59e0b;background:#fffbeb;color:#b45309;font-size:12px;font-weight:700;cursor:help}.product-link-events-list{margin:0;padding:0;list-style:none;display:grid;gap:4px}.product-link-events-list li{display:grid;gap:2px}.product-link-events-type{font-weight:600;color:var(--c-text-strong)}.product-link-events-date{color:var(--c-muted);font-size:12px}.product-show-images-grid{display:grid;grid-template-columns:repeat(auto-fill, minmax(220px, 1fr));gap:12px}.product-show-image-card{border:1px solid var(--c-border);border-radius:10px;background:#fff;padding:10px;overflow:hidden}.product-show-image-card__meta{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;min-width:0}.product-show-image-path{font-size:12px;min-width:0;overflow:hidden}.product-show-image-path summary{cursor:pointer;color:var(--c-muted, #888);list-style:none;user-select:none;white-space:nowrap}.product-show-image-path summary::-webkit-details-marker{display:none}.product-show-image-path summary::after{content:" ▾"}.product-show-image-path[open] summary::after{content:" ▴"}.product-show-image-path__url{margin-top:4px;word-break:break-all;overflow-wrap:break-word;font-size:11px}.product-show-image{width:100%;max-height:260px;object-fit:cover;border-radius:8px;border:1px solid #d9e0ea}.shipment-grid{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:12px}.searchable-select{position:relative}.searchable-select__trigger{display:flex;align-items:center;justify-content:space-between;cursor:pointer;user-select:none;min-height:34px}.searchable-select__trigger::after{content:"";width:0;height:0;border-left:4px solid rgba(0,0,0,0);border-right:4px solid rgba(0,0,0,0);border-top:5px solid var(--c-text-muted, #6b7280);margin-left:8px;flex-shrink:0}.searchable-select__trigger--placeholder{color:var(--c-text-muted, #6b7280)}.searchable-select__dropdown{display:none;position:absolute;left:0;right:0;top:100%;z-index:50;max-height:280px;overflow:auto;background:#fff;border:1px solid var(--c-border);border-top:0;border-radius:0 0 8px 8px;box-shadow:0 8px 20px rgba(15,23,42,.12)}.searchable-select__dropdown.is-open{display:block}.searchable-select__search{position:sticky;top:0;border:none !important;border-bottom:1px solid var(--c-border) !important;border-radius:0 !important;box-shadow:none !important;font-size:13px;background:#fff;z-index:1}.searchable-select__option{padding:7px 10px;font-size:13px;cursor:pointer;color:var(--c-text-strong)}.searchable-select__option:hover{background:#f1f5f9}.searchable-select__option.is-selected{background:#edf2ff;font-weight:600}.flash{padding:10px 14px;border-radius:8px;font-size:13px;font-weight:500}.flash--success{background:#f0fdf4;border:1px solid #bbf7d0;color:#166534}.flash--error{background:#fef2f2;border:1px solid #fecaca;color:#b91c1c}.content-tabs-card{margin-top:0}.content-tabs-nav{display:flex;gap:4px;border-bottom:2px solid var(--c-border);margin-bottom:16px;flex-wrap:wrap}.content-tab-btn{padding:8px 16px;border:none;background:none;cursor:pointer;font-size:14px;font-weight:500;color:var(--c-text-muted, #6b7280);border-bottom:2px solid rgba(0,0,0,0);margin-bottom:-2px;border-radius:4px 4px 0 0;transition:color .15s,border-color .15s}.content-tab-btn:hover{color:var(--c-text-strong, #111827)}.content-tab-btn.is-active{color:var(--c-primary, #2563eb);border-bottom-color:var(--c-primary, #2563eb)}.content-tab-panel{display:none}.content-tab-panel.is-active{display:block}.shoppro-tabs-toolbar{display:flex;align-items:flex-end;justify-content:space-between;gap:10px;margin-bottom:10px;flex-wrap:wrap}.shoppro-tabs-toolbar__field{margin:0;min-width:260px;max-width:420px;flex:1 1 320px}.shoppro-tabs-toolbar__field .form-control{width:100%}.shoppro-tabs-toolbar__actions{display:inline-flex;align-items:center;gap:8px}.dm-carrier-select{min-width:140px}.dm-service-wrap{min-width:200px}.dm-service-wrap .dm-inpost-panel .form-control,.dm-service-wrap .dm-apaczka-panel .form-control{width:100%}.integration-settings-group{grid-column:1/-1;border:1px solid var(--c-border);border-radius:10px;background:#f8fbff;padding:10px}.integration-settings-group__head{margin-bottom:8px;padding:4px 0;border-bottom:1px solid #e2e8f0}.integration-settings-group__title{margin:0;font-size:14px;font-weight:600;letter-spacing:.01em;color:var(--c-text-strong, #1e293b)}.integration-settings-group__desc{margin:4px 0 0;color:#4b5563}.integration-settings-group__grid{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:10px 12px;align-items:start}.integration-settings-group__full{grid-column:1/-1}.integration-settings-group__grid .form-field{margin:0;align-self:start}.integration-settings-group__grid .form-control{min-height:34px;height:34px}.integration-settings-group__grid input[type=date].form-control{line-height:1.2}.integration-settings-checkboxes{border:0;padding:0;margin:0}.integration-settings-checkboxes .field-label{display:block;margin-bottom:2px}.integration-settings-checkboxes__list{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:6px 12px}.integration-settings-checkboxes__item{display:inline-flex;align-items:center;gap:6px;font-size:13px;color:#334155}.topbar__hamburger{display:none;align-items:center;justify-content:center;width:36px;height:36px;padding:0;background:rgba(0,0,0,0);border:none;color:var(--c-text-strong);cursor:pointer;border-radius:6px;flex-shrink:0}.topbar__hamburger:hover{background:var(--c-bg-subtle, #f1f5f9)}.sidebar-backdrop{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:999;opacity:0;transition:opacity .25s ease}.sidebar-backdrop.is-visible{display:block;opacity:1}body.no-scroll{overflow:hidden}@media(max-width: 768px){.topbar__hamburger{display:flex}.sidebar{position:fixed;top:0;left:0;bottom:0;width:280px;min-width:280px;z-index:1000;transform:translateX(-100%);transition:transform .25s ease;border-right:1px solid #243041;overflow-y:auto}.sidebar.is-mobile-open{transform:translateX(0)}.sidebar__brand{margin:4px 4px 12px}.sidebar__collapse-btn{display:flex}.sidebar__collapse-icon{transform:rotate(180deg)}.sidebar__nav{display:grid;gap:4px}.topbar{padding:0 14px}.container{margin-top:16px;width:calc(100% - 16px);margin-left:8px;margin-right:8px;padding:0 3px 12px}.settings-grid{grid-template-columns:1fr}.page-head{flex-direction:column;align-items:flex-start}.orders-stats{grid-template-columns:1fr;width:100%}.order-show-layout{grid-template-columns:1fr}.order-statuses-side{position:static;top:auto}.order-statuses-side__title{cursor:pointer}.order-statuses-side__arrow{display:block}.order-details-actions{justify-content:flex-start}.order-grid-2,.order-grid-3{grid-template-columns:1fr}.order-kv{grid-template-columns:1fr;gap:2px}.filters-grid,.form-grid,.form-grid-2,.form-grid-3,.form-grid-4,.shipment-grid,.statuses-form,.statuses-inline-form,.table-list-filters,.product-links-search-form,.product-links-inline-form{grid-template-columns:1fr}.statuses-dnd-item__content{display:block}.statuses-inline-delete{margin-top:6px}.filters-actions{align-items:center}.table-list__header,.table-list__footer{align-items:flex-start}.product-links-head{grid-template-columns:1fr}.integration-settings-group__grid{grid-template-columns:1fr}.integration-settings-checkboxes__list{grid-template-columns:1fr}.card{padding:12px}.modal--image-preview{width:min(92vw,100%)}.email-tpl-editor-wrap{flex-direction:column}.email-tpl-var-panel{min-width:200px}.modal-box{width:95vw;max-height:90vh}}.email-tpl-editor-wrap{display:flex;flex-direction:column;border:1px solid var(--c-border);border-radius:6px;overflow:visible}.email-tpl-toolbar{display:flex;align-items:center;gap:6px;padding:6px 8px;background:var(--c-bg-subtle, #f8f9fa);border-bottom:1px solid var(--c-border)}.email-tpl-var-dropdown{position:relative}.email-tpl-var-panel{position:absolute;top:100%;left:0;z-index:300;min-width:260px;max-height:320px;overflow-y:auto;background:var(--c-bg);border:1px solid var(--c-border);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.12);padding:6px;margin-top:4px}.email-var-group:not(:first-child){margin-top:6px;padding-top:6px;border-top:1px solid var(--c-border)}.email-var-group__label{font-size:11px;font-weight:600;text-transform:uppercase;color:var(--c-text-muted);padding:2px 4px;letter-spacing:.03em}.email-var-item{display:block;width:100%;text-align:left;padding:3px 6px;margin:1px 0;border:none;background:none;font-size:12px;font-family:"Roboto Mono",monospace;color:var(--c-text);border-radius:3px;cursor:pointer}.email-var-item:hover{background:var(--c-primary);color:#fff}#js-quill-editor{min-height:200px}#js-quill-editor .ql-editor{min-height:200px;font-size:13px}.modal-overlay{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.45)}.modal-box{width:min(680px,90vw);max-height:80vh;background:var(--c-bg);border-radius:8px;box-shadow:0 8px 30px rgba(0,0,0,.2);display:flex;flex-direction:column;overflow:hidden}.modal-box__header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--c-border)}.modal-box__title{margin:0;font-size:15px;font-weight:600}.modal-box__close{background:none;border:none;font-size:22px;line-height:1;cursor:pointer;color:var(--c-text-muted);padding:0 4px}.modal-box__close:hover{color:var(--c-text)}.modal-box__body{padding:12px 16px;overflow-y:auto;flex:1}.table-list-table tbody tr.order-row-aged>td{border-top:2px solid rgba(0,0,0,0);border-bottom:2px solid rgba(0,0,0,0)}.table-list-table tbody tr.order-row-aged>td:first-child{border-left:2px solid rgba(0,0,0,0)}.table-list-table tbody tr.order-row-aged>td:last-child{border-right:2px solid rgba(0,0,0,0)}.table-list-table tbody tr.order-row-aged-4>td{border-color:#f8b4b4}.table-list-table tbody tr.order-row-aged-5>td{border-color:#f28282}.table-list-table tbody tr.order-row-aged-6>td{border-color:#e74c3c}.table-list-table tbody tr.order-row-aged-7>td{border-color:#991b1b} diff --git a/public/assets/js/modules/statistics-summary-charts.js b/public/assets/js/modules/statistics-summary-charts.js new file mode 100644 index 0000000..7c8ebca --- /dev/null +++ b/public/assets/js/modules/statistics-summary-charts.js @@ -0,0 +1,119 @@ +(function () { + 'use strict'; + + var palette = ['#2563eb', '#0f766e', '#c2410c', '#7c3aed', '#be123c', '#0369a1', '#4d7c0f', '#9333ea']; + var totalColor = '#111827'; + + function parseData() { + var node = document.getElementById('js-statistics-summary-data'); + if (!node) return null; + + try { + return JSON.parse(node.textContent || '{}'); + } catch (error) { + return null; + } + } + + function colorForSeries(item, index) { + return item.key === 'total' ? totalColor : palette[index % palette.length]; + } + + function moneyLabel(value) { + return Number(value || 0).toLocaleString('pl-PL', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }); + } + + function datasetForSeries(item, index) { + var color = colorForSeries(item, index); + var isTotal = item.key === 'total'; + + return { + label: item.label || item.key || '', + data: item.values || [], + borderColor: color, + backgroundColor: color, + borderWidth: isTotal ? 3 : 2, + pointRadius: isTotal ? 4 : 3, + pointHoverRadius: isTotal ? 6 : 5, + tension: 0.25 + }; + } + + function renderChart(container, chart) { + if (!window.Chart || !container || !chart || !Array.isArray(chart.labels) || !Array.isArray(chart.series)) return; + + var canvas = container.querySelector('canvas'); + if (!canvas) return; + + var isMoney = chart.valueType === 'money'; + var context = canvas.getContext('2d'); + + new window.Chart(context, { + type: 'line', + data: { + labels: chart.labels, + datasets: chart.series.map(datasetForSeries) + }, + options: { + responsive: true, + maintainAspectRatio: false, + interaction: { + mode: 'index', + intersect: false + }, + plugins: { + legend: { + position: 'bottom', + labels: { + boxWidth: 18, + boxHeight: 3, + usePointStyle: false + } + }, + tooltip: { + callbacks: { + label: function (item) { + var label = item.dataset.label ? item.dataset.label + ': ' : ''; + return label + (isMoney ? moneyLabel(item.parsed.y) : Math.round(item.parsed.y)); + } + } + } + }, + scales: { + x: { + grid: { + display: false + } + }, + y: { + beginAtZero: true, + ticks: { + callback: function (value) { + return isMoney ? moneyLabel(value) : value; + } + } + } + } + } + }); + } + + function init() { + var data = parseData(); + if (!data) return; + + document.querySelectorAll('[data-statistics-chart]').forEach(function (container) { + var key = container.getAttribute('data-statistics-chart'); + renderChart(container, data[key]); + }); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); diff --git a/resources/lang/pl.php b/resources/lang/pl.php index d64711e..23a45aa 100644 --- a/resources/lang/pl.php +++ b/resources/lang/pl.php @@ -24,6 +24,7 @@ return [ 'orders' => 'Zamowienia', 'orders_list' => 'Lista zamowien', 'statistics' => 'Statystyki', + 'statistics_summary' => 'Podsumowanie', 'statistics_orders' => 'Zamowienia', 'marketplace' => 'Marketplace', 'cron' => 'Harmonogram', @@ -221,6 +222,29 @@ return [ ], ], 'statistics' => [ + 'summary' => [ + 'title' => 'Podsumowanie statystyk', + 'description' => 'Miesieczne trendy ilosci i wartosci zamowien z podzialem na integracje.', + 'empty' => 'Brak danych dla wybranych filtrow.', + 'charts' => [ + 'orders_count' => 'Ilosc zamowien miesiecznie', + 'orders_value' => 'Wartosc zamowien miesiecznie', + ], + 'filters' => [ + 'date_from' => 'Data od', + 'date_to' => 'Data do', + 'channels' => 'Kanaly sprzedazy', + 'status_groups' => 'Grupy statusow', + ], + 'columns' => [ + 'month' => 'Miesiac', + 'total' => 'Razem', + ], + 'actions' => [ + 'apply_filters' => 'Filtruj', + 'reset_filters' => 'Wyczysc', + ], + ], 'orders' => [ 'title' => 'Statystyki zamowien', 'description' => 'Dzienne podsumowanie ilosci i kwot zamowien z podzialem na kanaly sprzedazy.', diff --git a/resources/scss/app.scss b/resources/scss/app.scss index 855e9f6..9baebd6 100644 --- a/resources/scss/app.scss +++ b/resources/scss/app.scss @@ -1219,6 +1219,74 @@ h4.section-title { } } +.statistics-summary-page { + padding: 10px; +} + +.statistics-summary-section { + display: grid; + gap: 12px; +} + +.statistics-summary-chart-grid, +.statistics-summary-table-grid { + display: grid; + gap: 12px; +} + +@media (min-width: 1100px) { + .statistics-summary-chart-grid, + .statistics-summary-table-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + align-items: start; + } +} + +.statistics-summary-card { + padding: 10px; +} + +.statistics-summary-card__head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + margin-bottom: 8px; +} + +.statistics-summary-chart { + position: relative; + height: 320px; +} + +.statistics-summary-chart canvas { + display: block; + width: 100%; + height: 100%; + border: 1px solid #e2e8f0; + border-radius: 6px; + background: #ffffff; +} + +.statistics-summary-fallback { + margin-top: 0; +} + +.statistics-summary-table { + min-width: 640px; + + th, + td { + white-space: nowrap; + text-align: right; + } + + th:first-child, + td:first-child { + text-align: left; + } +} + .orders-head { display: flex; align-items: flex-start; diff --git a/resources/views/layouts/app.php b/resources/views/layouts/app.php index f575c86..9219e0d 100644 --- a/resources/views/layouts/app.php +++ b/resources/views/layouts/app.php @@ -64,6 +64,9 @@