/*
 * GraphX Manage — component layer for the Product Catalog prototype.
 * Built on tokens.css, following DESIGN_SYSTEM.md §2 (component inventory),
 * §3 (screen archetypes) and §4 (interaction rules). Class names mirror the
 * real app's vocabulary (.kpi, .navitem, .ibtn, .pager, .badge, .btn-tool, …)
 * so this prototype reads as the same system, not a lookalike.
 */

* { 
  box-sizing: border-box; 
  -ms-overflow-style: none; 
  scrollbar-width: none; 
}
*::-webkit-scrollbar {
  display: none;
}
html, body { margin: 0; padding: 0; }

body {
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { font-family: var(--font-display); margin: 0; }
::selection { background: rgba(0,255,255,.25); }

:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--focus-ring);
}

/* ---------- prototype banner (honest-labeling rule, §4.6) ---------- */
.proto-banner {
  display: none;
}
.proto-banner b { color: var(--ink); }

/* ---------- app shell ---------- */
.app-shell { display: flex; min-height: 100vh; }

.sidebar {
  width: var(--nav-width);
  flex: none;
  background: var(--sidebar);
  border-right: 1px solid var(--line);
  padding: 18px 12px 20px;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;  /* brand + CTA stay pinned; only .navscroll scrolls (mirrors real .sidebar) */
}

/* Matches apps/web/app/globals.css's .brand/.brand-lockup exactly (real file, real sizing) —
   the CSS-drawn "GX" mark + "GraphX Manage" wordmark this replaced was a placeholder, not the
   real logo. */
.brand { display: block; padding: 2px 8px 14px; }
.brand-lockup { display: block; width: 100%; max-width: 196px; height: auto; }

/* The nav list owns the scroll, so the brand lockup + "+ New order" CTA above it stay fixed at
   the top no matter how long the nav gets. min-height:0 lets this flex child shrink below its
   content height so overflow actually engages (mirrors apps/web/app/globals.css's .navscroll). */
.navscroll {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  margin: 0 -6px; padding: 0 6px 4px;
  scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.16) transparent;
  overscroll-behavior: contain;
}
.navscroll::-webkit-scrollbar { width: 8px; }
.navscroll::-webkit-scrollbar-track { background: transparent; }
.navscroll::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,.13); border-radius: 8px;
  border: 2px solid transparent; background-clip: content-box;
}
.navscroll::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.24); background-clip: content-box; }

/* Dashboard link + "+ New order" CTA above the accordion areas — mirrors apps/web/app/nav.tsx's
   persistent chrome (DASHBOARD_ITEM + the .cta link), dimmed here since both are outside this
   prototype's Product Catalog scope (see GX.NAV in app.js). */
.cta {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin: 0 6px 14px; padding: 10px; border-radius: 11px; border: 0;
  background: var(--cyan); color: #06122b; font-weight: 800; font-size: 13px;
  box-shadow: 0 6px 18px rgba(0,255,255,.16);
}
.navitem.navitem-root { margin-top: 2px; }

/* Sub-group header inside the modeled Product Catalog area (Products / Catalog Setup / Pricing) —
   mirrors real nav.tsx's .navgroup-label (rendered only for multi-item groups in a multi-group
   area, same rule this prototype's single modeled area follows). */
.navgroup-label {
  margin: 9px 10px 4px; padding-top: 9px;
  border-top: 1px solid var(--line);
  font-size: 9px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-mut);
}
.navarea .navgroup-label:first-child { border-top: 0; padding-top: 0; margin-top: 2px; }


/* Hard separation between areas — a hairline rule + top spacing, so each module reads as its own
   block (mirrors apps/web/app/globals.css's .navarea). The first area drops the divider. */
.navarea { display: flex; flex-direction: column; gap: 2px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line-2); }
.navarea:first-of-type { margin-top: 2px; padding-top: 0; border-top: 0; }
/* Accordion header — full-width button that toggles its area open/closed (mirrors
   apps/web/app/globals.css's real .navarea-label; app.js's toggleArea() drives the .open class).
   Cyan, heavy, wide-tracked uppercase with a leading lucide icon — the real app's area headers. */
.navarea-label {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; border: 0; background: none; cursor: pointer; font-family: inherit; text-align: left;
  border-radius: 8px;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--cyan);
  opacity: .72;
  transition: opacity .12s, background .12s;
  padding: 7px 10px;
  min-width: 0;
}
/* icon + label sit together on the left; the chevron is pushed to the right by the label's
   space-between. */
.navarea-title { display: flex; align-items: center; gap: 8px; min-width: 0; }
.navarea-icon { flex: 0 0 auto; color: currentColor; }
.navarea-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.navarea-label:hover { opacity: 1; background: rgba(255,255,255,.04); }
.navarea.open > .navarea-label { opacity: .95; }
/* Caret built from two borders: points right when closed, rotates down when the area is open. */
.navarea-chev {
  width: 6px; height: 6px; flex-shrink: 0;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); transition: transform .15s ease; opacity: .7;
}
.navarea.open .navarea-chev { transform: rotate(45deg); }
.navitem {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border-radius: var(--nav-item-radius);
  color: var(--ink-dim);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  position: relative;
}
.navitem:hover { background: rgba(255,255,255,.045); color: var(--ink); }
.navitem .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .35; flex: none; }
.navitem.active {
  background: rgba(0,255,255,.09);
  color: var(--ink);
  font-weight: 600;
}
.navitem.active::before {
  content: ""; position: absolute; left: -12px; top: 8px; bottom: 8px; width: 3px;
  border-radius: 3px; background: var(--cyan);
}
.navitem.active .dot { background: var(--cyan); opacity: 1; }
.navitem .tag {
  margin-left: auto; font-size: 9.5px; font-weight: 700; letter-spacing: .05em;
  color: var(--blue-ink); background: rgba(101,154,255,.14); border: 1px solid rgba(101,154,255,.3);
  border-radius: 5px; padding: 1px 5px;
}
.navsub { margin-left: 20px; display: flex; flex-direction: column; gap: 1px; }
.navsub .navitem { font-size: 12.5px; padding: 6px 10px; }

.main-col { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  position: sticky; top: 0; z-index: 5;
  background: var(--topbar-bg);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  padding: 0 24px;
  min-height: 56px;
  display: flex; align-items: center; gap: 16px;
}
.crumbbar { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--ink-mut); flex: 1; min-width: 0; }
.crumbbar a { color: var(--ink-dim); }
.crumbbar a:hover { color: var(--cyan); }
.crumbbar .sep { opacity: .5; }
.crumbbar .current { color: var(--ink); font-weight: 600; }
.crumb-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }

.topbar-search {
  display: flex; align-items: center; gap: 8px;
  background: var(--input-bg, var(--panel));
  border: 1px solid var(--line); border-radius: 10px;
  padding: 6px 12px; width: 220px; color: var(--ink-mut); font-size: 12.5px;
}

.qc { display: flex; align-items: center; gap: 6px; }
.qc button {
  border-radius: var(--badge-radius); padding: 5px 12px; font-size: 12px; font-weight: 700;
  border: 1px solid var(--line-2); background: transparent; cursor: pointer;
}
.qc-so { color: var(--cyan); border-color: rgba(0,255,255,.35); background: rgba(0,255,255,.08); }
.qc-qt { color: var(--blue-ink); border-color: rgba(101,154,255,.35); background: rgba(101,154,255,.08); }
.qc-cu { color: var(--slate-ink); border-color: var(--line-2); background: rgba(255,255,255,.05); }

/* Theme toggle — a proper square icon button (min-height:0/padding:0 override the global button
   rule's 38px min-height, which was stretching it into a 32×38 rectangle). The sun/moon icons are
   stacked and cross-fade + rotate when the theme flips. */
.theme-toggle {
  position: relative; width: 34px; height: 34px; min-height: 0; padding: 0; flex: none;
  border-radius: 9px; border: 1px solid var(--line-2);
  background: var(--panel); color: var(--ink-dim); cursor: pointer; overflow: hidden;
}
.theme-toggle:hover { color: var(--cyan); border-color: rgba(0,255,255,.4); background: rgba(0,255,255,.06); }
.theme-toggle:active { transform: scale(.9); }
.theme-toggle .ico {
  position: absolute; inset: 0; display: grid; place-items: center;
  transition: opacity .3s ease, transform .45s cubic-bezier(.5,1.5,.5,1);
}
.theme-toggle .ico svg { width: 17px; height: 17px; display: block; }
/* dark (default): moon in view, sun rotated out */
.theme-toggle .ico-sun  { opacity: 0; transform: rotate(-90deg) scale(.4); }
.theme-toggle .ico-moon { opacity: 1; transform: rotate(0) scale(1); }
/* light: sun in view, moon rotated out */
:root[data-theme="light"] .theme-toggle .ico-sun  { opacity: 1; transform: rotate(0) scale(1); }
:root[data-theme="light"] .theme-toggle .ico-moon { opacity: 0; transform: rotate(90deg) scale(.4); }

.idchip { display: flex; align-items: center; gap: 8px; padding: 4px 6px 4px 4px; border-radius: 10px; cursor: pointer; }
.idchip .av { width: 28px; height: 28px; border-radius: 50%; background: var(--grad); display: grid; place-items: center; font-size: 11px; font-weight: 800; color: var(--navy); }
.idchip .name { font-size: 12.5px; font-weight: 600; }
.idchip .role { font-size: 10.5px; color: var(--ink-mut); }

.content { padding: 24px 28px 64px; flex: 1; }

/* ---------- PageHeader ---------- */
.page-h-wrap {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
  margin-bottom: 22px; padding-bottom: 20px; flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
}
.page-h-back {
  font-size: 12px; color: var(--ink-mut); margin-bottom: 8px; display: inline-flex; align-items: center; gap: 4px;
}
.page-h-back:hover { color: var(--cyan); }
.page-h { font-size: 23px; font-weight: 700; color: var(--ink-strong); letter-spacing: -.01em; line-height: 1.25; }
.page-h-meta { color: var(--ink-mut); font-size: 12.5px; margin-top: 5px; max-width: 62ch; line-height: 1.5; }
.page-h-actions { display: flex; gap: 8px; flex: none; align-items: center; }

/* ---------- search box (icon + input + clear) ---------- */
.search-box { position: relative; display: flex; align-items: center; }
.search-box .search-icon {
  position: absolute; left: 11px; width: 15px; height: 15px; color: var(--ink-mut);
  pointer-events: none; flex: none;
}
.search-box input {
  padding-left: 34px; padding-right: 30px; width: 100%;
}
.search-box .search-clear {
  position: absolute; right: 5px; width: 22px; height: 22px; min-height: 0; padding: 0;
  border: none; background: transparent; color: var(--ink-mut); border-radius: 6px;
  display: none; align-items: center; justify-content: center; font-size: 13px; cursor: pointer;
}
.search-box .search-clear:hover { background: rgba(255,255,255,.08); color: var(--ink); }
.search-box.has-value .search-clear { display: flex; }
.split-search { margin-bottom: 10px; }
.split-search .search-box { width: 100%; }
.list-empty-row { text-align: center; }

/* ---------- buttons ---------- */
button, .btn {
  font-family: var(--font-ui);
  font-size: var(--button-font-size);
  font-weight: var(--button-font-weight);
  border-radius: var(--button-radius);
  padding: var(--button-padding-y) var(--button-padding-x);
  min-height: var(--button-min-height);
  border: 1px solid var(--line-2);
  background: var(--panel-2);
  color: var(--ink);
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
  transition: background .12s ease, border-color .12s ease, opacity .12s ease;
}
button:hover { background: rgba(255,255,255,.08); }
button:disabled { opacity: .42; cursor: not-allowed; }
:is(button,a).primary { background: rgba(0,255,255,.13); border-color: rgba(0,255,255,.4); color: var(--cyan); }
:is(button,a).primary:hover { background: rgba(0,255,255,.19); }
:is(button,a).ghost { background: transparent; border-color: transparent; color: var(--cyan); padding-left: 6px; padding-right: 6px; }
:is(button,a).ghost:hover { background: rgba(0,255,255,.08); }
:is(button,a).btn-add {
  background: var(--grad); border: none; color: var(--navy); font-weight: 700;
}
:is(button,a).btn-add:hover { filter: brightness(1.06); }
:is(button,a).btn-tool { background: rgba(101,154,255,.10); border-color: rgba(101,154,255,.35); color: var(--blue-ink); }
:is(button,a).btn-bulk { background: rgba(255,255,255,.05); border-color: var(--line-2); color: var(--ink-dim); }
button.danger { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger-text); }
button.small { min-height: 30px; padding: 5px 10px; font-size: 12px; }
.ibtn {
  width: 26px; height: 26px; min-height: 0; padding: 0; justify-content: center;
  border-radius: 8px; background: transparent; border: 1px solid transparent; color: var(--ink-mut);
}
.ibtn:hover { background: rgba(255,255,255,.07); color: var(--ink); }
.ibtn.danger { color: var(--danger-text); }
/* An inline SVG with a viewBox but no width/height would size to its container/intrinsic box and
   render huge inside the 26px button — pin every .ibtn glyph to a crisp 15px. */
.ibtn svg { width: 15px; height: 15px; display: block; }
.action-link {
  min-width: 74px; height: auto; min-height: 0; white-space: nowrap;
  background: transparent; border: none; color: var(--cyan); padding: 2px 4px; font-size: 12.5px; font-weight: 600;
}
.action-link:hover { text-decoration: underline; background: transparent; }
.topbar-launch, .launch-storefront {
  background: rgba(255,255,255,.05); border: 1px solid var(--line-2); color: var(--ink-dim); font-size: 12px;
}

/* ---------- cards / panels ---------- */
.card, .panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--card-radius);
  padding: var(--card-padding);
}
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.panel-head h2, .panel-head h3 { font-size: 15px; font-weight: 700; }
.panel-head-actions { display: flex; gap: 8px; }
.panel-desc { color: var(--ink-mut); font-size: 12.5px; margin: -8px 0 14px; }

.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; margin-bottom: 22px; }
.kpi { position: relative; background: var(--panel); border: 1px solid var(--line); border-radius: var(--card-radius); padding: 16px 18px; overflow: hidden; }
.kpi::after { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--cyan); }
.kpi .lbl { font-size: 11px; color: var(--ink-mut); text-transform: uppercase; letter-spacing: .06em; }
.kpi .val { font-size: 24px; font-weight: 800; color: var(--ink-strong); margin-top: 4px; font-variant-numeric: tabular-nums; }
.kpi .sub { font-size: 11.5px; color: var(--ink-mut); margin-top: 2px; }

/* ---------- tables / DataTable / Pager ---------- */
.gridwrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--card-radius); }
table.dt { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 720px; }
table.dt thead th {
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.02));
  color: var(--ink-dim); text-align: left; font-weight: 600; font-size: 11.5px;
  letter-spacing: .03em; text-transform: uppercase;
  padding: 10px 14px; border-bottom: 1px solid var(--line-2); white-space: nowrap;
}
table.dt thead th.sortable { cursor: pointer; }
table.dt thead th .car { opacity: .5; font-size: 10px; margin-left: 4px; }
table.dt tbody td { padding: 10px 14px; border-bottom: 1px solid var(--line); vertical-align: middle; }
table.dt tbody tr:nth-child(even) { background: rgba(255,255,255,.015); }
table.dt tbody tr:hover { background: rgba(0,255,255,.035); }
table.dt tbody tr:last-child td { border-bottom: none; }
.cell-mut { color: var(--ink-mut); }
.cell-name { font-weight: 600; color: var(--ink); }
.cell-actions { text-align: right; white-space: nowrap; }
.cell-actions > * { margin-left: 4px; vertical-align: middle; }
.thumb { width: 34px; height: 34px; border-radius: 8px; background: var(--panel-2); border: 1px solid var(--line); display: inline-block; }

.pager { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 4px 0; flex-wrap: wrap; font-size: 12.5px; color: var(--ink-mut); }
.pager .pages { display: flex; gap: 4px; }
.pager button { min-height: 28px; padding: 4px 10px; font-size: 12px; }
.pager button.cur { background: var(--cyan); color: var(--pager-cur-text); border-color: var(--cyan); }
.pager select { min-height: 28px; }

/* ---------- filter bar ---------- */
.filterbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.filterbar .search-box { flex: 1 1 220px; min-width: 200px; max-width: 380px; }
.filterbar select { width: auto; min-width: 132px; }
.filter-results { font-size: 12px; color: var(--ink-mut); white-space: nowrap; margin-left: auto; padding: 0 2px; font-variant-numeric: tabular-nums; }
.filterbar-toolbar { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }

/* ---------- forms: Section / FormGrid / FormField / FormActions ---------- */
.section { background: var(--panel); border: 1px solid var(--line); border-radius: var(--card-radius); padding: var(--card-padding); margin-bottom: 18px; }
.section-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 16px; }
.section-head h3 { font-size: 14.5px; font-weight: 700; }
.section-head p { margin: 3px 0 0; font-size: 12px; color: var(--ink-mut); }

.formgrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px 16px; }
.formgrid.col-1 { grid-template-columns: 1fr; }
@media (max-width: 640px) { .formgrid { grid-template-columns: 1fr; } }

/* Scoped to caption-style labels only (plain "Field Name" text) — a label that wraps a
   control (check-row, toggle, or any other clickable option row nested in a .field) is a
   control, not a caption, and must keep its own layout/case. Without :not(:has(input)) this
   descendant selector clobbered every such label — forcing them to display:block (breaking
   their flex layout) and text-transform:uppercase (shouting normal-case option text) — with
   radio inputs hit hardest, since only "checkbox" had a width override, so a plain <input
   type="radio"> also inherited the global input{width:100%} rule meant for text fields. */
.field label:not(:has(input)) {
  display: block; font-size: var(--label-fs); font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-mut); margin-bottom: 6px;
}
.field label .req { color: var(--danger-text); margin-left: 3px; }
.field .hint { font-size: var(--hint-fs); color: var(--ink-mut); margin-top: 5px; }
.field .err { font-size: var(--hint-fs); color: var(--danger-text); margin-top: 5px; }

input, select, textarea {
  width: 100%; background: var(--panel-2); border: 1px solid var(--line-2); border-radius: 9px;
  color: var(--ink); font-family: var(--font-ui); font-size: 13px; padding: 9px 11px;
}
input:disabled, select:disabled, textarea:disabled { opacity: .5; }
input::placeholder { color: var(--ink-mut); }
/* The select control's own background is a translucent panel tint (--panel-2); that must not
   bleed into the native dropdown popup, where near-white text over it is unreadable. Pin the
   option rows to an opaque, theme-aware surface (navy in dark, white in light). Pairs with
   color-scheme (tokens.css) so the popup renders correctly across browsers. */
select option, select optgroup { background-color: var(--modal-bg); color: var(--ink); }

.form-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }
.form-actions.start { justify-content: flex-start; }

/* ---------- badges / chips / status pills ---------- */
.badge { display: inline-flex; align-items: center; gap: 5px; border-radius: var(--badge-radius); padding: var(--badge-padding); font-size: 11.5px; font-weight: 700; border: 1px solid transparent; }
.badge.ok { background: var(--ok-bg); color: var(--ok-text); border-color: var(--ok-border); }
.badge.info { background: var(--info-bg); color: var(--info-text); border-color: var(--info-border); }
.badge.warn { background: var(--warn-bg); color: var(--warn-text); border-color: var(--warn-border); }
.badge.danger { background: var(--danger-bg); color: var(--danger-text); border-color: var(--danger-border); }
.badge.active { background: var(--active-bg); color: var(--active-text); border-color: var(--active-border); }
.badge.neutral { background: var(--neutral-bg); color: var(--neutral-text); border-color: var(--neutral-border); }
.badge .dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.tag-ops { font-size: 9.5px; font-weight: 800; letter-spacing: .05em; color: var(--blue-ink); background: rgba(101,154,255,.14); border: 1px solid rgba(101,154,255,.3); border-radius: 5px; padding: 1px 6px; }

.chip { display: inline-flex; align-items: center; gap: 6px; background: rgba(255,255,255,.05); border: 1px solid var(--line-2); color: var(--ink-dim); border-radius: 999px; padding: 5px 10px 5px 12px; font-size: 12px; }
.chip button { min-height: 0; padding: 0; border: none; background: transparent; color: var(--ink-mut); font-size: 13px; }
.chip button:hover { color: var(--danger-text); background: transparent; }

/* ---------- tabs ---------- */
.tabstrip { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin-bottom: 20px; overflow-x: auto; }
.tabstrip button {
  border: none; background: transparent; border-radius: 0; min-height: 0;
  padding: 11px 16px; font-size: 13px; font-weight: 600; color: var(--ink-mut);
  border-bottom: 2px solid transparent; white-space: nowrap;
}
.tabstrip button:hover { color: var(--ink); background: transparent; }
.tabstrip button.active { color: var(--cyan); border-bottom-color: var(--cyan); }
.tabstrip button .count { margin-left: 6px; font-size: 10.5px; background: rgba(255,255,255,.08); border-radius: 999px; padding: 1px 6px; color: var(--ink-mut); }
.tabstrip button.active .count { background: rgba(0,255,255,.16); color: var(--cyan); }
.tabpanel { display: none; }
.tabpanel.active { display: block; }

/* ---------- split pane (list + detail) ---------- */
.splitpane { display: grid; grid-template-columns: 320px 1fr; gap: 18px; align-items: start; }
@media (max-width: 900px) { .splitpane { grid-template-columns: 1fr; } }
.split-list { border: 1px solid var(--line); border-radius: var(--card-radius); background: var(--panel); overflow: hidden; }
.split-list-item { padding: 12px 14px; border-bottom: 1px solid var(--line); cursor: pointer; font-size: 13px; }
.split-list-item:last-child { border-bottom: none; }
.split-list-item:hover { background: rgba(255,255,255,.03); }
.split-list-item.active { background: rgba(0,255,255,.07); border-left: 2px solid var(--cyan); }
.split-list-item .t { font-weight: 600; }
.split-list-item .s { color: var(--ink-mut); font-size: 11.5px; margin-top: 2px; }

/* ---------- category tree-table (Manage Categories) ---------- */
/* The tree is rendered as an aligned table: a header + one grid row per visible node. Every row
   shares the same column template (via --tree-cols), so the Products / Sub-categories / Actions
   columns line up at every depth; only the Category cell is indented (by --depth), which keeps
   parent/child obvious without knocking the number columns out of alignment. Reuses the app's
   existing table idiom — same --line row separators and cyan-tint row hover as .dt. */
.tree-table { --tree-cols: minmax(0, 1fr) 150px 160px 46px; }
.tree-head, .tree-row {
  display: grid; grid-template-columns: var(--tree-cols); align-items: center; column-gap: 12px;
}
.tree-head {
  padding: 9px 12px; border-bottom: 1px solid var(--line-2);
  font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink-mut);
}
.tree { display: flex; flex-direction: column; }

.tree-row {
  padding: 8px 12px; font-size: 13px; border-bottom: 1px solid var(--line);
  cursor: default; transition: background .1s ease;
}
.tree-row:last-child { border-bottom: 0; }
.tree-row.has-children { cursor: pointer; }
.tree-row:hover { background: rgba(0,255,255,.035); }          /* same tint as .dt row hover */

/* category cell — the only indented cell; twist + name live here */
.tr-cat { display: flex; align-items: center; gap: 8px; min-width: 0; padding-left: calc(var(--depth, 0) * 22px); }
.tree-row .twist {
  width: 15px; height: 15px; flex: none; display: inline-flex; align-items: center; justify-content: center;
  color: var(--ink-mut); font-size: 9px; line-height: 1; transition: transform .15s ease;
}
.tree-row.collapsed .twist { transform: rotate(-90deg); }
.tree-row .twist.leaf { font-size: 5px; opacity: .4; }
.tr-cat .n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); font-weight: 500; }
.tree-row.inactive .tr-cat .n { color: var(--ink-mut); }
/* Inactive is the only status shown (Active is implied) — a quiet outlined tag, not a pill. */
.tr-cat .tag-off {
  flex: none; font-size: 9.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-mut); border: 1px solid var(--line-2); border-radius: 5px; padding: 1px 6px;
}

/* number columns — left-aligned, tabular so they read as a column */
.tr-num { color: var(--ink-dim); font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tr-num.muted { color: var(--ink-mut); }

/* actions — one quiet, always-present menu button (no hover-reveal, no layout shift) */
.tr-actions { display: flex; justify-content: flex-end; }
.tr-actions .tree-menu { opacity: .5; transition: opacity .1s ease; }
.tree-row:hover .tr-actions .tree-menu, .tr-actions .tree-menu:focus-visible { opacity: 1; }

/* group (top-level) rows read a touch stronger */
.tree-row.is-group .tr-cat .n { font-weight: 700; font-size: 13.5px; color: var(--ink-strong); }
.tree-row.is-group .twist { color: var(--ink-dim); }

/* ---------- notice ---------- */
.notice { display: flex; align-items: flex-start; gap: 10px; border-radius: 10px; padding: 12px 14px; font-size: 13px; margin-bottom: 16px; border: 1px solid; }
.notice.error { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger-text); }
.notice.success { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok-text); }
.notice.info { background: var(--info-bg); border-color: var(--info-border); color: var(--info-text); }
.notice .x { margin-left: auto; cursor: pointer; opacity: .7; }

/* ---------- modal ---------- */
.modal-overlay { position: fixed; inset: 0; background: var(--overlay); display: none; align-items: center; justify-content: center; z-index: 50; padding: 20px; }
.modal-overlay.open { display: flex; }
.modal { background: var(--modal-bg); border: 1px solid var(--line-2); border-radius: 16px; width: 100%; max-width: 480px; padding: 22px; box-shadow: 0 20px 60px rgba(0,0,0,.4); }
.modal h3 { font-size: 16px; margin-bottom: 4px; }
.modal .sub { color: var(--ink-mut); font-size: 12.5px; margin-bottom: 18px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }

/* ---------- stepper (wizards) ---------- */
.stepper { display: flex; align-items: center; gap: 10px; margin-bottom: 22px; }
.step { display: flex; align-items: center; gap: 8px; color: var(--ink-mut); font-size: 12.5px; font-weight: 600; }
.step .n { width: 22px; height: 22px; border-radius: 50%; background: var(--panel-2); border: 1px solid var(--line-2); display: grid; place-items: center; font-size: 11px; }
.step.active { color: var(--ink); }
.step.active .n { background: rgba(0,255,255,.14); border-color: var(--cyan); color: var(--cyan); }
.step.done .n { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok-text); }
.step-sep { width: 24px; height: 1px; background: var(--line-2); }

/* ---------- empty state ---------- */
.empty { text-align: center; padding: 48px 20px; color: var(--ink-mut); }
.empty .glyph { font-size: 26px; margin-bottom: 10px; opacity: .6; }
.empty h4 { color: var(--ink); font-size: 14.5px; margin-bottom: 4px; }
.empty p { font-size: 12.5px; margin: 0 0 14px; }

/* ---------- misc helpers ---------- */
.muted { color: var(--ink-mut); }
.mono { font-family: "SFMono-Regular", Consolas, monospace; font-size: 12px; }
.hr { border: none; border-top: 1px solid var(--line); margin: 18px 0; }
.stack { display: flex; flex-direction: column; gap: 10px; }
.row { display: flex; align-items: center; gap: 10px; }
.row.between { justify-content: space-between; }
.right { margin-left: auto; }
.mt-0 { margin-top: 0; }
.gate-note { font-size: 12px; color: var(--ink-mut); display: flex; align-items: center; gap: 6px; }
.gate-note .k { color: var(--ink); font-weight: 600; }

/* ---------- action menu (dropdown) ---------- */
.gx-menu {
  position: fixed;
  min-width: 190px;
  background: var(--modal-bg);
  border: 1px solid var(--line-2);
  border-radius: 10px;
  box-shadow: 0 12px 28px rgba(0,0,0,.35);
  padding: 6px;
  z-index: 80;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.gx-menu-item { text-align: left; background: transparent; border: none; padding: 8px 10px; font-size: 13px; border-radius: 7px; color: var(--ink); min-height: 0; width: 100%; justify-content: flex-start; }
.gx-menu-item:hover:not(:disabled) { background: rgba(255,255,255,.07); }
.gx-menu-item:disabled { opacity: .42; cursor: not-allowed; }
.gx-menu-item.danger { color: var(--danger-text); }
.gx-menu-div { height: 1px; background: var(--line); margin: 4px 2px; }

/* ---------- generic "selected"/locked states reused by several pages ---------- */
.row-selected { background: rgba(0,255,255,.06); border-left: 2px solid var(--cyan); }
.readonly-lock { position: relative; opacity: .55; pointer-events: none; }
.readonly-lock::after { content: "Read-only — OPS-owned"; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 11.5px; font-weight: 600; color: var(--ink-mut); background: rgba(0,0,0,.02); }

/* ---------- toast ---------- */
#gx-toast-host { position: fixed; bottom: 20px; right: 20px; z-index: 100; display: flex; flex-direction: column; gap: 8px; pointer-events: none; }
.gx-toast {
  background: var(--modal-bg);
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--cyan);
  border-radius: 10px;
  padding: 10px 16px;
  font-size: 13px;
  color: var(--ink);
  box-shadow: 0 8px 24px rgba(0,0,0,.35);
  min-width: 200px;
  max-width: 340px;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .2s ease, transform .2s ease;
  pointer-events: auto;
}
.gx-toast.in { opacity: 1; transform: translateY(0); }
.gx-toast-ok { border-left-color: var(--ok-text); }
.gx-toast-warn { border-left-color: var(--warn-text); }
.gx-toast-danger { border-left-color: var(--danger-text); }

/* ---------- pretty checkbox rows ---------- */
.check-row { display: flex; align-items: center; gap: 8px; padding: 6px 0; font-size: 13px; color: var(--ink-dim); cursor: pointer; }
/* Plain "input" (not "input[type=checkbox]") on purpose — a .check-row wraps a checkbox OR a
   radio (e.g. Add Product's "Enable Stock Management"), and only the checkbox variant used to
   get width:auto here, so a radio fell through to the global input{width:100%} text-field rule
   and rendered as a huge invisible box instead of a small circle. */
.check-row input { width: auto; margin: 0; accent-color: var(--cyan); }

/* ---------- flash animation for new rows ---------- */
@keyframes flash {
  0% { background: rgba(0,255,255,.16); }
  100% { background: transparent; }
}
tr.just-added { animation: flash 1s ease-out; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* Smooth theme cross-fade — the toggle adds `class="theming"` to <html> for ~0.45s so every
   surface eases between the dark and light palettes instead of snapping. Scoped to the theming
   window (no permanent transition cost) and to viewers who haven't asked for reduced motion. */
@media (prefers-reduced-motion: no-preference) {
  html.theming,
  html.theming *,
  html.theming *::before,
  html.theming *::after {
    transition: background-color .32s ease, color .32s ease, border-color .32s ease, fill .32s ease !important;
  }
}

/* ---------- two-column section layout (Add Product-style pages) ---------- */
.grid-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
@media (max-width: 900px) { .grid-2col { grid-template-columns: 1fr; } }
.field-row { display: flex; align-items: center; gap: 12px; }
.field-row label { margin: 0; }

/* ---------- toggle switch (on/off, e.g. Status, Adhesive Product) ---------- */
.toggle { position: relative; display: inline-flex; align-items: center; width: 42px; height: 23px; flex: none; cursor: pointer; }
.toggle input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.toggle .track { position: absolute; inset: 0; background: var(--line-2); border-radius: 999px; transition: background .15s ease; }
.toggle .track .thumb {
  position: absolute; top: 3px; left: 3px; width: 17px; height: 17px; border-radius: 50%;
  background: var(--ink-strong); transition: left .15s ease; box-shadow: 0 1px 3px rgba(0,0,0,.4);
}
.toggle input:checked ~ .track { background: var(--cyan); }
.toggle input:checked ~ .track .thumb { left: 22px; background: var(--navy); }
.toggle input:disabled ~ .track { opacity: .5; cursor: not-allowed; }

/* ---------- reorderable option list (Add Product's "Customization Option") ---------- */
.reorder-list { display: flex; flex-direction: column; gap: 6px; }
.reorder-row { display: flex; align-items: center; gap: 10px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; }
.reorder-row .reorder-handle { display: flex; flex-direction: column; gap: 0; }
.reorder-row .reorder-handle button {
  border: none; background: transparent; min-height: 0; padding: 1px 4px; color: var(--ink-mut); font-size: 10px; line-height: 1.3;
}
.reorder-row .reorder-handle button:hover:not(:disabled) { color: var(--cyan); background: transparent; }
.reorder-row .check-row { flex: 1; padding: 0; }

/* ---------- Product Editor: field-status (compact "attached · remove" hint under a select) ---------- */
/* Sits directly under a form field's control. One inline row: a status dot + label + a Remove
   action-link. Replaces the older two-column "Status" formgrid cell — showing a full labeled
   field just to say "Attached" was noise; a compact hint under the field is enough. Colored via
   data-state (attached = ok green, detached = muted) so the dot reads at a glance without a
   separate class swap. */
.field-status {
  display: flex; align-items: center; gap: 12px;
  margin-top: 6px;
  font-size: 12px;
}
.field-status-text {
  color: var(--ok-text);
  font-weight: 600;
  font-size: 11.5px;
  letter-spacing: .01em;
}
.field-status-text[data-state="detached"] { color: var(--ink-mut); }
.field-status .action-link { min-width: 0; height: auto; padding: 0; font-size: 12px; font-weight: 600; }

/* ---------- Product Editor: chip-tray (per-entity tag row) ---------- */
/* One line for tags attached to an entity — Categories on the product editor is the exemplar.
   The whole row is one flex flow: label → chips → an inline "+ Add" that itself looks like a
   chip (dashed cyan outline). That makes it read as ONE component, not "label + separate action".
   .chip-tray-body uses display:contents so the JS-inserted chips are direct flex children of the
   tray, so they flow inline with the label and the +Add button — no visual break in the middle. */
.chip-tray {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 0 0 20px;
}
.chip-tray-label {
  font-size: 12.5px; font-weight: 600; color: var(--ink-dim);
  margin-right: 4px; flex: none;
}
.chip-tray-body { display: contents; }
/* "+ Add" affordance — matches the .chip pill geometry so it sits in the row as a peer, but
   dashed + cyan to signal "click to add another chip" rather than "existing chip". */
.chip-add {
  display: inline-flex; align-items: center; gap: 4px;
  border: 1px dashed rgba(0,255,255,.4);
  background: transparent; color: var(--cyan);
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 12px; font-weight: 600; line-height: 1;
  min-height: 0; cursor: pointer;
  transition: background .12s ease, border-color .12s ease;
}
.chip-add:hover { background: rgba(0,255,255,.10); border-color: var(--cyan); }
/* Muted hint shown when the tray is empty ("No categories yet — customers won't find this product."). */
.chip-tray-empty { color: var(--ink-mut); font-size: 12px; }

/* ---------- Product Editor: PageHeader identity strip ---------- */
/* Small row of source/status badges that sits UNDER the .page-h title (DS §2 PageHeader spec
   keeps the title semantic + text-only; the badges are a peer identity row, not part of the
   title). Matches the .page-h-meta line's left alignment and vertical rhythm. */
.identity-strip { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 6px; }

/* ---------- Product Editor: price matrix (Sizes × Quantity bands) ---------- */
/* Not a .dt list — it's a 2D matrix (rows = quantity bands, columns = sizes), so it needs its
   own grid semantics. Uses the same token palette and border density as .dt for visual
   consistency across the app. Wrap in .gridwrap for the same overflow-scroll behavior. */
.price-matrix { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 720px; }
.price-matrix thead th {
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.02));
  color: var(--ink-dim); font-size: 11.5px; font-weight: 600;
  letter-spacing: .03em; text-transform: uppercase; text-align: center;
  padding: 10px 12px; border-bottom: 1px solid var(--line-2); white-space: nowrap;
}
.price-matrix thead th:first-child { text-align: left; }
.price-matrix tbody td { padding: 10px 12px; text-align: center; border-bottom: 1px solid var(--line); vertical-align: middle; }
.price-matrix tbody tr:last-child td { border-bottom: none; }
.price-matrix tbody tr:hover { background: rgba(0,255,255,.035); }
.price-matrix td.qty {
  text-align: left; font-weight: 600; color: var(--ink);
  background: rgba(255,255,255,.02); min-width: 130px;
}
.price-matrix td.qty input { width: 100%; font-weight: 600; }
.price-matrix .price-cell .p { font-weight: 700; color: var(--ink-strong); font-size: 13px; }
.price-matrix .price-cell .c { font-size: 10.5px; color: var(--ink-mut); }
.price-matrix .price-cell input {
  padding: 4px 6px; font-size: 12.5px; text-align: center;
  max-width: 80px; margin: 0 auto; display: block;
}
.price-matrix .price-cell input.cost-input { margin-top: 3px; opacity: .75; max-width: 70px; }

/* Notice at the end of a .section shouldn't add its own bottom margin on top of the section's
   own padding — collapses the redundant spacing so notices inside a section sit flush at the
   bottom. Applies via :last-child so a notice that's followed by more content keeps its normal
   16px rhythm. */
.section > .notice:last-child { margin-bottom: 0; }

/* ---------- stock/location badge (Manage Stock's "Not Set") ---------- */
.badge-loc { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: var(--badge-radius); cursor: pointer; border: 1px solid transparent; }
.badge-loc.unset { background: var(--danger-bg); color: var(--danger-text); border-color: var(--danger-border); }
.badge-loc.set { background: var(--ok-bg); color: var(--ok-text); border-color: var(--ok-border); }
