/* SGB-CUSTOMER-PORTAL-LOCAL-V1-001 Phase 1B-UI-R1
   Design tokens + shared components. Plain CSS, no build step, no
   framework. Saigonbay navy stays the brand primary (matches the
   existing login identity); tokens below only formalize it into a
   reusable system rather than one-off hex values per template. */

@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400&display=swap');

:root {
  color-scheme: light;

  /* Brand */
  --color-navy-900: #0b3d66;
  --color-navy-700: #12588f;
  --color-navy-500: #1b76b8;

  /* Semantic surface/text tokens */
  --color-primary: var(--color-navy-900);
  --color-primary-hover: var(--color-navy-700);
  --color-on-primary: #ffffff;

  --color-background: #f4f6f9;
  --color-surface: #ffffff;
  --color-surface-muted: #eef1f6;

  --color-text: #1e2a38;
  --color-text-muted: #5b6b7f;
  --color-text-faint: #94a3b8;

  --color-border: #e3e8ef;
  --color-border-strong: #c9d2de;

  --color-destructive: #b3261e;
  --color-destructive-bg: #fdecea;
  --color-destructive-border: #f5c6c3;

  --color-focus-ring: #1b76b8;

  /* Spacing scale (8 / 12 / 16 core, with a couple of extremes) */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;

  /* Radius / elevation, restrained */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --shadow-sm: 0 1px 2px rgba(15, 32, 55, 0.06);
  --shadow-md: 0 4px 16px rgba(15, 32, 55, 0.08);

  --sidebar-width: 248px;
  --sidebar-width-collapsed: 64px;
  --header-height: 64px;

  --font-sans: "Plus Jakarta Sans", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-sans);
  background: var(--color-background);
  color: var(--color-text);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

button, input {
  font-family: inherit;
  font-size: inherit;
}

/* ---------- App shell: sidebar + header + main ---------- */

.app-shell {
  display: flex;
  min-height: 100dvh;
}

.sidebar {
  width: var(--sidebar-width);
  flex-shrink: 0;
  background: var(--color-primary);
  color: rgba(255, 255, 255, 0.92);
  display: flex;
  flex-direction: column;
  padding: var(--space-5) 0;
  position: fixed;
  inset: 0 auto 0 0;
  z-index: 40;
  transition: transform 0.2s ease;
}

.sidebar-brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding: 0 var(--space-5) var(--space-5);
}

/* TASK-SGB-PORTAL-LOGO-FIT-LOCAL-002: the official logo (2029x441,
   ~4.6:1, provided at app/static/img/logo.png) has a WHITE background,
   so it sits inside its own small white, lightly-rounded frame rather
   than directly on the navy sidebar (a transparent-looking white
   rectangle floating on navy reads as a rendering bug, not a brand
   mark). Sidebar content width is exactly 248px sidebar - 2*24px
   (--space-5) padding = 200px, which is also this frame's required
   width -- it fills the row on its own; the subtitle + collapse toggle
   moved to their own row below (sidebar-brand-footer) since there is no
   remaining horizontal room beside a 200px-wide frame. */
.brand-logo-frame {
  width: 200px;
  max-width: 100%;
  height: 50px;
  box-sizing: border-box;
  padding: 2px var(--space-2);
  background: #ffffff;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.brand-logo-img {
  width: 100%;
  height: auto;
  max-width: 200px;
  max-height: 46px;
  object-fit: contain;
  display: block;
}

/* Shown ONLY if the <img> above fails to load (see its onerror handler
   in base.html) -- never simultaneously with the image, per this task's
   own "no duplicated SAIGONBAY line" rule. Dark text because it now
   lives inside the white frame, not directly on the navy sidebar. */
.brand-fallback-text {
  color: var(--color-primary);
  font-weight: 800;
  font-size: 17px;
  letter-spacing: 0.4px;
}

.sidebar-brand .sub {
  display: block;
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.2px;
  color: rgba(255, 255, 255, 0.65);
}

.sidebar-brand-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
}

/* TASK-SGB-PORTAL-LOGO-FIT-LOCAL-002: the collapsed sidebar (64px) never
   squeezes the 4.6:1 wide logo down -- it would be illegibly thin. A
   compact ~40x40 mark is shown instead. No separate cropped mark asset
   was provided and this logo's own "SaigonBay" oval isn't square (it is
   itself wider than tall), so cropping it here would risk slicing the
   text/star at an arbitrary, unreviewed boundary -- per this task's own
   explicit fallback rule, plain "SB" text is used instead of a blind
   crop. Hidden by default, shown only in the collapsed state below. */
.brand-mark {
  display: none;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  background: #ffffff;
  color: var(--color-primary);
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.5px;
  text-align: center;
  line-height: 40px;
}

.sidebar-collapse-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: transparent;
  color: rgba(255, 255, 255, 0.85);
  cursor: pointer;
}
.sidebar-collapse-toggle:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }

.sidebar-collapse-toggle .collapse-icon {
  transition: transform 0.2s ease;
}

.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: 0 var(--space-3);
  flex: 1;
  overflow-y: auto;
}

.sidebar-section-gap { height: var(--space-4); }

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: rgba(255, 255, 255, 0.85);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  min-height: 40px;
}

.nav-item svg { flex-shrink: 0; opacity: 0.9; }

.nav-item:hover { background: rgba(255, 255, 255, 0.08); color: #fff; }

.nav-item.active {
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
}

.nav-item.disabled {
  color: rgba(255, 255, 255, 0.42);
  cursor: default;
}
.nav-item.disabled:hover { background: transparent; }

.nav-badge {
  margin-left: auto;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.3px;
  padding: 2px 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.14);
  color: rgba(255, 255, 255, 0.75);
  white-space: nowrap;
}

.sidebar-footer {
  padding: var(--space-3) var(--space-3) 0;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  margin-top: var(--space-3);
}

.sidebar-footer form { margin: 0; }

.sidebar-footer button.nav-item {
  width: 100%;
  border: none;
  background: transparent;
  cursor: pointer;
  text-align: left;
}
.sidebar-footer button.nav-item:hover { background: rgba(255, 255, 255, 0.08); }

.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(11, 20, 33, 0.45);
  z-index: 35;
}

/* ---------- Sidebar collapsed state (desktop only) ----------
   TASK-SGB-PORTAL-UI-SIDEBAR-RESIZE-LOCAL-001. Toggled as a class on
   <html> (not .app-shell/.sidebar directly) so both .sidebar and
   .main-column can react from the same single source of truth with no
   inline styles/JS-computed widths. .main-column is already `flex: 1`
   with no fixed width of its own (see below) -- shrinking .sidebar's
   width and matching .main-column's margin-left is the ONLY change
   needed for the content area (including the intake grid/table, which
   is width:100% of its own scroll container) to actually reclaim the
   freed space; no separate "expand panel" logic is needed anywhere
   downstream. Scoped to the >1023px desktop layout only (see the
   existing @media (max-width: 1023px) block further down) -- on mobile
   the sidebar is already an off-canvas overlay via .is-open/.menu-toggle,
   a completely separate, untouched mechanism. */
html.sgb-sidebar-collapsed .sidebar { width: var(--sidebar-width-collapsed); }
html.sgb-sidebar-collapsed .main-column { margin-left: var(--sidebar-width-collapsed); }

/* TASK-SGB-PORTAL-LOGO-FIT-LOCAL-002: the full-width logo frame never
   squeezes into 64px -- it's hidden entirely and the 40x40 .brand-mark
   badge is shown instead. Toggle button drops to its own centered row
   below the mark, since there's no room beside a 40px badge at this
   width either. Same single button element throughout, just re-flowed,
   never duplicated. */
html.sgb-sidebar-collapsed .sidebar-brand {
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2) var(--space-3);
}
html.sgb-sidebar-collapsed .brand-logo-frame { display: none; }
html.sgb-sidebar-collapsed .brand-mark { display: block; }
html.sgb-sidebar-collapsed .sidebar-brand-footer {
  flex-direction: column;
  justify-content: center;
  gap: var(--space-2);
}
html.sgb-sidebar-collapsed .sidebar-brand-footer .sub { display: none; }
html.sgb-sidebar-collapsed .sidebar-collapse-toggle .collapse-icon { transform: rotate(180deg); }

html.sgb-sidebar-collapsed .nav-item { justify-content: center; padding-left: 0; padding-right: 0; }
html.sgb-sidebar-collapsed .nav-item > span { display: none; }

/* ---------- Main column ---------- */

.main-column {
  margin-left: var(--sidebar-width);
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.topbar {
  height: var(--header-height);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--space-5);
  position: sticky;
  top: 0;
  z-index: 20;
}

.topbar-left {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.menu-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
}
.menu-toggle:hover { background: var(--color-surface-muted); }

.topbar-identity {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.identity-badge {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border-radius: 999px;
  background: var(--color-surface-muted);
  color: var(--color-text);
  font-size: 13px;
  font-weight: 600;
}
.identity-badge svg { color: var(--color-text-muted); }

main.page {
  padding: var(--space-6) var(--space-5) var(--space-7);
  max-width: 1120px;
  width: 100%;
  margin: 0 auto;
}

/* Intake is a data-entry workspace, not a narrow reading column -- give
   it the full available width instead of the 1120px dashboard cap. */
main.page.page-wide {
  max-width: none;
}

/* ---------- Page header ---------- */

.page-header h1 {
  font-size: 24px;
  font-weight: 700;
  margin: 0 0 var(--space-1);
  color: var(--color-text);
}

.page-header p {
  margin: 0 0 var(--space-5);
  color: var(--color-text-muted);
  font-size: 14px;
}

.page-header-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

/* ---------- Account profile (TASK-SGB-PORTAL-ACCOUNT-PROFILE-UX-LOCAL-001) ----------
   Superseded the old flat .tracking-card-row list on /account (values
   pushed hard against the right edge via justify-content: space-between,
   fine for a compact tracking card but wrong for a full profile page).
   Fields below stack label above value instead -- always left-aligned,
   long company names/addresses wrap naturally, never truncated. */

.profile-header-card {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-5);
  margin-bottom: var(--space-5);
}

/* Same real logo asset + onerror-to-initials fallback already
   established for the sidebar brand (TASK-SGB-PORTAL-LOGO-FIT-LOCAL-
   001/002) -- reused verbatim here, not a second logo mechanism. White
   background because the source PNG itself has a white background
   (same reasoning as the sidebar's own logo frame). */
.profile-header-logo {
  width: 64px;
  height: 64px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: #ffffff;
  border: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.profile-header-logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 6px;
  box-sizing: border-box;
}
.profile-header-logo-fallback {
  font-weight: 800;
  font-size: 20px;
  letter-spacing: 0.5px;
  color: var(--color-primary);
}

.profile-header-info { min-width: 0; }
.profile-header-name {
  font-size: 20px;
  font-weight: 700;
  color: var(--color-text);
  overflow-wrap: break-word;
  margin-bottom: var(--space-1);
}
.profile-header-meta {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  font-size: 13px;
}
.profile-header-code { color: var(--color-text-muted); }
.profile-header-code.is-empty { color: var(--color-text-faint); }

.profile-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5);
  margin-bottom: var(--space-5);
  align-items: start;
}

.profile-group-card { padding: var(--space-5); }
.profile-group-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--color-text);
  margin: 0 0 var(--space-4);
}

.profile-field { margin-bottom: var(--space-4); }
.profile-field:last-child { margin-bottom: 0; }
.profile-field-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin-bottom: 4px;
}
.profile-field-value {
  display: block;
  font-size: 15px;
  color: var(--color-text);
  overflow-wrap: break-word;
}
.profile-field-value.is-empty { color: var(--color-text-faint); }

.profile-security-card .profile-group-title { margin-bottom: var(--space-4); }

@media (max-width: 720px) {
  .profile-grid { grid-template-columns: 1fr; }
  .profile-header-card { align-items: flex-start; }
}

/* ---------- Wallet (TASK-SGB-WALLET-VIETQR-PREP-LOCAL-001) ---------- */

.wallet-balance-grid { grid-template-columns: 1fr; max-width: 320px; }
.wallet-topup-card,
.wallet-history-card { margin-top: var(--space-5); }
.wallet-topup-form { margin-top: var(--space-4); max-width: 320px; }
.wallet-topup-result { margin-top: var(--space-4); }
.wallet-qr-image {
  display: block;
  width: 220px;
  height: 220px;
  margin-top: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

/* QR-BROWSER-DISPLAY-001: unmissable "simulated vs real" marker, always
   shown directly above the QR image/payload -- never left to the image
   content alone to convey this. */
.wallet-qr-badge {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-weight: 600;
}
.wallet-qr-badge.is-simulated {
  background: var(--color-destructive-bg);
  color: var(--color-destructive);
  border: 1px solid var(--color-destructive-border);
}
.wallet-qr-badge.is-real {
  background: #e9f7ef;
  color: #1e7e42;
  border: 1px solid #bfe6cd;
}
.wallet-qr-copy-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
  max-width: 420px;
}
.wallet-qr-payload {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 6px var(--space-2);
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: 12px;
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 10px var(--space-4);
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 14px;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  min-height: 40px;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.btn-primary {
  background: var(--color-primary);
  color: var(--color-on-primary);
}
.btn-primary:hover { background: var(--color-primary-hover); }
.btn-primary:disabled,
.btn-primary[aria-disabled="true"] {
  background: var(--color-border-strong);
  color: var(--color-text-faint);
  cursor: not-allowed;
}

.btn-secondary {
  background: var(--color-surface);
  color: var(--color-text);
  border-color: var(--color-border-strong);
}
.btn-secondary:hover { background: var(--color-surface-muted); }

/* ---------- KPI cards ---------- */

.kpi-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}

.kpi-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  box-shadow: var(--shadow-sm);
}

.kpi-label {
  font-size: 13px;
  color: var(--color-text-muted);
  font-weight: 500;
  margin-bottom: var(--space-2);
}

.kpi-value {
  font-size: 28px;
  font-weight: 700;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}

.kpi-value.is-empty { color: var(--color-text-faint); }

/* ---------- Section / cards ---------- */

.section-title {
  font-size: 15px;
  font-weight: 700;
  margin: 0 0 var(--space-4);
  color: var(--color-text);
}

.panel {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

.btn-sm { padding: 4px 10px; font-size: 12px; }
.badge-pending { color: #b45309; font-size: 12px; font-weight: 600; }
.badge-none { color: var(--color-text-faint); font-size: 12px; }
/* TASK-SGB-CUSTOMER-PORTAL-GATE-P2C-LABELS-IMPLEMENTATION-014B: a real,
   customer-owned Shipment with no epacket.batch.line (no row_uuid) --
   distinct from "no label yet" (.badge-none) or "label pending"
   (.badge-pending), since here the gap is the Portal route itself, not
   the underlying artifact. */
.badge-unavailable { color: var(--color-text-faint); font-size: 12px; font-style: italic; }

/* GATE-E5D: the Tracking Center's own small, truthful customer-facing
   status vocabulary (bz.portal.intake.service._resolve_customer_
   tracking_status()) -- color-only text badges, same minimal style as
   .badge-pending/.badge-none above, never a heavier "progress bar" that
   would imply more certainty than the underlying data supports. */
.badge-received { color: var(--color-text-muted); font-size: 12px; font-weight: 600; }
.badge-processing { color: #b45309; font-size: 12px; font-weight: 600; }
.badge-tracking-ready { color: #1b76b8; font-size: 12px; font-weight: 600; }
.badge-label-ready { color: #1b76b8; font-size: 12px; font-weight: 600; }
.badge-complete { color: #15803d; font-size: 12px; font-weight: 600; }

/* GATE-E5D: the Tracking Center's search/filter bar -- reuses .field's
   own input styling (login.html's precedent) in a compact horizontal
   row instead of the stacked vertical form layout .field was designed
   for; wraps at narrow widths (Section 32) rather than overflowing. */
.tracking-search-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: flex-end;
  margin-bottom: var(--space-4);
}
.tracking-search-bar .field { margin-bottom: 0; flex: 1 1 240px; }
.tracking-search-bar select {
  width: 100%;
  padding: 11px var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  font-size: 15px;
  min-height: 44px;
  background: var(--color-surface);
  color: var(--color-text);
}
.tracking-search-bar .btn { flex: 0 0 auto; }

.tracking-pagination {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
  font-size: 13px;
  color: var(--color-text-muted);
}

/* GATE-E5D: compact card list for narrow widths (Section 32) -- the
   Tracking list swaps its table for stacked cards below the same
   breakpoint .orders-grid-scroll already collapses at, never a scaled-
   down 30-column ERP grid. */
.tracking-cards { display: none; }
.tracking-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  padding: var(--space-4);
  margin-bottom: var(--space-3);
}
.tracking-card-row { display: flex; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-2); font-size: 14px; }
.tracking-card-row .label { color: var(--color-text-muted); }
.tracking-card-actions { display: flex; gap: var(--space-2); margin-top: var(--space-3); }

@media (max-width: 720px) {
  .tracking-cards { display: block; }
  .tracking-grid-panel { display: none; }
}

.tracking-detail-panel { padding: var(--space-5); }
.tracking-detail-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
  font-size: 14px;
}
.tracking-detail-row:last-child { border-bottom: none; }
.tracking-detail-row .label { color: var(--color-text-muted); }
.tracking-detail-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-4); }

/* TASK-SGB-PORTAL-ORDERS-SUBMIT-BULK-PRINT-FULL-WIDTH-001 Section 5:
   /orders now uses the SAME sticky-header/frozen-leading-column pattern
   already proven on the Tạo đơn hàng grid (see .intake-grid* below) --
   parallel class names so the two grids can diverge independently, but
   identical mechanics: one scroll container (.orders-grid-scroll) gives
   a single horizontal+vertical scrollbar, `position: sticky` on thead
   keeps the header visible while scrolling down, and the same
   left-offset-stacking trick pins the first four columns (checkbox,
   Ngày gửi, Mã đơn khách hàng, Order ID) while scrolling right --
   Giá/Trạng thái/Tracking/Barcode/Label/Thao tác all stay in the normal
   scrolling body, never hidden behind a frozen column. */
.orders-grid-panel {
  overflow: hidden;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
}
.orders-grid-scroll {
  overflow: auto;
  max-height: 72vh;
  background: var(--color-surface);
}
table.orders-grid {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  font-size: 13px;
  background: var(--color-surface);
}
.orders-grid th,
.orders-grid td {
  padding: var(--space-3) var(--space-4);
  border-right: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
  text-align: left;
  white-space: nowrap;
  min-width: 110px;
}
.orders-grid th:last-child,
.orders-grid td:last-child { border-right: none; }
.orders-grid thead th {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
  font-weight: 600;
  font-size: 12px;
}
.orders-grid tbody tr:hover td { background: #f7f9fc; }

/* R: box-sizing: border-box + an explicit fixed width/padding on every
   sticky column below is required, not decorative -- the generic
   .orders-grid td padding above is 12px/16px, and without pinning the
   box model here each cell's rendered width can grow past its `left`
   offset (content-box default adds padding ON TOP of width), which
   would silently desync every column after it, exactly the bug already
   found and fixed once on the Tạo đơn hàng grid's own col-select/
   col-stt pair (see .intake-grid's own comment above). */
.orders-grid th.col-select,
.orders-grid td.col-select {
  position: sticky;
  left: 0;
  z-index: 4;
  box-sizing: border-box;
  width: 40px;
  min-width: 40px;
  max-width: 40px;
  padding: 0;
  text-align: center;
  vertical-align: middle;
  background: var(--color-surface-muted);
}
.orders-grid tbody td.col-select { background: var(--color-surface); }
.orders-grid th.col-sent-date,
.orders-grid td.col-sent-date {
  position: sticky;
  left: 40px;
  z-index: 4;
  box-sizing: border-box;
  width: 130px;
  min-width: 130px;
  max-width: 130px;
  background: var(--color-surface-muted);
}
.orders-grid tbody td.col-sent-date { background: var(--color-surface); }
.orders-grid th.col-order-code,
.orders-grid td.col-order-code {
  position: sticky;
  left: 170px;
  z-index: 4;
  box-sizing: border-box;
  width: 150px;
  min-width: 150px;
  max-width: 150px;
  background: var(--color-surface-muted);
}
.orders-grid tbody td.col-order-code { background: var(--color-surface); }
.orders-grid th.col-order-id,
.orders-grid td.col-order-id {
  position: sticky;
  left: 320px;
  z-index: 4;
  box-sizing: border-box;
  width: 170px;
  min-width: 170px;
  max-width: 170px;
  border-right: 2px solid var(--color-border-strong);
  background: var(--color-surface-muted);
}
.orders-grid tbody td.col-order-id { background: var(--color-surface); }
.orders-grid tbody tr:hover td.col-select,
.orders-grid tbody tr:hover td.col-sent-date,
.orders-grid tbody tr:hover td.col-order-code,
.orders-grid tbody tr:hover td.col-order-id { background: #f7f9fc; }
.orders-grid td.col-actions,
.orders-grid th.col-actions { min-width: 80px; }

@media (max-width: 640px) {
  .orders-grid-scroll { max-height: none; }
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--space-4);
}

.feature-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  text-decoration: none;
  color: var(--color-text);
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.feature-card .icon-wrap {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  background: var(--color-surface-muted);
  color: var(--color-primary);
  display: flex;
  align-items: center;
  justify-content: center;
}

.feature-card .title { font-weight: 600; font-size: 14px; }
.feature-card .badge { font-size: 11px; color: var(--color-text-faint); }

.feature-card.disabled { cursor: default; }
.feature-card:not(.disabled):hover {
  box-shadow: var(--shadow-md);
  border-color: var(--color-border-strong);
}

/* ---------- Empty state ---------- */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-7) var(--space-5);
  color: var(--color-text-muted);
}

.empty-state .icon-wrap {
  width: 56px;
  height: 56px;
  border-radius: 999px;
  background: var(--color-surface-muted);
  color: var(--color-text-faint);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--space-4);
}

.empty-state .title {
  font-weight: 600;
  color: var(--color-text);
  margin-bottom: var(--space-1);
  font-size: 14px;
}

.empty-state .hint { font-size: 13px; max-width: 360px; }

/* ---------- Login page ---------- */

.login-body {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
  background: linear-gradient(160deg, #0b3d66 0%, #12588f 55%, #1b76b8 100%);
}

.login-card {
  width: 100%;
  max-width: 400px;
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 60px rgba(6, 20, 38, 0.28);
  padding: var(--space-7) var(--space-6);
}

.login-brand { text-align: center; margin-bottom: var(--space-6); }
.login-brand .name {
  font-size: 22px;
  font-weight: 800;
  color: var(--color-primary);
  letter-spacing: 0.5px;
}
.login-brand .sub {
  font-size: 13px;
  color: var(--color-text-muted);
  margin-top: var(--space-1);
}

.field { margin-bottom: var(--space-4); }

.field label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text);
  margin-bottom: var(--space-2);
}

.field .input-wrap { position: relative; }

.field input[type="text"],
.field input[type="password"],
.field input[type="email"] {
  width: 100%;
  padding: 11px var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  font-size: 15px;
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  min-height: 44px;
  background: var(--color-surface);
  color: var(--color-text);
}

.field input:focus {
  border-color: var(--color-focus-ring);
  box-shadow: 0 0 0 3px rgba(27, 118, 184, 0.15);
}

.field input.has-toggle { padding-right: 44px; }

.password-toggle {
  position: absolute;
  right: 4px;
  top: 4px;
  bottom: 4px;
  width: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.password-toggle:hover { background: var(--color-surface-muted); }

.login-submit { width: 100%; justify-content: center; margin-top: var(--space-2); }

.alert-error {
  margin-top: var(--space-4);
  background: var(--color-destructive-bg);
  color: var(--color-destructive);
  border: 1px solid var(--color-destructive-border);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  font-size: 13px;
  text-align: center;
}

.login-footer {
  margin-top: var(--space-6);
  text-align: center;
  font-size: 12px;
  color: var(--color-text-faint);
}

/* ---------- Degraded / error page ---------- */

.status-page {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-background);
  padding: var(--space-5);
}
.status-card {
  max-width: 420px;
  text-align: center;
  padding: var(--space-6);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.status-card h1 { color: var(--color-primary); font-size: 17px; margin: 0 0 var(--space-2); }
.status-card p { color: var(--color-text-muted); font-size: 14px; margin: 0; }

/* ---------- Responsive ---------- */

/* ---------- Intake workspace (Phase 1C) ---------- */

.intake-toolbar-actions {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.intake-bulk-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-3);
  font-size: 13px;
  color: var(--color-text-muted);
}
.intake-bulk-toolbar select {
  padding: 6px var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}
.intake-selected-count {
  font-weight: 600;
  color: var(--color-primary);
}
.intake-counters {
  margin-left: auto;
  font-weight: 600;
  color: var(--color-text-muted);
}

.intake-status-bar {
  margin-bottom: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-weight: 600;
}
.intake-status-bar.is-success {
  background: #e9f7ef;
  color: #1e7e42;
  border: 1px solid #bfe6cd;
}
.intake-status-bar.is-error {
  background: var(--color-destructive-bg);
  color: var(--color-destructive);
  border: 1px solid var(--color-destructive-border);
}
.intake-status-bar.is-pending {
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
}

/* TASK-SGB-PORTAL-DRAFT-FIELD-ERROR-LOCAL-001: top-of-grid summary of
   every blocking field error from the last Save Draft response. */
.intake-error-summary {
  margin-bottom: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--color-destructive-bg);
  color: var(--color-destructive);
  border: 1px solid var(--color-destructive-border);
  font-size: 13px;
}
.intake-error-summary strong {
  display: block;
  margin-bottom: var(--space-2);
}
.intake-error-summary ul {
  margin: 0;
  padding-left: 20px;
}
.intake-error-summary li {
  margin-bottom: 2px;
}

/* ---------- Intake grid: Google-Sheets/Excel-style light matrix
   (Phase 1C-UI-R2) -- every cell keeps a soft, visible border on its own
   right/bottom edge; the panel's own 1px frame supplies the top/left
   edge, so the whole sheet reads as one clean grid with no doubled
   lines. Visual only: no field/route/validation logic lives here. */

.intake-grid-panel {
  overflow: hidden;
  margin-bottom: var(--space-4);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
}

.intake-grid-scroll {
  overflow: auto;
  max-height: 66vh;
  background: var(--color-surface);
}

table.intake-grid {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  min-width: 100%;
  font-size: 13px;
  background: var(--color-surface);
}

.intake-grid th,
.intake-grid td {
  border-right: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
}
.intake-grid th:last-child,
.intake-grid td:last-child { border-right: none; }

.intake-grid thead th {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
  font-weight: 600;
  font-size: 12px;
  text-align: left;
  padding: 9px var(--space-2);
  border-bottom: 1px solid var(--color-border-strong);
  white-space: nowrap;
}

.intake-grid thead th.required::after {
  content: " *";
  color: var(--color-destructive);
}

.intake-grid tbody td {
  padding: 0;
  vertical-align: middle;
  background: var(--color-surface);
}

.intake-grid tbody tr:hover td { background: #f7f9fc; }

/* R1 Section 2: the checkbox column and the # column form one frozen
   "corner" pair when scrolling horizontally. Both MUST share the exact
   same box-sizing/width math or their `left` offsets drift by however
   many px the border/padding adds outside the declared width (mismatch
   here is what made the # column visually overlap/clip under the
   checkbox column) -- so both are pinned with box-sizing: border-box
   and matching min/max-width (not just `width`, which table auto-layout
   can otherwise stretch if content needs more room). */
.intake-grid th.col-select,
.intake-grid td.col-select,
.intake-grid th.col-stt,
.intake-grid td.col-stt {
  position: sticky;
  z-index: 4;
  box-sizing: border-box;
  text-align: center;
  vertical-align: middle;
  background: var(--color-surface-muted);
  overflow: hidden;
}
.intake-grid th.col-select,
.intake-grid td.col-select {
  left: 0;
  width: 36px;
  min-width: 36px;
  max-width: 36px;
  padding: 0;
}
.intake-grid th.col-stt,
.intake-grid td.col-stt {
  /* R3: widened from 36px and padding trimmed from 8px/side to 3px/side --
     36px with 8px padding left only ~20px for digits, not enough for a
     3-digit row number (MAX_ROWS_PER_SUBMISSION=500 makes "500" a real,
     reachable value) without the cell growing past its declared width in
     some browsers' auto-layout table algorithm, which desynced this
     column's actual rendered width from the `left: 36px` its neighbor
     (Mã đơn khách hàng, the first real data column) was positioned
     against -- exactly the reported "cột cố định che chữ" symptom. */
  left: 36px;
  width: 40px;
  min-width: 40px;
  max-width: 40px;
  padding: 0 3px;
  color: var(--color-text-faint);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
}
.intake-grid th.col-select,
.intake-grid th.col-stt {
  z-index: 6;
}
.intake-grid tbody tr:hover td.col-select,
.intake-grid tbody tr:hover td.col-stt {
  background: var(--color-surface-muted);
}
.intake-grid .row-select-checkbox,
.intake-grid #intakeSelectAll {
  margin: 0;
  vertical-align: middle;
}

.intake-grid td.col-actions { width: 40px; text-align: center; }

/* TASK-SGB-PORTAL-SENT-DATE-COLUMN-001: read-only, not part of the
   sticky checkbox/# corner (no reason to freeze it too) and not part
   of the editable-cell styling below -- plain text, muted, no input
   chrome, so it reads as clearly non-editable at a glance. */
.intake-grid td.col-sent-date,
.intake-grid th.col-sent-date {
  width: 132px;
  min-width: 132px;
  padding: 7px var(--space-2);
  color: var(--color-text-muted);
  font-size: 12px;
  white-space: nowrap;
  text-align: left;
}

/* TASK-SGB-PORTAL-ORDER-LIFECYCLE-001: same read-only treatment as
   col-sent-date above, plus a small colored badge so Lưu nháp/Đang xử
   lý/Giữ lại are distinguishable at a glance in the same grid. */
.intake-grid td.col-portal-status,
.intake-grid th.col-portal-status {
  width: 96px;
  min-width: 96px;
  padding: 7px var(--space-2);
  font-size: 12px;
  white-space: nowrap;
  text-align: left;
}
.intake-grid td.col-portal-status.status-draft { color: var(--color-text-muted); }
.intake-grid td.col-portal-status.status-processing { color: #1e7e42; font-weight: 600; }
.intake-grid td.col-portal-status.status-held { color: #b45309; font-weight: 600; }

#btnViewProcessing { margin-bottom: var(--space-4); }

.intake-cell-input,
.intake-cell-select {
  display: block;
  width: 100%;
  height: 100%;
  min-width: 96px;
  min-height: 32px;
  border: 1px solid transparent;
  background: transparent;
  padding: 7px var(--space-2);
  font-size: 13px;
  font-family: inherit;
  color: var(--color-text);
  border-radius: 0;
  appearance: none;
  -webkit-appearance: none;
}
.intake-cell-select {
  min-width: 76px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235b6b7f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 6px center;
  padding-right: 26px;
  cursor: pointer;
}
.intake-cell-input.is-number { min-width: 70px; text-align: right; font-variant-numeric: tabular-nums; }

.intake-cell-input:hover,
.intake-cell-select:hover { background-color: #fbfcfe; }
.intake-cell-select:hover { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235b6b7f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); }

.intake-cell-input:focus,
.intake-cell-select:focus {
  outline: none;
  background: var(--color-surface);
  box-shadow: inset 0 0 0 2px var(--color-focus-ring), 0 1px 4px rgba(27, 118, 184, 0.18);
  position: relative;
  z-index: 2;
}

/* TASK-SGB-PORTAL-GRID-SHORTCUTS-001: Excel-style range selection overlay.
   Deliberately separate from the row-select checkbox ("row.selected" /
   .row-select-checkbox, used only for the bulk region-apply toolbar) --
   this is a rectangular CELL range, painted on the <td> itself so it
   stays visible even though every cell's own input keeps a transparent
   background. */
td.cell-in-selection {
  background-color: var(--color-focus-ring-bg, rgba(27, 118, 184, 0.10));
  position: relative;
}
td.cell-in-selection .intake-cell-input,
td.cell-in-selection .intake-cell-select {
  background-color: transparent;
}
td.cell-active-anchor {
  outline: 2px solid var(--color-primary);
  outline-offset: -2px;
  z-index: 3;
  position: relative;
}

td.has-error .intake-cell-input,
td.has-error .intake-cell-select {
  background-color: var(--color-destructive-bg);
  color: var(--color-destructive);
  box-shadow: inset 0 0 0 1.5px var(--color-destructive-border);
  position: relative;
  z-index: 1;
}
td.has-error .intake-cell-input:focus,
td.has-error .intake-cell-select:focus {
  box-shadow: inset 0 0 0 2px var(--color-destructive), 0 1px 4px rgba(179, 38, 30, 0.18);
  z-index: 2;
}

/* TASK-SGB-CUSTOMER-PORTAL-PICKUP-LOCATION-001 Gate 6C Section 16: the
   read-only derived-Hub indicator under the Pickup selector -- informational
   only, never an editable control, never larger than the cell it sits in
   (Section 27: keep the column usable, don't widen it). */
.pickup-hub-readonly {
  font-size: 11px;
  color: var(--color-text-faint);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.intake-pickup-unavailable {
  font-size: 12px;
  color: var(--color-text-faint);
  font-style: italic;
}

.row-delete-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  background: transparent;
  color: var(--color-text-faint);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.row-delete-btn:hover { background: var(--color-destructive-bg); color: var(--color-destructive); }

.intake-hint {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  color: var(--color-text-muted);
  font-size: 12px;
  margin: 0;
}
.intake-hint svg { flex-shrink: 0; margin-top: 1px; color: var(--color-text-faint); }

@media (max-width: 1023px) {
  .sidebar {
    transform: translateX(-100%);
    box-shadow: var(--shadow-md);
  }
  .sidebar.is-open { transform: translateX(0); }
  .sidebar-backdrop.is-open { display: block; }

  .main-column { margin-left: 0; }
  .menu-toggle { display: inline-flex; }

  .kpi-grid { grid-template-columns: repeat(2, 1fr); }

  /* TASK-SGB-PORTAL-UI-SIDEBAR-RESIZE-LOCAL-001: the desktop collapse
     feature is meaningless below this breakpoint (the sidebar is already
     a full-width off-canvas overlay, toggled by .is-open, not by width)
     -- if a visitor collapsed it on desktop and then resized/reloaded on
     mobile, force the full expanded appearance and hide the collapse
     button rather than showing a confusing narrow overlay. .main-column
     already unconditionally resets to margin-left: 0 two rules above,
     regardless of this state. */
  html.sgb-sidebar-collapsed .sidebar { width: var(--sidebar-width); }
  html.sgb-sidebar-collapsed .sidebar-brand {
    align-items: flex-start;
    padding: 0 var(--space-5) var(--space-5);
  }
  html.sgb-sidebar-collapsed .brand-logo-frame { display: flex; }
  html.sgb-sidebar-collapsed .brand-mark { display: none; }
  html.sgb-sidebar-collapsed .sidebar-brand-footer {
    flex-direction: row;
    justify-content: space-between;
  }
  html.sgb-sidebar-collapsed .sidebar-brand-footer .sub { display: block; }
  html.sgb-sidebar-collapsed .sidebar-collapse-toggle { display: none; }
  html.sgb-sidebar-collapsed .nav-item { justify-content: flex-start; padding-left: var(--space-3); padding-right: var(--space-3); }
  html.sgb-sidebar-collapsed .nav-item > span { display: inline; }
}

@media (max-width: 640px) {
  main.page { padding: var(--space-5) var(--space-4) var(--space-6); }
  .kpi-grid { grid-template-columns: 1fr 1fr; gap: var(--space-3); }
  .topbar { padding: 0 var(--space-4); }
  .topbar-identity .identity-badge span.name-text { display: none; }
  .login-card { padding: var(--space-6) var(--space-5); }
  .feature-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
}

/* TASK-SGB-CUSTOMER-PORTAL-GATE-P2A-MARKETPLACE-GRID-011: "Đơn TMĐT chờ
   xử lý" rebuilt as a spreadsheet grid sharing the SAME frame as
   /create-order -- col-portal-status colors here use marketplace's own
   status vocabulary (imported/needs_review/ready_for_confirmation/
   confirmed/source_changed/error), distinct from create-order's own
   draft/processing/held vocabulary above. The old card-based
   .marketplace-queue-card/-fields/-actions/-badge rules (TASK-007) are
   removed -- the template no longer renders cards. */
.intake-grid td.col-portal-status.status-imported { color: var(--color-text-muted); }
.intake-grid td.col-portal-status.status-needs_review { color: #b45309; font-weight: 600; }
.intake-grid td.col-portal-status.status-ready_for_confirmation { color: #1e7e42; font-weight: 600; }
.intake-grid td.col-portal-status.status-confirmed { color: var(--color-navy-700); font-weight: 600; }
.intake-grid td.col-portal-status.status-source_changed,
.intake-grid td.col-portal-status.status-error { color: var(--color-destructive); font-weight: 600; }

.mp-queue-empty-row td {
  padding: var(--space-6) var(--space-4);
  text-align: center;
  color: var(--color-text-muted);
}
.mp-queue-row-warning { background: var(--color-destructive-bg); }
.mp-queue-readonly-cell {
  display: inline-block;
  padding: 7px var(--space-2);
  color: var(--color-text-muted);
}
.mp-queue-warning-cell {
  min-width: 220px;
  font-size: 12px;
  color: var(--color-destructive);
}
/* GATE-E3C Section 10/17: derived "Xử lý tại" preview must read as
   plainly non-editable -- distinct from an ordinary readonly-after-
   confirm cell (which used to be an active input). */
.mp-queue-hub-preview {
  font-weight: 600;
  background: var(--color-muted-bg, rgba(0, 0, 0, 0.04));
  border-radius: 4px;
}

/* TASK-SGB-MARKETPLACE-PORTAL-ORDER-INTAKE-STANDARD-006 Phase 1:
   "Kết nối Marketplace" -- multi-platform connection cards + picker. */
.mp-panel { padding: var(--space-5); }
.mp-panel h2 { margin-top: 0; margin-bottom: var(--space-4); font-size: 16px; }

.mp-connection-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.mp-connection-card {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-4);
}
.mp-connection-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.mp-platform-name { font-weight: 700; }
.mp-state-badge {
  font-size: 12px;
  font-weight: 600;
  padding: 2px 10px;
  border-radius: 999px;
}
.mp-state-badge.is-ok { background: #e9f7ef; color: #1e7e42; }
.mp-state-badge.is-error { background: var(--color-destructive-bg); color: var(--color-destructive); }
.mp-state-badge.is-pending { background: var(--color-surface-muted); color: var(--color-text-muted); }
.mp-state-badge.is-off { background: var(--color-border); color: var(--color-text-faint); }
.mp-connection-shop { color: var(--color-text-muted); font-size: 13px; margin-top: 4px; }
.mp-connection-health-msg { font-size: 13px; margin-top: var(--space-2); }
.mp-connection-meta { font-size: 12px; color: var(--color-text-faint); margin-top: var(--space-2); }
.mp-connection-actions {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.mp-platform-picker {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
}
.mp-platform-tab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: var(--space-3) var(--space-2);
  font-weight: 600;
  color: var(--color-text-muted);
  cursor: pointer;
}
.mp-platform-tab.is-active { color: var(--color-primary); border-bottom-color: var(--color-primary); }
.mp-platform-panel label { display: block; margin-top: var(--space-3); margin-bottom: 4px; font-weight: 600; font-size: 13px; }
.mp-platform-panel input { width: 100%; padding: 8px 10px; border: 1px solid var(--color-border-strong); border-radius: var(--radius-sm); }
.mp-platform-panel .field-hint { color: var(--color-text-faint); font-size: 12px; margin-top: var(--space-2); }
.mp-platform-panel .btn { margin-top: var(--space-3); }
.mp-platform-unsupported input,
.mp-platform-unsupported select { background: var(--color-surface-muted); color: var(--color-text-faint); }
.mp-platform-panel select { width: 100%; padding: 8px 10px; border: 1px solid var(--color-border-strong); border-radius: var(--radius-sm); margin-bottom: var(--space-2); }

.marketplace-queue-pagination {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-top: var(--space-5);
}

/* ---------- AR Payment (TASK-SGB-CUSTOMER-AR-PAYMENT-001 Gate AR1) ----------
   Placed at the very end of this file on purpose: every rule below is a
   brand-new class (.ar-*), so cascade order relative to the existing
   @media (max-width: 1023px)/(max-width: 640px) blocks above never
   matters here -- unlike .kpi-grid, nothing here is redefined by an
   earlier, lower-specificity rule that a later @media block could
   silently win against. Reuses only existing :root tokens; no new
   token, no !important (this file has none). */

.ar-row-readonly { background: var(--color-surface-muted); }
.ar-row-readonly td { color: var(--color-text-faint); }

.ar-select-bar {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
}
.ar-select-bar #arPaySubmit:disabled { background: var(--color-border-strong); color: var(--color-text-faint); }

.ar-history-card { margin-top: var(--space-5); }

.ar-payment-detail-panel { max-width: 480px; }
.ar-payment-code-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.ar-payment-code {
  font-size: 20px;
  font-weight: 700;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
.ar-payment-qr {
  display: block;
  max-width: 260px;
  width: 100%;
  height: auto;
  margin: 0 auto var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
.ar-payment-detail-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
  font-size: 14px;
}
.ar-payment-detail-row:last-child { border-bottom: none; }
.ar-payment-detail-row .label { color: var(--color-text-muted); min-width: 160px; }
.ar-payment-detail-row span:not(.label) { font-variant-numeric: tabular-nums; user-select: all; }
.ar-copy-btn { padding: 4px var(--space-2); font-size: 12px; margin-left: auto; }

@media (max-width: 640px) {
  /* Mục 28: bảng chứng từ AR chuyển sang dạng card -- mỗi <tr> thành
     một khối, mỗi <td> tự in nhãn cột của mình qua ::before, đọc từ
     attr(data-label) mà Jinja đã render sẵn trên mỗi <th>/<tr>. */
  .ar-items-grid, .ar-items-grid thead, .ar-items-grid tbody,
  .ar-items-grid th, .ar-items-grid td, .ar-items-grid tr {
    display: block;
  }
  .ar-items-grid thead tr { position: absolute; top: -9999px; left: -9999px; }
  /* .orders-grid's own th.col-select/td.col-select rule pins that column
     with position: sticky + a fixed background -- same (class, class,
     tag) specificity as this override, so appearing LATER in this file
     is what makes this one win; without it the checkbox cell would keep
     trying to stick to the left edge of a table that no longer has one
     inside this card layout. */
  .ar-items-grid td.col-select,
  .ar-items-grid th.col-select {
    position: static;
    border-right: none;
  }
  .ar-items-grid tr {
    margin-bottom: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
  }
  .ar-items-grid td {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    border: none;
    padding: var(--space-1) 0;
  }
  .ar-items-grid td::before {
    content: attr(data-th);
    color: var(--color-text-muted);
    font-weight: 600;
    margin-right: var(--space-3);
  }
  .ar-payment-qr { max-width: 100%; }
  .ar-payment-detail-row { flex-wrap: wrap; }
  .ar-payment-detail-row .label { min-width: 100%; }
}
