ifnex/03_WordPress/wp-content/plugins/ifnex-bridge/assets/css/ifnex-bridge.css
Kazem Alghasi a4fc807160 feat(address-book): implement customer address book system (phase 3.9)
Introduce a comprehensive address management system allowing users to
save, manage, and reuse sender and receiver addresses during the
ordering process. This feature bridges the WordPress frontend with the
Laravel backend API.

Key changes:
- Backend (Laravel):
  - Added `AddressBookEntry` model and migration for storing addresses
    with role (sender/receiver), usage tracking, and default status.
  - Implemented `AddressBookController` with full CRUD functionality
    secured via Sanctum and ownership validation.
  - Integrated address usage tracking and upsert logic into the
    `CustomerOrderController` to prevent duplicate entries.
  - Added 18 new feature tests covering ownership, limits, and
    validation.
- Frontend (WordPress):
  - Added a new "Address Book" tab in the user dashboard with card-based
    UI, filtering, and SweetAlert2 integration.
  - Enhanced the order form with dropdown selectors for saved addresses
    and "save this address" checkboxes for both sender and receiver.
  - Implemented secure AJAX proxies in `user-bridge.php` with nonce
    and sanitization.
- Documentation:
  - Updated `AGENT.md` and `CLIENT_DELIVERY.md` to reflect phase 3.9
    completion and updated the project roadmap.
  - Removed obsolete `README-INSTALL.md`.
2026-10-31 19:57:01 +03:30

818 lines
22 KiB
CSS

/**
* IFNEX Bridge Styles
* استایل‌های پلاگین IFNEX Logistics Bridge
* بر اساس IFNEX Design System
*/
:root {
--ifnex-primary: #f59e0b;
--ifnex-primary-dark: #d97706;
--ifnex-primary-light: #fbbf24;
--ifnex-success: #059669;
--ifnex-success-light: #d1fae5;
--ifnex-danger: #dc2626;
--ifnex-danger-light: #fee2e2;
--ifnex-warning: #f59e0b;
--ifnex-warning-light: #fef3c7;
--ifnex-info: #2563eb;
--ifnex-info-light: #dbeafe;
--ifnex-gray-900: #111827;
--ifnex-gray-700: #374151;
--ifnex-gray-600: #4b5563;
--ifnex-gray-500: #6b7280;
--ifnex-gray-400: #9ca3af;
--ifnex-gray-300: #d1d5db;
--ifnex-gray-200: #e5e7eb;
--ifnex-gray-100: #f3f4f6;
--ifnex-gray-50: #f9fafb;
--ifnex-white: #ffffff;
--ifnex-font-family: 'Vazirmatn', 'IranYekan', ui-sans-serif, system-ui, sans-serif;
--ifnex-radius-sm: 0.375rem;
--ifnex-radius-md: 0.5rem;
--ifnex-radius-lg: 0.75rem;
}
/* ============================================
GLOBAL
============================================ */
.ifnex-widget,
.ifnex-tracking-container,
.ifnex-tracking-result,
.ifnex-transactions,
.ifnex-wallet-balance {
font-family: var(--ifnex-font-family) !important;
direction: rtl !important;
text-align: right !important;
color: var(--ifnex-gray-900) !important;
}
/* ============================================
WALLET BALANCE
============================================ */
.ifnex-wallet-balance {
background: var(--ifnex-white) !important;
border: 1px solid var(--ifnex-gray-200) !important;
border-radius: var(--ifnex-radius-lg) !important;
padding: 1.25rem !important;
margin: 1rem 0 !important;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important;
}
.ifnex-balance-main {
display: flex !important;
justify-content: space-between !important;
align-items: center !important;
margin-bottom: 1rem !important;
padding-bottom: 1rem !important;
border-bottom: 1px solid var(--ifnex-gray-200) !important;
}
.ifnex-balance-label {
font-size: 0.875rem !important;
color: var(--ifnex-gray-500) !important;
font-weight: 500 !important;
}
.ifnex-balance-amount {
font-size: 1.5rem !important;
font-weight: 700 !important;
color: var(--ifnex-success) !important;
}
.ifnex-balance-details {
margin-top: 1rem !important;
}
.ifnex-balance-details p {
margin: 0.5rem 0 !important;
font-size: 0.875rem !important;
color: var(--ifnex-gray-700) !important;
}
.ifnex-balance-details strong {
color: var(--ifnex-gray-500) !important;
margin-left: 0.5rem !important;
}
.ifnex-wallet-frozen {
color: var(--ifnex-danger) !important;
font-weight: 600 !important;
margin-top: 1rem !important;
padding: 0.75rem 1rem !important;
background: var(--ifnex-danger-light) !important;
border-radius: var(--ifnex-radius-md) !important;
border-right: 3px solid var(--ifnex-danger) !important;
}
/* ============================================
TRANSACTIONS
============================================ */
.ifnex-transactions {
margin: 1rem 0 !important;
}
.ifnex-transactions h3 {
font-size: 1.125rem !important;
font-weight: 600 !important;
color: var(--ifnex-gray-900) !important;
margin-bottom: 1rem !important;
padding-bottom: 0.5rem !important;
border-bottom: 2px solid var(--ifnex-primary) !important;
}
.ifnex-transactions-list {
display: flex !important;
flex-direction: column !important;
gap: 0.75rem !important;
}
.ifnex-transaction-item {
background: var(--ifnex-white) !important;
border: 1px solid var(--ifnex-gray-200) !important;
border-radius: var(--ifnex-radius-lg) !important;
padding: 1rem !important;
transition: all 0.2s ease !important;
}
.ifnex-transaction-item:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important;
border-color: var(--ifnex-primary-light) !important;
}
.ifnex-transaction-header {
display: flex !important;
justify-content: space-between !important;
align-items: center !important;
margin-bottom: 0.5rem !important;
}
.ifnex-transaction-type {
display: inline-block !important;
padding: 0.25rem 0.75rem !important;
border-radius: var(--ifnex-radius-sm) !important;
font-size: 0.75rem !important;
font-weight: 500 !important;
text-transform: uppercase !important;
background: var(--ifnex-info-light) !important;
color: var(--ifnex-info) !important;
}
.ifnex-transaction-type.deposit {
background: var(--ifnex-success-light) !important;
color: var(--ifnex-success) !important;
}
.ifnex-transaction-type.withdrawal,
.ifnex-transaction-type.order_payment {
background: var(--ifnex-danger-light) !important;
color: var(--ifnex-danger) !important;
}
.ifnex-transaction-type.refund {
background: var(--ifnex-info-light) !important;
color: var(--ifnex-info) !important;
}
.ifnex-transaction-amount {
font-size: 1rem !important;
font-weight: 700 !important;
font-family: var(--ifnex-font-family) !important;
}
.ifnex-transaction-amount.positive {
color: var(--ifnex-success) !important;
}
.ifnex-transaction-amount.negative {
color: var(--ifnex-danger) !important;
}
.ifnex-transaction-details {
margin-top: 0.5rem !important;
}
.ifnex-transaction-description {
color: var(--ifnex-gray-700) !important;
font-size: 0.875rem !important;
margin: 0 0 0.5rem 0 !important;
}
.ifnex-transaction-meta {
display: flex !important;
gap: 0.75rem !important;
font-size: 0.75rem !important;
color: var(--ifnex-gray-500) !important;
}
.ifnex-transaction-status {
display: inline-block !important;
padding: 0.125rem 0.5rem !important;
border-radius: var(--ifnex-radius-sm) !important;
background: var(--ifnex-gray-100) !important;
color: var(--ifnex-gray-700) !important;
font-size: 0.75rem !important;
}
.ifnex-transaction-status.completed {
background: var(--ifnex-success-light) !important;
color: var(--ifnex-success) !important;
}
.ifnex-transaction-status.pending {
background: var(--ifnex-warning-light) !important;
color: #92400e !important;
}
.ifnex-transaction-status.failed {
background: var(--ifnex-danger-light) !important;
color: var(--ifnex-danger) !important;
}
.ifnex-transaction-ref {
margin-top: 0.5rem !important;
font-size: 0.75rem !important;
color: var(--ifnex-gray-500) !important;
font-family: monospace !important;
}
/* ============================================
TRACKING FORM
============================================ */
.ifnex-tracking-container {
max-width: 700px !important;
margin: 1.5rem auto !important;
padding: 1.5rem !important;
background: var(--ifnex-white) !important;
border: 1px solid var(--ifnex-gray-200) !important;
border-radius: var(--ifnex-radius-lg) !important;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important;
}
.ifnex-tracking-container h2 {
font-size: 1.25rem !important;
font-weight: 700 !important;
color: var(--ifnex-gray-900) !important;
margin-bottom: 1rem !important;
padding-bottom: 0.5rem !important;
border-bottom: 2px solid var(--ifnex-primary) !important;
}
.ifnex-tracking-form {
margin-bottom: 1.5rem !important;
}
.ifnex-form-group {
display: flex !important;
gap: 0.75rem !important;
}
.ifnex-form-group input {
flex: 1 !important;
padding: 0.75rem 1rem !important;
border: 1px solid var(--ifnex-gray-300) !important;
border-radius: var(--ifnex-radius-md) !important;
font-size: 0.9375rem !important;
font-family: var(--ifnex-font-family) !important;
transition: var(--ifnex-transition) !important;
}
.ifnex-form-group input:focus {
outline: none !important;
border-color: var(--ifnex-primary) !important;
box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1) !important;
}
.ifnex-form-group button {
padding: 0.75rem 1.5rem !important;
background: var(--ifnex-primary) !important;
color: var(--ifnex-white) !important;
border: none !important;
border-radius: var(--ifnex-radius-md) !important;
cursor: pointer !important;
font-size: 0.9375rem !important;
font-weight: 600 !important;
font-family: var(--ifnex-font-family) !important;
transition: var(--ifnex-transition) !important;
}
.ifnex-form-group button:hover {
background: var(--ifnex-primary-dark) !important;
transform: translateY(-1px) !important;
box-shadow: var(--ifnex-shadow-md) !important;
}
.ifnex-form-group button:disabled {
background: var(--ifnex-gray-400) !important;
cursor: not-allowed !important;
transform: none !important;
box-shadow: none !important;
}
.ifnex-tracking-result {
margin-top: 1.5rem !important;
padding: 1.25rem !important;
background: var(--ifnex-gray-50) !important;
border-radius: var(--ifnex-radius-md) !important;
border: 1px solid var(--ifnex-gray-200) !important;
}
.ifnex-error {
color: var(--ifnex-danger) !important;
font-weight: 500 !important;
padding: 0.75rem 1rem !important;
background: var(--ifnex-danger-light) !important;
border-radius: var(--ifnex-radius-md) !important;
border-right: 3px solid var(--ifnex-danger) !important;
}
.ifnex-tracking-status h3 {
margin-top: 0 !important;
font-size: 1.125rem !important;
font-weight: 700 !important;
color: var(--ifnex-gray-900) !important;
}
.ifnex-status-badge {
display: inline-block !important;
padding: 0.375rem 0.875rem !important;
background: var(--ifnex-primary) !important;
color: var(--ifnex-white) !important;
border-radius: var(--ifnex-radius-md) !important;
margin-bottom: 0.75rem !important;
font-weight: 600 !important;
font-size: 0.875rem !important;
}
.ifnex-status-badge.delivered {
background: var(--ifnex-success) !important;
}
.ifnex-status-badge.failed {
background: var(--ifnex-danger) !important;
}
.ifnex-status-badge.in_transit {
background: var(--ifnex-info) !important;
}
.ifnex-tracking-details {
margin-top: 1rem !important;
}
.ifnex-tracking-details p {
margin: 0.5rem 0 !important;
font-size: 0.875rem !important;
color: var(--ifnex-gray-700) !important;
}
.ifnex-tracking-details strong {
color: var(--ifnex-gray-700) !important;
margin-left: 0.5rem !important;
}
.ifnex-timeline {
margin-top: 1.5rem !important;
padding-top: 1rem !important;
border-top: 1px solid var(--ifnex-gray-200) !important;
}
.ifnex-timeline h4 {
font-size: 1rem !important;
font-weight: 600 !important;
color: var(--ifnex-gray-900) !important;
margin-bottom: 0.75rem !important;
}
.ifnex-timeline ul {
list-style: none !important;
padding: 0 !important;
margin: 0 !important;
}
.ifnex-timeline li {
padding: 0.75rem !important;
border-bottom: 1px solid var(--ifnex-gray-100) !important;
display: flex !important;
gap: 0.75rem !important;
align-items: flex-start !important;
font-size: 0.875rem !important;
}
.ifnex-timeline li:last-child {
border-bottom: none !important;
}
.ifnex-timeline li strong {
color: var(--ifnex-primary) !important;
font-weight: 600 !important;
white-space: nowrap !important;
min-width: 100px !important;
}
.ifnex-timeline li span {
color: var(--ifnex-gray-700) !important;
flex: 1 !important;
}
.ifnex-timeline li small {
color: var(--ifnex-gray-400) !important;
font-size: 0.75rem !important;
white-space: nowrap !important;
}
/* ============================================
RESPONSIVE
============================================ */
@media (max-width: 768px) {
.ifnex-tracking-container {
max-width: 100% !important;
padding: 1rem !important;
margin: 1rem 0 !important;
}
.ifnex-form-group {
flex-direction: column !important;
}
.ifnex-form-group button {
width: 100% !important;
}
.ifnex-balance-amount {
font-size: 1.25rem !important;
}
.ifnex-transaction-header {
flex-direction: column !important;
align-items: flex-start !important;
gap: 0.5rem !important;
}
}
/* ============================================
ORDER FORM STEPS
============================================ */
.ifnex-form-step {
display: none !important;
}
.ifnex-form-step.active {
display: block !important;
}
.ifnex-steps {
display: flex !important;
justify-content: space-between !important;
margin-bottom: 2rem !important;
padding: 1rem !important;
background: var(--ifnex-gray-50) !important;
border-radius: var(--ifnex-radius-lg) !important;
border: 1px solid var(--ifnex-gray-200) !important;
}
.ifnex-step {
flex: 1 !important;
text-align: center !important;
padding: 0.5rem !important;
position: relative !important;
color: var(--ifnex-gray-400) !important;
font-size: 0.75rem !important;
transition: all 0.3s ease !important;
}
.ifnex-step span {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
width: 28px !important;
height: 28px !important;
border-radius: 50% !important;
background: var(--ifnex-gray-200) !important;
color: var(--ifnex-gray-500) !important;
font-weight: 600 !important;
font-size: 0.875rem !important;
margin-bottom: 0.25rem !important;
}
.ifnex-step.active {
color: var(--ifnex-primary) !important;
font-weight: 600 !important;
}
.ifnex-step.active span {
background: var(--ifnex-primary) !important;
color: var(--ifnex-white) !important;
}
.ifnex-step.done {
color: var(--ifnex-success) !important;
}
.ifnex-step.done span {
background: var(--ifnex-success) !important;
color: var(--ifnex-white) !important;
}
.ifnex-form-nav {
display: flex !important;
justify-content: space-between !important;
align-items: center !important;
margin-top: 1.5rem !important;
padding-top: 1rem !important;
border-top: 1px solid var(--ifnex-gray-200) !important;
}
.ifnex-form-card {
background: var(--ifnex-white) !important;
border: 1px solid var(--ifnex-gray-200) !important;
border-radius: var(--ifnex-radius-lg) !important;
padding: 1.5rem !important;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important;
}
.ifnex-form-card h3 {
font-size: 1rem !important;
font-weight: 600 !important;
color: var(--ifnex-gray-900) !important;
margin-bottom: 1rem !important;
padding-bottom: 0.5rem !important;
border-bottom: 2px solid var(--ifnex-primary) !important;
}
.ifnex-form-grid {
display: grid !important;
grid-template-columns: repeat(2, 1fr) !important;
gap: 1rem !important;
}
.ifnex-form-grid .full {
grid-column: span 2 !important;
}
.ifnex-field {
display: flex !important;
flex-direction: column !important;
}
.ifnex-field label {
font-size: 0.875rem !important;
font-weight: 500 !important;
color: var(--ifnex-gray-700) !important;
margin-bottom: 0.375rem !important;
}
.ifnex-field input,
.ifnex-field select,
.ifnex-field textarea {
padding: 0.625rem 0.875rem !important;
border: 1px solid var(--ifnex-gray-300) !important;
border-radius: var(--ifnex-radius-md) !important;
font-size: 0.875rem !important;
font-family: var(--ifnex-font-family) !important;
transition: all 0.2s ease !important;
}
.ifnex-field input:focus,
.ifnex-field select:focus,
.ifnex-field textarea:focus {
outline: none !important;
border-color: var(--ifnex-primary) !important;
box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1) !important;
}
.ifnex-error-box {
padding: 0.75rem 1rem !important;
background: var(--ifnex-danger-light) !important;
border: 1px solid var(--ifnex-danger) !important;
border-radius: var(--ifnex-radius-md) !important;
color: var(--ifnex-danger) !important;
font-size: 0.875rem !important;
margin-bottom: 1rem !important;
}
.ifnex-success-box {
padding: 0.75rem 1rem !important;
background: var(--ifnex-success-light) !important;
border: 1px solid var(--ifnex-success) !important;
border-radius: var(--ifnex-radius-md) !important;
color: var(--ifnex-success) !important;
font-size: 0.875rem !important;
margin-bottom: 1rem !important;
}
.ifnex-warning-box {
padding: 0.75rem 1rem !important;
background: var(--ifnex-warning-light) !important;
border: 1px solid var(--ifnex-warning) !important;
border-radius: var(--ifnex-radius-md) !important;
color: #92400e !important;
font-size: 0.875rem !important;
margin-bottom: 1rem !important;
}
/* ═══════════════════════════════════════════
دفترچه آدرس — تب پنل کاربری (فاز ۳.۹)
═══════════════════════════════════════════ */
.ifnx-notice {
padding: 12px 16px;
border-radius: var(--ifnex-radius-md, 10px);
margin-bottom: 1rem;
font-size: 0.875rem;
}
.ifnx-notice-error {
background: var(--ifnex-danger-light, #fee2e2);
border: 1px solid #fecaca;
color: #991b1b;
}
.ifnx-address-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 18px;
}
.ifnx-address-filters {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.ifnx-chip {
display: inline-flex;
align-items: center;
padding: 7px 16px;
border-radius: 999px;
font-size: 13px;
font-weight: 600;
color: var(--ifnex-gray-600, #4b5563);
background: var(--ifnex-gray-100, #f3f4f6);
border: 1px solid var(--ifnex-gray-200, #e5e7eb);
text-decoration: none;
transition: all 0.15s ease;
}
.ifnx-chip:hover {
background: var(--ifnex-warning-light, #fef3c7);
border-color: #fcd34d;
color: #92400e;
}
.ifnx-chip.active {
background: var(--ifnex-primary, #f59e0b);
border-color: var(--ifnex-primary, #f59e0b);
color: #fff;
}
/* فرم افزودن/ویرایش */
.ifnx-address-form {
background: var(--ifnex-white, #fff);
border: 1px solid var(--ifnex-gray-200, #e5e7eb);
border-radius: var(--ifnex-radius-md, 12px);
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}
.ifnx-address-form-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
gap: 14px;
margin-bottom: 16px;
}
.ifnx-address-form-grid .full { grid-column: 1 / -1; }
.ifnx-addr-checkbox {
display: inline-flex;
align-items: center;
gap: 8px;
cursor: pointer;
font-size: 13px;
font-weight: 500;
color: var(--ifnex-gray-700, #374151);
padding: 8px 12px;
background: var(--ifnex-warning-light, #fef3c7);
border: 1px dashed #fcd34d;
border-radius: 8px;
user-select: none;
}
.ifnx-addr-checkbox input { accent-color: var(--ifnex-primary, #f59e0b); width: 17px; height: 17px; }
.ifnx-address-form-actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
/* کارت‌های آدرس */
.ifnx-address-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 16px;
}
.ifnx-address-card {
background: var(--ifnex-white, #fff);
border: 1px solid var(--ifnex-gray-200, #e5e7eb);
border-radius: var(--ifnex-radius-md, 12px);
padding: 16px;
display: flex;
flex-direction: column;
gap: 8px;
transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.ifnx-address-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.07);
}
.ifnx-address-card.is-default {
border-color: #fcd34d;
background: linear-gradient(180deg, #fffbeb 0%, #ffffff 40%);
}
.ifnx-address-card-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.ifnx-address-role {
display: inline-flex;
align-items: center;
font-size: 11px;
font-weight: 700;
padding: 4px 10px;
border-radius: 999px;
}
.ifnx-address-role.role-sender {
background: var(--ifnex-info-light, #dbeafe);
color: #1e40af;
}
.ifnx-address-role.role-receiver {
background: var(--ifnex-success-light, #d1fae5);
color: #065f46;
}
.ifnx-address-default-badge {
font-size: 11px;
font-weight: 700;
color: #92400e;
background: var(--ifnex-warning-light, #fef3c7);
padding: 4px 10px;
border-radius: 999px;
}
.ifnx-address-card-title {
font-size: 15px;
font-weight: 700;
color: var(--ifnex-gray-900, #111827);
}
.ifnx-address-card-meta {
display: flex;
flex-wrap: wrap;
gap: 6px 14px;
font-size: 12px;
color: var(--ifnex-gray-600, #4b5563);
}
.ifnx-address-card-text {
font-size: 13px;
line-height: 1.7;
color: var(--ifnex-gray-700, #374151);
background: var(--ifnex-gray-50, #f9fafb);
border-radius: 8px;
padding: 10px 12px;
flex: 1;
}
.ifnx-address-card-actions {
display: flex;
gap: 8px;
flex-wrap: wrap;
border-top: 1px solid var(--ifnex-gray-100, #f3f4f6);
padding-top: 12px;
margin-top: 4px;
}
.ifnx-address-card-actions .ifnex-btn[disabled] {
opacity: 0.45;
cursor: not-allowed;
}
/* حالت خالی */
.ifnx-address-empty {
text-align: center;
padding: 48px 20px;
background: var(--ifnex-white, #fff);
border: 2px dashed var(--ifnex-gray-200, #e5e7eb);
border-radius: var(--ifnex-radius-md, 12px);
}
.ifnx-address-empty-icon { font-size: 42px; margin-bottom: 10px; }
.ifnx-address-empty h3 {
font-size: 16px;
color: var(--ifnex-gray-900, #111827);
margin: 0 0 8px;
}
.ifnx-address-empty p {
font-size: 13px;
color: var(--ifnex-gray-500, #6b7280);
max-width: 460px;
margin: 0 auto;
line-height: 1.8;
}
/* موبایل */
@media (max-width: 640px) {
.ifnx-address-toolbar { flex-direction: column; align-items: stretch; }
.ifnx-address-grid { grid-template-columns: 1fr; }
.ifnx-address-form-grid { grid-template-columns: 1fr; }
}