/* ============================================================
   CHHAPERIA ERP — APP LAYOUT & COMPONENTS
   ============================================================ */

/* ---------- SPLASH ---------- */
.splash{position:fixed;inset:0;z-index:9999;display:grid;place-content:center;justify-items:center;gap:22px;
  background:var(--bg);}
.splash.hide{opacity:0;pointer-events:none;transition:opacity .5s ease}
.splash-mark img{width:230px}
.splash-bar{width:220px;height:5px;border-radius:14px;background:var(--panel-3);overflow:hidden}
.splash-bar span{display:block;height:100%;width:40%;border-radius:14px;
  background:linear-gradient(90deg,var(--brand-orange),var(--brand-red));animation:load 1.1s ease-in-out infinite}
.splash-text{font-weight:800;letter-spacing:.32em;color:var(--text-dim);font-size:13px}
@keyframes load{0%{transform:translateX(-120%)}100%{transform:translateX(330%)}}
@keyframes floaty{0%,100%{transform:translateY(0)}50%{transform:translateY(-10px)}}

/* ---------- SHELL ---------- */
.app-shell{display:grid;grid-template-columns:262px minmax(0,1fr);height:100vh;height:100dvh;}
.app-shell.collapsed{grid-template-columns:74px 1fr}

/* ---------- SIDEBAR ---------- */
.sidebar{background:var(--sidebar);border-right:1px solid var(--sidebar-line);
  display:flex;flex-direction:column;min-height:0;position:relative;z-index:30}
.sidebar-brand{display:flex;align-items:center;height:64px;padding:0 18px;border-bottom:1px solid var(--sidebar-line)}
.brand-logo-full{height:30px}
.brand-logo-mark{height:34px;display:none}
.collapsed .brand-logo-full{display:none}
.collapsed .brand-logo-mark{display:block;margin:0 auto}
.nav{flex:1;overflow-y:auto;padding:12px 12px 6px;display:flex;flex-direction:column;gap:4px}
.nav-section{font-size:10px;letter-spacing:.18em;color:#59637a;text-transform:uppercase;
  padding:16px 12px 6px;font-weight:800}
/* ---- section dropdowns (App.buildNav wraps each section in .nav-group;
   the supervisor shell renders bare .nav-section divs and keeps its flat
   look — everything interactive is scoped under .nav-group) ---- */
.nav-group{display:flex;flex-direction:column;gap:4px}
.nav-group-items{display:flex;flex-direction:column;gap:4px}
.nav-group:not(.open)>.nav-group-items{display:none}
.nav-group>.nav-section{display:flex;align-items:center;gap:8px;width:100%;
  background:none;border:none;cursor:pointer;font-family:inherit;text-align:left;
  transition:color var(--tr)}
.nav-group>.nav-section:hover{color:#8b96ad}
.nav-sec-lbl{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nav-sec-chev{font-size:10px;letter-spacing:0;opacity:.7;transition:transform var(--tr)}
.nav-group:not(.open) .nav-sec-chev{transform:rotate(-90deg)}
/* a closed fold's alert total — the .pill look, warn/danger like the items' own */
.nav-sec-badge{font-size:10px;font-weight:700;padding:2px 8px;border-radius:14px;letter-spacing:0;
  background:var(--accent-soft);color:var(--accent-300)}
.nav-sec-badge.warn{background:var(--warn-soft);color:var(--warn)}
.nav-sec-badge.danger{background:var(--danger-soft);color:var(--danger)}
/* collapsed rail: dropdowns off — every icon stays reachable, the head is a divider */
.collapsed .nav-group:not(.open)>.nav-group-items{display:flex}
.collapsed .nav-group>.nav-section{pointer-events:none}
.collapsed .nav-sec-chev,.collapsed .nav-sec-badge,.collapsed .nav-sec-lbl{display:none}
/* collapsed rail: hide the section label (it squished/wrapped) and show a
   clean centered divider between icon groups instead */
.collapsed .nav-section{font-size:0;letter-spacing:0;padding:12px 0 8px}
.collapsed .nav-section::after{content:"";display:block;width:22px;height:2px;border-radius:2px;margin:0 auto;background:var(--sidebar-line)}
.collapsed .nav-group>.nav-section::after{margin:0 auto}
.nav-item{display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:10px;color:var(--sidebar-text);
  cursor:pointer;font-weight:600;font-size:13px;position:relative;transition:var(--tr);white-space:nowrap}
/* emoji glyphs rendered as a uniform monochrome icon set — colour is the
   reward for hover/active, so the rail reads as one system, not a toybox */
.nav-item .ic{width:20px;text-align:center;font-size:17px;flex:0 0 20px;
  filter:grayscale(1);opacity:.8;transition:filter var(--tr),opacity var(--tr)}
.nav-item:hover{background:rgba(255,255,255,.055);color:#fff}
.nav-item:hover .ic,.nav-item.active .ic{filter:none;opacity:1}
.nav-item.active{color:#fff;background:var(--accent-soft);
  box-shadow:inset 0 0 0 1px var(--accent-line)}
.nav-item.active::before{content:"";position:absolute;left:-12px;top:7px;bottom:7px;width:4px;border-radius:0 4px 4px 0;
  background:var(--accent)}
.nav-item .pill{margin-left:auto;font-size:10px;font-weight:700;padding:2px 8px;border-radius:14px;
  background:var(--accent-soft);color:var(--accent-300)}
.nav-item .pill.warn{background:var(--warn-soft);color:var(--warn)}
.nav-item .pill.danger{background:var(--danger-soft);color:var(--danger)}
.collapsed .nav-item{justify-content:center;padding:12px 0}
.collapsed .nav-item .lbl,.collapsed .nav-item .pill{display:none}
.sidebar-foot{padding:12px;border-top:1px solid var(--sidebar-line)}
.org-card{display:flex;align-items:center;gap:10px;background:rgba(255,255,255,.04);border:1px solid var(--sidebar-line);
  padding:10px 12px;border-radius:10px}
.org-dot{width:9px;height:9px;border-radius:50%;background:var(--ok);box-shadow:0 0 0 3px var(--ok-soft);flex:0 0 9px}
.org-name{font-size:13px;font-weight:700;color:#dfe6f1}
.org-sub{font-size:11px;color:#6f7c92}
.collapsed .org-card>div:last-child{display:none}
.collapsed .org-card{justify-content:center}

/* ---------- TOPBAR ---------- */
.main{display:flex;flex-direction:column;min-width:0;min-height:0}
.topbar{height:64px;display:flex;align-items:center;gap:12px;padding:0 18px;
  background:var(--glass);backdrop-filter:blur(16px) saturate(1.4);-webkit-backdrop-filter:blur(16px) saturate(1.4);
  border-bottom:1px solid var(--line);position:sticky;top:0;z-index:20}
.topbar-spacer{flex:1}
.icon-btn{width:38px;height:38px;border-radius:10px;border:1px solid var(--line);background:var(--panel-2);
  color:var(--text-dim);font-size:17px;cursor:pointer;display:grid;place-items:center;box-shadow:var(--inset-top);
  transition:var(--tr);position:relative}
.icon-btn:hover{color:var(--text);border-color:var(--accent-line);background:var(--panel-3);transform:translateY(-1px)}
.icon-btn:active{transform:translateY(0) scale(.95)}
.menu-toggle{font-size:17px}
/* min-width:0 and an ellipsis on the page name: a long crumb ("Label Studio")
   could not shrink, and on a phone held sideways (821–900px, the desktop
   shell) it pushed the top bar 40px past the edge — which a mobile browser
   answers by widening the whole layout viewport, clipping every screen. */
.crumbs{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--text-mut);font-weight:600;min-width:0}
.crumbs .cur{color:var(--text);font-weight:700;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.crumbs .sep{opacity:.5}
/* the way back to the tab you came from, ahead of the crumbs */
.crumb-back{display:inline-flex;align-items:center;gap:6px;margin-right:4px;
  padding:4px 10px 4px 8px;border-radius:999px;border:1px solid var(--line);
  background:var(--panel-2);color:var(--text-dim);font-family:inherit;font-size:12px;
  font-weight:700;cursor:pointer;transition:var(--tr);max-width:180px}
.crumb-back:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.crumb-back-a{font-size:15px;line-height:1}
.crumb-back-t{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.search-trigger{display:flex;align-items:center;gap:10px;height:38px;padding:0 12px;border-radius:10px;
  border:1px solid var(--line);background:var(--panel-2);color:var(--text-mut);cursor:pointer;font-size:13px;
  font-weight:600;transition:var(--tr);min-width:240px}
.search-trigger:hover{border-color:var(--accent-line);color:var(--text-dim)}
.search-trigger .si{font-size:17px}
.search-trigger kbd{margin-left:auto}
.bell .badge{position:absolute;top:-5px;right:-5px;min-width:18px;height:18px;border-radius:14px;background:var(--danger);
  color:#fff;font-size:10px;font-weight:800;display:grid;place-items:center;padding:0 4px;border:2px solid var(--bg)}
.user-chip{display:flex;align-items:center;gap:10px;padding:4px 4px 4px 6px;border-radius:10px;cursor:pointer;transition:var(--tr)}
.user-chip:hover{background:var(--panel-2)}
.avatar{width:36px;height:36px;border-radius:10px;display:grid;place-items:center;font-weight:800;font-size:13px;color:#fff;
  background:var(--brand-orange)}
.user-meta{line-height:1.2}
.user-name{font-size:13px;font-weight:700}
.user-role{font-size:11px;color:var(--text-mut)}

/* accent popover */
.accent-pop{position:relative}
.accent-menu{position:absolute;top:46px;right:0;width:226px;background:var(--panel);border:1px solid var(--line);
  border-radius:14px;box-shadow:var(--shadow-pop);padding:14px;z-index:50}
.accent-title{font-size:11px;font-weight:700;color:var(--text-mut);text-transform:uppercase;letter-spacing:.12em;margin-bottom:10px}
.swatches{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
.swatch{height:34px;border-radius:10px;cursor:pointer;border:2px solid transparent;transition:var(--tr);position:relative}
.swatch:hover{transform:scale(1.08)}
.swatch.sel{border-color:var(--text)}
.swatch.sel::after{content:"✓";position:absolute;inset:0;display:grid;place-items:center;color:#fff;font-weight:800;font-size:13px;
  text-shadow:0 1px 3px rgba(0,0,0,.5)}
.auto-accent{display:flex;align-items:center;gap:8px;margin-top:12px;font-size:12px;color:var(--text-dim);cursor:pointer}

/* ---------- "New Item" split-button dropdown ---------- */
.ni-drop{position:relative;display:inline-block}
.ni-drop .caret{margin-left:6px;font-size:11px;opacity:.85;display:inline-block;transition:transform .18s ease}
.ni-drop .btn.open .caret{transform:rotate(180deg)}
.ni-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:216px;background:var(--panel);
  border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow-pop);padding:6px;z-index:60;
  display:flex;flex-direction:column;gap:2px}
.ni-menu[hidden]{display:none}
.ni-opt{display:flex;align-items:center;gap:10px;width:100%;text-align:left;padding:10px 12px;border:none;
  background:none;color:var(--text);font:inherit;font-weight:600;font-size:13px;border-radius:10px;cursor:pointer;transition:var(--tr)}
.ni-opt:hover{background:var(--panel-2);color:var(--accent)}

/* ---------- VIEW / GENERIC ---------- */
.view{flex:1;overflow-y:auto;padding:24px;scroll-behavior:smooth}
/* readable measure on wide monitors — content caps and centres; full-bleed
   modules (Label Studio) opt out below */
.view>*{max-width:1680px;margin-left:auto;margin-right:auto}
.view>.ls{max-width:none}
.page-head{display:flex;align-items:flex-end;gap:16px;margin-bottom:24px;flex-wrap:wrap}
.page-title{font-size:var(--fs-2xl);font-weight:800;letter-spacing:-.02em;display:flex;align-items:center;gap:12px}
.page-title .dot{width:10px;height:10px;border-radius:4px;background:var(--accent);transform:rotate(45deg)}
.page-sub{color:var(--text-mut);font-size:13px;margin-top:4px}
.page-head .actions{margin-left:auto;display:flex;gap:10px;flex-wrap:wrap}

/* buttons */
.btn{display:inline-flex;align-items:center;gap:8px;height:38px;padding:0 16px;border-radius:10px;font-weight:600;
  font-size:13px;cursor:pointer;border:1px solid var(--line);background:var(--panel-2);color:var(--text);
  transition:transform var(--tr),box-shadow var(--tr),border-color var(--tr),background var(--tr),color var(--tr);white-space:nowrap}
.btn:hover{border-color:var(--accent-line);transform:translateY(-1px);box-shadow:var(--shadow-1)}
.btn:active{transform:translateY(0)}
.btn.primary{background:var(--accent);color:#fff;border:none;font-weight:700}
.btn.primary:hover{filter:brightness(1.06);box-shadow:var(--shadow-1)}
.btn.ghost{background:transparent;box-shadow:none}
.btn.ghost:hover{background:var(--panel-2)}
.btn.danger{color:var(--danger);border-color:var(--danger-soft);background:var(--danger-soft)}
.btn.danger:hover{border-color:var(--danger);background:var(--danger-soft)}
/* solid destructive CTA — the confirm dialog's "yes, do it" button */
.btn.danger-solid{background:var(--danger);color:#fff;border:none;font-weight:700}
.btn.danger-solid:hover{filter:brightness(1.06);box-shadow:var(--shadow-1)}
.btn.sm{height:32px;padding:0 12px;font-size:12px;border-radius:8px}
.btn:disabled{opacity:.55;cursor:not-allowed;transform:none;box-shadow:none}
.btn .ic{font-size:15px}

/* cards & grid */
.grid{display:grid;gap:16px}
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:16px;
  box-shadow:var(--shadow-1);transition:var(--tr);position:relative;overflow:hidden}
.card.hover{cursor:pointer}
.card.hover:hover{border-color:var(--accent-line);transform:translateY(-1px);box-shadow:var(--shadow-2)}
.card-head{display:flex;align-items:center;gap:10px;margin-bottom:16px}
.card-head h3{font-size:var(--fs-lg);font-weight:700;letter-spacing:-.01em}
.card-head .sub{font-size:var(--fs-sm);color:var(--text-mut)}
.card-head .tools{margin-left:auto;display:flex;gap:6px}

/* KPI — precision console tile: accent rail + machined depth */
.kpi-grid{grid-template-columns:repeat(auto-fit,minmax(216px,1fr))}
.kpi{padding:16px;border-radius:var(--radius);background:var(--panel);
  border:1px solid var(--line);position:relative;overflow:hidden;
  box-shadow:var(--shadow-1);transition:box-shadow var(--tr),border-color var(--tr);cursor:default}
.kpi::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--accent);opacity:.9}
.kpi:hover{border-color:var(--accent-line)}
.kpi-top{display:flex;align-items:center;justify-content:space-between;position:relative;z-index:1}
.kpi-ic{width:40px;height:40px;border-radius:10px;display:grid;place-items:center;font-size:21px;
  background:var(--accent-soft);color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent-line)}
.kpi-icn.blue{background:var(--info-soft);color:var(--info)}
.kpi-val{font-size:var(--fs-3xl);font-weight:800;letter-spacing:-.02em;margin-top:14px;position:relative;z-index:1;line-height:1.05}
.kpi-label{font-size:var(--fs-xs);color:var(--text-mut);font-weight:600;text-transform:uppercase;letter-spacing:.05em;position:relative;z-index:1;margin-top:4px}
.kpi-delta{display:inline-flex;align-items:center;gap:4px;font-size:var(--fs-xs);font-weight:700;margin-top:10px;
  padding:4px 8px;border-radius:var(--radius-pill);position:relative;z-index:1}
.kpi-delta.up{background:var(--ok-soft);color:var(--ok)}
.kpi-delta.down{background:var(--danger-soft);color:var(--danger)}
.kpi-delta.flat{background:var(--panel-3);color:var(--text-mut)}

/* compact KPI row — all tiles on one horizontal line, tighter (dashboard) */
.kpi-grid.compact{grid-template-columns:repeat(6,minmax(0,1fr));gap:12px}
.kpi-grid.compact .kpi{padding:14px 14px}
.kpi-grid.compact .kpi-ic{width:34px;height:34px;border-radius:10px;font-size:17px}
.kpi-grid.compact .kpi-val{font-size:21px;margin-top:10px}
.kpi-grid.compact .kpi-label{font-size:11px;letter-spacing:.04em}
.kpi-grid.compact .kpi-delta{font-size:11px;margin-top:8px;padding:2px 8px}
.kpi-grid.compact .chart-box{display:none}                 /* drop sparkline so 6 fit cleanly */
/* the Calendar shows four, not the dashboard's six — spread them evenly */
.kpi-grid.compact.cal-kpi{grid-template-columns:repeat(4,minmax(0,1fr))}
@media(max-width:900px){ .kpi-grid.compact.cal-kpi{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media(max-width:1240px){ .kpi-grid.compact{grid-template-columns:repeat(3,minmax(0,1fr))} }
@media(max-width:640px){ .kpi-grid.compact{grid-template-columns:repeat(2,minmax(0,1fr))} }

/* chips & badges */
.chip{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;padding:4px 10px;border-radius:var(--radius-pill);
  background:var(--panel-3);color:var(--text-dim);box-shadow:var(--inset-top);white-space:nowrap}
.chip .d{width:7px;height:7px;border-radius:50%}
.badge-s{font-size:11px;font-weight:700;padding:4px 10px;border-radius:6px;display:inline-flex;align-items:center;gap:6px;line-height:1.4;white-space:nowrap}
.s-ok{background:var(--ok-soft);color:var(--ok)}
.s-warn{background:var(--warn-soft);color:var(--warn)}
.s-danger{background:var(--danger-soft);color:var(--danger)}
.s-info{background:var(--info-soft);color:var(--info)}
.s-mut{background:var(--panel-3);color:var(--text-mut)}
.s-violet{background:var(--violet-soft);color:var(--violet)}
/* inline text link (accent colour + hover underline; overrides the global bare <a>) */
.a-link{color:var(--accent);text-decoration:none;overflow-wrap:anywhere;cursor:pointer;transition:var(--tr)}
.a-link:hover{text-decoration:underline}
/* clickable contacts: phone (call) + WhatsApp button, and the mail-app chooser popover */
.contact-line{color:var(--text-mut)}
.contact-cell{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap;vertical-align:middle}
.wa-btn{display:inline-flex;align-items:center;justify-content:center;width:23px;height:23px;border-radius:6px;
  background:var(--ok-soft);text-decoration:none;font-size:12px;line-height:1;flex:0 0 auto;transition:var(--tr)}
.wa-btn:hover{filter:brightness(1.12)}
.contact-pop{position:absolute;z-index:9999;min-width:232px;max-width:min(300px,92vw);
  background:var(--panel);border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow-pop);
  padding:6px;display:flex;flex-direction:column;gap:2px;animation:fadein .14s ease}
.contact-pop-head{padding:8px 12px 6px;font-size:11px;font-weight:800;color:var(--text-mut);
  text-transform:uppercase;letter-spacing:.04em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mail-opt{display:flex;align-items:center;gap:12px;width:100%;text-align:left;padding:10px 12px;border:none;
  border-radius:10px;background:none;color:var(--text);font:inherit;cursor:pointer;transition:var(--tr)}
.mail-opt:hover{background:var(--panel-2)}
.mail-opt-ic{font-size:17px;flex:0 0 auto;width:22px;text-align:center}
.mail-opt-tx{display:flex;flex-direction:column;gap:1px;min-width:0;line-height:1.25}
.mail-opt-tx b{font-size:13px;font-weight:700}
.mail-opt-tx .muted{font-size:11px;color:var(--text-mut)}

/* tables */
.table-wrap{overflow-x:auto;border-radius:var(--radius);border:1px solid var(--line);background:var(--panel);
  box-shadow:var(--shadow-1),var(--inset-top)}
table.tbl{width:100%;border-collapse:collapse;font-size:13px}
/* Standard table alignment (2026-08-31): text columns read LEFT, numeric
   columns read RIGHT — the heading follows its column, so figures line up on
   tabular digits and names align with their heading. */
.tbl thead th{text-align:left;padding:10px 10px;
  font-size:var(--fs-xs);font-weight:700;color:var(--text-mut);
  text-transform:uppercase;letter-spacing:.06em;border-bottom:1px solid var(--line-strong);
  background:var(--panel-2);
  position:sticky;top:0;z-index:1;cursor:pointer;user-select:none;white-space:normal;vertical-align:bottom;transition:color var(--tr)}
.tbl thead th.num{text-align:right}
.tbl thead th:hover{color:var(--text-dim)}
.tbl thead th .sortable{display:inline-flex;align-items:center;gap:6px}
.tbl thead th .arr{opacity:.4;font-size:10px}
.tbl thead th.sorted{color:var(--accent)}
.tbl thead th.sorted .arr{opacity:1;color:var(--accent)}
.tbl tbody td{text-align:left;padding:10px;
  border-bottom:1px solid var(--line);vertical-align:middle;overflow-wrap:break-word}
.tbl tbody tr{transition:background .12s,box-shadow .12s}
.tbl tbody tr:nth-child(even){background:var(--table-stripe)}
.tbl tbody tr:hover{background:var(--table-hover);box-shadow:inset 2px 0 0 var(--accent)}
.tbl tbody tr:last-child td{border-bottom:none}
.tbl .num{text-align:right;font-family:var(--mono);
  font-variant-numeric:tabular-nums;letter-spacing:-.01em;white-space:nowrap}
.tbl tbody td:has(.cell-main),.tbl tbody td.nm{text-align:left}
/* escape hatch: a cell whose content genuinely centres (status dots, actions) */
.tbl tbody td.ctr{text-align:center}
.tbl .mono{font-family:var(--mono);font-size:12px;white-space:nowrap}
/* A CODE is mono but must be allowed to break on its own hyphens. Left to
   nowrap, the longest item code in the catalogue (44 characters) claimed 347px
   of an 1128px table and squeezed the material name — the one thing on the row
   worth reading — down to 128px and five wrapped lines. */
.tbl .mono.code{white-space:normal;overflow-wrap:anywhere;line-height:1.35}
/* Declared column widths are hints under `table-layout:auto`; this keeps the
   name column from being squeezed below what a name needs to read as one.
   A centred status cell (Production's Stage) uses .cell-main for its label
   too; the floor is not for it — it pushed the row actions off a 1440 screen. */
.tbl th[style*="width"]{box-sizing:border-box}
.tbl tbody td:has(.cell-main):not(.ctr){min-width:150px}
.tbl .strong{font-weight:700}
.row-click{cursor:pointer}
.cell-main{font-weight:700}
.cell-sub{font-size:11px;color:var(--text-mut)}

/* toolbar (filters) */
.toolbar{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap}
.input,.select{height:38px;padding:0 12px;border-radius:10px;border:1px solid var(--line);background:var(--panel-2);
  color:var(--text);font-size:13px;font-family:inherit;box-shadow:var(--inset-top);transition:var(--tr);outline:none}
.input:hover,.select:hover{border-color:var(--line-strong)}
.input:focus,.select:focus{border-color:var(--accent);box-shadow:var(--ring)}
.input::placeholder{color:var(--text-mut)}
/* No spinner arrows on number inputs, anywhere (removed 2026-08-27 at the
   user's request): every figure here is typed, and the tiny up/down buttons
   only ever nudged a quantity by accident on a touch screen. */
input[type=number]{-moz-appearance:textfield;appearance:textfield}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;appearance:none;margin:0}
.input.search{min-width:240px;padding-left:34px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' fill='none' stroke='%238a94a6' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:11px center}
.date-range{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}
.date-label,.range-sep{font-size:11px;font-weight:800;text-transform:uppercase;color:var(--text-mut);letter-spacing:.04em}
.date-input{min-width:140px}
textarea.input{height:auto;padding:10px 12px;resize:vertical;min-height:78px;line-height:1.5}

/* searchable select (combobox) — see _erpUtil.searchSelect */
.ss{position:relative}
.ss .ss-input{width:100%}
.ss-pop{position:fixed;z-index:200;max-height:240px;overflow-y:auto;background:var(--panel);
  border:1px solid var(--line-strong);border-radius:10px;box-shadow:var(--shadow-pop);padding:6px;
  /* the popup is sized to its input, but a material option reads
     "NAME · thickness · GSM" and needs more room than the narrow table cell
     it sits in — without this, .ss-opt's ellipsis hides the very part that
     tells two similar materials apart */
  min-width:min(420px,92vw);max-width:92vw}
.ss-opt{padding:8px 10px;border-radius:6px;font-size:13px;line-height:1.3;cursor:pointer;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ss-opt:hover,.ss-opt.act{background:var(--panel-2);color:var(--accent)}
.ss-opt.sel{font-weight:700}
.ss-empty{padding:8px 10px;font-size:13px;color:var(--text-mut)}
.ss-input.is-locked{opacity:.65;pointer-events:none}
.seg{display:inline-flex;background:var(--panel-2);border:1px solid var(--line);border-radius:10px;padding:4px;gap:2px;box-shadow:var(--inset-top)}
.seg button{border:none;background:transparent;color:var(--text-mut);font-weight:700;font-size:13px;padding:6px 14px;
  border-radius:6px;cursor:pointer;transition:var(--tr)}
.seg button:hover{color:var(--text-dim)}
.seg button.on{background:var(--accent);color:#fff}

/* progress / meters */
.meter{height:8px;border-radius:14px;background:var(--panel-3);overflow:hidden;position:relative}
.meter span{display:block;height:100%;border-radius:14px;background:var(--accent);
  transition:width .6s cubic-bezier(.4,0,.2,1)}
.meter.ok span{background:var(--ok)}
.meter.warn span{background:var(--warn)}
.meter.danger span{background:var(--danger)}

/* layout helpers */
.cols-2{grid-template-columns:repeat(2,1fr)}
.cols-3{grid-template-columns:repeat(3,1fr)}
.cols-12{grid-template-columns:repeat(12,1fr)}
.span-4{grid-column:span 4}.span-5{grid-column:span 5}.span-6{grid-column:span 6}
.span-7{grid-column:span 7}.span-8{grid-column:span 8}.span-12{grid-column:span 12}
.muted{color:var(--text-mut)}.dim{color:var(--text-dim)}
.right{text-align:right}.center{text-align:center}
.flex{display:flex}.between{justify-content:space-between}.aic{align-items:center}.gap{gap:10px}.wrap{flex-wrap:wrap}
.mono{font-family:var(--mono)}
.empty{padding:50px 20px;text-align:center;color:var(--text-mut)}
.empty .big{font-size:42px;opacity:.4;margin-bottom:10px}

/* ranked bar list (Revenue by Product) — DOM-based so the full product
   name wraps and stays readable on every device; no canvas label clipping */
.rankbars{display:flex;flex-direction:column;gap:16px;margin-top:2px}
.rankbar-top{display:flex;align-items:baseline;gap:10px;margin-bottom:8px}
.rankbar-rank{flex:0 0 auto;min-width:22px;font-size:11px;font-weight:800;color:var(--text-mut);font-family:var(--mono)}
.rankbar-name{flex:1;min-width:0;font-size:13px;font-weight:600;line-height:1.3}
.rankbar-val{flex:0 0 auto;font-size:13px;font-weight:800;font-family:var(--mono);white-space:nowrap;color:var(--text)}
.rankbar-val .sh{margin-left:6px;font-weight:600;font-size:11px;color:var(--text-mut)}
.rankbar-track{height:8px;border-radius:14px;background:var(--panel-3);overflow:hidden}
.rankbar-fill{display:block;height:100%;width:0;border-radius:14px;
  background:var(--accent);
  transition:width .7s cubic-bezier(.4,0,.2,1)}

/* mini-bars & spark */
.barlist{display:flex;flex-direction:column;gap:12px}
.barlist .row{display:grid;grid-template-columns:130px 1fr 56px;align-items:center;gap:12px;font-size:13px}
.barlist .row .lab{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.barlist .row .val{text-align:right;font-family:var(--mono);font-weight:600;color:var(--text-dim)}

/* chart legend under the card title */
.chart-legend-row{display:flex;gap:8px;flex-wrap:wrap;margin:-6px 0 12px}

/* currency exchange (dashboard) — labelled From row, ⇅, To row, unit rate */
.fx-conv{display:flex;flex-direction:column;gap:4px;margin-bottom:12px}
.fx-conv-row{display:grid;grid-template-columns:minmax(0,1fr) 124px;gap:8px;align-items:end}
.fx-field{display:flex;flex-direction:column;gap:6px;min-width:0}
.fx-lbl{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.09em;
  color:var(--text-mut);padding-left:2px}
.fx-amt{font-family:var(--mono);font-weight:700;min-width:0}
.fx-out{display:flex;align-items:center;height:38px;padding:0 12px;border-radius:10px;
  border:1px solid var(--line);background:var(--panel-3);color:var(--text);
  font-family:var(--mono);font-weight:800;font-size:15px;
  min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.fx-sel{font-family:var(--mono);font-weight:700;padding:0 6px;min-width:0}
/* From/To are custom listboxes, not <select>: Windows draws native select
   popups through the OS, which has no colour-emoji support, so the flags
   never rendered there. Our own markup draws them like the rate list does. */
.fx-pick{position:relative;min-width:0}
/* the label is centred on the WHOLE button, so the caret is taken out of the
   flow — symmetric padding on .fx-pick-cur keeps long labels off the caret */
.fx-pick-btn{display:flex;align-items:center;justify-content:center;width:100%;cursor:pointer;
  position:relative;text-align:center;font-size:13px}
.fx-pick-btn[aria-expanded="true"]{border-color:var(--accent);box-shadow:var(--ring)}
.fx-pick-cur{min-width:0;padding:0 12px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.fx-pick-caret{position:absolute;right:7px;top:50%;transform:translateY(-50%);
  font-size:10px;color:var(--text-mut);pointer-events:none}
.fx-pick-pop{position:fixed;z-index:200;max-height:272px;overflow-y:auto;background:var(--panel);
  border:1px solid var(--line-strong);border-radius:10px;box-shadow:var(--shadow-pop);padding:6px;
  min-width:min(250px,92vw);max-width:92vw}
.fx-opt{display:grid;grid-template-columns:40px 34px 1fr;align-items:center;gap:10px;
  padding:8px 10px;border-radius:6px;cursor:pointer;font-size:13px;color:var(--text)}
.fx-opt:hover,.fx-opt.act{background:var(--panel-2);color:var(--accent)}
.fx-opt.sel{font-weight:700}
.fx-opt-sym{font-family:var(--mono);font-weight:700;font-size:12px;color:var(--text-dim);text-align:center}
/* the ⇅ sits on a hairline that visually joins the two rows */
.fx-swap-wrap{display:flex;align-items:center;gap:10px;margin:2px 0}
.fx-swap-wrap::before,.fx-swap-wrap::after{content:"";flex:1;border-top:1px solid var(--line)}
.fx-swap{width:30px;height:30px;flex:0 0 30px;border-radius:50%;font-size:13px;line-height:1}
.fx-rate{font-size:11px;font-family:var(--mono);color:var(--text-mut);text-align:center;
  margin-top:6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fx-divider{border-top:1px solid var(--line);margin-bottom:4px}
.fx-list{display:flex;flex-direction:column}
.fx-row{display:grid;grid-template-columns:auto 44px 1fr auto;align-items:center;gap:10px;
  padding:8px 0;border-bottom:1px solid var(--line);font-size:13px}
.fx-row:last-child{border-bottom:none}
/* national flag, drawn as inline SVG — Windows ships no flag emoji glyph */
.fx-flag{display:block;width:21px;height:14px;border-radius:2px;overflow:hidden;
  line-height:0;box-shadow:0 0 0 1px var(--line) inset,var(--shadow-1)}
.fx-flag-svg,.fx-flag svg{display:block;width:100%;height:100%}
/* fallback when we have no artwork for a country: its 2-letter code */
.fx-flag.txt{width:auto;height:auto;line-height:1;box-shadow:none;padding:4px 6px;
  border:1px solid var(--line);border-radius:4px;background:var(--panel-2);
  font-family:var(--mono);font-weight:800;font-size:10px;letter-spacing:.06em;color:var(--text-dim)}
.fx-code{font-family:var(--mono);font-weight:800;font-size:12px;color:var(--text-mut)}
.fx-name{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fx-val{text-align:right;font-family:var(--mono);font-weight:700;white-space:nowrap;color:var(--text)}
.fx-dir{margin-left:6px;font-size:10px;font-weight:800}
.fx-dir.up{color:var(--ok)}
.fx-dir.down{color:var(--danger)}
/* A row another screen navigated TO: hold it lit long enough
   to find, then fade out so the table reads normally again. */
@keyframes rowFlash{
  0%{background:var(--accent-soft);box-shadow:inset 3px 0 0 var(--accent)}
  70%{background:var(--accent-soft);box-shadow:inset 3px 0 0 var(--accent)}
  100%{background:transparent;box-shadow:inset 3px 0 0 transparent}
}
/* tables flash their cells (a <tr> takes no background of its own); anything
   card-shaped — phone rows, the CRM board's leads — flashes as one block */
tr.row-flash>td,.row-flash:not(tr){animation:rowFlash 2.6s ease-out 1}
.tbl-card-row.row-flash,.crm-lead.row-flash{border-radius:10px}
@media (prefers-reduced-motion:reduce){
  tr.row-flash>td,.row-flash:not(tr){animation:none;background:var(--accent-soft)}
}

.fx-dir.flat{color:var(--text-mut)}
/* Google could not be read for this pair — we show nothing rather than a
   number from another source (see backend/src/services/fxService.js) */
.fx-val.fx-na{color:var(--text-mut);font-weight:600}

/* donut legend */
.legend{display:flex;flex-direction:column;gap:10px}
.legend .li{display:flex;align-items:center;gap:10px;font-size:13px}
.legend .li .d{width:10px;height:10px;border-radius:4px;flex:0 0 10px}
.legend .li .v{margin-left:auto;font-family:var(--mono);font-weight:700;color:var(--text-dim)}

/* drawer */
.drawer{position:fixed;top:0;right:0;width:400px;max-width:92vw;height:100vh;height:100dvh;background:var(--panel);
  border-left:1px solid var(--line);box-shadow:var(--shadow-pop);z-index:200;display:flex;flex-direction:column;
  transform:translateX(100%);transition:transform .3s cubic-bezier(.4,0,.2,1)}
.drawer.open{transform:none}
.drawer-head{display:flex;align-items:center;justify-content:space-between;padding:18px;border-bottom:1px solid var(--line)}
.drawer-head h3{font-size:15px;font-weight:700}
.drawer-body{flex:1;overflow-y:auto;padding:14px}
/* day-by-day date header in the notifications drawer */
.alert-date{display:flex;align-items:center;gap:10px;position:sticky;top:-14px;z-index:1;
  padding:10px 2px 8px;margin:2px 0 6px;background:var(--panel)}
.alert-date-lbl{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:var(--text-dim);white-space:nowrap}
.alert-date-rule{flex:1;height:1px;background:var(--line)}
.alert-date-n{font-size:11px;font-weight:700;color:var(--text-mut);background:var(--panel-3);
  box-shadow:var(--inset-top);padding:2px 8px;border-radius:var(--radius-pill);white-space:nowrap}
.alert-item{display:flex;gap:12px;padding:14px;border-radius:10px;border:1px solid var(--line);margin-bottom:10px;
  transition:var(--tr);cursor:pointer;background:var(--panel-2)}
.alert-item:hover{border-color:var(--accent-line);transform:translateX(-3px)}
.alert-ic{width:36px;height:36px;border-radius:10px;display:grid;place-items:center;font-size:17px;flex:0 0 36px}
.alert-item .t{font-size:13px;font-weight:700}
.alert-item .d{font-size:12px;color:var(--text-mut);margin-top:2px}
.alert-item .ago{font-size:11px;color:var(--text-mut);margin-top:6px}

.scrim{position:fixed;inset:0;background:var(--scrim);backdrop-filter:blur(2px);z-index:150}

/* command palette */
.cmdk{position:fixed;inset:0;z-index:300;display:flex;justify-content:center;align-items:flex-start;
  padding-top:14vh;background:var(--scrim);backdrop-filter:blur(4px)}
.cmdk-box{width:min(640px,92vw);background:var(--panel);border:1px solid var(--line-strong);border-radius:14px;
  box-shadow:var(--shadow-pop),var(--inset-top);overflow:hidden;animation:pop .18s var(--spring)}
@keyframes pop{from{transform:scale(.96)translateY(-8px);opacity:0}to{transform:none;opacity:1}}
#cmdkInput{width:100%;height:56px;border:none;background:transparent;color:var(--text);font-size:17px;padding:0 20px;
  outline:none;border-bottom:1px solid var(--line);font-family:inherit}
.cmdk-results{max-height:50vh;overflow-y:auto;padding:8px}
.cmdk-row{display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:10px;cursor:pointer;font-size:13px}
.cmdk-row .ic{font-size:17px;width:22px;text-align:center}
.cmdk-row .meta{margin-left:auto;font-size:11px;color:var(--text-mut)}
.cmdk-row.sel,.cmdk-row:hover{background:var(--accent-soft)}
.cmdk-row .tag{font-size:10px;font-weight:700;color:var(--text-mut);text-transform:uppercase}
.cmdk-foot{display:flex;gap:14px;padding:10px 16px;border-top:1px solid var(--line);font-size:11px;color:var(--text-mut)}

/* modal */
.modal-host{position:fixed;inset:0;z-index:250;display:grid;place-items:center;padding:20px;
  background:var(--scrim);backdrop-filter:blur(6px)}
.modal{width:min(720px,96vw);max-height:90vh;overflow-y:auto;background:var(--panel);border:1px solid var(--line-strong);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-pop);animation:pop .2s var(--spring)}
.modal-head{display:flex;align-items:center;gap:12px;padding:16px 20px;border-bottom:1px solid var(--line);
  position:sticky;top:0;background:var(--panel);z-index:2}
.modal-head h3{font-size:var(--fs-xl);font-weight:800;letter-spacing:-.02em}
.modal-head .sub{font-size:12px;color:var(--text-mut)}
.modal-body{padding:20px}
.modal-foot{display:flex;gap:10px;justify-content:flex-end;padding:16px 20px;border-top:1px solid var(--line);
  position:sticky;bottom:0;background:var(--panel)}
.form-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}
.field{display:flex;flex-direction:column;gap:6px}
.field.full{grid-column:1/-1}
.field label{font-size:12px;font-weight:700;color:var(--text-dim)}
.field .hint{font-size:11px;color:var(--text-mut)}

/* toasts */
.toast-stack{position:fixed;bottom:22px;right:22px;z-index:400;display:flex;flex-direction:column;gap:10px}
.toast{display:flex;align-items:center;gap:12px;min-width:280px;max-width:380px;padding:12px 16px;border-radius:var(--radius);
  background:var(--panel);border:1px solid var(--line-strong);box-shadow:var(--shadow-pop);
  animation:slidein .3s var(--spring);border-left:4px solid var(--accent)}
.toast.ok{border-left-color:var(--ok)} .toast.warn{border-left-color:var(--warn)}
.toast.danger{border-left-color:var(--danger)} .toast.info{border-left-color:var(--info)}
.toast .ic{font-size:21px}
.toast .t{font-size:13px;font-weight:700}
.toast .d{font-size:12px;color:var(--text-mut)}
@keyframes slidein{from{transform:translateX(120%);opacity:0}to{transform:none;opacity:1}}
.toast.out{animation:slideout .3s ease forwards}
@keyframes slideout{to{transform:translateX(120%);opacity:0}}

/* timeline */
.timeline{position:relative;padding-left:24px}
.timeline::before{content:"";position:absolute;left:7px;top:4px;bottom:4px;width:2px;background:var(--line)}
.tl-item{position:relative;padding-bottom:18px}
.tl-item::before{content:"";position:absolute;left:-21px;top:3px;width:12px;height:12px;border-radius:50%;
  background:var(--accent);box-shadow:0 0 0 4px var(--accent-soft)}
.tl-item .tt{font-size:13px;font-weight:700}
.tl-item .td{font-size:12px;color:var(--text-mut)}

/* canvas charts fill */
.chart-box{position:relative;width:100%}
canvas{display:block;width:100%}
.chart-tooltip{position:absolute;pointer-events:none;background:var(--elev);border:1px solid var(--line-strong);
  border-radius:10px;padding:8px 12px;font-size:12px;box-shadow:var(--shadow-2);z-index:5;transition:opacity .12s;white-space:nowrap}
.chart-tooltip .tt-t{font-weight:700;margin-bottom:4px}
.chart-tooltip .tt-r{display:flex;align-items:center;gap:8px;color:var(--text-dim)}
.chart-tooltip .tt-r .d{width:8px;height:8px;border-radius:2px}
.chart-tooltip .tt-r b{margin-left:auto;color:var(--text);font-family:var(--mono)}

/* responsive */
@media(max-width:1100px){
  .app-shell{grid-template-columns:74px 1fr}
  .brand-logo-full{display:none}.brand-logo-mark{display:block;margin:0 auto}
  .nav-item{justify-content:center;padding:12px 0}.nav-item .lbl,.nav-item .pill{display:none}
  .nav-section{font-size:0;letter-spacing:0;padding:12px 0 8px}
  .nav-section::after{content:"";display:block;width:22px;height:2px;border-radius:2px;margin:0 auto;background:var(--sidebar-line)}
  .org-card>div:last-child{display:none}
  .span-4,.span-5,.span-6,.span-7,.span-8{grid-column:span 12}
  .cols-2,.cols-3{grid-template-columns:1fr}
}
/* medium screens: the icon rail stays; the ☰ toggle now slides open a
   full labelled drawer (over the content) instead of squeezing labels
   into the 74px rail where they overlapped the icons. */
@media(max-width:1100px) and (min-width:821px){
  .sidebar{transition:width .2s ease, box-shadow .2s ease}
  .app-shell.collapsed .sidebar{position:fixed;top:0;left:0;bottom:0;width:250px;z-index:95;
    background:var(--sidebar);border-right:1px solid var(--sidebar-line);box-shadow:26px 0 70px rgba(0,0,0,.5)}
  .app-shell.collapsed .sidebar-brand{display:flex}
  .app-shell.collapsed .brand-logo-full{display:block}
  .app-shell.collapsed .brand-logo-mark{display:none}
  .app-shell.collapsed .nav-section{display:block;text-align:left;font-size:10px;letter-spacing:.18em;padding:14px 12px 6px}
  .app-shell.collapsed .nav-section::after{display:none}
  .app-shell.collapsed .nav-item{justify-content:flex-start;padding:10px 12px;gap:12px}
  .app-shell.collapsed .nav-item .lbl{display:block}
  .app-shell.collapsed .nav-item .pill{display:inline-flex;position:static;margin-left:auto}
  .app-shell.collapsed .sidebar-foot{display:block}
  .app-shell.collapsed .org-card{justify-content:flex-start}
  .app-shell.collapsed .org-card>div:last-child{display:block}
  .nav-scrim.show{display:block}
}
/* backdrop behind the tablet drawer (only ever visible in the drawer range) */
.nav-scrim{position:fixed;inset:0;background:var(--scrim);backdrop-filter:blur(2px);z-index:94;display:none}
@media(max-width:680px){
  .search-trigger span:not(.si){display:none}.search-trigger{min-width:0}
  .user-meta{display:none}.view{padding:16px}
  .form-grid{grid-template-columns:repeat(auto-fit,minmax(146px,1fr))}
}
@media(max-width:820px){
  .app-shell,.app-shell.collapsed{grid-template-columns:1fr;height:100dvh}
  .main{width:100vw;min-width:0}

  .sidebar{position:fixed;left:0;right:0;bottom:0;height:calc(70px + env(safe-area-inset-bottom));
    min-height:0;z-index:90;border-right:none;border-top:1px solid var(--sidebar-line);
    padding:0 8px env(safe-area-inset-bottom);box-shadow:0 -14px 34px rgba(0,0,0,.28)}
  .sidebar-brand,.sidebar-foot,.nav-section{display:none}
  .nav{height:70px;min-width:0;overflow-x:auto;overflow-y:hidden;padding:8px 2px;flex-direction:row;gap:6px;scroll-snap-type:x proximity}
  .nav::-webkit-scrollbar{display:none}
  .nav{scrollbar-width:none}
  .nav-item,.collapsed .nav-item{flex:0 0 72px;height:54px;flex-direction:column;justify-content:center;gap:4px;
    padding:6px 8px;border-radius:10px;font-size:11px;text-align:center;scroll-snap-align:start}
  .nav-item .ic,.collapsed .nav-item .ic{width:auto;flex:0 0 auto;font-size:17px;line-height:1}
  .nav-item .lbl,.collapsed .nav-item .lbl{display:block;max-width:64px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .nav-item .pill,.collapsed .nav-item .pill{display:grid;position:absolute;top:3px;right:6px;min-width:17px;height:17px;padding:0 6px;place-items:center}
  .nav-item.active{background:var(--accent-soft)}
  .nav-item.active::before{left:14px;right:14px;top:auto;bottom:-8px;width:auto;height:3px;border-radius:4px 4px 0 0}

  .topbar{height:56px;padding:0 10px;gap:8px}
  .menu-toggle{display:none}
  .topbar-spacer{display:none}
  .crumbs{flex:1;min-width:0;gap:0;font-size:13px}
  .crumbs .brandcrumb,.crumbs .sep{display:none}
  .crumb-back{max-width:110px}
  .crumb-back-t{display:none}
  .crumb-back{padding:4px 8px}
  .crumbs .cur{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .search-trigger{width:38px;min-width:38px;padding:0;justify-content:center}
  .search-trigger span:not(.si),.search-trigger kbd{display:none}
  .accent-pop{display:none}
  .user-chip{padding:0;gap:6px}
  .user-meta{display:none}
  .avatar{width:34px;height:34px;border-radius:10px;font-size:12px}
  #logoutBtn{width:34px;height:34px;border-radius:10px;margin-left:0!important}
  .icon-btn{width:38px;height:38px;border-radius:10px}

  .view{padding:12px 12px calc(88px + env(safe-area-inset-bottom));min-width:0}
  .page-head{align-items:flex-start;margin-bottom:12px;gap:10px}
  .page-title{font-size:21px;line-height:1.2;min-width:0}
  .page-title .dot{width:9px;height:9px;flex:0 0 9px}
  .page-sub{font-size:12px;line-height:1.4;margin-top:4px}
  .page-head .actions{width:100%;margin-left:0;gap:8px}
  /* 104px, not 140px, so three short actions share one row instead of one of
     them being pushed onto a line of its own */
  .page-head .actions .btn{flex:1 1 104px;justify-content:center}

  .grid{gap:10px}
  .card{padding:12px;border-radius:10px}
  .card-head{margin-bottom:10px}
  /* TWO KPI tiles a row. One per row pushed the actual content of every
     section most of a screen down before anything could be read — four
     tiles cost ~560px of mostly empty tile. */
  .kpi-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
  .kpi{padding:12px 12px;border-radius:10px}
  .kpi::before{width:2px}
  .kpi:hover::before{width:3px}
  .kpi-ic{width:28px;height:28px;border-radius:10px;font-size:15px}
  .kpi-val{font-size:21px;margin-top:8px;letter-spacing:-.03em}
  .kpi-label{font-size:10px;letter-spacing:.03em;line-height:1.25;margin-top:2px}
  .kpi-delta{font-size:10px;margin-top:6px;padding:2px 8px}
  .cols-2,.cols-3,.cols-12{grid-template-columns:1fr}
  .span-4,.span-5,.span-6,.span-7,.span-8,.span-12{grid-column:1/-1}

  .toolbar{align-items:stretch;gap:8px;margin-bottom:10px}
  /* the search box owns its row; the filter selects pair up two to a row and
     a lone one still grows to fill, so "All Categories" + "All Status" cost
     one row instead of two */
  .toolbar>.input,.toolbar>.search{flex:1 1 100%;width:100%;min-width:0}
  .toolbar>.select{flex:1 1 44%;width:auto;min-width:0}
  .toolbar>div[style*="margin-left:auto"]{margin-left:0!important;width:100%;display:flex;justify-content:flex-end}
  /* The label used to own a whole row, then the preset another, then the two
     dates, then Clear — four rows to pick a date range. Label and preset now
     share the first row, so it is three. */
  .date-range{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px 8px;width:100%;align-items:center}
  .date-label{grid-column:1;grid-row:1;white-space:nowrap}
  .date-range>.select{grid-column:2;grid-row:1;width:100%}
  .date-input{min-width:0;width:100%}
  .range-sep{display:none}
  .date-range>.btn{grid-column:1/-1;justify-content:center}
  .seg{max-width:100%;overflow-x:auto;white-space:nowrap}
  .seg button{flex:0 0 auto}

  .table-wrap{max-width:100%;border-radius:10px;-webkit-overflow-scrolling:touch}
  table.tbl{min-width:720px;font-size:13px}
  .tbl thead th{padding:12px 12px}
  .tbl tbody td{padding:10px 12px}

  .barlist .row{grid-template-columns:minmax(92px,1fr) 1.4fr auto;gap:8px}
  .crm-hero{grid-template-columns:1fr;gap:14px}
  .crm-gauge{order:-1}
  .crm-funnel{overflow-x:auto;padding-bottom:4px}
  .crm-fseg{min-width:132px}

  .drawer{width:100vw;max-width:100vw;height:100dvh}
  .cmdk{padding:8px;align-items:flex-start}
  .cmdk-box{width:100%;border-radius:14px}
  .cmdk-foot{display:none}
  .modal-host{padding:8px;place-items:end center}
  .modal{width:100%;max-height:calc(100dvh - 16px);border-radius:16px 16px 0 0}
  .modal-head{padding:12px 14px}
  .modal-body{padding:14px}
  .modal-foot{padding:12px 14px;flex-wrap:wrap;gap:8px}
  .modal-foot .btn{flex:1 1 104px;justify-content:center}
  /* Short fields sit two-up rather than one per row — the same intent the
     desktop form already has, which the phone layout was throwing away. A
     .field.full still spans, and auto-fit drops to one column on a narrow
     phone where two would be too tight to type in. */
  .form-grid{grid-template-columns:repeat(auto-fit,minmax(146px,1fr));gap:12px}
  /* paired fields: when one label wraps to two lines and its neighbour does
     not, let the label take up the slack so both controls still line up */
  .form-grid .field > label{flex:1 0 auto}

  .toast-stack{left:10px;right:10px;bottom:calc(84px + env(safe-area-inset-bottom))}
  .toast{min-width:0;max-width:none;width:100%}

  .login-screen{padding:14px}
  .login-card{width:100%;padding:26px 22px;border-radius:14px}

  .sup-tabs{flex-wrap:nowrap;overflow-x:auto;padding-bottom:2px}
  .sup-card-head{flex-direction:column;align-items:flex-start}
  .sup-status{white-space:normal}
  .sup-actions{flex-direction:column}
  .sup-act{width:100%;min-width:0}
}
@media(max-width:420px){
  .topbar{padding:0 8px;gap:6px}
  .icon-btn,.search-trigger{width:36px;height:36px;min-width:36px}
  .avatar{width:32px;height:32px}
  #logoutBtn{width:32px;height:32px}
  .nav-item,.collapsed .nav-item{flex-basis:66px}
  .view{padding-left:12px;padding-right:12px}
}

/* ---------- PHONE: data tables become stacked cards ----------
   On narrow screens a wide table is unreadable behind a horizontal
   scrollbar. Here every row turns into a self-contained card and each
   cell shows its column name (from td[data-label], set in ui.js table())
   beside its value — so a whole record reads top-to-bottom, no sideways
   scrolling. Kept ≤640px so tablets keep the real table. */
@media(max-width:640px){
  .table-wrap{overflow-x:visible;border:none;background:transparent;box-shadow:none}
  table.tbl,.tbl tbody,.tbl tbody tr,.tbl tbody td{display:block;width:auto}
  table.tbl{min-width:0;font-size:13px}
  .tbl thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .tbl tbody tr{background:var(--panel);border:1px solid var(--line);border-radius:14px;
    box-shadow:var(--shadow-1),var(--inset-top);padding:6px 2px 6px;margin-bottom:10px;overflow:hidden}
  .tbl tbody tr:nth-child(even){background:var(--panel)}
  .tbl tbody tr:hover{background:var(--panel);box-shadow:var(--shadow-1),var(--inset-top)}
  .tbl tbody tr:last-child td{border-bottom:none}
  .tbl tbody td{border:none;padding:8px 12px;display:flex;align-items:center;
    justify-content:space-between;gap:14px;text-align:right;min-height:0}
  .tbl tbody td.num{text-align:right}
  .tbl tbody td::before{content:attr(data-label);flex:0 0 auto;text-align:left;
    font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;
    color:var(--text-mut);white-space:nowrap}
  .tbl tbody td[data-label=""]::before{content:none}
  /* first cell = card header: full width, no label prefix, emphasised */
  .tbl tbody td:first-child{background:var(--panel-2);border-radius:10px;margin:0 6px 8px;
    padding:12px 14px;text-align:left;display:block}
  .tbl tbody td:first-child::before{content:none}
  .tbl tbody td:first-child .cell-main{font-size:15px}
  /* empty-state row keeps its centered look, not the label:value grid */
  .tbl tbody td[colspan]{display:block;padding:0}
  .tbl tbody td[colspan]::before{content:none}
}

/* ---------- ABC classification: compact list on phones ----------
   The full 5-column table is fine on laptops/tablets but becomes a
   very long stack of cards on a phone. There we swap it for a tight
   Class + name list; tapping a row opens the full details in a modal. */
.abc-mobile{display:none}
@media(max-width:640px){
  .abc-full{display:none}
  .abc-mobile{display:block}
  .abc-mobile.empty{padding:40px 20px;text-align:center;color:var(--text-mut)}
  .abc-row{display:flex;align-items:center;gap:12px;width:100%;text-align:left;
    padding:12px 12px;border:none;border-bottom:1px solid var(--line);background:none;
    color:var(--text);font:inherit;cursor:pointer;transition:var(--tr)}
  .abc-row:last-child{border-bottom:none}
  .abc-row:active{background:var(--panel-2)}
  .abc-cls{flex:0 0 30px;width:30px;height:30px;border-radius:10px;display:grid;place-items:center;
    font-size:13px;font-weight:800}
  .abc-cls.abc-A{background:var(--danger-soft);color:var(--danger)}
  .abc-cls.abc-B{background:var(--warn-soft);color:var(--warn)}
  .abc-cls.abc-C{background:var(--ok-soft);color:var(--ok)}
  .abc-nm{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
  .abc-nm .cell-main{font-weight:700;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .abc-nm .cell-sub{font-size:11px;color:var(--text-mut)}
  .abc-chev{flex:0 0 auto;color:var(--text-mut);font-size:21px;line-height:1;font-weight:700}
}

/* ---------- PHONE: compact tap-to-open cards for data tables ----------
   Generalises the ABC pattern to EVERY section except Operations. On
   phones each row shows its key parameters (name/id + identity line + the
   most telling value & status), and tapping opens the record's own detail
   view (opts.onRow) or a generated field list. Applied via ui.js table()
   (adds .tbl-compact + a .tbl-cards sibling). Laptops/tablets and the
   Operations section are untouched. */
.tbl-cards{display:none}
.tbl-card-dl{display:flex;flex-direction:column}
.tbl-card-dl .tcd-row{display:flex;align-items:baseline;justify-content:space-between;gap:16px;
  padding:10px 2px;border-bottom:1px solid var(--line)}
.tbl-card-dl .tcd-row:last-child{border-bottom:none}
.tbl-card-dl .tcd-row.nolabel{justify-content:flex-start}
.tbl-card-dl .tcd-k{flex:0 0 auto;font-size:11px;font-weight:800;text-transform:uppercase;
  letter-spacing:.04em;color:var(--text-mut)}
.tbl-card-dl .tcd-v{flex:1;min-width:0;text-align:right;font-size:13px;font-weight:600;overflow-wrap:anywhere}
/* the value may embed the list's nowrap primary line — let it wrap here so
   a long name can't force the modal wider than the phone viewport */
.tbl-card-dl .tcd-v .cell-main,.tbl-card-dl .tcd-v .cell-sub{white-space:normal}
.tbl-card-dl .tcd-row.nolabel .tcd-v{text-align:left}
@media(max-width:640px){
  .table-wrap.tbl-compact{overflow-x:visible;border:none;background:transparent;box-shadow:none;padding:0}
  .table-wrap.tbl-compact > table.tbl{display:none}
  .tbl-cards{display:block;background:var(--panel);border:1px solid var(--line);border-radius:14px;
    box-shadow:var(--shadow-1),var(--inset-top);overflow:hidden}
  .tbl-cards-empty{padding:40px 20px;text-align:center;color:var(--text-mut)}
  .tbl-card-row{display:flex;align-items:center;gap:10px;width:100%;text-align:left;
    padding:10px 12px;border:none;border-bottom:1px solid var(--line);background:none;
    color:var(--text);font:inherit;cursor:pointer;transition:var(--tr)}
  .tbl-card-row:last-child{border-bottom:none}
  .tbl-card-row:active{background:var(--panel-2)}
  .tbl-card-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
  /* phone cards show the FULL name — wrap it instead of cutting it off */
  .tbl-card-head{font-weight:700;font-size:15px;white-space:normal;overflow-wrap:anywhere;line-height:1.3}
  .tbl-card-head .cell-main{font-weight:700;font-size:15px;white-space:normal;overflow-wrap:anywhere;line-height:1.3}
  /* The identity lines under the name (code · category · HSN) each had a row
     to themselves, so one stock item cost five lines. They run together on
     one wrapped line with a separator instead. */
  .tbl-card-head .cell-sub{display:inline;font-size:11px;color:var(--text-mut);
    white-space:normal;overflow-wrap:anywhere;margin-top:0}
  .tbl-card-head .cell-sub + .cell-sub::before{content:"·";margin:0 6px;opacity:.55}
  .tbl-card-sub{font-size:12px;color:var(--text-mut);white-space:normal;overflow-wrap:anywhere}
  .tbl-card-params{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;margin-top:1px}
  .tcp{display:inline-flex;align-items:center;gap:6px;font-size:13px;min-width:0}
  .tcp-k{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:var(--text-mut)}
  .tcp-v{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .tbl-card-chev{flex:0 0 auto;color:var(--text-mut);font-size:21px;line-height:1;font-weight:700}
}
.fade-in{animation:fadein .35s ease}
@keyframes fadein{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* ---------- PHONE: attendance muster becomes per-worker cards ----------
   The month matrix (31 day-columns) is unreadable on a phone — either a
   cramped sticky-column scroller or, worse, mangled into a vertical block
   stack by the generic .tbl card rule. On ≤640px we hide the matrix and
   show one card per worker: full-width name + P/OT summary, and the whole
   month as a single horizontally-scrolling strip of tappable day cells.
   Uses full phone width (no 150px sticky column) and scopes horizontal
   scrolling to each worker instead of one giant grid. Desktop untouched. */
.muster-mobile{display:none}
@media(max-width:640px){
  .muster-full{display:none}
  .muster-mobile{display:block}
  .mcard{background:var(--panel);border:1px solid var(--line);border-radius:14px;
    box-shadow:var(--shadow-1),var(--inset-top);padding:10px 0 4px;margin-bottom:12px;overflow:hidden}
  .mcard-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:0 14px 8px}
  .mcard-name{font-weight:700;font-size:15px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .mcard-stats{flex:0 0 auto;display:flex;gap:6px}
  .mstrip{display:flex;gap:6px;overflow-x:auto;padding:2px 14px 10px;
    scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch}
  .mstrip::-webkit-scrollbar{height:5px}
  .mstrip::-webkit-scrollbar-thumb{background:var(--line);border-radius:4px}
  .mcell{flex:0 0 auto;scroll-snap-align:start;display:flex;flex-direction:column;align-items:center;gap:4px;
    width:38px;padding:6px 0 8px;border:1px solid var(--line);border-radius:10px;background:var(--panel-2);
    color:var(--text);font:inherit;cursor:pointer;transition:var(--tr)}
  .mcell:active{background:var(--panel-3)}
  .mcell.sun{background:var(--danger-soft)}
  .mcell-wd{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.03em;color:var(--text-mut)}
  .mcell-d{font-size:12px;font-weight:700;line-height:1}
  .mcell .badge-s{padding:2px 0;min-width:22px;justify-content:center;font-size:11px}
  .mcell-e{font-size:13px;color:var(--text-mut);line-height:1;height:18px;display:flex;align-items:center}
}

/* ============================================================
   CRM PIPELINE — funnel command panel + kanban board
   The pipeline funnel is the signature: each open stage is a
   segment sized by its weighted value, so you see where the
   money sits and how it narrows toward Won at a glance.
   ============================================================ */
/* ---- dashboard grid ---- */
.crm-grid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:14px;margin-bottom:16px}
.crm-s3{grid-column:span 3}.crm-s4{grid-column:span 4}
.crm-s5{grid-column:span 5}.crm-s7{grid-column:span 7}
.crm-s8{grid-column:span 8}.crm-s12{grid-column:1/-1}
@media(max-width:1180px){.crm-s3{grid-column:span 6}.crm-s4,.crm-s5,.crm-s7,.crm-s8{grid-column:1/-1}}
@media(max-width:640px){.crm-s3{grid-column:1/-1}}
.crm-eyebrow{font-size:11px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--text-mut)}

/* ---- KPI card with micro-visual ---- */
.crm-kpi{padding:16px 16px 14px;display:flex;flex-direction:column;gap:2px;min-height:132px}
.crm-kpi-top{display:flex;align-items:center;gap:8px;color:var(--text-mut)}
.crm-kpi-ic{width:24px;height:24px;border-radius:6px;display:grid;place-items:center;font-size:12px;
  background:var(--panel-3);flex:0 0 auto}
.crm-kpi-lab{font-size:12px;font-weight:700;letter-spacing:.01em}
.crm-kpi-val{font-size:26px;font-weight:800;letter-spacing:-.025em;line-height:1.15;margin-top:10px;font-family:var(--mono)}
.crm-kpi-foot{margin-top:auto;padding-top:10px;display:flex;align-items:center;gap:8px;font-size:11px;color:var(--text-mut);font-weight:600}
.crm-delta{display:inline-flex;align-items:center;gap:4px;font-size:11px;font-weight:800;padding:2px 8px;border-radius:14px;white-space:nowrap}
.crm-delta.up{background:var(--ok-soft);color:var(--ok)}
.crm-delta.down{background:var(--danger-soft);color:var(--danger)}
.crm-delta.flat{background:var(--panel-3);color:var(--text-mut)}
.crm-kpi-vis{height:38px;margin:8px -4px -2px;position:relative}
.crm-kpi-vis canvas{width:100%;display:block}
/* stacked mini stage bars inside a KPI */
.crm-mini{display:flex;flex-direction:column;gap:6px;margin-top:10px}
.crm-mini-row{display:flex;align-items:center;gap:8px;font-size:11px;font-weight:700;color:var(--text-mut)}
.crm-mini-lab{flex:0 0 62px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.crm-mini-track{flex:1;height:5px;border-radius:4px;background:var(--panel-3);overflow:hidden}
.crm-mini-track>span{display:block;height:100%;border-radius:4px}
.crm-mini-n{flex:0 0 auto;font-family:var(--mono);color:var(--text-dim)}

/* ---- the funnel ribbon (signature) ---- */
.crm-fcard{display:flex;flex-direction:column}
.crm-fcard .crm-funnel{flex:1}
.crm-funnel{display:flex;align-items:stretch;gap:8px;min-height:104px}
.crm-fseg{--sc:var(--accent);flex:1 1 0;min-width:104px;border:1px solid var(--line);border-top:3px solid var(--sc);
  border-radius:10px;padding:10px 14px 12px;background:color-mix(in srgb,var(--sc) 7%,var(--panel));
  display:flex;flex-direction:column;gap:2px;cursor:pointer;transition:var(--tr)}
.crm-fseg:hover{background:color-mix(in srgb,var(--sc) 14%,var(--panel));transform:translateY(-1px)}
.crm-fseg-stage{font-size:12px;font-weight:800;display:flex;align-items:center;gap:6px}
.crm-fseg-val{font-size:17px;font-weight:800;font-family:var(--mono);letter-spacing:-.01em;margin-top:1px}
.crm-fseg-count{font-size:11px;color:var(--text-mut);font-weight:600}
.crm-fseg-age{font-size:11px;color:var(--text-mut);font-weight:600;margin-top:10px;padding-top:8px;
  border-top:1px dashed var(--line)}
.crm-fbar{height:4px;border-radius:4px;background:var(--sc);margin-top:auto;opacity:.9}
.crm-fchev{align-self:center;color:var(--text-mut);font-size:17px;font-weight:800;flex:0 0 auto}
.crm-fout{--sc:var(--ok);flex:0 0 auto;min-width:104px;border:1px solid color-mix(in srgb,var(--sc) 32%,var(--line));
  border-radius:10px;padding:10px 14px;background:color-mix(in srgb,var(--sc) 9%,var(--panel));
  display:flex;flex-direction:column;gap:2px;justify-content:center}

/* ---- source split (donut + legend) ---- */
.crm-split{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.crm-split .chart-box{flex:0 0 168px;width:168px}
.crm-legend{flex:1;min-width:170px;display:flex;flex-direction:column;gap:1px}
.crm-leg-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line);font-size:12px}
.crm-leg-row:last-child{border-bottom:none}
.crm-leg-row .d{width:8px;height:8px;border-radius:50%;flex:0 0 auto}
.crm-leg-nm{flex:1;min-width:0;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.crm-leg-v{font-family:var(--mono);font-weight:800;font-size:12px}
.crm-leg-n{font-size:11px;color:var(--text-mut);font-weight:600;flex:0 0 auto}

/* ---- activity feed ---- */
.crm-feed{display:flex;flex-direction:column}
.crm-feed-row{display:flex;align-items:flex-start;gap:12px;padding:10px 0;border-bottom:1px solid var(--line);
  cursor:pointer;transition:var(--tr)}
.crm-feed-row:last-child{border-bottom:none}
.crm-feed-row:hover{background:var(--panel-2);border-radius:10px;padding-left:8px;padding-right:8px;margin:0 -8px}
.crm-feed-ic{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;font-size:13px;flex:0 0 auto;
  background:var(--accent-soft)}
.crm-feed-tx{flex:1;min-width:0}
.crm-feed-t{font-size:13px;font-weight:700;line-height:1.35}
.crm-feed-d{font-size:12px;color:var(--text-mut);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.crm-feed-when{font-size:11px;color:var(--text-mut);font-weight:600;flex:0 0 auto;white-space:nowrap;padding-top:2px}

/* ---- PRIORITY BLOCK: today's follow-ups (leads the page) ---- */
.crm-fu{--sc:var(--warn);margin-bottom:16px;padding:0;overflow:hidden;
  border:1px solid color-mix(in srgb,var(--sc) 40%,var(--line))}
.crm-fu.calm{--sc:var(--ok)}
.crm-fu-head{display:flex;align-items:center;gap:14px;padding:14px 18px;
  background:color-mix(in srgb,var(--sc) 11%,var(--panel));
  border-bottom:1px solid color-mix(in srgb,var(--sc) 26%,var(--line))}
.crm-fu-ic{width:36px;height:36px;border-radius:10px;display:grid;place-items:center;font-size:17px;flex:0 0 auto;
  background:color-mix(in srgb,var(--sc) 22%,var(--panel))}
.crm-fu-title{font-size:15px;font-weight:800;letter-spacing:-.015em}
.crm-fu-sub{font-size:12px;color:var(--text-mut);margin-top:2px;font-weight:600}
.crm-fu-tally{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap}
.crm-fu-rows{display:flex;flex-direction:column}
.crm-fu-row{display:flex;align-items:center;gap:14px;padding:12px 18px;border-bottom:1px solid var(--line);
  cursor:pointer;transition:var(--tr);text-align:left;width:100%;background:none;border-left:none;
  border-right:none;border-top:none;color:var(--text);font:inherit}
.crm-fu-row:last-child{border-bottom:none}
.crm-fu-row:hover{background:var(--panel-2)}
.crm-fu-dot{width:8px;height:8px;border-radius:50%;flex:0 0 auto;background:var(--warn)}
.crm-fu-dot.over{background:var(--danger)}
.crm-fu-co{font-weight:700;font-size:13px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.crm-fu-meta{font-size:12px;color:var(--text-mut);font-weight:600;flex:0 0 auto}
.crm-fu-val{font-family:var(--mono);font-weight:800;font-size:13px;flex:0 0 auto}
.crm-fu-when{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  padding:4px 10px;border-radius:14px;flex:0 0 auto;white-space:nowrap}
.crm-fu-when.over{background:var(--danger-soft);color:var(--danger)}
.crm-fu-when.today{background:var(--warn-soft);color:var(--warn)}
.crm-fu-empty{display:flex;align-items:center;gap:14px;padding:16px 18px}
@media(max-width:640px){.crm-fu-meta,.crm-fu-val{display:none}}

/* clickable drill-down affordance */
.crm-click{cursor:pointer}
.crm-click:hover{border-color:var(--accent-line);transform:translateY(-2px);box-shadow:var(--shadow-2)}
.crm-kpi-more{font-size:15px;color:var(--text-mut);margin-left:auto;line-height:1;transition:var(--tr)}
.crm-click:hover .crm-kpi-more{color:var(--accent);transform:translateX(2px)}
.crm-col-head.crm-click:hover{background:var(--panel-3)}
.crm-col-head.crm-click:hover{transform:none;box-shadow:none}

/* drill-down popup bits */
.crm-drill-row{display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px solid var(--line);cursor:pointer}
.crm-drill-row:last-child{border-bottom:none}
.crm-drill-row:hover{background:var(--panel-2);border-radius:10px;padding-left:8px;padding-right:8px;margin:0 -8px}
.crm-drill-co{flex:1;min-width:0;font-weight:700;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.crm-drill-sub{font-size:11px;color:var(--text-mut);margin-top:2px;font-weight:600}
.crm-none{color:var(--text-mut);font-size:12px;text-align:center;padding:26px 0;opacity:.75}

/* ============================================================
   IN-APP DOCUMENT VIEWER (the TDS booklet)
   A PDF read inside the working area, menu still on the left.
   The frame takes the height the page head leaves behind, so the
   booklet gets the whole panel instead of a letterbox.
   ============================================================ */
.doc-shell{background:var(--panel-2);border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;box-shadow:var(--shadow-1);height:calc(100vh - 210px);min-height:420px}
.doc-frame{display:block;width:100%;height:100%;border:0;background:#fff}
@media(max-width:820px){ .doc-shell{height:calc(100vh - 240px);min-height:340px} }

/* ---- pipeline board: a card carousel ----------------------------------
   One stage per slide. The centred slide is brought forward and its
   neighbours sit back, so the eye lands on the stage being worked instead
   of five equal columns competing. The rail is a real scroller with
   scroll-snap, so a touch swipe and a trackpad gesture work natively; the
   arrows, dots and arrow keys just scroll it to the next snap point. */
.crm-car{display:flex;align-items:center;gap:6px}
/* position:relative makes the view the slides' offsetParent, so their
   offsetLeft is measured against the scroller itself — that is what the
   centring maths uses, and offsetLeft (unlike a client rect) ignores the
   scale transform on the inactive slides */
.crm-car-view{position:relative;flex:1;min-width:0;overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;scrollbar-width:none;padding:16px 0 12px;outline:none}
.crm-car-view::-webkit-scrollbar{display:none}
.crm-car-view:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:var(--radius)}
.crm-car-rail{display:flex;align-items:stretch;gap:14px;width:max-content}
.crm-car-pad{flex:0 0 0;pointer-events:none}

.crm-car-slide{--sc:var(--accent);flex:0 0 clamp(230px,25vw,290px);scroll-snap-align:center;
  background:var(--panel-2);border:1px solid var(--line);border-radius:var(--radius);
  display:flex;flex-direction:column;padding:12px 12px 10px;
  transform:scale(.9);opacity:.5;transform-origin:center;
  transition:transform .38s cubic-bezier(.22,.61,.36,1),opacity .38s ease,
    box-shadow .38s ease,border-color .38s ease,background .38s ease}
.crm-car-slide.is-near{transform:scale(.94);opacity:.72}
.crm-car-slide.is-active{transform:scale(1);opacity:1;background:var(--panel);
  border-color:color-mix(in srgb,var(--sc) 40%,var(--line));box-shadow:var(--shadow-2)}
/* the active stage is the only one that gets its accent underline */
.crm-car-head{display:flex;align-items:baseline;justify-content:center;gap:6px;
  padding:4px 6px 8px;border-radius:var(--radius-sm);position:relative;text-align:center;flex-wrap:wrap}
.crm-car-head::after{content:"";position:absolute;left:50%;right:50%;bottom:2px;height:2px;border-radius:2px;
  background:var(--sc);opacity:0;transition:left .38s ease,right .38s ease,opacity .38s ease}
.crm-car-slide.is-active .crm-car-head::after{left:22%;right:22%;opacity:.9}
.crm-car-ic{font-size:12px;line-height:1}
.crm-car-stage{font-weight:800;font-size:15px;color:var(--sc);letter-spacing:.2px}
.crm-car-n{font-size:12px;font-weight:700;color:var(--text-mut)}
.crm-car-val{text-align:center;font-size:12px;font-weight:800;font-family:var(--mono);
  color:var(--text-mut);margin:-2px 0 10px}
/* a stage with more leads than fit scrolls; the last card fades out rather
   than being sliced off, which also says "there is more below" */
.crm-car-body{display:flex;flex-direction:column;gap:10px;overflow-y:auto;max-height:46vh;
  padding:1px;scrollbar-width:thin;
  -webkit-mask-image:linear-gradient(#000 calc(100% - 26px),transparent);
  mask-image:linear-gradient(#000 calc(100% - 26px),transparent)}
/* nothing to scroll → no fade */
.crm-car-body:not(.is-scrollable){-webkit-mask-image:none;mask-image:none}
.crm-empty{color:var(--text-mut);font-size:12px;text-align:center;padding:22px 0;opacity:.7}

/* round prev/next, sitting outside the rail like the reference */
.crm-car-nav{flex:0 0 auto;width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  background:var(--panel);border:1px solid var(--line);color:var(--text-dim);
  font-size:21px;line-height:1;padding-bottom:4px;cursor:pointer;transition:var(--tr);box-shadow:var(--shadow-1)}
.crm-car-nav:hover:not(:disabled){background:var(--panel-3);color:var(--accent);
  border-color:var(--accent-line);transform:scale(1.08);box-shadow:var(--shadow-2)}
.crm-car-nav:active:not(:disabled){transform:scale(.96)}
.crm-car-nav:disabled{opacity:.3;cursor:default}

/* dot strip under the rail */
.crm-car-dots{display:flex;justify-content:center;align-items:center;gap:8px;
  margin:2px auto 4px;padding:6px 14px;width:max-content;
  background:var(--panel-2);border:1px solid var(--line);border-radius:14px}
.crm-car-dot{width:7px;height:7px;border-radius:50%;border:none;padding:0;cursor:pointer;
  background:var(--line-strong);transition:width .3s ease,background .3s ease}
.crm-car-dot:hover{background:var(--text-mut)}
.crm-car-dot.on{width:20px;border-radius:14px;background:var(--accent)}

@media(max-width:640px){
  .crm-car-slide{flex-basis:min(78vw,290px)}
  .crm-car-body{max-height:52vh}
  .crm-car-nav{width:30px;height:30px;font-size:17px}
}
@media(prefers-reduced-motion:reduce){
  .crm-car-slide,.crm-car-head::after,.crm-car-dot,.crm-car-nav{transition:none}
  .crm-car-view{scroll-behavior:auto}
}

/* ---- lead card (inside a carousel slide) ---- */
.crm-lead{--sc:var(--accent);background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:12px 12px 10px;cursor:pointer;transition:var(--tr);box-shadow:var(--shadow-1)}
.crm-car-slide.is-active .crm-lead{background:var(--panel-2)}
.crm-lead:hover{transform:translateY(-2px);box-shadow:var(--shadow-2);
  border-color:color-mix(in srgb,var(--sc) 42%,var(--line))}
.crm-lead-top{display:flex;align-items:center;gap:10px}
/* round, ringed initial — the reference's signature mark */
.crm-lead-ava{flex:0 0 auto;width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  font-weight:800;font-size:15px;background:color-mix(in srgb,var(--sc) 14%,var(--panel));
  color:var(--sc);box-shadow:0 0 0 2px color-mix(in srgb,var(--sc) 45%,transparent)}
.crm-lead-id{flex:1;min-width:0}
.crm-lead-co{font-weight:700;font-size:13px;line-height:1.25;overflow-wrap:anywhere}
.crm-lead-val{font-size:13px;font-weight:800;font-family:var(--mono);margin-top:2px}
.crm-lead-prod{margin-top:10px;font-size:11px;font-weight:600;color:var(--text-dim);
  background:var(--panel-3);border-radius:10px;padding:6px 10px;line-height:1.35;overflow-wrap:anywhere}
.crm-lead-foot{display:flex;justify-content:space-between;align-items:center;gap:8px;
  font-size:11px;margin-top:10px;padding-top:8px;border-top:1px solid var(--line)}
.crm-lead-who{color:var(--text-mut);font-weight:600;min-width:0;overflow-wrap:anywhere}
.crm-lead-due{font-weight:800;font-family:var(--mono);white-space:nowrap;color:var(--text-mut)}
.crm-lead-due.late{color:var(--danger)}

/* the drill-down popups still use these two */
.crm-ava{flex:0 0 auto;width:30px;height:30px;border-radius:10px;display:grid;place-items:center;font-weight:800;font-size:13px;
  background:color-mix(in srgb,var(--sc) 16%,var(--panel));color:var(--sc)}
.crm-card-val{font-size:12px;font-weight:800;font-family:var(--mono);white-space:nowrap}

/* ============================================================
   LOGIN GATE
   ============================================================ */
.login-screen{position:fixed;inset:0;z-index:200;display:flex;align-items:center;justify-content:center;padding:20px;
  background:
    radial-gradient(900px 600px at 78% 12%, rgba(240,104,32,.14), transparent 55%),
    #0a0c11}
.login-card{position:relative;width:min(400px,94vw);background:var(--panel,#fff);border:1px solid var(--line-strong);border-radius:var(--radius-lg);padding:34px 30px;
  box-shadow:var(--shadow-pop);text-align:center;animation:pop .45s var(--spring)}
.login-logo{height:54px;margin-bottom:18px;object-fit:contain}
.login-title{font-size:17px;font-weight:800;color:var(--text)}
.login-sub{font-size:13px;color:var(--text-mut);margin:4px 0 22px}
.login-form{display:flex;flex-direction:column;gap:14px;text-align:left}
.login-field{display:flex;flex-direction:column;gap:6px}
.login-field span{font-size:12px;font-weight:700;color:var(--text-dim);text-transform:uppercase;letter-spacing:.04em}
.login-field input{padding:12px 14px;border:1.5px solid var(--line);border-radius:10px;font-size:15px;
  background:var(--panel-2);color:var(--text);transition:var(--tr)}
.login-field input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft,rgba(240,104,32,.15))}
.login-error{background:var(--danger-soft,#fde8e8);color:var(--danger,#c0392b);padding:10px 12px;border-radius:10px;font-size:13px;font-weight:600}
.login-btn{margin-top:6px;padding:14px;border:none;border-radius:10px;font-size:15px;font-weight:800;cursor:pointer;
  color:#fff;background:var(--brand-orange);transition:var(--tr)}
.login-btn:hover{filter:brightness(1.06)}
.login-btn:disabled{opacity:.6;cursor:wait}
.login-foot{margin-top:20px;font-size:11px;color:var(--text-mut)}

/* ============================================================
   SUPERVISOR (HYBRID) — admin shell + big tap-friendly job cards
   Renders inside the admin #app shell, so it inherits the sidebar,
   topbar, dynamic accent colours and dark/light theme for free.
   These styles are theme-aware (use var() tokens) + touch-sized.
   ============================================================ */
/* hide office/admin-only chrome when the shell is in supervisor mode — the
   search box stays: the floor reaches the TDS booklet by searching, the same
   way every other login does (mod-supervisor binds it) */
/* the floor keeps the bell (its failed batches live under it since 2026-09-02) */
.app-shell.sup-mode .accent-pop{ display:none }

.sup-loading{padding:60px 20px;text-align:center;color:var(--text-mut);font-size:15px}
.sup-tabs{display:flex;gap:8px;margin:0 0 16px;overflow-x:auto;flex-wrap:wrap}
.sup-tab{flex-shrink:0;padding:10px 18px;border:1.5px solid var(--line);border-radius:14px;background:var(--panel);color:var(--text-dim);
  font-size:15px;font-weight:700;cursor:pointer;white-space:nowrap;transition:var(--tr)}
.sup-tab.on{background:var(--accent);color:#fff;border-color:var(--accent)}
.sup-list{display:grid;gap:14px;grid-template-columns:1fr}
.sup-card{background:var(--panel);border-radius:var(--radius);padding:16px;box-shadow:var(--shadow-1);border:1px solid var(--line);transition:var(--tr)}
.sup-card:hover{box-shadow:var(--shadow-2)}
.sup-card.overdue{border-color:var(--danger)}
.sup-card-head{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;margin-bottom:14px}
.sup-card-prod{font-size:17px;font-weight:800;line-height:1.25;color:var(--text)}
.sup-card-meta{font-size:12px;color:var(--text-mut);margin-top:4px;font-family:var(--mono,monospace)}
.sup-status{font-size:11px;font-weight:800;padding:4px 12px;border:1.5px solid;border-radius:14px;white-space:nowrap;text-transform:uppercase;letter-spacing:.03em}
.sup-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(95px,1fr));gap:12px;margin-bottom:14px}
.sup-fact-l{font-size:11px;color:var(--text-mut);font-weight:700;text-transform:uppercase;letter-spacing:.04em}
.sup-fact-v{font-size:15px;font-weight:600;margin-top:2px;color:var(--text)}
/* a fact the floor has not been told — stated, not left blank */
.sup-fact-mut{color:var(--text-mut);font-weight:500;font-size:13px}
/* a reading the next floor is READING, not taking: label left, value right */
.sup-lab-read{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  padding:10px 2px;border-bottom:1px solid var(--line);font-size:15px}
.sup-lab-read .k{color:var(--text-dim)}
.sup-lab-read .v{font-size:17px;font-weight:800;white-space:nowrap}
.sup-mat{margin-bottom:14px;background:var(--panel-2);border-radius:10px;padding:4px 14px;border:1px solid var(--line)}
.sup-mat summary{font-size:13px;font-weight:700;color:var(--text-dim);cursor:pointer;padding:10px 0}
.sup-mat-list{padding:4px 0 12px;display:flex;flex-direction:column;gap:8px}
.sup-mat-row{display:flex;justify-content:space-between;gap:12px;align-items:flex-start;font-size:13px;color:var(--text-dim)}
/* the material, and under it the store(s) it is fetched from */
.sup-mat-nm{display:flex;flex-direction:column;gap:1px;min-width:0;overflow-wrap:anywhere}
.sup-mat-wh{font-size:12px;color:var(--text-mut)}
/* HOW MUCH OFF WHICH SHELF. A draw that no single store covers is split, and
   the floor has to walk to each one — so every store gets its own line with
   its own quantity, set apart from the material's total on the right. A store
   the stock has ALREADY been issued from is a fact and stays quiet; one still
   to be drawn carries the accent edge the floor's outstanding work uses.
   Stacked, not inline: on a phone in a workshop three stores across one line
   would wrap into an unreadable run of names and numbers. */
.sup-mat-whs{display:flex;flex-direction:column;gap:2px;margin-top:2px;align-items:flex-start}
.sup-mat-whs .sup-mat-wh{display:inline-flex;align-items:center;gap:4px;
  padding:1px 8px;border-radius:var(--radius-pill);background:var(--panel-3);
  border:1px solid var(--accent-line);color:var(--text-dim);font-weight:600}
.sup-mat-whs .sup-mat-wh.is-done{border-color:transparent;color:var(--text-mut);font-weight:400}
.sup-mat-split{font-size:11px;color:var(--text-mut)}
.sup-mat-row b{flex:0 0 auto;white-space:nowrap}
.sup-actions{display:flex;gap:10px;flex-wrap:wrap}
.sup-act{flex:1;min-width:150px;padding:16px;border:none;border-radius:10px;font-size:17px;font-weight:800;cursor:pointer;transition:var(--tr)}
.sup-act.primary{color:#fff;background:var(--accent)}
.sup-act.primary:hover{filter:brightness(1.07)}
.sup-act.ghost{flex:0 0 auto;min-width:auto;background:var(--panel-2);color:var(--text-dim);border:1px solid var(--line)}
.sup-act:disabled{opacity:.6;cursor:wait}
/* a stage held back by an unmet requirement, not by a request in flight */
.sup-act.blocked{background:var(--panel-2);color:var(--text-mut);border:1px dashed var(--line)}
.sup-act.blocked:disabled{cursor:not-allowed;opacity:1}

/* ---- QC on a coated batch: what the floor still has to measure ---- */
.sup-lab{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:14px;padding:12px 14px;
  border-radius:10px;border:1px solid var(--warn,#d97706);
  background:color-mix(in srgb,var(--warn,#d97706) 10%,transparent)}
.sup-lab.done{border-color:var(--line);background:var(--panel-2)}
.sup-lab-main{flex:1;min-width:180px}
.sup-lab-t{font-size:13px;font-weight:800;color:var(--warn,#d97706)}
.sup-lab.done .sup-lab-t{color:var(--ok)}
.sup-lab-s{margin-top:4px;font-size:12px;color:var(--text-dim);line-height:1.5}
.sup-lab-btn{flex:0 0 auto;padding:10px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;
  background:var(--panel-2);color:var(--text-dim);border:1px solid var(--line);transition:var(--tr)}
.sup-lab-btn.urge{background:var(--warn,#d97706);color:#fff;border-color:transparent}
.sup-lab-btn:hover{filter:brightness(1.07)}
.sup-lab-ctx{margin-bottom:14px;padding:10px 12px;border-radius:10px;background:var(--panel-2);
  border:1px solid var(--line);font-size:13px;line-height:1.6;color:var(--text-dim)}
.sup-lab-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.sup-lab-fld label{display:flex;justify-content:space-between;align-items:baseline;gap:8px;margin-bottom:6px;
  font-size:12px;font-weight:700;color:var(--text-dim)}
.sup-lab-fld label .u{font-weight:500;font-size:11px;color:var(--text-mut)}
.sup-lab-fld .input{width:100%}
.sup-done-tag{flex:1;text-align:center;padding:14px;color:var(--ok);font-weight:800;background:var(--ok-soft,rgba(22,163,74,.12));border-radius:10px}
/* Packed and waiting on the office. Sized and placed exactly like the button
   that used to sit here, but flat and unclickable — the floor reports this
   state, it does not act on it. Deliberately NOT green: the job is not
   finished business until the lorry has gone. */
.sup-ready-tag{flex:1;text-align:center;padding:12px 14px;border-radius:10px;
  background:color-mix(in srgb,var(--info) 12%,transparent);
  border:1px dashed color-mix(in srgb,var(--info) 45%,transparent);cursor:default}
.sup-ready-tag .t{color:var(--info);font-weight:800;font-size:15px;line-height:1.3}
.sup-ready-tag .s{color:var(--text-mut);font-size:12px;font-weight:600;margin-top:4px;line-height:1.35}
.sup-empty{text-align:center;padding:50px 20px;color:var(--text-mut)}
.sup-empty .big{font-size:42px;margin-bottom:10px}
/* Schedule — the bucket headings between each run of job cards. Sized to be
   read across a workshop rather than leaned into, and sticky so the floor can
   still tell which bucket it is looking at part-way down a long list. */
.sup-sched-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin:22px 0 12px;padding:10px 14px;border-radius:10px;
  background:var(--panel-2);border:1px solid var(--line);
  position:sticky;top:0;z-index:2}
.sup-sched-head:first-of-type{margin-top:4px}
.sup-sched-ic{font-size:21px;line-height:1}
.sup-sched-t{font-size:15px;font-weight:800;letter-spacing:.2px;color:var(--text)}
.sup-sched-n{min-width:24px;text-align:center;padding:2px 10px;border-radius:14px;
  background:var(--accent);color:#fff;font-size:12px;font-weight:800}
.sup-sched-h{font-size:12px;color:var(--text-mut);margin-left:auto}
@media(max-width:560px){ .sup-sched-h{display:none} }
/* tablet / PC: multi-column job grid */
@media(min-width:760px){ .sup-list{grid-template-columns:repeat(2,1fr)} }
@media(min-width:1180px){ .sup-list{grid-template-columns:repeat(3,1fr)} }

/* ---- Report extra material: a compact button beside the facts (Priority) ---- */
.sup-facts-row{display:flex;align-items:flex-start;gap:10px;margin-bottom:14px}
.sup-facts-row .sup-facts{flex:1;margin-bottom:0}
.sup-excess-mini{flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;
  border-radius:10px;font-family:inherit;font-size:13px;font-weight:800;cursor:pointer;color:var(--accent);
  background:var(--accent-soft);border:1px solid var(--accent-line);transition:var(--tr);white-space:nowrap}
.sup-excess-mini:hover{background:var(--accent);color:#fff;border-color:var(--accent)}
.sup-excess-mini .ic{font-size:15px;line-height:1}
.xm-ctx{display:flex;gap:10px;background:var(--warn-soft);border:1px solid rgba(234,179,8,.3);border-radius:10px;
  padding:12px 14px;font-size:13px;color:var(--text-dim);line-height:1.45;margin-bottom:16px}
.xm-lines-h{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:10px}
.xm-t{font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:var(--text-dim)}
.xm-lines{display:flex;flex-direction:column;gap:10px}
.xm-line{padding:12px;border:1px solid var(--line);border-radius:10px;background:var(--panel-2);display:flex;flex-direction:column;gap:10px}
.xm-grid{display:grid;grid-template-columns:1.4fr .9fr 1fr;gap:10px}
.xm-grid.r2{grid-template-columns:1fr 1.2fr auto;align-items:end}
.xm-fld{display:flex;flex-direction:column;gap:6px;min-width:0}
.xm-fld label{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:var(--text-mut)}
.xm-fld .select,.xm-fld .input{width:100%}
.xm-qty{position:relative}
.xm-qty .input{padding-right:38px}
.xm-uom{position:absolute;right:11px;top:50%;transform:translateY(-50%);font-size:11px;font-weight:700;color:var(--text-mut);pointer-events:none}
.xm-rm{height:38px;width:40px;border-radius:10px;border:1px solid var(--line);background:var(--panel);color:var(--text-mut);font-size:15px;cursor:pointer;transition:var(--tr)}
.xm-rm:hover{color:var(--danger);border-color:var(--danger-soft)}
.xm-summ{font-size:13px;color:var(--text-dim);font-weight:600;margin-right:auto}
.xm-foot-btns{display:flex;gap:10px}
@media(max-width:560px){ .xm-grid,.xm-grid.r2{grid-template-columns:1fr} }


/* New W.O. — the stages this product will run (single-material products skip coating) */
.wo-route{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:10px 12px;border-radius:10px;
  background:var(--panel-2);border:1px solid var(--line)}
.wo-route-lbl{font-size:10px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;color:var(--text-mut)}
.wo-route-path{font-size:13px;font-weight:700;color:var(--text)}

/* ============================================================
   DOCUMENT FORMS (New / Edit purchase order · sales order)
   A header block of fields + a list of line items. The header
   packs into 3 columns on a wide modal; each line item is its own
   card — the product on its own row so a long name stays readable,
   its numbers beneath — so nothing is ever clipped or side-scrolled.
   ============================================================ */
.doc-sec{display:flex;align-items:center;gap:12px;margin:22px 0 12px}
.doc-sec:first-child{margin-top:2px}
.doc-sec-t{font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--accent);white-space:nowrap}
.doc-sec-l{flex:1;height:1px;background:var(--line)}
.form-grid.g3{grid-template-columns:repeat(3,minmax(0,1fr))}
@media(max-width:1100px){ .form-grid.g3{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media(max-width:680px){ .form-grid.g3{grid-template-columns:repeat(auto-fit,minmax(146px,1fr))} }

.doc-lines{display:flex;flex-direction:column;gap:10px}
.doc-line{border:1px solid var(--line);border-radius:10px;background:var(--panel-2);padding:12px 12px 12px}
.doc-line-top{display:flex;align-items:center;gap:10px}
.doc-line-no{flex:0 0 auto;width:30px;height:30px;border-radius:10px;display:grid;place-items:center;
  background:var(--panel-3);color:var(--text-mut);font-family:var(--mono);font-size:12px;font-weight:800}
.doc-line-item{flex:1;min-width:0}
.doc-line-item .ss-wrap,.doc-line-item .select,.doc-line-item .input{width:100%}
.doc-line-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));gap:10px;margin-top:10px}
.doc-line-f{display:flex;flex-direction:column;gap:4px;min-width:0}
.doc-line-f label{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:var(--text-mut)}
.doc-line-f .input,.doc-line-f .select{width:100%;min-width:0}
.doc-line-x{flex:0 0 auto}
.doc-add{margin-top:12px}
.doc-tot{display:flex;justify-content:flex-end;margin-top:18px}

/* A long <option> (e.g. a company name + GSTIN) must not stretch its grid
   column: the control shrinks with the column instead of widening it. */
.form-grid .field{min-width:0}
.form-grid .field > *{min-width:0}
.form-grid .field .select,.form-grid .field .input,
.form-grid .field select,.form-grid .field input,.form-grid .field textarea{width:100%;min-width:0}

/* BOM editor components table: roomy on desktop, but it must FIT the modal on a
   tablet or phone instead of forcing a sideways scroll. The fixed cell widths
   live here (not inline) so they can relax on a narrow screen. */
.bom-edit-tbl{width:100%;table-layout:auto}
.bom-edit-tbl .bom-nm{min-width:250px}
.bom-edit-tbl .bom-num{width:100px}
.bom-edit-tbl .bom-unit{width:74px}
@media(max-width:1120px){
  .bom-edit-tbl th,.bom-edit-tbl td{padding:8px 4px;font-size:12px}
  .bom-edit-tbl th{white-space:normal}
  .bom-edit-tbl .bom-nm{min-width:0}
  .bom-edit-tbl .bom-num,.bom-edit-tbl .bom-unit{width:auto;min-width:0}
  .bom-edit-tbl .input,.bom-edit-tbl .select{min-width:0;width:100%;padding:0 6px}
}
/* small tablets: squeeze once more so eight columns still fit the dialog */
@media(max-width:900px){
  .bom-edit-tbl th,.bom-edit-tbl td{padding:6px 2px;font-size:12px}
  .bom-edit-tbl .input,.bom-edit-tbl .select{padding:0 4px;font-size:12px}
}

/* BOM editor: the components table stays a REAL table at every width.
   The generic phone card layout stacks cells and reads their column name from
   data-label — this table is hand-built and has none, so stacking left a row of
   unlabelled inputs. A labelled table you swipe sideways is far more usable. */
.bom-edit-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;
  border:1px solid var(--line);border-radius:10px;background:var(--panel)}
@media(max-width:640px){
  .bom-edit-wrap table.bom-edit-tbl{display:table;min-width:720px;font-size:12px}
  .bom-edit-wrap .bom-edit-tbl thead{position:static;width:auto;height:auto;clip:auto;overflow:visible}
  .bom-edit-wrap .bom-edit-tbl tbody{display:table-row-group}
  .bom-edit-wrap .bom-edit-tbl tbody tr{display:table-row;background:none;border:none;
    border-radius:0;margin:0;box-shadow:none}
  .bom-edit-wrap .bom-edit-tbl tbody tr:nth-child(even){background:var(--table-stripe)}
  .bom-edit-wrap .bom-edit-tbl tbody td{display:table-cell;text-align:center;
    border-bottom:1px solid var(--line);padding:6px 4px;min-height:0;justify-content:initial}
  .bom-edit-wrap .bom-edit-tbl tbody td::before{content:none}
  .bom-edit-wrap .bom-edit-tbl tbody td:first-child{background:none;border-radius:0;margin:0;
    padding:6px 4px;display:table-cell;text-align:left}
  .bom-edit-wrap .bom-edit-tbl tbody td[colspan]{display:table-cell}
}

/* sales-order line: what the floor already has finished for this product */
.so-ready{margin-top:8px;font-size:12px;line-height:1.45;color:var(--text-mut);
  border-top:1px dashed var(--line);padding-top:8px}

/* Payslip detail — mirrors the printed sheet: employee strip, earnings /
   deductions tables and the net-pay bar (no boxed key/value list) */
.pay-who{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px 18px;
  border:1px solid var(--line);border-radius:10px;background:var(--panel-2);padding:10px 14px;margin-bottom:12px}
.pay-who > div{display:flex;justify-content:space-between;gap:10px;align-items:center;min-width:0}
.pay-who span{font-size:10px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--text-mut)}
.pay-who b{font-size:13px}
.pay-who b.nm{font-size:15px;font-weight:800}
.pay-cols{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.pay-tbl tfoot td{background:var(--panel-2);border-top:2px solid var(--line-strong)}
.pay-net{display:flex;justify-content:space-between;align-items:center;margin-top:12px;
  background:var(--accent-grad);color:#fff;border-radius:10px;padding:10px 16px;
  font-weight:800;letter-spacing:.06em}
.pay-net b{font-size:21px}
@media(max-width:680px){ .pay-who{grid-template-columns:1fr} .pay-cols{grid-template-columns:1fr} }

/* ---- work order waiting on raw material -----------------------------------
   The row is tinted so a pending order cannot be read as one merely in
   progress, and the tint survives the zebra striping and hover of .tbl. */
.tbl tbody tr.wo-pending > td,
.tbl tbody tr.wo-pending:nth-child(even) > td { background: var(--danger-soft, #fdecec); }
.tbl tbody tr.wo-pending:hover > td { background: var(--danger-soft, #fbdcdc); filter: brightness(0.98); }
.tbl tbody tr.wo-pending > td:first-child { box-shadow: inset 3px 0 0 var(--danger, #d64545); }
.wo-pending-tag { display:inline-block; font-size:11px; font-weight:800; letter-spacing:.4px;
  color: var(--danger, #d64545); border:1px solid var(--danger, #d64545); border-radius:4px;
  padding:1px 8px; white-space:nowrap; }
/* The floor's partial-order warning: the headline and the quantities that
   explain it are ONE message, so they sit in one red box, all in red. */
.sup-partial { display:block; margin-top:8px; padding:10px 12px;
  border:1.5px solid var(--danger, #d64545); border-radius:10px;
  color: var(--danger, #d64545); }
.sup-partial-head { font-size:11px; font-weight:800; letter-spacing:.4px; text-transform:uppercase; }
.sup-partial-sub { margin-top:6px; font-size:12px; line-height:1.55; font-weight:600;
  color: var(--danger, #d64545); }
.sup-card.partial { border-color: var(--danger, #d64545); }

/* ---- PO / SO totals panel ---------------------------------------------------
   It used to hug the right edge at whatever width its content happened to need,
   so long figures wrapped or sat cramped. Centre it and give it real width, with
   the labels and the amounts on opposite edges of a comfortable column. */
.doc-tot{ justify-content:center; }
.doc-tot > *{ width:min(560px, 100%); }
.doc-tot .card, .doc-tot > div{ font-size:13px; }
@media (max-width:640px){ .doc-tot > *{ width:100%; } }

/* ---- the pending line under a work-order row -------------------------------
   Full width, so the quantities read on one line instead of being crammed into
   the Stage cell and pushing the table into a sideways scroll. */
.tbl tbody tr.row-after > td{ padding:0; }
.tbl tbody tr.row-after.wo-pending > td{ background: var(--danger-soft, #fdecec); }
.tbl tbody tr.row-after > td.row-after-cell{ border-top:0; }
.wo-pending-note{ display:flex; flex-wrap:wrap; align-items:center; gap:8px 18px;
  padding:8px 12px 10px; font-size:12px; color: var(--danger, #d64545);
  border-top:1px dashed var(--danger, #d64545); }
.wo-pending-note .strong{ font-weight:800; }

/* ---- stacked sub-values in a table cell -------------------------------------
   Details under a cell's main value sit ONE PER LINE. Running them together
   across the column ("CODE · CATEGORY · HSN") forces the column wider than it
   needs to be and pushes wide tables into a sideways scroll. */
.tbl td .cell-sub + .cell-sub{ margin-top:2px; }
.tbl td .cell-sub{ display:block; }

/* ============================================================
   CALENDAR
   Built from the same parts as the rest of the app — panel, line,
   radius, the --c1..--c8 accents — so a new grid does not read as a
   bolted-on widget. Each entry carries its source colour in --sc.
   ============================================================ */
/* ‹ August 2026 › is ONE line. The arrows never shrink and the row never
   wraps: inside a shared toolbar a flex item can be squeezed, and a squeezed
   38px button that has given up its width leaves the label nowhere to sit. */
.cal-nav{display:flex;flex-wrap:nowrap;align-items:center;gap:8px;flex:0 0 auto}
.cal-nav>.icon-btn{flex:0 0 38px}
/* THE ONE CONTROL ROW. View switch, month arrows, search and the source chips
   are all the same decision — what the grid shows — so they share a line and
   wrap together. Three stacked bands used to sit between the heading and the
   grid; on a laptop that put the first week of the month below the fold. */
.cal-bar{row-gap:8px}
.cal-bar .cal-chips{margin:0}
.cal-bar .input.search{flex:1 1 190px;min-width:150px;max-width:320px}
/* the month label keeps a fixed width so the arrows do not shuffle sideways
   between a short month and a long one — narrower here than it was on a row
   of its own, because it is no longer the only thing on the line */
.cal-label{font-weight:800;font-size:14.5px;min-width:150px;text-align:center;letter-spacing:-.01em}

/* ---- source filter chips: click to hide a whole stream ---- */
.cal-chips{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 14px}
.cal-chip{--sc:var(--c1);display:inline-flex;align-items:center;gap:7px;cursor:pointer;
  font-size:11.5px;font-weight:700;padding:5px 11px;border-radius:var(--radius-pill);
  border:1px solid var(--line);background:var(--panel-2);color:var(--text-mut);
  transition:background .15s,color .15s,border-color .15s,opacity .15s;opacity:.62}
.cal-chip:hover{color:var(--text-dim);border-color:var(--line-strong)}
.cal-chip.on{opacity:1;color:var(--text);border-color:var(--sc);background:var(--panel)}
.cal-chip-d{width:9px;height:9px;border-radius:50%;background:var(--sc);flex:0 0 auto}
.cal-chip:not(.on) .cal-chip-d{background:var(--line-strong)}
.cal-chip-n{font-variant-numeric:tabular-nums;opacity:.7;font-weight:800}

/* ---- month grid ---- */
.cal-wrap{border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:var(--panel)}
/* minmax(0,1fr), NOT 1fr: a bare 1fr floors each track at the cell's
   min-content, and an entry pill carries a nowrap title — so seven day
   columns insisted on ~210px each (1481px of grid) and .cal-wrap's
   overflow:hidden quietly ate the last days of every week, on a desktop
   as much as a tablet. Zeroing the floor lets the track shrink and hands
   the truncation back to .cal-ev-t's ellipsis, where it belongs. */
.cal-head{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));background:var(--panel-2);
  border-bottom:1px solid var(--line)}
.cal-hd{padding:9px 10px;font-size:11px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--text-mut);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr))}
.cal-cell{min-height:112px;min-width:0;padding:6px 7px 8px;border-right:1px solid var(--line);
  border-bottom:1px solid var(--line);display:flex;flex-direction:column;gap:4px;cursor:pointer;
  transition:background .15s}
.cal-cell:nth-child(7n){border-right:none}
.cal-cell:hover{background:var(--panel-2)}
/* a day outside the month being viewed stays visible but recedes */
.cal-cell.out{opacity:.42}
.cal-cell.today{background:var(--accent-soft)}
.cal-cell.today .cal-cell-n{background:var(--accent-grad);color:#fff;
  width:23px;height:23px;border-radius:50%;display:grid;place-items:center}
.cal-cell-top{display:flex;align-items:center;justify-content:space-between;gap:4px;min-height:23px;min-width:0}
.cal-cell-n{font-size:12px;font-weight:800;color:var(--text-dim);font-variant-numeric:tabular-nums}
.cal-more{border:none;background:transparent;cursor:pointer;font-size:10.5px;font-weight:800;
  color:var(--text-mut);padding:1px 4px;border-radius:5px}
.cal-more:hover{background:var(--line);color:var(--text)}
.cal-cell-body{display:flex;flex-direction:column;gap:3px;min-width:0}

/* ---- an entry, as a pill in the month grid ---- */
.cal-ev{--sc:var(--c1);display:flex;align-items:center;gap:5px;width:100%;cursor:pointer;
  border:none;border-left:3px solid var(--sc);background:var(--panel-2);
  border-radius:5px;padding:3px 6px;text-align:left;font-size:11px;font-weight:600;
  color:var(--text-dim);min-width:0;transition:background .15s,color .15s}
.cal-ev:hover{background:var(--line);color:var(--text)}
.cal-ev-ic{flex:0 0 auto;font-size:10px}
.cal-ev-t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* a date that has passed and is still open is the whole point of the view */
.cal-ev.late{background:var(--danger-soft,#fdecec);color:var(--danger);border-left-color:var(--danger)}
.cal-ev.now{background:var(--accent-soft);color:var(--text)}
.cal-ev.done{opacity:.5;text-decoration:line-through}

/* ---- week / day columns ---- */
.cal-cols{display:grid;grid-template-columns:repeat(7,1fr);gap:10px}
.cal-cols.one{grid-template-columns:1fr}
.cal-col{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;display:flex;flex-direction:column;min-width:0}
.cal-col.today{border-color:var(--accent)}
.cal-col-head{display:flex;align-items:baseline;gap:6px;padding:9px 11px;
  background:var(--panel-2);border-bottom:1px solid var(--line)}
.cal-col.today .cal-col-head{background:var(--accent-soft)}
.cal-col-wd{font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:var(--text-mut)}
.cal-col-d{font-size:17px;font-weight:800;letter-spacing:-.02em}
.cal-col-m{font-size:11px;color:var(--text-mut);font-weight:700}
.cal-col-add{margin-left:auto;border:none;background:transparent;cursor:pointer;
  color:var(--text-mut);font-size:13px;padding:0 2px;border-radius:5px}
.cal-col-add:hover{color:var(--accent)}
.cal-col-body{padding:8px;display:flex;flex-direction:column;gap:6px;min-height:70px}
.cal-none{font-size:11.5px;color:var(--text-mut);padding:10px 4px;text-align:center}

/* ---- an entry, as a full row (week / day / agenda / drill-downs) ---- */
.cal-row{--sc:var(--c1);display:flex;align-items:center;gap:9px;width:100%;cursor:pointer;
  border:1px solid var(--line);border-left:3px solid var(--sc);background:var(--panel-2);
  border-radius:8px;padding:8px 10px;text-align:left;color:inherit;
  transition:background .15s,border-color .15s,transform .12s}
.cal-row:hover{background:var(--panel);border-color:var(--line-strong);transform:translateX(2px)}
.cal-row-ic{flex:0 0 auto;font-size:14px}
.cal-row-tx{display:flex;flex-direction:column;gap:1px;min-width:0;flex:1}
.cal-row-t{font-size:12.5px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-row-s{font-size:11px;color:var(--text-mut);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-row-time{font-size:11.5px;font-weight:800;color:var(--text-dim);font-variant-numeric:tabular-nums;flex:0 0 auto}
.cal-row-v{font-size:12px;font-weight:800;flex:0 0 auto}
.cal-row.late{border-left-color:var(--danger);background:var(--danger-soft,#fdecec)}
.cal-row.late .cal-row-t{color:var(--danger)}
.cal-row.now{border-left-color:var(--accent)}
.cal-row.done{opacity:.55}
.cal-row.done .cal-row-t{text-decoration:line-through}
.cal-day-list{display:flex;flex-direction:column;gap:7px}

/* ---- agenda ---- */
.cal-agenda{display:flex;flex-direction:column;gap:14px}
.cal-ag-day{display:flex;gap:14px;align-items:flex-start}
.cal-ag-date{flex:0 0 58px;text-align:center;padding:8px 0;border-radius:10px;
  background:var(--panel-2);border:1px solid var(--line)}
.cal-ag-date.today{background:var(--accent-grad);border-color:transparent;color:#fff}
.cal-ag-n{display:block;font-size:19px;font-weight:800;line-height:1.1;letter-spacing:-.02em}
.cal-ag-wd{display:block;font-size:10px;font-weight:700;text-transform:uppercase;
  letter-spacing:.04em;opacity:.75;margin-top:2px}
.cal-ag-rows{flex:1;display:flex;flex-direction:column;gap:6px;min-width:0}

/* ---- narrow screens: the 7-column grid stops being readable ---- */
@media (max-width:900px){
  .cal-cols{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:640px){
  .cal-label{min-width:0;flex:1;font-size:13.5px}
  .cal-cols{grid-template-columns:1fr}
  .cal-cell{min-height:76px;padding:4px}
  .cal-hd{padding:7px 4px;font-size:9.5px}
  /* only the first letter of the weekday fits */
  .cal-hd{overflow:hidden;white-space:nowrap}
  .cal-ev-t{display:none}
  .cal-ev{justify-content:center;padding:3px 4px}
  .cal-ag-day{gap:9px}
  .cal-ag-date{flex-basis:46px}
  .cal-chips{gap:6px;margin-bottom:10px}
  .cal-chip{padding:4px 9px;font-size:11px}
}

/* ============================================================
   PHONE DENSITY PASS
   Everything below only ever applies at phone widths. The app
   already fitted a phone without sideways scrolling; what it cost
   was VERTICAL — one field, one figure or one label:value pair per
   row meant the real content of a screen started well below the
   fold. These rules pack those pairs up without shrinking a single
   tap target: the padding and the empty half-rows go, the buttons,
   inputs and rows you actually touch keep their size.
   ============================================================ */

/* ---- stacked data rows pack two pairs to a line -------------------------
   Operations keeps the stacked label:value card (the floor needs Start /
   Complete on the row itself, which tap-to-open cards would hide). One pair
   per row made a work order ~950px tall — eight labelled rows for values as
   short as "kg" or a date. Two-up, with the label over its value, reads the
   same and halves it. Applied via .tbl-stack from ui.js table(). */
@media(max-width:640px){
  .table-wrap.tbl-stack tbody tr{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
    align-content:start;padding-bottom:8px}
  /* block, NOT a flex column: as a flex container the cell would stack the
     value's own spans too, breaking "184 kg" over two lines and stopping the
     action buttons from filling the row */
  .table-wrap.tbl-stack tbody td{display:block;text-align:left;padding:6px 12px}
  .table-wrap.tbl-stack tbody td.num,
  .table-wrap.tbl-stack tbody td.ctr{text-align:left}
  .table-wrap.tbl-stack tbody td::before{display:block;text-align:left;font-size:10px;margin-bottom:1px}
  /* the identity cell, the actions cell and any full-width note keep the row */
  .table-wrap.tbl-stack tbody td:first-child{grid-column:1/-1;margin:0 6px 6px;padding:10px 12px}
  .table-wrap.tbl-stack tbody td[data-label=""]{grid-column:1/-1}
  .table-wrap.tbl-stack tbody td[colspan]{grid-column:1/-1}
  /* an empty cell still occupies its half of the row, which is what keeps the
     pairs aligned in two clean columns */
  .table-wrap.tbl-stack tbody td:empty{display:none}
}

/* ---- small figure clusters stay multi-column ----------------------------
   .cols-2/.cols-3 collapse to one column on a phone, which is right for a
   grid of cards but wrong for a huddle of six short figures inside a card or
   a dialog — those became six near-empty rows. Tagged at the call site so
   nothing else is affected. */
@media(max-width:820px){
  .grid.cols-2.statgrid,.grid.cols-3.statgrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
  .grid.cols-3.statgrid-3{grid-template-columns:repeat(3,minmax(0,1fr))}
  .statgrid .card{padding:10px 12px}
}

/* ---- CRM: two KPI cards a row, and a tighter follow-up block ---- */
@media(max-width:640px){
  .crm-grid{gap:10px;margin-bottom:12px}
  .crm-s3{grid-column:span 6}
  .crm-kpi{min-height:0;padding:12px 12px 10px}
  .crm-kpi-val{font-size:21px;margin-top:6px}
  .crm-kpi-lab{font-size:11px}
  .crm-kpi-ic{width:20px;height:20px;border-radius:6px;font-size:10px}
  .crm-kpi-foot{padding-top:8px;font-size:10px}
  .crm-kpi-vis{height:30px}
  .crm-mini{gap:4px;margin-top:8px}
  .crm-mini-lab{flex-basis:48px;font-size:10px}
  .crm-fu{margin-bottom:12px}
  .crm-fu-head{padding:12px 14px;gap:10px}
  .crm-fu-ic{width:30px;height:30px;border-radius:10px;font-size:15px}
  .crm-fu-title{font-size:15px}
  .crm-fu-sub{font-size:11px}
  .crm-fu-row{padding:10px 14px;gap:10px}
  .crm-fu-co{font-size:13px}
  .crm-leg-row{padding:6px 0}
  .crm-feed-row{padding:8px 0;gap:10px}
  .crm-feed-ic{width:26px;height:26px;font-size:12px}
}

/* ---- HR / supervisor: trim the frame, never the touch targets ---- */
@media(max-width:640px){
  .sup-tabs{gap:6px;margin-bottom:12px}
  .sup-tab{padding:8px 14px;font-size:13px}
  .sup-card{padding:14px}
  .sup-card-head{margin-bottom:10px}
  .sup-facts{gap:10px;margin-bottom:10px}
  .sup-mat{margin-bottom:10px}
  .sup-lab{padding:10px 12px;margin-bottom:10px;gap:10px}
  .mcard{margin-bottom:10px;padding:10px 0 4px}
  .mcard-head{padding:0 12px 8px}
  .mstrip{padding:2px 12px 10px;gap:6px}
}

/* ---- HR · Settings: a deduction's rates stay on one row ------------------
   Three fields at a 120px floor need 380px, and a phone row is 340px, so PF
   and ESI each broke 2 + 1 — the third rate dropped to its own line and read
   as though it belonged to the next deduction. On a phone let the fields
   share the row equally instead; the 120px floor still governs desktop, and
   PT (two fields) is unaffected either way. */
.ded-f{flex:1;min-width:120px}
@media(max-width:640px){
  /* A grid, not a flex row. Each field is display:contents, so every TITLE
     lands in the first track and every BOX in the second — and a title that
     runs to two lines ("Wage Cap ₹/mo" does once the phone's text size is
     turned up) grows the title track for all three instead of dropping its
     own box a line below its neighbours. The titles sit at the foot of their
     track so each stays against the box it names. */
  .ded-fields{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);
    grid-template-rows:auto auto;gap:0 8px;align-items:end}
  .ded-fields>.ded-f{display:contents}
}

/* ---- EXPORT PREVIEW: say how much before you take it away ----------------
   The toolbar above every preview table. It wraps rather than scrolls, because
   the dialog is already as wide as it goes and a control that scrolls out of
   sight is a control nobody knows is there. */
.dp-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:12px;
  padding-bottom:12px;border-bottom:1px solid var(--line)}
.dp-bar .search-wrap,.dp-bar .search{min-width:170px}
.dp-cols{max-height:280px;overflow:auto;min-width:210px;padding:4px}
.dp-col{display:flex;align-items:center;gap:8px;cursor:pointer;white-space:nowrap}
.dp-col-all{font-weight:700;border-bottom:1px solid var(--line);margin-bottom:2px}
/* the row ticks, and the typed row count, on the report preview */
.dp-pick,.dp-pick-all{width:16px;height:16px;margin:0;accent-color:var(--accent);cursor:pointer;vertical-align:middle}
.tbl th:has(.dp-pick-all){text-align:center}
.dp-limitwrap{display:inline-flex;align-items:center;gap:6px;font-size:12px}
.dp-limit{width:92px;height:34px;padding:0 8px}
@media(max-width:640px){
  /* on a phone the count sits under the controls instead of being pushed off */
  .dp-bar>div[style*="margin-left:auto"]{margin-left:0 !important;width:100%}
}

/* ---- WHICH STORE A WORK ORDER DRAWS EACH MATERIAL FROM -------------------
   The picker sits under the material's name, where the store chip otherwise
   goes, so it must not stretch the row. The note above the list says whether
   there is a choice to make at all — without it the control was invisible on
   the recipes (almost all of them here) whose materials each sit in one store,
   and its absence read as the feature not being there. */
.wo-wh-wrap{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:4px}
.wo-wh-lbl{font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--text-mut)}
.wo-wh-pick{max-width:300px;font-size:11.5px;padding:3px 8px;height:auto;
  border-color:var(--accent-line)}
.wo-store-note{display:flex;align-items:flex-start;gap:10px;margin:14px 0 2px;
  padding:9px 12px;border-radius:10px;background:var(--panel-2);border:1px solid var(--line)}
.wo-store-note.pick{border-color:var(--accent-line);background:var(--accent-soft)}
.wo-store-ic{font-size:15px;line-height:1.2;flex:0 0 auto}
/* a chosen store that cannot cover the draw says so, and names one that can */
.wo-wh-short{font-size:11px;line-height:1.5;color:var(--warn);margin-top:3px;max-width:420px}
.wo-wh-short .wo-wh-alt{color:var(--text-mut)}

/* ---- HOW MUCH OFF WHICH SHELF ---------------------------------------------
   A draw is split across stores whenever one cannot cover it, so a material
   naming a single store was telling the storeman half the answer. Each store
   it comes out of gets a chip carrying its own quantity — set in the figure
   type the rest of the sheet uses for quantities, so the numbers line up with
   the need beside them. A chip for stock ALREADY ISSUED is a fact rather than
   a forecast and reads in the settled colour; one still to be drawn carries
   the accent edge that marks everything on these sheets the floor has yet to
   do. Wrapping, because three stores on one line would push the quantity
   column off a narrow card. */
.wo-src-whs{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:4px}
.wo-src-wh{display:inline-flex;align-items:center;gap:4px;white-space:nowrap;
  font-size:11px;font-weight:600;padding:2px 7px;border-radius:var(--radius-pill);
  color:var(--text-dim);background:var(--panel-3);
  border:1px solid var(--accent-line)}
.wo-src-wh.is-done{border-color:transparent;color:var(--text-mut);font-weight:500}

/* ---- HR PERKS: one tile per perk ------------------------------------------
   The two perks were a card each, then plain rows in a shared card, and both
   read as a wall of prose with unlabelled numbers in it. As tiles: the icon
   and name identify the perk, the badge on the right says what it is worth
   right now (or "Off" at zero, which is how both are switched off), each
   figure carries its own unit beside the box, and the rule sits underneath in
   the quiet type it deserves. */
.perk-list{display:flex;flex-direction:column;gap:10px}
.perk{background:var(--panel-2);border:1px solid var(--line);border-radius:12px;
  padding:13px 14px;transition:border-color var(--tr),opacity var(--tr)}
.perk:focus-within{border-color:var(--accent-line)}
/* switched off: still perfectly readable, just plainly not in play */
.perk.is-off{opacity:.72}
.perk-head{display:flex;align-items:center;gap:11px}
.perk-ic{width:34px;height:34px;border-radius:10px;display:grid;place-items:center;font-size:16px;
  background:var(--accent-soft);box-shadow:inset 0 0 0 1px var(--accent-line);flex:0 0 34px}
.perk-id{min-width:0;display:flex;flex-direction:column;gap:2px}
.perk-name{font-size:13.5px;font-weight:700;letter-spacing:-.01em}
.perk-sub{font-size:11.5px;color:var(--text-mut);line-height:1.35}
.perk-state{margin-left:auto;flex:0 0 auto;font-size:11.5px;font-weight:700;white-space:nowrap;
  padding:4px 10px;border-radius:var(--radius-pill);background:var(--ok-soft);color:var(--ok)}
.perk-state.off{background:var(--panel-3);color:var(--text-mut)}
/* the figures: label above, box and its unit on one line */
.perk-fields{display:flex;flex-wrap:wrap;gap:10px 16px;margin:12px 0 0}
.perk-f{display:flex;flex-direction:column;gap:5px;min-width:0}
.perk-f-lbl{font-size:10.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--text-mut)}
.perk-f-in{display:flex;align-items:center;gap:7px}
.perk-f-in .input{width:104px;text-align:right;font-variant-numeric:tabular-nums}
.perk-f-unit{font-size:11.5px;color:var(--text-mut);white-space:nowrap}
.perk-note{font-size:11.5px;line-height:1.6;color:var(--text-dim);margin:11px 0 0;
  padding-top:10px;border-top:1px solid var(--line)}
@media(max-width:640px){
  /* A grid, so the badge drops to its own line UNDER the name and stays lined
     up with it, instead of squeezing the name to nothing on the same row. */
  .perk-head{display:grid;grid-template-columns:34px 1fr;gap:0 11px;align-items:center}
  .perk-id{grid-column:2}
  .perk-state{grid-column:2;justify-self:start;margin:8px 0 0}
  .perk-fields{gap:10px 12px}
  .perk-f{flex:1 1 132px}
  .perk-f-in .input{width:100%;min-width:0}
}

/* ---- a job sheet's material rows on a phone ------------------------------
   The layer row runs name · code · spec · store · quantity, which no phone
   fits on one line. Left to wrap it broke wherever a word ran out of room, so
   the quantity landed in a different place on every row and stopped reading
   as a column. Below 640px a row that names a store puts the quantity top
   right and stacks the rest under the name. Only rows carrying a store are
   laid out this way — the BOM view, which shows none, keeps the plain
   wrapping row it has always had, at every width. */
.lp-qty{margin-left:auto}
@media(max-width:640px){
  .lp-row-wh{display:grid;grid-template-columns:1fr auto;gap:1px 8px;align-items:baseline}
  .lp-row-wh>*{grid-column:1}
  .lp-row-wh>.lp-qty{grid-column:2;grid-row:1;margin-left:0}
  /* likewise for a stock draw: the roll's name owns the first line, its
     quantity and store the second, rather than breaking mid-way */
  .wo-src>.wo-src-nm{flex:1 1 100%}
}

/* ---- payslip, PO/SO totals and the document forms ---- */
@media(max-width:640px){
  .pay-who{padding:10px 12px;margin-bottom:10px;gap:6px 14px}
  .pay-cols{gap:10px}
  .doc-sec{margin:16px 0 10px}
  .doc-line{padding:10px 10px 12px}
  .doc-line-fields{gap:8px;margin-top:10px}
  .doc-lines{gap:8px}
  .doc-tot{margin-top:14px}
  /* the booklet reader has the bottom nav below it, not just the topbar */
  .doc-shell{height:calc(100dvh - 290px);min-height:300px}
}

/* ---- small phones (≤360px): stop intrinsic widths winning ----------------
   A card head with tool chips, and any control whose default intrinsic width
   is wider than the flex box holding it, both spilled past the right edge on
   a 320px phone. Neither can be reached by the layouts above. */
@media(max-width:640px){
  .card-head{flex-wrap:wrap;row-gap:6px}
  .card-head .tools{margin-left:auto;flex-wrap:wrap}
  /* an <input>'s default size attribute makes it ~170px wide however narrow
     its container is; cap it so it can never outgrow the card */
  .input,.select,textarea.input{max-width:100%;min-width:0}
}

/* ---- the alert drawer and the ranked/bar lists ---- */
@media(max-width:640px){
  .drawer-body{padding:12px}
  .alert-item{padding:12px;gap:10px;margin-bottom:8px}
  .alert-ic{width:30px;height:30px;flex-basis:30px;font-size:15px}
  .rankbars{gap:12px}
  .rankbar-top{margin-bottom:6px}
  .barlist{gap:10px}
  .timeline{padding-left:20px}
  .tl-item{padding-bottom:14px}
  .legend{gap:8px}
  .empty{padding:34px 16px}
  .empty .big{font-size:34px;margin-bottom:8px}
}

/* ---- TOUCH TARGETS -------------------------------------------------------
   Sized for a mouse, these controls came out 23–27px tall, which a fingertip
   misses. Everything a finger has to hit gets at least 34px on a touch-width
   screen. Only the box grows — type size, colour and spacing are untouched,
   so nothing about the density changes, and the pointer layouts above 900px
   keep the compact sizes they were drawn at. */
@media(max-width:900px){
  .seg button{min-height:34px;padding:6px 14px}
  .cal-chip{min-height:34px;padding:6px 12px}
  .wa-btn{width:32px;height:32px;border-radius:10px;font-size:15px}
  .cal-col-add,.cal-more{min-width:28px;min-height:28px}
  /* inline record links sit in dense rows, so they get reach rather than
     bulk: vertical padding on an inline box paints and taps outside the
     line box without moving a single row — a 14px link taps like 24px */
  .a-link{padding:6px 0}
  /* the month grid's entry pills: 24px is the floor a fingertip can work
     with, and a miss still lands on the day cell, which opens the day */
  .cal-ev{min-height:24px}
  /* the month grid's entry pills: 24px is the floor a fingertip can work
     with, and a miss still lands on the day cell, which opens the day */
  .cal-ev{min-height:24px}
  /* a native checkbox renders 13px however the row around it is styled */
  input[type=checkbox],input[type=radio]{width:20px;height:20px;flex:0 0 auto}
  /* The carousel dots stay 7px — they are an indicator, and fattening them
     would read as buttons. They get the reach instead of the size: an
     invisible pad over each dot, and enough gap that two never overlap. */
  .crm-car-dots{gap:16px}
  .crm-car-dot{position:relative}
  .crm-car-dot::after{content:"";position:absolute;inset:-11px -7px}
}
/* the Label Studio gallery's controls get the same treatment, but their base
   rules live at the bottom of this file — the override sits after them, at the
   very end, where source order cannot quietly undo it */


/* ============================================================
   LABEL PRINTING WIZARD — Procurement → PO → 🏷 Stickers
   Three steps in one dialog: fields & data, layout, preview.
   ============================================================ */
.wz-rail{display:flex;gap:10px;margin:-2px 0 20px;flex-wrap:wrap}
.wz-step{display:flex;align-items:center;gap:10px;padding:10px 16px;border-radius:var(--radius-pill);
  border:1px solid var(--line);background:var(--panel-2);color:var(--text-mut);text-align:left;
  font-size:13px;font-weight:700;cursor:pointer;transition:var(--tr);flex:1 1 0;min-width:148px}
.wz-step:hover{border-color:var(--accent-line);color:var(--text-dim)}
.wz-step .n{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;flex:0 0 22px;
  background:var(--line);color:var(--text-mut);font-size:11px;font-weight:800}
.wz-step.done{color:var(--text-dim)}
.wz-step.done .n{background:var(--ok);color:#fff}
.wz-step.on{border-color:transparent;background:var(--accent-grad);color:#fff;
  box-shadow:0 4px 14px var(--accent-soft),inset 0 1px 0 rgba(255,255,255,.25)}
.wz-step.on .n{background:rgba(255,255,255,.3);color:#fff}
.wz-pane{min-height:412px}

.wz-sec{font-size:11px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  color:var(--text-mut);margin:20px 0 10px}
.wz-sec:first-child{margin-top:0}
.wz-auto{display:inline-flex;align-items:center;gap:8px;text-transform:none;letter-spacing:0;
  font-size:12px;font-weight:600;color:var(--text-dim);cursor:pointer}

/* ---- label colour + symbol (layout step) ----
   The dial is the OS colour picker; the chips are the standard set. Both write
   the same cfg.bg, and the small preview shows the ink the label will use. */
.wz-colrow{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.wz-dial{width:46px;height:34px;padding:2px;border:1px solid var(--line);border-radius:10px;
  background:var(--surface-2);cursor:pointer;flex:none}
.wz-dial::-webkit-color-swatch-wrapper{padding:0}
.wz-dial::-webkit-color-swatch{border:none;border-radius:6px}
.wz-hex{width:104px;flex:none;font-family:var(--mono);text-transform:lowercase}
.wz-inkpv{flex:1 1 130px;min-width:120px;height:34px;display:flex;align-items:center;
  justify-content:center;border:1px solid var(--line);border-radius:10px;
  font:700 12px/1 "Times New Roman",Georgia,serif;letter-spacing:.04em;
  background:#fff;color:#000;overflow:hidden}
.wz-sw{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.wz-chip{width:28px;height:28px;border-radius:10px;border:1px solid var(--line);
  cursor:pointer;padding:0;position:relative;transition:transform .1s ease}
.wz-chip:hover{transform:scale(1.09)}
.wz-chip.on{box-shadow:0 0 0 2px var(--bg),0 0 0 4px var(--accent)}
.wz-symb{min-width:34px;height:34px;border-radius:10px;border:1px solid var(--line);
  background:var(--surface-2);color:var(--text);cursor:pointer;font-size:17px;line-height:1;
  display:inline-flex;align-items:center;justify-content:center;padding:0 6px}
.wz-symb:hover{border-color:var(--accent)}
/* the shape picker — the icon IS the shape, drawn in CSS so it cannot fall
   back to a missing-glyph box the way a unicode ellipse might */
.wz-shapes{display:flex;gap:8px;flex-wrap:wrap}
.wz-shp{display:flex;flex-direction:column;align-items:center;gap:6px;padding:10px 10px 8px;
  min-width:64px;border:1px solid var(--line);border-radius:10px;background:var(--surface-2);
  color:var(--text-dim);cursor:pointer;font-size:11px;font-weight:600;transition:var(--tr)}
.wz-shp:hover{border-color:var(--accent)}
.wz-shp.on{background:var(--accent-soft);border-color:var(--accent);color:var(--accent-300)}
.wz-shp i{display:block;width:26px;height:16px;border:2px solid currentColor;border-radius:2px}
.wz-shp i.s-round{border-radius:6px}
.wz-shp i.s-ellipse{border-radius:50%}
.wz-shp i.s-circle,.wz-shp i.s-disc{width:16px;border-radius:50%}
.wz-shp i.s-disc{position:relative}
.wz-shp i.s-disc::after{content:"";position:absolute;left:50%;top:50%;width:5px;height:5px;
  border-radius:50%;border:2px solid currentColor;transform:translate(-50%,-50%)}
/* placed symbols: a header row, then glyph · x · y · size · remove */
.wz-symhead,.wz-symrow{display:grid;grid-template-columns:34px 1fr 1fr 1fr 30px;gap:8px;
  align-items:center}
.wz-symhead{margin-top:12px;font-size:10px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text-mut)}
.wz-symrow{margin-top:6px}
.wz-symrow .g{font-size:17px;text-align:center}
/* background picture controls */
.wz-thumb{width:46px;height:34px;object-fit:contain;border:1px solid var(--line);
  border-radius:10px;background:var(--surface-2);flex:none}
.wz-picwrap{margin-top:12px}
/* per-field colour dot in step 1 */
.wz-dot{width:26px;height:26px;padding:1px;border:1px solid var(--line);border-radius:6px;
  background:var(--surface-2);cursor:pointer;flex:none}
.wz-dot::-webkit-color-swatch-wrapper{padding:0}
.wz-dot::-webkit-color-swatch{border:none;border-radius:4px}
/* the design pane's inspector: whatever is selected, its knobs in one strip */
.wz-insp{display:flex;align-items:center;gap:12px;flex-wrap:wrap;min-height:40px;width:100%;
  padding:8px 10px;margin-bottom:2px;border:1px solid var(--line);border-radius:10px;
  background:var(--surface-2)}
.wz-insplbl{font-size:12px;font-weight:800;letter-spacing:.04em;color:var(--text)}
.wz-inspfld{display:inline-flex;align-items:center;gap:8px;font-size:12px;font-weight:600;
  color:var(--text-dim)}
.wz-inspfld .input{height:30px;padding:0 8px}
/* the canvas well the label floats in */
.wz-canvas{display:flex;justify-content:center;align-items:center;width:100%;
  padding:18px;border-radius:10px;border:1px solid var(--line);background:var(--surface-2)}
/* the design-tools rail: a proper settings panel — sections divide with a
   rule, every row stretches full width, nothing floats centred */
.wz-pv.wz-tools{align-items:stretch}   /* out-specifies .wz-pv's centring below */
.wz-tools .wz-sec{margin:14px 0 10px;padding-top:14px;border-top:1px solid var(--line)}
.wz-tools .wz-sec:first-of-type{margin-top:0;padding-top:0;border-top:0}
.wz-tools .seg{display:inline-flex}
.wz-tools .hint{font-size:12px;line-height:1.55}
.wz-picchip{display:flex;align-items:center;gap:10px}
.wz-picchip .wz-thumb{width:42px;height:30px}
/* the full-width tools rail lays out as three columns; each column's first
   section drops the divider it would otherwise start with */
.wz-toolgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));
  gap:4px 30px;width:100%}
.wz-toolgrid>div>.wz-sec:first-child{margin-top:0;padding-top:0;border-top:0}

/* step 1 — a tick and its fetched value, side by side */
.wz-fld{display:grid;grid-template-columns:minmax(152px,196px) 1fr;gap:12px;align-items:center;
  padding:6px 10px;border-radius:10px;border:1px solid transparent;transition:var(--tr)}
.wz-fld:hover{background:var(--panel-2)}
.wz-fld.off{opacity:.45}
.wz-fld label{display:flex;align-items:center;gap:10px;font-size:13px;font-weight:600;
  color:var(--text-dim);cursor:pointer;margin:0}
.wz-fld .input{height:34px}

/* step 2 — controls left, the sheet drawn to scale on the right */
.wz-cols{display:grid;grid-template-columns:1fr 300px;gap:26px;align-items:start}
.wz-diag{background:var(--panel-2);border:1px solid var(--line);border-radius:var(--radius);
  padding:18px 16px;display:flex;flex-direction:column;align-items:center;gap:14px;
  position:sticky;top:0;overflow:visible}
.wz-page{position:relative;background:#fff;border:1px solid #c9c9c9;
  box-shadow:0 8px 26px rgba(0,0,0,.3)}
.wz-lab{position:absolute;background:var(--accent-soft);border:1px solid var(--accent);border-radius:2px}
.wz-lab.bad{background:var(--danger-soft);border-color:var(--danger);z-index:1}
.wz-dim{font-size:12px;color:var(--text-mut);text-align:center;line-height:1.7}
.wz-dim b{color:var(--text);font-weight:700}

.wz-alert{display:flex;gap:12px;align-items:flex-start;margin-top:22px;padding:14px 16px;
  border-radius:var(--radius-sm);background:var(--danger-soft);border:1px solid var(--danger);
  color:var(--danger);font-size:13px;line-height:1.6}
.wz-alert .ic{font-size:15px;line-height:1.3;flex:0 0 auto}
.wz-alert.ok{background:var(--ok-soft);border-color:var(--ok);color:var(--ok)}

/* step 3 — the label itself beside the sheet it prints on */
.wz-split{display:grid;grid-template-columns:1fr 1fr;gap:20px;align-items:start}
.wz-pv{border:1px solid var(--line);border-radius:var(--radius);background:var(--panel-2);
  padding:16px;display:flex;flex-direction:column;align-items:center;gap:14px}
.wz-pv h4{font-size:11px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  color:var(--text-mut);align-self:flex-start}
.wz-frame{overflow:hidden;background:#fff;box-shadow:0 8px 26px rgba(0,0,0,.3);flex:0 0 auto}
.wz-frame iframe{display:block;border:0}
.wz-nav{display:flex;align-items:center;gap:10px;font-size:13px;font-weight:700;color:var(--text-mut)}

@media (max-width:900px){
  .wz-cols,.wz-split{grid-template-columns:1fr}
  .wz-diag{position:static}
  .wz-fld{grid-template-columns:1fr;gap:6px;padding:10px 10px}
  .wz-pane{min-height:0}
}

/* ---- label wizard: field picker, layout modes, copies ---------------- */
.wz-ta{width:100%;min-height:36px;max-height:260px;padding:8px 12px;border-radius:10px;
  border:1px solid var(--line);background:var(--panel-2);color:var(--text);
  font:inherit;font-size:13px;line-height:1.45;resize:vertical;overflow:hidden;
  transition:var(--tr);display:block}
.wz-ta:hover{border-color:var(--line-strong)}
.wz-ta:focus{border-color:var(--accent);box-shadow:var(--ring);outline:none}
.wz-ta::placeholder{color:var(--text-mut)}

.wz-pickbar{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.wz-pickbar .input{flex:1 1 240px;min-width:200px}
.wz-createrow{display:flex;gap:10px;align-items:center;margin-top:10px;padding:12px 12px;
  border:1px dashed var(--accent-line);border-radius:var(--radius-sm);background:var(--accent-soft)}
.wz-createrow .input{flex:1 1 auto}

.wz-avail{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px;max-height:172px;overflow-y:auto;
  padding:2px}
.wz-av{display:inline-flex;align-items:center;gap:8px;padding:6px 6px 6px 14px;border-radius:var(--radius-pill);
  border:1px solid var(--line);background:var(--panel-2);font-size:13px;font-weight:600;
  color:var(--text-dim);transition:var(--tr)}
.wz-av:hover{border-color:var(--accent-line);color:var(--text)}
.wz-av .badge-s{font-size:10px;padding:1px 6px}
.wz-plus{width:23px;height:23px;flex:0 0 23px;border-radius:50%;border:none;cursor:pointer;
  background:var(--accent-grad);color:#fff;font-size:15px;font-weight:800;line-height:1;
  display:grid;place-items:center;transition:var(--tr)}
.wz-plus:hover{filter:brightness(1.1);transform:scale(1.08)}

/* an added field: name, its value, and the controls that order or remove it */
.wz-fld{grid-template-columns:minmax(140px,178px) 1fr auto}
.wz-fldname{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13px;
  font-weight:600;color:var(--text-dim)}
.wz-fldname .badge-s{font-size:10px;padding:1px 6px}
.wz-fldact{display:flex;gap:6px;align-items:center}
.wz-mini{width:27px;height:27px;border-radius:10px;border:1px solid var(--line);cursor:pointer;
  background:var(--panel-2);color:var(--text-mut);font-size:12px;line-height:1;
  display:grid;place-items:center;transition:var(--tr)}
.wz-mini:hover:not(:disabled){border-color:var(--accent-line);color:var(--text)}
.wz-mini:disabled{opacity:.32;cursor:default}
.wz-mini.danger:hover:not(:disabled){border-color:var(--danger);color:var(--danger);
  background:var(--danger-soft)}

.wz-modes{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.wz-mode{display:flex;gap:12px;align-items:flex-start;padding:14px 14px;cursor:pointer;
  border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--panel-2);
  transition:var(--tr)}
.wz-mode:hover{border-color:var(--accent-line)}
.wz-mode.on{border-color:var(--accent);background:var(--accent-soft)}
.wz-mode .t{font-size:13px;font-weight:700;color:var(--text)}
.wz-mode .n{font-size:12px;color:var(--text-mut);margin-top:4px;line-height:1.5}

.wz-copies{display:flex;gap:18px;align-items:flex-end;flex-wrap:wrap;margin-top:20px;
  padding:14px 16px;border:1px solid var(--line);border-radius:var(--radius);background:var(--panel-2)}
.wz-tally{font-size:13px;color:var(--text-mut);line-height:1.6;padding-bottom:10px}
.wz-tally b{color:var(--text);font-weight:700}

@media (max-width:900px){
  .wz-fld{grid-template-columns:1fr}
  .wz-modes{grid-template-columns:1fr}
  .wz-fldact{justify-content:flex-end}
}

/* ---- incoming-material testing (GRN testing) --------------------------------
   Two standing notices in the test form and on a purchase order: an
   explanatory one (this material has no parameter list / no limits yet, so the
   readings are recorded rather than graded) and a FAILED one, which has to read
   as a problem the office must act on — the goods are already in stock by the
   time a lot fails, so this notice is the only thing standing between a failed
   delivery and it being used. */
.qc-note{padding:10px 12px;border:1px solid var(--line);border-left:3px solid var(--warn,#d99a2b);
  border-radius:var(--radius);background:var(--panel-2);color:var(--text-dim);line-height:1.6}
.qc-note.bad{border-left-color:var(--danger,#d64545);color:var(--danger,#d64545);
  background:var(--danger-soft,#fdecec);font-weight:600}

/* the admin parameter picker: one row per parameter — tick on the left, its
   min/max on the right, dimmed until the parameter is actually asked for */
.qc-plist{display:flex;flex-direction:column;gap:2px}
.qc-prow{display:grid;grid-template-columns:1fr 210px;gap:12px;align-items:center;
  padding:8px 10px;border-radius:10px}
.qc-prow:nth-child(odd){background:var(--panel-2)}
.qc-pchk{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:13px}
.qc-plbl{font-weight:600}
.qc-plim{display:flex;align-items:center;gap:8px;transition:opacity .15s}
.qc-plim .input{padding:6px 8px;font-size:12px;text-align:right}
.qc-pdash{color:var(--text-mut);font-size:12px}
@media (max-width:700px){
  .qc-prow{grid-template-columns:1fr;gap:6px}
  .qc-plim{justify-content:flex-start}
}

/* ============================================================
   LABEL STUDIO — the label designer
   Inventory ▸ Label Studio.

     ribbon                Clipboard · Font · Paragraph · Spacing
     Tools | canvas | Object Properties over Object Layers
     document tabs
     status bar            label size · view · zoom

   WHY THIS ONE SCREEN IS NOT IN THE APP'S THEME.
   Everywhere else in the ERP a panel is a panel and takes the
   operator's chosen accent and dark or light mode. This screen is a
   different kind of thing: it is a WINDOW onto a sheet of white
   label stock, and the colour of the label is the colour of the
   label. A dark grey canvas with an orange selection handle tells
   you nothing true about what will come out of the printer, and a
   designer that re-tints itself between two machines in the same
   plant is a designer two people cannot talk about over the phone.
   So the studio paints its own light chrome from the tokens below —
   scoped to .ls, so nothing outside this screen is touched — and
   the label in the middle of it is white because it is white.

   The dialogs (Properties, Page setup, Print, Label layout) open in
   the app's own modal, outside .ls, and so keep the app's theme.
   That is deliberate: they belong to the ERP, not to the window.
   ============================================================ */
.ls{
  /* the window's own palette */
  --lsw:#ffffff;              /* panels */
  --lsbar:#f8f9fa;            /* ribbon, toolbars, tab strip */
  --lsstage:#f1f3f4;          /* the desk the label lies on */
  --lsline:#dadce0;           /* structural rules */
  --lsline2:#e9eaec;          /* rules inside a group */
  --lstx:#202124;             /* type */
  --lsdim:#5f6368;            /* labels, captions, ticks */
  --lsblue:#1a73e8;           /* selection, pressed, the label's own accent */
  --lssoft:#e8f0fe;           /* pressed / selected fill */
  --lssoft2:#d2e3fc;          /* pressed / selected border */
  --ls-toolsw:140px;
  --ls-rightw:210px;

  display:flex;flex-direction:column;
  /* The height is MEASURED and set inline by fitStudio() — see the note there.
     This is only the floor it can never go below, and the value used for the
     one frame before the measurement lands. */
  height:calc(100vh - 194px);min-height:520px;
  border:1px solid var(--lsline);border-radius:10px;overflow:hidden;
  position:relative;
  background:var(--lsw);color:var(--lstx);
  box-shadow:0 1px 2px rgba(60,64,67,.18),0 6px 22px rgba(60,64,67,.12);
  font-family:'Segoe UI',system-ui,-apple-system,Roboto,'Helvetica Neue',sans-serif;
  font-size:12px;
  -webkit-font-smoothing:antialiased;
}
.ls .sp{flex:1 1 auto}
.ls-ic{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto}
.ls-ic svg{display:block}

/* The gallery of saved labels is an ERP page, not the window — it keeps the
   app's own theme, and the fixed-height frame comes off. */
.ls.ls-browse{height:auto;min-height:0;border:0;border-radius:0;overflow:visible;
  background:transparent;color:inherit;font-family:var(--font);font-size:inherit}

/* ============================================================
   THE RIBBON
   ============================================================ */
/* The groups scroll in a strip of their own; the size block beside it never
   leaves the screen — it carries the way back to the library. */
.ls-ribbon{display:flex;flex-direction:column;flex:0 0 auto;
  padding:0 6px 0;border-bottom:1px solid var(--lsline);
  background:linear-gradient(180deg,#fdfdfe,var(--lsbar));
  overflow:hidden}
.ls-rscroll{display:flex;align-items:stretch;flex:1 1 auto;min-width:0;
  overflow-x:auto;overflow-y:hidden;scrollbar-width:thin}
.ls-rg{display:flex;flex-direction:column;justify-content:space-between;
  padding:0 10px;border-right:1px solid var(--lsline2);flex:0 0 auto}
.ls-rgc{display:flex;align-items:flex-start;padding:3px 0 2px}
.ls-rgb{display:flex;align-items:flex-start;gap:5px}
.ls-rcol{display:flex;flex-direction:column;gap:2px}
.ls-rstack{justify-content:center;gap:1px;padding-top:1px}
.ls-rrow{display:flex;align-items:center;gap:2px}
.ls-rsep{width:1px;height:18px;margin:0 3px;background:var(--lsline)}
.ls-rgl{text-align:center;font-size:10.5px;color:var(--lsdim);padding:1px 0 3px;
  white-space:nowrap}
.ls-rico{display:inline-flex;align-items:center;justify-content:center;
  width:24px;height:26px;color:var(--lsdim)}
.ls-rico.off{opacity:.36}

/* ============================================================
   THE SIZE BLOCK — top right, in the corner the ribbon leaves.
   ============================================================ */
.ls-docbox{flex:0 0 auto;align-self:center;display:flex;align-items:center;gap:6px;
  margin:0 2px 6px 12px;padding:4px 5px 4px 3px;
  border:1px solid var(--lsline);border-radius:8px;background:#fff;
  box-shadow:0 1px 2px rgba(60,64,67,.08)}
.ls-dsize{padding:3px 9px;border:1px solid transparent;border-radius:5px;background:transparent;
  color:var(--lstx);font-family:inherit;font-size:12px;font-weight:600;cursor:pointer;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.ls-dsize:hover{background:var(--lssoft);border-color:var(--lssoft2);color:var(--lsblue)}
.ls-dmode{font-size:10.5px;color:var(--lsdim);white-space:nowrap;
  padding:1px 6px;border-radius:9px;background:var(--lsstage)}
/* full screen, tucked in beside the size */
.ls-rfs{width:24px;height:22px;flex:0 0 auto;display:flex;
  align-items:center;justify-content:center;border:1px solid transparent;border-radius:4px;
  background:transparent;color:var(--lsdim);cursor:pointer;padding:0}
.ls-rfs:hover{background:var(--lssoft);border-color:var(--lssoft2);color:var(--lsblue)}
/* ---- the way out, in the top-right corner ----
   Given a word as well as an arrow, and set off by a rule from the size block,
   because it is the one control on this screen somebody hunts for without
   knowing the toolbar. The arrow is the shared "chev" glyph turned a quarter
   turn anticlockwise — one icon, pointed whichever way a button needs it. */
.ls-exit{display:flex;align-items:center;gap:4px;flex:0 0 auto;height:24px;
  margin-left:2px;padding:0 9px 0 5px;border:1px solid transparent;border-radius:6px;
  background:transparent;color:var(--lstx);font-family:inherit;font-size:12px;
  font-weight:600;white-space:nowrap;cursor:pointer;transition:var(--tr)}
.ls-exit::before{content:"";width:1px;height:16px;margin-right:5px;
  background:var(--lsline)}
.ls-exit svg{transform:rotate(90deg)}
.ls-exit:hover{background:var(--lssoft);border-color:var(--lssoft2);color:var(--lsblue)}

/* ---- the three shapes of ribbon button ---- */
.ls-b{display:flex;align-items:center;justify-content:center;gap:3px;
  min-width:26px;height:26px;padding:0 4px;border:1px solid transparent;border-radius:4px;
  background:transparent;color:#3c4043;font-family:inherit;font-size:12.5px;line-height:1;
  cursor:pointer;transition:background .12s,border-color .12s}
.ls-b:hover:not(.off){background:var(--lssoft);border-color:var(--lssoft2)}
.ls-b.on{background:var(--lssoft);border-color:var(--lssoft2);color:var(--lsblue)}
.ls-b.off{opacity:.36;cursor:default}
.ls-bt{display:inline-flex;align-items:center;line-height:1}
.ls-bt i{font-style:normal;font-size:7px;margin-left:1px;position:relative;top:-1px}
.ls-fx-b .ls-bt{font-weight:800;font-family:Georgia,'Times New Roman',serif}
.ls-fx-i .ls-bt{font-style:italic;font-weight:600;font-family:Georgia,'Times New Roman',serif}
.ls-fx-u .ls-bt{text-decoration:underline;text-underline-offset:2px;
  font-family:Georgia,'Times New Roman',serif}
.ls-fx-a .ls-bt{font-weight:600}

.ls-bb{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:2px;
  width:58px;padding:4px 2px 2px;border:1px solid transparent;border-radius:4px;
  background:transparent;color:#3c4043;font-family:inherit;font-size:10.5px;line-height:1.15;
  cursor:pointer;transition:background .12s,border-color .12s}
.ls-bb:hover:not(.off){background:var(--lssoft);border-color:var(--lssoft2)}
.ls-bb.on{background:var(--lssoft);border-color:var(--lssoft2);color:var(--lsblue)}
.ls-bb.off{opacity:.36;cursor:default}
.ls-bbl{white-space:pre-line;text-align:center}

.ls-bs{display:flex;align-items:center;gap:5px;width:100%;height:19px;padding:0 5px;
  border:1px solid transparent;border-radius:3px;background:transparent;color:#3c4043;
  font-family:inherit;font-size:11px;line-height:1;text-align:left;cursor:pointer;
  transition:background .12s,border-color .12s}
.ls-bs:hover:not(.off){background:var(--lssoft);border-color:var(--lssoft2)}
.ls-bs.off{opacity:.36;cursor:default}

/* ---- ribbon fields ---- */
.ls-sel{height:24px;padding:0 3px;border:1px solid var(--lsline);border-radius:3px;
  background:#fff;color:var(--lstx);font-family:inherit;font-size:11.5px;cursor:pointer}
.ls-sel:focus{outline:none;border-color:var(--lsblue);box-shadow:0 0 0 1px var(--lsblue)}
.ls-sel:disabled{opacity:.5;background:#f5f6f7;cursor:default}
.ls-num{width:56px;height:24px;padding:0 2px 0 6px;border:1px solid var(--lsline);
  border-radius:3px;background:#fff;color:var(--lstx);font-family:inherit;font-size:11.5px}
.ls-num:focus{outline:none;border-color:var(--lsblue);box-shadow:0 0 0 1px var(--lsblue)}
.ls-num:disabled{opacity:.5;background:#f5f6f7}
.ls-unit{font-size:10px;color:var(--lsdim);padding:0 2px}
/* the colour chip: a swatch (or a letter over a colour bar) that opens the palette */
.ls-swatch{position:relative;display:inline-flex;align-items:center;gap:3px;height:26px;
  padding:0 4px;border:1px solid transparent;border-radius:4px;background:transparent;
  color:var(--lsdim);cursor:pointer;margin:0;font-family:inherit}
.ls-swatch:hover:not(.off){background:var(--lssoft);border-color:var(--lssoft2)}
.ls-swatch.off{opacity:.36;cursor:default}
.ls-swc{display:block;width:16px;height:16px;border:1px solid #9aa0a6;border-radius:2px;
  flex:0 0 auto}
.ls-swc.none{background:
  linear-gradient(45deg,transparent 44%,#d93025 44%,#d93025 56%,transparent 56%),#fff}
.ls-cw{display:flex;flex-direction:column;align-items:center;gap:2px;line-height:1}
.ls-cglyph{font-size:11px;font-weight:700;color:var(--lstx);line-height:1}
.ls-swc.bar{width:16px;height:4px;border-radius:1px;border:0;box-shadow:inset 0 0 0 1px rgba(0,0,0,.18)}
.ls-swin{position:absolute;left:0;top:0;width:1px;height:1px;opacity:0;
  border:0;padding:0;margin:0}
.ls-swfull{width:100%;max-width:100%;min-width:0;height:26px;border:1px solid var(--lsline);border-radius:3px;
  background:#fff;justify-content:flex-start}
.ls-swfull:hover:not(.off){background:#f8f9fa;border-color:var(--lsline)}
.ls-swt{flex:1 1 auto;text-align:left;font-size:11px;color:var(--lstx);
  font-variant-numeric:tabular-nums}

/* ---- the colour palette ---- */
.ls-cpop{position:absolute;z-index:80;width:236px;padding:8px;
  border:1px solid var(--lsline);border-radius:6px;background:#fff;
  box-shadow:0 2px 6px rgba(60,64,67,.3),0 8px 24px rgba(60,64,67,.2)}
/* ---- Insert ▸ Table's size grid (Word's rows × columns picker) ---- */
.ls-tpick{position:absolute;z-index:80;padding:8px;
  border:1px solid var(--lsline);border-radius:6px;background:#fff;
  box-shadow:0 2px 6px rgba(60,64,67,.3),0 8px 24px rgba(60,64,67,.2)}
.ls-tpick-cap{font-size:11.5px;line-height:1.3;margin:0 0 6px;white-space:nowrap;
  font-variant-numeric:tabular-nums}
.ls-tpick-grid{display:grid;grid-template-columns:repeat(10,14px);gap:2px}
.ls-tpk{width:14px;height:14px;padding:0;border:1px solid var(--lsline);border-radius:1px;
  background:#fff;cursor:pointer}
.ls-tpk.on{background:var(--lssoft2);border-color:var(--lsblue)}
.ls-chead{font-size:10px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  color:var(--lsdim);margin:8px 0 4px}
.ls-chead:first-child{margin-top:0}
.ls-cgrid{display:grid;grid-template-columns:repeat(8,1fr);gap:3px}
.ls-cs{width:100%;aspect-ratio:1/1;min-height:20px;padding:0;cursor:pointer;
  border:1px solid rgba(0,0,0,.16);border-radius:3px}
.ls-cs:hover{transform:scale(1.14);border-color:var(--lstx)}
.ls-cs.on{box-shadow:0 0 0 2px #fff,0 0 0 3.5px var(--lsblue)}
.ls-cnone{display:flex;align-items:center;gap:7px;width:100%;padding:5px 6px;margin-bottom:2px;
  border:1px solid var(--lsline);border-radius:4px;background:#fff;color:var(--lstx);
  font-family:inherit;font-size:11.5px;cursor:pointer}
.ls-cnone:hover{background:var(--lssoft);border-color:var(--lssoft2)}
.ls-crow{display:flex;gap:4px}
.ls-chex{flex:1 1 auto;min-width:0;height:26px;padding:0 6px;border:1px solid var(--lsline);
  border-radius:3px;background:#fff;color:var(--lstx);font-family:var(--mono),monospace;
  font-size:11.5px;text-transform:uppercase}
.ls-chex:focus{outline:none;border-color:var(--lsblue);box-shadow:0 0 0 1px var(--lsblue)}
.ls-cok{flex:0 0 auto;height:26px;padding:0 10px;border:1px solid var(--lsline);border-radius:3px;
  background:var(--lsbar);color:var(--lstx);font-family:inherit;font-size:11.5px;cursor:pointer}
.ls-cok:hover{background:var(--lssoft);border-color:var(--lssoft2);color:var(--lsblue)}
.ls-cmore{position:relative;display:flex;align-items:center;gap:7px;margin-top:8px;padding:6px;
  border-top:1px solid var(--lsline2);color:var(--lsblue);font-size:11.5px;cursor:pointer}
.ls-cmore:hover{background:var(--lssoft);border-radius:4px}

/* ---- the typable combo: a box you can type in, with the list on the caret ---- */
.ls-combo{display:inline-flex;align-items:stretch;height:24px;border:1px solid var(--lsline);
  border-radius:3px;background:#fff;overflow:hidden}
.ls-combo:focus-within{border-color:var(--lsblue);box-shadow:0 0 0 1px var(--lsblue)}
.ls-combo.off{opacity:.5;background:#f5f6f7}
.ls-cin{flex:1 1 auto;min-width:0;width:100%;height:100%;padding:0 4px 0 6px;border:0;
  background:transparent;color:var(--lstx);font-family:inherit;font-size:11.5px;
  font-variant-numeric:tabular-nums}
.ls-cin:focus{outline:none}
.ls-ccar{flex:0 0 auto;width:18px;display:flex;align-items:center;justify-content:center;
  border:0;border-left:1px solid var(--lsline2);background:var(--lsbar);color:var(--lsdim);
  cursor:pointer;padding:0}
.ls-ccar:hover{background:var(--lssoft);color:var(--lsblue)}
.ls-fr .ls-combo,.ls-frow .ls-combo{height:26px}

/* ============================================================
   THE WORKSPACE
   ============================================================ */
.ls-body{flex:1 1 auto;min-height:0;display:grid}
.ls-body>*{min-width:0;min-height:0}

.ls-panel{display:flex;flex-direction:column;min-height:0;background:var(--lsw)}
.ls-ph{display:flex;align-items:center;gap:6px;height:27px;flex:0 0 auto;padding:0 5px 0 9px;
  border-bottom:1px solid var(--lsline);background:var(--lsbar);
  font-size:12px;font-weight:600;color:#3c4043;white-space:nowrap}
.ls-px{margin-left:auto;width:19px;height:19px;display:flex;align-items:center;
  justify-content:center;border:0;border-radius:3px;background:transparent;color:var(--lsdim);
  cursor:pointer;padding:0;flex:0 0 auto}
.ls-px:hover{background:#e8eaed;color:var(--lstx)}

/* ---- Tools ---- */
.ls-tools{border-right:1px solid var(--lsline)}
.ls-tlist{flex:1 1 auto;min-height:0;overflow:auto;padding:5px 4px}
.ls-tool{position:relative;display:flex;align-items:center;gap:9px;width:100%;height:30px;
  padding:0 8px 0 10px;border:1px solid transparent;border-radius:5px;background:transparent;
  color:#3c4043;font-family:inherit;font-size:12px;text-align:left;cursor:pointer;
  transition:background .12s,border-color .12s,color .12s}
.ls-tool:hover{background:#f1f3f4}
.ls-tool.on{background:var(--lssoft);border-color:var(--lssoft2);color:var(--lsblue);
  font-weight:600}
/* a bar down the left of the armed tool: which tool is live, read at a glance */
.ls-tool.on::before{content:"";position:absolute;left:-1px;top:5px;bottom:5px;width:3px;
  border-radius:0 3px 3px 0;background:var(--lsblue)}
.ls-tool .ls-ic{color:var(--lsdim)}
.ls-tool.on .ls-ic{color:var(--lsblue)}
.ls-tooll{flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* ---- the centre: canvas toolbar over the stage ---- */
.ls-centre{display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--lsstage)}
.ls-ctb{display:flex;align-items:center;gap:2px;height:32px;flex:0 0 auto;padding:0 8px;
  border-bottom:1px solid var(--lsline);background:var(--lsbar);overflow-x:auto}
.ls-ctb .ls-b{color:var(--lsdim)}
.ls-ctbsep{width:1px;height:18px;margin:0 7px;background:var(--lsline);flex:0 0 auto}
.ls-canvas-wrap{display:flex;flex-direction:column;min-width:0;min-height:0;flex:1 1 auto}
/* The desk the label lies on: a soft vignette so the white sticker reads as a
   physical thing sitting on a surface rather than a hole in the panel. */
.ls-stage{flex:1 1 auto;min-height:0;overflow:auto;display:flex;align-items:center;
  justify-content:center;padding:28px;
  background:radial-gradient(120% 100% at 50% 0%,#fafbfc 0%,var(--lsstage) 70%)}
.ls-canvas{position:relative;flex:0 0 auto;outline:none;border-radius:4px;
  box-shadow:0 0 0 1px rgba(60,64,67,.14),0 2px 5px rgba(60,64,67,.2),
    0 12px 28px rgba(60,64,67,.14)}
.ls-canvas:focus-visible{box-shadow:0 1px 3px rgba(60,64,67,.28),0 6px 14px rgba(60,64,67,.14),
  0 0 0 2px var(--lssoft2)}
.ls-canvas.arm{cursor:crosshair;touch-action:none}
.ls-layer{position:absolute;left:0;top:0;overflow:hidden;pointer-events:none}
.ls-skin{position:absolute;inset:0}
/* ---- A DRAG ON THE LABEL BELONGS TO THE LABEL ----
   Move, resize and draw are pointer gestures. On a touch screen the browser
   claims a drag for panning unless it is told otherwise, and it claims it
   from the first millimetre — so the object never moved on any phone or
   tablet. Only the parts that are dragged say none: bare label keeps its
   pan, which is how a label wider than the screen is reached at all. */
.ls-hit{position:absolute;cursor:move;border:1px dashed transparent;touch-action:none}
.ls-hit:hover{border-color:rgba(26,115,232,.5)}
.ls-hit.on{border:1px dashed var(--lsblue)}
.ls-canvas.arm .ls-hit{pointer-events:none}
.ls-band{position:absolute;border:1px dashed var(--lsblue);background:rgba(26,115,232,.1);
  pointer-events:none}
/* ---- a multi-selection: one dashed box round the lot ---- */
.ls-selbox{position:absolute;pointer-events:none;border:1px dashed var(--lsblue);
  outline:1px dashed rgba(255,255,255,.7);outline-offset:-2px}
.ls-selcount{position:absolute;left:0;top:-17px;padding:1px 6px;border-radius:4px 4px 0 0;
  background:var(--lsblue);color:#fff;font-size:9.5px;font-weight:600;line-height:1.6;
  white-space:nowrap}
/* ---- smart guides: the line an object just snapped to ---- */
.ls-guides{position:absolute;inset:0;pointer-events:none;overflow:hidden}
.ls-g{position:absolute;background:#e8710a;opacity:.9}
.ls-g.v{top:-6px;bottom:-6px;width:1px;margin-left:-.5px}
.ls-g.h{left:-6px;right:-6px;height:1px;margin-top:-.5px}
/* a centre line reads differently from an edge line, so it is drawn dashed */
.ls-g.mid{background:repeating-linear-gradient(var(--dir,180deg),
  #d926a9 0 4px,transparent 4px 8px)}
.ls-g.v.mid{--dir:180deg}
.ls-g.h.mid{--dir:90deg}
/* the background picture's own box, in Custom fit — amber, so it can never be
   mistaken for a selected object */
.ls-bghit{position:absolute;cursor:move;border:1px dashed #e8710a;
  background:rgba(232,113,10,.05)}
.ls-bghit:hover{background:rgba(232,113,10,.1)}
.ls-bghit .ls-h{background:#e8710a}
/* the tag IS the way out of adjusting, so it takes clicks */
.ls-bgtag{position:absolute;left:-1px;top:-18px;display:flex;align-items:center;gap:4px;
  height:18px;padding:0 6px;border:0;border-radius:4px 4px 0 0;
  background:#e8710a;color:#fff;font-family:inherit;font-size:10px;font-weight:600;
  line-height:1;white-space:nowrap;cursor:pointer}
.ls-bgtag:hover{background:#c85f08}
.ls-armhint{flex:0 0 auto;padding:5px 8px;font-size:11.5px;font-weight:600;
  color:var(--lsblue);text-align:center;background:var(--lssoft);
  border-top:1px solid var(--lssoft2)}
/* the eight grips, on the selected object only */
/* 7px is a mouse's target. A thumb cannot find it, so resizing did not
   exist on touch. The dot stays 7px to the eye — ::after grows only the
   reachable area around it, and only where the pointer is coarse. */
.ls-h{position:absolute;width:7px;height:7px;background:var(--lsblue);touch-action:none;
  border:1px solid #fff;border-radius:1px;box-shadow:0 0 1px rgba(0,0,0,.35)}
.ls-h-nw{left:-4px;top:-4px;cursor:nwse-resize}
.ls-h-n {left:calc(50% - 3.5px);top:-4px;cursor:ns-resize}
.ls-h-ne{right:-4px;top:-4px;cursor:nesw-resize}
.ls-h-e {right:-4px;top:calc(50% - 3.5px);cursor:ew-resize}
.ls-h-se{right:-4px;bottom:-4px;cursor:nwse-resize}
.ls-h-s {left:calc(50% - 3.5px);bottom:-4px;cursor:ns-resize}
.ls-h-sw{left:-4px;bottom:-4px;cursor:nesw-resize}
.ls-h-w {left:-4px;top:calc(50% - 3.5px);cursor:ew-resize}
@media (pointer:coarse){
  .ls-h::after{content:"";position:absolute;left:50%;top:50%;width:32px;height:32px;
    transform:translate(-50%,-50%)}
}
/* ---- a table's inner borders: 6px strips to drag (Word's cursor), a 1px
   blue line down / across the middle on hover; 14px on a coarse pointer ---- */
.ls-tbh{position:absolute;touch-action:none}
.ls-tbh[data-ax="c"]{cursor:col-resize}
.ls-tbh[data-ax="r"]{cursor:row-resize}
.ls-tbh[data-ax="c"]:hover{background:linear-gradient(90deg,transparent calc(50% - .5px),
  var(--lsblue) calc(50% - .5px),var(--lsblue) calc(50% + .5px),transparent calc(50% + .5px))}
.ls-tbh[data-ax="r"]:hover{background:linear-gradient(180deg,transparent calc(50% - .5px),
  var(--lsblue) calc(50% - .5px),var(--lsblue) calc(50% + .5px),transparent calc(50% + .5px))}
@media (pointer:coarse){
  .ls-tbh[data-ax="c"]{width:14px!important;margin-left:-4px}
  .ls-tbh[data-ax="r"]{height:14px!important;margin-top:-4px}
}

/* ---- rulers ----
   A two-by-two grid: corner, horizontal rule, vertical rule, label. Because
   the label is a grid cell rather than something the rules are positioned
   against, they stay pinned to its edges at every zoom. */
.ls-rig{display:grid;grid-template-columns:19px auto;grid-template-rows:19px auto;flex:0 0 auto;
  margin:auto}
.ls-corner{grid-area:1/1;display:flex;align-items:center;justify-content:center;
  font-size:8px;font-weight:600;color:var(--lsdim);background:#fff;
  border:1px solid var(--lsline);border-right:0;border-bottom:0}
.ls-ruler{position:relative;background:#fff;border:1px solid var(--lsline);overflow:hidden}
.ls-ruler.h{grid-area:1/2;height:19px;border-bottom:0}
.ls-ruler.v{grid-area:2/1;width:19px;border-right:0}
.ls-ruler .tk{position:absolute;background:#9aa0a6}
.ls-ruler.h .tk{bottom:0;width:1px;height:3px}
.ls-ruler.h .tk.md{height:6px}
.ls-ruler.h .tk.mj{height:9px;background:#5f6368}
.ls-ruler.v .tk{right:0;height:1px;width:3px}
.ls-ruler.v .tk.md{width:6px}
.ls-ruler.v .tk.mj{width:9px;background:#5f6368}
.ls-ruler .tn{position:absolute;font-size:8px;font-weight:500;color:var(--lsdim);
  font-style:normal;font-variant-numeric:tabular-nums;line-height:1}
.ls-ruler.h .tn{top:2px;transform:translateX(2px)}
.ls-ruler.v .tn{left:2px;transform:translateY(1px)}
.ls-rig .ls-canvas{grid-area:2/2;border-radius:0 4px 4px 4px}

/* ---- the right rail: properties over layers ---- */
.ls-right{display:flex;flex-direction:column;min-height:0;overflow:hidden;
  background:var(--lsw);border-left:1px solid var(--lsline)}
.ls-props{flex:1 1 auto;min-height:0}
.ls-layers{flex:0 0 auto;max-height:44%;border-top:1px solid var(--lsline)}
/* NOTHING IN THIS PANEL MAY SCROLL SIDEWAYS.
   It used to. A field row was a flex line of "label … control", and the
   controls carry width:100% — which in a flex line resolves against the whole
   row, not the space left over, so a select sat at the full panel width with
   its label pushed off the side. Rows are a GRID now: a column for the name
   that is allowed to shrink, and a fixed column for the control. The body
   scrolls up and down only, and the horizontal axis is clipped as a backstop
   so no future field can bring the bar back. */
.ls-pbody{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;
  padding:9px 10px 14px;display:flex;flex-direction:column;gap:10px}
.ls-pbody>*{max-width:100%;min-width:0}
.ls-ptype{display:flex;align-items:center;gap:7px;font-size:12.5px;font-weight:600;
  color:var(--lstx);padding-bottom:2px;min-width:0}
.ls-ptype>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ls-ptype .ls-ic{color:var(--lsdim)}
.ls-f{display:flex;flex-direction:column;gap:4px;min-width:0;max-width:100%}
.ls-fr{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,106px);
  align-items:center;gap:8px;min-width:0;max-width:100%}
.ls-fr>*{min-width:0;max-width:100%}
.ls-fr>.ls-frow{justify-content:flex-end}
.ls-fl{font-size:11px;color:var(--lsdim);line-height:1.3;min-width:0;overflow-wrap:break-word}
.ls-frow{display:flex;align-items:center;gap:3px;min-width:0;max-width:100%}
.ls-frow>*{min-width:0}
.ls-frow>.ls-in,.ls-frow>.ls-combo,.ls-frow>.ls-swatch{flex:1 1 auto;min-width:54px}
.ls-frow>.ls-b{flex:0 0 auto}
.ls-fgrid{gap:2px}
/* the panel's buttons are a shade narrower than the ribbon's — four of them
   plus a field have to share 190 px */
.ls-pbody .ls-b{min-width:24px;padding:0 3px}
.ls-in{width:100%;max-width:100%;min-width:0;height:26px;padding:0 6px;
  border:1px solid var(--lsline);border-radius:3px;
  background:#fff;color:var(--lstx);font-family:inherit;font-size:12px}
.ls-in:focus{outline:none;border-color:var(--lsblue);box-shadow:0 0 0 1px var(--lsblue)}
select.ls-in{padding-left:3px;cursor:pointer}
.ls-ta{min-height:26px;max-height:120px;padding:4px 6px;line-height:1.35;resize:vertical;
  overflow:auto;white-space:pre-wrap}
/* ---- the picture field: a thumbnail and a button ----
   The file input itself is hidden inside the label, because the platform's own
   control is a different size and a different set of words on every machine
   and all of them are wider than this column. */
.ls-pic{display:flex;align-items:stretch;gap:8px;min-width:0;max-width:100%}
.ls-pic-th{flex:0 0 auto;width:52px;height:52px;border-radius:6px;
  border:1px solid var(--lsline);background-color:#fff;background-size:contain;
  background-position:center;background-repeat:no-repeat;
  /* a chequerboard, so a picture with transparency reads as transparent */
  box-shadow:inset 0 0 0 100px transparent}
.ls-pic-th.none{display:flex;align-items:center;justify-content:center;
  border-style:dashed;color:#9aa0a6;background:var(--lsbar)}
.ls-pic-c{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:4px;
  justify-content:center}
.ls-pic-btn{display:flex;align-items:center;justify-content:center;gap:5px;
  height:26px;padding:0 8px;border:1px solid var(--lsline);border-radius:4px;
  background:var(--lsbar);color:var(--lstx);font-size:11.5px;cursor:pointer;
  white-space:nowrap;overflow:hidden;margin:0}
.ls-pic-btn:hover{background:var(--lssoft);border-color:var(--lsblue);color:var(--lsblue)}
.ls-pic-btn span{overflow:hidden;text-overflow:ellipsis}
.ls-pickin{position:absolute;width:1px;height:1px;opacity:0;overflow:hidden;
  border:0;padding:0;margin:-1px;clip:rect(0 0 0 0)}
.ls-pic-rm{height:22px;padding:0 8px;border:1px solid transparent;border-radius:4px;
  background:transparent;color:#c5221f;font-family:inherit;font-size:11px;cursor:pointer}
.ls-pic-rm:hover{background:#fce8e6;border-color:#f5c6c2}

/* a proper full-width button inside the panel — "Adjust on canvas" */
.ls-pbtn{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;
  height:28px;padding:0 10px;border:1px solid var(--lsline);border-radius:5px;
  background:var(--lsbar);color:var(--lstx);font-family:inherit;font-size:11.5px;
  font-weight:600;cursor:pointer;transition:background .12s,border-color .12s,color .12s}
.ls-pbtn:hover{background:var(--lssoft);border-color:var(--lsblue);color:var(--lsblue)}
.ls-pbtn.on{background:#fef0e6;border-color:#e8710a;color:#a35200}
.ls-pbtn.on:hover{background:#fde3d0}
.ls-pchk{display:flex;align-items:center;gap:7px;font-size:11.5px;color:var(--lstx);
  cursor:pointer;margin:0}
.ls-pchk input{accent-color:var(--lsblue);margin:0}
.ls-plink{align-self:flex-start;padding:4px 0;border:0;background:transparent;
  color:var(--lsblue);font-family:inherit;font-size:11.5px;text-align:left;cursor:pointer;
  text-decoration:underline;text-underline-offset:2px}
.ls-plink.danger{color:#d93025}
.ls-pall{margin-top:2px;padding-top:9px;border-top:1px solid var(--lsline2);width:100%}
.ls-pok{font-size:11px;color:#137333;line-height:1.4}
.ls-pbad{font-size:11px;color:#c5221f;line-height:1.4}
.ls-none{font-size:11.5px;color:var(--lsdim);line-height:1.55;padding:8px 9px}
/* a named divider inside the panel, and the sentence under a field */
.ls-psec{margin:4px 0 -2px;padding-top:9px;border-top:1px solid var(--lsline2);
  font-size:10px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--lsdim)}
.ls-phint{font-size:10.5px;color:var(--lsdim);line-height:1.45;margin-top:-4px}
.ls-pmulti{padding:7px 9px;border-radius:5px;background:var(--lssoft);
  border:1px solid var(--lssoft2);color:#174ea6;font-size:10.5px;line-height:1.5}
/* "you are editing something that is not drawn" — amber, and it carries the cure */
.ls-phid{display:flex;flex-direction:column;gap:7px;padding:8px 9px;border-radius:5px;
  background:#fef7e0;border:1px solid #f3d68a;color:#8a5300;font-size:10.5px;line-height:1.5}
.ls-phid .btn{align-self:flex-start;height:26px;padding:0 10px;font-size:11px}
.ls-pover{display:flex;flex-direction:column;gap:7px;padding:8px 9px;border-radius:5px;
  background:#fce8e6;border:1px solid #f5c6c2;color:#a50e0e;font-size:10.5px;line-height:1.5}
.ls-pover .ls-pbtn{background:#fff;border-color:#f0a9a3;color:#a50e0e}
.ls-pover .ls-pbtn:hover{background:#fff0ee;border-color:#d93025;color:#a50e0e}

/* ---- Object Layers ---- */
.ls-llist{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;padding:3px 0}
.ls-lrow{display:flex;align-items:center;gap:6px;height:26px;padding:0 8px 0 5px;
  cursor:pointer;font-size:12px;color:#3c4043;user-select:none}
.ls-lrow:hover{background:#f1f3f4}
.ls-lrow.on{background:var(--lssoft);color:var(--lsblue);font-weight:600}
.ls-lrow.off .ls-lnm{opacity:.45;text-decoration:line-through}
.ls-lnm{flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ls-eye{width:20px;height:20px;flex:0 0 auto;display:flex;align-items:center;
  justify-content:center;border:0;border-radius:3px;background:transparent;
  color:var(--lsdim);cursor:pointer;padding:0}
.ls-eye:hover{background:#e8eaed;color:var(--lstx)}
.ls-lrow.on .ls-eye{color:var(--lsblue)}

/* ============================================================
   DOCUMENT TABS — one per label, along the foot.
   ============================================================ */
.ls-tabs{display:flex;align-items:stretch;gap:3px;height:30px;flex:0 0 auto;padding:3px 8px 0;
  border-top:1px solid var(--lsline);background:var(--lsstage);overflow-x:auto}
.ls-tab{display:flex;align-items:center;gap:5px;flex:0 0 auto;height:27px;padding:0 4px 0 12px;
  border:1px solid var(--lsline);border-bottom:0;border-radius:6px 6px 0 0;background:#eceff1;
  color:var(--lsdim);font-size:11.5px;cursor:pointer;user-select:none;
  transition:background .12s,color .12s}
.ls-tab:hover{background:#f4f6f7;color:var(--lstx)}
.ls-tab.on{background:var(--lsw);color:var(--lstx);font-weight:600;
  box-shadow:inset 0 2px 0 var(--lsblue)}
.ls-tabn{max-width:170px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ls-tabd{color:var(--lsblue);font-size:15px;line-height:0}
.ls-tabx{width:17px;height:17px;flex:0 0 auto;display:flex;align-items:center;
  justify-content:center;border:0;border-radius:3px;background:transparent;
  color:var(--lsdim);cursor:pointer;padding:0;opacity:.5}
.ls-tabx:hover{background:#fce8e6;color:#c5221f;opacity:1}
.ls-tab.on .ls-tabx{opacity:.75}
.ls-tabadd{width:27px;height:27px;flex:0 0 auto;align-self:flex-end;display:flex;
  align-items:center;justify-content:center;border:1px dashed var(--lsline);
  border-bottom:0;border-radius:6px 6px 0 0;background:transparent;color:var(--lsdim);
  cursor:pointer;padding:0}
.ls-tabadd:hover{background:var(--lssoft);border-color:var(--lsblue);border-style:solid;
  border-bottom:0;color:var(--lsblue)}

/* ============================================================
   STATUS BAR
   ============================================================ */
.ls-status{display:flex;align-items:center;gap:14px;height:27px;flex:0 0 auto;padding:0 6px 0 12px;
  border-top:1px solid var(--lsline);background:var(--lsbar);
  font-size:11px;color:var(--lsdim);white-space:nowrap;overflow:hidden}
.ls-st-i{font-variant-numeric:tabular-nums}
.ls-st-i.bad{color:#c5221f;font-weight:600}
.ls-read{font-variant-numeric:tabular-nums;color:var(--lstx);overflow:hidden;
  text-overflow:ellipsis}
.ls-vb{width:24px;height:22px;flex:0 0 auto;display:flex;align-items:center;
  justify-content:center;border:1px solid transparent;border-radius:3px;background:transparent;
  color:var(--lsdim);cursor:pointer;padding:0}
.ls-vb:hover{background:var(--lssoft);border-color:var(--lssoft2);color:var(--lsblue)}
.ls-vb.on{background:var(--lssoft);border-color:var(--lssoft2);color:var(--lsblue)}
.ls-zpc{min-width:34px;text-align:right;font-variant-numeric:tabular-nums;color:var(--lstx)}
.ls-zsl{width:110px;flex:0 0 auto;accent-color:var(--lsblue);cursor:pointer;margin:0}
/* ⚠ THE BAR MUST NEVER BE WIDER THAN THE STUDIO. Its prose did not shrink,
   so on a phone held sideways (844px) the bar ran 40px past the edge — and a
   mobile browser answers an overflowing page by widening the layout viewport
   to fit it, which clipped the right edge of EVERY row of the studio, the
   way out of the designer included. The prose gives way; the controls stay. */
.ls-status{overflow:hidden;min-width:0}
.ls-st-i{flex:0 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ls-read{flex:1 1 auto;min-width:0;white-space:nowrap;text-overflow:ellipsis}

/* ============================================================
   THE CONTEXT MENU
   ============================================================ */
.ls-ctx{position:absolute;z-index:80;min-width:216px;max-height:min(70vh,520px);overflow:auto;
  padding:4px;border:1px solid var(--lsline);border-radius:6px;background:#fff;
  box-shadow:0 2px 6px rgba(60,64,67,.3),0 8px 24px rgba(60,64,67,.2)}
.ls-ctx-i{display:flex;align-items:center;gap:8px;width:100%;padding:5px 8px;border:0;
  border-radius:4px;background:transparent;color:var(--lstx);font-family:inherit;font-size:12px;
  text-align:left;cursor:pointer}
.ls-ctx-i:hover:not(.off){background:var(--lssoft)}
.ls-ctx-i.off{opacity:.4;cursor:default}
.ls-ctx-i.danger:hover:not(.off){background:#fce8e6;color:#c5221f}
.ls-ctx-m{flex:0 0 auto;width:12px;text-align:center;font-size:10px;color:var(--lsblue)}
.ls-ctx-l{flex:1 1 auto;white-space:pre}
.ls-ctx-k{flex:0 0 auto;font-size:10.5px;color:var(--lsdim)}
.ls-ctx-sep{height:1px;margin:4px 8px;background:var(--lsline2)}

/* ---- typing straight onto the label ----
   The FRAME does the vertical alignment and carries the field's shading, so
   what is being typed sits exactly where the ink will be. The textarea inside
   is transparent and borderless — the ring is on the frame. */
/* ⚠ overflow:HIDDEN, to match the label.
   This was overflow:visible so the hint chip underneath would not be clipped,
   and the cost was that text being typed sprawled straight out of its box and
   across the label — while the printed render clips it. You were editing
   something that could never come out of the printer. The hint is a separate
   element on the canvas now, so the frame can clip like the real thing. */
/* ⚠ TRANSPARENT. It used to paint an opaque white panel, which hid the
   label's background colour, its background picture and any object the text
   was sitting on — so starting to type made the design vanish and you were
   writing onto a blank rectangle. The object being edited is left out of the
   canvas render instead (labelInner's ctx.skip), so there is nothing to cover
   up: the editor draws that one object and everything behind it shows. Any
   shading the field carries is repainted inline by editText. */
.ls-editbox{position:absolute;z-index:6;display:flex;justify-content:stretch;
  border:1px solid var(--lsblue);box-shadow:0 0 0 2px var(--lssoft2);
  background:transparent;overflow:hidden}
/* a barcode's DATA is not what the object looks like, so this one does get a
   panel to read it on — just not an opaque one */
.ls-editbox.data{background:rgba(255,251,230,.93);border-color:#e8710a;
  box-shadow:0 0 0 2px rgba(232,113,10,.25)}
.ls-edit{flex:1 1 auto;min-width:0;margin:0;padding:0;border:0;outline:none;resize:none;
  background:transparent;overflow:hidden;overflow-wrap:anywhere;
  font-family:inherit;display:block}
.ls-editbox::selection,.ls-edit::selection{background:var(--lssoft2)}
/* what the keys do — a sibling of the frame, so the frame can clip */
.ls-edittip{position:absolute;z-index:7;padding:2px 7px;border-radius:0 0 4px 4px;
  background:var(--lsblue);color:#fff;font-size:9.5px;font-weight:600;line-height:1.6;
  white-space:normal;max-width:min(70vw,560px);pointer-events:none;
  font-family:'Segoe UI',system-ui,sans-serif;letter-spacing:.01em}
.ls-edittip.data{background:#e8710a}
/* ---- WORD'S WAY: the text box is contenteditable, drawn from the field's
   runs, one span per run. It fills the frame; the frame clips and scrolls. */
.ls-edit.ls-rich{width:100%;min-height:1em;cursor:text;overflow-y:auto;
  -webkit-user-select:text;user-select:text;caret-color:var(--lsblue);
  overflow-wrap:anywhere;word-break:normal}
.ls-edit.ls-rich:focus{outline:none}
.ls-edit.ls-rich span{white-space:inherit}
/* the four letter buttons Word has that this ribbon did not: S, x², x₂ */
.ls-fx-s .ls-bt{text-decoration:line-through;font-weight:600;
  font-family:Georgia,'Times New Roman',serif}
.ls-fx-v .ls-bt{font-weight:600;font-family:Georgia,'Times New Roman',serif;align-items:flex-start}
.ls-fx-v .ls-bt sup,.ls-fx-v .ls-bt sub{font-size:7.5px;line-height:0;font-weight:700;
  position:relative}
.ls-fx-v .ls-bt sup{top:-2px}
.ls-fx-v .ls-bt sub{top:4px}
/* Format Painter is loaded: the pointer says so over every object */
.ls-canvas.ls-painting,.ls-canvas.ls-painting .ls-hit{cursor:copy}
.ls-bb.on .ls-bbl{color:var(--lsblue)}
/* the text does not fit its box — said on the object, while there is still
   time to do something about it */
.ls-over{position:absolute;z-index:5;pointer-events:none;
  box-shadow:inset 0 0 0 1px #d93025}
.ls-overtag{position:absolute;right:-1px;top:-16px;padding:1px 6px;border-radius:4px 4px 0 0;
  background:#d93025;color:#fff;font-size:9.5px;font-weight:600;line-height:1.6;
  white-space:nowrap}

/* ============================================================
   FULL SCREEN
   Used by the real Fullscreen API (where only the padding matters) and as the
   fallback when the API is refused, where these rules ARE the effect.
   ============================================================ */
/* z-index 200 is DELIBERATE and must stay under the app's own overlays:
   .modal-host is 250 and .toast-stack is 400, so every dialog and every toast
   still lands ON TOP of the studio when it is filling the screen. Raising this
   above either of them would put the studio back where it was — hiding the
   Print dialog behind itself. Also under .cmdk (300), so Ctrl+K still works. */
.ls-full{position:fixed;inset:0;z-index:200;height:100vh;min-height:0;
  border:0;border-radius:0;box-shadow:none}
/* the gallery, full screen: an ERP page filling the viewport, so it scrolls */
.ls-full.ls-browse{height:100vh;overflow:auto;padding:14px 16px;background:var(--bg)}

/* ============================================================
   THE GALLERY OF SAVED LABELS
   An ERP page in the ERP's own theme — see the note at the top.
   ============================================================ */
.ls-top{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.ls-lbl{font-size:11px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  color:var(--text-mut)}
.ls-browse .sp,.ls-top .sp{flex:1 1 auto}
.ls-gal{display:flex;flex-direction:column;gap:22px}

/* ---- the banner ---- */
.ls-hero{position:relative;display:flex;align-items:center;gap:24px;flex-wrap:wrap;
  padding:26px 28px;border-radius:var(--radius-lg);border:1px solid var(--line);
  background:
    radial-gradient(760px 300px at 88% -30%, var(--accent-soft), transparent 62%),
    linear-gradient(135deg, var(--panel-2), var(--panel));
  overflow:hidden}
.ls-hero::after{content:"";position:absolute;right:-70px;bottom:-90px;width:280px;height:280px;
  border-radius:50%;background:var(--accent-soft);filter:blur(8px);pointer-events:none}
.ls-hero-l{flex:1 1 460px;min-width:0;position:relative;z-index:1}
.ls-hero-k{font-size:10.5px;font-weight:800;letter-spacing:.22em;color:var(--accent)}
.ls-hero-t{margin-top:8px;font-size:26px;font-weight:800;letter-spacing:-.02em;color:var(--text)}
.ls-hero-s{margin-top:8px;font-size:13px;color:var(--text-mut);line-height:1.65;max-width:620px}
.ls-hero-a{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:18px}

/* ---- a titled section of the start page ---- */
.ls-sec{display:flex;flex-direction:column;gap:11px}
.ls-sec-h{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.ls-search{max-width:260px;flex:0 1 260px;padding:7px 11px;font-size:12.5px}

.ls-gal-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(228px,1fr));gap:14px}
.ls-gal-none{grid-column:1/-1;padding:20px 4px;font-size:12.5px;color:var(--text-mut)}
.ls-gal-card{position:relative;display:flex;flex-direction:column;gap:7px;padding:12px;
  text-align:left;border-radius:var(--radius);border:1px solid var(--line);
  background:var(--panel-2);cursor:pointer;transition:var(--tr)}
.ls-gal-card:hover{border-color:var(--accent);background:var(--accent-soft);
  transform:translateY(-2px);box-shadow:var(--shadow-pop)}
.ls-gal-card:focus-visible{outline:none;border-color:var(--accent);box-shadow:var(--ring)}
.ls-gal-card.on{border-color:var(--accent)}
.ls-gal-pv{display:flex;align-items:center;justify-content:center;padding:8px;border-radius:10px;
  background:var(--surface-2);border:1px solid var(--line)}
.ls-gal-n{font-size:13px;font-weight:800;color:var(--text);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.ls-gal-d{font-size:11.5px;color:var(--text-mut);line-height:1.55}
.ls-gal-m{display:flex;align-items:center;gap:8px;margin-top:2px;
  font-size:11px;font-weight:700;color:var(--accent)}
.ls-gal-print{display:flex;align-items:center;gap:5px;height:26px;padding:0 10px;
  border-radius:8px;border:1px solid var(--line);background:var(--panel);
  color:var(--text-dim);font-family:inherit;font-size:11.5px;font-weight:700;cursor:pointer;
  transition:var(--tr)}
.ls-gal-print:hover{border-color:transparent;background:var(--accent-grad);color:#fff}
.ls-gal-act{position:absolute;top:8px;right:8px;display:flex;gap:3px;opacity:0;
  transition:opacity var(--tr)}
.ls-gal-card:hover .ls-gal-act,.ls-gal-card:focus-within .ls-gal-act{opacity:1}
.ls-gal-act .mini{width:24px;height:24px;border-radius:6px;border:1px solid var(--line);
  background:var(--panel);color:var(--text-mut);font-size:11px;line-height:1;padding:0;cursor:pointer}
.ls-gal-act .mini:hover{background:var(--surface-2);color:var(--text);border-color:var(--line-strong)}
.ls-gal-act .mini.danger:hover{background:var(--danger-soft);color:var(--danger);border-color:var(--danger)}

/* ============================================================
   THE DIALOGS — Properties, Page setup, Print, Label layout.
   They open in the app's own modal, outside .ls, and so keep the
   app's theme and its tokens.
   ============================================================ */
.ls-lay{display:flex;flex-direction:column;gap:12px}
.ls-lay-tabs{display:flex;gap:4px;padding:4px;border-radius:10px;border:1px solid var(--line);
  background:var(--panel-2);align-self:flex-start}
.ls-lay-tab{padding:8px 16px;border:1px solid transparent;border-radius:7px;background:transparent;
  color:var(--text-dim);font-size:12.5px;font-weight:700;cursor:pointer;transition:var(--tr)}
.ls-lay-tab:hover{background:var(--panel);color:var(--text)}
.ls-lay-tab.on{background:var(--panel);border-color:var(--accent);color:var(--accent)}
.ls-lay-sub{font-size:12px;color:var(--text-mut);line-height:1.5;margin:-2px 0 2px}
.ls-lay-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:8px;
  max-height:min(50vh,400px);overflow:auto;padding:2px}
.ls-lay-c{display:flex;flex-direction:column;align-items:center;gap:5px;padding:11px 9px 10px;
  border-radius:10px;border:1px solid var(--line);background:var(--panel-2);color:inherit;
  text-align:center;cursor:pointer;transition:var(--tr)}
.ls-lay-c:hover{border-color:var(--accent-line);background:var(--accent-soft)}
.ls-lay-c.on{border-color:var(--accent);background:var(--accent-soft);
  box-shadow:inset 0 0 0 1px var(--accent)}
.ls-lay-pv{height:60px;width:100%;display:flex;align-items:center;justify-content:center}
.ls-lay-box{border:1px solid var(--text-mut);border-radius:2px;background:var(--panel)}
.ls-lay-c:hover .ls-lay-box,.ls-lay-c.on .ls-lay-box{border-color:var(--accent)}
.ls-lay-sz{font-size:12.5px;font-weight:800;color:var(--text);font-variant-numeric:tabular-nums}
.ls-lay-n{font-size:11px;color:var(--text-mut);line-height:1.35}
.ls-lay-per{font-size:10.5px;font-weight:700;color:var(--accent)}
.ls-lay-per.bad{color:var(--danger)}
.ls-lay-custom{display:flex;flex-direction:column;gap:12px;max-width:440px}
.ls-lay-custom .field{margin:0}
.ls-lay-swap{display:flex}

/* ---- the chooser, split: set it up on the left, see it on the right ----
   The preview is sticky because the stock list scrolls: picking the 22nd
   Novajet card must not scroll the picture of what you just picked off the
   screen, which is the only reason the picture is there. */
.ls-lay-2{display:grid;grid-template-columns:minmax(0,1fr) 248px;gap:18px;align-items:start}
.ls-lay-l{display:flex;flex-direction:column;gap:12px;min-width:0}
.ls-lay-prev{position:sticky;top:0;display:flex;flex-direction:column;gap:6px;
  padding:14px 12px;border-radius:12px;border:1px solid var(--line);background:var(--panel-2)}
.ls-lay-pt{font-size:10px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;
  color:var(--text-mut)}
.ls-lay-pt+.ls-lay-one,.ls-lay-pt+.ls-lay-pagewrap{margin-top:2px}
.ls-lay-one{display:flex;align-items:center;justify-content:center;padding:10px 0 4px}
/* the label is white because a label is white — same rule as the canvas */
.ls-lay-onebox{background:#fff;border:1px solid #b9bec4;box-shadow:0 1px 4px rgba(0,0,0,.18)}
.ls-lay-cap{font-size:11px;color:var(--text-mut);text-align:center;
  font-variant-numeric:tabular-nums;line-height:1.45}
.ls-lay-cap.bad{color:var(--danger);font-weight:700}
.ls-lay-pagewrap{display:flex;justify-content:center;padding:8px 0 4px}
.ls-lay-page{position:relative;background:#fff;border:1px solid #b9bec4;
  box-shadow:0 1px 5px rgba(0,0,0,.2)}
.ls-lay-cell{position:absolute;background:#eef1f4;border:.5px solid #9aa0a6}
/* where one feed of the roll ends and the next begins */
.ls-lay-feed{position:absolute;left:0;right:0;height:0;border-top:1px dashed #c2c7cc}
.ls-lay-roll{display:flex;flex-direction:column;gap:10px;padding-top:2px}
.ls-lay-roll .field{margin:0}
.ls-lay-unver{font-size:10.5px;line-height:1.5;color:var(--warn,#c08a2e);
  border-top:1px solid var(--line);padding-top:8px;margin-top:2px}
@media (max-width:900px){
  .ls-lay-2{grid-template-columns:1fr}
  .ls-lay-prev{position:static}
}

.ls-props-dlg{display:grid;grid-template-columns:172px minmax(0,1fr);gap:20px;align-items:start}
.ls-pcats{display:flex;flex-direction:column;gap:3px}
.ls-pcat{padding:9px 11px;border-radius:8px;border:1px solid transparent;background:var(--panel-2);
  color:var(--text-dim);font-size:12.5px;font-weight:600;text-align:left;cursor:pointer;
  transition:var(--tr)}
.ls-pcat:hover{border-color:var(--line-strong);color:var(--text)}
.ls-pcat.on{border-color:transparent;background:var(--accent-grad);color:#fff}
.ls-ppanel{min-width:0}
.ls-ppanel .field{margin-bottom:12px}
.ls-ppanel .wz-sec:first-child{margin-top:0;padding-top:0;border-top:0}
.ls-setup2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:26px;align-items:start}
.ls-setup2 .wz-sec{margin:16px 0 10px;padding-top:13px;border-top:1px solid var(--line)}
.ls-setup2 .wz-sec:first-child{margin-top:0;padding-top:0;border-top:0}
.ls-setup2 .field{margin-bottom:10px}

/* ============================================================
   PRINT — THE PAGE PLANNER

   One screen. What to print down the left, every page of the run
   down the right. No tabs and no modes: a plain run and a
   hand-mixed sheet are the same list of pages, so they look the
   same and are edited the same way.
   ============================================================ */
.ls-pp{display:flex;flex-direction:column;gap:11px}

/* ---- the answer, across the top ---- */
.ls-pp-top{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:9px 13px;
  border-radius:var(--radius);border:1px solid var(--accent-line);
  background:linear-gradient(135deg,var(--accent-soft),transparent 66%),var(--panel-2)}
.ls-pp-top.bad{border-color:var(--danger);background:var(--danger-soft)}
.ls-pp-sum{display:flex;flex-direction:column;gap:1px}
.ls-pp-sum b{font-size:19px;font-weight:800;color:var(--text);line-height:1.05;
  font-variant-numeric:tabular-nums}
.ls-pp-sum span{font-size:11px;font-weight:600;color:var(--text-mut)}
.ls-pp-arrow{font-size:17px;color:var(--text-mut);opacity:.55}
.ls-pp-meta{margin-left:auto;text-align:right;font-size:12px;font-weight:700;
  color:var(--text);font-variant-numeric:tabular-nums}
.ls-pp-warn{padding:11px 15px;border-radius:var(--radius);border:1px solid var(--danger);
  background:var(--danger-soft);color:var(--danger);font-size:12.5px;font-weight:600;
  line-height:1.55}

.ls-pp-main{display:grid;grid-template-columns:minmax(0,286px) minmax(0,1fr);
  gap:16px;align-items:start}
/* the sticker and the sheet share a row — stacking them was the whole reason
   the pages strip fell below the fold */
.ls-pp-prevrow{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:14px;align-items:start}
.ls-pp-prevcol{display:flex;flex-direction:column;gap:6px;min-width:0}
.ls-pp-side{display:flex;flex-direction:column;gap:8px;min-width:0}
.ls-pp-right{display:flex;flex-direction:column;gap:10px;min-width:0}
.ls-pp-sec{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;padding-top:0;
  font-size:9.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  color:var(--text-mut)}
.ls-pp-sec:first-child{padding-top:0}
.ls-pp-h{font-size:10px;font-weight:500;letter-spacing:0;text-transform:none;
  color:var(--text-mut);line-height:1.35}
.ls-pp-note{padding:7px 10px;border-radius:9px;border:1px dashed var(--line-strong);
  background:var(--panel-2);color:var(--text-mut);font-size:10.5px;line-height:1.45}

/* ---- the designs: one CARD each ----
   The count and the start position live ON the card, under the design's own
   colour — the tinted left edge and the dot are the same custom property, set
   inline per card, so "the blue one" reads the same in the list and on any
   future key. A count of zero IS the old untick: kept, greyed, unprinted. */
.ls-pp-designs{display:flex;flex-direction:column;gap:5px}
.ls-pp-card{position:relative;display:flex;flex-direction:column;gap:5px;
  padding:7px 9px 7px 12px;border-radius:9px;
  border:1px solid var(--line);background:var(--panel);cursor:pointer;
  transition:var(--tr);overflow:hidden}
.ls-pp-card::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;
  background:var(--ppd,var(--accent))}
.ls-pp-card:hover{border-color:var(--accent-line)}
.ls-pp-card.on{border-color:var(--accent);box-shadow:var(--ring)}
.ls-pp-card.off{background:var(--panel-2)}
.ls-pp-card.off .ls-pp-dn{color:var(--text-mut)}
.ls-pp-cardrow{display:flex;align-items:center;gap:7px;min-width:0;flex-wrap:wrap}
.ls-pp-cardrow.sub{padding-left:17px;gap:5px}
/* the two numbers share the line under the name — narrow, centred, each
   behind its own small caption */
.ls-pp-cardrow.sub .ls-pp-in{flex:0 1 58px;text-align:center}
.ls-pp-dot{flex:0 0 10px;width:10px;height:10px;border-radius:50%;
  background:var(--ppd,var(--accent))}
/* THE WHOLE NAME, ALWAYS. An ellipsis hides the very thing being chosen
   between — "BOX TEMPLATE copy" and "BOX TEMPLATE copy 2" read identically
   once they are cut off. It wraps instead, however long it is. */
.ls-pp-dn{flex:1 1 auto;min-width:0;font-size:12px;font-weight:700;color:var(--text);
  white-space:normal;overflow-wrap:anywhere;line-height:1.3}
.ls-pp-x{flex:0 0 auto;font-size:11px;font-weight:700;color:var(--text-mut);
  font-variant-numeric:tabular-nums}
/* STARTS AT — small caps, and an input whose EMPTINESS is an answer */
.ls-pp-sl{flex:0 0 auto;font-size:10px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text-mut)}
.ls-pp-card .ls-pp-startin{flex:0 1 74px;padding:4px 6px;font-size:11.5px;
  text-align:center}
.ls-pp-card .ls-pp-startin::placeholder{font-size:10px;color:var(--text-mut)}
/* a design that does not exist yet — dashed, like every "add" here */
.ls-pp-addlbl{display:flex;align-items:center;justify-content:center;gap:7px;
  padding:7px 10px;border-radius:9px;border:1.5px dashed var(--line-strong);
  background:transparent;color:var(--text-mut);font-family:inherit;font-size:12.5px;
  font-weight:700;cursor:pointer;transition:var(--tr)}
.ls-pp-addlbl:hover{border-color:var(--accent);color:var(--text)}
.ls-pp-addlbl .ls-pp-plus{font-size:17px}
/* the x that takes an added design back out of the run */
.ls-pp-rmlbl{flex:0 0 auto;width:22px;height:22px;display:flex;align-items:center;
  justify-content:center;border:0;border-radius:6px;background:transparent;
  color:var(--text-mut);font-size:12px;cursor:pointer;transition:var(--tr)}
.ls-pp-rmlbl:hover{background:var(--panel-3);color:var(--danger)}
/* the chooser the add button unfolds into: same-stock designs, then new */
.ls-pp-addmenu{display:flex;flex-direction:column;gap:4px;padding:9px;
  border-radius:12px;border:1.5px dashed var(--line-strong);background:var(--panel-2)}
.ls-pp-addhead{padding:2px 4px 6px;font-size:10.5px;font-weight:800;
  letter-spacing:.05em;text-transform:uppercase;color:var(--text-mut)}
.ls-pp-addrow{display:flex;align-items:center;gap:7px;padding:6px 9px;
  border-radius:8px;border:1px solid var(--line);background:var(--panel);
  color:var(--text);font-family:inherit;font-size:11.5px;font-weight:700;
  text-align:left;cursor:pointer;transition:var(--tr)}
.ls-pp-addrow:hover{border-color:var(--accent);background:var(--accent-soft)}
.ls-pp-addrow .ls-pp-dn{flex:1 1 auto;white-space:normal;overflow-wrap:anywhere}
.ls-pp-addrow .ls-pp-x{flex:0 0 auto}
.ls-pp-addrow.new{border-style:dashed;color:var(--text-dim)}
.ls-pp-addrow.new .ls-pp-plus{font-size:15px}
.ls-pp-addrow.quiet{border-color:transparent;background:transparent;
  color:var(--text-mut);font-weight:600;justify-content:center}
.ls-pp-addrow.quiet:hover{background:var(--panel-3);border-color:transparent}

/* the way into arranging pages by hand — the screen's one big decision */
.ls-pp-arrange{width:100%;height:34px;border-radius:10px;font-size:12.5px;
  font-weight:800;letter-spacing:.01em}

/* ---- fields ---- */
.ls-pp-f{display:flex;flex-direction:column;gap:3px;margin:0;min-width:0}
.ls-pp-l{font-size:11px;font-weight:600;color:var(--text-dim)}
.ls-pp-in{width:100%;min-width:0;padding:6px 9px;border-radius:8px;
  border:1px solid var(--line);background:var(--panel-2);color:var(--text);
  font-family:inherit;font-size:12.5px;font-variant-numeric:tabular-nums;transition:var(--tr)}
.ls-pp-in:focus{outline:none;border-color:var(--accent);box-shadow:var(--ring);
  background:var(--panel)}
.ls-pp-d .ls-pp-in{flex:0 0 64px;padding:6px 8px;font-size:12.5px;text-align:right}
.ls-pp-chk{display:flex;align-items:center;gap:9px;margin:0;cursor:pointer;
  font-size:12.5px;font-weight:600;color:var(--text-dim)}
.ls-pp-chk input{accent-color:var(--accent);width:16px;height:16px;margin:0;cursor:pointer}
.ls-pp-chk:hover{color:var(--text)}
.ls-pp-span{display:flex;align-items:center;gap:9px;flex-wrap:wrap;padding:9px 12px;
  border-radius:10px;border:1px solid var(--line);background:var(--panel-2)}
.ls-pp-span b{font-family:var(--mono),monospace;font-size:14px;color:var(--text)}

/* "this field reads product.name — here is what it will look like" */
.ls-bindex{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;
  padding:8px 10px;border-radius:8px;border:1px solid var(--line);
  background:var(--panel-2)}
.ls-bindex-l{font-size:10px;font-weight:800;letter-spacing:.08em;
  text-transform:uppercase;color:var(--text-mut)}
.ls-bindex b{font-size:13px;color:var(--text)}
.ls-bindex-h{flex:1 1 100%;font-size:10.5px;color:var(--text-mut)}

/* ---- the two print previews: the sticker, and the sheet it lands on ----
   Both are iframes of the REAL print HTML, so they carry the label's own white
   ground rather than the studio's chrome. The number badges sit over the sheet
   and are pointer-transparent — the iframe underneath must stay inert. */
.ls-pp-one{display:flex;justify-content:center;padding:2px 0 0}
.ls-pp-cap{font-size:10px;color:var(--text-mut);text-align:center;
  font-variant-numeric:tabular-nums;padding-bottom:4px}
.ls-pp-sheetwrap{display:flex;justify-content:center;padding:2px 0 0}
.ls-pp-sheet{position:relative;overflow:hidden;background:#fff;
  border:1px solid #b9bec4;box-shadow:0 1px 6px rgba(0,0,0,.22)}
.ls-pp-sheet iframe{border:0;display:block;pointer-events:none}
.ls-pp-num{position:absolute;display:flex;align-items:center;justify-content:center;
  pointer-events:none}
.ls-pp-num span{min-width:15px;padding:1px 4px;border-radius:20px;
  background:rgba(20,22,26,.72);color:#fff;font-size:9.5px;font-weight:800;
  line-height:1.5;font-variant-numeric:tabular-nums}
/* THE START POSITION, marked on the numbered sheet. Everything before it is
   left empty by the run, so the badge that says where it begins has to be the
   one badge you can find without counting. */
.ls-pp-num.start span{background:var(--accent);box-shadow:0 0 0 2px #fff,
  0 0 0 3.5px var(--accent);transform:scale(1.15)}

/* ---- ARRANGE BY HAND ----
   The same numbered boxes, switched on: each die-cut takes a click or a drag
   and writes straight into the plan the printer reads. The states are drawn
   on the BOX (a border over the sheet), never by moving the number — the
   number is the print order and holds still while stickers change hands. */
.ls-pp-sheet.hand .ls-pp-num{pointer-events:auto;cursor:pointer;border-radius:3px;
  touch-action:none}
.ls-pp-sheet.hand .ls-pp-num.free{border:1.5px dashed rgba(20,22,26,.25)}

/* ---- THE PAGES — every page of a hand-arranged run ----
   Thumbnails the composeHtml renderer draws, so a page's little picture is
   the very thing the printer gets. The selected one wears the accent ring;
   Add page is a card-shaped button so the strip reads as one row of pages. */
.ls-pp-pgs{display:flex;flex-wrap:wrap;gap:7px;align-items:stretch}
.ls-pp-pgc{display:flex;flex-direction:column;gap:3px;padding:5px;border-radius:9px;
  border:1px solid var(--line);background:var(--panel-2);cursor:pointer;
  transition:var(--tr)}
.ls-pp-pgc:hover{border-color:var(--accent-line)}
.ls-pp-pgc:focus-visible{outline:none;border-color:var(--accent);box-shadow:var(--ring)}
.ls-pp-pgc.on{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent)}
.ls-pp-pgn{display:flex;align-items:center;gap:4px;font-size:10px;font-weight:700;
  color:var(--text-dim)}
.ls-pp-pgn span:first-child{flex:1 1 auto}
.ls-pp-pgi{font-size:11px;opacity:.6}
.ls-pp-pgadd{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:3px;min-width:70px;border-radius:9px;border:1.5px dashed var(--line-strong);
  background:transparent;color:var(--text-mut);font-family:inherit;font-size:12px;
  font-weight:700;cursor:pointer;transition:var(--tr)}
.ls-pp-pgadd:hover{border-color:var(--accent);color:var(--text)}
.ls-pp-plus{font-size:20px;line-height:1;font-weight:400}
.ls-pp-pgact{display:flex;gap:6px;flex-wrap:wrap}
/* the sheet is white label stock whatever the app theme, so the hover tints
   are fixed light-ink values rather than theme variables — see the .ls rule
   that the studio paints its own chrome */
.ls-pp-sheet.hand .ls-pp-num.free:hover{border-color:var(--accent);
  background:rgba(232,113,10,.08)}
.ls-pp-sheet.hand .ls-pp-num.fill{border:1.5px solid rgba(20,22,26,.35);cursor:grab}
.ls-pp-sheet.hand .ls-pp-num.fill:hover{border-color:var(--accent)}
.ls-pp-sheet.hand .ls-pp-num.drag{cursor:grabbing;opacity:.65}
.ls-pp-sheet.hand .ls-pp-num.over{border:2px solid var(--accent);
  background:rgba(232,113,10,.14)}

.ls-pp-pane{min-width:0}

@media (max-width:1000px){
  .ls-pp-main{grid-template-columns:1fr}
  .ls-pp-meta{margin-left:0;text-align:left;width:100%}
}

.ls-row{display:grid;gap:10px}
.ls-inline{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.ls-chk{display:flex;align-items:center;gap:7px;font-size:12px;font-weight:600;
  color:var(--text-dim);cursor:pointer;margin:0}
.ls-col{display:flex;align-items:center;gap:6px}
.ls-col input[type=color]{width:100%;height:34px;padding:2px;border-radius:8px;
  border:1px solid var(--line);background:var(--panel-2);cursor:pointer}
.ls-ok{font-size:11.5px;font-weight:700;color:var(--ok);line-height:1.5}
.ls-bad{font-size:11.5px;font-weight:700;color:var(--danger);line-height:1.5}

/* ============================================================
   NARROW SCREENS
   The rail folds away first, then the toolbox: on a tablet the
   canvas is the thing you came for, and both panels are a button
   on the status bar away.
   ============================================================ */
/* The four ribbon groups and the size block together need about 1270px.
   Below a 1600px window they do not have it, so the size block takes a row
   of its own above the groups — the size at the left, the full-screen switch
   and the way out at the right — rather than fighting the groups for the
   same row and losing (which is how the door out of the designer went off
   the edge of every laptop). The groups then have the whole width and fit
   without scrolling down to about 1180px. */
@media (max-width:1600px){
  .ls-docbox{margin:2px 0 2px 8px;padding:2px 4px}
}
@media (max-width:1500px){
  .ls-dsl{display:none}          /* "46.0 mm x 11.0 mm" is the part that is read */
}
@media (max-width:1240px){
  .ls{--ls-rightw:196px}
}
@media (max-width:1040px){
  .ls{--ls-toolsw:126px;--ls-rightw:0px}
  .ls-right{display:none}
  .ls-bb{width:50px}
  .ls-tabn{max-width:110px}
}
@media (max-width:780px){
  .ls{--ls-toolsw:0px}
  .ls-tools{display:none}
  .ls-rgl{display:none}
  .ls-stage{padding:14px}
  /* the Font group leads on a phone: it is what a thumb goes to the ribbon
     for while typing; the clipboard waits at the end of the strip */
  .ls-rg-font{order:0}.ls-rg-para{order:1}.ls-rg-space{order:2}.ls-rg-clip{order:3}.ls-rg-edit{order:4}
  .ls-dmode{display:none}
  .ls-rscroll{-webkit-overflow-scrolling:touch;scrollbar-width:none}
  .ls-rscroll::-webkit-scrollbar{display:none}
  /* the keyboard hint means nothing to a thumb */
  .ls-edittip{display:none}
}
@media (max-width:760px){
  .ls-pp-prevrow{grid-template-columns:1fr}
}
@media (max-width:900px){
  /* minmax(0,…), not 1fr: a bare 1fr cannot shrink below its widest control,
     and the stock select's longest name is wider than a phone — so the whole
     column, and every field in it, ran off the sheet's right edge */
  .ls-props-dlg,.ls-setup2{grid-template-columns:minmax(0,1fr);gap:14px}
  .ls-setup2 .select,.ls-setup2 .input,.ls-props-dlg .select,.ls-props-dlg .input,
  .ls-lay .select,.ls-lay .input{width:100%;max-width:100%;min-width:0;box-sizing:border-box}
  .ls-setup2 .ls-chk{margin-bottom:10px}
  .ls-pcats{flex-direction:row;flex-wrap:wrap}
}

/* ============================================================
   PHONE & TABLET LAYOUT PASS

   Every rule below sits inside a max-width query, so the desktop
   rendering is byte-for-byte what it was. Ordered widest first,
   because that is the order the cascade reads them in.
   ============================================================ */

/* ---- boxes measured from the viewport height ----
   100vh on a phone or tablet counts the strip sitting behind the
   address bar, so a box sized from it hangs off the bottom of the
   screen and its last row of controls cannot be reached. dvh is
   the height actually on show and follows the bar as it hides.
   The app shell and the drawer were already written this way;
   these three were left behind on vh. */
@media (max-width:1100px){
  .doc-shell{height:calc(100dvh - 210px)}
  .ls{height:calc(100dvh - 194px)}
  .ls-full,.ls-full.ls-browse{height:100dvh}
}

/* ---- the same boxes, on a phone ----
   Their min-heights were floors written for a laptop: 520px of
   studio and 340px of PDF, on a screen whose whole working area
   between the topbar and the bottom nav is about 420px. The floor
   was doing the overflowing, so on a phone it goes. */
@media (max-width:820px){
  .doc-shell{height:calc(100dvh - 220px);min-height:240px}
  .ls{min-height:0}
}

/* ---- phones: the month calendar ----
   Seven columns of a 360px screen leave about 34px of usable cell
   — narrower than the event pill's own left border and padding,
   so its text was rendering as a column of single letters. The
   cell keeps its square in the month, and each entry falls back
   to the coloured bar it already draws down its edge. The day is
   still tappable, which is where the detail was always read. */
@media (max-width:640px){
  .cal-hd{padding:7px 2px;font-size:9px;letter-spacing:0;text-align:center}
  .cal-cell{min-height:62px;padding:4px 3px 5px;gap:3px}
  .cal-cell-top{min-height:19px}
  .cal-cell-n{font-size:11px}
  .cal-cell.today .cal-cell-n{width:19px;height:19px;font-size:10px}
  /* min-height:0 as well: the ≤900px touch pass above gives the pill a
     24px tap floor, and here the pill stops being the tap target at all */
  .cal-ev{height:5px;min-height:0;padding:0;gap:0;border-left:none;border-radius:3px;background:var(--sc)}
  .cal-ev-ic,.cal-ev-t{display:none}
  /* late and today are the two states worth seeing from across the
     month, so they keep a solid colour rather than their soft fill */
  .cal-ev.late{background:var(--danger)}
  .cal-ev.now{background:var(--accent)}
  .cal-more{font-size:9.5px;padding:0 3px}
}

/* ---- small phones: rows of small controls ----
   Eight accent swatches and the symbol row both fit by arithmetic
   and not by much. The gap gives way before the control does, so
   what you are aiming a thumb at stays the size it was. */
@media (max-width:480px){
  .wz-symhead,.wz-symrow{grid-template-columns:28px 1fr 1fr 1fr 26px;gap:5px}
}
@media (max-width:420px){
  .swatches{gap:6px}
}

/* ============================================================
   LABEL STUDIO ON A PHONE OR TABLET

   The studio was built as three columns — Tools, canvas, the
   properties rail — and the narrow-screen rules above simply
   delete the outer two. That left three things genuinely broken
   rather than merely cramped, and this block is about those:

     · The Tools panel is the ONLY way to add an object to a
       label. display:none at 780px meant a phone could open a
       label, and edit nothing onto it.
     · The status bar buttons that toggle both panels sit at the
       END of a bar that does not wrap and clips its overflow, so
       on a phone they were cut off the edge — the toggle existed
       but could not be reached.
     · The rail is the only home of Object Layers, and it goes at
       1040px, which is most tablets.

   So below those widths the panels stop being columns and become
   sheets that slide over the canvas, which is what the toggles
   were always for. Everything is inside a max-width query; the
   three-column desktop studio is untouched.
   ============================================================ */

/* ---- tablet: the properties rail, as a sheet ---- */
@media (max-width:1040px){
  /* the sheets are positioned against the WORKSPACE, not the whole studio:
     anchored to .ls they would span its full height and cover the doc tabs
     and the status bar — including the button that closes them again */
  .ls-body{position:relative}
  .ls-right{display:flex;position:absolute;top:0;right:0;bottom:0;z-index:30;
    width:min(300px,86%);border-left:1px solid var(--lsline);
    box-shadow:-2px 0 10px rgba(32,33,36,.18),0 0 30px rgba(32,33,36,.22)}
  /* the readout keeps its place here, but the zoom gives up some width
     so the three view buttons after it stay on the bar */
  .ls-status{gap:9px}
  .ls-zsl{width:84px}
}

/* ---- phone: BOTH panels, as sheets along the bottom ----

   A side sheet is the tablet's answer and the wrong one here. 300px of
   panel over a 390px screen leaves a sliver of label, so you are editing
   something you cannot see; and the rail stacks Properties above Layers,
   which in a workspace around 200px tall is two scrolling boxes of about
   ninety pixels each. That is the mess, and it is fairly earned.

   Along the bottom instead: full width, a little over half the height,
   the label still visible above it. A field row gets the phone's whole
   390px instead of 300, so a name and its control stop fighting over the
   same line, and Tools goes into two columns — a vertical list of ten was
   the only reason that panel ever had to be tall.

   Both sheets own the bottom edge, so only one may be open at a time; the
   status-bar toggles close the other (see the note on them). */
@media (max-width:780px){
  /* NOT position:absolute — the panel is the body's second ROW here, and it
     has to occupy the grid cell paint() gave it. The ≤1040 rule above floats
     the rail over the canvas for a tablet, which is right when the canvas is
     wide; this undoes it, because on a phone that float IS the problem. */
  .ls-tools,.ls-right{display:flex;position:static;left:auto;right:auto;
    top:auto;bottom:auto;width:auto;max-height:none;min-height:0;
    border:0;border-top:1px solid var(--lsline);border-radius:0;box-shadow:none}

  /* Ten tools down a single column is a panel as tall as the screen. Two
     fixed columns, not auto-fill: the row is the full width of the phone,
     and stating the count means it cannot resolve to one on a narrow one. */
  .ls-tlist{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
    gap:4px;align-content:start}
  .ls-tooll{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

  /* Properties is what was asked for; Layers is the list you glance at —
     so Layers takes a third and Properties keeps everything else */
  .ls-layers{max-height:34%}

  /* the × is how a panel is put away, so it has to be worth aiming a thumb
     at — and the header is the only handle the row has */
  .ls-ph{height:34px}
  .ls-px{width:26px;height:26px}
  .ls-tool{height:34px}

  /* the bar clips what overflows, and the controls are at the end of it:
     the prose goes so the buttons survive */
  .ls-status{gap:7px;padding:0 5px 0 8px}
  .ls-st-i,.ls-read{display:none}
  .ls-vb{width:28px;height:24px}
  .ls-zsl{width:64px}

  /* both strips scroll sideways by design — let them do it like a phone */
  .ls-ctb,.ls-tabs{-webkit-overflow-scrolling:touch;scrollbar-width:none}
  .ls-ctb::-webkit-scrollbar,.ls-tabs::-webkit-scrollbar{display:none}
}

/* ---- a SHORT window: a phone on its side, or a split screen ----
   The rail divides its height between Properties and Layers, and 44% to
   Layers is right when there is 500px of rail. A phone in landscape gives
   it about 150px, where the same 44% leaves Properties three fields and a
   scrollbar — the same mess as the phone, arrived at from the other side.
   Layers gives way: it keeps a strip worth reading and Properties takes
   what is left. Width is not the thing that is short here, so this is a
   height query and applies to the side sheet and the column alike. */
@media (max-height:560px){
  .ls-layers{max-height:96px}
}

/* ---- touch: the per-label buttons on a gallery card ----
   opacity:0 until :hover is a control that does not exist on a
   touch screen — rename, duplicate and delete were invisible and
   unreachable on every phone and tablet. Nothing here fires on a
   mouse, so the desktop card still reveals them on hover. */
@media (hover:none) and (max-width:1100px){
  .ls-gal-act{opacity:1}
}

/* ---- small phones ---- */
@media (max-width:480px){
  .ls-stage{padding:10px}
  .ls-tabn{max-width:78px}
  /* the colour popup is placed by script and can be opened near the right
     edge; without this it is drawn partly off the screen */
  .ls-cpop{max-width:92vw}
}

/* ---- TOUCH TARGETS, Label Studio gallery -------------------------------
   The tail of the touch pass (see the block after the alert-drawer rules):
   these controls' base sizes are declared above, so their finger-size
   override must come after them or equal specificity hands the win back. */
@media (max-width:900px){
  .ls-gal-act .mini{width:32px;height:32px;border-radius:8px}
  .ls-gal-print{height:32px;padding:0 12px}
}


/* ============================================================
   CRM — PIPELINE UPGRADE
   Filter bar, lead score, deal-rot flag, drag-and-drop affordance,
   stage conversion, forecast and the quotation builder.
   These sit at the end of the file on purpose: several of them
   extend rules declared in the CRM block above (.crm-lead,
   .crm-fchev, .crm-car-slide), and an override at equal
   specificity has to come after what it overrides.
   ============================================================ */

/* ---- filter bar ---------------------------------------------------------
   One row on a desktop, wrapping to as many as it needs on a tablet. The
   search box is the only thing that grows; the selects stay at their
   natural width so the chips keep their place on the line. */
.crm-filter{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 14px}
.crm-filter-q{flex:1 1 260px;min-width:0;height:36px}
.crm-filter-sel{flex:0 0 auto;height:36px;max-width:200px}
.crm-chips{display:flex;gap:8px;flex-wrap:wrap}
.crm-chip{display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 14px;
  border:1px solid var(--line);border-radius:var(--radius-pill);background:var(--panel);
  font:600 12px/1 inherit;color:var(--text-dim);cursor:pointer;transition:var(--tr);white-space:nowrap}
.crm-chip b{font-family:var(--mono);font-weight:800;font-size:12px}
.crm-chip:hover:not(:disabled){border-color:var(--line-strong);color:var(--text)}
.crm-chip.on{background:color-mix(in srgb,var(--accent) 13%,var(--panel));
  border-color:color-mix(in srgb,var(--accent) 55%,var(--line));color:var(--accent)}
.crm-chip.empty,.crm-chip:disabled{opacity:.42;cursor:default}

/* ---- lead score ring ----------------------------------------------------
   A conic sweep of --p percent. The ring carries the band by colour so it
   reads at a glance on a crowded board; the number is for when it doesn't. */
.crm-pip{flex:0 0 auto;width:32px;height:32px;border-radius:50%;border:0;padding:0;cursor:pointer;
  display:grid;place-items:center;position:relative;background:conic-gradient(
    var(--pc) calc(var(--p,0)*1%), color-mix(in srgb,var(--line) 60%,transparent) 0);
  --pc:var(--text-mut);transition:var(--tr)}
.crm-pip::before{content:"";position:absolute;inset:3px;border-radius:50%;background:var(--panel)}
.crm-car-slide.is-active .crm-pip::before{background:var(--panel-2)}
.crm-pip.hot{--pc:var(--danger)} .crm-pip.warm{--pc:var(--warn)} .crm-pip.cold{--pc:var(--text-mut)}
.crm-pip-n{position:relative;font:800 11px/1 var(--mono);color:var(--text)}
.crm-pip:hover{transform:scale(1.09)}

/* ---- a lead going cold --------------------------------------------------
   The card keeps its stage colour; only a warm left edge and one line of
   text change, so "going cold" reads as a state of the lead rather than as
   a second, competing category of card. */
.crm-lead.is-rot{border-left:3px solid var(--warn)}
.crm-lead-rot{margin-top:8px;font-size:11px;font-weight:700;color:var(--warn);
  background:color-mix(in srgb,var(--warn) 11%,transparent);border-radius:6px;
  padding:4px 8px;line-height:1.3}

/* ---- drag and drop ------------------------------------------------------
   The dragged card fades in place; the column it is over lifts its tint and
   dashes its border so the drop target is never ambiguous. */
.crm-lead.is-dragging{opacity:.4;transform:none;cursor:grabbing}
.crm-car-slide.is-drop{outline:2px dashed color-mix(in srgb,var(--sc) 70%,transparent);
  outline-offset:-4px;background:color-mix(in srgb,var(--sc) 9%,var(--panel))}
@media(hover:hover){ .crm-lead[draggable=true]{cursor:grab} }

/* ---- stage conversion, shown in the funnel's gaps ---------------------- */
.crm-fchev.has-rate{display:flex;flex-direction:column;align-items:center;gap:2px;justify-content:center}
.crm-fchev-ic{font-size:17px;line-height:1}
.crm-fchev-rate{font:800 10px/1 var(--mono);color:var(--text-mut);white-space:nowrap}
.crm-fchev-rate.good{color:var(--ok)}
.crm-fchev-rate.poor{color:var(--danger)}

/* ---- score breakdown ---------------------------------------------------- */
.crm-score-bars{display:flex;flex-direction:column;gap:14px}
.crm-score-row{display:grid;grid-template-columns:1fr;gap:6px}
.crm-score-k{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  font-size:13px;font-weight:700}
.crm-score-pts{font:800 12px/1 var(--mono);color:var(--text-mut)}
.crm-score-track{height:7px;border-radius:99px;background:var(--panel-3);overflow:hidden}
.crm-score-track>span{display:block;height:100%;border-radius:99px;background:var(--accent)}
.crm-score-why{font-size:12px;color:var(--text-mut)}

/* ---- forecast ----------------------------------------------------------
   Committed sits IN FRONT of weighted in the same column rather than beside
   it: the committed figure is a subset of the weighted one, and two adjacent
   bars would invite reading it as an additional amount. */
.crm-fc{display:flex;align-items:flex-end;gap:10px;height:190px;margin:4px 0 12px}
.crm-fc-col{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;gap:6px;
  height:100%;border-radius:10px;padding:6px 4px 0;transition:var(--tr)}
.crm-fc-col.crm-click{cursor:pointer}
.crm-fc-col.crm-click:hover{background:var(--panel-3)}
.crm-fc-stack{flex:1;width:100%;max-width:58px;margin:0 auto;display:flex;align-items:flex-end;
  justify-content:center;gap:4px;min-height:2px}
.crm-fc-bar{flex:1 1 0;min-width:0;border-radius:5px 5px 0 0;min-height:2px}
.crm-fc-bar.weighted{background:color-mix(in srgb,var(--accent) 34%,transparent)}
.crm-fc-bar.commit{background:var(--accent)}
.crm-fc-m{font-size:11px;font-weight:700;color:var(--text-dim);white-space:nowrap}
.crm-fc-v{font:700 10.5px/1 var(--mono);color:var(--text-mut);white-space:nowrap}
.crm-fc-key{display:flex;gap:18px;flex-wrap:wrap;font-size:12px;color:var(--text-mut);
  border-top:1px solid var(--line);padding-top:10px}
.crm-fc-key span{display:inline-flex;align-items:center;gap:8px}
.crm-fc-key i.k{width:11px;height:11px;border-radius:4px;flex:0 0 auto}
.crm-fc-key i.k.commit{background:var(--accent)}
.crm-fc-key i.k.weighted{background:color-mix(in srgb,var(--accent) 34%,transparent)}
.crm-fc-note{margin-top:14px;border-top:1px solid var(--line);padding-top:6px}

/* ---- duplicate warning in the lead form -------------------------------- */
.crm-dup{border:1px solid color-mix(in srgb,var(--warn) 45%,var(--line));border-radius:var(--radius-sm);
  background:color-mix(in srgb,var(--warn) 9%,transparent);padding:10px 12px}
.crm-dup-t{font-size:12px;font-weight:800;color:var(--warn);margin-bottom:6px}
.crm-dup-b{display:flex;flex-direction:column;gap:4px}
.crm-dup-row{font-size:12px;color:var(--text-dim);text-align:left;line-height:1.45}
.crm-dup-row.link{background:none;border:0;padding:0;cursor:pointer;color:var(--accent);font-weight:600}
.crm-dup-row.link:hover{text-decoration:underline}

/* ---- quotation builder --------------------------------------------------
   Six columns on a desktop. Below 780px the grid would crush the product
   select to nothing, so each line becomes its own labelled block instead. */
.crm-q-lines{display:flex;flex-direction:column;gap:8px}
.crm-q-row{display:grid;grid-template-columns:minmax(0,2.4fr) minmax(0,1.3fr) minmax(0,1fr) 78px minmax(0,1fr) 34px;
  gap:8px;align-items:center}
.crm-q-row.head{font-size:10px;text-transform:uppercase;letter-spacing:.6px;color:var(--text-mut);
  font-weight:700;padding:0 2px}
.crm-q-row.head span:nth-child(3),.crm-q-row.head span:nth-child(4),
.crm-q-row.head span:nth-child(5){text-align:right}
.crm-q-row .input,.crm-q-row .select{height:34px}
.crm-q-row input[type=number]{text-align:right}
.crm-q-qty{display:flex;align-items:center;gap:6px;min-width:0}
.crm-q-qty .input{min-width:0}
.crm-q-qty .chip{flex:0 0 auto;font-size:11px}
.crm-q-amt{text-align:right;font:800 12.5px/1 var(--mono)}
.crm-q-tot{margin-top:14px;display:flex;justify-content:flex-end}
.crm-q-tot-rows{min-width:270px;border-top:1px solid var(--line-strong);padding-top:10px}
.crm-q-tot-row{display:flex;justify-content:space-between;gap:20px;font-size:13px;padding:4px 0}
.crm-q-tot-row span:last-child{font-family:var(--mono);font-weight:700}
.crm-q-tot-row.strong{font-weight:800;font-size:15px;border-top:1px solid var(--line);
  margin-top:6px;padding-top:8px}
.crm-q-mini{display:flex;flex-direction:column;gap:4px;margin-bottom:10px}
.crm-q-mini-row{display:flex;justify-content:space-between;gap:12px;font-size:12px;align-items:baseline}
.crm-q-mini-row span:first-child{font-weight:600;flex:1;min-width:0}
.crm-q-mini-row span:last-child{font-family:var(--mono);font-weight:700}

@media(max-width:780px){
  .crm-q-row.head{display:none}
  .crm-q-row{grid-template-columns:1fr 1fr;gap:8px;border:1px solid var(--line);
    border-radius:var(--radius-sm);padding:10px;background:var(--panel-2)}
  .crm-q-row>.select{grid-column:1/-1}
  .crm-q-amt{grid-column:1/2;align-self:center;text-align:left;font-size:13px}
  .crm-q-row>.icon-btn{grid-column:2/3;justify-self:end}
  .crm-q-tot-rows{min-width:0;width:100%}
}
@media(max-width:640px){
  .crm-fc{height:150px;gap:6px}
  .crm-fc-m{font-size:10px}
  .crm-fc-v{display:none}
  .crm-filter-sel{flex:1 1 140px;max-width:none}
}


/* ---- NEW ITEM, ONE SHOT (mod-catalogue.js, 2026-09-02) ----
   Row grids: headers on top, a number down the left, boxes in columns, and
   no table rules — the item's test parameters and its recipe are entered
   this way, one row per parameter or component, as many as are added. */
.cg-sec{margin:18px 0 6px;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-mut);display:flex;align-items:center;gap:10px}
.cg-sec .sp{flex:1;height:1px;background:var(--line)}
.cg-grid{display:grid;gap:8px 10px;align-items:center;margin-top:8px}
.cg-grid.tp{grid-template-columns:28px minmax(150px,1.5fr) 100px minmax(84px,1fr) minmax(84px,1fr) 92px 32px}
.cg-grid.bm{grid-template-columns:28px minmax(200px,2fr) 110px 90px 32px}
.cg-grid .h{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-mut);white-space:nowrap}
.cg-grid .n{font-size:12px;color:var(--text-mut);text-align:right;font-variant-numeric:tabular-nums}
.cg-grid .input,.cg-grid .select,.cg-grid .ss{min-width:0}
.cg-grid .input[disabled]{opacity:.35}
.cg-empty{font-size:12px;color:var(--text-mut);padding:6px 0}
.cg-kv{display:grid;grid-template-columns:160px 1fr;gap:4px 12px;font-size:13px}
.cg-kv .k{color:var(--text-mut)}
@media (max-width:900px){
  .cg-grid.tp{grid-template-columns:24px 1fr 90px 1fr 1fr 76px 28px}
  .cg-kv{grid-template-columns:1fr}
}

/* ---- section dropdowns on tablet & phone ----
   The .nav-group dropdowns arrived after the rail / drawer / bottom-bar rules
   above, and `.nav-group>.nav-section{display:flex}` outranks their plain
   `.nav-section` selectors — so the fold heads (chevron, label, alert badge)
   leaked into the icon rail and the phone's bottom bar, and a closed fold hid
   its items from both. Each width gets the dropdowns it can actually use. */

/* tablet, icon rail (drawer shut): no folds — every icon reachable, the head
   is just the divider between groups */
@media(max-width:1100px) and (min-width:821px){
  .app-shell:not(.collapsed) .nav-group:not(.open)>.nav-group-items{display:flex}
  .app-shell:not(.collapsed) .nav-group>.nav-section{pointer-events:none;justify-content:center;
    font-size:0;letter-spacing:0;padding:12px 0 8px}
  .app-shell:not(.collapsed) .nav-sec-chev,
  .app-shell:not(.collapsed) .nav-sec-badge,
  .app-shell:not(.collapsed) .nav-sec-lbl{display:none}

  /* tablet, ☰ drawer open: the drawer is lifted out of the grid (position:
     fixed), which let the page fall into the 74px rail column and vanish
     behind the scrim. The page keeps its own column. */
  .app-shell.collapsed .main{grid-column:2}
  /* …and the drawer is a full labelled menu, so its folds work like the
     desktop sidebar's: label, chevron, alert total, open / close on tap */
  .app-shell.collapsed .nav-group>.nav-section{display:flex;pointer-events:auto}
  .app-shell.collapsed .nav-group>.nav-section::after{display:none}
  .app-shell.collapsed .nav-sec-lbl{display:block}
  .app-shell.collapsed .nav-sec-chev{display:inline}
  .app-shell.collapsed .nav-sec-badge{display:inline}
  .app-shell.collapsed .nav-group:not(.open)>.nav-group-items{display:none}
}

/* phone & tablet portrait, bottom bar: one flat, swipeable row of every item.
   The groups dissolve (display:contents) so their items join the bar's own
   row instead of stacking as columns inside it; the heads are hidden. */
@media(max-width:820px){
  .nav-group,.nav-group-items,
  .nav-group:not(.open)>.nav-group-items{display:contents}
  .nav-group>.nav-section{display:none}
}

/* ---- dialog header tools + the pocket calculator (UI.calcButton) ---- */
.modal-head-tools{margin-left:auto;display:flex;align-items:center;gap:8px}
.calc-wrap{position:relative}
.calc-btn{display:grid;place-items:center;color:var(--accent-300)}
.calc-btn.on{border-color:var(--accent-line);background:var(--accent-soft);color:var(--accent)}
.calc-pop{position:absolute;top:calc(100% + 8px);right:0;z-index:20;width:320px;padding:16px;
  background:var(--elev);border:1px solid var(--line-strong);border-radius:18px;box-shadow:var(--shadow-pop);
  animation:pop .16s var(--spring)}
.calc-pop[hidden]{display:none}
.calc-expr{min-height:20px;font-size:13px;color:var(--text-mut);text-align:right;font-family:var(--mono);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:0 4px}
.calc-out{width:100%;margin:4px 0 14px;padding:10px 14px;border-radius:12px;border:1px solid var(--line);
  background:var(--panel-2);color:var(--text);font:700 30px/1.25 var(--mono);text-align:right}
.calc-out:focus{outline:none;border-color:var(--accent-line)}
.calc-pad{display:grid;grid-template-columns:repeat(4,1fr);gap:9px}
.calc-k{height:54px;border-radius:12px;border:1px solid var(--line);background:var(--panel-2);color:var(--text);
  font-family:inherit;font-size:20px;font-weight:600;cursor:pointer;transition:background var(--tr),transform var(--tr)}
.calc-k:hover{background:var(--panel-3)}
.calc-k:active{transform:scale(.95)}
.calc-k.op{color:var(--accent-300);font-size:22px}
.calc-k.fn{color:var(--text-mut)}
.calc-k.wide{grid-column:span 2}
.calc-k.eq{background:var(--accent);border-color:var(--accent);color:#fff;font-size:22px}
.calc-foot{display:flex;justify-content:flex-end;margin-top:12px}
@media(max-width:640px){ .calc-pop{position:fixed;top:auto;right:12px;left:12px;bottom:calc(84px + env(safe-area-inset-bottom));width:auto;
    max-height:calc(100vh - 100px - env(safe-area-inset-bottom));max-height:calc(100dvh - 100px - env(safe-area-inset-bottom));
    overflow-y:auto;overscroll-behavior:contain}
  .calc-k{height:50px} }
@media(max-width:640px) and (max-height:600px){ .calc-k{height:40px} }

/* once open it floats free of the header (JS sets left/top) and is dragged by
   its grip; the grip's ✕ is the only ✕ on screen while it is open */
.calc-pop.float{position:fixed;top:auto;right:auto;bottom:auto;margin:0;
  max-height:calc(100vh - 16px);max-height:calc(100dvh - 16px);overflow-y:auto}
/* while it floats, the head's stacking context rises above the body's searchable-select lists (.ss-pop, z 200) */
.modal-head.calc-open{z-index:201}
.calc-grip{display:flex;align-items:center;gap:8px;margin:-16px -16px 10px;padding:8px 10px 8px 14px;
  border-bottom:1px solid var(--line);border-radius:18px 18px 0 0;background:var(--panel-2);
  position:sticky;top:0;z-index:1;
  cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
.calc-grip.dragging{cursor:grabbing}
.calc-grip:focus-visible{outline:2px solid var(--accent-line);outline-offset:-2px}
.calc-grip-dots{color:var(--text-mut);font-size:15px;line-height:1;letter-spacing:-3px}
.calc-grip-title{flex:1;font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--text-mut)}
.calc-x{width:28px;height:28px;border-radius:8px;border:1px solid var(--line);background:var(--panel);color:var(--text);
  font-family:inherit;font-size:13px;font-weight:700;line-height:1;cursor:pointer;display:grid;place-items:center;
  transition:background var(--tr),border-color var(--tr)}
.calc-x:hover{border-color:var(--accent-line);background:var(--panel-3)}
@media(max-width:640px){ .calc-grip{cursor:default;touch-action:auto} }

/* ---- Word's ribbon tabs (Home · Insert · Layout · View), the size block beside them ---- */
.ls-rtop{display:flex;align-items:center;flex-wrap:wrap;gap:4px;padding:2px 0 0}
.ls-rtop .ls-docbox{margin:2px 0 3px 12px}
.ls-rtabs{display:flex;align-items:flex-end;gap:2px}
.ls-rtab{padding:5px 12px 6px;border:1px solid transparent;border-bottom:0;border-radius:6px 6px 0 0;
  background:transparent;color:var(--lsdim);font-family:inherit;font-size:12.5px;font-weight:600;cursor:pointer}
.ls-rtab:hover{color:var(--lstx);background:rgba(60,64,67,.06)}
.ls-rtab.on{color:var(--lsblue);background:var(--lsw);border-color:var(--lsline);position:relative;top:1px}
.ls-ribbon>.ls-rscroll{border-top:1px solid var(--lsline);background:var(--lsw);padding:2px 0 0}
.ls-bs.on{background:var(--lssoft);color:var(--lsblue)}
.ls-btxt{width:auto;padding:0 8px;white-space:nowrap}
/* the Find & Replace bar under the ribbon */
.ls-findbar{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:5px 8px;
  border-top:1px solid var(--lsline);background:var(--lsbar)}
.ls-findbar .ls-in{height:26px;padding:0 8px;font-size:12px}
.ls-findq,.ls-findr{width:180px;max-width:40vw}
.ls-findn{font-size:11px;color:var(--lsdim);min-width:56px}
.ls-findopt{font-size:11.5px;gap:4px;display:inline-flex;align-items:center;color:var(--lsdim)}
@media (max-width:780px){ .ls-rtab{padding:5px 8px 6px;font-size:12px} }

/* ---- Label Studio print dialog: View data ---- */
.ls-pp-data{min-width:0}
.ls-pp-tblwrap{max-height:52vh;overflow:auto;border:1px solid var(--line);border-radius:10px;margin-top:8px}
.ls-pp-tbl{width:100%;border-collapse:collapse;font-size:12px}
.ls-pp-tbl th{position:sticky;top:0;z-index:1;background:var(--panel-2);text-align:left;font-size:10.5px;
  text-transform:uppercase;letter-spacing:.06em;color:var(--text-mut);padding:7px 10px;border-bottom:1px solid var(--line);white-space:nowrap}
.ls-pp-tbl td{padding:6px 10px;border-bottom:1px solid var(--line);font-family:var(--mono);white-space:nowrap}
.ls-pp-tbl td:nth-child(-n+3){color:var(--text-mut)}
.ls-pp-tbl .bad{color:var(--warn)}

/* ---- signature picker on the PO / SO / quotation forms ---- */
.sig-pick .sig-prev{margin-bottom:6px}
.sig-pick .sig-prev img{display:block;height:54px;max-width:260px;object-fit:contain;background:#fff;border:1px solid var(--line);border-radius:8px;padding:4px}

/* ---- print preview, in this tab (UI.printHtml): a document viewer ---- */
.print-preview{position:fixed;inset:0;z-index:300;display:flex;flex-direction:column;background:var(--bg);color:var(--text)}
.print-preview-bar{display:flex;align-items:center;gap:12px;padding:8px 14px;background:var(--panel);border-bottom:1px solid var(--line);flex:0 0 auto;box-shadow:0 1px 0 rgba(0,0,0,.08)}
.print-preview-title{display:flex;flex-direction:column;min-width:0;line-height:1.25}
.print-preview-title b{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.print-preview-title .muted{font-size:11.5px}
.print-close{white-space:nowrap}
.print-zoom{display:flex;align-items:center;gap:2px;padding:2px;border:1px solid var(--line);border-radius:10px;background:var(--panel-2)}
.print-zoom .print-zb{min-width:32px;padding:4px 8px;font-size:12px}
.print-zoom-n{min-width:46px;text-align:center;font-family:var(--mono);font-size:12px;color:var(--text-mut)}
.print-go{white-space:nowrap;padding-left:16px;padding-right:18px}
.print-desk{flex:1 1 auto;min-height:0;overflow:auto;padding:28px 32px 40px;display:flex;justify-content:center;align-items:flex-start;
  background:
    radial-gradient(circle at 1px 1px, rgba(127,127,127,.22) 1px, transparent 1.2px) 0 0/22px 22px,
    linear-gradient(180deg, rgba(0,0,0,.06), rgba(0,0,0,0) 120px);
  background-color:var(--panel-2)}
.print-stack{display:flex;flex-direction:column;align-items:center;gap:22px;flex:0 0 auto}
.print-page-wrap{display:flex;flex-direction:column;align-items:center;gap:6px}
.print-page{position:relative;flex:0 0 auto;background:#fff;border-radius:2px;overflow:hidden;
  box-shadow:0 1px 2px rgba(0,0,0,.25),0 14px 40px rgba(0,0,0,.35),0 0 0 1px rgba(0,0,0,.08)}
.print-win{position:absolute;overflow:hidden}
.print-preview-frame{position:absolute;left:0;top:0;border:0;background:#fff;transform-origin:top left;pointer-events:none}
.print-page-n{font-size:11px;color:var(--text-mut);font-family:var(--mono)}
.print-preview-hint{flex:0 0 auto;padding:7px 14px;font-size:11.5px;color:var(--text-mut);background:var(--panel);border-top:1px solid var(--line);text-align:center}
@media(max-width:760px){
  .print-preview-bar{flex-wrap:wrap;gap:6px 8px;padding:6px 10px}
  .print-preview-title{order:-1;flex:1 1 100%;text-align:center;align-items:center}
  .print-preview-title .muted{display:none}
  .print-zoom .print-zb{min-width:28px;padding:4px 6px}
  .print-zoom .print-zb:nth-child(4),.print-zoom .print-zb:nth-child(5){display:none}
  .print-close span:last-child{display:none}
  .print-close{padding:6px 10px}
  .print-desk{padding:12px 8px 24px}
  .print-preview-hint{display:none}
}

/* Production's five KPIs: five across on a laptop, two-up on a phone like every other page */
.kpi-grid-5{grid-template-columns:repeat(auto-fit,minmax(196px,1fr))}
@media(max-width:640px){ .kpi-grid.kpi-grid-5{grid-template-columns:repeat(2,minmax(0,1fr))} }

/* Products & BOM series headings: name and count on one line, the strapline under them on a phone */
.bom-series-head{flex-wrap:wrap}
.bom-series-head h2{white-space:nowrap}
@media(max-width:640px){ .bom-series-head .muted{order:3;flex:1 1 100%;font-size:12px;margin-top:-4px} }
