/* ============================================================
   layout.css — App shell: loading screen, login, header nav
                (drawer below 1024px), main wrapper, page areas
   ============================================================ */

/* ── Initial loading screen ─────────────────────────────────── */
#loading-screen {
  position: fixed;
  inset: 0;
  background: var(--surface);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  gap: 16px;
}

.load-text {
  font-family: var(--font-title);
  font-size: 15px;
  font-weight: 600;
  color: var(--txt-3);
}

/* ── Login / auth screens ───────────────────────────────────── */
#login-screen,
#org-selector-screen {
  min-height: 100vh;
  width: 100vw;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  box-sizing: border-box;
}

.login-card {
  background:    var(--surface);
  border:        1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow:    var(--shadow-lg);
  padding:       40px 44px;
  width:         100%;
  max-width:     400px;
  animation: slideUp .25s var(--ease);
}

.login-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 12px;
  margin-bottom: 28px;
}

.login-brand-name { font-family: var(--font-title); font-size: 17px; font-weight: 700; color: var(--txt-1); }
.login-brand-sub  { font-size: 11px; color: var(--txt-4); margin-top: 1px; }

/* Agency credit under the product name. Scoped to the anchor so the org
   selector — which reuses .login-brand-sub to show the signed-in user —
   keeps its plain-text styling. Muted by default so it stays subordinate
   to Xcel Rack, resolving to the Xcelerate Brands orange on hover. */
a.login-brand-sub {
  display: inline-block;
  position: relative;          /* anchor for .brand-mark */
  text-decoration: none;
  transition: color .15s var(--ease);
}

/* The global `a:hover { text-decoration: underline }` in main.css ties on
   specificity with the rule above, and this file loads later — so the
   underline has to be re-stated here or it never appears. */
a.login-brand-sub:hover,
a.login-brand-sub:focus-visible {
  color: var(--brand-accent);
  text-decoration: underline;
}

/* Logo that pops out past the end of the text on hover.
   Absolutely positioned so a mark twice the text height neither grows
   the line nor shifts the brand block when it appears — it overflows
   the anchor instead. */
.brand-mark {
  position: absolute;
  /* Base sits on the byline's bottom edge, at the tail of the "s" in
     "Brands". bottom:100% put the whole mark above the line and it
     towered over the card; bottom:-2px let it hang below the text.
     Zero is the middle: it never drops below the byline, and it grows
     up and to the right out of that corner. */
  left: 100%;
  bottom: 0;
  /* Negative pull tucks the mark against the "s" rather than leaving it
     beside the word. The logo artwork carries its own transparent
     padding, so zero margin still reads as a visible gap. */
  margin-left: -10px;
  height: 64px;
  width: 64px;
  /* Hard ceiling. The asset is 128x128 and the tag carries width/height
     attributes, so even with this stylesheet missing entirely the mark
     renders small instead of blowing the login card apart. */
  max-width: 64px;
  max-height: 64px;
  opacity: 0;
  /* Origin at the bottom-left corner means the scale itself lifts the
     mark upward — the growth direction IS the animation. */
  transform: scale(.25);
  transform-origin: left bottom;
  pointer-events: none;        /* never intercepts the link's own hover */
  transition: opacity .16s var(--ease),
              transform .28s cubic-bezier(.34, 1.56, .64, 1); /* overshoot = "pop" */
}

a.login-brand-sub:hover .brand-mark,
a.login-brand-sub:focus-visible .brand-mark {
  opacity: 1;
  transform: scale(1);
}

/* Respect users who have asked the OS to reduce motion: still reveal the
   mark, just without the springy scale. */
@media (prefers-reduced-motion: reduce) {
  .brand-mark { transition: opacity .16s linear; transform: scale(1); }
}

.login-heading { font-size: 20px; margin-bottom: 6px; }
.login-sub     { font-size: 13px; color: var(--txt-3); margin-bottom: 24px; }

.login-error {
  font-size: 12px;
  color: var(--error);
  background: var(--error-bg);
  border: 1px solid var(--error-bd);
  border-radius: var(--r-sm);
  padding: 8px 12px;
  margin-bottom: 14px;
  display: none;
}
.login-error.visible { display: block; }

/* ── Maintenance notice ─────────────────────────────────────────
   Full-screen, centred, and deliberately calm: the user has done
   nothing wrong and nothing of theirs is lost. */
#maintenance-screen {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--bg);
}

.maint-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  padding: 36px 40px 30px;
  width: 100%;
  max-width: 480px;
  text-align: center;
  animation: slideUp .25s var(--ease);
}

.maint-art {
  width: 100%;
  max-width: 260px;
  height: auto;
  margin: 0 auto 18px;
  display: block;
}

.maint-title {
  font-family: var(--font-title);
  font-size: 22px;
  font-weight: 700;
  color: var(--txt-1);
  margin: 0 0 8px;
}
.maint-text {
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--txt-3);
  margin: 0 0 14px;
}
.maint-eta {
  font-size: 13.5px;
  color: var(--txt-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 10px 14px;
  margin-bottom: 18px;
}
.maint-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 14px;
}
.maint-foot { font-size: 12px; color: var(--txt-4); margin: 0; }

/* The old large Maintenance panel is gone. Maintenance is now a single
   compact row inside the Diagnostics console and is styled there, in
   js/diagnostics.js, next to the markup it belongs to. */

/* ── App shell ──────────────────────────────────────────────── */
#app-shell {
  display: flex;
  height: 100vh;
  overflow: hidden;
}

/* ── Main menu (module switcher) ──────────────────────────────
   Names the module you are in — WMS, Forecasting, Uploads — with the
   module's pages rendered as the row beside it. The trigger carries
   the product's blue so the module reads as the anchor of the whole
   header, and the open panel marks the current module the same way. */
.module-menu {
  position: relative;
  flex-shrink: 0;
  margin-right: 10px;
  padding-right: 12px;
  border-right: 1px solid var(--border);
}

.module-menu-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 12px;
  background: var(--primary);
  color: #fff;
  border: none;
  border-radius: var(--r-sm);
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur), filter var(--dur);
}
.module-menu-trigger:hover { filter: brightness(1.08); }
.module-menu-trigger:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.module-menu-trigger .icon { width: 16px; height: 16px; color: #fff; }
.module-menu-chevron { width: 14px !important; height: 14px !important; opacity: .8; transition: transform var(--dur) var(--ease); }
.module-menu.open .module-menu-chevron { transform: rotate(180deg); }

.module-menu-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 190px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  padding: 5px;
  z-index: 600;
  display: none;
}
.module-menu.open .module-menu-panel { display: block; }

.module-menu-panel button {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 9px 10px;
  background: transparent;
  border: none;
  border-radius: var(--r-sm);
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--txt-2);
  text-align: left;
  cursor: pointer;
  transition: background var(--dur), color var(--dur);
}
.module-menu-panel button:hover { background: var(--surface-3); color: var(--txt-1); }
.module-menu-panel button .icon { width: 15px; height: 15px; opacity: .75; flex-shrink: 0; }

/* The module you are in: solid blue, white text — unmistakably "you
   are here", not merely highlighted. */
.module-menu-panel button.active {
  background: var(--primary);
  color: #fff;
  font-weight: 600;
}
.module-menu-panel button.active .icon { color: #fff; opacity: 1; }
.module-menu-panel button.active:hover { background: var(--primary); color: #fff; }

/* View-only members see Uploads marked, not missing (soft access). */
.module-menu-panel button.is-access-blocked {
  opacity: .5;
  cursor: not-allowed;
}

/* Submenu filtering: items outside the current module leave the row.
   The drawer stylesheet reveals them again — the phone keeps one flat
   menu (see the drawer section below). */
.topnav .nav-item.module-hidden { display: none; }

/* ── Submenu row ──────────────────────────────────────────────
   The current module's pages, along the header beside the main menu
   that names the module. Nothing sits to the left of the content, so
   every page is full width. Below 1024px this same <nav> becomes the
   off-canvas drawer — see the drawer section further down. */
.topnav {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: 1;
  min-width: 0;
  /* Never clipped: the restricted-item tooltip hangs below the header,
     and a box that scrolls on one axis clips the other whatever it
     declares. Nothing overflows either — a module holds at most five
     pages, and below 1280px the labels drop to icons. */
  overflow: visible;
}

/* A module with one page is fully named by the main menu; its row would
   repeat that one label and nothing else. */
.topnav.rail-hidden { display: none; }

.nav-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: var(--r-sm);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--txt-3);
  cursor: pointer;
  user-select: none;
  position: relative;
  white-space: nowrap;
  flex-shrink: 0;
  transition: background var(--dur), color var(--dur);
}
.nav-item:hover  { background: var(--surface-3); color: var(--txt-1); }
.nav-item.active { background: var(--primary-50); color: var(--primary-text); font-weight: 600; }

.nav-label { overflow: hidden; }

.nav-icon {
  font-size: 16px;
  width: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  opacity: .7;
}
.nav-item.active .nav-icon { opacity: 1; }

/* Tooltip, hanging below the header rather than beside the rail. Defined
   once and revealed in the only two cases that need it: an item with no
   label to read, and a restricted item, where the tooltip is the only
   thing that can say WHY it is not yours. */
.nav-item::after {
  display: none;
  content: attr(data-tooltip);
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background: var(--txt-1);
  color: #fff;
  font-size: 12px;
  font-weight: 500;
  padding: 5px 10px;
  border-radius: var(--r-sm);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 120ms var(--ease);
  z-index: 500;
}
.nav-item.is-access-blocked::after { display: block; }
.nav-item:hover::after { opacity: 1; }

/* Between the drawer breakpoint and 1280px the labels come off. The
   main menu, five page tabs, the workspace switcher and the account
   menu do not fit on one row at that width, and icons with tooltips
   beat a header that overlaps itself. */
@media (min-width: 1025px) and (max-width: 1440px) {
  .topnav .nav-label { display: none; }
  .topnav .nav-item  { padding: 8px 10px; }
  /* With no label to read, the tooltip is the label. */
  .nav-item::after   { display: block; }
  /* The account name and role go too before the tabs would collide with
     them — the avatar still identifies the session. */
  .user-menu-text    { display: none; }
  .user-menu-trigger { padding: 5px; gap: 5px; }
}

/* ── Account menu ─────────────────────────────── */
/* Identity plus the two things that belong to it: your profile, and the
   way out. Sign out used to sit permanently in the rail one slip away
   from ending a session. */
.user-menu { position: relative; flex-shrink: 0; }

.user-menu-trigger {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 8px 5px 5px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  cursor: pointer;
  font-family: inherit;
  transition: background var(--dur), border-color var(--dur);
}
.user-menu-trigger:hover { background: var(--surface-3); border-color: var(--border); }
.user-menu-trigger:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.user-menu-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.2;
  min-width: 0;
  max-width: 160px;
}
.user-menu-text > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }

.user-menu-chevron {
  width: 14px; height: 14px;
  color: var(--txt-4);
  flex-shrink: 0;
  transition: transform var(--dur) var(--ease);
}
.user-menu.open .user-menu-chevron { transform: rotate(180deg); }

.user-menu-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 210px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  padding: 5px;
  z-index: 600;
  display: none;
}
.user-menu.open .user-menu-panel { display: block; }

.user-menu-panel button {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 9px 10px;
  background: transparent;
  border: none;
  border-radius: var(--r-sm);
  font-family: inherit;
  font-size: 13.5px;
  color: var(--txt-2);
  text-align: left;
  cursor: pointer;
  transition: background var(--dur), color var(--dur);
}
.user-menu-panel button:hover { background: var(--surface-3); color: var(--txt-1); }
.user-menu-panel button:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.user-menu-panel .icon { width: 15px; height: 15px; opacity: .75; flex-shrink: 0; }

.user-menu-sep { height: 1px; background: var(--border); margin: 4px 6px; }

.user-menu-danger:hover { background: var(--error-bg) !important; color: var(--error, #dc2626) !important; }
.user-menu-danger:hover .icon { color: var(--error, #dc2626); opacity: 1; }

.sidebar-avatar,
.user-avatar-sm {
  width: 30px; height: 30px;
  background: var(--primary-100);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px; font-weight: 700;
  color: var(--primary-text);
  flex-shrink: 0;
}

.sidebar-user-name { font-size: 13px; font-weight: 600; color: var(--txt-1); line-height: 1.2; }
.sidebar-user-role { font-size: 11px; color: var(--txt-4); text-transform: capitalize; }

/* ── Main wrapper ───────────────────────────────────────────── */
.main-wrapper {
  /* Full width. There is no rail to offset for. */
  flex: 1;
  width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

/* ── Topbar ─────────────────────────────────────────────────── */
.topbar {
  height: var(--topbar-h);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 24px;
  position: sticky;
  top: 0;
  z-index: 50;
  flex-shrink: 0;
}

.topbar-title {
  display: none;   /* drawer layout only — the nav names the page otherwise */
  font-family: var(--font-title);
  font-size: 18px;
  font-weight: 700;
  color: var(--txt-1);
  flex: 1;
  min-width: 0;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
  /* Always hard right. The page tabs carry flex:1 and normally push
     these over, but a single-page module (Forecasting, Uploads) renders
     no tabs at all — without this the workspace and account slid left
     and sat against the main menu. */
  margin-left: auto;
}

/* Mobile-only hamburger button in topbar — hidden on desktop/tablet. */
.topbar-menu-btn {
  display: none;
  width: 36px; height: 36px;
  border: none;
  border-radius: var(--r-sm);
  background: var(--surface-3);
  color: var(--txt-2);
  cursor: pointer;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.topbar-menu-btn:hover { background: var(--primary-50); color: var(--primary-text); }
.topbar-menu-btn:active { transform: scale(.95); }

/* ── Sidebar backdrop (mobile offcanvas) ────────────────────── */
.sidebar-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, .45);
  z-index: 99;
  opacity: 0;
  visibility: hidden;
  transition: opacity 220ms var(--ease), visibility 0s linear 220ms;
}
body.sidebar-mobile-open .sidebar-backdrop {
  opacity: 1;
  visibility: visible;
  transition: opacity 220ms var(--ease);
}

/* ── Drawer layout (below 1024px) ────────────────── */
/* Same <nav>, laid out as the off-canvas drawer it used to be. A
   horizontal header cannot hold ten destinations on a tablet or phone
   without wrapping into a second and third row, which would eat the
   vertical space the tables need. */
@media (max-width: 1024px) {
  /* The drawer lives inside the header, and the header's z-index is the
     one that counts: a positioned ancestor with a z-index makes its own
     stacking context, so the drawer's 1000 is measured INSIDE the
     topbar's 50 and the backdrop at 99 would paint straight over it.
     Lifting the header above the backdrop puts the drawer above it too. */
  .topbar { z-index: 1001; }

  .topnav {
    position: fixed;
    left: 0; top: 0; bottom: 0;
    width: 264px;
    flex: 0 0 auto;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 3px;
    padding: 14px 10px;
    background: var(--surface);
    border-right: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    overflow-x: hidden;
    overflow-y: auto;
    transform: translateX(-100%);
    transition: transform 240ms var(--ease);
    z-index: 1000;
  }
  body.sidebar-mobile-open .topnav { transform: translateX(0); }

  .topnav .nav-item { padding: 11px 14px; font-size: 14px; }

  /* Every item is labelled in the drawer, and a tooltip on touch fires
     on tap and covers the thing just tapped. */
  .nav-item.is-access-blocked::after { display: none !important; }

  /* The hamburger and the page title take the nav's place. */
  .topbar-menu-btn { display: flex; }
  .topbar-title    { display: block; }

  /* The drawer is one flat menu — the module split keeps the rail
     short on a desktop, and the drawer has no such problem. Every
     module's pages show, and a rail hidden for a single-page module
     must still open as the drawer. */
  .module-menu { display: none !important; }
  .topnav .nav-item.module-hidden { display: flex; }
  .topnav.rail-hidden { display: flex; }
}

/* Below 768px the account name and role drop out of the trigger — the
   avatar alone identifies the session, and the header needs the width
   for the workspace switcher. */
@media (max-width: 768px) {
  .user-menu-text { display: none; }
  .user-menu-trigger { padding: 5px; gap: 5px; }
}

/* ── Page content ───────────────────────────────────────────── */
.page-content {
  flex: 1;
  /* Full width: nothing sits beside it. min-width:0 keeps a wide table
     scrolling inside its own container rather than pushing the page
     past the viewport. */
  min-width: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.page        { display: none; }
.page.active {
  display: flex;
  flex-direction: column;
  flex: 1;
  overflow: hidden;
  animation: fadeIn .18s var(--ease);
}
/* Standard pages scroll with padding — excludes pages with custom internal layout */
.page.active:not(#page-dashboard):not(#page-box-lookup):not(#page-uploads):not(#page-admin-dashboard):not(#page-inventory):not(#page-orders) {
  padding: 24px;
  overflow-y: auto;
}

/* ── Platform Overview ──────────────────────────────────────────
   The page itself does not scroll. Header and stat cards are fixed,
   and the activity feed is the only thing that moves — a dashboard you
   have to scroll to see the numbers on is not a dashboard.

   flex rather than a fixed 70vh: the feed takes whatever is left after
   the header and cards, so it fills a tall screen and still fits a
   short one, where a hard vh value would either overflow or leave a
   gap. min-height:0 is what actually lets a flex child shrink below
   its content and scroll — without it the feed grows and pushes the
   page instead. */
#page-admin-dashboard.page.active {
  padding: 24px;
  overflow: hidden;
  gap: 0;
}
#page-admin-dashboard .section-header,
#page-admin-dashboard #platform-stats { flex: 0 0 auto; }

#page-admin-dashboard > .card {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin-top: 16px;
}
#page-admin-dashboard > .card > .card-header { flex: 0 0 auto; }

#platform-activity {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Room for the last row's border to breathe against the card edge. */
  padding-right: 4px;
}

.settings-sticky {
  flex-shrink: 0;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  padding: 18px 24px 0;
}
.settings-sticky .section-header { margin-bottom: 14px; }

/* Body is a flex column — tab panels fill it and scroll themselves */
.settings-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 20px 24px 24px;
}

/* Every active settings tab panel fills remaining height and scrolls */
#page-settings .tab-panel.active {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* Logs tab: panel itself does NOT scroll — only the content area inside does */
#page-settings #tab-logs.tab-panel.active {
  overflow: hidden;
}

/* System Status tab: same viewport-fit pattern as Inventory / Orders.
   The tab-panel doesn't scroll; the card fills it and the inner content
   region scrolls internally if the diagnostics rows overflow. Keeps the
   page free of an outer scrollbar regardless of admin tooling height. */
#page-settings #tab-system.tab-panel.active {
  overflow: hidden;
}
#tab-system > .card {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
#tab-system > .card > .card-header { flex-shrink: 0; }
/* Flex column so the Diagnostics console below can grow to fill the
   remaining height, and the panels inside it can be flex-sized
   without the outer container ever needing to scroll. */
#tab-system #system-status-content {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
#tab-system #system-status-content > .diag { flex: 1; min-height: 0; }

.settings-logs-card {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/* Logs content: fills remaining card space and scrolls */
.settings-logs-content {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
}
#logs-pagination { flex-shrink: 0; }

/* ── Inventory + Orders: viewport-fit table pages ───────────── */
#page-inventory,
#page-orders {
  overflow: hidden;
  padding: 16px;
}

/* Card fills remaining height as a flex column */
#page-inventory > .card,
#page-orders > .card {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* Filter bar and delete bar never shrink */
#page-inventory .filter-bar,
#page-orders .filter-bar,
#inv-delete-bar { flex-shrink: 0; }

/* Table wrap fills remaining space and scrolls vertically */
#page-inventory .table-wrap,
#page-orders .table-wrap {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
}

/* Pagination stays pinned at the bottom */
#page-inventory .pagination,
#page-orders .pagination { flex-shrink: 0; }

/* ── Dashboard ──────────────────────────────────────────────────
   Scope bar pinned, everything below it scrolls as one document: the
   page is a report, and a report with four independent scroll regions
   is four places to lose your position. */
#page-dashboard.page.active {
  overflow: hidden;
  padding: 0;
}

.dash-scope {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.dash-scope-trail { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; }
.dash-scope-controls { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

.crumb {
  font-size: 13px;
  font-weight: 600;
  color: var(--txt-2);
  white-space: nowrap;
}
.crumb--root { color: var(--txt-3); font-weight: 500; }
.crumb--leaf { color: var(--primary-text); }
.crumb-sep   { color: var(--txt-4); font-size: 13px; }

.dash-sku-search { position: relative; display: flex; align-items: center; }
.dash-sku-search .icon {
  position: absolute; left: 10px;
  width: 14px; height: 14px;
  color: var(--txt-4); pointer-events: none;
}
.dash-sku-search input { width: 230px; padding-left: 32px; }

.dash-sku-suggest {
  position: absolute;
  top: calc(100% + 4px); right: 0;
  min-width: 280px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  padding: 4px;
  z-index: 400;
  display: none;
  max-height: 300px;
  overflow-y: auto;
}
.dash-sku-suggest.open { display: block; }
.dash-sku-suggest button {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 8px 10px;
  background: transparent; border: none; border-radius: var(--r-sm);
  font-family: inherit; font-size: 12.5px; color: var(--txt-1);
  text-align: left; cursor: pointer;
}
.dash-sku-suggest button:hover { background: var(--surface-3); }
.suggest-meta  { font-size: 11.5px; color: var(--txt-4); flex-shrink: 0; }
.suggest-empty { padding: 10px; font-size: 12.5px; color: var(--txt-4); }

/* The report itself. One scroll container. */
.dash-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* ── Stat tiles ────────────────────────────────────────────────
   Hero numbers, not charts: a figure with its movement beside it is
   read faster than any plot of two points. */
.dash-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
@media (max-width: 1200px) { .dash-stats { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .dash-stats { grid-template-columns: 1fr; } }

.stat-tile {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  padding: 14px 16px;
  min-width: 0;
}
.stat-tile--warn { border-left-color: var(--warning); }
.stat-tile--loading { min-height: 108px; opacity: .5; }

.stat-label {
  font-size: 11.5px; font-weight: 600; color: var(--txt-3);
  text-transform: uppercase; letter-spacing: .04em;
}
.stat-value {
  font-family: var(--font-title);
  font-size: 26px; font-weight: 700; color: var(--txt-1);
  line-height: 1.15; margin: 4px 0 8px;
  font-variant-numeric: tabular-nums;
}
.stat-rows { display: flex; flex-direction: column; gap: 3px; }
.stat-row  { display: flex; align-items: center; gap: 6px; font-size: 11.5px; }
.stat-row-label  { color: var(--txt-4); min-width: 34px; }
.stat-row-prev   { color: var(--txt-4); }
.stat-row-strong { color: var(--txt-2); font-weight: 600; margin-left: auto; font-variant-numeric: tabular-nums; }

/* Movement. Colour AND an arrow AND a sign — three encodings, so the
   direction survives a colour-blind reader and a black-and-white print. */
.delta {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 11.5px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.delta--up   { color: #15803d; }
.delta--down { color: #b91c1c; }
.delta--flat { color: var(--txt-4); }
.delta--none { color: var(--txt-4); font-weight: 500; }

.stat-note {
  grid-column: 1 / -1;
  display: flex; align-items: flex-start; gap: 8px;
  padding: 10px 14px;
  font-size: 12px; line-height: 1.5;
  color: var(--txt-2);
  background: var(--warning-bg, #fffbeb);
  border: 1px solid var(--warning-bd, #fde68a);
  border-radius: var(--r-md);
}
.stat-note .icon { width: 15px; height: 15px; color: var(--warning); flex-shrink: 0; margin-top: 1px; }
.stat-note--error { background: var(--error-bg); border-color: var(--error-bd); color: var(--error); }

/* ── Charts ────────────────────────────────────────────────────── */
.dash-chart-card { padding: 0; }
.dash-chart-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding: 14px 16px 10px;
}
.dash-chart-title { font-size: 14px; font-weight: 700; color: var(--txt-1); }
.dash-chart-sub   { font-size: 12px; color: var(--txt-4); margin-top: 2px; }
.dash-chart-controls { display: flex; align-items: center; gap: 8px; }

.dash-chart-body { position: relative; height: 280px; padding: 0 12px 14px; }
.dash-chart-body--short { height: 190px; }

/* Segmented control — one measure at a time, because two measures on
   one plot needs two y-scales and then the crossings mean nothing. */
.seg-control {
  display: inline-flex;
  background: var(--surface-3);
  border-radius: var(--r-sm);
  padding: 2px;
}
.seg-btn {
  border: none; background: transparent;
  padding: 5px 11px;
  font-family: inherit; font-size: 12px; font-weight: 600;
  color: var(--txt-3); cursor: pointer;
  border-radius: calc(var(--r-sm) - 1px);
  transition: background var(--dur), color var(--dur);
}
.seg-btn:hover  { color: var(--txt-1); }
.seg-btn.active { background: var(--surface); color: var(--primary-text); box-shadow: var(--shadow-sm); }

.dash-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
@media (max-width: 1100px) { .dash-split { grid-template-columns: 1fr; } }

.dash-panel { padding: 0; display: flex; flex-direction: column; }
.dash-panel-head { padding: 14px 16px 6px; }
.dash-panel-table { border: none; border-radius: 0; }

/* A colour chip beside the name, so the chart and the table name the
   same market the same way. */
.series-dot {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 2px;
  margin-right: 7px;
  vertical-align: baseline;
}

/* ── Inventory position ────────────────────────────────────────── */
.dash-inv { padding: 4px 16px 10px; }
.inv-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 7px 0;
  font-size: 13px;
  border-bottom: 1px dashed var(--border);
}
.inv-row:last-child { border-bottom: none; }
.inv-label { color: var(--txt-3); }
.inv-value { font-weight: 600; color: var(--txt-1); font-variant-numeric: tabular-nums; }
.inv-row--warn   .inv-value { color: #b45309; }
.inv-row--danger .inv-value { color: #b91c1c; }

/* Recommendations, each one derived from a number already on screen. */
.dash-actions { padding: 4px 12px 14px; display: flex; flex-direction: column; gap: 8px; }
.action-item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  font-size: 12.5px; line-height: 1.5;
  color: var(--txt-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--r-md);
}
.action-item .icon { width: 16px; height: 16px; flex-shrink: 0; }
.action-text { flex: 1; min-width: 0; }
.action-item--danger { border-left-color: var(--error); }
.action-item--danger .icon { color: var(--error); }
.action-item--warn   { border-left-color: var(--warning); }
.action-item--warn   .icon { color: var(--warning); }
.action-item--ok     { border-left-color: var(--success); }
.action-item--ok     .icon { color: var(--success); }

.dash-sku-card { display: flex; flex-direction: column; }

/* A product's offers, shown beneath it rather than by replacing the
   page. Recessed so the nesting is obvious at a glance. */
.item-detail-row > .item-detail-cell {
  padding: 0;
  background: var(--surface-2);
  border-top: 1px solid var(--border);
}
.item-detail-loading {
  padding: 14px 20px;
  font-size: 12.5px;
  color: var(--txt-4);
}
.item-detail-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}
.item-detail-table th {
  padding: 8px 12px;
  text-align: left;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--txt-4);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.item-detail-table th.num,
.item-detail-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.item-detail-table td {
  padding: 8px 12px;
  color: var(--txt-2);
  border-bottom: 1px dashed var(--border);
}
.item-detail-table tr:last-child td { border-bottom: none; }
/* The first column lines up under the product it belongs to. */
.item-detail-table th:first-child,
.item-detail-table td:first-child { padding-left: 34px; }

/* Case arithmetic under the order quantity: shown, not folded in, so
   nobody wonders why 4 became 20. */
.order-cases {
  font-size: 10.5px;
  font-weight: 500;
  color: var(--txt-4);
  margin-top: 1px;
}

/* ── Inventory Forecasting ──────────────────────────────────────
   Same viewport-fit contract as the two pages above: the page holds
   still, the table scrolls. The KPI cards and the coverage line are
   fixed-height headers above it. */
#page-forecast.page.active {
  overflow: hidden;
  padding: 16px;
  gap: 12px;
}

#page-forecast > .forecast-table-card {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

#page-forecast .forecast-config,
#page-forecast .filter-bar,
#page-forecast .forecast-coverage,
#page-forecast .pagination { flex-shrink: 0; }

#page-forecast .table-wrap {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

.forecast-cards {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
@media (max-width: 1100px) { .forecast-cards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .forecast-cards { grid-template-columns: 1fr; } }

.forecast-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  padding: 14px 16px;
  min-width: 0;
}
/* The two cards that mean "act on this" carry their colour on the left
   edge rather than across the whole card: four tinted blocks read as an
   alarm, and then none of them do. */
.forecast-card--warn   { border-left-color: var(--warning); }
.forecast-card--danger { border-left-color: var(--error); }

.forecast-card-value {
  font-family: var(--font-title);
  font-size: 24px;
  font-weight: 700;
  color: var(--txt-1);
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.forecast-card-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--txt-2);
  margin-top: 3px;
}
.forecast-card-sub {
  font-size: 11.5px;
  color: var(--txt-4);
  margin-top: 3px;
  line-height: 1.45;
}

/* Horizon control: label, preset dropdown and the custom field read as
   one thing, because they are one setting. */
.forecast-horizon {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  flex: 0 0 auto;
}
.forecast-horizon-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--txt-3);
  white-space: nowrap;
}

/* How much history the forecast is standing on. Sits between the
   filters and the table because it qualifies everything below it. */
/* Configuration gaps. Optional inputs the forecast has not been given
   — each one changes the answer, and only the operator can supply it. */
.forecast-config-inner {
  padding: 12px 16px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--txt-2);
  background: var(--warning-bg, #fffbeb);
  border-bottom: 1px solid var(--warning-bd, #fde68a);
}
.forecast-config-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: var(--txt-1);
}
.forecast-config-head .icon { width: 15px; height: 15px; color: var(--warning); flex-shrink: 0; }
.forecast-config-list {
  margin: 8px 0 8px 26px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.forecast-config-list li { margin: 0; }
.forecast-config-foot {
  margin-left: 26px;
  color: var(--txt-3);
  font-size: 12px;
}
.forecast-config--ok {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface-2);
  border-bottom-color: var(--border);
  color: var(--txt-3);
}
.forecast-config--ok .icon { width: 14px; height: 14px; color: var(--success); flex-shrink: 0; }

.forecast-coverage-inner {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  font-size: 12px;
  color: var(--txt-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  line-height: 1.5;
}
.forecast-coverage-inner .icon {
  width: 14px; height: 14px;
  flex-shrink: 0;
  color: var(--txt-4);
}
.forecast-coverage--info .icon { color: var(--primary); }
.forecast-coverage--warn {
  background: var(--warning-bg, #fffbeb);
  color: var(--txt-2);
}
.forecast-coverage--warn .icon { color: var(--warning); }

/* ── Box Lookup dedicated page ──────────────────────────────── */
#page-box-lookup { overflow: hidden; }

.blookup-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  flex-shrink: 0;
  box-shadow: 0 1px 4px rgba(0,0,0,.04);
}

.blookup-body {
  flex: 1;
  overflow-y: auto;
  padding: 20px 24px;
}

.blookup-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 80px 24px;
  gap: 16px;
  text-align: center;
  color: var(--txt-4);
}
.blookup-empty-icon { opacity: .35; margin-bottom: 4px; }
.blookup-empty-title { font-size: 15px; font-weight: 600; color: var(--txt-3); }
.blookup-empty-sub { font-size: 13px; color: var(--txt-4); max-width: 320px; }

/* ── Uploads page ───────────────────────────────────────────── */
#page-uploads { overflow: hidden; }

.uploads-top {
  flex-shrink: 0;
  padding: 18px 24px 14px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

/* Upload History uses the same viewport-fit flex pattern as Inventory /
   Orders: the card becomes a flex column, the filter-bar sits at the top
   without scrolling, and only the table-wrap scrolls. This avoids the
   sticky-positioning quirks (transparent rows bleeding through, etc.)
   that previously appeared with a sticky filter-bar inside a scroll
   container. */
.uploads-history {
  flex: 1;
  overflow: hidden;
  padding: 16px 24px 24px;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.uploads-history > .card-table {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.uploads-history > .card-table > .filter-bar { flex-shrink: 0; }
.uploads-history > .card-table > .table-wrap {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
}

/* Sticky table headers across scrollable page sections.
   Settings tabs + Box Lookup still use a page-level scroll container, so
   their table-wraps need overflow:visible to let <thead> stick to the
   outer scrollbox. Uploads now scrolls inside .table-wrap itself, so it
   keeps the default overflow. */
#page-settings .tab-panel .table-wrap,
.blookup-body .table-wrap {
  overflow: visible;
}

/* ── Section header ─────────────────────────────────────────── */
.section-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 20px;
  gap: 12px;
}

.section-title   { font-family: var(--font-title); font-size: 20px; font-weight: 700; color: var(--txt-1); }
.section-sub     { font-size: 13px; color: var(--txt-3); margin-top: 3px; }
.section-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

/* ──────────────────────────────────────────────────────────────
   Responsive
   ─────────────────────────────────────────────────────────────
   Strategy:
   - Desktop  (>1024px): viewport-fit layout (no main page scroll —
     only tables, charts, and content regions scroll internally).
   - Tablet   (≤1024px): main wrapper scrolls; pages and inner
     regions revert to natural page flow. Sidebar still inline.
   - Mobile   (≤768px):  sidebar becomes off-canvas with backdrop.
                         Hamburger button in the topbar opens it.
   - Small    (≤480px):  tighter paddings and stacked elements.
   ────────────────────────────────────────────────────────────── */

/* ── Tablet & below: allow main page to scroll ──────────────── */
@media (max-width: 1024px) {
  #app-shell {
    height: auto;
    min-height: 100vh;
    overflow: visible;
  }
  .main-wrapper {
    height: auto;
    min-height: 100vh;
    overflow: visible;
  }
  .page-content {
    overflow: visible;
    flex: 1 1 auto;
  }
  .page.active {
    overflow: visible;
    flex: 1 1 auto;
  }

  /* Pages with custom viewport-fit flex layout revert to natural flow */
  #page-dashboard,
  #page-box-lookup,
  #page-uploads,
  #page-settings,
  #page-inventory,
  #page-orders,
  #page-forecast.page.active { overflow: visible; }

  #page-forecast .table-wrap {
    flex: 0 0 auto;
    overflow-x: auto;
    overflow-y: visible;
  }

  /* Internal scroll regions release their scroll on tablet — page scrolls instead */
  .dash-charts-area,
  .blookup-body,
  .uploads-history,
  #page-settings .tab-panel.active,
  .settings-logs-content {
    overflow: visible;
    flex: 0 0 auto;
  }

  /* Tables still scroll horizontally when they overflow */
  #page-inventory .table-wrap,
  #page-orders .table-wrap,
  .uploads-history .table-wrap {
    flex: 0 0 auto;
    overflow-x: auto;
    overflow-y: visible;
    max-height: none;
  }

  /* Settings tab content stops being a viewport-fit flex column */
  .settings-body { flex: 0 0 auto; }
  .settings-logs-card { min-height: 0; }

  /* Topbar no longer needs to be sticky inside a fixed shell */
  .topbar { position: sticky; top: 0; }

  /* Padding trims for denser content */
  #page-inventory,
  #page-orders { padding: 14px; }
  .uploads-top { padding: 14px 16px 12px; }
  .uploads-history { padding: 12px 16px 16px; }
  .blookup-search { padding: 10px 16px; }
  .blookup-body { padding: 16px; }
  .settings-sticky { padding: 14px 16px 0; }
  .settings-body { padding: 14px 16px 16px; }
}

/* ── Mobile: off-canvas sidebar with backdrop ───────────────── */
@media (max-width: 768px) {
  :root { --topbar-h: 56px; }

    .topbar { padding: 0 14px; gap: 10px; }
  .topbar-title { font-size: 16px; }

  /* Tighter page paddings */
  #page-inventory,
  #page-orders { padding: 10px; }
  .uploads-top { padding: 12px; }
  .uploads-history { padding: 10px 12px 14px; }
  .blookup-search { padding: 10px 12px; }
  .blookup-body { padding: 12px; }
  .settings-sticky { padding: 12px 12px 0; }
  .settings-body { padding: 12px; }
}

/* ── Small mobile: tightest layout ──────────────────────────── */
@media (max-width: 480px) {
  :root { --topbar-h: 52px; }
  .topbar { padding: 0 10px; gap: 8px; }
  .topbar-title { font-size: 15px; }
  .topbar-actions { gap: 6px; }
  .login-card { padding: 28px 22px; }
  .section-title { font-size: 18px; }
}

/* ── Workspace selector cards ───────────────────────────────── */
/* Hover lives here rather than inline on the element: inline styles
   cannot express :hover, so the cards previously had a background
   transition that nothing ever triggered. */
.org-card {
  cursor: pointer;
  padding: 14px 16px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.org-card:hover {
  background: var(--primary-50);
  border-color: var(--primary-100);
}
.org-card:hover .org-card-arrow { color: var(--primary); }
.org-card-arrow { color: var(--txt-4); font-size: 18px; transition: color .15s var(--ease); }

/* ── No organization access screen ──────────────────────────── */
#no-org-screen,
#forgot-screen {
  position: relative;
  min-height: 100vh;
  width: 100vw;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  box-sizing: border-box;
  overflow: hidden;
}

.no-org-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  padding: 40px 44px;
  width: 100%;
  max-width: 460px;
  text-align: center;
  animation: slideUp .25s var(--ease);
}

.no-org-icon {
  width: 56px;
  height: 56px;
  margin: 0 auto 18px;
  border-radius: 50%;
  background: var(--warning-bg);
  border: 1px solid var(--warning-bd);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--warning);
}
.no-org-icon .icon { width: 26px; height: 26px; }

.no-org-title { font-size: 20px; margin-bottom: 8px; color: var(--txt-1); }
.no-org-text  { font-size: 13.5px; color: var(--txt-3); line-height: 1.6; margin-bottom: 24px; }

@media (max-width: 560px) {
  .no-org-card { padding: 30px 22px; }
}

/* ── Avatar picture ───────────────────────────── */
/* The avatar shows an uploaded picture when there is one and the
   account's initial when there is not. */
.sidebar-avatar {
  overflow: hidden;
  background-size: cover;
  background-position: center;
}
/* With a picture set the initial must not show through it. */
.sidebar-avatar.has-image { color: transparent; background-color: transparent; }

/* SKU structure banner. Fixed height above the scrolling card, per the
   page contract: chrome does not scroll, the configuration does. */
.sku-struct-banner {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 16px;
  margin-bottom: 12px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--txt-2);
  background: var(--primary-50);
  border: 1px solid var(--primary-100);
  border-radius: var(--r-md);
}
.sku-struct-banner .icon {
  width: 17px; height: 17px;
  color: var(--primary);
  flex-shrink: 0;
  margin-top: 2px;
}
.sku-struct-banner strong { color: var(--txt-1); }
.sku-struct-banner-warn {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed var(--primary-100);
  color: var(--txt-3);
}

/* ── Organization Management ────────────────────────────────────
   The page itself does not scroll. The configuration card fills the
   remaining height and scrolls internally, with its save buttons pinned
   at the bottom — a Save you have to hunt for by scrolling is a Save
   people stop trusting they pressed. */
#page-org-manage.page.active {
  padding: 24px;
  overflow: hidden;
}

.org-manage-stack {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.org-config-card {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 0;
}

/* min-height:0 is what lets a flex child shrink below its content and
   scroll; without it the card grows and pushes the page instead. */
.org-config-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 18px 4px;
}

.org-config-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0 18px;
}

.org-config-divider {
  height: 1px;
  background: var(--border);
  margin: 4px 0 18px;
}

.org-config-footer {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 18px;
  border-top: 1px solid var(--border);
  background: var(--surface);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}
.org-config-footer .form-error { margin: 0 auto 0 0; }

/* Back bar on the Organization page stays put while the SKU editor
   scrolls beneath it — the way out of a long form should not require
   scrolling back to the top to find it. */
#page-org-manage .section-header {
  position: sticky;
  top: 0;
  z-index: 20;
  margin: 0 0 12px 0;
  padding: 0 0 12px 0;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

/* ── Users and Organizations: pin the controls, scroll the rows ──
   These two pages scrolled as a whole, so the search box and the New
   button left the screen as soon as you moved down a list — on the two
   screens where you are most likely to search, then act on what you
   found.

   Same structure Inventory and Orders already use: the PAGE does not
   scroll, the table does. That keeps the filter bar and the header where
   they are without a single sticky offset to keep in sync with padding,
   which is what makes sticky bars drift when a header height changes. */
#page-users.page.active,
#page-organizations.page.active,
#page-logs.page.active,
#page-system.page.active {
  padding: 24px;
  overflow: hidden;
}

#page-users .section-header,
#page-organizations .section-header { flex: 0 0 auto; }

#page-users > .card-table,
#page-organizations > .card-table {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

#page-users > .card-table > .filter-bar,
#page-organizations > .card-table > .filter-bar { flex-shrink: 0; }

/* min-height:0 is what lets a flex child shrink below its content and
   scroll; without it the table grows and pushes the page instead. */
#page-users > .card-table > .table-wrap,
#page-organizations > .card-table > .table-wrap {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}


/* ── Activity Log and Diagnostics ───────────────────────────────
   Same contract as Users and Organizations: the PAGE never scrolls, the
   content inside it does. A page that scrolls AND contains a scrolling
   table gives two scrollbars racing each other, and the one under the
   cursor is rarely the one you meant. */
#page-logs > .card,
#page-system > .card {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* min-height:0 is what lets a flex child shrink below its content. */
#page-logs .settings-logs-content {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* Diagnostics: the content box is a column that FILLS, not one that
   scrolls. Everything on this page has a fixed height except the
   terminal, so the terminal takes whatever is left and scrolls inside
   itself — one scrollbar on the page, and it is the one you want. */
#page-system #system-status-content {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

#page-logs .pagination { flex-shrink: 0; }

/* Filter bar: fixed at the top of the card while the entries scroll
   under it, so the filters you set stay visible next to the results
   they produced. */
#page-logs .logs-filters { flex: 0 0 auto; }

.logs-filters {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}

.logs-filter-search {
  position: relative;
  flex: 1 1 260px;
  min-width: 200px;
  display: flex;
  align-items: center;
}
.logs-filter-search .icon {
  position: absolute;
  left: 10px;
  width: 15px; height: 15px;
  color: var(--txt-4);
  pointer-events: none;
}
.logs-filter-search input {
  width: 100%;
  padding: 7px 10px 7px 32px;
  font-size: 13px;
  font-family: inherit;
  color: var(--txt-1);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
.logs-filter-search input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-50);
}

.logs-filter-dates {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
}
.logs-filter-dates label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--txt-4);
  margin: 0;
}
.logs-filter-dates input {
  padding: 6px 8px;
  font-size: 12.5px;
  font-family: inherit;
  color: var(--txt-1);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
.logs-filter-dates input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-50);
}

@media (max-width: 768px) {
  .logs-filters { padding: 10px; gap: 8px; }
  .logs-filter-dates { flex: 1 1 100%; }
  .logs-filter-dates input { flex: 1 1 0; min-width: 0; }
}

/* Integrations. Ordinary content page: the PAGE does not scroll, the
   content box inside it does. Styles for the cards live in
   js/integrations.js next to the markup; what belongs here is the
   page-level scroll contract. */
#page-integrations-amazon.page.active {
  padding: 24px;
  overflow: hidden;
}
#page-integrations-amazon > #integrations-content {
  flex: 1 1 auto;
  min-height: 0;      /* not optional — without it the cards push the page */
  overflow-y: auto;
}

/* Diagnostics console. The heights come from js/diagnostics.js, which
   keeps its own styles alongside the markup it owns; what belongs HERE
   is only the page-level contract those styles hang off.

   The console is a column that FILLS: status bar, health cards and the
   maintenance row are fixed, the workspace takes the rest, and the one
   scroll region is the selected panel's body. The terminal sits at the
   bottom of the right column and is collapsed until something is run,
   so it never eats height it is not using. */
#page-system #system-status-content > .diag {
  flex: 1 1 auto;
  min-height: 0;
}

/* Any preformatted output wraps rather than stretching its frame — the
   panel body is what scrolls, and never sideways. */
#page-system pre {
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0;
}
