/* ========== CUSTOM BREAKPOINT FOR 4K/ULTRA-WIDE SCREENS ========== */
/* Bootstrap 5 xxl starts at 1400px, but we need a larger breakpoint for 4K displays */
/* xxxl breakpoint: 2560px and above (covers 2560x1440 and 3840x2160) */

@media (min-width: 2560px) {
  .col-xxxl-1 { flex: 0 0 auto; width: 8.33333333%; }
  .col-xxxl-2 { flex: 0 0 auto; width: 16.66666667%; }
  .col-xxxl-3 { flex: 0 0 auto; width: 25%; }
  .col-xxxl-4 { flex: 0 0 auto; width: 33.33333333%; }
  .col-xxxl-5 { flex: 0 0 auto; width: 41.66666667%; }
  .col-xxxl-6 { flex: 0 0 auto; width: 50%; }
  .col-xxxl-7 { flex: 0 0 auto; width: 58.33333333%; }
  .col-xxxl-8 { flex: 0 0 auto; width: 66.66666667%; }
  .col-xxxl-9 { flex: 0 0 auto; width: 75%; }
  .col-xxxl-10 { flex: 0 0 auto; width: 83.33333333%; }
  .col-xxxl-11 { flex: 0 0 auto; width: 91.66666667%; }
  .col-xxxl-12 { flex: 0 0 auto; width: 100%; }
  .col-xxxl-auto { flex: 0 0 auto; width: auto; }
}

/* ========== SIDEBAR NAVIGATION ACTIVE STATE FIX ========== */
/* Fix for nav-active class when html doesn't have sidebar-light class */
ul.nav-main > li.nav-active > a {
  color: #0088cc !important; /* Porto Admin blue */
}

ul.nav-main > li.nav-active > a i {
  color: #0088cc !important;
}

/* Invoice icon cursor */
.btn-invoice {
  cursor: pointer;
}

.btn-invoice:hover {
  color: #0d6efd !important;
}
.edit-loading-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(255, 255, 255, 0.8);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

.edit-loading-spinner {
  width: 50px;
  height: 50px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #007bff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 20px;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.edit-loading-text {
  font-size: 16px;
  color: #666;
  font-weight: 500;
}

.edit-content-blur {
  filter: blur(2px);
  pointer-events: none;
  opacity: 0.7;
}

/* Packing Module Styles */

/* Barcode Scanner Input */
.barcode-input {
  font-size: 1.5rem !important;
  font-weight: 600;
  text-align: center;
  letter-spacing: 2px;
  font-family: 'Courier New', Courier, monospace;
  border: 2px solid #0d6efd;
  background-color: #f8f9fa;
}

.barcode-input:focus {
  border-color: #0d6efd;
  box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
  background-color: #fff;
}

/* Barcode Display */
.barcode-display {
  min-height: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Libre Barcode 128', monospace;
}

/* Card Stats */
.card-stat {
  border-left: 4px solid #dee2e6;
  transition: all 0.3s ease;
}

.card-stat:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

/* Capacity Progress Bars */
.progress {
  background-color: #e9ecef;
}

.progress-bar.bg-success {
  background-color: #28a745 !important;
}

.progress-bar.bg-warning {
  background-color: #ffc107 !important;
}

/* Adjustment Reason Dropdown - Invalid State */
.adjustment-reason.is-invalid {
  border-color: #dc3545;
}

/* Summary Section - Compact Styling */
.card-header.py-2 {
  padding-top: 0.5rem !important;
  padding-bottom: 0.5rem !important;
}

.card-body.py-3 {
  padding-top: 0.75rem !important;
  padding-bottom: 0.75rem !important;
}

/* Subtle Quantity Adjustment Display */
.border-start.border-3 {
  border-left-width: 3px !important;
}

.progress-bar.bg-danger {
  background-color: #dc3545 !important;
}

/* Bag Status Badges */
.badge.bg-primary {
  background-color: #0d6efd !important;
}

.badge.bg-info {
  background-color: #0dcaf0 !important;
  color: #000 !important;
}

.badge.bg-success {
  background-color: #198754 !important;
}

.badge.bg-danger {
  background-color: #dc3545 !important;
}

.badge.bg-warning {
  background-color: #ffc107 !important;
  color: #000 !important;
}

.badge.bg-secondary {
  background-color: #6c757d !important;
  color: #fff !important;
}

/* Stock Badge - for stock bags (from previous sessions) */
.badge-stock {
  background-color: #6c757d !important;
  color: #fff !important;
}

/* Box Status Badges - same as bag badges for consistency */

/* Scanner Card */
#scannerCard {
  border: 2px solid #0d6efd;
  transition: all 0.3s ease;
}

#scannerCard:hover {
  box-shadow: 0 4px 12px rgba(13, 110, 253, 0.2);
}

/* Scan Status Icon Animation */
.scan-status-icon {
  transition: all 0.3s ease;
}

.scan-status-icon .fa-check-circle {
  animation: pulse 0.5s ease-in-out;
}

.scan-status-icon .fa-times-circle {
  animation: shake 0.5s ease-in-out;
}

@keyframes pulse {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.2);
  }
}

@keyframes shake {
  0%, 100% {
    transform: translateX(0);
  }
  25% {
    transform: translateX(-5px);
  }
  75% {
    transform: translateX(5px);
  }
}

/* Stage Buttons */
.stage-btn {
  position: relative;
  overflow: hidden;
}

.stage-btn::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background-color: transparent;
  transition: background-color 0.3s ease;
}

.stage-btn.btn-primary::after {
  background-color: #0d6efd;
}

.stage-btn.btn-warning::after {
  background-color: #ffc107;
}

.stage-btn.btn-success::after {
  background-color: #198754;
}

/* Session Duration Badge */
#sessionDuration {
  font-size: 1.1rem;
  font-weight: 600;
  padding: 0.5rem 1rem;
  font-family: 'Courier New', Courier, monospace;
}

/* Scanned Items Table Animation */
#scannedItemsTable tbody tr {
  animation: fadeIn 0.3s ease-in-out;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Label Preview Modal */
#modalLabelPreview .barcode-display {
  background-color: #fff;
  border: 1px solid #dee2e6;
  padding: 1rem;
}

/* Keyboard Shortcuts */
kbd {
  display: inline-block;
  padding: 0.25rem 0.5rem;
  font-size: 0.875rem;
  font-family: 'Courier New', Courier, monospace;
  line-height: 1;
  color: #212529;
  background-color: #f8f9fa;
  border: 1px solid #ced4da;
  border-radius: 0.25rem;
  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
}

/* Responsive Tablet Support */
@media (max-width: 768px) {
  .barcode-input {
    font-size: 1.2rem !important;
  }

  .card-stat h3 {
    font-size: 1.5rem;
  }

  #sessionDuration {
    font-size: 0.9rem;
  }
}

/* ========== PACKING SESSION STEP INDICATOR ========== */
.step-indicator {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 1rem;
  position: relative;
  padding: 0 2rem;
  margin-bottom: 2rem;
}

.step-indicator .step {
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  z-index: 1;
}

/* Shared with .wizard-step-circle (product-special-prices wizard) below - same circle-badge look
   for both step indicators, one declaration block. */
.step-indicator .step span,
.wizard-step-circle {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background-color: #e9ecef;
  color: #6c757d;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 0.875rem;
  border: 3px solid #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
  margin-bottom: 0.5rem;
}

/* Shared with .wizard-step-label below. */
.step-indicator .step-label,
.wizard-step-label {
  font-size: 0.75rem;
  color: #6c757d;
  text-align: center;
  font-weight: 500;
  margin-top: 0.25rem;
  transition: color 0.3s ease;
}

.step-indicator .step.active span {
  background-color: #0d6efd;
  color: #fff;
  box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.25);
  transform: scale(1.1);
}

.step-indicator .step.active .step-label {
  color: #0d6efd;
  font-weight: 700;
}

.step-indicator .step.completed span {
  background-color: #198754;
  color: #fff;
}

.step-indicator .step.completed .step-label {
  color: #198754;
  font-weight: 600;
}

.step-indicator .step-connector {
  flex: 1;
  height: 2px;
  background-color: #e9ecef;
  min-width: 50px;
}

.step-indicator .step.completed + .step-connector {
  background-color: #198754;
}

/* Spares calculation display */
.spares-info {
  color: #0dcaf0;
  font-size: 0.85rem;
  font-weight: 500;
}

.spares-warning {
  color: #dc3545;
  font-size: 0.85rem;
  font-weight: 500;
}

.spares-summary {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Reason field styling */
.reason-container {
  margin-top: 0.5rem;
}

.reason-field {
  background-color: #fff3cd;
  border-left: 3px solid #ffc107;
  padding: 0.75rem;
  border-radius: 0.375rem;
}

.reason-field label {
  font-size: 0.85rem;
  font-weight: 600;
  color: #856404;
  margin-bottom: 0.5rem;
  display: block;
}

.reason-field .form-control-sm {
  font-size: 0.85rem;
}

/* Box capacity warning */
.box-capacity-warning {
  background-color: #fff3cd;
  border-left: 3px solid #ffc107;
  padding: 0.75rem;
  border-radius: 0.375rem;
  font-size: 0.85rem;
  color: #856404;
}

.box-capacity-warning i {
  color: #ffc107;
}

/* Responsive adjustments for step indicator */
@media (max-width: 768px) {
  .step-indicator {
    padding: 0 1rem;
  }

  .step-indicator .step span {
    width: 36px;
    height: 36px;
    font-size: 0.8rem;
  }

  .step-indicator .step-label {
    font-size: 0.7rem;
  }

  .step-indicator .step.active span {
    transform: scale(1.05);
  }

  .step-indicator .step-connector {
    min-width: 30px;
  }
}

/* Enhanced table styling for order details */
#cartTable {
  font-size: 0.9rem;
}

#cartTable .quantity-column {
  width: 80px;
  max-width: 80px;
}

#cartTable .price-column {
  width: 120px;
  max-width: 120px;
}

#cartTable .cart-rate {
  width: 100%;
  min-width: 110px;
  font-size: 0.85rem;
  padding: 4px 8px;
}

#cartTable td {
  padding: 8px 4px;
  vertical-align: middle;
}

#cartTable .text-end {
  text-align: right !important;
}

/* Shipping modal specific styles */
.shipping-quantity-input {
  width: 80px;
  text-align: right;
}

/* Datepicker specific styles */
.datepicker {
  z-index: 1060 !important; /* Ensure it appears above modal */
}

.datepicker table tr td.disabled,
.datepicker table tr td.disabled:hover {
  background: none;
  color: #999999;
  cursor: default;
}

.datepicker table tr td.today,
.datepicker table tr td.today:hover,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:hover {
  background-color: #ffeaa7;
  background-image: linear-gradient(to bottom, #ffeaa7, #ffe082);
  color: #000;
}

.datepicker table tr td.active,
.datepicker table tr td.active:hover,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active.disabled:hover {
  background-color: #006be6;
  background-image: linear-gradient(to bottom, #006be6, #0056b3);
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

/* Table styling improvements */
#shippingItemsTable .quantity-input {
  text-align: right;
}

#shippingItemsTable .form-control-sm {
  font-size: 0.875rem;
}

/* Responsive adjustments */
@media (max-width: 768px) {
  .shipping-quantity-input {
    width: 60px;
  }

  .modal-lg {
    max-width: 95%;
  }
}

/* Spinner for order edit form */
.edit-details-spinner-overlay {
  position: absolute !important;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(255, 255, 255, 0.95);
  z-index: 9999 !important;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 0.375rem;
  min-height: 200px;
}

.edit-details-spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #e9ecef;
  border-top: 4px solid #ffc107;
  border-radius: 50%;
  animation: order-spin 1s linear infinite;
}

@keyframes order-spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

/* Blur effect for content during update */
.order-update-blur {
  filter: blur(2px);
  opacity: 0.6;
  pointer-events: none;
  user-select: none;
  transition: all 0.3s ease;
}

/* Ensure card has proper positioning context */
.card {
  position: relative;
}

/* Style for spinner text */
.edit-details-spinner-overlay .text-muted {
  font-size: 14px;
  font-weight: 500;
  margin-top: 10px;
}

/* ========== NOTES TEXTAREA ENHANCEMENTS ========== */

/* Auto-expand textareas when they have content */
#customer_note.show,
#notes.show {
  min-height: 80px !important;
  transition: all 0.3s ease-in-out;
}

/* Highlight textareas with content - subtle yellow background */
#customer_note:not(:placeholder-shown),
#notes:not(:placeholder-shown) {
  background-color: #fffbf0;
  border-color: #ffc107;
}

/* Visual indicator for expanded sections - yellow caret */
.form-label .fa-caret-up {
  color: #ffc107;
}

/* Ensure textareas are fully visible when expanded */
.collapse.show {
  overflow: visible !important;
}

/* Add smooth animation when expanding/collapsing */
#customer_note,
#notes {
  transition: all 0.3s ease-in-out;
}

/* Note: CSS 'content' property doesn't work on ::placeholder pseudo-element */
/* Placeholder text should be set in HTML with placeholder attribute */
#customer_note::placeholder {
  color: #6c757d;
  font-style: italic;
}

#notes::placeholder {
  color: #6c757d;
  font-style: italic;
}

/* FIX: :has() selector may not be supported in all browsers, use fallback */
/* Make the labels clearer when content exists */
.form-label.has-content .fa-caret-up {
  color: #28a745; /* Green when expanded with content */
}

/* Alternative without :has() for better browser support */
.form-label.expanded .fa-caret-up {
  color: #28a745;
}

/* Optional: Add a badge indicator when notes have content */
.notes-indicator {
  display: inline-block;
  background: #ffc107;
  color: #000;
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 0.75rem;
  margin-left: 5px;
}

/* Additional enhancement: Visual feedback when notes are being edited */
#customer_note:focus,
#notes:focus {
  background-color: #fff;
  border-color: #80bdff;
  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}

/* Make collapsed textareas smaller to save space */
#customer_note:not(.show),
#notes:not(.show) {
  min-height: 38px !important;
}

/* Payment Modal - Right-align amount inputs */
#modalPayment input[type="text"]#payment_amount,
#modalPayment .payment-allocation-input {
  text-align: right;
}

/* Also apply to any other amount inputs in payment contexts */
.amount-input,
input.text-right {
  text-align: right;
}

/* Ensure payment method dropdown is properly enabled/disabled with visual feedback */
#payment_method:disabled {
  background-color: #e9ecef;
  cursor: not-allowed;
}

/* Tooltip text alignment - for tooltips that need left alignment */
.tooltip .tooltip-inner {
  text-align: left !important;
}

/* Specific class for amount tooltips with left-aligned content */
[data-bs-toggle="tooltip"].amount-tooltip + .tooltip .tooltip-inner {
  text-align: left !important;
  max-width: 300px;
}

/* Dark tooltip styling */
.tooltip-dark .tooltip-inner {
  background-color: #212529;
  color: #fff;
  max-width: 300px;
}

.tooltip-dark .tooltip-arrow::before {
  border-top-color: #212529;
}

/* Support arrows in all directions for dark tooltip */
.tooltip-dark.bs-tooltip-end .tooltip-arrow::before {
  border-right-color: #212529;
}

.tooltip-dark.bs-tooltip-start .tooltip-arrow::before {
  border-left-color: #212529;
}

.tooltip-dark.bs-tooltip-bottom .tooltip-arrow::before {
  border-bottom-color: #212529;
}

/* Dark popover styling (matches tooltip-dark) */
.popover-dark .popover-body {
  background-color: #212529;
  color: #fff;
  padding: 0.5rem 0.75rem;
}
.popover-dark .popover-arrow::after {
  border-bottom-color: #212529;
}
.popover-dark {
  border-color: #212529;
}

/* ========== USER FORM COMPACT LAYOUT ========== */

/* Reduce overall form vertical spacing */
#userForm .mb-3 {
  margin-bottom: 1rem !important;
}

#userForm .mb-4 {
  margin-bottom: 1.25rem !important;
}

/* Compact phone rows */
.phone-row {
  background-color: #f8f9fa;
  transition: background-color 0.2s ease;
}

.phone-row:hover {
  background-color: #e9ecef;
}

.phone-row .form-control-sm {
  font-size: 0.875rem;
  padding: 0.375rem 0.5rem;
}

/* Compact address rows */
.address-row {
  background-color: #f8f9fa;
  transition: background-color 0.2s ease;
}

.address-row:hover {
  background-color: #e9ecef;
}

.address-row .form-control-sm {
  font-size: 0.875rem;
  padding: 0.375rem 0.5rem;
}

/* Compact spacing for address details when expanded */
.address-row .address-details {
  padding-top: 0.5rem;
  border-top: 1px solid #dee2e6;
  margin-top: 0.5rem;
}

/* Reduce gap between radio button and title input */
.phone-row .col-auto,
.address-row .col-auto {
  padding-left: 0.25rem;
  padding-right: 0.25rem;
}

/* Compact section headers */
#userForm h6 {
  font-size: 0.95rem;
  font-weight: 600;
  margin-bottom: 0.5rem;
}

/* Ensure form controls in rows are properly aligned */
.phone-row .row,
.address-row .row {
  margin-left: 0;
  margin-right: 0;
}

/* Responsive behavior - stack on mobile */
@media (max-width: 768px) {
  .phone-row .col-md-4,
  .phone-row .col-md {
    flex: 0 0 100%;
    max-width: 100%;
    margin-top: 0.25rem;
  }

  .address-row .col-md-3,
  .address-row .col-md {
    flex: 0 0 100%;
    max-width: 100%;
    margin-top: 0.25rem;
  }

  .address-row .address-details .col-md-4 {
    flex: 0 0 100%;
    max-width: 100%;
    margin-top: 0.25rem;
  }
}

/* Button spacing adjustments */
#btnAddPhone,
#btnAddAddress {
  padding: 0.25rem 0.5rem;
  font-size: 0.875rem;
}

/* Container padding adjustments for phone and address sections */
#phoneRows,
#addressRows {
  margin-top: 0.5rem !important;
}

/* ========== NOTIFICATION PADDING FIX ========== */
/* Increase padding around the notification icon circle */
.ui-pnotify .notification {
  padding: 20px 20px 20px 95px !important;
  min-height: 75px !important;
}

.ui-pnotify .notification .ui-pnotify-icon {
  width: 95px !important;
}

/* ========== PRODUCT SPECIAL PRICES MODAL ========== */
/* Stepped form fieldsets */
#modalSpecialPrice fieldset {
  border: 1px solid #e9ecef;
  border-radius: 0.375rem;
  padding: 1rem;
  background-color: #f8f9fa;
}

#modalSpecialPrice fieldset legend {
  margin-bottom: 0.75rem;
  padding: 0 0.5rem;
  width: auto;
  float: none;
  border-bottom: none;
}

/* Conflict warning styling */
#conflictWarning {
  border-left: 4px solid #ffc107;
}

/* Form check labels for better spacing */
#modalSpecialPrice .form-check-label {
  display: inline-flex;
  align-items: center;
  margin-left: 0.25rem;
}

/* ========== WIZARD PROGRESS INDICATOR ========== */
.wizard-progress {
  position: relative;
  margin-bottom: 2rem;
}

.wizard-progress-steps {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  position: relative;
  padding: 0 1rem;
}

/* Connecting line between steps */
.wizard-progress-steps::before {
  content: '';
  position: absolute;
  top: 20px;
  left: calc(8.33% + 1rem);
  right: calc(8.33% + 1rem);
  height: 2px;
  background-color: #e9ecef;
  z-index: 0;
}

.wizard-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
  position: relative;
  z-index: 1;
  max-width: 120px;
}

/* Base .wizard-step-circle / .wizard-step-label declarations now live on the shared
   .step-indicator .step span / .wizard-step-circle and .step-indicator .step-label /
   .wizard-step-label rules above. */

/* Active step styling */
.wizard-step.active .wizard-step-circle {
  background-color: #0d6efd;
  color: #fff;
  border-color: #fff;
  box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.25);
  transform: scale(1.1);
}

.wizard-step.active .wizard-step-label {
  color: #0d6efd;
  font-weight: 700;
}

/* Completed step styling */
.wizard-step.completed .wizard-step-circle {
  background-color: #198754;
  color: #fff;
  border-color: #fff;
}

.wizard-step.completed .wizard-step-label {
  color: #198754;
  font-weight: 600;
}

/* Progress line for completed steps */
.wizard-step.completed::before {
  content: '';
  position: absolute;
  top: 20px;
  left: -50%;
  width: 100%;
  height: 2px;
  background-color: #198754;
  z-index: 0;
}

.wizard-step:first-child.completed::before {
  display: none;
}

/* Last step (Summary) with checkmark icon */
.wizard-step[data-step="6"] .wizard-step-circle {
  font-size: 1rem;
}

/* ========== WIZARD STEP CONTENT ========== */
.wizard-step-content {
  min-height: 250px;
  animation: wizardFadeIn 0.3s ease;
}

/* Named distinctly from #scannedItemsTable's fadeIn above: keyframes are global, so the two
   collided under one shared name and this block silently overrode the other's translateY
   direction for both consumers. */
@keyframes wizardFadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ========== SUMMARY SECTION ========== */
.summary-item {
  padding: 0.75rem;
  background-color: #f8f9fa;
  border-radius: 0.375rem;
  border-left: 3px solid #0d6efd;
  transition: all 0.2s ease;
}

.summary-item:hover {
  background-color: #e9ecef;
  border-left-color: #198754;
}

.summary-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: #6c757d;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 0.25rem;
  display: flex;
  align-items: center;
}

.summary-value {
  font-size: 0.95rem;
  color: #212529;
  font-weight: 500;
  word-wrap: break-word;
}

/* ========== RESPONSIVE WIZARD ========== */
@media (max-width: 992px) {
  .wizard-progress-steps {
    padding: 0 0.5rem;
  }

  .wizard-step-circle {
    width: 36px;
    height: 36px;
    font-size: 0.8rem;
  }

  .wizard-step-label {
    font-size: 0.7rem;
  }

  .wizard-step.active .wizard-step-circle {
    transform: scale(1.05);
  }
}

@media (max-width: 768px) {
  .wizard-progress-steps {
    padding: 0 0.25rem;
  }

  .wizard-step {
    max-width: 80px;
  }

  .wizard-step-circle {
    width: 32px;
    height: 32px;
    font-size: 0.75rem;
  }

  .wizard-step-label {
    font-size: 0.65rem;
  }

  .wizard-progress-steps::before {
    top: 16px;
  }

  .wizard-step.completed::before {
    top: 16px;
  }

  .summary-item {
    padding: 0.5rem;
  }

  .summary-label {
    font-size: 0.7rem;
  }

  .summary-value {
    font-size: 0.85rem;
  }
}

@media (max-width: 576px) {
  .wizard-step-label {
    display: none; /* Hide labels on very small screens */
  }

  .wizard-step {
    max-width: 50px;
  }
}

/* Fix Select2 dropdown 1px offset in modals */
.modal .select2-container--bootstrap-5 .select2-dropdown {
  left: -1px !important;
}

/* ========== WARNING BORDER ========== */

/* A global override of Bootstrap's .border-warning: it widens and recolours the border on every
   element carrying the class across the admin, not only on the invoice upload it was written for. */
.border-warning {
  border-color: #ffc107 !important;
  border-width: 2px !important;
}

/* ========== SELECT2 VALIDATION ERROR STYLING ========== */
/* Style Select2 dropdown when underlying select has is-invalid class */
.select2-selection.is-invalid {
  border-color: #dc3545 !important;
  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25) !important;
}

/* Also style when parent has is-invalid */
.is-invalid + .select2-container .select2-selection {
  border-color: #dc3545 !important;
}

.is-invalid + .select2-container .select2-selection:focus {
  border-color: #dc3545 !important;
  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25) !important;
}

/* ========== READONLY FIELD MATCHING A DISABLED SIBLING CONTROL ========== */

/* A readonly field standing in for a disabled control beside it (e.g. the blind-mode
   Closing Date next to the disabled Cashier Account select) must read as the same
   "fixed" state, not as a muted hint. Bootstrap leaves a readonly .form-control white
   with normal text, so without this it looks editable next to a grey disabled select.
   Opt in with .form-control-readonly-fixed rather than making this the default for
   every readonly input - plenty of readonly fields (datepicker triggers, calculated
   totals) are meant to look like ordinary inputs. */
.form-control[readonly].form-control-readonly-fixed {
  background-color: #e9ecef;
  border-color: #dee2e6;
  color: #212529;
  cursor: default;
}

/* Edit company hint alert */
#editCompanyHint {
  font-size: 0.875rem;
  padding: 0.75rem;
  margin-bottom: 1rem;
}

#editCompanyHint i {
  margin-right: 0.5rem;
}

/* ========== BOX FILLING WORKFLOW ANIMATIONS ========== */

/* Pulse overlay for full-screen visual feedback. Shared base/success/error with
   .scan-pulse-overlay below (SCAN FEEDBACK section) - same full-page flash, one declaration
   block each; .scan-pulse-overlay additionally carries its own warning variant. */
.pulse-overlay,
.scan-pulse-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
  transition: opacity 0.1s ease;
}

.pulse-overlay.pulse-success,
.scan-pulse-overlay.scan-pulse-success {
  background-color: rgba(40, 167, 69, 0.3); /* green */
  opacity: 1;
}

.pulse-overlay.pulse-error,
.scan-pulse-overlay.scan-pulse-error {
  background-color: rgba(220, 53, 69, 0.3); /* red */
  opacity: 1;
}

/* Modal success/error pulse for barcode scanning */
.modal-content.bg-success-pulse {
  animation: modal-pulse-success 0.4s ease-out;
}

.modal-content.bg-danger-pulse {
  animation: modal-pulse-error 0.4s ease-out;
}

@keyframes modal-pulse-success {
  0% { box-shadow: 0 0 0 0 rgba(40, 167, 69, 0.7); }
  50% { box-shadow: 0 0 20px 10px rgba(40, 167, 69, 0.4); }
  100% { box-shadow: 0 0 0 0 rgba(40, 167, 69, 0); }
}

@keyframes modal-pulse-error {
  0% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7); }
  50% { box-shadow: 0 0 20px 10px rgba(220, 53, 69, 0.4); }
  100% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); }
}

/* Counter pop animation */
.counter-update {
  animation: counter-pop 0.2s ease-out;
}

@keyframes counter-pop {
  0% { transform: scale(1); }
  50% { transform: scale(1.2); }
  100% { transform: scale(1); }
}

/* Bag list item fade-in animation */
.bag-list-item {
  animation: bag-fade-in 0.3s ease-in;
}

@keyframes bag-fade-in {
  from {
    opacity: 0;
    transform: translateY(-5px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ========== PACK PICKER COMPONENT (FIFO Selection) ========== */

/* Fixed column widths table - ensures consistent widths across all tables.
   The pinned columns already claim 460px, so on a phone the two auto columns
   (Product, Packed In) would collapse to a single character per line. The
   min-width holds them readable and hands the overflow to the surrounding
   .table-responsive as a horizontal scroll; it stays under the modal-lg body
   width so desktop never gets a scrollbar. */
.table-fixed-columns {
  table-layout: fixed;
  width: 100%;
  min-width: 720px;
}

/* Pack picker item card */
.pack-picker-item {
  transition: all 0.2s ease;
}

.pack-picker-item:hover {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* Pack picker card spacing - override theme.css .card + .card margin */
.pack-picker-item.card + .pack-picker-item.card {
  margin-top: 0.5rem;
}

/* Pack picker collapsible header */
.pack-picker-header {
  user-select: none;
}

.pack-picker-header:hover {
  background-color: #e9ecef !important;
}

/* Chevron icon styling */
.pack-picker-chevron {
  font-size: 0.85rem;
  color: #6c757d;
}

/* Unit row styling */
.pack-picker-unit {
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.pack-picker-unit:hover {
  background-color: rgba(13, 110, 253, 0.05);
}

/* A card header that IS its own collapse control (e.g. the marketplace
   settings Connection card). The button carries `.stretched-link`, so its hit
   area is the whole header and the chevron is only the INDICATOR - the title
   and the space beside it toggle the card too. Bootstrap adds `.collapsed` to
   the trigger while the target is hidden and removes it once shown, so the
   arrow turns with no JS. */
.card-title-toggle {
  cursor: pointer;
  color: inherit;
  border: 0;
  background: none;
}

.card-title-toggle:hover,
.card-title-toggle:focus-visible {
  color: inherit;
  opacity: 0.85;
}

.card-title-toggle .fa-chevron-down {
  transition: transform 0.2s ease;
}

/* Expanded points the arrow up; Bootstrap strips `.collapsed` when it opens. */
.card-title-toggle:not(.collapsed) .fa-chevron-down {
  transform: rotate(180deg);
}

.pack-picker-unit.selected {
  background-color: rgba(13, 110, 253, 0.1) !important;
  border-left: 3px solid #0d6efd;
}

/* Priority badge (FIFO order) */
.priority-badge {
  font-size: 0.7rem;
  padding: 0.25rem 0.35rem;
  font-weight: 600;
}

/* Unit code - monospace for barcode */
.unit-code {
  font-family: 'Courier New', Courier, monospace;
  font-size: 0.85rem;
  font-weight: 600;
  color: #212529;
  background-color: #f8f9fa;
  padding: 0.15rem 0.35rem;
  border-radius: 0.25rem;
}

/* Expiry badge */
.expiry-badge {
  color: #6c757d;
  font-size: 0.75rem;
}

/* Checkbox styling */
.pack-picker-checkbox {
  cursor: pointer;
  width: 18px;
  height: 18px;
  margin-top: 0.15rem;
}

/* Spare options section */
.pack-picker-item .form-check {
  padding-left: 1.75rem;
}

.spare-quantity-input {
  width: 70px;
  text-align: center;
  margin: 0 0.25rem;
}

.spare-quantity-input:disabled {
  background-color: #e9ecef;
  cursor: not-allowed;
}

/* Selection counter in footer */
.pack-picker-selected-count {
  font-size: 1.1rem;
  font-weight: 700;
}

/* Card footer emphasis */
.pack-picker-item .card-footer {
  font-size: 0.9rem;
  font-weight: 500;
}

/* Deselected/missing pack visual indicator (Ship modal) */
.pack-picker-unit.deselected {
  opacity: 0.6;
  text-decoration: line-through;
  background-color: rgba(220, 53, 69, 0.1);
}

.pack-picker-unit.deselected .unit-code {
  text-decoration: line-through;
  color: var(--bs-danger);
}

.pack-picker-unit.deselected .pack-picker-checkbox {
  opacity: 0.5;
}

/* Badge for missing packs in Ship modal */
.pack-missing-badge {
  font-size: 0.7rem;
  padding: 0.15rem 0.4rem;
  margin-left: 0.5rem;
  background-color: var(--bs-danger);
  color: white;
  border-radius: 0.25rem;
}

/* Responsive adjustments */
@media (max-width: 768px) {
  .pack-picker-item table {
    font-size: 0.85rem;
  }

  .pack-picker-item th,
  .pack-picker-item td {
    padding: 0.5rem 0.25rem;
  }

  .priority-badge {
    font-size: 0.65rem;
    padding: 0.2rem 0.3rem;
  }

  .unit-code {
    font-size: 0.75rem;
    padding: 0.1rem 0.25rem;
  }

  .spare-quantity-input {
    width: 60px;
  }
}

/* Hide validation icon in pack qty inputs */
.pack-qty.is-invalid {
  background-image: none !important;
  padding-right: 0.2rem !important;
}

/* ============================================
   SCAN FEEDBACK - Universal Pulse Effects
   ============================================ */

/* Full-page pulse overlay for scan feedback. Base/success/error declarations are shared with
   .pulse-overlay above (BOX FILLING WORKFLOW ANIMATIONS section) - see the comment there. */
.scan-pulse-overlay.scan-pulse-warning {
  background-color: rgba(255, 193, 7, 0.3);
  opacity: 1;
}

/* Modal-scoped pulse - border glow effect */
.modal-content.scan-pulse-modal-success {
  box-shadow: 0 0 0 4px rgba(40, 167, 69, 0.7), 0 0 20px rgba(40, 167, 69, 0.5) !important;
}

.modal-content.scan-pulse-modal-error {
  box-shadow: 0 0 0 4px rgba(220, 53, 69, 0.7), 0 0 20px rgba(220, 53, 69, 0.5) !important;
}

.modal-content.scan-pulse-modal-warning {
  box-shadow: 0 0 0 4px rgba(255, 193, 7, 0.7), 0 0 20px rgba(255, 193, 7, 0.5) !important;
}

/* Duplicate Detection Modal - Vendor Form */
.duplicate-item-clickable {
  cursor: pointer;
  transition: all 0.15s ease-in-out;
  border-left: 3px solid transparent !important;
}

.duplicate-item-clickable:hover {
  background-color: #e3f2fd;
  border-color: #0d6efd !important;
  border-left: 3px solid #0d6efd !important;
}

.duplicate-item-clickable:hover .duplicate-select-icon {
  color: #0d6efd !important;
}

.duplicate-item-clickable.border-primary {
  border-left: 3px solid #0d6efd !important;
}

.duplicate-item-disabled {
  opacity: 0.7;
  background-color: #f8f9fa;
}

/* Backwards compatibility for existing hover class */
.duplicate-item-hover:hover {
  background-color: #e3f2fd;
  border-color: #0d6efd !important;
  cursor: pointer;
}

/* ========== MODAL TABS STYLING ========== */
/* Improve visibility of tabs in modals */
.modal .nav-tabs .nav-link {
  color: #495057;
  font-weight: 500;
  background-color: #f8f9fa;
  border-color: #dee2e6 #dee2e6 #fff;
}

.modal .nav-tabs .nav-link:hover {
  color: #0d6efd;
  background-color: #e9ecef;
  border-color: #dee2e6 #dee2e6 #fff;
}

.modal .nav-tabs .nav-link.active {
  color: #0d6efd;
  font-weight: 600;
  background-color: #fff;
  border-color: #dee2e6 #dee2e6 #fff;
  border-top: 3px solid #0d6efd;
}

/* Payment modal has 7 tabs (+ badge counts) that overflow the modal width.
   Keep the whole nav on ONE row: no wrap, tighter horizontal padding, and
   horizontal scroll on narrow widths instead of dropping a tab to a new line. */
#paymentTabs.nav-tabs {
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
}

#paymentTabs.nav-tabs .nav-link {
  padding-left: 0.6rem;
  padding-right: 0.6rem;
  white-space: nowrap;
}

/* ========== TAB VALIDATION ERROR INDICATORS ========== */
/* Visual indicator for tabs containing validation errors */
.modal .nav-tabs .nav-link.tab-has-error {
  color: #dc3545;
  background-color: #fff5f5;
  border-color: #f8d7da #f8d7da #fff;
}

.modal .nav-tabs .nav-link.tab-has-error:hover {
  color: #b02a37;
  background-color: #fcecec;
}

.modal .nav-tabs .nav-link.tab-has-error.active {
  color: #dc3545;
  background-color: #fff;
  border-top-width: 3px;
  border-color: #dc3545 #f8d7da #fff;
}

/* Red dot badge for tabs with errors */
.tab-error-badge {
  display: inline-block;
  width: 8px;
  height: 8px;
  background-color: #dc3545;
  border-radius: 50%;
  vertical-align: middle;
  animation: tab-error-pulse 1.5s ease-in-out infinite;
}

@keyframes tab-error-pulse {
  0%, 100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.7;
    transform: scale(1.2);
  }
}

/* Ensure invalid-feedback is visible when shown */
.modal .invalid-feedback {
  display: none;
}

.modal .is-invalid ~ .invalid-feedback,
.modal .is-invalid + .select2-container ~ .invalid-feedback {
  display: block;
}

/* ========== DATATABLE CHILD ROWS (Production Plans) ========== */
/* Hide default DataTables ::before triangle arrow */
td.dt-control::before {
  display: none !important;
}

/* Expand/collapse button column */
td.dt-control {
  cursor: pointer;
  text-align: center;
  vertical-align: middle;
}

/* Only show pointer cursor when there's an expand icon */
td.dt-control:empty {
  cursor: default;
}

td.dt-control i {
  font-size: 1.1rem;
  transition: all 0.2s ease;
}

td.dt-control:hover i {
  transform: scale(1.2);
}

/* Expanded row styling */
tr.shown td.dt-control i {
  color: #dc3545 !important;
}

/* Child row content */
tr.shown + tr > td {
  padding: 0 !important;
  background-color: #f8f9fa;
}

/* Child row cards */
tr.shown + tr .card {
  border: 1px solid #dee2e6;
  box-shadow: none;
}

tr.shown + tr .card-header {
  border-bottom: 1px solid #dee2e6;
}

tr.shown + tr .table {
  margin-bottom: 0;
}

/* Session tables in child rows */
tr.shown + tr .table-sm th,
tr.shown + tr .table-sm td {
  padding: 0.4rem 0.6rem;
}

/* Batch number code styling in child rows */
tr.shown + tr code {
  background-color: #e9ecef;
  padding: 0.15rem 0.4rem;
  border-radius: 0.25rem;
  font-size: 0.85rem;
}

/* ========== PRODUCTION PLAN EDITOR MODAL ========== */
/* Reduce margin between session cards */
#sessionsContainer .session-card:not(:first-child) {
  margin-top: 0.5rem !important;
}

#sessionsContainer .session-card {
  margin-bottom: 0.5rem !important;
}

/* Hide validation icon in narrow inputs (mobile/small screens) */
@media (max-width: 576px) {
  .form-control.is-invalid,
  .form-select.is-invalid {
    background-image: none !important;
    padding-right: 0.75rem !important;
  }
}

/* Also hide in small quantity inputs (always narrow) */
.batch-quantity-input.is-invalid {
  background-image: none !important;
  padding-right: 0.75rem !important;
}

/* ========== ATTACHMENT/RECEIPT PREVIEW AREA ========== */
/* Styles for the multiple attachment preview in transaction modal */

/* Container for attachment items */
.attachment-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: flex-start;
}

/* Individual attachment item */
.attachment-item {
  display: inline-flex;
  flex-shrink: 0;
  background-color: #f8f9fa;
  border: 1px solid #dee2e6;
  border-radius: 8px;
  transition: all 0.2s ease;
}

.attachment-item:hover {
  background-color: #e9ecef;
  border-color: #adb5bd;
}

/* Attachment icon (clickable) */
.attachment-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  min-height: 40px;
  cursor: pointer;
  transition: transform 0.15s ease;
}

.attachment-icon:hover {
  transform: scale(1.05);
}

/* Remove button on attachment */
.btn-remove-attachment {
  opacity: 0;
  transition: opacity 0.2s ease;
}

.attachment-item:hover .btn-remove-attachment {
  opacity: 1;
}

/* Add attachment button */
.btn-add-attachment {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: all 0.2s ease;
}

.btn-add-attachment:hover {
  background-color: #f8f9fa;
  border-color: #6c757d;
}

/* Receipt dropzone area */
#receiptDropZone {
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

#receiptDropZone.border-primary {
  background-color: #f0f7ff;
}

/* ========== PRODUCTION PLAN SESSIONS HIERARCHY ========== */
/* Two-level expansion: Plan -> Sessions -> Batches */

/* Cursor pointer utility for clickable rows */
.cursor-pointer {
  cursor: pointer;
}

/* Lets a flex child shrink below its content width, so a .text-truncate inside
   it truncates instead of pushing sibling columns out of the container */
.min-w-0 {
  min-width: 0;
}

/* Session row hover effect */
.plan-sessions-container .session-row:hover {
  background-color: #f8f9fa;
}

/* Session caret icon rotation */
.plan-sessions-container .session-caret {
  transition: transform 0.2s ease;
}

/* Batches container indent */
.plan-sessions-container .session-batches-row td {
  border-top: none;
}

/* ========== ORDER MODAL - STOCK QUANTITY WARNING ========== */
/* Prevent input group from wrapping - keep (stock) input x# on same line */
.pack-qty-group {
  flex-wrap: nowrap !important;
  min-width: max-content;
}

/* Over limit: Red styling for quantity inputs exceeding available stock */
.pack-qty.stock-exceeded {
  border-color: #dc3545 !important;
  background-color: #fff5f5 !important;
  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25) !important;
}

/* At limit: Yellow styling for quantity inputs at exactly available stock */
.pack-qty.stock-at-limit {
  border-color: #ffc107 !important;
  background-color: #fffbf0 !important;
  box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.25) !important;
}

/* Warning text below input */
.stock-warning-text {
  font-size: 0.7rem;
  line-height: 1.2;
  white-space: nowrap;
}

/* ========== ORDER MODAL PRODUCTS TABLE - HEADER PAGINATION ========== */
/* Pagination controls in DataTable header row */
#orderModalProductsTable_wrapper > .row.align-items-center.mb-2 {
  margin-bottom: 0.5rem !important;
}

/* Compact pagination styling in header */
#orderModalProductsTable_wrapper .dataTables_paginate {
  margin: 0;
  padding: 0;
}

#orderModalProductsTable_wrapper .dataTables_paginate .pagination {
  margin: 0;
  gap: 2px;
}

#orderModalProductsTable_wrapper .dataTables_paginate .pagination .page-link {
  padding: 0.25rem 0.5rem;
  font-size: 0.8rem;
  border-radius: 0.25rem;
}

/* Search box styling in header */
#orderModalProductsTable_wrapper .dataTables_filter {
  margin: 0;
}

#orderModalProductsTable_wrapper .dataTables_filter input {
  width: 180px;
  padding: 0.25rem 0.5rem;
  font-size: 0.85rem;
}

/* =================================================================
   Select2 Multiselect - Fix fixed height from theme.css
   ================================================================= */
.select2-container--bootstrap-5 .select2-selection--multiple,
.select2-container--bootstrap .select2-selection--multiple {
  min-height: 0 !important;
  height: auto !important;
  display: flex !important;
  flex-wrap: wrap;
  align-items: center;
  padding: 2px 4px !important;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice {
  padding: 1px 6px !important;
  margin: 2px 4px 2px 0 !important;
  font-size: 0.8rem;
  line-height: 1.4;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-search--inline {
  width: auto !important;
  flex: 0 1 auto;
  z-index: auto;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-search__field {
  height: 24px !important;
  margin: 0 !important;
}

/* =================================================================
   Order Status Filter - Select2 Multiselect Styling
   ================================================================= */

/* Container styling for the status filter */
#orderStatusFilter + .select2-container {
  min-width: 180px;
}

/* Custom "X selected" badge styling */
#orderStatusFilter + .select2-container .select2-selection__choice--custom {
  background-color: var(--bs-primary);
  color: #fff;
  border: none;
  border-radius: 0.25rem;
  padding: 0.15rem 0.5rem;
  font-size: 0.8rem;
  margin: 2px;
}

/* Ensure proper alignment with Bootstrap 5 theme */
#orderStatusFilter + .select2-container--bootstrap-5 .select2-selection--multiple {
  min-height: calc(1.5em + 0.5rem + 2px);
  padding: 0.15rem 0.25rem;
}

/* ========== BARCODE CAMERA SCANNER ========== */
#barcodeScannerOverlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: #000;
  z-index: 2000;
  display: flex;
  flex-direction: column;
}

#barcodeScannerOverlay .scanner-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.85);
  color: #fff;
  z-index: 1;
  min-height: 44px;
}

#barcodeScannerOverlay .scanner-title {
  font-size: 1.1rem;
  font-weight: 600;
}

#barcodeScannerOverlay .btn-scanner-close,
#barcodeScannerOverlay .btn-scanner-torch {
  background: none;
  border: none;
  color: #fff;
  font-size: 1.5rem;
  padding: 8px 12px;
  cursor: pointer;
  line-height: 1;
}

#barcodeScannerOverlay .btn-scanner-close:hover,
#barcodeScannerOverlay .btn-scanner-torch:hover {
  color: #ccc;
}

#barcodeScannerOverlay .btn-scanner-torch.active {
  color: #ffc107;
}

#barcodeScannerOverlay .scanner-viewfinder {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
}

#barcodeScannerReader {
  width: 100%;
  height: 100%;
}

#barcodeScannerReader > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

#barcodeScannerOverlay .scanner-guide-box {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 280px;
  height: 100px;
  border: 3px solid #fff;
  border-radius: 8px;
  pointer-events: none;
  z-index: 10;
  box-shadow: 0 0 12px rgba(0, 0, 0, 0.5), inset 0 0 12px rgba(0, 0, 0, 0.3);
}

#barcodeScannerOverlay .scanner-footer {
  padding: 16px;
  text-align: center;
  color: rgba(255, 255, 255, 0.7);
  background: rgba(0, 0, 0, 0.85);
  z-index: 1;
}

#barcodeScannerOverlay .scanner-footer p {
  margin: 0;
  font-size: 0.95rem;
}

#barcodeScannerOverlay .scanner-error {
  color: #f44336;
  font-weight: 600;
}

.scanner-flash {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(76, 175, 80, 0.4);
  z-index: 2001;
  pointer-events: none;
  animation: scanFlash 0.3s ease-out forwards;
}

@keyframes scanFlash {
  0% { opacity: 1; }
  100% { opacity: 0; }
}

.btn-camera-scan {
  cursor: pointer;
  background: #f8f9fa !important;
  border-color: #ced4da !important;
  transition: color 0.15s, background-color 0.15s;
}

.btn-camera-scan:hover {
  background: #e9ecef !important;
  color: #0d6efd;
}

/* =========================================================================
 * Dashboard preferences UI (Task #30)
 * -------------------------------------------------------------------------
 * Per-user customization: "Customize" toggle in the dashboard header enters
 * an edit mode where widgets can be hidden (red X in the top-right of every
 * card) or reordered with HTML5 drag-and-drop.
 *
 * Layout strategy:
 * - Wrappers on full-width positions (main_action_band, right_sidebar) use
 *   plain `display: block` and behave as normal containers both in and out
 *   of edit mode. The widget templates there span the full row already.
 * - Wrappers on grid positions (main_kpi_strip, main_trend_charts,
 *   main_lists) use `display: contents` in normal mode so the child widget's
 *   own `col-*` classes participate directly in the Bootstrap row grid.
 *   This keeps the pre-Task-#30 layout byte-for-byte identical at every
 *   breakpoint. In edit mode the wrapper becomes a full-width block so it
 *   can host the drag outline and the hide button; the grid visually
 *   collapses to a single stacked column, which is the explicit trade-off
 *   for having a bounding box to drag. Users exit edit mode to see their
 *   new layout in the real grid.
 * ========================================================================= */

.dashboard-widget-wrapper {
  position: relative;
}

.dashboard-widget-wrapper--grid {
  /* Transparent to Bootstrap grid in normal mode: the child widget's own
   * col-* classes become direct children of the .row parent, which is what
   * the pre-Task-#30 layout produced. */
  display: contents;
}

body.dashboard-edit-mode .dashboard-widget-wrapper {
  cursor: move;
  outline: 2px dashed #adb5bd;
  outline-offset: 4px;
  margin-bottom: 0.75rem;
  background-color: rgba(13, 110, 253, 0.02);
  transition: outline-color 0.15s ease, background-color 0.15s ease;
}

body.dashboard-edit-mode .dashboard-widget-wrapper--grid {
  /* Exit display:contents so the wrapper becomes a real box we can drag.
   * Becomes full-width (column 12) in edit mode - the user returns to the
   * real grid on "Done". */
  display: block;
  flex: 0 0 100%;
  max-width: 100%;
  width: 100%;
}

body.dashboard-edit-mode .dashboard-widget-wrapper:hover {
  outline-color: #0d6efd;
  background-color: rgba(13, 110, 253, 0.05);
}

/* Edit-mode controls overlay (hide button, drag handle hint) */
.widget-edit-controls {
  display: none;
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  z-index: 20;
  gap: 0.25rem;
  align-items: center;
}

body.dashboard-edit-mode .dashboard-widget-wrapper .widget-edit-controls {
  display: flex;
}

.widget-edit-controls .btn-hide-widget {
  background-color: #dc3545;
  color: #fff;
  border: 1px solid #b02a37;
  border-radius: 50%;
  width: 1.75rem;
  height: 1.75rem;
  line-height: 1;
  font-size: 0.9rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}

.widget-edit-controls .btn-hide-widget:hover {
  background-color: #b02a37;
}

.widget-edit-controls .widget-drag-handle {
  color: #6c757d;
  font-size: 0.9rem;
  padding: 0 0.25rem;
  pointer-events: none;
}

/* Drag feedback */
.dashboard-widget-wrapper.dragging {
  opacity: 0.4;
}

.dashboard-widget-wrapper.drag-over {
  outline-color: #0d6efd;
  outline-width: 3px;
  background-color: rgba(13, 110, 253, 0.1);
}

/* Fade-out animation when a widget is being hidden */
.dashboard-widget-wrapper.widget-hiding {
  opacity: 0;
  transform: scale(0.95);
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
}

/* DT 2.x processing indicator: position below thead (default sits over header row) */
.dt-container .dt-processing {
  position: absolute;
  top: 5% !important;
}

/* PackPicker parent/child mutual-exclusion: dim rows constrained by current selection */
.pack-picker-row-disabled { opacity: 0.45; }
.pack-picker-row-disabled .pack-picker-checkbox { pointer-events: none; }

/* ========== PRODUCTION GANTT SCHEDULE ========== */
/* Bar styles: color by machine type (set via custom_class on Frappe Gantt task) */
#ganttSvg .bar-wrapper.evt-type-mixer .bar    { fill: #e85d75; }
#ganttSvg .bar-wrapper.evt-type-divider .bar  { fill: #ffb74d; }
#ganttSvg .bar-wrapper.evt-type-shaper .bar   { fill: #26c6da; }
#ganttSvg .bar-wrapper.evt-type-press .bar    { fill: #9575cd; }
#ganttSvg .bar-wrapper.evt-type-proofer .bar  { fill: #81c784; }
#ganttSvg .bar-wrapper.evt-type-oven .bar     { fill: #ffd54f; }
#ganttSvg .bar-wrapper.evt-type-cooler .bar   { fill: #90caf9; }
#ganttSvg .bar-wrapper.evt-type-other .bar    { fill: #bdbdbd; }

/* Locked bars: darker border + subtle pattern */
#ganttSvg .bar-wrapper.evt-locked .bar {
  stroke: #212529;
  stroke-width: 2;
}

/* Conflict bars: red border + flashing outline */
#ganttSvg .bar-wrapper.evt-conflict .bar {
  stroke: #dc3545;
  stroke-width: 3;
}

#ganttSvg .bar-label {
  font-size: 11px;
  fill: #1a1a1a;
}

/* Empty / loading state */
#ganttCanvas { min-height: 320px; }

/* ========== STOCK TRANSFERS PAGE TABS ========== */
#transfersPageTabs .nav-link:not(.active) { color: #333; }

/* ========== LEGACY IMPORT - DEEP ANALYSIS ACCORDIONS ========== */
/* Bootstrap 5's default accordion renders a non-active (collapsed) header with
   a white background and only a hairline shared border, and an open header with
   a light-blue active fill. Inside this white modal body the collapsed buckets
   therefore read as flat plain-text rows: the chevron is faint and there is no
   per-section frame, so an operator cannot tell they expand. These rules make
   every bucket (outer buckets + the nested drifted rows) read as a separated,
   bordered, clearly-collapsible card regardless of open/collapsed state.
   Scoped to the two deep-analysis accordion IDs so no other accordion changes. */
#deepAnalysisAccordion.accordion,
#deepAnalysisDriftedAccordion.accordion {
  --bs-accordion-btn-icon-width: 1.1rem;
}

#deepAnalysisAccordion > .accordion-item,
#deepAnalysisDriftedAccordion > .accordion-item {
  border: 1px solid #dee2e6;
  border-radius: 0.375rem;
  margin-bottom: 0.5rem;
  overflow: hidden;
}

#deepAnalysisAccordion > .accordion-item:last-child,
#deepAnalysisDriftedAccordion > .accordion-item:last-child {
  margin-bottom: 0;
}

/* Light header fill on collapsed buckets so the clickable header stands apart
   from the white modal body (open headers keep Bootstrap's active blue fill). */
#deepAnalysisAccordion .accordion-button.collapsed,
#deepAnalysisDriftedAccordion .accordion-button.collapsed {
  background-color: #f8f9fa;
}

#deepAnalysisAccordion .accordion-button.collapsed:hover,
#deepAnalysisDriftedAccordion .accordion-button.collapsed:hover {
  background-color: #eef0f2;
}

/* Keep the chevron fully visible and pinned right. The header's inner flex row
   is w-100 with right padding (pe-3); flex-shrink:0 guarantees the ::after
   chevron always keeps its box and is never squeezed to zero by that row. */
#deepAnalysisAccordion .accordion-button::after,
#deepAnalysisDriftedAccordion .accordion-button::after {
  flex-shrink: 0;
}

/* ========== LEGACY IMPORT - DEEP ANALYSIS ORDER CONTEXT EXPANDER ========== */
/* Inline per-row "order context" strip for the phase-11 unmatched_new_creatable /
   unmatched_new_ambiguous buckets (see DEEP_ANALYSIS_CONTEXT_EXPANDER_BUCKETS in
   settings.legacy-import.js). Shades the expanded strip so the two side-by-side
   mini-tables read as attached context under the row rather than a new
   independent table row. */
#modalDeepAnalysis .deep-analysis-context-row > td {
  background-color: #f8f9fa;
  padding: 0.75rem 1rem;
}

#modalDeepAnalysis .deep-analysis-context-toggle {
  color: #6c757d;
  text-decoration: none;
}

#modalDeepAnalysis .deep-analysis-context-toggle:hover {
  color: #0d6efd;
}

#modalDeepAnalysis .deep-analysis-context-table {
  font-size: 0.8125rem;
}

/* Denser, borderless read: dropping `table-bordered` (settings.legacy-import.js)
   already removes the vertical/outer grid lines and leaves Bootstrap's default
   light per-row bottom border - this just tightens the vertical padding on top
   of `table-sm` so each order reads as one compact line instead of a boxed
   cell block. Owner request, 2026-08-25. */
#modalDeepAnalysis .deep-analysis-context-table > :not(caption) > * > * {
  padding-top: 0.2rem;
  padding-bottom: 0.2rem;
}

/* Side-by-side residual linker (residual_side_by_side bucket). Each customer
   group is a shaded card separating one customer's legacy/admin tables from the
   next, so a long list of groups stays scannable. Reuses the context-table
   styling above for the two mini-tables inside each group. */
#modalDeepAnalysis .residual-customer-group {
  padding: 0.75rem 1rem;
  background-color: #f8f9fa;
  border: 1px solid #e9ecef;
  border-radius: 0.375rem;
}

/* Stock-check close-session full-page overlay spinner. Fixed, above the Bootstrap
   modal layer (z-index ~1055) so it can be raised over the preview-confirm modal
   with no blank flash; centred spinner mirrors the modal-spinner-overlay look. */
.close-session-overlay {
  position: fixed;
  inset: 0;
  z-index: 20000;
  background: rgba(255, 255, 255, 0.9);
  align-items: center;
  justify-content: center;
}

/* Statistics recompute busy state. A localized, theme-aware cover pinned over
   the content area (KPI cards + charts) while a period / baseline change is in
   flight. Bootstrap CSS variables keep the backdrop and spinner colour in step
   with the active theme; border-radius:inherit hugs the wrapped card corners.
   Position/layout is shared with .dt-loading-overlay below (Product Flow forecast
   table busy state) - each keeps its own z-index/opacity/border-radius. */
.stats-loading-overlay,
.dt-loading-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* The statistics overlay covers a container several screens tall, so it does NOT
   inherit the shared `align-items: center` above: centring on the CONTAINER put
   the spinner far below the fold, and all the operator could see was a washed-out
   empty page that read as disabled rather than as loading. The badge is pinned to
   the top of the overlay and made `sticky`, so it sits inside the viewport on
   first paint and follows the operator down as they scroll.

   The wash is opaque enough to make "not ready" unmistakable, and the badge
   carries a VISIBLE label - a lone spinner on a page whose skeleton already shows
   grey dashes was being read as a broken page. Statistics > Customers was measured
   recomputing for tens of seconds on every load on 2026-09-19, before the server
   gained a cache backend, so this state is on screen long enough that it has to
   explain itself. How long it lasts now depends on that server rather than on
   this stylesheet; re-measure before deciding the label is no longer needed. */
.stats-loading-overlay {
  z-index: 20;
  background-color: rgba(var(--bs-body-bg-rgb, 255, 255, 255), 0.85);
  border-radius: inherit;
  align-items: flex-start;
}

/* `fixed`, NOT `sticky`, and this was measured rather than assumed. Sticky was
   tried first and does not engage here: Porto's fixed layout puts the scrolling
   box on `html.fixed`, and an ancestor between the overlay and it has a clipped
   overflow, which becomes the sticky element's scrollport and never scrolls. The
   badge stayed glued to the overlay's top edge and left the viewport at
   `scrollTop: 1800` (measured top: -1486px). Fixed holds it at 40vh at every
   scroll position, which is what the operator actually needs.

   Safe because exactly one overlay is on screen at a time - each statistics page
   covers a single content container, and show() is idempotent. If a second
   simultaneous target is ever added, two badges would stack here. */
.stats-loading-badge {
  position: fixed;
  top: 40vh;
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1.25rem;
  border-radius: 2rem;
  background-color: var(--bs-body-bg, #fff);
  box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.15);
  font-size: 0.9rem;
  color: var(--bs-body-color, #212529);
}

.stats-loading-overlay .fa-spinner {
  font-size: 1.5rem;
  color: var(--bs-primary, #0d6efd);
}

/* Qualifier badge inside a KPI card title (Statistics). Sits beside an already
   small, uppercased heading, so it needs to read smaller than Bootstrap's
   smallest badge and to center on the heading's baseline. No `fs-` utility goes
   below 1rem, hence a named class rather than an inline style repeated per
   card. */
.kpi-card-badge {
  font-size: 0.6rem;
  vertical-align: middle;
}

/* Cohort retention heatmap (Statistics > Customers). Hand-rolled CSS grid - no
   charting library in this codebase ships a heatmap primitive, and the price
   waterfall widget already set the house precedent for a hand-rolled table
   over a new dependency. Column count varies per payload (`periods`), so
   statistics.customers.js sets grid-template-columns inline per render; this
   rule only owns cell layout/typography. Retention-intensity background is
   also set inline per cell (an rgba primary-color alpha scaled to the
   retention fraction) so the CSS stays data-agnostic. Null cells (period not
   yet observable) get the FIXED grey below rather than an interpolated
   color, so "not yet observable" can never be mistaken for a low but
   measured retention value. */
.cohort-heatmap {
  display: grid;
  gap: 2px;
  font-size: 0.75rem;
}

.cohort-heatmap-header,
.cohort-heatmap-cell {
  padding: 0.4rem 0.25rem;
  text-align: center;
  border-radius: 2px;
}

.cohort-heatmap-header {
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
}

.cohort-heatmap-row-label {
  padding: 0.4rem 0.5rem;
  font-weight: 600;
  white-space: nowrap;
  text-align: left;
}

.cohort-heatmap-cell-null {
  background-color: var(--bs-secondary-bg, #e9ecef);
  color: var(--bs-secondary-color, #6c757d);
}

/* Day-of-week x week heatmap (Statistics > Sales). Same hand-rolled CSS grid
   precedent as .cohort-heatmap above, kept as a separate rule set rather than
   reused directly because this grid also carries a right-hand marginal
   column (per-weekday Total Rev / Invoices / AOV) that the cohort grid does
   not have. Column count (weeks) varies per payload, so
   statistics.sales.js sets grid-template-columns inline per render; this
   rule only owns cell layout/typography. Revenue intensity is set inline per
   cell (rgba primary-color alpha scaled against `dow.max_cell_rev`), the
   same formula the cohort heatmap and the Product Trajectory amount-cell use.
   A `null` cell (no data for that day/week) gets the FIXED grey below rather
   than a zero-intensity blue, so "no data" is never mistaken for "sold
   nothing" - a day that genuinely sold zero still renders at the lightest
   blue with its real Rp 0 figure, not grey. */
.dow-heatmap {
  display: grid;
  gap: 2px;
  font-size: 0.75rem;
}

.dow-heatmap-header,
.dow-heatmap-cell,
.dow-heatmap-margin {
  padding: 0.4rem 0.25rem;
  text-align: center;
  border-radius: 2px;
}

.dow-heatmap-header {
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
}

.dow-heatmap-row-label {
  padding: 0.4rem 0.5rem;
  font-weight: 600;
  white-space: nowrap;
  text-align: left;
}

.dow-heatmap-cell-null {
  background-color: var(--bs-secondary-bg, #e9ecef);
  color: var(--bs-secondary-color, #6c757d);
}

.dow-heatmap-margin {
  font-weight: 600;
  background-color: var(--bs-tertiary-bg, var(--bs-secondary-bg, #f1f3f5));
  white-space: nowrap;
}

/* Small colour-key dot, shared by every Statistics legend that pairs a
   colour with a label (Customers cohort heatmap intensity key, new-vs-repeat
   donut legend, concentration top-10 list; Sales day-of-week heatmap legend)
   - one swatch style instead of a per-widget copy. */
.legend-swatch {
  display: inline-block;
  width: 0.9rem;
  height: 0.9rem;
  border-radius: 2px;
  vertical-align: middle;
}

/* Product Flow forecast table: manual busy overlay for the DataTables destroy/rebuild
   cycle (data fetched via $.ajax before init, so `processing: true` never fires on
   load). Theme-aware background matches .stats-loading-overlay convention; shared
   position/layout declarations are on the combined selector above. */
.dt-loading-overlay {
  z-index: 10;
  background-color: rgba(var(--bs-body-bg-rgb, 255, 255, 255), 0.7);
}

/* Map Picker Modal: google.maps.places.PlaceAutocompleteElement is a custom element
   that renders its own internal input, so it needs an explicit block/full-width rule
   to match the surrounding Bootstrap form layout (see map-picker-modal.php/.js). */
#mapPickerSearchSlot gmp-place-autocomplete {
  display: block;
  width: 100%;
}

/* ========== PACKING SESSION V2 - BIG ROUND BUTTON ========== */
/* The round screen's one dominant control - a large, roughly square touch target for an
   operator working at arm's length with flour on their hands, rather than a wide bar.
   Shared by both buttons that occupy this same screen slot (#pv2BtnBig: Start/Next,
   btn-primary; #pv2BtnGoVerify: All groups printed - Verify, btn-success - see
   packing-v2/index.php) so the size and shape stay identical across every state; only
   the color/icon/label differ per button. clamp() keeps it a true square that shrinks
   on a narrow screen instead of overflowing. Icon stacks above the label (gap, not
   margin) so the longer "All groups printed - Verify" label wraps onto extra lines
   inside the same box instead of stretching it into a bar - .btn defaults to
   white-space: nowrap, which is what pushed that label wide before this rule. */
.pv2-btn-round {
  width: clamp(150px, 32vw, 220px);
  height: clamp(150px, 32vw, 220px);
  /* display:flex makes the button block-level, so the card body's text-center no
     longer reaches it - without this it sits hard against the left edge. */
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.5rem;
  white-space: normal;
  text-align: center;
  line-height: 1.25;
  font-size: 1.5rem;
}

/* ========== FONT AWESOME FALLBACK (body.fa-failed) ========== */
/* The detection block in layout/logged.php and layout/base.php adds .fa-failed to
   <body> when the FA kit does not load. Icon-only buttons are then unreadable, so
   the label is painted from the button's tooltip text instead.

   Three attributes carry that text, because a tooltip moves it as it initializes:
   markup ships `title`, Bootstrap parks the old value on `data-bs-original-title`
   when it takes ownership, and TooltipManager's title adoption writes
   `data-bs-title`. Matching only `title` left every tooltip-bearing button blank
   in fallback mode. Later rules win, so the freshest attribute is the one painted. */
.fa-failed .btn[title] i.fas,
.fa-failed .btn[title] i.far,
.fa-failed .btn[title] i.fab,
.fa-failed .btn[data-bs-original-title] i.fas,
.fa-failed .btn[data-bs-original-title] i.far,
.fa-failed .btn[data-bs-original-title] i.fab,
.fa-failed .btn[data-bs-title] i.fas,
.fa-failed .btn[data-bs-title] i.far,
.fa-failed .btn[data-bs-title] i.fab { display: none; }

.fa-failed .btn[title]::after { content: attr(title); font-size: 0.75rem; }
.fa-failed .btn[data-bs-original-title]::after { content: attr(data-bs-original-title); font-size: 0.75rem; }
.fa-failed .btn[data-bs-title]::after { content: attr(data-bs-title); font-size: 0.75rem; }

.fa-failed .btn[title].btn-sm::after,
.fa-failed .btn[data-bs-original-title].btn-sm::after,
.fa-failed .btn[data-bs-title].btn-sm::after { font-size: 0.65rem; }

/* Two-part action icon: a main glyph with a small glyph pinned to its lower-right corner, so one
   button reads as a variant of another. Used on the contacts list, where the invitation button is
   a paper plane on its own for a first invitation, a paper plane plus a circular arrow when the
   press resends a live invitation, and a paper plane plus a stop sign to withdraw one.
   The badge carries the button's own background so it stays legible over the main glyph. */
.btn-icon-badge {
  position: relative;
  display: inline-block;
  line-height: 1;
}

.btn-icon-badge > .btn-icon-badge-mark {
  position: absolute;
  right: -0.5em;
  bottom: -0.4em;
  font-size: 0.62em;
  line-height: 1;
  border-radius: 50%;
  background: #fff;
  padding: 0.08em;
}

/* On hover the outline button fills, so the badge must follow the filled background instead of
   staying white against it. */
.btn:hover .btn-icon-badge > .btn-icon-badge-mark,
.btn:focus .btn-icon-badge > .btn-icon-badge-mark,
.btn:active .btn-icon-badge > .btn-icon-badge-mark {
  background: transparent;
}

/* A locked pack-type size must LOOK locked.
   The size of a pack type that is already in use cannot be changed, and the modal disables the
   three inputs to say so. The theme repaints a disabled .form-control back to white, which reads
   as an ordinary editable box - the operator types, nothing happens, and the only clue is the
   warning text further up. The disabled Contains select beside them is already grey, so the row
   looked inconsistent as well as wrong. Same treatment as #payment_method:disabled above. */
.pack-type-size-group .form-control:disabled {
  background-color: #e9ecef;
  cursor: not-allowed;
}

/* Topbar task bell: two badges (personal + team counts, topbar-task-bell.js). The theme's
   `.notifications > li .notification-icon .badge` rule positions every `.badge` inside the
   bell icon at the SAME absolute spot (top-right), so with two badges present the second
   would render directly on top of the first. Pin the team badge to the icon's top-left
   corner instead, leaving the personal badge at the theme's default top-right. */
#topbar-task-badge-team {
  right: auto;
  left: -8px;
}

/* Compact date range (opt-in via $extraWrapClass = 'input-daterange-compact' on
   components/_date-range-picker.php). A text input defaults to ~20 characters of width, so a
   dd/mm/yyyy value sat in a box far wider than itself; size each input to the date instead. */
.input-daterange-compact {
  width: auto;
  flex-wrap: nowrap;
}
.input-daterange-compact > .form-control {
  flex: 0 0 auto;
  width: 6.25rem;
  min-width: 0;
  padding-left: 0.4rem;
  padding-right: 0.4rem;
  text-align: center;
}
