/* kuemue B2B design system — Shopify-admin-style neutrals (gray canvas, white cards,
   near-black ink, blue interactive), lowercase wordmark brand.
   Every page uses these tokens/components; page CSS only adds layout. Mobile-first. */

:root {
  color-scheme: light;
  --ink: #1a1a1a;
  --ink-2: #303030;
  --paper: #ffffff;
  --card: #ffffff;
  --line: #e3e3e3;
  --line-2: #c9c9c9;
  --accent: #005bd3;
  --accent-ink: #004299;
  --accent-soft: #eaf4ff;
  --muted: #616161;
  --hover: #f6f6f6;
  --chip: #f1f1f1;
  --glass: rgba(255,255,255,.92);
  --skel-a: #ebebeb;
  --skel-b: #f7f7f7;
  --ok: #008060;    --ok-soft: #e5f3ee;
  --warn: #8a6116;  --warn-soft: #fdf3d8;
  --bad: #c5280c;   --bad-soft: #fedad9;
  --info: #00527c;  --info-soft: #e0f0fa;
  --violet: #6b4fa3; --violet-soft: #ece6f6;
  --teal: #1f7a72;  --teal-soft: #e0f0ee;
  /* Chart series colours — fixed order, CVD-validated. s1 mirrors --accent; numbers/labels never wear these. */
  --s1: #005bd3; --s2: #00897b; --s3: #6b4fa3; --s4: #b07d3f;
  --r: 12px;
  --r-sm: 8px;
  --shadow: 0 1px 2px rgba(20,20,20,.05), 0 4px 16px rgba(20,20,20,.06);
  --shadow-lg: 0 4px 12px rgba(20,20,20,.08), 0 16px 48px rgba(20,20,20,.14);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  /* Motion curves. The built-in CSS easings are too soft to read as deliberate, so every
     transition below uses one of these three. --ease-out for anything entering or leaving,
     --ease-in-out for something moving on screen, --ease-drawer for the mobile bottom sheet
     (the curve Ionic uses for iOS sheets). */
  --ease-out: cubic-bezier(.23, 1, .32, 1);
  --ease-in-out: cubic-bezier(.77, 0, .175, 1);
  --ease-drawer: cubic-bezier(.32, .72, 0, 1);
}

/* Dark theme — soft dark grey, deliberately not black. Admin-only for now:
   only admin.html sets data-theme (from localStorage kb2b_theme). */
html[data-theme="dark"] {
  color-scheme: dark;
  --ink: #e7e7e7;
  --ink-2: #cfcfcf;
  --paper: #202020;
  --card: #2a2a2a;
  --line: #3d3d3d;
  --line-2: #555555;
  --accent: #4c9aff;
  --accent-ink: #8ab8ff;
  --accent-soft: #1d2c40;
  --muted: #a3a3a3;
  --hover: #333333;
  --chip: #383838;
  --glass: rgba(32,32,32,.92);
  --skel-a: #2e2e2e;
  --skel-b: #383838;
  --pdp-box: #242424;      /* .pdp-notes surface — admin preview renders it in dark theme too */
  --ok: #41bd90;    --ok-soft: #16352b;
  --warn: #d9ab52;  --warn-soft: #372c13;
  --bad: #ff7f68;   --bad-soft: #422019;
  --info: #5cb3e6;  --info-soft: #15303f;
  --violet: #ab90d9; --violet-soft: #2c2439;
  --teal: #58b6ac;  --teal-soft: #17312e;
  /* Chart series colours — dark-theme variants, same fixed order. */
  --s1: #3a7fe6; --s2: #219e90; --s3: #8f73c6; --s4: #b28a39;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 4px 16px rgba(0,0,0,.35);
  --shadow-lg: 0 4px 12px rgba(0,0,0,.5), 0 16px 48px rgba(0,0,0,.55);
}

* { box-sizing: border-box; }
/* display rules on classes (.btn etc.) beat the UA's [hidden] — restore its authority */
[hidden] { display: none !important; }

/* Partner avatar/logo circle (initials fallback) */
.avic {
  width: 32px; height: 32px; border-radius: 999px; object-fit: cover; flex: none;
  background: var(--accent-soft); color: var(--accent-ink);
  display: inline-flex; align-items: center; justify-content: center;
  font: 700 13px/1 var(--font); vertical-align: middle; margin-inline-end: 8px;
}
.avic-lg { width: 56px; height: 56px; font-size: 20px; margin-inline-end: 12px; }

/* Floating row-action menu — shared by orders, catalogue, partners */
.ao-menu { position: fixed; z-index: 80; background: var(--card); border: 1px solid var(--line-2); border-radius: 10px; box-shadow: var(--shadow); min-width: 160px; padding: 4px; }
.ao-menu button { display: block; width: 100%; text-align: start; border: 0; background: none; padding: 8px 12px; border-radius: 7px; font: 500 14px/1.2 var(--font); color: var(--ink); cursor: pointer; }
.ao-menu button:hover { background: var(--hover); }
.ao-menu button.danger { color: var(--bad); }

/* Notification per-event toggles (Settings → Notifications) */
/* Permissions matrix: parent rows are section headers; child (per-action) rows are indented,
   tinted and tree-connected so the hierarchy reads at a glance (theme-aware). */
.perm-prow td.perm-phead { padding-block: 2px; }
/* The whole parent label is one big toggle: hover-highlights the row and drops the actions. */
.perm-toggle { display: flex; align-items: center; gap: 10px; width: 100%; border: 0; background: none; cursor: pointer; padding: 8px 10px; border-radius: 8px; font: inherit; font-weight: 600; color: var(--ink); text-align: start; }
.perm-toggle:hover { background: var(--hover); }
.perm-x { font-size: 17px; line-height: 1; width: 15px; text-align: center; color: var(--accent); flex: none; transition: color .12s; }
.perm-toggle:hover .perm-x { color: var(--accent-ink); }
.perm-prow > td:first-child { font-weight: 600; }
.perm-srow > td { background: var(--hover); }                       /* tinted band groups the actions under their parent */
.perm-srow .perm-sub { padding-inline-start: 38px; color: var(--muted); font-size: 13.5px; position: relative; }
.perm-srow .perm-sub::before {                                     /* short elbow = "belongs to the row above" */
  content: ""; position: absolute; inset-inline-start: 20px; top: calc(50% - 1px);
  width: 10px; height: 1px; background: var(--line-2);
}
.ntoggles { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 6px 16px; margin-top: 6px; }
.ntoggle { display: flex; align-items: center; gap: 8px; font-size: 14px; cursor: pointer; }
.ntoggle input { width: 16px; height: 16px; accent-color: var(--accent); flex: none; }
/* Staff-notification roles × events matrix (Settings → Notifications): events down, roles across. */
.sr-scroll { overflow-x: auto; margin-top: 6px; }
.sr-matrix { border-collapse: collapse; font-size: 14px; }
.sr-matrix th, .sr-matrix td { padding: 6px 10px; text-align: center; }
.sr-matrix thead th { font-weight: 600; color: var(--muted); border-bottom: 1px solid var(--line-2); }
.sr-matrix td.sr-ev { text-align: start; white-space: nowrap; }
.sr-matrix tbody tr:hover { background: var(--hover); }
.sr-matrix input { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }
.sr-matrix input:disabled { cursor: default; opacity: .6; }

/* Tag chips — shared by orders AND partners (must not depend on admin-orders.js injectCss) */
.ao-chip { display: inline-block; background: var(--accent-soft); color: var(--accent-ink); border-radius: 999px; padding: 1px 8px; font-size: 11px; font-weight: 600; margin: 2px 0 0; margin-inline-end: 4px; white-space: nowrap; }
.ao-chip .x { cursor: pointer; margin-inline-start: 4px; opacity: .6; }
.ao-chip .x:hover { opacity: 1; }

/* Bulk actions (UI kit row 5) — shared by the admin list views. The checkbox
   column stays in the DOM but only shows while its card carries .bulk-on. */
.bulkbar { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; padding: 9px 14px; background: var(--accent-soft); border-block: 1px solid var(--line-2); font-size: 13.5px; }
.card > .bulkbar:first-child { border-top: 0; border-radius: var(--r) var(--r) 0 0; }
.bulkbar .bulk-all { display: flex; align-items: center; gap: 7px; font-weight: 600; cursor: pointer; }
.table th.blk, .table td.blk { display: none; width: 34px; padding-inline-end: 0; }
.bulk-on .table th.blk, .bulk-on .table td.blk { display: table-cell; }
.blk input, .bulk-all input { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; margin: 0; flex: none; }
.blk input:disabled { opacity: .35; cursor: default; }
/* Right-pinned action group for list filter rows (Export / Select). margin-inline-start:auto
   keeps it flush-right on its flex line, so it wraps as one unit to the right instead of a
   lone button drifting to the left of a second line. */
.tb-right { display: inline-flex; gap: 8px; align-items: center; margin-inline-start: auto; }
/* Filter row shared by Orders + Developer lists (Orders re-declares it in its injected
   CSS; kept here so pages that render before Orders still get the flex layout). */
.ao-filters { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin: 0 0 12px; }
.ao-filters .input { max-width: 150px; padding: 7px 10px; font-size: 13.5px; }
/* While selecting in the catalogue, hide the drag handle — dragging would fight
   bulk mode's row-click-to-select (entering bulk mode does not repaint the rows). */
.bulk-on .ac-drag { display: none; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--paper); color: var(--ink);
  font-family: var(--font); font-size: 15px; line-height: 1.55;
}
h1,h2,h3,h4 { margin: 0 0 .5em; line-height: 1.25; letter-spacing: -.01em; }
h1 { font-size: 26px; } h2 { font-size: 20px; } h3 { font-size: 16px; }
p { margin: 0 0 1em; }
a { color: var(--accent-ink); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; }
::placeholder { color: #b5b5b5; }

/* ── Brand ── */
.wordmark { font-weight: 700; font-size: 22px; letter-spacing: -.5px; color: var(--ink); }
.wordmark b { font-weight: 700; }
/* The kuemue logo image (public/assets/logo-kuemue.jpg, from kuemue.com) replaces the text
   wordmark on partner-facing pages — never write the brand as "KueMue". */
.wordmark img.logo-img { height: 24px; width: auto; display: inline-block; vertical-align: middle; border: 0; }
/* The logo JPG is black-on-white — in dark mode give it a small white chip so it reads as a badge. */
html[data-theme="dark"] .wordmark img.logo-img { background: #fff; padding: 3px 7px; border-radius: 7px; height: 26px; }
/* Admin brand layout: logo + "wholesale" inline on the first line; the ROLE badge (owner/admin/…)
   drops to its own line, aligned with the logo's left edge. (Rare "acting as" pill stacks below.) */
.brand .wordmark { display: block; white-space: nowrap; }
.brand .wordmark img.logo-img { height: 20px; } /* narrow sidebar: keep logo + "wholesale" on one line */
/* The base .wordmark .tag rule shoves pills up 3px to sit beside TEXT — next to the logo IMAGE
   they must centre on the same line instead. */
.brand .wordmark .tag { vertical-align: middle; }
.brand .wordmark .tag.role-admin { display: block; width: max-content; margin: 6px 0 0; margin-inline-start: 0; }
.brand .wordmark #baseRoleTag { display: inline-block; margin: 4px 0 0; margin-inline-start: 0; }
/* Role badge — a coloured pill so you always know which surface you're in.
   Distinct colour per role: wholesale (blue), admin (ink), affiliate (teal). */
.wordmark .tag {
  display: inline-block; font-size: 10px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--accent-ink); background: var(--accent-soft); padding: 3px 8px; border-radius: 999px;
  margin-inline-start: 8px; vertical-align: 3px; line-height: 1;
}
.wordmark .tag.role-admin     { color: var(--paper); background: var(--ink); }
.wordmark .tag.role-wholesale { color: var(--accent-ink); background: var(--accent-soft); }
.wordmark .tag.role-affiliate { color: var(--teal); background: var(--teal-soft); }

/* ── Buttons ── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 18px; border-radius: 10px; border: 1px solid var(--line-2);
  background: var(--card); color: var(--ink); font: 600 14px/1.2 var(--font);
  cursor: pointer; text-decoration: none;
  transition: background .12s, border-color .12s, opacity .12s, transform .16s var(--ease-out);
  min-height: 42px;
}
/* Press feedback. Nothing in the UI confirmed a click before this, so every button felt one step
   removed from the pointer. Scale stays subtle on purpose: enough to feel, not enough to notice. */
.btn:active { transform: scale(.97); }
.btn:disabled:active, .btn[disabled]:active { transform: none; }
.btn:hover { background: var(--hover); text-decoration: none; }
.btn:disabled { opacity: .5; cursor: default; pointer-events: none; }
/* Primary and accent buttons share ONE colour — the shop accent (Settings → Appearance). */
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-ink); }
.btn-accent { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-accent:hover { background: var(--accent-ink); }
.btn-danger { background: var(--card); border-color: var(--bad); color: var(--bad); }
.btn-danger:hover { background: var(--bad-soft); }
.btn-ghost { background: transparent; border-color: transparent; }
.btn-ghost:hover { background: var(--hover); }
.btn-sm { padding: 6px 12px; min-height: 32px; font-size: 13px; border-radius: 8px; }
.btn-block { width: 100%; }

/* ── Forms ── */
.label { display: block; font: 600 13px/1.3 var(--font); color: var(--ink-2); margin: 14px 0 6px; }
.label .req { color: var(--bad); }
.input, .select, .textarea {
  width: 100%; padding: 10px 12px; border: 1px solid var(--line-2); border-radius: 10px;
  background: var(--card); color: var(--ink); font: 400 15px/1.4 var(--font);
  outline: none; transition: border-color .12s, box-shadow .12s;
}
.input:focus, .select:focus, .textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
/* field-sizing:content = the box grows to fit its text, so a pre-filled textarea
   (debug report description, product description, settings) shows everything with
   no scrollbar and no dragging. min-height still floors empty composers; resize
   still lets you shrink one by hand. Older browsers just keep the old scrollbar. */
.textarea { min-height: 90px; resize: vertical; field-sizing: content; }
.field-err { color: var(--bad); font-size: 13px; margin-top: 4px; }
.hint { color: var(--muted); font-size: 13px; margin-top: 4px; }

/* ── Real flags + currency picker ── native <option>s can't hold images and Windows can't draw flag
   emoji, so flags are <img> SVGs and the currency <select> is a hidden value-carrier under a facade. */
/* 1.05em is the PRICE default: it scales with whatever text the flag sits in, so the hero price,
   a 13px ≈ line and a totals row all read the same weight — and any new price surface is correct
   without touching this file. (An explicit per-context whitelist was tried first and silently
   missed every site added after it.) margin-inline-end mirrors automatically for RTL. */
.flag {
  display: inline-block; width: 1.05em; aspect-ratio: 4 / 3; height: auto;
  border-radius: 2px; box-shadow: 0 0 0 1px rgba(0, 0, 0, .09); object-fit: cover;
  vertical-align: -.12em; margin-inline-end: .3em;
}
/* The currency picker is a control, not a price — it keeps the larger flag it was designed with. */
.ccy-dd-cur .flag, .ccy-opt .flag { width: 1.25em; vertical-align: -.17em; }
.price-now .flag { vertical-align: -.04em; margin-inline-end: .34em; }
.ccy-pick { display: inline-flex; align-items: center; gap: 8px; }
.ccy-dd { position: relative; display: inline-block; text-align: start; }
.ccy-dd.block { display: block; width: 100%; }
.ccy-dd-native { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.ccy-dd-btn {
  display: inline-flex; align-items: center; gap: 8px; width: 100%;
  padding: 10px 12px; border: 1px solid var(--line-2); border-radius: 10px;
  background: var(--card); color: var(--ink); font: 400 15px/1.4 var(--font);
  cursor: pointer; transition: border-color .12s, box-shadow .12s;
}
.ccy-dd.sm .ccy-dd-btn { padding: 6px 9px 6px 10px; font-size: 13.5px; border-radius: 9px; }
.ccy-dd-btn:hover { border-color: var(--line-2); }
.ccy-dd-btn:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.ccy-dd-cur { display: inline-flex; align-items: center; min-width: 0; }
.ccy-dd-cur .flag { margin-inline-end: 7px; }
.ccy-dd-code { font-weight: 600; letter-spacing: .01em; }
.ccy-dd-chev { margin-inline-start: auto; color: var(--muted); flex: none; transition: transform .15s; }
.ccy-dd-btn[aria-expanded="true"] .ccy-dd-chev { transform: rotate(180deg); }
/* The popup PANEL. Scrolling moved to .ccy-dd-opts below so the search box stays pinned while the
   currency list scrolls under it — 62 options is far past what anyone should have to scroll blind. */
.ccy-dd-list {
  position: absolute; z-index: 90; top: calc(100% + 4px); inset-inline-start: 0;
  /* At least as wide as the button, but never narrower than a typeable search box — the compact
     switcher in the catalogue toolbar is ~108px, which left no room to type a country name. */
  min-width: max(100%, 200px);
  padding: 5px; background: var(--card); border: 1px solid var(--line-2); border-radius: 11px;
  box-shadow: var(--shadow-lg);
}
.ccy-dd-search {
  width: 100%; margin-bottom: 5px; padding: 8px 10px; font-size: 14px; border-radius: 8px;
}
.ccy-dd-opts { max-height: 262px; overflow-y: auto; margin: 0; padding: 0; list-style: none; }
.ccy-dd-empty { margin: 0; padding: 10px; color: var(--muted); font-size: 13.5px; text-align: center; }
.ccy-opt {
  display: flex; align-items: center; gap: 3px; padding: 8px 10px; border-radius: 8px;
  font: 500 14px/1.2 var(--font); color: var(--ink); cursor: pointer; white-space: nowrap;
}
.ccy-opt .flag { margin-inline-end: 5px; }
.ccy-opt.kb, .ccy-opt:hover { background: var(--accent-soft); }
.ccy-opt.on { color: var(--accent-ink); }
.ccy-opt.on::after { content: "✓"; margin-inline-start: auto; padding-inline-start: 14px; font-weight: 700; }
.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
@media (max-width: 560px) { .row2 { grid-template-columns: 1fr; } }

/* ── Cards / layout ── */
.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow); }
.card-pad { padding: 20px; }
.card h3 { margin-bottom: 12px; }
.stack > * + * { margin-top: 14px; }
.split { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.wrap { max-width: 1100px; margin: 0 auto; padding: 0 16px; }
.muted { color: var(--muted); }
.small { font-size: 13px; }
.mono { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }
.right { text-align: end; }
.nowrap { white-space: nowrap; }

/* ── Tables ── */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th {
  text-align: start; font: 600 12px/1.3 var(--font); text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); padding: 10px 12px; border-bottom: 1px solid var(--line);
}
/* A right-aligned column: the header must follow its cells (base `.table th` outranks `.right` alone). */
.table th.right { text-align: end; }
.table td { padding: 12px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.table tr:last-child td { border-bottom: 0; }
.table tbody tr { cursor: default; }
.table .rowlink { cursor: pointer; }
.table .rowlink:hover { background: var(--hover); }

/* ── Badges & status pills ── */
.badge {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px; border-radius: 999px;
  font: 600 12px/1.4 var(--font); background: var(--chip); color: var(--ink-2); white-space: nowrap;
}
/* Count pill — subtle neutral counter beside a list title (setCount in ui.js). */
.count-pill {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 20px; padding: 0 7px; border-radius: 999px;
  background: var(--chip); color: var(--muted);
  font: 600 12px/1 var(--font); font-variant-numeric: tabular-nums;
  vertical-align: middle; margin-inline-start: 8px; translate: 0 -1px;
}
.count-pill:empty { display: none; } /* nothing before data loads */

/* ── Notifications: ONE style for the bell dropdown + its rows, shared by admin and portal.
   Both shells used to carry near-identical copies in their own <style>, and the portal's
   hardcoded #f6f6f6 so it broke in dark mode. ── */
.bell-menu { width: min(92vw, 380px); max-height: 72vh; overflow-y: auto; padding: 4px; }
.bell-menu .bell-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 10px 7px; margin-bottom: 2px; border-bottom: 1px solid var(--line);
  position: sticky; top: -4px; background: var(--card); z-index: 1;
}
.bell-menu .bell-head b { font-size: 13px; }
/* Beats the shells' `.menu button { display:block; width:100% }`, which stretched this action
   to full width and wrapped its label onto two lines. */
.bell-menu .bell-head .bell-clear {
  display: inline-block; width: auto; padding: 3px 9px; border: 0; border-radius: 999px;
  background: none; color: var(--muted); cursor: pointer; white-space: nowrap;
  font: 600 12px/1.4 var(--font); text-align: center;
}
.bell-menu .bell-head .bell-clear:hover { background: var(--chip); color: var(--ink); }
.notif-item {
  display: grid; grid-template-columns: 6px minmax(0, 1fr); gap: 0 9px;
  padding: 9px 10px; border-radius: 8px; cursor: pointer;
}
.notif-item + .notif-item { margin-top: 1px; }
.notif-item:hover { background: var(--hover); }
/* Unread reads as a dot + weight, not a full tinted block — the tint made a busy list shout. */
.notif-item::before {
  content: ""; grid-column: 1; grid-row: 1 / span 2;
  width: 6px; height: 6px; border-radius: 50%; margin-top: 6px; background: transparent;
}
.notif-item.unread::before { background: var(--accent); }
.notif-head { grid-column: 2; grid-row: 1; display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.notif-title { font: 600 13.5px/1.35 var(--font); color: var(--ink-2); }
.notif-item.unread .notif-title { font-weight: 700; color: var(--ink); }
.notif-time { font-size: 11.5px; color: var(--muted); white-space: nowrap; flex: none; }
.notif-body {
  grid-column: 2; grid-row: 2; margin-top: 2px; font-size: 12.5px; line-height: 1.45; color: var(--muted);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pill-draft, .pill-expired, .pill-cancelled { background: var(--chip); color: var(--muted); }
.pill-submitted, .pill-under_review { background: var(--info-soft); color: var(--info); }
.pill-quoted { background: var(--violet-soft); color: var(--violet); }
.pill-awaiting_deposit, .pill-awaiting_balance { background: var(--warn-soft); color: var(--warn); }
.pill-preparing, .pill-ready_to_ship { background: var(--teal-soft); color: var(--teal); }
.pill-shipped { background: var(--info-soft); color: var(--info); }
.pill-delivered, .pill-completed, .pill-confirmed, .pill-approved { background: var(--ok-soft); color: var(--ok); }
.pill-declined, .pill-rejected, .pill-suspended { background: var(--bad-soft); color: var(--bad); }
.pill-pending { background: var(--warn-soft); color: var(--warn); }
/* Ticket statuses (support + debug) reuse the pill system */
.pill-open { background: var(--info-soft); color: var(--info); }
.pill-resolved { background: var(--ok-soft); color: var(--ok); }
.pill-closed, .pill-archived { background: var(--chip); color: var(--muted); }
/* Debug priority (schema: low | normal | high) reuses the pill system */
.pill-high { background: var(--bad-soft); color: var(--bad); }
.pill-normal { background: var(--warn-soft); color: var(--warn); }
.pill-low { background: var(--ok-soft); color: var(--ok); }

/* Ticket message thread (admin + portal) */
.tk-msg { padding: 10px 12px; border-radius: var(--r-sm); margin-bottom: 10px; border: 1px solid var(--line); background: var(--paper); }
.tk-msg:last-child { margin-bottom: 0; }
.tk-by-admin { background: var(--accent-soft); border-color: var(--line-2); }
.tk-by-system { font-style: italic; color: var(--muted); }
.tk-msg-head { display: flex; gap: 8px; align-items: baseline; margin-bottom: 4px; flex-wrap: wrap; }
.tk-msg-body { line-height: 1.5; }

/* Staged composer attachments (ui.js attachStager): chips wait in the composer until Send. */
.att-strip { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 4px; }
.att-strip[hidden] { display: none !important; }
.att-chip { display: inline-flex; align-items: center; gap: 7px; max-width: 220px; padding: 5px 8px; border: 1px solid var(--line); border-radius: 10px; background: var(--hover); font-size: 12px; color: var(--muted); }
.att-chip img { width: 34px; height: 34px; object-fit: cover; border-radius: 6px; flex: none; }
.att-chip .att-ico { font-size: 15px; flex: none; }
.att-chip .att-nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.att-rm { border: 0; background: transparent; color: var(--muted); cursor: pointer; font-size: 13px; line-height: 1; padding: 0 2px; flex: none; }
.att-rm:hover { color: var(--bad); }
.att-dragging { position: relative; }
.att-drop { position: absolute; inset: 6px; z-index: 5; display: none; align-items: center; justify-content: center; gap: 8px; border: 2px dashed var(--accent); border-radius: 12px; background: var(--accent-soft); color: var(--accent-ink); font-weight: 600; font-size: 14px; pointer-events: none; }
.att-dragging .att-drop { display: flex; }

/* ── Nav (top bar) ── */
.nav {
  position: sticky; top: 0; z-index: 40; background: var(--glass); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.nav-in { display: flex; align-items: center; gap: 16px; min-height: 58px; }
.nav .spacer { flex: 1; }
.nav a.navlink { color: var(--ink-2); font-weight: 600; font-size: 14px; padding: 8px 10px; border-radius: 8px; }
.nav a.navlink:hover { background: rgba(20,20,20,.05); text-decoration: none; }
.nav a.navlink.on { color: var(--ink); background: rgba(20,20,20,.07); }

/* ── Bottom tab bar (portal, mobile) ── */
.tabbar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 40; display: none;
  background: var(--card); border-top: 1px solid var(--line);
  padding: 6px max(8px, env(safe-area-inset-left)) max(6px, env(safe-area-inset-bottom));
}
.tabbar .tb {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
  color: var(--muted); font: 600 11px/1.2 var(--font); padding: 6px 0; border-radius: 8px;
  text-decoration: none; position: relative;
}
.tabbar .tb.on { color: var(--ink); }
.tabbar .tb svg { width: 22px; height: 22px; }
.tabbar .tb .dot {
  position: absolute; top: 2px; inset-inline-end: calc(50% - 16px); min-width: 16px; height: 16px; border-radius: 999px;
  background: var(--accent); color: #fff; font-size: 10px; line-height: 16px; text-align: center; padding: 0 4px;
}
@media (max-width: 720px) { .tabbar { display: flex; } .has-tabbar { padding-bottom: 76px; } }

/* ── Global top bar (admin + portal) — brand left · global search centre · utilities right ──
   Fixed full-width band; page CSS offsets .shell/.side/.main below it and tunes the brand block.
   An almost-white rail: it reads as a band by being a whisker off the page (barely-off-white in
   light theme, slightly LIGHTER than the #202020 page in dark). All bar-local colours come from the
   .topbar-scoped --tb-* props; the role/accent colour lives on the bar's TOP edge (page CSS sets it).
   Dropdown cards below reset back to normal ink. */
.topbar {
  --tb-bg: #fbfbfb;                    /* light theme band — barely off the white page */
  --tb-ink: var(--ink);               /* normal dark text/icons on the light band */
  --tb-muted: var(--muted);           /* placeholder + kbd text */
  --tb-line: var(--line);             /* subtle button/inset borders */
  --tb-btn-hover: rgba(0,0,0,.05);
  --tb-input-bg: #fff;                /* white search inset (light theme) */
  --tb-kbd-bg: #eee;
  position: fixed; top: 0; left: 0; right: 0; z-index: 45; height: 44px;
  display: flex; align-items: center; gap: 10px; padding: 0 16px;
  background: var(--tb-bg); border-bottom: 1px solid var(--line); color: var(--tb-ink);
}
html[data-theme="dark"] .topbar {
  --tb-bg: #232323; --tb-input-bg: #2e2e2e; --tb-kbd-bg: #333; --tb-btn-hover: rgba(255,255,255,.07);
}
.topbar .brand { flex: none; display: flex; align-items: center; gap: 8px; padding: 0; margin: 0; }
.topbar .brand .wordmark { display: inline-flex; align-items: center; }
.topbar .brand .wordmark img.logo-img { height: 20px; }
/* The logo JPG has a white box baked in — blend it into the grey bar rather than chipping it.
   Light: multiply drops the white box on the light-grey band. Dark: invert to white, screen drops the box.
   (Overrides the generic dark .wordmark img white-chip rule inside the bar via higher specificity.) */
.topbar .brand .wordmark img.logo-img { mix-blend-mode: multiply; background: none; padding: 0; }
html[data-theme="dark"] .topbar .brand .wordmark img.logo-img { filter: invert(1); mix-blend-mode: screen; background: none; padding: 0; }
/* "wholesale" — a sleek accent-tinted pill (not a solid block), right after the logo (admin + portal). */
.topbar .tb-badge {
  flex: none; font: 800 9px/1 var(--font); letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
  padding: 3px 8px; border-radius: 999px; white-space: nowrap;
}
/* Role/surface chip in the right cluster (before the bell) — same subtle tint recipe.
   Admin paints --rolec per role via applyRoleColor; portal falls back to the accent. */
.topbar .tb-role { flex: none; display: inline-flex; align-items: center; gap: 6px; }
.topbar .tb-role .tag {
  display: inline-block; font: 800 10px/1 var(--font); letter-spacing: .08em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 999px;
  color: var(--rolec, var(--accent));
  background: color-mix(in srgb, var(--rolec, var(--accent)) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--rolec, var(--accent)) 25%, transparent);
}
.topbar .tb-right { flex: none; display: flex; align-items: center; gap: 8px; margin-inline-start: auto; }
/* Utility buttons on the light bar: transparent, muted icon, subtle border, faint hover. */
.topbar .ubtn {
  background: transparent; border-color: var(--tb-line); color: var(--ink-2); box-shadow: none;
}
.topbar .ubtn:hover { background: var(--tb-btn-hover); }
/* Dropdowns hanging off the bar are normal cards — reset the inherited light band text so
   their contents render in normal ink (they set their own token colours on top of this). */
.topbar .menu { color: var(--ink); }
/* Count badge on a top-bar utility button (portal cart). */
.topbar .ubtn .ubtn-cnt {
  position: absolute; top: -2px; inset-inline-end: -2px; min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 999px; background: var(--accent); color: #fff; font: 700 10px/16px var(--font);
  text-align: center; box-shadow: 0 0 0 2px var(--tb-bg);
}
.topbar .ubtn .ubtn-cnt[hidden] { display: none; }

/* Centre search — the input + its search icon are ONE visual group (input flex, icon flush right). */
.gsearch { position: relative; flex: 1; max-width: 560px; margin: 0 auto; display: flex; align-items: center; gap: 6px; }
.gs-field { position: relative; flex: 1; display: flex; align-items: center; }
.gsearch .input {
  flex: 1; min-height: 32px; padding: 6px 52px 6px 12px; font-size: 13.5px;
  background: var(--tb-input-bg); border-color: var(--tb-line); color: var(--tb-ink);
}
.gsearch .input:focus { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.gsearch .input::placeholder { color: var(--tb-muted); }
.gsearch .gs-kbd {
  position: absolute; inset-inline-end: 10px; top: 50%; transform: translateY(-50%); pointer-events: none;
  font: 600 11px/1 var(--font); color: var(--tb-muted); background: var(--tb-kbd-bg);
  border: 1px solid var(--tb-line); border-radius: 6px; padding: 3px 6px; white-space: nowrap;
}
/* Search launcher — the icon sits beside the field at every width (reuses .ubtn on the dark band). */
.gs-search-btn { flex: none; }
/* The top-bar field is now a readonly trigger — click / focus / Ctrl-K opens the modal palette below. */
.gsearch .input[readonly] { cursor: pointer; }

/* ── Global search modal palette (ui.js wireGlobalSearch — Shopify-admin pattern) ──
   Opened by the top-bar trigger, #gsBtn, or Ctrl/Cmd+K. Backdrop + centred panel on document.body,
   anchored near the top; the results area (.gs-body) scrolls, everything above it stays put. */
.gs-backdrop {
  position: fixed; inset: 0; z-index: 90; background: rgba(0,0,0,.4);
  display: flex; align-items: flex-start; justify-content: center; padding: 12px;
}
html[data-theme="dark"] .gs-backdrop { background: rgba(0,0,0,.55); }
.gs-modal {
  width: min(680px, 94vw); margin-top: 8vh; max-height: 72vh;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow-lg); color: var(--ink);
}
@media (max-width: 560px) { .gs-modal { margin-top: 12px; } }
.gs-input-row { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); }
.gs-mag { width: 18px; height: 18px; flex: none; color: var(--muted); }
.gs-modal-input {
  flex: 1; min-width: 0; border: 0; background: none; outline: none; padding: 0;
  font: 400 15px/1.4 var(--font); color: var(--ink);
}
.gs-modal-input::placeholder { color: var(--muted); }
/* Scope chips — one per group the surface exposes; the selected one inverts. */
.gs-chips { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 16px; border-bottom: 1px solid var(--line); }
.gs-chips .chip {
  border: 1px solid var(--line); background: none; color: var(--muted);
  font: 600 12px/1 var(--font); padding: 5px 11px; border-radius: 999px; cursor: pointer; white-space: nowrap;
}
.gs-chips .chip:hover { background: var(--hover); }
.gs-chips .chip.on { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.gs-body { overflow-y: auto; padding: 6px; }
.gs-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 9px 12px 4px;
  font: 700 11px/1.2 var(--font); text-transform: uppercase; letter-spacing: .06em; color: var(--muted);
}
.gs-clear { border: 0; background: none; color: var(--accent-ink); font: 600 11px/1 var(--font); cursor: pointer; text-transform: none; letter-spacing: 0; }
.gs-clear:hover { text-decoration: underline; }
.gs-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: 8px; cursor: pointer; }
.gs-row:hover, .gs-row.on { background: var(--hover); }
.gs-row-l { font: 600 14px/1.3 var(--font); color: var(--ink); white-space: nowrap; flex: none; max-width: 55%; overflow: hidden; text-overflow: ellipsis; }
.gs-row-s { color: var(--muted); font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
.gs-row .badge { margin-inline-start: auto; flex: none; }
.gs-empty { padding: 18px 12px; text-align: center; color: var(--muted); font-size: 13px; }
/* Recent-search rows: a clock glyph + the query, free to span the row (no 55% cap). */
.gs-recent .gs-clock { width: 14px; height: 14px; flex: none; color: var(--muted); }
.gs-recent .gs-row-l { max-width: none; flex: 1; font-weight: 500; }

@media (max-width: 999px) {
  /* The field collapses to just the launcher icon; #gsBtn opens the modal (same modal at every width). */
  .gsearch { position: static; flex: none; max-width: none; margin: 0; gap: 0; }
  .gs-field { display: none; }
}
@media (max-width: 560px) {
  .topbar .tb-badge, .topbar .tb-role { display: none; } /* hide the pills only when they can't fit */
}

/* ── Sidebar (admin, desktop) ── */
.shell { display: flex; min-height: 100vh; }
.side {
  width: 220px; flex: none; border-inline-end: 1px solid var(--line); background: var(--paper);
  padding: 18px 12px; position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.side .navlink {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 10px;
  color: var(--ink-2); font: 600 14px/1.2 var(--font); text-decoration: none; margin-bottom: 2px;
}
.side .navlink:hover { background: rgba(20,20,20,.05); }
.side .navlink.on { background: var(--card); color: var(--ink); box-shadow: var(--shadow), inset 0 0 0 1px var(--line); }
.side .navlink .cnt { margin-inline-start: auto; }
.main { flex: 1; min-width: 0; padding: 22px 24px 60px; background: var(--card); }
/* Centre the content column in every role's portal (admin, partner, developer …) */
.main > #view { max-width: 1200px; margin: 0 auto; }
@media (max-width: 999px) {
  .shell { display: block; }
  .side { position: static; width: auto; height: auto; display: flex; overflow-x: auto; border-inline-end: 0; border-bottom: 1px solid var(--line); padding: 8px; }
  .side .navlink { white-space: nowrap; }
  .main { padding: 16px 14px 60px; }
}

/* ── Modal ── */
.modal-back {
  position: fixed; inset: 0; z-index: 90; background: rgba(20,20,20,.45);
  display: flex; align-items: center; justify-content: center; padding: 16px;
}
.modal {
  background: var(--card); border-radius: 16px; box-shadow: var(--shadow-lg);
  width: 100%; max-width: 520px; max-height: 88vh; overflow-y: auto; padding: 22px;
}
.modal.modal-lg { max-width: 760px; }
@media (max-width: 560px) { .modal-back { align-items: flex-end; padding: 0; } .modal { border-radius: 16px 16px 0 0; max-height: 92vh; } }

/* ── Toast ── */
#toasts { position: fixed; top: 14px; left: 50%; transform: translateX(-50%); z-index: 100; display: flex; flex-direction: column; gap: 8px; width: min(92vw, 420px); }
.toast {
  background: var(--ink); color: var(--paper); border-radius: 10px; padding: 12px 16px; font-size: 14px;
  box-shadow: var(--shadow-lg); animation: toastin .18s var(--ease-out);
}
.toast.err { background: var(--bad); color: #fff; }
.toast.ok { background: var(--ok); }
@keyframes toastin { from { opacity: 0; transform: translateY(-6px) scale(.98); } }

/* ── Product grid ── */
.grid-products { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; }
@media (max-width: 560px) { .grid-products { grid-template-columns: repeat(2, 1fr); gap: 10px; } }
.pcard { background: var(--card); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; cursor: pointer; transition: box-shadow .12s, transform .12s; display: flex; flex-direction: column; }
/* Hover lift only where a real pointer exists. On a touch screen a tap fires :hover and the card
   stays raised until you tap elsewhere, which reads as a stuck card. */
@media (hover: hover) and (pointer: fine) {
  .pcard:hover { box-shadow: var(--shadow); transform: translateY(-1px); }
}
.pcard:active { transform: scale(.995); }
.pcard .pimg { aspect-ratio: 1; background: var(--accent-soft) center/cover no-repeat; display: flex; align-items: center; justify-content: center; color: var(--accent); font-size: 34px; }
.pcard .pbody { padding: 12px 14px 14px; display: flex; flex-direction: column; gap: 4px; flex: 1; }
.pcard .pname { font-weight: 600; font-size: 14px; }
.pcard .pprice { font-weight: 700; font-size: 15px; }
.pcard .pfrom { color: var(--muted); font-size: 12px; }
/* "Ask us for pricing" stand-in shown to partners without the see-prices capability (theme-aware). */
.pprice-ask { color: var(--muted); font-weight: 600; }

/* ── Stats / empty / skeleton ── */
/* Dashboard stat tiles: centred content, whole tile is a link, number coloured by meaning. */
.stat { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 5px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r); padding: 18px 14px; min-height: 88px;
  color: var(--ink); text-decoration: none; transition: border-color .12s, box-shadow .12s, transform .12s; }
@media (hover: hover) and (pointer: fine) {
  a.stat:hover { box-shadow: var(--shadow); transform: translateY(-1px); text-decoration: none; }
}
.stat .n { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.05; color: var(--muted); } /* default (zero) = calm grey */
.stat .l { color: var(--muted); font-size: 12.5px; font-weight: 600; line-height: 1.3; }
/* Semantic tones — colour the NUMBER only (tile stays a plain card), and only when the
   count is > 0 (a zero needs no attention → it stays calm grey). */
.stat.tone-bad  .n { color: var(--bad); }
.stat.tone-warn .n { color: var(--warn); }
.stat.tone-ok   .n { color: var(--ok); }
.grid-stats { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.empty { text-align: center; color: var(--muted); padding: 48px 16px; }
.empty .big { font-size: 34px; margin-bottom: 8px; }
.skel { background: linear-gradient(90deg, var(--skel-a) 25%, var(--skel-b) 50%, var(--skel-a) 75%); background-size: 200% 100%; animation: skel 1.1s infinite linear; border-radius: 8px; min-height: 16px; }
@keyframes skel { to { background-position: -200% 0; } }

/* ── Timeline ── */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { position: relative; padding: 0 0 18px; padding-inline-start: 26px; }
.timeline li::before { content: ""; position: absolute; inset-inline-start: 7px; top: 6px; width: 8px; height: 8px; border-radius: 999px; background: var(--accent); }
.timeline li::after { content: ""; position: absolute; inset-inline-start: 10.5px; top: 18px; bottom: -2px; width: 1.5px; background: var(--line-2); }
.timeline li:last-child::after { display: none; }
.timeline .t-title { font-weight: 600; font-size: 14px; }
.timeline .t-sub { color: var(--muted); font-size: 12.5px; }

/* ── Tabs ── */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); overflow-x: auto; }
.tabs .tab {
  padding: 10px 14px; font: 600 14px/1.2 var(--font); color: var(--muted); cursor: pointer;
  border-bottom: 2px solid transparent; white-space: nowrap; background: none; border-top: 0; border-left: 0; border-right: 0;
}
.tabs .tab.on { color: var(--ink); border-bottom-color: var(--ink); }

/* ── Motion: smooth page + tab transitions. All of it is gated behind the OS "reduce motion"
   setting, and only ever animates opacity/transform (compositor-cheap, no layout/jank). ── */
.tabs .tab { transition: color .15s ease, border-color .15s ease; }
.dbg-toptabs .dbg-tt { transition: color .15s ease, border-color .15s ease, background .15s ease; }

/* ── Overlay entrances ──
   The modal, the row context menu and the currency dropdown all used to appear with no transition:
   absent one frame, fully drawn the next. Each now arrives from where it belongs. The fade runs for
   everyone so nothing ever pops in; the movement sits behind the OS reduce-motion setting below. */
.modal-back, .modal, .ao-menu, .ccy-dd-list { animation: overlayFade .16s var(--ease-out) both; }
/* A context menu opens down and to the right of the click, so it should grow from that corner
   rather than from its middle. The dropdown is anchored under its button, so it grows from the top
   edge. `top` rather than `top left` keeps that correct when the portal flips to RTL. */
.ao-menu { transform-origin: top left; }
.ccy-dd-list { transform-origin: top; }
@keyframes overlayFade { from { opacity: 0; } }

@media (prefers-reduced-motion: no-preference) {
  /* Modals keep the default centre origin: they are not anchored to a trigger, they own the
     viewport. Scale starts at .97, never 0, because nothing real grows out of nothing. */
  .modal { animation: modalIn .2s var(--ease-out) both; }
  .ao-menu { animation: menuIn .15s var(--ease-out) both; }
  .ccy-dd-list { animation: menuIn .16s var(--ease-out) both; }
  @keyframes modalIn { from { opacity: 0; transform: scale(.97); } }
  @keyframes menuIn { from { opacity: 0; transform: scale(.96); } }
  /* Under 560px the modal is a bottom sheet (see the .modal-back rule above), so it rises from the
     edge it is pinned to instead of scaling from the centre. The percentage is the sheet's own
     height, so this holds whatever the content is. */
  @media (max-width: 560px) {
    .modal { animation: sheetIn .28s var(--ease-drawer) both; }
    @keyframes sheetIn { from { transform: translateY(100%); } }
  }
}
@media (prefers-reduced-motion: no-preference) {
  /* A pure, unhurried opacity cross-fade — no slide/transform (that read as a "hard" snap).
     Longer + gentle easing makes page and tab changes feel soft. */
  @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
  /* Re-triggered by the routers on every navigation (view.classList add/remove) so each page
     change fades in; the class is harmless on browsers/settings that skip the animation. */
  #view.view-anim { animation: fadeIn .38s ease both; }
  /* List/tab content swaps (debug subtabs, ticket detail, bottom tab panels) fade in too.
     One selector for every admin list body — it was per-id, which meant each new list had to
     remember to add its own rule (and two of them shipped the JS class with no CSS behind it). */
  #dbgBody.fade-in, #aoRows.fade-in, #pBody.fade-in, #tkBody.fade-in, #actBody.fade-in,
  #fuListBody.fade-in, #acRows.fade-in { animation: fadeIn .34s ease both; }
  .prod-tabs .tab-panel:not([hidden]) { animation: fadeIn .34s ease both; }
}

/* ── Developer opened-ticket tabs — single line, overflow ⋮ menu, drag-reorder ── */
.dbg-toptabs { position: relative; width: 100%; display: flex; gap: 4px; align-items: center; overflow: hidden; margin: 0 0 10px; padding-inline-end: 40px; min-height: 34px; }
.dbg-toptabs .dbg-tt { display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px; font: 600 13px/1.2 var(--font); color: var(--muted); background: var(--hover); border: 1px solid var(--line); border-radius: 8px; cursor: pointer; white-space: nowrap; }
.dbg-toptabs .dbg-tt.on { color: var(--ink); border-color: var(--ink); background: var(--card); }
.dbg-toptabs .dbg-tt.dragging { opacity: .5; }
.dbg-toptabs .dbg-tt-x { opacity: .55; font-size: 11px; }
.dbg-toptabs .dbg-tt-x:hover { opacity: 1; }
.dbg-tt-more { position: absolute; inset-inline-end: 0; top: 50%; transform: translateY(-50%); border: 1px solid var(--line); background: var(--card); border-radius: 8px; cursor: pointer; font-size: 16px; line-height: 1; color: var(--muted); padding: 5px 9px; }
.dbg-tt-more:hover { color: var(--ink); }
.ao-menu button .dbg-mx { float: inline-end; opacity: .55; margin-inline-start: 14px; }
.ao-menu button .dbg-mx:hover { opacity: 1; }
/* Drop targets while dragging a tab: the ⋮ button and the overflow dropdown. */
.dbg-tt-more.drag-over { color: var(--ink); border-color: var(--ink); box-shadow: 0 0 0 2px var(--line-2) inset; }
.ao-menu.dbg-more.drag-over { outline: 2px solid var(--ink); outline-offset: -2px; }
.ao-menu.dbg-more button.dragging { opacity: .5; }
/* Active/open ticket highlighted inside the overflow dropdown (matches the row tab .on). */
.ao-menu.dbg-more button.on { color: var(--ink); font-weight: 700; }
/* "Close all tabs" sits under the overflow list — ruled off from it, but not when it's alone. */
.ao-menu.dbg-more .dbg-closeall:not(:only-child) { border-top: 1px solid var(--line); border-radius: 0; margin-top: 4px; padding-top: 10px; }
/* Triage dropdown: the row's current value is bold. */
.ao-menu button.on { color: var(--ink); font-weight: 700; }

/* ── Misc ── */
.divider { height: 1px; background: var(--line); margin: 18px 0; border: 0; }
.kv { display: grid; grid-template-columns: 140px 1fr; gap: 6px 14px; font-size: 14px; }
.kv dt { color: var(--muted); } .kv dd { margin: 0; }
@media (max-width: 480px) { .kv { grid-template-columns: 1fr; gap: 0; } .kv dt { margin-top: 8px; } }
.qty-stepper { display: inline-flex; align-items: center; border: 1px solid var(--line-2); border-radius: 10px; overflow: hidden; }
.qty-stepper button { width: 40px; height: 40px; border: 0; background: var(--card); font-size: 18px; cursor: pointer; color: var(--ink); }
.qty-stepper button:hover { background: var(--hover); }
.qty-stepper input { width: 64px; height: 40px; border: 0; border-inline: 1px solid var(--line); text-align: center; font: 600 15px var(--font); outline: none; }
.notif-dot { position: absolute; top: -3px; inset-inline-end: -3px; min-width: 17px; height: 17px; border-radius: 999px; background: var(--accent); color: #fff; font-size: 10.5px; line-height: 17px; text-align: center; padding: 0 4px; font-weight: 700; }

/* ── Product detail page (portal live view + admin "View as partner" preview share this) ──
   Moved here from portal.html so the admin preview overlay renders identically. */
.prod-wrap { max-width: 1200px; margin: 0 auto; padding: 0 clamp(0px, 3vw, 32px); }
.pgrid { display: grid; gap: 22px; margin-top: 4px; }
@media (min-width: 860px) { .pgrid { column-gap: 48px; } } /* breathing room between gallery and info */
@media (min-width: 860px) {
  .pgrid { grid-template-columns: 5fr 6fr; align-items: start; }
  /* Shopify-style: the gallery stays put while the info column scrolls past it, then the page
     scrolls on to related products + the description/shipping/warranty tabs below. */
  .pgrid > .pgal { position: sticky; top: 16px; align-self: start; }
}
.gal-main { aspect-ratio: 1; border-radius: var(--r); background: var(--accent-soft); display: flex; align-items: center; justify-content: center; overflow: hidden; font-size: 72px; color: var(--accent); border: 1px solid var(--line); }
.gal-main img { width: 100%; height: 100%; object-fit: cover; }
.gal-play { width: 64px; height: 64px; border-radius: 999px; border: 0; cursor: pointer; background: rgba(20,20,20,.6); color: #fff; font-size: 24px; padding-inline-start: 4px; display: flex; align-items: center; justify-content: center; }
.gal-play:hover { background: rgba(20,20,20,.78); }
/* Shopify-style prev/next arrows over the main image (kept OUTSIDE #galMain — its innerHTML
   is replaced on every image/video swap, which would wipe buttons rendered inside it). */
.gal-wrap { position: relative; }
.gal-wrap .gal-main img { cursor: zoom-in; }
.gal-nav { position: absolute; top: 50%; transform: translateY(-50%); z-index: 2; width: 38px; height: 38px; border-radius: 999px; border: 1px solid var(--line); background: rgba(255,255,255,.92); color: var(--ink); font-size: 22px; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; }
.gal-nav:hover { background: #fff; }
.gal-prev { left: 10px; }
.gal-next { right: 10px; }
.gal-thumbs { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.gal-thumbs .th { position: relative; width: 58px; height: 58px; border-radius: 10px; overflow: hidden; border: 2px solid transparent; cursor: pointer; background: var(--accent-soft); flex: none; padding: 0; }
.gal-thumbs .th.on { border-color: var(--accent); }
.gal-thumbs .th img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gal-thumbs .th-vid-bg { width: 100%; height: 100%; background: var(--accent-soft) center/cover no-repeat; display: flex; align-items: center; justify-content: center; font-size: 20px; color: var(--accent); }
.gal-thumbs .th-play { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(20,20,20,.34); color: #fff; font-size: 15px; padding-inline-start: 2px; }
#brkTable tr.brk-on td { background: var(--accent-soft); }
/* ── media lightbox (openLightbox in ui.js) ─────────────────────────────────── */
.lb-back { position: fixed; inset: 0; z-index: 120; background: rgba(15,15,15,.85); }
.lb-top { position: absolute; top: 0; left: 0; right: 0; height: 52px; display: flex; align-items: center; justify-content: space-between; padding: 0 14px; z-index: 3; }
.lb-count { font: 600 14px/1 var(--font); color: #e8e8e8; }
.lb-tools { display: flex; gap: 8px; }
.lb-btn { width: 38px; height: 38px; border-radius: 999px; border: 0; background: rgba(255,255,255,.14); color: #fff; font-size: 19px; line-height: 1; cursor: pointer; }
.lb-btn:hover { background: rgba(255,255,255,.28); }
.lb-btn:disabled { opacity: .35; cursor: default; }
.lb-nav { position: absolute; top: 50%; transform: translateY(-50%); z-index: 3; width: 44px; height: 44px; border-radius: 999px; border: 0; background: rgba(255,255,255,.14); color: #fff; font-size: 26px; line-height: 1; cursor: pointer; }
.lb-nav:hover { background: rgba(255,255,255,.28); }
.lb-prev { left: 12px; }
.lb-next { right: 12px; }
.lb-stage { position: absolute; inset: 52px 0 0 0; overflow: auto; display: flex; align-items: center; justify-content: center; }
.lb-stage img { max-width: min(90vw, 1100px); max-height: calc(100vh - 76px); object-fit: contain; cursor: zoom-in; user-select: none; }
.lb-stage.zoomed { display: block; }  /* panning: image overflows, native scroll takes over */
.lb-stage.zoomed img { max-width: none; max-height: none; cursor: zoom-out; }
.lb-stage video { max-width: 90vw; max-height: calc(100vh - 76px); }
/* Rail is wide enough that the scrollbar (styled slim below) never overlaps the 62px thumbs. */
.lb-rail { position: absolute; top: 60px; right: 14px; bottom: 14px; width: 80px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; z-index: 3; padding-right: 12px; scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.35) transparent; }
.lb-rail::-webkit-scrollbar { width: 6px; }
.lb-rail::-webkit-scrollbar-track { background: transparent; }
.lb-rail::-webkit-scrollbar-thumb { background: rgba(255,255,255,.35); border-radius: 3px; }
.lb-th { position: relative; width: 58px; height: 58px; flex: none; border-radius: 8px; overflow: hidden; border: 2px solid transparent; padding: 0; cursor: pointer; background: #2a2a2a; }
.lb-th img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: .8; }
.lb-th.on { border-color: #fff; }
.lb-th.on img { opacity: 1; }
.lb-th-play { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #fff; background: rgba(20,20,20,.4); z-index: 1; font-size: 14px; }
@media (min-width: 721px) { .lb-back:has(.lb-rail) .lb-stage { right: 104px; } .lb-back:has(.lb-rail) .lb-next { right: 112px; } }
@media (max-width: 720px) { .lb-rail { display: none; } }
/* short blurb — full text lives in the Description tab below */
.prod-blurb { color: var(--ink-2); font-size: 14px; line-height: 1.6; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
/* Shopify-style hero price: big current unit, muted strikethrough compare-at beside it */
.price-block { display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px; margin: 12px 0 4px; }
.price-now { font: 700 30px/1.1 var(--font); color: var(--ink); }
.price-block .approx { flex-basis: 100%; margin: 0; }
/* Malaysia retail price — plain (no strikethrough) so partners read their margin at a glance */
.retail-line { font-size: 13.5px; color: var(--muted); margin: 0 0 12px; }
.retail-line b { color: var(--ink-2); font-weight: 700; }
.save-badge { display: inline-block; background: var(--ok-soft); color: var(--ok); border-radius: 999px; padding: 1px 8px; font-size: 12px; font-weight: 700; margin-inline-start: 6px; }
/* Shopify-style tier table — compact width (so the price isn't flung to the page edge),
   plain rows with a light hairline; the active tier is highlighted via .brk-on. */
.brk-lite { max-width: 460px; }
.brk-lite th { padding: 8px 12px; }
.brk-lite td { padding: 10px 12px; border-bottom: 1px solid var(--line); }
.brk-lite tbody tr:last-child td { border-bottom: 0; }
.addrow { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 14px; }
.addrow .btn { flex: 1; min-width: 150px; border-radius: 999px; }
/* Ready-stock badge on the product page — green pill, theme-aware via --ok / --ok-soft. */
.ready-flag { display: inline-flex; align-items: center; gap: 6px; background: var(--ok-soft); color: var(--ok); border-radius: 999px; padding: 3px 10px; font-size: 12px; font-weight: 700; margin: 8px 0 2px; }
.ready-flag .ready-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); }

/* variant selectors (Shopify-style) */
.opt-groups { margin: 8px 0 6px; display: flex; flex-direction: column; gap: 14px; }
.opt-head { font: 600 13px/1.3 var(--font); color: var(--ink-2); margin-bottom: 6px; }
.opt-head .opt-name { color: var(--ink); }
.opt-head .opt-current { color: var(--muted); font-weight: 600; }
.opt-values { display: flex; gap: 8px; flex-wrap: wrap; }
.opt-btn { border: 1px solid var(--line-2); background: var(--card); border-radius: 9px; padding: 8px 14px; font: 600 13px/1.2 var(--font); color: var(--ink-2); cursor: pointer; min-height: 40px; }
.opt-btn:hover { border-color: var(--ink-2); }
.opt-btn.on { border-color: var(--ink); background: var(--ink); color: var(--paper); }
.opt-sw { width: 40px; height: 40px; border-radius: 999px; border: 2px solid transparent; background: none; padding: 3px; cursor: pointer; }
.opt-sw span { display: block; width: 100%; height: 100%; border-radius: 999px; border: 1px solid rgba(20,20,20,.15); }
.opt-sw:hover { border-color: var(--line-2); }
.opt-sw.on { border-color: var(--ink); }
/* combination not sold (no matching variant) — crossed out, Shopify-style */
.opt-btn.unavail { color: var(--muted); border-style: dashed;
  background-image: linear-gradient(to top right, transparent 46%, var(--bad) 47%, var(--bad) 53%, transparent 54%); }
.opt-btn.unavail.on { background-color: var(--card); color: var(--muted); border-color: var(--line-2); }
.opt-sw.unavail { opacity: .45;
  background-image: linear-gradient(to top right, transparent 46%, var(--bad) 47%, var(--bad) 53%, transparent 54%); }

/* "Pairs well with" — compact rows inside the product info column (portal PDP + admin preview) */
.pairs { margin-top: 22px; border-top: 1px solid var(--line); padding-top: 14px; }
.pairs-h { font-size: 12px; margin-bottom: 10px; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); }
.pair-row { display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; grid-template-rows: auto auto;
  column-gap: 12px; align-items: center; padding: 9px 0; border-top: 1px solid var(--line); cursor: pointer; }
.pair-row:first-of-type { border-top: 0; }
.pair-thumb { grid-row: 1 / 3; width: 56px; height: 56px; border-radius: 10px; overflow: hidden;
  background: var(--accent-soft) center/cover no-repeat; display: flex; align-items: center; justify-content: center;
  color: var(--accent); font-size: 22px; border: 1px solid var(--line); }
.pair-name { grid-column: 2; grid-row: 1; font-weight: 600; font-size: 13.5px; line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.pair-price { grid-column: 2; grid-row: 2; color: var(--ink-2); font-size: 12.5px; margin-top: 2px; }
.pair-price s { color: var(--muted); }
.pair-btn { grid-column: 3; grid-row: 1 / 3; }

/* PDP panel pieces shared by the portal product page AND the admin "View as partner"
   preview (returnsPanelHtml in ui.js renders this markup on both). Portal-only pieces
   (.pdp-table, .pdp-blockhead) stay in portal.html. */
.pdp-lead { max-width: 64ch; color: var(--ink-2); }
.pdp-notes { background: var(--pdp-box, #f4f4f4); border-radius: var(--r); padding: 16px 22px; margin-top: 16px; }
.pdp-notes ul { margin: 0; padding-inline-start: 20px; display: flex; flex-direction: column; gap: 9px; }
.pdp-notes li { color: var(--ink-2); }
.pdp-notes li strong { color: var(--ink); }

/* bottom description / shipping / warranty tabs */
.prod-tabs { margin-top: 40px; }
/* Shopify-style: the tab row sits centred on the page; panels centre under it */
.prod-tabs .tabs { justify-content: center; gap: 8px; }
.prod-tabs .tab-panel { padding: 18px 2px 4px; max-width: 820px; margin: 0 auto; font-size: 14px; line-height: 1.65; }
.prod-tabs .tab-panel p { color: var(--ink-2); }

/* retail compare (product page + related/catalogue cards) */
.retail-note { margin: -4px 0 12px; font-size: 13.5px; }
.retail-note s { color: var(--muted); }
.pcard .pretail { color: var(--muted); font-size: 12px; }

/* ── Admin "View as partner" full-screen preview overlay ── */
.pv-overlay { position: fixed; inset: 0; z-index: 95; background: var(--paper); display: flex; flex-direction: column; }
.pv-bar { display: flex; align-items: center; gap: 12px; padding: 10px clamp(12px, 3vw, 24px); background: var(--card); border-bottom: 1px solid var(--line); flex: none; }
.pv-bar .pv-title { font-weight: 700; }
.pv-bar .pv-note { color: var(--muted); font-size: 12.5px; }
.pv-bar .spacer { flex: 1; }
.pv-seg { display: inline-flex; border: 1px solid var(--line-2); border-radius: 9px; overflow: hidden; }
.pv-seg button { border: 0; background: var(--card); color: var(--ink-2); font: 600 13px/1 var(--font); padding: 9px 14px; cursor: pointer; }
.pv-seg button + button { border-inline-start: 1px solid var(--line-2); }
.pv-seg button.on { background: var(--ink); color: var(--paper); }
.pv-body { flex: 1; overflow-y: auto; padding: 22px 0 60px; }
.pv-body .addrow .btn { pointer-events: none; }

/* ── Media fallbacks (UI kit row 18) ── */
/* Broken product images self-heal to a neutral ◌ tile (imgHeal in ui.js) — never the browser icon. */
img.img-heal { object-fit: contain; background: var(--accent-soft); }
/* Muted first-frame <video> stands in wherever a product has a video but no thumbnail image. */
.vid-pv { object-fit: cover; pointer-events: none; display: block; background: #000; }
.th-vid-bg .vid-pv, .lb-th .vid-pv, .pimg .vid-pv { width: 100%; height: 100%; }
.gal-main { position: relative; }
.gal-main .vid-pv { position: absolute; inset: 0; width: 100%; height: 100%; }
.gal-main .gal-play { position: relative; z-index: 1; }

/* ── Shipping journey globe (portal + admin) ───────────────────────────── */
.jr-card { overflow: hidden; }
.jr-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }
.jr-eyebrow { font: 700 11px/1 var(--font); text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
.jr-route { font: 600 14px/1.3 var(--font); color: var(--ink); }
.jr-route .a { color: var(--muted); margin: 0 6px; }
.jr-stage { position: relative; width: 100%; aspect-ratio: 16 / 10; max-height: 360px; }
.jr-globe { display: block; width: 100%; height: 100%; touch-action: none; }
.jr-now { position: absolute; left: 2px; bottom: 2px; right: 2px; display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; pointer-events: none; }
.jr-lbl { font: 600 10.5px/1 var(--font); text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.jr-val { font: 700 16px/1.25 var(--font); color: var(--ink); }
.jr-eta { font: 500 12px/1 var(--font); color: var(--muted); background: var(--paper); border: 1px solid var(--line); padding: 5px 10px; border-radius: 999px; white-space: nowrap; }
.jr-hint { font-size: 11.5px; color: var(--muted); margin-top: 8px; }
.jr-duo { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 640px) { .jr-duo { grid-template-columns: 1fr; } }
.jr-panel { position: relative; border: 1px solid var(--line); border-radius: 12px; overflow: hidden; aspect-ratio: 1 / 1; }
.jr-panel .jr-globe { position: absolute; inset: 0; }
.jr-badge { position: absolute; top: 10px; left: 10px; z-index: 2; font: 700 10.5px/1 var(--font); text-transform: uppercase; letter-spacing: .05em; padding: 5px 8px; border-radius: 6px; }
.jr-badge.cust { color: var(--ink-2); background: var(--paper); border: 1px solid var(--line); }
.jr-badge.real { color: #b53523; background: #fbe9e6; border: 1px solid #f0ccc6; }
html[data-theme="dark"] .jr-badge.real { color: #ec8073; background: #2a1512; border-color: #3d211c; }
.jr-mask { display: flex; gap: 8px; align-items: flex-start; font-size: 12.5px; color: var(--muted); margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
.jr-mask b { color: var(--ink); }
.jr-steps { display: flex; gap: 0; margin: 6px 0 2px; }
.jr-step { flex: 1; text-align: center; position: relative; padding-top: 24px; }
.jr-step::before { content: ""; position: absolute; top: 6px; left: -50%; width: 100%; height: 2px; background: var(--line); }
.jr-step:first-child::before { display: none; }
.jr-step .k { position: absolute; top: 0; left: 50%; transform: translateX(-50%); width: 14px; height: 14px; border-radius: 50%; background: var(--card); border: 2.5px solid var(--line); }
.jr-step.done::before { background: var(--ok); }
.jr-step.done .k, .jr-step.cur .k { border-color: var(--ok); background: var(--ok); }
.jr-step.cur .k { box-shadow: 0 0 0 4px var(--ok-soft); }
.jr-step .lb { font: 600 12px/1.2 var(--font); color: var(--muted); }
.jr-step.cur .lb, .jr-step.done .lb { color: var(--ink); }
.jr-origin { display: flex; align-items: center; gap: 8px; margin-top: 14px; font-size: 13.5px; color: var(--ink); }

/* Debug-report inline edit (developer) — title/description edit in place, category/priority as selects */
.tk-title { font: 700 20px/1.3 var(--font); color: var(--ink); width: 100%; padding: 4px 8px; margin: 0 0 2px -8px; border: 1px solid transparent; border-radius: 8px; background: transparent; }
.tk-title:hover { border-color: var(--line); }
.tk-title:focus { border-color: var(--accent); background: var(--card); outline: none; }
.tk-meta { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: flex-end; margin-top: 10px; }
.tk-fld { display: flex; flex-direction: column; gap: 4px; }
.tk-fld select, .tk-fld .input { max-width: 200px; padding: 6px 10px; font-size: 13px; }
.tk-desc-edit { width: 100%; min-height: 60px; }

/* Debug report list is its own scrollable panel with its OWN side scrollbar, so the title, tabs and
   filters stay put while the rows scroll. JS (fitList) sizes the panel to fill the viewport below the
   filters — as many rows as the screen allows, the rest one scroll away; this rule is the pre-JS
   fallback. The column header pins to the top of the panel as you scroll. */
#dbgList .table thead th { position: sticky; top: 0; z-index: 2; background: var(--card); }
#dbgList .table-wrap { max-height: calc(100vh - 300px); min-height: 320px; overflow-y: auto; }
/* Category / Priority / Assignee cells are click-to-change: a caret reserves its space always
   (so hovering never nudges the column) and fades in with a tinted cell on hover. */
#dbgList td[data-edit]::after { content: '▾'; margin-inline-start: 6px; color: var(--muted); opacity: 0; }
#dbgList td[data-edit]:hover { background: var(--hover); box-shadow: inset 0 0 0 1px var(--line); }
#dbgList td[data-edit]:hover::after { opacity: 1; }
