/* ============================================================================
   SupplyIQ Design System
   ----------------------------------------------------------------------------
   One shared visual language for all five SupplyIQ web applications (Website,
   Brand, Distributor, Master Distributor, Superadmin).

   Loaded AFTER tabler.min.css and custom.css, BEFORE each portal's theme.css.
   Like custom.css this file is deliberately ACCENT-AGNOSTIC: every portal
   keeps its own --tblr-primary from its theme.css (Brand indigo, Distributor
   teal, MD amber, Superadmin pink) and this system reads that variable rather
   than hardcoding a colour. That is what makes the platform look like one
   product while each role stays instantly identifiable.

   Design intent (mission S2): modern, professional, clean, enterprise, fast,
   trustworthy. A serious B2B distribution operating platform -- NOT a
   consumer shopping UI. No decorative gradients, no oversized type, no
   animation for its own sake.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   1. DESIGN TOKENS
   Single source of truth -- now in supplyiq-tokens.css so the Framework7
   mobile layer can consume the SAME block without loading any Tabler-coupled
   component rules from this file (2026-08-25 mobile-PWA mission). @import is
   valid here because this was the file's first rule: only comments precede
   it. Existing pages keep their single <link> to this file and are unchanged.
   --------------------------------------------------------------------------- */
@import url('supplyiq-tokens.css?v=1');

/* ---------------------------------------------------------------------------
   2. BASE
   --------------------------------------------------------------------------- */
body {
  background: var(--sq-surface-sunken);
  color: var(--sq-text);
  -webkit-text-size-adjust: 100%;   /* stop iOS Safari inflating text in landscape */
}

/* S16: nothing may ever scroll the page sideways. Belt and braces -- the
   real fixes are per-component below; this only stops a stray wide child
   from taking the whole document with it. */
html,
body {
  max-width: 100%;
  overflow-x: hidden;
}

/* S14: a visible, consistent focus ring everywhere, replacing Tabler's
   inconsistent per-component treatment. :focus-visible so it appears for
   keyboard users without ringing on every mouse click. */
a:focus-visible,
button:focus-visible,
[role='button']:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
.form-control:focus-visible,
.form-select:focus-visible {
  outline: 2px solid var(--tblr-primary);
  outline-offset: 2px;
  border-radius: var(--sq-radius-sm);
}

/* S15: respect the OS "reduce motion" setting rather than animating anyway. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------------------------------------
   3. CARD / SURFACE
   --------------------------------------------------------------------------- */
.card,
.sq-card {
  background: var(--sq-surface);
  border: 1px solid var(--sq-border);
  border-radius: var(--sq-radius);
  box-shadow: var(--sq-shadow-sm);
}

.sq-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sq-space-3);
  padding: var(--sq-space-4) var(--sq-space-5);
  border-bottom: 1px solid var(--sq-border);
}

.sq-card-title {
  font-size: var(--sq-font-md);
  font-weight: 600;
  margin: 0;
  color: var(--sq-text);
}

.sq-card-body {
  padding: var(--sq-space-5);
}

/* Section heading used between blocks on a dashboard */
.sq-section-title {
  font-size: var(--sq-font-sm);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--sq-text-subtle);
  margin: var(--sq-space-6) 0 var(--sq-space-3);
}

.sq-section-title:first-child {
  margin-top: 0;
}

/* ---------------------------------------------------------------------------
   4. KPI / STAT TILE  (S8 dashboards)
   Deliberately compact -- S2 forbids "large unnecessary cards".
   --------------------------------------------------------------------------- */
.sq-kpi-grid {
  display: grid;
  gap: var(--sq-space-3);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}

.sq-kpi {
  display: flex;
  align-items: flex-start;
  gap: var(--sq-space-3);
  padding: var(--sq-space-4);
  background: var(--sq-surface);
  border: 1px solid var(--sq-border);
  border-radius: var(--sq-radius);
  box-shadow: var(--sq-shadow-sm);
  text-decoration: none;
  color: inherit;
  min-width: 0;
  transition: border-color 0.15s var(--sq-ease), box-shadow 0.15s var(--sq-ease);
}

/* Only KPI tiles that actually navigate get affordance (many are inert). */
a.sq-kpi:hover,
a.sq-kpi:focus-visible {
  border-color: var(--tblr-primary);
  box-shadow: var(--sq-shadow);
}

.sq-kpi-icon {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: var(--sq-radius-sm);
  background: rgba(var(--tblr-primary-rgb), 0.12);
  color: var(--sq-accent-ink);
  font-size: 1.15rem;
}

/* The tile is rendered with <span> children so it can be wrapped in an <a>
   without nesting block elements inside an inline anchor -- so each part is
   promoted to a block here. */
.sq-kpi-body {
  min-width: 0;
  display: block;
}

.sq-kpi-label {
  display: block;
  font-size: var(--sq-font-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--sq-text-subtle);
  line-height: 1.3;
}

.sq-kpi-value {
  display: block;
  font-size: var(--sq-font-xl);
  font-weight: 700;
  line-height: 1.2;
  color: var(--sq-text);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;      /* long currency never widens the grid */
}

.sq-kpi-meta {
  display: block;
  font-size: var(--sq-font-xs);
  color: var(--sq-text-muted);
  line-height: 1.3;
}

/* ---------------------------------------------------------------------------
   4b. LEGACY KPI CLASSES -> same visual language  (S20)
   Three KPI variants predate this design system and are each rendered by
   working dashboard JS: `.kpi-card` (Brand + Distributor dashboards),
   `.admin-kpi-card` (Superadmin) and `.stat-card` (older pages). The Master
   Distributor dashboard already uses the shared renderStatsRow().

   Rewriting three working dashboards' JS to emit .sq-kpi would be a large,
   risky diff for a purely visual gain, and S17 requires those dashboards keep
   working. Instead the legacy classes are normalised onto the same tokens
   here -- identical type scale, border, radius, elevation and icon treatment
   as .sq-kpi -- so all five applications read as one product (S2/S20) with no
   markup or behaviour change. Their extra affordances (the Brand trend line,
   Superadmin's is-unavailable state) are preserved, not flattened.
   --------------------------------------------------------------------------- */
/* The Superadmin selectors are qualified with .card (and the value/label with
   their parent) purely for specificity: admin.css is linked AFTER this file on
   those pages, so an equal-specificity rule here would lose the tie. */
.kpi-card,
.card.admin-kpi-card,
.stat-card {
  border: 1px solid var(--sq-border);
  border-radius: var(--sq-radius);
  box-shadow: var(--sq-shadow-sm);
  background: var(--sq-surface);
}

.admin-kpi-card .admin-kpi-value {
  font-size: var(--sq-font-xl);
  font-weight: 700;
  line-height: 1.2;
  color: var(--sq-text);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
  margin: 0;
}

.admin-kpi-card .admin-kpi-label {
  font-size: var(--sq-font-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--sq-text-subtle);
  line-height: 1.3;
}

.admin-kpi-card .admin-kpi-icon {
  width: 38px;
  height: 38px;
  border-radius: var(--sq-radius-sm);
  font-size: 1.15rem;
}

.kpi-card .card-body,
.admin-kpi-card .card-body,
.stat-card .card-body {
  /* The old 140px floor made these tiles far taller than they needed to be;
     S2 explicitly rules out "large unnecessary cards". */
  min-height: 0;
  padding: var(--sq-space-4);
  gap: var(--sq-space-3);
}

.kpi-card-value,
.stat-value {
  font-size: var(--sq-font-xl);
  font-weight: 700;
  line-height: 1.2;
  color: var(--sq-text);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
  margin: 0;
}

.kpi-card-label,
.stat-label {
  font-size: var(--sq-font-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--sq-text-subtle);
  line-height: 1.3;
}

.kpi-card-trend {
  font-size: var(--sq-font-xs);
  font-weight: 600;
  line-height: 1.3;
}

.kpi-card-trend.up { color: var(--sq-success); }
.kpi-card-trend.down { color: var(--sq-danger); }
.kpi-card-trend.neutral { color: var(--sq-text-muted); }

.stat-icon,
.admin-kpi-icon {
  width: 38px;
  height: 38px;
  border-radius: var(--sq-radius-sm);
  background: rgba(var(--tblr-primary-rgb), 0.12);
  color: var(--sq-accent-ink);
  font-size: 1.15rem;
}

/* Hover affordance matched to .sq-kpi: a border tint, not a lift. A
   translateY on a grid of tiles reads as consumer-app decoration (S2). */
.admin-kpi-card:hover,
a.stat-card-clickable:hover,
a.kpi-card:hover {
  transform: none;
  border-color: var(--tblr-primary);
  box-shadow: var(--sq-shadow);
}

/* ---------------------------------------------------------------------------
   5. STATUS PILLS  (S10 order status, S11 return status)
   Tinted surface + readable foreground, never colour alone.
   --------------------------------------------------------------------------- */
.sq-status {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.2em 0.65em;
  border-radius: var(--sq-radius-pill);
  font-size: var(--sq-font-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: capitalize;
  white-space: nowrap;
  background: var(--sq-neutral-bg);
  color: var(--sq-neutral);
}

.sq-status::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}

.sq-status--pending {
  background: var(--sq-warning-bg);
  color: var(--sq-warning);
}

.sq-status--approved,
.sq-status--modified {
  background: var(--sq-info-bg);
  color: var(--sq-info);
}

.sq-status--fulfilled,
.sq-status--completed,
.sq-status--delivered {
  background: var(--sq-success-bg);
  color: var(--sq-success);
}

.sq-status--cancelled,
.sq-status--rejected {
  background: var(--sq-danger-bg);
  color: var(--sq-danger);
}

.sq-status--active {
  background: var(--sq-success-bg);
  color: var(--sq-success);
}

.sq-status--inactive {
  background: var(--sq-neutral-bg);
  color: var(--sq-neutral);
}

/* Existing Tabler status badges are spread across many pages as
   `badge bg-*-lt`. Rather than rewrite every one of those call sites (a large
   diff over working pages), they are mapped onto the same semantic palette as
   .sq-status here, so status reads identically platform-wide (S10/S12). New
   code should call statusBadge() from shell.js instead. */
.badge.bg-yellow-lt,
.badge.bg-orange-lt {
  background: var(--sq-warning-bg) !important;
  color: var(--sq-warning) !important;
}

.badge.bg-green-lt,
.badge.bg-teal-lt,
.badge.bg-success-lt {
  background: var(--sq-success-bg) !important;
  color: var(--sq-success) !important;
}

.badge.bg-red-lt,
.badge.bg-danger-lt {
  background: var(--sq-danger-bg) !important;
  color: var(--sq-danger) !important;
}

.badge.bg-blue-lt,
.badge.bg-azure-lt,
.badge.bg-primary-lt,
.badge.bg-purple-lt {
  background: var(--sq-info-bg) !important;
  color: var(--sq-info) !important;
}

.badge.bg-secondary-lt {
  background: var(--sq-neutral-bg) !important;
  color: var(--sq-neutral) !important;
}

.badge {
  border-radius: var(--sq-radius-pill);
  font-size: var(--sq-font-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 0.25em 0.7em;
}

/* ---------------------------------------------------------------------------
   6. BUTTONS  (S13 touch targets, S14 button sizes)
   --------------------------------------------------------------------------- */
.btn {
  border-radius: var(--sq-radius-sm);
  font-weight: 600;
  font-size: var(--sq-font-base);
}

/* Any interactive control must clear the 44px touch floor.
   Keyed on BOTH a coarse pointer and the mobile breakpoint: pointer:coarse
   alone misses touch-capable laptops and hybrid devices, and cannot be
   exercised at all when auditing a narrow viewport on a desktop browser --
   which is exactly where these targets get checked. Desktop mouse users at
   >=768px keep the original compact density. */
@media (pointer: coarse), (max-width: 767.98px) {
  .btn,
  .form-control,
  .form-select,
  .nav-link,
  .dropdown-item {
    min-height: var(--sq-touch);
  }

  .btn-icon {
    min-width: var(--sq-touch);
  }

  /* .btn-sm is used for row actions (edit / message / cancel) and its own
     padding keeps it near 26px tall, under the floor above. On a phone those
     are the primary way to act on an order, so they get real targets. */
  .btn-sm {
    min-height: var(--sq-touch);
    min-width: var(--sq-touch);
    padding-inline: var(--sq-space-3);
    font-size: var(--sq-font-sm);
  }

  /* An icon-only .btn-sm should stay square rather than stretch. */
  .btn-sm:has(> i:only-child) {
    padding-inline: 0;
  }

  /* Pagination comes from the shared renderPaginationNav() helper, so its
     buttons are 32px on every list page in all five apps until fixed here. */
  .page-link {
    min-height: var(--sq-touch);
    min-width: var(--sq-touch);
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

/* ---------------------------------------------------------------------------
   7. TABLES -> responsive cards  (S7.4, S13, S16)
   The single largest mobile-overflow source: 66 raw <table> elements.
   Desktop keeps a real table. Below the md breakpoint each row becomes a card
   and each cell shows its column name from the data-label written by
   shared/js/responsive-table.js -- so no per-page HTML edits are needed.
   --------------------------------------------------------------------------- */
.table {
  font-size: var(--sq-font-base);
  color: var(--sq-text);
}

.table thead th {
  font-size: var(--sq-font-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--sq-text-subtle);
  background: var(--sq-surface-sunken);
  border-bottom: 1px solid var(--sq-border-strong);
  white-space: nowrap;
}

.table tbody td {
  vertical-align: middle;
}

/* Money/quantity columns line up digit-for-digit (S10). */
.table td.sq-num,
.table th.sq-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Desktop-side safety: a wide table scrolls INSIDE its own wrapper rather
   than pushing the page sideways. */
.sq-table-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

@media (max-width: 767.98px) {
  .sq-table-responsive {
    border: 0;
  }

  .sq-table-responsive thead {
    display: none;              /* labels move into each cell */
  }

  .sq-table-responsive tbody,
  .sq-table-responsive tr,
  .sq-table-responsive td {
    display: block;
    width: 100%;
  }

  .sq-table-responsive tr {
    background: var(--sq-surface);
    border: 1px solid var(--sq-border);
    border-radius: var(--sq-radius);
    box-shadow: var(--sq-shadow-sm);
    margin-bottom: var(--sq-space-3);
    padding: var(--sq-space-2) var(--sq-space-3);
  }

  .sq-table-responsive td {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sq-space-4);
    padding: var(--sq-space-2) 0;
    border: 0;
    border-bottom: 1px solid var(--sq-border);
    text-align: left !important;
    min-height: 0;
  }

  .sq-table-responsive tr td:last-child {
    border-bottom: 0;
  }

  .sq-table-responsive td::before {
    content: attr(data-label);
    flex: 0 0 40%;
    font-size: var(--sq-font-xs);
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--sq-text-subtle);
  }

  /* A cell with no label (usually the actions column) spans the full width
     and right-aligns its buttons. */
  .sq-table-responsive td[data-label='']::before {
    display: none;
  }

  .sq-table-responsive td[data-label=''] {
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: var(--sq-space-2);
  }

  /* Empty-state / colspan rows must not be turned into a labelled card. */
  .sq-table-responsive td[colspan]::before {
    display: none;
  }

  .sq-table-responsive td[colspan] {
    justify-content: center;
    text-align: center !important;
  }
}

/* ---------------------------------------------------------------------------
   8. FORMS  (S13)
   --------------------------------------------------------------------------- */
.form-label {
  font-size: var(--sq-font-sm);
  font-weight: 600;
  color: var(--sq-text);
  margin-bottom: var(--sq-space-1);
}

.form-control,
.form-select {
  border-radius: var(--sq-radius-sm);
  border-color: var(--sq-border-strong);
  font-size: var(--sq-font-base);
  color: var(--sq-text);
}

.form-control:focus,
.form-select:focus {
  border-color: var(--tblr-primary);
  box-shadow: 0 0 0 3px rgba(var(--tblr-primary-rgb), 0.15);
}

.form-hint {
  font-size: var(--sq-font-xs);
  color: var(--sq-text-muted);
}

.invalid-feedback,
.sq-field-error {
  display: block;
  font-size: var(--sq-font-xs);
  font-weight: 600;
  color: var(--sq-danger);
  margin-top: var(--sq-space-1);
}

/* Mobile: forms collapse to a single column and inputs hit 16px so iOS
   Safari does not zoom the viewport on focus (a real horizontal-overflow
   trigger, not a cosmetic detail). */
@media (max-width: 767.98px) {
  .sq-form-grid,
  .row.sq-form-row > [class*='col-'] {
    width: 100% !important;
    flex: 0 0 100% !important;
    max-width: 100% !important;
  }

  .form-control,
  .form-select,
  textarea.form-control {
    font-size: 16px;
  }
}

/* ---------------------------------------------------------------------------
   8b. PHOTO / FILE UPLOAD  (S11 return photo, S13 mobile-friendly image upload)
   The return-photo field is the one place a user is expected to submit a
   picture from a phone, standing in a warehouse looking at damaged goods.
   A default <input type="file"> renders there as a small grey button with a
   truncated filename -- technically working, but a poor target and no
   indication of what it wants. These rules restyle the existing input in
   place: no markup change, so the Mission 1 upload behaviour (validation,
   POST /api/returns/{id}/photo, 5MB limit) is untouched.
   --------------------------------------------------------------------------- */
input[type='file'].form-control {
  padding: var(--sq-space-3);
  border: 1px dashed var(--sq-border-strong);
  border-radius: var(--sq-radius);
  background: var(--sq-surface-sunken);
  color: var(--sq-text-muted);
  font-size: var(--sq-font-sm);
  cursor: pointer;
  min-height: var(--sq-touch);
}

input[type='file'].form-control:hover,
input[type='file'].form-control:focus {
  border-color: var(--tblr-primary);
  background: var(--sq-surface);
}

/* The native "Choose file" button itself -- a real, comfortable target
   rather than the browser default. */
input[type='file'].form-control::file-selector-button {
  margin-right: var(--sq-space-3);
  padding: 0.5rem 0.9rem;
  border: 0;
  border-radius: var(--sq-radius-sm);
  background: var(--tblr-primary);
  color: #fff;
  font-weight: 600;
  font-size: var(--sq-font-sm);
  cursor: pointer;
  min-height: 36px;
}

/* Feedback line under the photo field: type rejection, "we'll reduce it
   automatically", the final size, or a compression failure. Sits directly
   under the input so the message is where the user is already looking, and is
   aria-live so it is announced rather than silently appearing. */
.sq-photo-status {
  margin-top: var(--sq-space-2);
  font-size: var(--sq-font-sm);
  font-weight: 500;
  line-height: 1.4;
  display: flex;
  align-items: flex-start;
  gap: var(--sq-space-2);
  padding: var(--sq-space-2) var(--sq-space-3);
  border-radius: var(--sq-radius-sm);
}

.sq-photo-status::before {
  font-weight: 700;
  flex: 0 0 auto;
}

.sq-photo-status--info {
  background: var(--sq-info-bg);
  color: var(--sq-info);
}

.sq-photo-status--info::before {
  content: '\2026';           /* ellipsis - work in progress */
}

.sq-photo-status--ok {
  background: var(--sq-success-bg);
  color: var(--sq-success);
}

.sq-photo-status--ok::before {
  content: '\2713';           /* check */
}

.sq-photo-status--error {
  background: var(--sq-danger-bg);
  color: var(--sq-danger);
}

.sq-photo-status--error::before {
  content: '\26A0';           /* warning */
}

/* Chosen-photo preview (create form) and stored photo evidence (detail view).
   Both are constrained by max-width so a large phone photo can never widen
   the layout (S16). */
#return-photo-preview img,
.sq-photo-evidence img {
  display: block;
  width: 100%;
  max-width: 320px;
  height: auto;
  border-radius: var(--sq-radius);
  border: 1px solid var(--sq-border);
  background: var(--sq-surface-sunken);
}

@media (max-width: 767.98px) {
  /* On a phone the preview goes full-bleed within the form: the whole point
     is to confirm the right photo was captured before submitting. */
  #return-photo-preview img,
  .sq-photo-evidence img {
    max-width: 100%;
    max-height: 60vh;
    object-fit: contain;
  }

  input[type='file'].form-control {
    padding: var(--sq-space-4);
    font-size: 16px;               /* no iOS zoom-on-focus */
  }

  input[type='file'].form-control::file-selector-button {
    min-height: var(--sq-touch);
    padding: 0.6rem 1rem;
  }
}

/* ---------------------------------------------------------------------------
   9. MODALS  (S13 "modal dialogs must fit the viewport")
   --------------------------------------------------------------------------- */
.modal-content {
  border: 0;
  border-radius: var(--sq-radius-lg);
  box-shadow: var(--sq-shadow-lg);
  max-height: calc(100dvh - 2rem);
}

.modal-header {
  border-bottom: 1px solid var(--sq-border);
}

.modal-footer {
  border-top: 1px solid var(--sq-border);
  gap: var(--sq-space-2);
}

.modal-title {
  font-size: var(--sq-font-md);
  font-weight: 700;
}

/* Never taller than the viewport: the body scrolls, header/footer pin. */
.modal-dialog {
  max-width: min(100% - 1rem, 42rem);
}

.modal-body {
  overflow-y: auto;
}

@media (max-width: 767.98px) {
  /* Sheet-style on phones: full width, anchored to the bottom, thumb-reachable
     actions -- an app pattern rather than a shrunken desktop dialog (S4). */
  .modal-dialog {
    margin: 0;
    max-width: 100%;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
  }

  /* Most dialogs in these portals use .modal-dialog-centered, whose
     `min-height: calc(100% - 1rem)` + flex centering re-centres the panel
     inside the fixed dialog -- leaving the "sheet" floating with a gap
     beneath it instead of sitting on the bottom edge. Collapse the dialog to
     its content height so the sheet is actually flush to the bottom. */
  .modal-dialog.modal-dialog-centered {
    min-height: 0;
    align-items: flex-end;
  }

  .modal-content {
    border-radius: var(--sq-radius-lg) var(--sq-radius-lg) 0 0;
    max-height: 92dvh;
  }

  .modal-footer {
    padding-bottom: max(var(--sq-space-4), env(safe-area-inset-bottom));
  }

  .modal-footer .btn {
    flex: 1 1 auto;
  }
}
