{"id":4858,"date":"2026-08-28T02:09:00","date_gmt":"2026-08-28T02:09:00","guid":{"rendered":"https:\/\/claimont.com\/?page_id=4858"},"modified":"2026-09-15T08:50:25","modified_gmt":"2026-09-15T08:50:25","slug":"price","status":"publish","type":"page","link":"https:\/\/claimont.com\/tr\/price\/","title":{"rendered":"Price List 2026"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"4858\" class=\"elementor elementor-4858\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ef08077 e-con-full e-flex e-con e-parent\" data-id=\"ef08077\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-bebdcac elementor-widget elementor-widget-html\" data-id=\"bebdcac\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<meta charset=\"utf-8\">\n<title>Claimont Price Desk<\/title>\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n<link rel=\"stylesheet\" href=\"https:\/\/fonts.googleapis.com\/css2?family=Archivo:wght@500;600;700&family=IBM+Plex+Mono:wght@400;500&family=Source+Sans+3:wght@400;600&display=swap\">\n\n<style>\n:root{\n  --ground:#F4F3EF; --surface:#FFFFFF; --surface-2:#FAF9F6; --sunken:#EDEBE5;\n  --ink:#191A16; --ink-2:#54564D; --ink-3:#82857A;\n  --line:#DFDDD4; --line-strong:#C7C4B8;\n  --accent:#0E5F58; --accent-soft:#DCEBE8; --accent-ink:#0A4741;\n  --good:#2E6E3A; --warn:#9A6206; --crit:#A32C22;\n  --warn-soft:#F7EBD4; --crit-soft:#F7E1DE; --good-soft:#E0EDE1;\n  --on-accent:#FFFFFF;\n  --shadow:0 1px 2px rgba(25,26,22,.06),0 8px 24px -12px rgba(25,26,22,.18);\n  --r:6px;\n}\n@media (prefers-color-scheme: dark){\n  :root:not([data-theme=\"light\"]){\n    --ground:#14150F; --surface:#1D1F19; --surface-2:#232520; --sunken:#191B15;\n    --ink:#EDEBE3; --ink-2:#A9AC9F; --ink-3:#7D8175;\n    --line:#32352C; --line-strong:#464A3E;\n    --accent:#63C4B8; --accent-soft:#1B3B37; --accent-ink:#8FD8CE;\n    --good:#7EBB86; --warn:#DFAE5B; --crit:#E2887C;\n    --warn-soft:#3A2E17; --crit-soft:#3A211D; --good-soft:#1E3022;\n    --on-accent:#10221F;\n    --shadow:0 1px 2px rgba(0,0,0,.4),0 8px 24px -12px rgba(0,0,0,.6);\n  }\n}\n:root[data-theme=\"dark\"]{\n  --ground:#14150F; --surface:#1D1F19; --surface-2:#232520; --sunken:#191B15;\n  --ink:#EDEBE3; --ink-2:#A9AC9F; --ink-3:#7D8175;\n  --line:#32352C; --line-strong:#464A3E;\n  --accent:#63C4B8; --accent-soft:#1B3B37; --accent-ink:#8FD8CE;\n  --good:#7EBB86; --warn:#DFAE5B; --crit:#E2887C;\n  --warn-soft:#3A2E17; --crit-soft:#3A211D; --good-soft:#1E3022;\n  --on-accent:#10221F;\n    --shadow:0 1px 2px rgba(0,0,0,.4),0 8px 24px -12px rgba(0,0,0,.6);\n}\n\n*{box-sizing:border-box}\n[hidden]{display:none!important}\nbody{\n  margin:0; background:var(--ground); color:var(--ink);\n  font-family:\"Source Sans 3\",system-ui,-apple-system,\"Segoe UI\",sans-serif;\n  font-size:15px; line-height:1.45; -webkit-font-smoothing:antialiased;\n}\nh1,h2,h3,.disp{font-family:Archivo,\"Arial Narrow\",system-ui,sans-serif;font-weight:600;letter-spacing:-.01em;margin:0}\n.mono{font-family:\"IBM Plex Mono\",ui-monospace,Menlo,monospace}\n.num{font-variant-numeric:tabular-nums}\nbutton,input,select{font:inherit;color:inherit}\n:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}\n\n.gate{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:28px 18px;background:var(--ground)}\n.gatebox{max-width:420px;width:100%;background:var(--surface);border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:32px 30px}\n.gatebox .bn{font-family:Archivo,sans-serif;font-weight:700;font-size:24px;letter-spacing:-.02em}\n.gatebox .bs{font-size:11.5px;color:var(--ink-3);letter-spacing:.12em;text-transform:uppercase;margin-top:2px}\n.gatebox h1{font-size:19px;margin:22px 0 6px}\n.gatebox p{color:var(--ink-2);font-size:14px;margin:0 0 18px}\n.gatebox input{width:100%;padding:11px 13px;background:var(--surface-2);border:1px solid var(--line-strong);border-radius:var(--r);\n  font-family:\"IBM Plex Mono\",monospace;font-size:16px;letter-spacing:.08em;text-transform:uppercase}\n.gatebox .row{display:flex;gap:8px;margin-top:12px}\n.gatebox .row .btn{flex:1;justify-content:center}\n.gateerr{color:var(--crit);font-size:13.5px;font-weight:600;margin-top:10px;min-height:20px}\n.langmini{display:flex;gap:6px;margin-top:18px}\n.langmini button{background:none;border:0;color:var(--ink-3);font-size:12.5px;font-weight:600;cursor:pointer;padding:2px 4px}\n.langmini button[aria-pressed=\"true\"]{color:var(--accent-ink);text-decoration:underline}\n.who{display:inline-flex;align-items:center;gap:7px;background:var(--accent-soft);border:1px solid var(--accent);\n  color:var(--accent-ink);border-radius:100px;padding:4px 12px;font-size:12.5px;font-weight:600}\n.who .role{opacity:.7;font-weight:400}\n\n\/* ---------- masthead ---------- *\/\n.wrap{max-width:1680px;margin:0 auto;padding:0 clamp(12px,2vw,28px)}\n.mast{background:var(--surface);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:40}\n.mast-in{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding-block:12px}\n.brandmark{display:flex;align-items:center;gap:11px;margin-right:auto}\n\/* The logo sits on its own light chip so the artwork reads the same in both\n   themes, whatever colour the file itself is. *\/\n.brandmark .logo{height:30px;width:auto;display:block;flex:none;\n  background:#fff;border-radius:5px;padding:3px 7px;box-shadow:0 1px 0 rgba(0,0,0,.06)}\n.brandmark .logo[hidden]{display:none}\n.brandmark .txt{display:flex;align-items:baseline;gap:10px}\n.brandmark .bn{font-family:Archivo,sans-serif;font-weight:700;font-size:19px;letter-spacing:-.02em}\n.brandmark .bs{font-size:12px;color:var(--ink-3);letter-spacing:.09em;text-transform:uppercase}\n.brandmark .bs::before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:2px;background:var(--accent);margin-right:7px;vertical-align:1px}\n.iconbtn{background:var(--surface-2);border:1px solid var(--line-strong);border-radius:var(--r);\n  padding:6px 11px;font-size:12.5px;font-weight:600;color:var(--ink-2);cursor:pointer;display:inline-flex;align-items:center;gap:6px}\n.iconbtn:hover{border-color:var(--crit);color:var(--crit)}\n.oldver{margin:14px 0 0;padding:12px 16px;border-radius:var(--r);background:var(--warn-soft);\n  border:1px solid var(--warn);color:var(--warn);font-size:13.5px;line-height:1.5}\n.oldver b{display:block;font-family:Archivo,sans-serif;font-size:14px;margin-bottom:3px}\n.seg{display:flex;border:1px solid var(--line-strong);border-radius:var(--r);overflow:hidden}\n.seg button{background:var(--surface);border:0;padding:6px 12px;font-size:13px;font-weight:600;color:var(--ink-2);cursor:pointer}\n.seg button+button{border-left:1px solid var(--line-strong)}\n.seg button[aria-pressed=\"true\"]{background:var(--accent);color:var(--on-accent)}\n\n.sync{display:inline-flex;align-items:center;gap:7px;border-radius:100px;padding:4px 11px;font-size:12.5px;font-weight:600;\n  background:var(--surface-2);border:1px solid var(--line-strong);color:var(--ink-2)}\n.sync::before{content:\"\";width:7px;height:7px;border-radius:50%;background:var(--ink-3);flex:none}\n.sync.live{background:var(--accent-soft);border-color:var(--accent);color:var(--accent-ink)}\n.sync.live::before{background:var(--good)}\n.sync.builtin{background:var(--warn-soft);border-color:var(--warn);color:var(--warn)}\n.sync.builtin::before{background:var(--warn)}\n.fx{display:flex;align-items:center;gap:8px;background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r);padding:5px 10px;font-size:12.5px;color:var(--ink-2)}\n.fx .dot{width:7px;height:7px;border-radius:50%;background:var(--ink-3);flex:none}\n.fx.live .dot{background:var(--good)}\n.fx.fallback .dot{background:var(--warn)}\n.fx input{width:64px;background:transparent;border:1px solid var(--line-strong);border-radius:4px;padding:1px 5px;font-family:\"IBM Plex Mono\",monospace;font-size:12.5px;font-variant-numeric:tabular-nums}\n\n\/* ---------- controls ---------- *\/\n.controls{background:var(--surface);border-bottom:1px solid var(--line);position:sticky;top:57px;z-index:35}\n.controls-in{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding-block:10px}\n.search{position:relative;flex:1 1 240px;max-width:340px}\n.search input{width:100%;padding:7px 10px 7px 30px;background:var(--surface-2);border:1px solid var(--line-strong);border-radius:var(--r)}\n.search svg{position:absolute;left:9px;top:50%;transform:translateY(-50%);width:14px;height:14px;stroke:var(--ink-3);fill:none;stroke-width:2}\n.chips{display:flex;gap:6px;flex-wrap:wrap}\n.chip{background:var(--surface-2);border:1px solid var(--line-strong);border-radius:100px;padding:5px 10px;font-size:12.5px;font-weight:600;color:var(--ink-2);cursor:pointer;white-space:nowrap}\n.chip[aria-pressed=\"true\"]{background:var(--accent-soft);border-color:var(--accent);color:var(--accent-ink)}\n.chip .c{color:var(--ink-3);font-weight:400;margin-left:5px;font-variant-numeric:tabular-nums}\n.chip[aria-pressed=\"true\"] .c{color:var(--accent-ink);opacity:.7}\n.spacer{margin-left:auto}\n.btn{background:var(--surface-2);border:1px solid var(--line-strong);border-radius:var(--r);padding:6px 11px;font-size:12.5px;font-weight:600;color:var(--ink-2);cursor:pointer;display:inline-flex;align-items:center;gap:6px}\n.btn:hover{border-color:var(--accent);color:var(--accent-ink)}\n.btn-pending{background:var(--warn-soft);border-color:var(--warn);color:var(--warn)}\n.btn-pending:hover{border-color:var(--warn);color:var(--warn);filter:brightness(.96)}\n.btn-pending::before{content:\"\";width:7px;height:7px;border-radius:50%;background:var(--warn);flex:none}\n.btn-primary{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}\n.btn-primary:hover{opacity:.92;color:var(--on-accent);border-color:var(--accent)}\n\ndetails.colmenu{position:relative}\ndetails.colmenu>summary{list-style:none;cursor:pointer}\ndetails.colmenu>summary::-webkit-details-marker{display:none}\n.colpanel{position:absolute;right:0;top:calc(100% + 6px);background:var(--surface);border:1px solid var(--line-strong);border-radius:var(--r);box-shadow:var(--shadow);padding:10px;min-width:210px;z-index:50}\n.colpanel label{display:flex;align-items:center;gap:8px;padding:5px 4px;font-size:13.5px;cursor:pointer;border-radius:4px}\n.colpanel label:hover{background:var(--surface-2)}\n.colpanel .hd{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);padding:4px;font-weight:600}\n\n\/* ---------- table ---------- *\/\n.tablewrap{background:var(--surface);border:1px solid var(--line);border-radius:0 0 var(--r) var(--r);\n  overflow-x:auto;box-shadow:var(--shadow);scrollbar-color:var(--accent) var(--sunken);scrollbar-width:auto}\n.tablewrap::-webkit-scrollbar{height:18px}\n.tablewrap::-webkit-scrollbar-track{background:var(--sunken);border-top:1px solid var(--line-strong)}\n.tablewrap::-webkit-scrollbar-thumb{background:var(--accent);border-radius:9px;border:4px solid var(--sunken)}\n.tablewrap::-webkit-scrollbar-thumb:hover{background:var(--accent-ink)}\n\n\/* a matching bar above the table, with a label, so sideways scrolling is obvious *\/\n.scrollbar{display:flex;align-items:center;gap:10px;margin:16px 0 0;padding:5px 10px 0;\n  background:var(--surface);border:1px solid var(--line);border-bottom:0;border-radius:var(--r) var(--r) 0 0}\n.scrollbar .hint{flex:none;font-family:Archivo,sans-serif;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;\n  font-weight:600;color:var(--accent-ink);white-space:nowrap;padding-bottom:5px}\n.scrolltop{flex:1;overflow-x:auto;overflow-y:hidden;height:18px;\n  scrollbar-color:var(--accent) var(--sunken);scrollbar-width:auto}\n.scrolltop::-webkit-scrollbar{height:18px}\n.scrolltop::-webkit-scrollbar-track{background:var(--sunken);border-radius:9px}\n.scrolltop::-webkit-scrollbar-thumb{background:var(--accent);border-radius:9px;border:4px solid var(--sunken)}\n.scrolltop::-webkit-scrollbar-thumb:hover{background:var(--accent-ink)}\n.scrolltop div{height:1px}\n@media screen and (max-width:860px){.scrollbar{display:none}}\n@media print{\n  \/* The portal is embedded in a WordPress page. Its header, footer, chat bubble\n     and language widget are not ours to style, so we hide whatever is not on the\n     path from <body> down to the portal (marked up in JS on beforeprint). *\/\n  [data-clhide]{display:none!important}\n  html,body{margin:0!important;padding:0!important;background:#fff!important}\n  \/* and the table stays a table, whatever the page width works out to *\/\n  table{display:table!important}thead{display:table-header-group!important}\n  tbody{display:table-row-group!important}tr{display:table-row!important}\n  th,td{display:table-cell!important}\n.scrollbar{display:none!important}.tablewrap{border:0}}\ntable{border-collapse:separate;border-spacing:0;width:100%;font-size:13.5px}\nthead th{\n  position:sticky;top:0;z-index:10;background:var(--sunken);text-align:left;\n  font-family:Archivo,sans-serif;font-weight:600;font-size:11px;letter-spacing:.06em;text-transform:uppercase;\n  color:var(--ink-2);padding:9px 10px;border-bottom:1px solid var(--line-strong);white-space:nowrap;vertical-align:bottom;\n}\nthead th.g-pack{background:var(--sunken)}\ntbody td{padding:8px 10px;border-bottom:1px solid var(--line);vertical-align:middle;white-space:nowrap}\ntbody tr:hover td{background:var(--surface-2)}\ntbody tr.has-qty td{background:var(--accent-soft)}\ntbody tr.has-qty:hover td{background:var(--accent-soft)}\ntd.n,th.n{text-align:right;font-variant-numeric:tabular-nums}\n.idx{color:var(--ink-3);font-family:\"IBM Plex Mono\",monospace;font-size:12px}\n.nophoto{display:block;background:repeating-linear-gradient(45deg,var(--sunken),var(--sunken) 5px,var(--surface-2) 5px,var(--surface-2) 10px)}\n.thumb{width:44px;height:58px;object-fit:contain;background:var(--surface-2);border:1px solid var(--line);border-radius:4px;display:block;cursor:zoom-in}\n.pname{white-space:normal;min-width:180px;max-width:280px}\n.pname .b{font-family:Archivo,sans-serif;font-weight:600;font-size:13px;display:block;letter-spacing:-.005em}\n.pname .f{color:var(--ink-2);font-size:12.5px;display:block;line-height:1.3}\n\/* Cartons is the one column people type into, so it is deliberately the\n   largest control on the row and reads as a field rather than a cell. *\/\n.qty{width:104px;padding:8px 10px;text-align:right;background:var(--surface-2);\n  border:2px solid var(--line-strong);border-radius:6px;font-family:\"IBM Plex Mono\",monospace;\n  font-variant-numeric:tabular-nums;font-size:16px;font-weight:600;color:var(--ink);\n  transition:border-color .12s,box-shadow .12s}\n.qty::placeholder{color:var(--ink-3);font-weight:400}\n\/* ---- the Cartons column can be dragged wider ------------------------------\n   The WordPress theme styles every number input as width:100% with a selector\n   that outranks a bare class, so the width is set on the COLUMN and the input\n   simply fills it. --qtyfit keeps the box wide enough for the longest number\n   already typed, so the figure is readable whether or not anyone drags. *\/\nth.c-qty,td.c-qty{width:max(var(--qtyw,104px),var(--qtyfit,0px));\n  min-width:max(var(--qtyw,104px),var(--qtyfit,0px))}\ntd.c-qty input.qty{width:100%;box-sizing:border-box;min-width:0}\n\/* the spinner arrows sit on top of the digits and steal about 17px *\/\ninput.qty{-moz-appearance:textfield;appearance:textfield}\ninput.qty::-webkit-outer-spin-button,input.qty::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\nth.c-qty{position:relative}\n.colgrip{position:absolute;top:0;right:0;width:12px;height:100%;cursor:col-resize;\n  display:flex;align-items:center;justify-content:center;touch-action:none;user-select:none}\n.colgrip::before{content:\"\";width:3px;height:56%;border-radius:2px;background:var(--line-strong)}\n\/* The header scrolls away with the page, so the drag handle alone is not enough \u2014\n   this stepper lives in the bar above the table and stays put. *\/\n.qtyctl{display:flex;align-items:center;gap:5px;flex:none;padding-bottom:5px;margin-left:auto}\n.qtyctl .lb{font-family:Archivo,sans-serif;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;\n  font-weight:600;color:var(--ink-3);white-space:nowrap}\n.qtyctl button{width:24px;height:24px;line-height:1;border:1px solid var(--line-strong);border-radius:5px;\n  background:var(--surface);color:var(--ink-2);font-size:15px;cursor:pointer;padding:0;\n  display:flex;align-items:center;justify-content:center}\n.qtyctl button:hover{border-color:var(--accent);color:var(--accent-ink)}\n.qtyctl .val{font-family:\"IBM Plex Mono\",monospace;font-size:11.5px;color:var(--ink-3);\n  min-width:38px;text-align:center;font-variant-numeric:tabular-nums}\n\/* the bar rides under the sticky toolbar so the stepper is always reachable *\/\n.scrollbar{position:sticky;top:var(--stickytop,150px);z-index:33}\n.colgrip:hover::before,.colgrip.on::before{background:var(--accent);width:4px}\nbody.colsizing{cursor:col-resize;user-select:none}\n@media print{.colgrip{display:none!important}}\n\n\/* ---- master edit: the table itself becomes the form ---- *\/\n.gedit{display:block;width:100%;box-sizing:border-box;max-width:100%;min-width:0;\n  padding:5px 6px;background:transparent;border:1px solid transparent;\n  border-radius:4px;font:inherit;font-size:13px;color:inherit;text-align:inherit}\n.gedit:hover{border-color:var(--line-strong);background:var(--surface-2)}\n.gedit:focus{outline:0;border-color:var(--accent);background:var(--surface);\n  box-shadow:0 0 0 3px var(--accent-soft);position:relative;z-index:2}\n\/* the spinner arrows steal about a centimetre from every numeric cell, which is\n   what was clipping the smaller prices *\/\n.gedit.n{text-align:right;font-family:\"IBM Plex Mono\",monospace;font-variant-numeric:tabular-nums;\n  -moz-appearance:textfield;appearance:textfield}\n.gedit::-webkit-outer-spin-button,.gedit::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\nbody.masteredit td.n{min-width:96px}\nbody.masteredit td.c-idx{min-width:74px}\n.idedit{font-weight:700}\n.refcode{font-family:\"IBM Plex Mono\",monospace;font-size:12.5px;font-weight:600;color:var(--accent-ink);\n  background:var(--accent-soft);border-radius:5px;padding:2px 7px;white-space:nowrap}\n.photoedit{position:relative;display:block;padding:0;border:0;background:none;cursor:pointer;line-height:0}\n.photoedit .pen2{position:absolute;right:-4px;bottom:-4px;width:16px;height:16px;border-radius:100px;\n  background:var(--accent);color:var(--on-accent);font-size:9px;line-height:16px;text-align:center}\n.photoedit:hover .thumb{outline:2px solid var(--accent);outline-offset:1px}\n\/* give the longer values room to be read without clicking into them *\/\n.gedit[data-k=\"cbm\"]{min-width:104px}\n.gedit[data-k=\"net\"],.gedit[data-k=\"gross\"],.gedit[data-k=\"tare\"]{min-width:88px}\n.gedit[data-k=\"shelf\"],.gedit[data-k=\"temp\"]{min-width:112px}\n.gedit[data-k=\"hs\"],.gedit[data-k=\"bc\"],.gedit[data-k=\"cbc\"]{min-width:158px}\n\/* brand and flavour stack instead of sitting side by side, which is what used\n   to push them across the Customers and Grammage columns *\/\n.nameedit{display:grid;gap:4px;min-width:0}\nbody.masteredit td{white-space:normal;vertical-align:top}\nbody.masteredit td.c-name{min-width:230px}\nbody.masteredit .c-photo{vertical-align:middle}\ntd.dirty{box-shadow:inset 3px 0 0 var(--warn)}\nbody.masteredit .mastonly{display:inline-flex}\n.mastonly{display:none}\nbody.masteredit #btn-master{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}\n.mastbar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:14px 0 0;padding:10px 14px;\n  background:var(--warn-soft);border:1px solid var(--warn);border-radius:var(--r);\n  color:var(--warn);font-size:13.5px;line-height:1.45}\n.mastbar b{font-family:Archivo,sans-serif}\n.mastbar .spacer{flex:1}\n.pubmsg{margin:10px 0 0;padding:9px 12px;border-radius:var(--r);font-size:13px;\n  background:var(--sunken);color:var(--ink-2)}\n.pubmsg.good{background:var(--accent-soft);color:var(--accent-ink);font-weight:600}\n.pubmsg.bad{background:var(--warn-soft);color:var(--warn);font-weight:600}\n.pubfall{margin-top:12px}\n.pubfall summary{cursor:pointer;font-size:12.5px;color:var(--ink-3);font-weight:600}\n.pubfall[open] summary{margin-bottom:8px}\n\/* ---- activity bell ---- *\/\n.bellwrap{position:relative}\n.bell{padding:6px 9px}\n.bell svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}\n.belln{position:absolute;top:-6px;right:-6px;min-width:18px;height:18px;padding:0 5px;border-radius:100px;\n  background:var(--crit);color:#fff;font-size:11px;font-weight:700;line-height:18px;text-align:center;\n  font-family:\"IBM Plex Mono\",monospace}\n.bellpanel{position:absolute;top:calc(100% + 8px);right:0;width:370px;max-width:88vw;z-index:60;\n  background:var(--surface);border:1px solid var(--line-strong);border-radius:var(--r);\n  box-shadow:0 18px 44px -18px rgba(25,26,22,.5);overflow:hidden}\n.bellhd{display:flex;align-items:center;gap:10px;padding:10px 13px;border-bottom:1px solid var(--line);\n  font-family:Archivo,sans-serif;font-weight:600;font-size:13px}\n.bellhd .linkbtn{margin-left:auto}\n.bellbody{max-height:min(58vh,440px);overflow-y:auto}\n.actcard{display:block;width:100%;text-align:left;background:none;border:0;border-bottom:1px solid var(--line);\n  padding:10px 13px;cursor:pointer;font:inherit;color:inherit}\n.actcard:hover{background:var(--surface-2)}\n.actcard:last-child{border-bottom:0}\n.actcard.unread{background:var(--accent-soft)}\n.actcard .who{display:block;font-weight:600;font-size:13.5px}\n.actcard .what{display:block;font-size:12.5px;color:var(--ink-2);margin-top:2px}\n.actcard .when{display:block;font-size:11.5px;color:var(--ink-3);margin-top:3px;font-variant-numeric:tabular-nums}\n.actcard .tagd{display:inline-block;font-size:10px;letter-spacing:.07em;text-transform:uppercase;\n  font-weight:700;padding:1px 6px;border-radius:100px;margin-right:6px;vertical-align:1px}\n.tag-order{background:var(--accent);color:var(--on-accent)}\n.tag-draft{background:var(--warn-soft);color:var(--warn)}\n.tag-open{background:var(--sunken);color:var(--ink-2)}\n.tag-msg{background:var(--accent-soft);color:var(--accent-ink)}\n.msgstart{margin:2px 0 8px;font-size:12px}\n.railempty.draftline{color:var(--warn)}\n.pill.draft{background:var(--warn-soft);color:var(--warn)}\n.qty:focus{outline:0;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);background:var(--surface)}\nth.c-qty,td.c-qty{background:var(--sunken)}\nthead th.c-qty{color:var(--accent-ink)}\ntbody tr.has-qty td.c-qty{background:var(--accent-soft)}\ntr.has-qty .qty{border-color:var(--accent);background:var(--surface);color:var(--accent-ink)}\n.muted{color:var(--ink-3)}\n.calc{color:var(--accent-ink);font-weight:600}\n.warnflag{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--warn);margin-left:5px;vertical-align:middle}\n.pub{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;border-radius:100px;padding:2px 9px;white-space:nowrap}\n.pub.on{background:var(--accent-soft);color:var(--accent-ink);border:1px solid var(--accent)}\n.pub.off{background:var(--sunken);color:var(--ink-3);border:1px solid var(--line-strong)}\ntbody tr.internal .pname .b{opacity:.72}\n\n\/* column group visibility *\/\n.hide-pack .g-pack,.hide-comp .g-comp,.hide-wt .g-wt,.hide-unit .g-unit,.hide-calc .g-calc{display:none}\n\n\/* ---------- summary dock ---------- *\/\n\/* The sticky dock competes with the table for screen height, so it stays short:\n   the totals only. Container planning sits below it in normal flow. *\/\n.dock{position:sticky;bottom:0;max-height:34vh;overflow-y:auto;z-index:38;background:var(--surface);border:1px solid var(--line);border-top:2px solid var(--accent);border-radius:var(--r) var(--r) 0 0;box-shadow:0 -6px 24px -14px rgba(25,26,22,.35);margin-top:16px}\n.dock-in{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(112px,1fr);gap:1px;\n  background:var(--line);overflow-x:auto;scrollbar-width:thin}\n@media screen and (max-width:900px){.dock-in{grid-auto-flow:row;grid-auto-columns:auto;\n  grid-template-columns:repeat(auto-fit,minmax(108px,1fr));overflow-x:visible}}\n.stat{background:var(--surface);padding:10px 12px}\n.stat .k{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);font-weight:600;font-family:Archivo,sans-serif}\n.stat .v{font-family:\"IBM Plex Mono\",monospace;font-variant-numeric:tabular-nums;font-size:17px;font-weight:500;margin-top:2px;letter-spacing:-.02em}\n.stat.money .v{color:var(--accent-ink)}\n.stat .sub{font-size:11.5px;color:var(--ink-3);font-variant-numeric:tabular-nums}\n\n.cont{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);margin-top:14px;padding:10px 12px;display:flex;gap:18px;align-items:center;flex-wrap:wrap}\n.cont .lbl{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);font-weight:600;font-family:Archivo,sans-serif}\n.meter{flex:1 1 160px;min-width:150px}\n.meter .row{display:flex;justify-content:space-between;font-size:11.5px;color:var(--ink-2);margin-bottom:3px;font-variant-numeric:tabular-nums}\n.meter .bar{height:7px;background:var(--sunken);border-radius:100px;overflow:hidden;border:1px solid var(--line)}\n.meter .fill{height:100%;background:var(--good);border-radius:100px;transition:width .25s ease}\n.meter.warn .fill{background:var(--warn)}\n.meter.over .fill{background:var(--crit)}\n.meter .pc{font-weight:600}\n.loadseg button{padding:4px 11px;font-size:12px}\n.meters{background:var(--surface);border-top:1px solid var(--line);padding:10px 12px;display:flex;gap:18px;align-items:center;flex-wrap:wrap}\n.contline{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding:10px 12px}\n.contline+.contline{border-top:1px solid var(--line)}\n.contline.pick label{font-size:12px;color:var(--ink-2);font-weight:600}\n.contline.pick select,.contline.pick input{padding:6px 9px;background:var(--surface-2);\n  border:1px solid var(--line-strong);border-radius:5px;font-size:13.5px}\n.contline.pick input{width:70px;text-align:right;font-variant-numeric:tabular-nums;font-family:\"IBM Plex Mono\",monospace}\n.linkbtn{background:none;border:0;color:var(--accent-ink);font-size:12.5px;font-weight:600;\n  text-decoration:underline;cursor:pointer;padding:0}\n.skumsg{flex:1 1 280px;min-width:240px;font-size:12.5px;font-weight:600;color:var(--good);\n  padding:4px 2px 0}\n.skumsg.over{color:var(--crit);animation:skupulse 1.5s ease-in-out infinite}\n@keyframes skupulse{0%,100%{opacity:1}50%{opacity:.55}}\n@media (prefers-reduced-motion: reduce){.skumsg.over{animation:none}}\n.fitmsg{flex:1 1 280px;min-width:240px;font-size:13px;display:flex;align-items:center;gap:9px;\n  padding:7px 12px;border-radius:var(--r);border:1px solid var(--line);background:var(--surface-2);color:var(--ink-2)}\n.fitmsg .dot2{width:9px;height:9px;border-radius:50%;flex:none;background:var(--ink-3)}\n.fitmsg b{color:var(--ink)}\n.fitmsg.full{background:var(--good-soft,var(--accent-soft));border-color:var(--good);color:var(--ink)}\n.fitmsg.full .dot2{background:var(--good)}\n.fitmsg.near{background:var(--surface-2);border-color:var(--line-strong)}\n.fitmsg.near .dot2{background:var(--good)}\n.fitmsg.light{background:var(--warn-soft);border-color:var(--warn);color:var(--warn)}\n.fitmsg.light .dot2{background:var(--warn)}\n.fitmsg.over{background:var(--crit-soft,var(--warn-soft));border-color:var(--crit);color:var(--crit)}\n.fitmsg.over .dot2{background:var(--crit)}\n.meter.dim{opacity:.55}\n.meter .alt{font-size:11.5px;color:var(--ink-2)}\n.ctable{width:100%;border-collapse:collapse;font-size:13.5px;margin-top:6px}\n.ctable th,.ctable td{padding:7px 9px;border-bottom:1px solid var(--line);text-align:left}\n.ctable th{font-family:Archivo,sans-serif;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3)}\n.ctable td.n{text-align:right;font-variant-numeric:tabular-nums}\n.palbox{position:relative}\n.palbox>summary{list-style:none;cursor:pointer}\n.palbox>summary::-webkit-details-marker{display:none}\n\/* expands in place \u2014 a floating panel kept getting clipped by the sticky column *\/\n.palpanel{position:static;margin-top:8px;background:var(--surface);border:1px solid var(--line-strong);\n  border-radius:8px;padding:12px;width:100%;box-shadow:none}\n.palpanel .f{display:flex;flex-direction:column;gap:4px;margin-bottom:10px}\n.palpanel label{font-size:11.5px;color:var(--ink-2);font-weight:600}\n.palpanel select,.palpanel input{padding:6px 9px;background:var(--surface-2);border:1px solid var(--line-strong);border-radius:5px;font-size:13.5px;width:100%}\n.palpanel .note{font-size:11.5px;color:var(--ink-3);line-height:1.4}\n.palpanel .slots{display:flex;gap:10px;font-size:11.5px;color:var(--ink-2);font-variant-numeric:tabular-nums;margin:-4px 0 10px}\n.palpanel .slots b{font-family:\"IBM Plex Mono\",monospace}\n\n\/* ---------- notes ---------- *\/\n.notes{margin:18px 0 40px;font-size:13px;color:var(--ink-2)}\n.notes h2{font-size:12px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);margin-bottom:8px}\n.notes ul{margin:0;padding-left:18px}\n.notes li{margin-bottom:4px}\n.notes .flag{color:var(--warn);font-weight:600}\n\n\/* ---------- row edit affordance ---------- *\/\n.rowedit{background:none;border:0;padding:0;cursor:pointer;color:var(--ink-3);font-family:\"IBM Plex Mono\",monospace;font-size:12px;display:inline-flex;align-items:center;gap:4px;border-radius:3px}\n.rowedit .pen{opacity:0;width:11px;height:11px;stroke:var(--accent);fill:none;stroke-width:2}\ntbody tr:hover .rowedit .pen{opacity:1}\n.rowedit:hover{color:var(--accent-ink)}\n\n\/* ---------- product form ---------- *\/\n.sheet{position:fixed;inset:0;background:rgba(10,11,8,.55);display:none;z-index:90;overflow-y:auto;padding:24px 16px}\n.sheet.on{display:block}\n.sheetbox{background:var(--surface);border:1px solid var(--line-strong);border-radius:10px;box-shadow:0 24px 60px -20px rgba(0,0,0,.5);max-width:920px;margin:0 auto}\n.sheethd{display:flex;align-items:center;gap:12px;padding:16px 20px;border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--surface);border-radius:10px 10px 0 0;z-index:2}\n.sheethd h2{font-size:17px;margin-right:auto}\n.sheetbody{padding:18px 20px}\n.fset{border:0;padding:0;margin:0 0 20px}\n.fset legend{font-family:Archivo,sans-serif;font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);font-weight:600;padding:0 0 8px}\n.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(158px,1fr));gap:12px}\n.f{display:flex;flex-direction:column;gap:4px}\n.f label{font-size:11.5px;color:var(--ink-2);font-weight:600}\n.f input,.f select{padding:7px 9px;background:var(--surface-2);border:1px solid var(--line-strong);border-radius:5px;width:100%;font-size:13.5px}\n.f input[type=number]{font-family:\"IBM Plex Mono\",monospace;font-variant-numeric:tabular-nums;text-align:right}\n.f .hint{font-size:11px;color:var(--ink-3)}\n.f.auto input{background:var(--sunken);color:var(--ink-2)}\n.photorow{display:flex;gap:16px;align-items:flex-start}\n.photoprev{width:104px;height:138px;flex:none;border:1px dashed var(--line-strong);border-radius:6px;background:var(--surface-2);display:flex;align-items:center;justify-content:center;overflow:hidden}\n.photoprev img{width:100%;height:100%;object-fit:contain}\n.photoprev span{font-size:11px;color:var(--ink-3);text-align:center;padding:6px}\n.sheetft{display:flex;gap:10px;align-items:center;padding:14px 20px;border-top:1px solid var(--line);position:sticky;bottom:0;background:var(--surface);border-radius:0 0 10px 10px}\n.err{color:var(--crit);font-size:12.5px;font-weight:600}\n\n\/* ---------- paste-back code panel ---------- *\/\n.codewrap{margin:18px 0 0;border:1px solid var(--accent);border-radius:var(--r);background:var(--surface);overflow:hidden}\n.codehd{display:flex;align-items:center;gap:10px;padding:11px 14px;background:var(--accent-soft);border-bottom:1px solid var(--accent)}\n.codehd .t{font-family:Archivo,sans-serif;font-weight:600;font-size:13px;color:var(--accent-ink);margin-right:auto}\n.codehd .n{font-size:12px;color:var(--accent-ink);opacity:.85}\n.codebody{padding:12px 14px}\n.codebody p{margin:0 0 10px;font-size:13px;color:var(--ink-2)}\n.regwrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--r);margin-bottom:14px}\n.regtbl{border-collapse:separate;border-spacing:0;width:100%;font-size:13px}\n.regtbl th{background:var(--sunken);text-align:left;font-family:Archivo,sans-serif;font-weight:600;font-size:10.5px;\n  letter-spacing:.06em;text-transform:uppercase;color:var(--ink-2);padding:8px 10px;border-bottom:1px solid var(--line-strong);white-space:nowrap}\n.regtbl td{padding:8px 10px;border-bottom:1px solid var(--line);white-space:nowrap}\n.regtbl tbody tr{cursor:pointer}\n.regtbl tbody tr:hover td{background:var(--surface-2)}\n.regtbl .code{font-family:\"IBM Plex Mono\",monospace}\n.regtbl .n{text-align:right;font-variant-numeric:tabular-nums}\n.regtbl tr.off td{opacity:.5}\n.tag{display:inline-block;border-radius:100px;padding:2px 9px;font-size:11px;font-weight:700}\n.tag.yes{background:var(--accent-soft);color:var(--accent-ink);border:1px solid var(--accent)}\n.tag.no{background:var(--sunken);color:var(--ink-3);border:1px solid var(--line-strong)}\n.tag.disc{background:var(--warn-soft);color:var(--warn);border:1px solid var(--warn)}\n.never{color:var(--ink-3)}\n.newcode{margin-top:8px;padding:14px;background:var(--accent-soft);border:1px solid var(--accent);border-radius:var(--r)}\n.newcode .lbl{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--accent-ink);font-weight:600;font-family:Archivo,sans-serif}\n.newcode p{font-size:12.5px;color:var(--accent-ink);margin:10px 0 0}\n.bigcode{font-family:\"IBM Plex Mono\",monospace;font-size:30px;font-weight:500;letter-spacing:.06em;\n  text-align:center;padding:16px 10px;background:var(--sunken);border:1px solid var(--line-strong);border-radius:var(--r);color:var(--accent-ink)}\n.codebody textarea{width:100%;height:150px;font-family:\"IBM Plex Mono\",monospace;font-size:11.5px;line-height:1.5;padding:10px;background:var(--sunken);border:1px solid var(--line-strong);border-radius:5px;resize:vertical;white-space:pre;color:var(--ink)}\n\n\/* lightbox *\/\n.lb{position:fixed;inset:0;background:rgba(10,11,8,.82);display:none;align-items:center;justify-content:center;z-index:100;padding:24px;cursor:zoom-out}\n.lb.on{display:flex}\n.lb img{max-width:min(460px,90vw);max-height:80vh;background:#fff;border-radius:8px;padding:12px}\n\n.empty{padding:44px 20px;text-align:center;color:var(--ink-3)}\n\n.layout{display:flex;gap:20px;align-items:flex-start}\n.main{flex:1;min-width:0}\n\/* Container planning is a side panel now, not a bar under the table \u2014 it stays\n   in view while you scroll the products, and stops eating the table's height. *\/\n\/* Everything that is not the product table lives in one left column, so the\n   table gets the whole of the rest of the width. The column is sticky and\n   scrolls on its own, which is what keeps three stacked panels usable. *\/\n.leftcol{width:288px;flex:none;position:sticky;top:120px;max-height:calc(100vh - 148px);\n  overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:14px;\n  padding-right:4px;scrollbar-width:thin}\n.leftcol > *{flex:none}\n.side{margin-top:0}\n\/* Inside the column the rail must not stick or scroll on its own \u2014 the column\n   does both. Left sticky, it rode over the panels underneath it. *\/\n.leftcol .rail{width:auto;position:static;top:auto;max-height:none;margin-top:16px;overflow:visible}\n.leftcol .railbody{max-height:none;overflow:visible}\n.leftcol .side{margin-top:0}\n\/* \u2500\u2500 3D live load view under the planner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n#c3d{margin:14px 2px 2px;user-select:none;touch-action:none}\n.c3dtitle{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);\n  font-weight:600;font-family:Archivo,sans-serif;margin:0 0 4px}\n.c3dtrack{display:flex;flex-wrap:wrap;gap:16px 30px;perspective:900px;padding:30px 6px 4px;cursor:grab}\n.c3dtrack:active{cursor:grabbing}\n.c3du{display:flex;flex-direction:column;align-items:center;gap:16px}\n.c3dbox{position:relative;width:104px;height:50px;transform-style:preserve-3d;\n  transform:rotateX(-24deg) rotateY(var(--ry,-32deg))}\n.c3df{position:absolute;left:50%;top:50%;border:1.5px solid var(--line-strong);box-sizing:border-box;\n  background:transparent;overflow:hidden}\n.c3df.cf{width:104px;height:50px;margin:-25px 0 0 -52px;transform:translateZ(23px)}\n.c3df.cs{width:46px;height:50px;margin:-25px 0 0 -23px;transform:rotateY(90deg) translateZ(52px)}\n.c3df.ct{width:104px;height:46px;margin:-23px 0 0 -52px;transform:rotateX(90deg) translateZ(25px);overflow:visible}\n.c3df.cf::after,.c3df.cs::after{content:\"\";position:absolute;inset:0;pointer-events:none;\n  background:repeating-linear-gradient(90deg,transparent 0 7px,rgba(127,127,127,.12) 7px 9px)}\n.c3df .lvl{position:absolute;left:0;right:0;bottom:0;height:0;background:var(--accent);opacity:.92;\n  transition:height .5s cubic-bezier(.22,.9,.36,1)}\n.c3df.cs .lvl{filter:brightness(.75)}\n.c3df.ct.full{background:var(--accent);filter:brightness(1.15);opacity:.95}\n.c3dbox.c3dw .c3df{border-color:var(--crit)}\n.c3dbox.c3dx .c3df{border:1.5px dashed var(--crit);animation:c3dp 1.5s ease-in-out infinite}\n@keyframes c3dp{0%,100%{opacity:.9}50%{opacity:.4}}\n@media (prefers-reduced-motion: reduce){.c3dbox.c3dx .c3df{animation:none}}\n.c3dlab{font-size:10.5px;color:var(--ink-2);font-variant-numeric:tabular-nums;text-align:center}\n.c3dlab.miss{color:var(--crit);font-weight:700}\n.c3dmore{font-weight:700;color:var(--ink-2);align-self:center;font-size:13px}\n.c3dmore.miss{color:var(--crit)}\n\/* \u2500\u2500 left-column sections: minimize + drag to reorder (desktop only) \u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n@media (min-width:861px){\n  .secbar{display:flex;align-items:center;gap:8px;padding:2px 2px 6px}\n  .secgrip{cursor:grab;color:var(--ink-3);font-size:14px;letter-spacing:-1px;line-height:1;\n    padding:3px 5px;border-radius:6px;flex:none;user-select:none}\n  .secgrip:hover{background:var(--sunken);color:var(--ink-2)}\n  .sectitle{flex:1;min-width:0;font-family:Archivo,sans-serif;font-weight:700;font-size:12px;\n    color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;visibility:hidden}\n  .secfold{flex:none;border:1px solid var(--line);background:var(--surface);border-radius:6px;\n    width:22px;height:22px;cursor:pointer;color:var(--ink-2);font-size:11px;line-height:1;padding:0}\n  .secfold:hover{background:var(--sunken)}\n  .secmin-on > *:not(.secbar){display:none!important}\n  .secmin-on .sectitle{visibility:visible}\n  .secmin-on{padding-bottom:2px;border-bottom:1px dashed var(--line);margin-bottom:10px}\n  .secdrag{opacity:.45;outline:2px dashed var(--line-strong);outline-offset:3px}\n}\n@media (max-width:860px){.secbar,#c3d{display:none!important}}\n.side .cont{margin-top:0;display:block;padding:0}\n.side .contline{padding:12px 14px;gap:10px}\n.side .contline.pick{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:9px 10px}\n.side .contline.pick .fitmsg{grid-column:1 \/ -1;min-width:0;flex:none}\n.side .contline.pick select,.side .contline.pick input{width:100%}\n.side .meters{display:block;padding:12px 14px}\n.side .meter{margin-bottom:11px}\n.side .meter:last-child{margin-bottom:0}\n.side .seg.loadseg{width:100%}\n.side .seg.loadseg button{flex:1}\n@media (max-width:1180px){\n  \/* below this the rail already collapses, so the planner returns to the flow *\/\n  .side{width:auto;position:static;max-height:none;margin-top:14px}\n  .side .contline.pick{grid-template-columns:auto auto 1fr}\n  .side .meters{display:flex;gap:18px;flex-wrap:wrap}\n  .side .meter{flex:1 1 180px;margin-bottom:0}\n}\n.rail{width:262px;flex:none;background:var(--surface);border:1px solid var(--line);border-radius:var(--r);\n  box-shadow:var(--shadow);margin-top:16px;position:sticky;top:120px;max-height:calc(100vh - 150px);\n  display:flex;flex-direction:column;overflow:hidden}\n.railhd{display:flex;align-items:center;gap:8px;padding:11px 14px;border-bottom:1px solid var(--line);\n  font-family:Archivo,sans-serif;font-weight:600;font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-2)}\n.railx{display:none;margin-left:auto;background:none;border:0;font-size:20px;line-height:1;color:var(--ink-3);cursor:pointer}\n.railbody{overflow-y:auto;padding:6px}\n.railempty{padding:16px 12px;font-size:12.5px;color:var(--ink-3);line-height:1.5}\n.railcount{background:var(--accent-soft);color:var(--accent-ink);border-radius:100px;padding:1px 8px;font-size:11.5px}\n.custcard{width:100%;text-align:left;background:none;border:1px solid transparent;border-radius:var(--r);\n  padding:9px 10px;cursor:pointer;display:block}\n.custcard:hover{background:var(--surface-2);border-color:var(--line)}\n.custcard.off{opacity:.5}\n.custcard .cn{font-weight:600;font-size:13.5px;display:block}\n.custcard .cmeta{font-size:11.5px;color:var(--ink-3);margin-top:1px;display:flex;gap:8px;flex-wrap:wrap}\n.custcard .pill{background:var(--sunken);border-radius:100px;padding:0 7px;font-variant-numeric:tabular-nums}\n.custcard .pill.has{background:var(--accent-soft);color:var(--accent-ink);font-weight:600}\n.custcard .pill.disc{background:var(--warn-soft);color:var(--warn);font-weight:600}\n.rowact{text-align:right;white-space:nowrap}\n.linkbtn.warn{color:var(--crit)}\n.pill.owner{background:#EAF2EF;color:var(--accent,#0E5F58);border-color:transparent;font-weight:600}\n.flnote2{margin-top:8px;font-size:11px;color:var(--ink-3);line-height:1.4}\n.qgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:16px}\n.qgrid .wide{grid-column:1\/-1}\n@media (max-width:760px){.qgrid{grid-template-columns:1fr}}\n.qt-items-h{font-family:Archivo,sans-serif;font-size:11px;letter-spacing:.09em;text-transform:uppercase;\n  color:var(--ink-3);margin:4px 0 8px}\n.dprice{width:96px;padding:6px 8px;border:1.5px solid var(--accent);border-radius:7px;text-align:right;\n  font-family:\"IBM Plex Mono\",monospace;font-size:13px;background:var(--surface)}\n.dprice.changed{background:var(--accent-soft);font-weight:700}\n#quoteprint{display:none}\n.qtywrap{display:contents}\n.qstep{display:none}\n.regtbl tr.arch{opacity:.55}\n.regtbl tr.arch td:first-child::after{content:\" \\2022 archived\";font-size:10.5px;color:var(--ink-3)}\n.olist{margin-top:4px;padding-left:10px;border-left:2px solid var(--line)}\n.ordercard{width:100%;text-align:left;background:none;border:0;border-radius:5px;padding:6px 8px;cursor:pointer;display:block}\n.ordercard:hover{background:var(--surface-2)}\n.ordercard .oid2{font-family:\"IBM Plex Mono\",monospace;font-size:11.5px}\n.ordercard .when{font-size:11px;color:var(--ink-3)}\n.ordercard .amt{font-size:12.5px;font-weight:700;color:var(--accent-ink);font-variant-numeric:tabular-nums}\n.clist{display:grid;grid-template-columns:auto 1fr;gap:6px 18px;margin:0;font-size:14px}\n.clist dt{color:var(--ink-2)}\n.clist dd{margin:0;font-weight:600;font-variant-numeric:tabular-nums}\n.clist dd.total{color:var(--accent-ink);font-size:16px}\n.was2{color:var(--ink-3);text-decoration:line-through;margin-right:6px;font-size:12.5px}\n@media screen and (max-width:1180px){\n  .rail{position:fixed;left:0;top:0;bottom:0;width:300px;max-height:none;margin:0;z-index:80;\n    border-radius:0;transform:translateX(-102%);transition:transform .22s ease}\n  .rail.on{transform:none}\n  .railx{display:block}\n  \/* Below this the side column stops being a column: it drops into the flow\n     BELOW the products, and stops being sticky \u2014 left sticky it floated over\n     the table and hid the very rows people came to read. *\/\n  .layout{display:flex;flex-direction:column}\n  .main{order:1;width:100%}\n  .leftcol{order:2;position:static;width:auto;max-height:none;overflow:visible;\n    padding-right:0;margin-top:4px}\n  .leftcol .rail{order:0}\n  .side{position:static;max-height:none}\n  .msgbody{max-height:340px}\n}\n\n\/* ---------- mobile cards ---------- *\/\n@media screen and (max-width:860px){\n  .mast{position:static}\n  .mast-in{gap:10px;padding-block:9px}\n  .brandmark .bn{font-size:16px}\n  .brandmark .bs{font-size:10.5px}\n  .fx{order:3;flex:1 1 100%;justify-content:flex-start;font-size:12px;padding:4px 8px}\n  .controls{top:0}\n  .controls-in{gap:8px;padding-block:8px}\n  .search{flex:1 1 100%;max-width:none}\n  .chips{flex:1 1 100%;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;padding-bottom:2px}\n  .chips::-webkit-scrollbar{display:none}\n  .spacer{display:none}\n  .btn{padding:6px 10px;font-size:12.5px}\n  .tablewrap{border:0;background:transparent;box-shadow:none;overflow:visible}\n  table,tbody,tr,td{display:block;width:100%}\n  thead{display:none}\n  tbody tr{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);margin-bottom:10px;padding:10px 12px;box-shadow:var(--shadow);display:grid;grid-template-columns:auto 1fr;gap:0 12px}\n  tbody tr.has-qty{border-color:var(--accent);border-width:1.5px}\n  tbody td{border:0;padding:3px 0;white-space:normal;display:flex;justify-content:space-between;gap:12px;grid-column:2}\n  tbody tr:hover td,tbody tr.has-qty td{background:transparent}\n  td[data-label]::before{content:attr(data-label);font-size:11px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3);font-weight:600;font-family:Archivo,sans-serif;flex:none;padding-top:2px}\n  td.c-photo{grid-column:1;grid-row:1 \/ span 3;padding:0}\n  td.c-photo::before{display:none}\n  .thumb{width:62px;height:82px}\n  td.c-idx{display:none}\n  td.c-name{grid-column:2;padding-bottom:6px}\n  td.c-name::before{display:none}\n  .pname{max-width:none}\n  td.c-qty{grid-column:1 \/ -1;border-top:1px dashed var(--line);margin-top:6px;padding-top:8px}\n  tbody tr:not(.has-qty) td.g-calc{display:none}\n  .qty{width:120px}\n  .dock-in{grid-template-columns:repeat(auto-fit,minmax(96px,1fr))}\n  .stat .v{font-size:15px}\n}\n\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550 mobile wizard \u2014 the same three-page flow as the customer portal \u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\n@media screen and (max-width:860px){\n  .mwnav{position:fixed;left:0;right:0;bottom:0;z-index:90;display:flex;align-items:center;gap:10px;\n    padding:10px 14px calc(10px + env(safe-area-inset-bottom));background:var(--surface);\n    border-top:1px solid var(--line-strong);box-shadow:0 -8px 24px rgba(15,23,42,.12)}\n  .mwback{width:46px;height:46px;border-radius:12px;border:1px solid var(--line-strong);\n    background:var(--surface-2);font-size:19px;color:var(--ink-2);flex:none;cursor:pointer}\n  .mwback[disabled]{opacity:.35}\n  .mwmid{flex:1;min-width:0;text-align:center}\n  .mwdots{display:flex;gap:6px;justify-content:center;margin-bottom:3px}\n  .mwdots span{width:22px;height:4px;border-radius:99px;background:var(--line-strong);transition:background .2s}\n  .mwdots span.on{background:var(--accent)}\n  .mwlbl{font-family:Archivo,sans-serif;font-weight:700;font-size:13px}\n  .mwtot{font-size:11.5px;color:var(--ink-2);font-variant-numeric:tabular-nums;min-height:14px}\n  .mwnext{flex:none;min-width:118px;height:46px;border-radius:12px;border:0;cursor:pointer;\n    background:var(--accent);color:#fff;font-family:Archivo,sans-serif;font-weight:700;font-size:14.5px;\n    box-shadow:0 4px 14px rgba(14,95,88,.35)}\n  .mwnext[hidden]{display:none}\n  body.mwiz{padding-bottom:84px}\n  body.mwiz .fx{display:none}\n  \/* everything off by default; each step turns its blocks on *\/\n  body.mwiz .controls, body.mwiz .tablewrap, body.mwiz .dock, body.mwiz .notes,\n  body.mwiz #msgside, body.mwiz #catadmin, body.mwiz #side, body.mwiz .rail,\n  body.mwiz .scrollbar, body.mwiz .mastbar, body.mwiz #codepanel{display:none}\n  body.mwiz.mstep-1 #side{display:block}\n  body.mwiz.mstep-2 .controls{display:block}\n  body.mwiz.mstep-2 .tablewrap{display:block}\n  body.mwiz.mstep-2 .controls .btn, body.mwiz.mstep-2 .colmenu, body.mwiz.mstep-2 .spacer{display:none}\n  body.mwiz.mstep-2 .controls .search{max-width:none;flex:1 1 100%}\n  body.mwiz.mstep-3 .dock{display:block;position:static;max-height:none;overflow:visible;border-radius:var(--r)}\n  body.mwiz.mstep-3 #msgside{display:block}\n  body.mwiz.mstep-3 #catadmin:not([hidden]){display:block}\n  body.mwiz.mstep-3 .rail{display:block;position:static;transform:none;width:auto;z-index:1;\n    border:1px solid var(--line);border-radius:var(--r);margin-top:12px;max-height:none}\n  body.mwiz.mstep-3 .railx{display:none}\n  body.mwiz.mstep-3 .controls{display:block}\n  body.mwiz.mstep-3 .controls .search, body.mwiz.mstep-3 .chips{display:none}\n  body.mwiz.mstep-3 .controls .btn{display:inline-flex;flex:1 1 44%;justify-content:center;padding:11px 10px;font-size:13.5px}\n  body.mwiz.mstep-3 #btn-master, body.mwiz.mstep-3 #btn-print, body.mwiz.mstep-3 .colmenu{display:none}\n  \/* lean product card: photo \u00b7 ref+price \u00b7 name \u00b7 size \u00b7 upc+unit price \u00b7 stepper \u00b7 total *\/\n  body.mwiz tbody td.k-pue,\n  body.mwiz tbody td.k-pce, body.mwiz tbody td.k-teur, body.mwiz tbody td.k-units,\n  body.mwiz tbody td.k-pallets, body.mwiz tbody td.k-tcbm, body.mwiz tbody td.k-tnet,\n  body.mwiz tbody td.k-tgross{display:none!important}\n  body.mwiz tbody tr{grid-template-columns:64px 1fr auto;gap:1px 12px;padding:12px 13px;align-items:center}\n  body.mwiz tbody td{grid-column:auto;padding:1px 0}\n  body.mwiz tbody td::before{display:none!important}\n  body.mwiz tbody td.c-photo{grid-column:1;grid-row:1\/span 4;padding:0}\n  body.mwiz .thumb{width:60px;height:76px}\n  body.mwiz tbody td.k-ref{grid-column:2;grid-row:1;padding:0;justify-content:flex-start}\n  body.mwiz tbody td.k-pc{grid-column:3;grid-row:1;justify-content:flex-end;font-size:14px;font-weight:600}\n  body.mwiz tbody td.c-name{grid-column:2\/span 2;grid-row:2;padding:0}\n  body.mwiz tbody td.c-pub{grid-column:2\/span 2;grid-row:3;padding:0;justify-content:flex-start}\n  body.mwiz tbody td.k-g{grid-column:2\/span 2;grid-row:4;justify-content:flex-start;color:var(--ink-3);font-size:12px;padding:0}\n  \/* units per carton and the unit \/ carton prices, each as a labelled line *\/\n  body.mwiz tbody td.k-upc, body.mwiz tbody td.k-pu{display:flex!important;grid-column:2\/span 2;\n    justify-content:space-between;align-items:baseline;padding:2px 0 0;font-size:12.5px;\n    font-variant-numeric:tabular-nums}\n  body.mwiz tbody td.k-upc{grid-row:5}\n  body.mwiz tbody td.k-pu{grid-row:6}\n  body.mwiz tbody td.k-upc::before, body.mwiz tbody td.k-pu::before{content:attr(data-label);\n    display:block!important;font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;\n    color:var(--ink-3);font-weight:600;font-family:Archivo,sans-serif}\n  body.mwiz tbody td.c-qty{grid-column:1\/-1;grid-row:7;border-top:1px dashed var(--line);\n    margin-top:9px;padding-top:10px;justify-content:center;\n    width:auto!important;min-width:0!important;background:transparent}\n  body.mwiz .qtywrap{display:flex;align-items:stretch;gap:0;width:100%;max-width:280px;margin:0 auto}\n  body.mwiz .qstep{display:block;width:52px;border:1px solid var(--line-strong);background:var(--surface-2);\n    font-size:20px;color:var(--accent-ink);cursor:pointer;flex:none}\n  body.mwiz .qminus{border-radius:11px 0 0 11px;border-right:0}\n  body.mwiz .qplus{border-radius:0 11px 11px 0;border-left:0}\n  body.mwiz .qty{flex:1;width:auto!important;min-width:0;height:46px;border-radius:0;text-align:center;\n    font-size:17px;font-weight:600;border:1px solid var(--line-strong)}\n  body.mwiz tbody td.k-tusd{grid-column:1\/-1;grid-row:8;display:flex!important;justify-content:space-between;\n    padding:8px 2px 0}\n  body.mwiz tbody td.k-tusd::before{content:attr(data-label);display:block!important;font-size:11px;\n    letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3);font-weight:600;font-family:Archivo,sans-serif}\n  body.mwiz tbody tr:not(.has-qty) td.k-tusd{display:none!important}\n  \/* the site's WhatsApp \/ chat floaters sit in the corner our nav owns \u2014 lift them *\/\n  body.mwiz .ht-ctc, body.mwiz .joinchat, body.mwiz .qlwapp, body.mwiz .chaty,\n  body.mwiz #chaty-widget, body.mwiz .wa-chat-box, body.mwiz .wa__btn_popup,\n  body.mwiz #whatsapp-chat, body.mwiz [class*=\"whatsapp\"i][class*=\"float\"i],\n  body.mwiz [id*=\"whatsapp\"i][style*=\"fixed\"]{bottom:96px!important}\n  \/* live container-fill readout on the product and desk steps *\/\n  .fitbar{position:fixed;left:10px;right:10px;bottom:calc(76px + env(safe-area-inset-bottom));z-index:89;\n    padding:9px 13px;border-radius:12px;background:var(--accent-soft);color:var(--accent-ink);\n    border:1px solid var(--line-strong);font-family:Archivo,sans-serif;font-weight:600;font-size:12.5px;\n    text-align:center;font-variant-numeric:tabular-nums}\n  .fitbar.warn{background:var(--warn-soft);color:var(--warn);border-color:var(--warn)}\n  .fitbar.over{background:#B3261E;color:#fff;border:0;font-weight:700;font-size:13px;\n    box-shadow:0 6px 18px rgba(160,40,24,.25);animation:fitpulse 1.5s ease-in-out infinite}\n  @keyframes fitpulse{0%,100%{box-shadow:0 0 0 0 rgba(217,119,106,.55)}50%{box-shadow:0 0 0 8px rgba(217,119,106,0)}}\n  @media (prefers-reduced-motion: reduce){.fitbar{animation:none}}\n}\n@media screen and (min-width:861px){.mwnav,.fitbar{display:none!important}}\n\n@media print{\n  @page{ size:A4 landscape; margin:7mm 6mm 9mm; }\n  .mast,.controls,.dock,.noprint,.lb,.sheet,.cat,.rail,.leftcol,.submitbar,.discbanner,\n  .draftbar,.mastbar,#codepanel{display:none!important}\n  html,body{background:#fff!important;color:#111!important}\n  body{font:9pt\/1.25 Helvetica,Arial,sans-serif;-webkit-print-color-adjust:exact;print-color-adjust:exact}\n  .wrap{max-width:none;padding:0}\n  .layout{display:block}\n  .tablewrap{border:0;box-shadow:none;overflow:visible;margin:0}\n\n  .printhead{display:block!important;padding:0 0 6px;border-bottom:2pt solid #0E5F58;margin-bottom:7px}\n  .printhead .t{font-size:15pt;font-weight:700;letter-spacing:-.3pt;color:#0E5F58}\n  .printhead .s{font-size:7.5pt;color:#444;margin-top:2px}\n  .printhead .buyer{font-size:8pt;margin-top:4px;padding-top:4px;border-top:.5pt solid #ccc;color:#111}\n\n  table{width:100%;border-collapse:collapse;table-layout:auto}\n  thead{display:table-header-group}\n  tfoot{display:table-footer-group}\n  tr{page-break-inside:avoid;break-inside:avoid}\n  thead th{\n    background:#0E5F58!important;color:#fff!important;position:static;\n    font-size:5.6pt;letter-spacing:.3pt;text-transform:uppercase;font-weight:700;\n    padding:2.5pt;border:0;border-bottom:.5pt solid #0E5F58;white-space:normal;vertical-align:bottom}\n  tbody td{padding:1.5pt 2.5pt;border:0;border-bottom:.4pt solid #DDD;font-size:6.9pt;\n    white-space:nowrap;vertical-align:middle}\n  \/* the product name is the only column allowed to wrap, and it gets the room\n     to do it in one or two lines instead of four *\/\n  th.c-name,td.c-name{width:150pt;max-width:150pt}\n  th.c-photo,td.c-photo{width:16pt}\n  tbody tr:nth-child(even) td{background:#F5F4F0!important}\n  tbody tr.has-qty td{background:#E4EFEA!important;font-weight:600}\n  .thumb{width:11pt;height:15pt;border:.4pt solid #ddd;border-radius:1pt;background:#fff}\n  .pname{white-space:normal;max-width:none;min-width:0}\n  .pname{line-height:1.15}\n  .pname .b{font-size:6.9pt;font-weight:700;display:inline}\n  .pname .f{font-size:6.9pt;color:#333;display:inline}\n  .pname .b::after{content:\" \u00b7 \";color:#999;font-weight:400}\n  .idx,.rowedit{font-size:6.6pt;color:#777}\n  .rowedit .pen,.warnflag{display:none!important}\n  \/* the chip styling is screen furniture; on paper just print the word *\/\n  .pub{background:none!important;border:0!important;padding:0!important;color:#333!important;\n       font-size:6.6pt;font-weight:600}\n  .was{font-size:5.8pt;color:#8a8a84}\n  .now{font-weight:700}\n  .muted{color:#aaa}\n  .qty{border:0!important;background:transparent!important;padding:0!important;width:auto!important;\n       font:700 7.6pt Helvetica,Arial,sans-serif;color:#111;-webkit-appearance:none;appearance:none;text-align:right}\n  .qty::-webkit-inner-spin-button,.qty::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}\n  td.n,th.n{text-align:right}\n  a{color:inherit;text-decoration:none}\n\n  \/* full price list \u2014 drop the order columns, keep everything descriptive *\/\n  body.print-all .g-calc,body.print-all td.c-qty,body.print-all th.c-qty{display:none!important}\n  \/* order sheet \u2014 drop the reference detail, keep what was ordered *\/\n  body.print-selected tbody tr:not(.has-qty){display:none!important}\n  body.print-selected .g-pack,body.print-selected .g-comp,body.print-selected .g-wt{display:none!important}\n  body.print-selected tbody tr:nth-child(even) td{background:transparent!important}\n  body.print-quote #app > *:not(#quoteprint){display:none!important}\n  body.print-quote #quoteprint{display:block!important}\n\n  .printfoot{display:block!important;margin-top:7px;padding-top:5px;border-top:1pt solid #0E5F58;\n    font-size:7.6pt;color:#222}\n  .printfoot strong{font-size:9pt;color:#0E5F58}\n}\n.printhead,.printfoot{display:none}\n\n\/* ---- messages ---- *\/\n\/* ---- catalogue admin ---- *\/\n.catadminbody{padding:0 14px 14px;display:flex;flex-direction:column;gap:10px}\n.catcur{margin:0;font-size:12.5px;color:var(--ink-2);line-height:1.45;overflow-wrap:anywhere}\n.catcur a{color:var(--accent-ink)}\n.catpick{text-align:center;cursor:pointer;flex:none;font-size:12.5px;padding:6px 10px}\n.docrow{display:flex;gap:10px;align-items:center;justify-content:space-between;\n  border:1px solid var(--line);border-radius:var(--r);padding:9px 11px;background:var(--surface-2)}\n.docrow .catcur{flex:1;min-width:0}\n.catprog .bar{height:6px;background:var(--sunken);border-radius:100px;overflow:hidden}\n.catprog .bar span{display:block;height:100%;width:0;background:var(--accent);transition:width .2s}\n.catprog .pc{display:block;font-size:11.5px;color:var(--ink-3);margin-top:4px;font-variant-numeric:tabular-nums}\n.catmsg{font-size:12.5px;padding:8px 10px;border-radius:var(--r);background:var(--sunken);color:var(--ink-2)}\n.catmsg.good{background:var(--accent-soft);color:var(--accent-ink);font-weight:600}\n.catmsg.bad{background:var(--warn-soft);color:var(--warn);font-weight:600}\n.catadminbody .f label{display:block;font-size:11.5px;color:var(--ink-3);margin:8px 0 3px;font-weight:600}\n.catadminbody .f input{width:100%;box-sizing:border-box;padding:6px 8px;font-size:12.5px;\n  border:1px solid var(--line-strong);border-radius:5px;background:var(--surface-2);color:inherit}\n.msgcard{display:flex;flex-direction:column;min-height:0}\n\/* Collapsing the conversation lifts everything below it up the column, which is\n   the point of having it at the top. The choice is remembered per browser. *\/\n.msgtoggle{background:none;border:0;padding:2px 4px;margin-left:auto;cursor:pointer;\n  color:var(--ink-3);display:flex;align-items:center;line-height:1}\n.msgtoggle:hover{color:var(--accent-ink)}\n.msgtoggle svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2.2;\n  stroke-linecap:round;stroke-linejoin:round;transition:transform .18s ease}\n#msgside.folded .msgtoggle svg{transform:rotate(-90deg)}\n#msgside.folded .msgbody,#msgside.folded .msgform{display:none}\n#msgside.folded .msghd{padding-bottom:12px}\n@media (prefers-reduced-motion: reduce){.msgtoggle svg{transition:none}}\n.msghd{align-items:center}\n.msgn{min-width:19px;height:19px;padding:0 6px;border-radius:100px;background:var(--crit);color:#fff;\n  font-size:11px;font-weight:700;line-height:19px;text-align:center;font-family:\"IBM Plex Mono\",monospace}\n.msghd .linkbtn{margin-left:auto}\n.msgbody{padding:0 14px 4px;max-height:290px;overflow-y:auto;display:flex;flex-direction:column;gap:9px}\n.msgempty{padding:10px 0 14px;color:var(--ink-3);font-size:12.5px;line-height:1.5}\n.bub{max-width:92%;padding:8px 11px;border-radius:12px;font-size:13px;line-height:1.45;\n  border:1px solid var(--line);background:var(--surface-2);align-self:flex-start;overflow-wrap:anywhere}\n.bub.mine{align-self:flex-end;background:var(--accent-soft);border-color:var(--accent-soft);color:var(--accent-ink)}\n.bub .meta{display:block;font-size:10.5px;color:var(--ink-3);margin-top:4px;font-variant-numeric:tabular-nums}\n.bub.mine .meta{color:var(--accent-ink);opacity:.75}\n.msgform{display:flex;gap:8px;align-items:flex-end;padding:11px 14px;border-top:1px solid var(--line)}\n.msgform textarea{flex:1;min-width:0;resize:vertical;padding:7px 9px;border:1px solid var(--line-strong);\n  border-radius:6px;background:var(--surface-2);font:inherit;font-size:13px;color:inherit;\n  font-family:\"Source Sans 3\",system-ui,sans-serif}\n.msgform textarea:focus{outline:0;border-color:var(--accent);background:var(--surface);\n  box-shadow:0 0 0 3px var(--accent-soft)}\n.msgform .btn{flex:none}\n.threadrow{display:block;width:100%;text-align:left;background:none;border:0;border-bottom:1px solid var(--line);\n  padding:9px 0;cursor:pointer;font:inherit;color:inherit}\n.threadrow:last-child{border-bottom:0}\n.threadrow:hover{color:var(--accent-ink)}\n.threadrow .tn{display:flex;align-items:center;gap:7px;font-weight:600;font-size:13.5px}\n.threadrow .tl{display:block;font-size:12px;color:var(--ink-2);margin-top:2px;\n  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.threadrow .tw{display:block;font-size:11px;color:var(--ink-3);margin-top:2px;font-variant-numeric:tabular-nums}\n.dotu{width:8px;height:8px;border-radius:100px;background:var(--crit);flex:none}\n\/* TranslatePress drops a floating EN\/TR bubble over every page. It overlaps the\n   totals panel and duplicates the switch already in our header, so it is hidden\n   on the portal pages only \u2014 the plugin still runs everywhere else. *\/\n#trp-floater-ls,.trp-floater-ls-codes,.trp-language-switcher-container.trp-bottom-right{display:none!important}\n@media (prefers-reduced-motion: reduce){*{transition:none!important;animation:none!important}}\n<\/style>\n\n<div class=\"gate\" id=\"gate\">\n  <div class=\"gatebox\">\n    <div class=\"bn\">CLAIMONT<\/div>\n    <div class=\"bs\" id=\"g-sub\">Internal \u00b7 Price list<\/div>\n    <h1 id=\"g-title\">Sign in<\/h1>\n    <p id=\"g-text\">Enter your personal staff code. Sami issues one per person.<\/p>\n    <input id=\"g-code\" type=\"text\" autocomplete=\"off\" spellcheck=\"false\" placeholder=\"CLA00000\" aria-label=\"Staff code\">\n    <div class=\"row\"><button class=\"btn btn-primary\" id=\"g-go\">Sign in<\/button><\/div>\n    <div class=\"gateerr\" id=\"g-err\"><\/div>\n    <div class=\"langmini\">\n      <button id=\"g-en\" aria-pressed=\"true\">English<\/button>\n      <button id=\"g-tr\" aria-pressed=\"false\">T\u00fcrk\u00e7e<\/button>\n    <\/div>\n  <\/div>\n<\/div>\n\n<div id=\"app\" hidden>\n<div class=\"mast\">\n  <div class=\"wrap mast-in\">\n    <div class=\"brandmark\">\n      <img decoding=\"async\" class=\"logo\" src=\"https:\/\/claimont.com\/wp-content\/uploads\/2024\/01\/logo.png\" alt=\"Claimont\" onerror=\"this.hidden=true\">\n      <span class=\"txt\">\n        <span class=\"bn\">CLAIMONT<\/span>\n        <span class=\"bs\" id=\"masthead-sub\">Export Desk<\/span>\n      <\/span>\n    <\/div>\n    <span class=\"who\" id=\"who\"><\/span>\n    <span class=\"sync\" id=\"sync\"><\/span>\n    <div class=\"fx\" id=\"fxbox\" title=\"\">\n      <span class=\"dot\"><\/span>\n      <span id=\"fxlabel\">USD \u2192 EUR<\/span>\n      <input id=\"fxrate\" type=\"number\" step=\"0.0001\" min=\"0.0001\" value=\"0.87\" aria-label=\"USD to EUR rate\">\n      <span id=\"fxsrc\" class=\"muted\"><\/span>\n    <\/div>\n    <div class=\"bellwrap\">\n      <button class=\"iconbtn bell\" id=\"btn-bell\" aria-expanded=\"false\" aria-label=\"Activity\">\n        <svg viewbox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M12 2a6 6 0 0 0-6 6v3.6L4.3 15a1 1 0 0 0 .9 1.5h13.6a1 1 0 0 0 .9-1.5L18 11.6V8a6 6 0 0 0-6-6z\"\/><path d=\"M9.5 19a2.5 2.5 0 0 0 5 0\"\/><\/svg>\n        <span class=\"belln\" id=\"belln\" hidden>0<\/span>\n      <\/button>\n      <div class=\"bellpanel\" id=\"bellpanel\" hidden>\n        <div class=\"bellhd\"><span id=\"bell-title\">Activity<\/span>\n          <button class=\"linkbtn\" id=\"bell-clear\">Mark all read<\/button><\/div>\n        <div class=\"bellbody\" id=\"bell-body\"><\/div>\n      <\/div>\n    <\/div>\n    <button class=\"iconbtn\" id=\"btn-signout\">Sign out<\/button>\n    <div class=\"seg\" role=\"group\" aria-label=\"Language\">\n      <button id=\"lang-en\" aria-pressed=\"true\">EN<\/button>\n      <button id=\"lang-tr\" aria-pressed=\"false\">TR<\/button>\n    <\/div>\n  <\/div>\n<\/div>\n\n<div class=\"controls\">\n  <div class=\"wrap controls-in\">\n    <div class=\"search\">\n      <svg viewbox=\"0 0 24 24\"><circle cx=\"11\" cy=\"11\" r=\"7\"\/><path d=\"M20 20l-3.5-3.5\"\/><\/svg>\n      <input id=\"q\" type=\"search\" placeholder=\"Search\" aria-label=\"Search\">\n    <\/div>\n    <div class=\"chips\" id=\"chips\"><\/div>\n    <div class=\"spacer\"><\/div>\n    <details class=\"colmenu\">\n      <summary class=\"btn\" id=\"colbtn\">Columns<\/summary>\n      <div class=\"colpanel\">\n        <div class=\"hd\" id=\"colhd\">Detail groups<\/div>\n        <label><input type=\"checkbox\" id=\"cg-pack\" checked><span id=\"lbl-pack\">Packing &amp; dimensions<\/span><\/label>\n        <label><input type=\"checkbox\" id=\"cg-wt\" checked><span id=\"lbl-wt\">Weights<\/span><\/label>\n        <label><input type=\"checkbox\" id=\"cg-comp\" checked><span id=\"lbl-comp\">Codes &amp; storage<\/span><\/label>\n        <label><input type=\"checkbox\" id=\"cg-unit\" checked><span id=\"lbl-unit\">Unit prices<\/span><\/label>\n        <label><input type=\"checkbox\" id=\"cg-calc\" checked><span id=\"lbl-calc\">Order totals<\/span><\/label>\n      <\/div>\n    <\/details>\n    <button class=\"btn\" id=\"btn-rail\">My customers<\/button>\n    <button class=\"btn\" id=\"btn-customers\">Customers<\/button>\n    <button class=\"btn\" id=\"btn-users\" hidden>Staff<\/button>\n    <button class=\"btn\" id=\"btn-add\">+ Add product<\/button>\n    <button class=\"btn\" id=\"btn-master\" aria-pressed=\"false\">Master edit<\/button>\n    <button class=\"btn btn-pending\" id=\"btn-pending\" hidden><\/button>\n    <button class=\"btn\" id=\"btn-reset\">Reset<\/button>\n    <button class=\"btn\" id=\"btn-csv\">Excel<\/button>\n    <button class=\"btn btn-primary\" id=\"btn-print\">PDF \/ Print<\/button>\n    <button class=\"btn btn-primary\" id=\"btn-quote\" disabled>Customer PDF<\/button>\n  <\/div>\n<\/div>\n\n<div class=\"wrap layout\">\n <div class=\"leftcol\" id=\"leftcol\">\n <aside class=\"side noprint\" id=\"side\">\n<div class=\"cont\" id=\"controw\">\n  <div class=\"contline\">\n    <span class=\"lbl\" id=\"contlbl\">Container planning<\/span>\n    <button class=\"linkbtn\" id=\"btn-continfo\">What do these mean?<\/button>\n    <div class=\"seg loadseg\" role=\"group\">\n      <button id=\"lm-floor\" aria-pressed=\"true\">Floor loaded<\/button>\n      <button id=\"lm-pal\" aria-pressed=\"false\">Palletised<\/button>\n    <\/div>\n    <details class=\"palbox\" id=\"palbox\" hidden>\n      <summary class=\"btn\" id=\"palbtn\">Pallet settings<\/summary>\n      <div class=\"palpanel\">\n        <div class=\"f\"><label for=\"pal-type\" id=\"l-paltype\">Pallet size<\/label>\n          <select id=\"pal-type\"><\/select><\/div>\n        <div class=\"slots\" id=\"pal-slots\"><\/div>\n        <div class=\"f\"><label for=\"pal-kg\" id=\"l-palkg\">Weight of one empty pallet (kg)<\/label>\n          <input id=\"pal-kg\" type=\"number\" min=\"0\" step=\"0.5\" value=\"25\"><\/div>\n        <div class=\"note\" id=\"pal-note\"><\/div>\n      <\/div>\n    <\/details>\n  <\/div>\n  <div class=\"contline pick\">\n    <label for=\"cont-type\" id=\"l-conttype\">I want to ship in<\/label>\n    <select id=\"cont-type\"><\/select>\n    <label for=\"cont-n\" id=\"l-contn\">How many<\/label>\n    <input id=\"cont-n\" type=\"number\" min=\"1\" max=\"99\" step=\"1\" value=\"1\">\n    <label for=\"sku-cap\" id=\"l-skucap\">Max SKUs per container<\/label>\n    <select id=\"sku-cap\">\n      <option value=\"0\">No limit<\/option>\n      <option value=\"2\">2<\/option><option value=\"3\">3<\/option>\n      <option value=\"4\">4<\/option><option value=\"5\">5<\/option><option value=\"6\">6<\/option>\n    <\/select>\n    <div class=\"skumsg\" id=\"skumsg\" hidden><\/div>\n    <div class=\"fitmsg\" id=\"fitmsg\"><\/div>\n  <\/div>\n  <div class=\"meters\" id=\"meters\"><\/div>\n  <div class=\"c3dwrap noprint\" id=\"c3d\"><\/div>\n  <div class=\"flnote2\">Floor-loading volumes keep a ~10% packing allowance in reserve.<\/div>\n<\/div>\n <\/aside>\n <aside class=\"side noprint\" id=\"msgside\">\n  <div class=\"cont msgcard\">\n    <div class=\"contline msghd\">\n      <span class=\"lbl\" id=\"msglbl\">Messages<\/span>\n      <span class=\"msgn\" id=\"msgn\" hidden>0<\/span>\n      <button class=\"msgtoggle\" id=\"msgfold\" aria-expanded=\"true\" aria-controls=\"msgbody\" aria-label=\"Collapse messages\">\n        <svg viewbox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\"\/><\/svg>\n      <\/button>\n      <button class=\"linkbtn\" id=\"msg-back\" hidden>\u2190 All<\/button>\n    <\/div>\n    <div class=\"msgbody\" id=\"msgbody\"><\/div>\n    <div class=\"msgform\" id=\"msgform\" hidden>\n      <textarea id=\"msgtext\" rows=\"2\" placeholder=\"Write a message\u2026\" aria-label=\"Mesaj\"><\/textarea>\n      <button class=\"btn btn-primary\" id=\"msgsend\">Send<\/button>\n    <\/div>\n  <\/div>\n <\/aside>\n <aside class=\"rail\" id=\"rail\">\n   <div class=\"railhd\"><span id=\"rail-title\">My customers<\/span>\n     <button class=\"railx\" id=\"rail-x\" aria-label=\"Kapat\">\u00d7<\/button><\/div>\n   <div class=\"railbody\" id=\"rail-body\"><\/div>\n <\/aside>\n <aside class=\"side noprint\" id=\"catadmin\" hidden>\n  <div class=\"cont catadmincard\">\n    <div class=\"contline\"><span class=\"lbl\" id=\"catadmin-lb\">Catalogue<\/span><\/div>\n    <div class=\"catadminbody\">\n      <div class=\"docrow\" data-kind=\"images\">\n        <p class=\"catcur\" id=\"doccur-images\">\u2014<\/p>\n        <label class=\"btn catpick\" for=\"docfile-images\" id=\"docpick-images\">Upload\u2026<\/label>\n        <input id=\"docfile-images\" type=\"file\" accept=\".csv,.txt,.json\" hidden>\n      <\/div>\n      <div class=\"docrow\" data-kind=\"catalogue\">\n        <p class=\"catcur\" id=\"doccur-catalogue\">\u2014<\/p>\n        <label class=\"btn catpick\" for=\"docfile-catalogue\" id=\"docpick-catalogue\">Upload\u2026<\/label>\n        <input id=\"docfile-catalogue\" type=\"file\" accept=\"application\/pdf,.pdf\" hidden>\n      <\/div>\n      <div class=\"docrow\" data-kind=\"pricePdf\">\n        <p class=\"catcur\" id=\"doccur-pricePdf\">\u2014<\/p>\n        <label class=\"btn catpick\" for=\"docfile-pricePdf\" id=\"docpick-pricePdf\">Upload\u2026<\/label>\n        <input id=\"docfile-pricePdf\" type=\"file\" accept=\"application\/pdf,.pdf\" hidden>\n      <\/div>\n      <div class=\"docrow\" data-kind=\"priceXlsx\">\n        <p class=\"catcur\" id=\"doccur-priceXlsx\">\u2014<\/p>\n        <label class=\"btn catpick\" for=\"docfile-priceXlsx\" id=\"docpick-priceXlsx\">Upload\u2026<\/label>\n        <input id=\"docfile-priceXlsx\" type=\"file\" accept=\".xlsx,application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet\" hidden>\n      <\/div>\n      <div class=\"catprog\" id=\"catadmin-prog\" hidden><div class=\"bar\"><span><\/span><\/div><span class=\"pc\" id=\"catadmin-pc\"><\/span><\/div>\n      <div class=\"catmsg\" id=\"catadmin-msg\" hidden><\/div>\n      <details class=\"pubfall\">\n        <summary id=\"catadmin-alt\">Use an address instead<\/summary>\n        <div class=\"f\"><label for=\"caturl\" id=\"catadmin-urllb\">Catalogue PDF address<\/label>\n          <input id=\"caturl\" type=\"url\" placeholder=\"https:\/\/\u2026\"><\/div>\n        <div class=\"f\"><label for=\"catpages\" id=\"catadmin-pageslb\">Snapshot images address<\/label>\n          <input id=\"catpages\" type=\"url\" placeholder=\"https:\/\/\u2026claimont-catalogue.txt\"><\/div>\n        <button class=\"btn\" id=\"catadmin-save\">Save<\/button>\n      <\/details>\n    <\/div>\n  <\/div>\n <\/aside>\n \n <\/div>\n <main class=\"main\">\n  <div class=\"oldver noprint\" id=\"oldver\" hidden><\/div>\n\n  <div class=\"printhead\">\n    <div class=\"t\" id=\"printtitle\">CLAIMONT \u2014 Price list 2026<\/div>\n    <div class=\"s\" id=\"printsub\"><\/div>\n  <\/div>\n\n  <div class=\"mastbar noprint\" id=\"mastbar\" hidden><\/div>\n\n  <div class=\"scrollbar noprint\" id=\"scrollbar\">\n    <span class=\"hint\" id=\"scrollhint\">Scroll for more columns \u2192<\/span>\n    <div class=\"scrolltop\" id=\"scrolltop\"><div id=\"scrollspacer\"><\/div><\/div>\n    <div class=\"qtyctl\" id=\"qtyctl\">\n      <span class=\"lb\" id=\"qtyctl-lb\">Cartons box<\/span>\n      <button type=\"button\" id=\"qty-narrow\" aria-label=\"Narrower\">\u2212<\/button>\n      <span class=\"val\" id=\"qty-val\">104<\/span>\n      <button type=\"button\" id=\"qty-wide\" aria-label=\"Wider\">+<\/button>\n    <\/div>\n  <\/div>\n  <div class=\"tablewrap\" id=\"tablewrap\">\n    <table id=\"tbl\">\n      <thead><tr id=\"hrow\"><\/tr><\/thead>\n      <tbody id=\"tbody\"><\/tbody>\n    <\/table>\n    <div class=\"empty\" id=\"empty\" hidden><\/div>\n  <\/div>\n\n  <div class=\"dock\" id=\"dock\">\n    <div class=\"dock-in\" id=\"stats\"><\/div>\n  <\/div>\n\n\n  <div class=\"printfoot\" id=\"printfoot\"><\/div>\n\n  <input id=\"gridphoto\" type=\"file\" accept=\"image\/*\" hidden>\n\n  <div id=\"codepanel\" class=\"noprint\" hidden><\/div>\n\n  <div class=\"notes noprint\">\n    <h2 id=\"noteshd\">Notes<\/h2>\n    <ul id=\"noteslist\"><\/ul>\n  <\/div>\n <\/main>\n<\/div>\n\n<div class=\"fitbar noprint\" id=\"fitbar\" hidden><\/div>\n<div class=\"mwnav noprint\" id=\"mwnav\" hidden>\n  <button class=\"mwback\" id=\"mw-back\" aria-label=\"Back\">&#8592;<\/button>\n  <div class=\"mwmid\">\n    <div class=\"mwdots\" aria-hidden=\"true\"><span><\/span><span><\/span><span><\/span><\/div>\n    <div class=\"mwlbl\" id=\"mw-lbl\"><\/div>\n    <div class=\"mwtot\" id=\"mw-tot\"><\/div>\n  <\/div>\n  <button class=\"mwnext\" id=\"mw-next\">Next &#8594;<\/button>\n<\/div>\n\n<div class=\"sheet\" id=\"quotesheet\" role=\"dialog\" aria-modal=\"true\">\n  <div class=\"sheetbox\" style=\"max-width:980px\">\n    <div class=\"sheethd\"><h2 id=\"qt-title\">Prepare the customer's order<\/h2><button class=\"btn\" id=\"qt-x\">Kapat<\/button><\/div>\n    <div class=\"sheetbody\">\n      <div class=\"qgrid\">\n        <div class=\"f\"><label id=\"qt-l-pick\" for=\"qt-pick\">Customer<\/label>\n          <select id=\"qt-pick\"><option value=\"\">\u2014<\/option><\/select><\/div>\n        <div class=\"f\"><label id=\"qt-l-company\" for=\"qt-company\">Company<\/label><input id=\"qt-company\"><\/div>\n        <div class=\"f\"><label id=\"qt-l-contact\" for=\"qt-contact\">Contact person<\/label><input id=\"qt-contact\"><\/div>\n        <div class=\"f\"><label id=\"qt-l-email\" for=\"qt-email\">Email<\/label><input id=\"qt-email\" type=\"email\"><\/div>\n        <div class=\"f\"><label id=\"qt-l-phone\" for=\"qt-phone\">Phone<\/label><input id=\"qt-phone\"><\/div>\n        <div class=\"f\"><label id=\"qt-l-country\" for=\"qt-country\">Country \/ destination<\/label><input id=\"qt-country\"><\/div>\n        <div class=\"f wide\"><label id=\"qt-l-notes\" for=\"qt-notes\">Notes on the document<\/label><input id=\"qt-notes\"><\/div>\n      <\/div>\n      <h3 class=\"qt-items-h\" id=\"qt-items-h\">Products \u2014 adjust the agreed price per carton<\/h3>\n      <div class=\"regwrap\"><table class=\"regtbl\" id=\"qt-table\"><thead><\/thead><tbody><\/tbody><tfoot><\/tfoot><\/table><\/div>\n    <\/div>\n    <div class=\"sheetft\">\n      <button class=\"btn btn-primary\" id=\"qt-print\">Print \/ Save as PDF<\/button>\n      <button class=\"btn\" id=\"qt-save\">Save to customer's orders<\/button>\n      <span class=\"muted\" id=\"qt-hint\"><\/span>\n    <\/div>\n  <\/div>\n<\/div>\n<div id=\"quoteprint\" hidden><\/div>\n\n<div class=\"sheet\" id=\"regsheet\" role=\"dialog\" aria-modal=\"true\">\n  <div class=\"sheetbox\" style=\"max-width:1080px\">\n    <div class=\"sheethd\">\n      <h2 id=\"reg-title\">Customers<\/h2>\n      <div class=\"seg\" id=\"reg-views\" role=\"group\" hidden>\n        <button id=\"reg-v-active\" aria-pressed=\"true\">Active<\/button>\n        <button id=\"reg-v-arch\" aria-pressed=\"false\">Archived<\/button>\n      <\/div>\n      <button class=\"btn btn-primary\" id=\"reg-new\">New<\/button>\n      <button class=\"btn\" id=\"reg-x\">Kapat<\/button>\n    <\/div>\n    <div class=\"sheetbody\">\n      <div class=\"regwrap\"><table class=\"regtbl\"><thead><tr id=\"reg-head\"><\/tr><\/thead>\n        <tbody id=\"reg-body\"><\/tbody><\/table><\/div>\n      <div class=\"empty\" id=\"reg-empty\" hidden><\/div>\n      <div id=\"reg-form\" hidden>\n        <fieldset class=\"fset\"><legend id=\"rf-legend\">Customer<\/legend>\n          <div class=\"grid\">\n            <div class=\"f\"><label for=\"rf-name\" id=\"rf-l-name\">Customer name<\/label><input id=\"rf-name\"><\/div>\n            <div class=\"f\"><label for=\"rf-rep\" id=\"rf-l-rep\">Representative<\/label><input id=\"rf-rep\" list=\"replist\" autocomplete=\"off\"><\/div>\n            <div class=\"f\"><label for=\"rf-mail\" id=\"rf-l-mail\">Contact email<\/label><input id=\"rf-mail\" type=\"email\" autocomplete=\"off\"><\/div>\n            <div class=\"f\"><label for=\"rf-cphone\" id=\"rf-l-cphone\">Contact phone<\/label><input id=\"rf-cphone\" type=\"text\" autocomplete=\"off\"><\/div>\n            <div class=\"f\"><label for=\"rf-ctitle\" id=\"rf-l-ctitle\">Title on their business card<\/label><input id=\"rf-ctitle\" type=\"text\" autocomplete=\"off\"><\/div>\n            <div class=\"f\"><label for=\"rf-country\" id=\"rf-l-country\">Country<\/label><input id=\"rf-country\" type=\"text\" autocomplete=\"off\"><\/div>\n            <div class=\"f\"><label for=\"rf-disc\" id=\"rf-l-disc\">Discount %<\/label><input id=\"rf-disc\" type=\"number\" min=\"0\" max=\"90\" step=\"0.5\" value=\"0\"><\/div>\n            <div class=\"f\"><label for=\"rf-owner\" id=\"rf-l-owner\">Assigned user<\/label>\n              <select id=\"rf-owner\"><\/select><\/div>\n            <div class=\"f\"><label for=\"rf-moq\" id=\"rf-l-moq\">Minimum SKUs<\/label>\n              <select id=\"rf-moq\">\n                <option value=\"0\">No limit<\/option>\n                <option value=\"2\">Up to 2 SKU per container\/truck<\/option>\n                <option value=\"3\">Up to 3 SKU per container\/truck<\/option>\n                <option value=\"4\">Up to 4 SKU per container\/truck<\/option><\/select><\/div>\n            <div class=\"f\"><label for=\"rf-role\" id=\"rf-l-role\">Role<\/label>\n              <select id=\"rf-role\">\n                <option value=\"user\">User<\/option>\n                <option value=\"super\">Super user<\/option>\n                <option value=\"admin\">Admin<\/option><\/select><\/div>\n            <div class=\"f\"><label for=\"rf-max\" id=\"rf-l-max\">Highest discount they may give %<\/label>\n              <input id=\"rf-max\" type=\"number\" min=\"0\" max=\"90\" step=\"1\" value=\"0\"><\/div>\n            <div class=\"f\"><label for=\"rf-uemail\" id=\"rf-l-uemail\">Email (shown to their customers)<\/label>\n              <input id=\"rf-uemail\" type=\"email\" autocomplete=\"off\"><\/div>\n            <div class=\"f\"><label for=\"rf-uphone\" id=\"rf-l-uphone\">Phone (shown to their customers)<\/label>\n              <input id=\"rf-uphone\" type=\"text\" autocomplete=\"off\"><\/div>\n            <div class=\"f wide\"><label style=\"display:flex;gap:9px;align-items:center;font-size:14px;cursor:pointer\">\n              <input type=\"checkbox\" id=\"rf-active\" checked> <span id=\"rf-l-active\">Active \u2014 the code works<\/span><\/label><\/div>\n          <\/div>\n        <\/fieldset>\n        <div class=\"newcode\" id=\"rf-newcode\" hidden>\n          <div class=\"lbl\" id=\"rf-codelbl\">Code<\/div>\n          <div class=\"bigcode\" id=\"rf-code\">\u2014<\/div>\n          <p id=\"rf-codenote\"><\/p>\n        <\/div>\n      <\/div>\n    <\/div>\n    <div class=\"sheetft\">\n      <button class=\"btn btn-primary\" id=\"reg-save\" hidden>Save<\/button>\n      <button class=\"btn\" id=\"reg-back\" hidden>Back to list<\/button>\n      <span class=\"err\" id=\"reg-err\"><\/span>\n      <span class=\"muted\" id=\"reg-status\" style=\"margin-left:auto\"><\/span>\n    <\/div>\n  <\/div>\n<\/div>\n\n<div class=\"sheet\" id=\"sheet\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"sheettitle\">\n  <div class=\"sheetbox\">\n    <div class=\"sheethd\">\n      <h2 id=\"sheettitle\">Add product<\/h2>\n      <button class=\"btn\" id=\"sheet-del\" hidden>Remove<\/button>\n      <button class=\"btn\" id=\"sheet-x\">Kapat<\/button>\n    <\/div>\n    <div class=\"sheetbody\" id=\"sheetbody\"><\/div>\n    <div class=\"sheetft\">\n      <button class=\"btn btn-primary\" id=\"sheet-save\">Save product<\/button>\n      <button class=\"btn\" id=\"sheet-cancel\">Cancel<\/button>\n      <span class=\"err\" id=\"sheet-err\"><\/span>\n    <\/div>\n  <\/div>\n<\/div>\n\n<\/div>\n\n<div class=\"sheet\" id=\"pastsheet\" role=\"dialog\" aria-modal=\"true\">\n  <div class=\"sheetbox\" style=\"max-width:940px\">\n    <div class=\"sheethd\"><h2 id=\"past-title\">Order<\/h2><button class=\"btn\" id=\"past-x\">Kapat<\/button><\/div>\n    <div class=\"sheetbody\" id=\"past-body\"><\/div>\n  <\/div>\n<\/div>\n\n<datalist id=\"replist\"><\/datalist>\n<div class=\"sheet\" id=\"infosheet\" role=\"dialog\" aria-modal=\"true\">\n  <div class=\"sheetbox\" style=\"max-width:720px\">\n    <div class=\"sheethd\"><h2 id=\"info-title\">Containers and pallets<\/h2><button class=\"btn\" id=\"info-x\">Kapat<\/button><\/div>\n    <div class=\"sheetbody\" id=\"info-body\"><\/div>\n  <\/div>\n<\/div>\n\n<div class=\"lb\" id=\"lb\"><img id=\"lbimg\" alt=\"\"><\/div>\n\n<script>\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n   EDIT PRICES HERE \u2014 everything else below is generated data.\n   Format:   item number: [ unit price USD, carton price USD ],\n   Both are ex-works. EUR is calculated from the rate in the header.\n   \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\nconst PRICES = {\n  1: [0.121, 6.05],   \/\/ 2603 \u00b7 Rixy Llama \u00b7 Cheddar Cheese Corn Chips \u00b7 18 g\n  2: [0.22, 3.3],   \/\/ 2652 \u00b7 Rixy Llama \u00b7 Cheddar Cheese Corn Chips \u00b7 35 g\n  3: [0.32, 4.8],   \/\/ 2607 \u00b7 Rixy Llama \u00b7 Cheddar Cheese Corn Chips \u00b7 65 g\n  4: [0.121, 6.05],   \/\/ 2634 \u00b7 Rixy Llama \u00b7 Space Chicken \u00b7 18 g\n  5: [0.32, 4.8],   \/\/ 2639 \u00b7 Rixy Llama \u00b7 Space Chicken \u00b7 65 g\n  6: [0.22, 3.3],   \/\/ 2653 \u00b7 Rixy Llama \u00b7 Space Chicken Corn Chips \u00b7 35 g\n  7: [0.32, 4.8],   \/\/ 2632 \u00b7 Rixy Llama \u00b7 Pizza Corn Chips \u00b7 65 g\n  8: [0.22, 3.3],   \/\/ 2654 \u00b7 Rixy Llama \u00b7 Pizza Corn Chips \u00b7 35 g\n  9: [0.121, 6.05],   \/\/ 2627 \u00b7 Rixy Llama \u00b7 Pizza Corn Chips \u00b7 18 g\n  10: [0.32, 4.8],   \/\/ 2615 \u00b7 Rixy Llama \u00b7 Peanut Butter Corn Chips \u00b7 65 g\n  11: [0.22, 3.3],   \/\/ 2612 \u00b7 Rixy Llama \u00b7 Peanut Butter Corn Chips \u00b7 35 g\n  12: [0.121, 6.05],   \/\/ 2609 \u00b7 Rixy Llama \u00b7 Burger Corn Chips \u00b7 18 g\n  13: [0.32, 4.8],   \/\/ 2622 \u00b7 Rixy Rings \u00b7 Onion \u00b7 60 g\n  14: [0.32, 4.8],   \/\/ 2625 \u00b7 Rixy Rings \u00b7 Sea Salt & Pepper \u00b7 60 g\n  15: [0.32, 4.8],   \/\/ 2620 \u00b7 Rixy Rings \u00b7 Cheese \u00b7 60 g\n  16: [0.22, 3.3],   \/\/ 2822 \u00b7 World of Unicorns \u00b7 Cheddar Cheese Corn Chips \u00b7 35 g\n  17: [0.32, 4.8],   \/\/ 2819 \u00b7 World of Unicorns \u00b7 Space Chicken Corn Chips \u00b7 65 g\n  18: [0.22, 3.3],   \/\/ 2823 \u00b7 World of Unicorns \u00b7 Space Chicken Corn Chips \u00b7 35 g\n  19: [0.32, 4.8],   \/\/ 2810 \u00b7 World of Unicorns \u00b7 Pizza Corn Chips \u00b7 65 g\n  20: [0.22, 3.3],   \/\/ 2824 \u00b7 World of Unicorns \u00b7 Pizza Corn Chips \u00b7 35 g\n  21: [0.7, 10.5],   \/\/ 2304 \u00b7 Lava Waves \u00b7 Spicy Cheese & Lime \u00b7 70 g\n  22: [0.4, 6.0],   \/\/ 2308 \u00b7 Lava Waves \u00b7 Spicy Cheese & Lime \u00b7 40 g\n  23: [0.7, 10.5],   \/\/ 2310 \u00b7 Lava Waves \u00b7 Tomato & Herbs \u00b7 70 g\n  24: [0.4, 6.0],   \/\/ 2314 \u00b7 Lava Waves \u00b7 Tomato & Herbs \u00b7 40 g\n  25: [0.7, 10.5],   \/\/ 2321 \u00b7 Lava Waves \u00b7 Atomic \u00b7 70 g\n  26: [0.4, 6.0],   \/\/ 2302 \u00b7 Lava Waves \u00b7 Atomic \u00b7 40 g\n  27: [0.4, 6.0],   \/\/ 2319 \u00b7 Lava Waves \u00b7 Pizza \u00b7 40 g\n  28: [0.44, 6.6],   \/\/ 2501 \u00b7 ProChips \u00b7 Cheddar Cheese & Onion Protein Chips \u00b7 50 g\n  29: [0.44, 6.6],   \/\/ 2502 \u00b7 ProChips \u00b7 Chilli Lime Protein Chips \u00b7 50 g\n  30: [0.44, 6.6],   \/\/ 2503 \u00b7 ProChips \u00b7 Herbs Seasoning Protein Chips \u00b7 50 g\n  31: [0.59, 7.08],   \/\/ 2642 \u00b7 Rixy XXL \u00b7 Holland Cheese \u00b7 107 g\n  32: [0.59, 7.08],   \/\/ 2655 \u00b7 Rixy XXL \u00b7 Sweet Corn \u00b7 107 g\n  33: [0.55, 11.0],   \/\/ 2618 \u00b7 Rixy XXL \u00b7 White Cheese \u00b7 90 g\n  34: [0.55, 11.0],   \/\/ 2617 \u00b7 Rixy XXL \u00b7 Ketchup \u00b7 90 g\n  35: [0.55, 11.0],   \/\/ 2656 \u00b7 Rixy XXL \u00b7 Chilli & Lime \u00b7 90 g\n  36: [0.59, 7.08],   \/\/ 2662 \u00b7 Rixy Llama XXL \u00b7 Pizza \u00b7 107 g\n  37: [0.59, 11.8],   \/\/ 2602 \u00b7 Rixy Dino XXL \u00b7 Pizza \u00b7 107 g\n  38: [0.59, 11.8],   \/\/ 2601 \u00b7 Rixy Dino XXL \u00b7 Cheese \u00b7 107 g\n  39: [0.69, 6.21],   \/\/ 2210 \u00b7 Dubai Fusion \u00b7 Garlic & Olive Oil \u00b7 115 g\n  40: [0.42, 6.3],   \/\/ 2202 \u00b7 Dubai Fusion \u00b7 Garlic & Olive Oil \u00b7 65 g\n  41: [0.69, 6.21],   \/\/ 2012 \u00b7 Dubai Fusion \u00b7 Pesto \u00b7 115 g\n  42: [0.42, 6.3],   \/\/ 2205 \u00b7 Dubai Fusion \u00b7 Pesto \u00b7 65 g\n  43: [0.69, 6.21],   \/\/ 2013 \u00b7 Dubai Fusion \u00b7 Sour Cream & Chives \u00b7 115 g\n  44: [0.69, 6.21],   \/\/ 2011 \u00b7 Dubai Fusion \u00b7 Napoli Pizza \u00b7 115 g\n  45: [0.35, 5.25],   \/\/ 2429 \u00b7 Munchiz SpongeBob \u00b7 Cheese \u00b7 35 g\n  46: [0.35, 5.25],   \/\/ 2434 \u00b7 Munchiz Ninja Turtles \u00b7 Pizza \u00b7 35 g\n  47: [0.35, 5.25],   \/\/ 2407 \u00b7 Munchiz Barbie \u00b7 Strawberry \u00b7 35 g\n  48: [0.35, 5.25],   \/\/ 2405 \u00b7 Munchiz Barbie \u00b7 Ketchup \u00b7 35 g\n  49: [0.35, 5.25],   \/\/ 2411 \u00b7 Munchiz Hello Kitty \u00b7 Vanilla & Milk \u00b7 35 g\n  50: [0.35, 5.25],   \/\/ 2423 \u00b7 Munchiz One Piece \u00b7 Mushroom & Cream \u00b7 35 g\n  51: [0.69, 13.8],   \/\/ 2425 \u00b7 Munchiz One Piece \u00b7 Spicy Cheese & Lime \u00b7 107 g\n  52: [0.35, 5.25],   \/\/ 2414 \u00b7 Munchiz Hot Wheels \u00b7 Cheese \u00b7 35 g\n  53: [0.69, 13.8],   \/\/ 2451 \u00b7 Munchiz Super Hero \u00b7 Chicken Noodles \u00b7 107 g\n  54: [0.69, 13.8],   \/\/ 2444 \u00b7 Munchiz SpongeBob XXL \u00b7 Cheese \u00b7 107 g\n  55: [0.69, 13.8],   \/\/ 2450 \u00b7 Munchiz Dora \u00b7 Cheddar Cheese \u00b7 107 g\n  56: [0.69, 13.8],   \/\/ 2446 \u00b7 Munchiz Barbie XXL \u00b7 Sweet Corn \u00b7 107 g\n  57: [0.69, 13.8],   \/\/ 2445 \u00b7 Munchiz Barbie XXL \u00b7 Cheese \u00b7 107 g\n  58: [0.69, 13.8],   \/\/ 2447 \u00b7 Munchiz Hello Kitty XXL \u00b7 Sweet Corn \u00b7 107 g\n  59: [0.69, 13.8],   \/\/ 2448 \u00b7 Munchiz Kuromi XXL \u00b7 Ketchup \u00b7 107 g\n  60: [0.35, 21.0],   \/\/ 2440 \u00b7 Munchiz Display Stand V3 \u00b7 Barbie Ketchup \u00b7 Hot Wheels Cheese \u00b7 Hello Kitty Vanilla & Milk \u00b7 SpongeBob Cheddar Cheese \u00b7 30 g\n  61: [0.6, 12.0],   \/\/ 2657 \u00b7 Puffy Cubs \u00b7 Salt & Vinegar \u00b7 99 g\n  62: [0.6, 12.0],   \/\/ 2658 \u00b7 Puffy Cubs \u00b7 Pesto \u00b7 99 g\n  63: [0.6, 12.0],   \/\/ 2659 \u00b7 Puffy Cubs \u00b7 French Cheese \u00b7 99 g\n  64: [0.6, 12.0],   \/\/ 2103 \u00b7 7Chips \u00b7 Ring Pizza \u00b7 99 g\n  65: [0.6, 12.0],   \/\/ 2104 \u00b7 7Chips \u00b7 Cone Ketchup & Mayonnaise \u00b7 99 g\n  66: [0.6, 12.0],   \/\/ 2105 \u00b7 7Chips \u00b7 Flower Chilli Lime \u00b7 99 g\n  67: [0.6, 12.0],   \/\/ 2106 \u00b7 7Chips \u00b7 Cone Salt & Vinegar \u00b7 99 g\n  68: [0.6, 12.0],   \/\/ 2107 \u00b7 7Chips \u00b7 Flat Pesto \u00b7 99 g\n  69: [0.6, 12.0],   \/\/ 2108 \u00b7 7Chips \u00b7 Flat Salt & Vinegar \u00b7 99 g\n  70: [0.6, 12.0],   \/\/ 2660 \u00b7 Rixy Pops \u00b7 Classic Popcorn \u00b7 99 g\n  71: [0.6, 12.0],   \/\/ 2661 \u00b7 Rixy Pops \u00b7 White Cheddar Popcorn \u00b7 99 g\n  72: [0.38, 5.7],   \/\/ 2504 \u00b7 ProKids \u00b7 Cheese \u00b7 35 g\n  73: [0.38, 5.7],   \/\/ 2505 \u00b7 ProKids \u00b7 Pizza \u00b7 35 g\n  74: [0.38, 5.7],   \/\/ 2506 \u00b7 ProKids \u00b7 Vegetable Seasoning \u00b7 35 g\n  75: [0.38, 5.7],   \/\/ 2507 \u00b7 ProKids \u00b7 Sweet Corn \u00b7 35 g\n};\n\n\/* \u2550\u2550\u2550 end of editable prices \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\n\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n   SHARED DATA PAGE\n   Both portals read this WordPress page, so a change published here\n   reaches the team portal and the customer portal at once.\n   Leave the path as it is unless you gave the page a different slug.\n   \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\nconst DATA_URL = \"\/claimont-data\/\";\n\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n   PRODUCT PHOTOS\n   The packshots live in one file so this page stays small enough to\n   paste into WordPress. Upload claimont-images.txt to Media Library,\n   copy its address, and paste it between the quotes below.\n   \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\nconst IMAGES_URL = \"\";\nconst IMAGES = {};\n\nfunction applyImages(map){\n  let n=0;\n  (typeof ALL!==\"undefined\"?ALL:DATA).forEach(d=>{\n    if(map[d.id]){\n      d.img=map[d.id]; n++;\n      \/* The photos arrive after the originals are snapshotted. Without this the\n         diff would treat every product's photo as \"changed\" and paste the whole\n         base64 image into the publish block on the first edit. *\/\n      if(typeof ORIGINAL!==\"undefined\" && ORIGINAL[d.id]) ORIGINAL[d.id].img = d.img;\n    }\n  });\n  return n;\n}\nfunction loadImages(){\n  if(IMAGES && Object.keys(IMAGES).length){ applyImages(IMAGES); return Promise.resolve(); }\n  \/* photos are heavy and change rarely \u2014 this browser keeps them until the\n     Portal-documents stamp says a newer set exists *\/\n  const KEY=\"clm-photos-\"+DATASET;\n  const stamp=String((settings&&settings.imagesUpdated)||\"\");\n  let cachedStamp=null;\n  try{\n    const c=JSON.parse(localStorage.getItem(KEY)||\"null\");\n    if(c&&c.map){ applyImages(c.map); renderBody(); cachedStamp=String(c.stamp||\"\"); }\n  }catch(e){}\n  if(cachedStamp!==null && stamp && cachedStamp===stamp) return Promise.resolve();\n  const fromService=()=>api({action:\"getImages\"})\n      .then(r=>{ if(r&&r.ok&&r.images){ applyImages(r.images); renderBody();\n        try{ localStorage.setItem(KEY, JSON.stringify({stamp:String(r.updated||stamp||\"\"), map:r.images})); }catch(e){}\n      } })\n      .catch(()=>{});\n  if(!IMAGES_URL || IMAGES_URL.indexOf(\"__\")===0) return fromService();\n  return fetch(IMAGES_URL,{credentials:\"same-origin\"})\n    .then(r=>r.ok?r.text():Promise.reject())\n    .then(txt=>{ applyImages(JSON.parse(txt)); renderBody(); })\n    .catch(fromService);   \/* the website refused the file? Drive serves it instead *\/\n}\n\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n   PORTAL BACKEND \u2014 the Google Apps Script web-app address.\n   Sign-in, the customer registry, discounts and order records all\n   live behind it. Same address as the customer portal uses.\n   \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\nconst ENDPOINT_URL = \"https:\/\/script.google.com\/macros\/s\/AKfycbwOaFLL7LPMiAMNOatbxQJrqxp4MugK9Fp1yZbu4B4heCQH986Kkgln87z55z8AHOWifQ\/exec\";\nfunction endpointReady(){ return ENDPOINT_URL && ENDPOINT_URL.indexOf(\"__\")!==0 && \/^https?:\/.test(ENDPOINT_URL); }\nfunction api(payload){\n  if(!endpointReady()) return Promise.reject(new Error(\"no_endpoint\"));\n  return fetch(ENDPOINT_URL,{\n    method:\"POST\",\n    headers:{\"Content-Type\":\"text\/plain;charset=utf-8\"},\n    body:JSON.stringify(payload)\n  }).then(r=>r.json());\n}\nlet me = { code:\"\", name:\"\", role:\"\", ref:\"\", can:{} };\n\nconst DATA = [{\"id\":1,\"ref\":\"2603\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Cheddar Cheese Corn Chips\",\"nameTr\":\"Cheddar Peyniri Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":18.0,\"upc\":50,\"cpp\":42,\"l\":59.3,\"w\":26.2,\"h\":30.8,\"cbm\":0.047853,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.9,\"tare\":0.3,\"gross\":1.2,\"pub\":true},{\"id\":2,\"ref\":\"2652\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Cheddar Cheese Corn Chips\",\"nameTr\":\"Cheddar Peyniri Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":3,\"ref\":\"2607\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Cheddar Cheese Corn Chips\",\"nameTr\":\"Cheddar Peyniri Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":65.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.975,\"tare\":0.4,\"gross\":1.375,\"pub\":true},{\"id\":4,\"ref\":\"2634\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Space Chicken\",\"nameTr\":\"Uzay Tavu\u011fu Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":18.0,\"upc\":50,\"cpp\":42,\"l\":59.3,\"w\":26.2,\"h\":30.8,\"cbm\":0.047853,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.9,\"tare\":0.4,\"gross\":1.3,\"pub\":true},{\"id\":5,\"ref\":\"2639\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Space Chicken\",\"nameTr\":\"Uzay Tavu\u011fu Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":65.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.975,\"tare\":0.4,\"gross\":1.375,\"pub\":true},{\"id\":6,\"ref\":\"2653\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Space Chicken Corn Chips\",\"nameTr\":\"Uzay Tavu\u011fu Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":7,\"ref\":\"2632\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Pizza Corn Chips\",\"nameTr\":\"Pizza Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":65.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.975,\"tare\":0.4,\"gross\":1.375,\"pub\":true},{\"id\":8,\"ref\":\"2654\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Pizza Corn Chips\",\"nameTr\":\"Pizza Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":9,\"ref\":\"2627\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Pizza Corn Chips\",\"nameTr\":\"Pizza Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":18.0,\"upc\":50,\"cpp\":42,\"l\":59.3,\"w\":26.2,\"h\":30.8,\"cbm\":0.047853,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.9,\"tare\":0.3,\"gross\":1.2,\"pub\":true},{\"id\":10,\"ref\":\"2615\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Peanut Butter Corn Chips\",\"nameTr\":\"F\u0131st\u0131k Ezmesi Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":65.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.975,\"tare\":0.4,\"gross\":1.375,\"pub\":true},{\"id\":11,\"ref\":\"2612\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Peanut Butter Corn Chips\",\"nameTr\":\"F\u0131st\u0131k Ezmesi Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":12,\"ref\":\"2609\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama\",\"brandTr\":\"Rixy Llama\",\"name\":\"Burger Corn Chips\",\"nameTr\":\"Burger Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":18.0,\"upc\":50,\"cpp\":42,\"l\":59.3,\"w\":26.2,\"h\":30.8,\"cbm\":0.047853,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.9,\"tare\":0.3,\"gross\":1.2,\"pub\":true},{\"id\":13,\"ref\":\"2622\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Rings\",\"brandTr\":\"Rixy Rings\",\"name\":\"Onion\",\"nameTr\":\"So\u011fan Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":60.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.9,\"tare\":0.4,\"gross\":1.3,\"pub\":true},{\"id\":14,\"ref\":\"2625\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Rings\",\"brandTr\":\"Rixy Rings\",\"name\":\"Sea Salt & Pepper\",\"nameTr\":\"Deniz Tuzu ve Karabiber Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":60.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.9,\"tare\":0.4,\"gross\":1.3,\"pub\":true},{\"id\":15,\"ref\":\"2620\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Rings\",\"brandTr\":\"Rixy Rings\",\"name\":\"Cheese\",\"nameTr\":\"Peynir Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":60.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.9,\"tare\":0.4,\"gross\":1.3,\"pub\":true},{\"id\":16,\"ref\":\"2822\",\"fam\":\"World of Unicorns\",\"famTr\":\"World of Unicorns\",\"brand\":\"World of Unicorns\",\"brandTr\":\"World of Unicorns\",\"name\":\"Cheddar Cheese Corn Chips\",\"nameTr\":\"Cheddar Peyniri Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":17,\"ref\":\"2819\",\"fam\":\"World of Unicorns\",\"famTr\":\"World of Unicorns\",\"brand\":\"World of Unicorns\",\"brandTr\":\"World of Unicorns\",\"name\":\"Space Chicken Corn Chips\",\"nameTr\":\"Uzay Tavu\u011fu Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":65.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.975,\"tare\":0.4,\"gross\":1.375,\"pub\":true},{\"id\":18,\"ref\":\"2823\",\"fam\":\"World of Unicorns\",\"famTr\":\"World of Unicorns\",\"brand\":\"World of Unicorns\",\"brandTr\":\"World of Unicorns\",\"name\":\"Space Chicken Corn Chips\",\"nameTr\":\"Uzay Tavu\u011fu Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":19,\"ref\":\"2810\",\"fam\":\"World of Unicorns\",\"famTr\":\"World of Unicorns\",\"brand\":\"World of Unicorns\",\"brandTr\":\"World of Unicorns\",\"name\":\"Pizza Corn Chips\",\"nameTr\":\"Pizza Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":65.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.975,\"tare\":0.4,\"gross\":1.375,\"pub\":true},{\"id\":20,\"ref\":\"2824\",\"fam\":\"World of Unicorns\",\"famTr\":\"World of Unicorns\",\"brand\":\"World of Unicorns\",\"brandTr\":\"World of Unicorns\",\"name\":\"Pizza Corn Chips\",\"nameTr\":\"Pizza Aromal\u0131 M\u0131s\u0131r Cipsi\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":21,\"ref\":\"2304\",\"fam\":\"Lava Waves\",\"famTr\":\"Lava Waves\",\"brand\":\"Lava Waves\",\"brandTr\":\"Lava Waves\",\"name\":\"Spicy Cheese & Lime\",\"nameTr\":\"Ac\u0131l\u0131 Peynir ve Misket Limonu Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":70.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.05,\"tare\":0.4,\"gross\":1.45,\"pub\":true},{\"id\":22,\"ref\":\"2308\",\"fam\":\"Lava Waves\",\"famTr\":\"Lava Waves\",\"brand\":\"Lava Waves\",\"brandTr\":\"Lava Waves\",\"name\":\"Spicy Cheese & Lime\",\"nameTr\":\"Ac\u0131l\u0131 Peynir ve Misket Limonu Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":40.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.6,\"tare\":0.3,\"gross\":0.9,\"pub\":true},{\"id\":23,\"ref\":\"2310\",\"fam\":\"Lava Waves\",\"famTr\":\"Lava Waves\",\"brand\":\"Lava Waves\",\"brandTr\":\"Lava Waves\",\"name\":\"Tomato & Herbs\",\"nameTr\":\"Domates ve Baharat Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":70.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.05,\"tare\":0.4,\"gross\":1.45,\"pub\":true},{\"id\":24,\"ref\":\"2314\",\"fam\":\"Lava Waves\",\"famTr\":\"Lava Waves\",\"brand\":\"Lava Waves\",\"brandTr\":\"Lava Waves\",\"name\":\"Tomato & Herbs\",\"nameTr\":\"Domates ve Baharat Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":40.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.6,\"tare\":0.3,\"gross\":0.9,\"pub\":true},{\"id\":25,\"ref\":\"2321\",\"fam\":\"Lava Waves\",\"famTr\":\"Lava Waves\",\"brand\":\"Lava Waves\",\"brandTr\":\"Lava Waves\",\"name\":\"Atomic\",\"nameTr\":\"Atomic (Ekstra Ac\u0131)\",\"shelf\":\"12 Months\",\"g\":70.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.05,\"tare\":0.4,\"gross\":1.45,\"pub\":true},{\"id\":26,\"ref\":\"2302\",\"fam\":\"Lava Waves\",\"famTr\":\"Lava Waves\",\"brand\":\"Lava Waves\",\"brandTr\":\"Lava Waves\",\"name\":\"Atomic\",\"nameTr\":\"Atomic (Ekstra Ac\u0131)\",\"shelf\":\"12 Months\",\"g\":40.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.6,\"tare\":0.3,\"gross\":0.9,\"pub\":true},{\"id\":27,\"ref\":\"2319\",\"fam\":\"Lava Waves\",\"famTr\":\"Lava Waves\",\"brand\":\"Lava Waves\",\"brandTr\":\"Lava Waves\",\"name\":\"Pizza\",\"nameTr\":\"Pizza Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":40.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.6,\"tare\":0.3,\"gross\":0.9,\"pub\":true},{\"id\":28,\"ref\":\"2501\",\"fam\":\"ProChips\",\"famTr\":\"ProChips\",\"brand\":\"ProChips\",\"brandTr\":\"ProChips\",\"name\":\"Cheddar Cheese & Onion Protein Chips\",\"nameTr\":\"Cheddar Peyniri ve So\u011fan Aromal\u0131 Protein Cips\",\"shelf\":\"12 Months\",\"g\":50.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.75,\"tare\":0.3,\"gross\":1.05,\"pub\":true},{\"id\":29,\"ref\":\"2502\",\"fam\":\"ProChips\",\"famTr\":\"ProChips\",\"brand\":\"ProChips\",\"brandTr\":\"ProChips\",\"name\":\"Chilli Lime Protein Chips\",\"nameTr\":\"Ac\u0131 Biber ve Misket Limonu Aromal\u0131 Protein Cips\",\"shelf\":\"12 Months\",\"g\":50.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.0,\"cbm\":0.026801,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.75,\"tare\":0.3,\"gross\":1.05,\"pub\":true},{\"id\":30,\"ref\":\"2503\",\"fam\":\"ProChips\",\"famTr\":\"ProChips\",\"brand\":\"ProChips\",\"brandTr\":\"ProChips\",\"name\":\"Herbs Seasoning Protein Chips\",\"nameTr\":\"Baharat Aromal\u0131 Protein Cips\",\"shelf\":\"12 Months\",\"g\":50.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.75,\"tare\":0.3,\"gross\":1.05,\"pub\":true},{\"id\":31,\"ref\":\"2642\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy XXL\",\"brandTr\":\"Rixy XXL\",\"name\":\"Holland Cheese\",\"nameTr\":\"Hollanda Peyniri Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":12,\"cpp\":28,\"l\":58.5,\"w\":39.5,\"h\":32.5,\"cbm\":0.075099,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.284,\"tare\":0.5,\"gross\":1.784,\"pub\":true},{\"id\":32,\"ref\":\"2655\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy XXL\",\"brandTr\":\"Rixy XXL\",\"name\":\"Sweet Corn\",\"nameTr\":\"Tatl\u0131 M\u0131s\u0131r Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":12,\"cpp\":28,\"l\":58.5,\"w\":39.5,\"h\":32.5,\"cbm\":0.075099,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.284,\"tare\":0.5,\"gross\":1.784,\"pub\":true},{\"id\":33,\"ref\":\"2618\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy XXL\",\"brandTr\":\"Rixy XXL\",\"name\":\"White Cheese\",\"nameTr\":\"Beyaz Peynir Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":90.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.8,\"tare\":0.5,\"gross\":2.3,\"pub\":true},{\"id\":34,\"ref\":\"2617\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy XXL\",\"brandTr\":\"Rixy XXL\",\"name\":\"Ketchup\",\"nameTr\":\"Ket\u00e7ap Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":90.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.8,\"tare\":0.5,\"gross\":2.3,\"pub\":true},{\"id\":35,\"ref\":\"2656\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy XXL\",\"brandTr\":\"Rixy XXL\",\"name\":\"Chilli & Lime\",\"nameTr\":\"Ac\u0131 Biber ve Misket Limonu Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":90.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.8,\"tare\":0.5,\"gross\":2.3,\"pub\":true},{\"id\":36,\"ref\":\"2662\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Llama XXL\",\"brandTr\":\"Rixy Llama XXL\",\"name\":\"Pizza\",\"nameTr\":\"Pizza Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":12,\"cpp\":28,\"l\":58.5,\"w\":39.5,\"h\":32.5,\"cbm\":0.075099,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.284,\"tare\":0.5,\"gross\":1.784,\"pub\":true},{\"id\":37,\"ref\":\"2602\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Dino XXL\",\"brandTr\":\"Rixy Dino XXL\",\"name\":\"Pizza\",\"nameTr\":\"Pizza Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":2.14,\"tare\":0.5,\"gross\":2.64,\"pub\":true},{\"id\":38,\"ref\":\"2601\",\"fam\":\"Rixy\",\"famTr\":\"Rixy\",\"brand\":\"Rixy Dino XXL\",\"brandTr\":\"Rixy Dino XXL\",\"name\":\"Cheese\",\"nameTr\":\"Peynir Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":2.14,\"tare\":0.5,\"gross\":2.64,\"pub\":true},{\"id\":39,\"ref\":\"2210\",\"fam\":\"Dubai Fusion\",\"famTr\":\"Dubai Fusion\",\"brand\":\"Dubai Fusion\",\"brandTr\":\"Dubai Fusion\",\"name\":\"Garlic & Olive Oil\",\"nameTr\":\"Sar\u0131msak ve Zeytinya\u011f\u0131 Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":115.0,\"upc\":9,\"cpp\":48,\"l\":54.0,\"w\":27.5,\"h\":28.0,\"cbm\":0.04158,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.035,\"tare\":0.4,\"gross\":1.435,\"pub\":true},{\"id\":40,\"ref\":\"2202\",\"fam\":\"Dubai Fusion\",\"famTr\":\"Dubai Fusion\",\"brand\":\"Dubai Fusion\",\"brandTr\":\"Dubai Fusion\",\"name\":\"Garlic & Olive Oil\",\"nameTr\":\"Sar\u0131msak ve Zeytinya\u011f\u0131 Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":65.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.975,\"tare\":0.4,\"gross\":1.375,\"pub\":true},{\"id\":41,\"ref\":\"2012\",\"fam\":\"Dubai Fusion\",\"famTr\":\"Dubai Fusion\",\"brand\":\"Dubai Fusion\",\"brandTr\":\"Dubai Fusion\",\"name\":\"Pesto\",\"nameTr\":\"Pesto Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":115.0,\"upc\":9,\"cpp\":48,\"l\":54.0,\"w\":27.5,\"h\":28.0,\"cbm\":0.04158,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.035,\"tare\":0.4,\"gross\":1.435,\"pub\":true},{\"id\":42,\"ref\":\"2205\",\"fam\":\"Dubai Fusion\",\"famTr\":\"Dubai Fusion\",\"brand\":\"Dubai Fusion\",\"brandTr\":\"Dubai Fusion\",\"name\":\"Pesto\",\"nameTr\":\"Pesto Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":65.0,\"upc\":15,\"cpp\":54,\"l\":39.5,\"w\":39.5,\"h\":25.0,\"cbm\":0.039006,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.975,\"tare\":0.4,\"gross\":1.375,\"pub\":true},{\"id\":43,\"ref\":\"2013\",\"fam\":\"Dubai Fusion\",\"famTr\":\"Dubai Fusion\",\"brand\":\"Dubai Fusion\",\"brandTr\":\"Dubai Fusion\",\"name\":\"Sour Cream & Chives\",\"nameTr\":\"Ek\u015fi Krema ve Frenk So\u011fan\u0131 Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":115.0,\"upc\":9,\"cpp\":48,\"l\":54.0,\"w\":27.5,\"h\":28.0,\"cbm\":0.04158,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.035,\"tare\":0.4,\"gross\":1.435,\"pub\":true},{\"id\":44,\"ref\":\"2011\",\"fam\":\"Dubai Fusion\",\"famTr\":\"Dubai Fusion\",\"brand\":\"Dubai Fusion\",\"brandTr\":\"Dubai Fusion\",\"name\":\"Napoli Pizza\",\"nameTr\":\"Napoli Pizza Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":115.0,\"upc\":9,\"cpp\":48,\"l\":54.0,\"w\":27.5,\"h\":28.0,\"cbm\":0.04158,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.035,\"tare\":0.4,\"gross\":1.435,\"pub\":true},{\"id\":45,\"ref\":\"2429\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz SpongeBob\",\"brandTr\":\"Munchiz SpongeBob\",\"name\":\"Cheese\",\"nameTr\":\"Peynir Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":46,\"ref\":\"2434\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Ninja Turtles\",\"brandTr\":\"Munchiz Ninja Turtles\",\"name\":\"Pizza\",\"nameTr\":\"Pizza Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":47,\"ref\":\"2407\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Barbie\",\"brandTr\":\"Munchiz Barbie\",\"name\":\"Strawberry\",\"nameTr\":\"\u00c7ilek Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":48,\"ref\":\"2405\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Barbie\",\"brandTr\":\"Munchiz Barbie\",\"name\":\"Ketchup\",\"nameTr\":\"Ket\u00e7ap Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":49,\"ref\":\"2411\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Hello Kitty\",\"brandTr\":\"Munchiz Hello Kitty\",\"name\":\"Vanilla & Milk\",\"nameTr\":\"Vanilya ve S\u00fct Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":50,\"ref\":\"2423\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz One Piece\",\"brandTr\":\"Munchiz One Piece\",\"name\":\"Mushroom & Cream\",\"nameTr\":\"Mantar ve Krema Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":51,\"ref\":\"2425\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz One Piece\",\"brandTr\":\"Munchiz One Piece\",\"name\":\"Spicy Cheese & Lime\",\"nameTr\":\"Ac\u0131l\u0131 Peynir ve Misket Limonu Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":2.14,\"tare\":0.5,\"gross\":2.64,\"pub\":true},{\"id\":52,\"ref\":\"2414\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Hot Wheels\",\"brandTr\":\"Munchiz Hot Wheels\",\"name\":\"Cheese\",\"nameTr\":\"Peynir Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":53,\"ref\":\"2451\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Super Hero\",\"brandTr\":\"Munchiz Super Hero\",\"name\":\"Chicken Noodles\",\"nameTr\":\"Tavuklu Noodle Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":2.14,\"tare\":0.5,\"gross\":2.64,\"pub\":true},{\"id\":54,\"ref\":\"2444\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz SpongeBob XXL\",\"brandTr\":\"Munchiz SpongeBob XXL\",\"name\":\"Cheese\",\"nameTr\":\"Peynir Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":2.14,\"tare\":0.5,\"gross\":2.64,\"pub\":true},{\"id\":55,\"ref\":\"2450\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Dora\",\"brandTr\":\"Munchiz Dora\",\"name\":\"Cheddar Cheese\",\"nameTr\":\"Cheddar Peyniri Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":2.14,\"tare\":0.5,\"gross\":2.64,\"pub\":true},{\"id\":56,\"ref\":\"2446\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Barbie XXL\",\"brandTr\":\"Munchiz Barbie XXL\",\"name\":\"Sweet Corn\",\"nameTr\":\"Sweet Corn\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":2.14,\"tare\":0.5,\"gross\":2.64,\"pub\":true},{\"id\":57,\"ref\":\"2445\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Barbie XXL\",\"brandTr\":\"Munchiz Barbie XXL\",\"name\":\"Cheese\",\"nameTr\":\"Peynir Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":2.14,\"tare\":0.5,\"gross\":2.64,\"pub\":true},{\"id\":58,\"ref\":\"2447\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Hello Kitty XXL\",\"brandTr\":\"Munchiz Hello Kitty XXL\",\"name\":\"Sweet Corn\",\"nameTr\":\"Sweet Corn\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":2.14,\"tare\":0.5,\"gross\":2.64,\"pub\":true},{\"id\":59,\"ref\":\"2448\",\"fam\":\"Munchiz\",\"famTr\":\"Munchiz\",\"brand\":\"Munchiz Kuromi XXL\",\"brandTr\":\"Munchiz Kuromi XXL\",\"name\":\"Ketchup\",\"nameTr\":\"Ket\u00e7ap Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":107.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":2.14,\"tare\":0.5,\"gross\":2.64,\"pub\":true},{\"id\":60,\"ref\":\"2440\",\"fam\":\"Munchiz Display Stand\",\"famTr\":\"Munchiz Display Stand\",\"brand\":\"Munchiz Display Stand V3\",\"brandTr\":\"Munchiz Stant V3\",\"name\":\"Barbie Ketchup \u00b7 Hot Wheels Cheese \u00b7 Hello Kitty Vanilla & Milk \u00b7 SpongeBob Cheddar Cheese\",\"nameTr\":\"Barbie Ket\u00e7ap \u00b7 Hot Wheels Peynir \u00b7 Hello Kitty Vanilya & S\u00fct \u00b7 SpongeBob Ka\u015far\",\"shelf\":\"12 Months\",\"g\":30.0,\"upc\":60,\"cpp\":16,\"l\":30.0,\"w\":40.0,\"h\":110.0,\"cbm\":0.132,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.8,\"tare\":2.0,\"gross\":3.8,\"pub\":true},{\"id\":61,\"ref\":\"2657\",\"fam\":\"Puffy Cubs\",\"famTr\":\"Puffy Cubs\",\"brand\":\"Puffy Cubs\",\"brandTr\":\"Puffy Cubs\",\"name\":\"Salt & Vinegar\",\"nameTr\":\"Tuz ve Sirke Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":62,\"ref\":\"2658\",\"fam\":\"Puffy Cubs\",\"famTr\":\"Puffy Cubs\",\"brand\":\"Puffy Cubs\",\"brandTr\":\"Puffy Cubs\",\"name\":\"Pesto\",\"nameTr\":\"Pesto Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":63,\"ref\":\"2659\",\"fam\":\"Puffy Cubs\",\"famTr\":\"Puffy Cubs\",\"brand\":\"Puffy Cubs\",\"brandTr\":\"Puffy Cubs\",\"name\":\"French Cheese\",\"nameTr\":\"Frans\u0131z Peyniri Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":64,\"ref\":\"2103\",\"fam\":\"7Chips\",\"famTr\":\"7Chips\",\"brand\":\"7Chips\",\"brandTr\":\"7Chips\",\"name\":\"Ring Pizza\",\"nameTr\":\"Ring Pizza\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":65,\"ref\":\"2104\",\"fam\":\"7Chips\",\"famTr\":\"7Chips\",\"brand\":\"7Chips\",\"brandTr\":\"7Chips\",\"name\":\"Cone Ketchup & Mayonnaise\",\"nameTr\":\"Cone Ketchup & Mayonnaise\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":66,\"ref\":\"2105\",\"fam\":\"7Chips\",\"famTr\":\"7Chips\",\"brand\":\"7Chips\",\"brandTr\":\"7Chips\",\"name\":\"Flower Chilli Lime\",\"nameTr\":\"Flower Chilli Lime\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":67,\"ref\":\"2106\",\"fam\":\"7Chips\",\"famTr\":\"7Chips\",\"brand\":\"7Chips\",\"brandTr\":\"7Chips\",\"name\":\"Cone Salt & Vinegar\",\"nameTr\":\"Cone Salt & Vinegar\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":68,\"ref\":\"2107\",\"fam\":\"7Chips\",\"famTr\":\"7Chips\",\"brand\":\"7Chips\",\"brandTr\":\"7Chips\",\"name\":\"Flat Pesto\",\"nameTr\":\"Flat Pesto\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":69,\"ref\":\"2108\",\"fam\":\"7Chips\",\"famTr\":\"7Chips\",\"brand\":\"7Chips\",\"brandTr\":\"7Chips\",\"name\":\"Flat Salt & Vinegar\",\"nameTr\":\"Flat Salt & Vinegar\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":70,\"ref\":\"2660\",\"fam\":\"Rixy Pops\",\"famTr\":\"Rixy Pops\",\"brand\":\"Rixy Pops\",\"brandTr\":\"Rixy Pops\",\"name\":\"Classic Popcorn\",\"nameTr\":\"Klasik\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":71,\"ref\":\"2661\",\"fam\":\"Rixy Pops\",\"famTr\":\"Rixy Pops\",\"brand\":\"Rixy Pops\",\"brandTr\":\"Rixy Pops\",\"name\":\"White Cheddar Popcorn\",\"nameTr\":\"Beyaz Peynir Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":99.0,\"upc\":20,\"cpp\":21,\"l\":80.0,\"w\":40.0,\"h\":30.0,\"cbm\":0.096,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":1.98,\"tare\":0.5,\"gross\":2.48,\"pub\":true},{\"id\":72,\"ref\":\"2504\",\"fam\":\"ProKids\",\"famTr\":\"ProKids\",\"brand\":\"ProKids\",\"brandTr\":\"ProKids\",\"name\":\"Cheese\",\"nameTr\":\"Peynir Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":73,\"ref\":\"2505\",\"fam\":\"ProKids\",\"famTr\":\"ProKids\",\"brand\":\"ProKids\",\"brandTr\":\"ProKids\",\"name\":\"Pizza\",\"nameTr\":\"Pizza Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":74,\"ref\":\"2506\",\"fam\":\"ProKids\",\"famTr\":\"ProKids\",\"brand\":\"ProKids\",\"brandTr\":\"ProKids\",\"name\":\"Vegetable Seasoning\",\"nameTr\":\"Sebze Baharatl\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true},{\"id\":75,\"ref\":\"2507\",\"fam\":\"ProKids\",\"famTr\":\"ProKids\",\"brand\":\"ProKids\",\"brandTr\":\"ProKids\",\"name\":\"Sweet Corn\",\"nameTr\":\"Tatl\u0131 M\u0131s\u0131r Aromal\u0131\",\"shelf\":\"12 Months\",\"g\":35.0,\"upc\":15,\"cpp\":72,\"l\":39.5,\"w\":29.5,\"h\":23.1,\"cbm\":0.026917,\"hs\":\"1905.90.55.00.00\",\"bc\":\"\",\"cbc\":\"\",\"temp\":\"18\u201325\u00b0C\",\"net\":0.525,\"tare\":0.3,\"gross\":0.825,\"pub\":true}];\nDATA.forEach(d=>{ const p = PRICES[d.id]; if(p){ d.pu = p[0]; d.pc = p[1]; } });\nDATA.sort((a,b)=>a.id-b.id);\n\nconst byId = id => DATA.find(x=>String(x.id)===String(id));\nlet sharedState = \"loading\", sharedDate = \"\";\n\nfunction applyShared(j){\n  if(j.prices) Object.keys(j.prices).forEach(id=>{ const d=byId(id); if(d){ d.pu=j.prices[id][0]; d.pc=j.prices[id][1]; } });\n  if(j.overrides) Object.keys(j.overrides).forEach(id=>{ const d=byId(id); if(d) Object.assign(d,j.overrides[id]); });\n  if(j.public) Object.keys(j.public).forEach(id=>{ const d=byId(id); if(d) d.pub=!!j.public[id]; });\n  if(Array.isArray(j.extra)) j.extra.forEach(e=>{ if(!byId(e.id)) DATA.push(e); });\n  DATA.sort((a,b)=>a.id-b.id);\n}\n\/* Product data comes from the service first \u2014 that is what an admin publishes.\n   The WordPress page stays as a fallback for when the service is unreachable. *\/\nfunction applySharedData(d){\n  if(!d||!d.updated) throw 0;\n  if(String(d.dataset||\"\")!==String(DATASET)) throw 0;   \/\/ stale \u2014 from the previous product list\n  const j={updated:d.updated, prices:d.prices, public:d.pub,\n           overrides:d.overrides, extra:Object.values(d.added||{})};\n  applyShared(j);\n  sharedState=\"live\"; sharedDate=d.updated;\n  seedDraft(j);\n  recomputeFlags(); renderChips(); renderAll(); renderSync(); renderCode();\n}\nfunction loadShared(){\n  return api({action:\"getData\"})\n    .then(r=>{ if(!r||!r.ok) throw 0; applySharedData(r.data); })\n    .catch(()=>loadSharedPage());\n}\nfunction loadSharedPage(){\n  return fetch(DATA_URL,{credentials:\"same-origin\"})\n    .then(r=>r.ok?r.text():Promise.reject())\n    .then(html=>{\n      const el=new DOMParser().parseFromString(html,\"text\/html\").querySelector(\"#claimont-data\");\n      if(!el) throw 0;\n      const j=JSON.parse(el.textContent.trim());\n      if(String(j.dataset||\"\")!==String(DATASET)) throw 0;    \/\/ stale block from the previous list\n      applyShared(j);\n      sharedState=\"live\"; sharedDate=j.updated||\"\";\n      seedDraft(j);\n      recomputeFlags(); renderChips(); renderAll(); renderSync(); renderCode();\n    })\n    .catch(()=>{ sharedState=\"builtin\"; renderSync(); });\n}\n\nconst T = {\n  en:{\n    sub:\"Internal \u00b7 Price list\", search:\"Search product, code, barcode\u2026\", all:\"All\",\n    columns:\"Columns\", colhd:\"Detail groups\", pack:\"Packing & dimensions\", wt:\"Weights\",\n    comp:\"Codes & storage\", unit:\"Unit prices\", calc:\"Order totals\",\n    reset:\"Reset\", csv:\"Excel\", print:\"PDF \/ Print\",\n    cols:{idx:\"#\",ref:\"Reference\",photo:\"Photo\",name:\"Product\",pub:\"Customers\",shelf:\"Shelf life\",g:\"Grammage\",upc:\"Units \/ carton\",\n      cpp:\"Cartons \/ pallet\",l:\"L cm\",w:\"W cm\",h:\"H cm\",cbm:\"CBM \/ carton\",hs:\"HS code\",bc:\"Unit barcode\",\n      cbc:\"Carton barcode\",temp:\"Storage\",net:\"Net kg \/ ctn\",tare:\"Tare kg\",gross:\"Gross kg \/ ctn\",\n      pu:\"Unit USD\",pue:\"Unit EUR\",pc:\"Carton USD\",pce:\"Carton EUR\",qty:\"Cartons\",\n      units:\"Units\",pallets:\"Pallets\",tcbm:\"Total CBM\",tnet:\"Total net kg\",tgross:\"Total gross kg\",\n      tusd:\"Total USD\",teur:\"Total EUR\"},\n    stats:{lines:\"Lines\",cartons:\"Cartons\",units:\"Units\",pallets:\"Pallets\",cbm:\"Total CBM\",\n      net:\"Net weight\",gross:\"Gross weight\",usd:\"Ex-works USD\",eur:\"Ex-works EUR\"},\n    contlbl:\"Container fill\", empty:\"No products match that search.\",\n    contlbl2:\"Container planning\",\n    shipIn:\"I want to ship in\", howMany:\"How many\", whatMean:\"What do these mean?\",\n    skuCapL:\"Max SKUs per container\", skuNoLimit:\"No limit\",\n    skuOkMsg:\"\u2713 {have} of max {max} SKUs\",\n    skuOverMsg:\"\u26a0 Too many SKUs \u2014 {have} of max {max}. Split the order or raise the limit.\",\n    wouldNeed:\"would need {n}\",\n    c3dTitle:\"Live load view \u2014 drag to rotate\", c3dExtra:\"more needed\",\n    fitBarOk:\"{n} \u00d7 {type} \u00b7 {pct}% full\",\n    fitBarOver:\"\u26a0 Will NOT fit in {n} \u00d7 {type} \u2014 needs {need}. Add a container or cut quantities.\",\n    fitBarW:\"\u26a0 Over the weight limit for {n} \u00d7 {type}. Add a container or cut quantities.\",\n    fitIdle:\"Enter quantities above and this will tell you whether the order fills the container you have chosen.\",\n    fitOver:\"This will not fit. You would need {need}, or {over} less cargo.\",\n    fitFull:\"Good full container load \u2014 {pct} of the space used.\",\n    fitNear:\"Fits, at {pct} full. There is still room for about {room}.\",\n    fitLight:\"Well short of a full container \u2014 only {pct} used. Around {room} of space would ship empty.\",\n    fitWeight:\"It is also over the {kg} payload limit, so weight will stop you before volume does.\",\n    infoTitle:\"Containers and pallets\",     infoCont:\"Container\", infoInner:\"Inside size\", infoVol:\"Usable volume\",\n    infoPal100:\"Pallets 100\u00d7120\", infoPalEuro:\"Pallets 80\u00d7120\", infoPayload:\"Max payload\",\n    infoIntro:\"Sea freight is sold by the container, not by weight, so the aim is to fill one as completely as you can. These are the three we ship in:\",\n    infoFloor:\"<b>Floor loaded<\/b> means cartons are stacked straight into the container by hand. It uses the most space, so you fit more in \u2014 but loading and unloading takes longer.\",\n    infoPallet:\"<b>Palletised<\/b> means cartons are stacked on wooden pallets and moved by forklift. Faster to handle and safer for the goods, but the pallets themselves take up space and add about 25 kg each, so a container holds less.\",\n    infoCaveat:\"Volumes and pallet counts are working figures for planning. Your freight forwarder decides the final loading plan.\",\n    signOut:\"Sign out\",\n    idHint:\"The product number. Changing it moves its prices and photo with it.\",\n    idTaken:\"Number {n} is already used by another product.\",\n    photoHint:\"Replace this photo\",\n    roles:{admin:\"admin\", super:\"super user\", user:\"user\"},\n    roleHelp:{admin:\"Everything \u2014 staff, customers, products, archiving.\",\n              super:\"Customer codes, and creating and editing product data.\",\n              user:\"Customer codes only.\"},\n    notAllowed:\"Your account cannot do that. Ask an admin.\",\n    archive:\"Archive\", restore:\"Restore\", archived:\"Archived\",\n    showArchived:\"Show archived\", hideArchived:\"Hide archived\",\n    archiveAsk:\"Archive {name}? It disappears from both portals but stays in the sheet, and you can restore it.\",\n    lastAdmin:\"That is the only admin left \u2014 promote someone else first.\",\n    catAdmin:\"Portal documents\", catUpload:\"Upload\u2026\",\n    docCatalogue:\"Product catalogue (PDF)\",\n    docImages:\"Product photos (the images file)\",\n    catNotImg:\"That is not the photos file (.csv, .txt or .json).\", docPricePdf:\"Price list (PDF)\", docPriceXlsx:\"Price list (Excel)\",\n    catNotXlsx:\"That is not an .xlsx file.\",\n    catCurrent:\"Current catalogue\", catOpenCur:\"Open the current one\",\n    catNone:\"No catalogue uploaded yet.\",\n    imgNone:\"No photos file uploaded yet \u2014 product pictures come from the built-in set.\",\n    catByUrl:\"Use an address instead\", catUrlLb:\"Catalogue PDF address\",\n    catPagesLb:\"Snapshot images address\", catSave:\"Save\",\n    catReading:\"Reading the file\u2026\", catSending:\"Sending to the service\u2026\",\n    catUploaded:\"Uploaded. Customers see the new catalogue from now on.\",\n    catReplaced:\"Replaced. The previous edition is in the Drive bin if you need it back.\",\n    catFailed:\"That didn't go through. Try again, or paste an address instead.\",\n    catSaved:\"Saved.\", catAdminOnly:\"Only an admin can change the catalogue.\",\n    catNotPdf:\"That is not a PDF.\",\n    catTooBig:\"That file is {mb} MB, which is too large to send this way. Upload it to WordPress and paste its address instead.\",\n    qtyResize:\"Drag to make the Cartons column wider\",\n    qtyBox:\"Cartons box\",\n    msgCollapse:\"Collapse messages\", msgExpand:\"Show messages\",\n    pubNow:\"Publish to everyone\", pubSending:\"Publishing\u2026\",\n    pubDone:\"Published. {n} product changes are now live in both portals.\",\n    pubDone1:\"Published. That change is now live in both portals.\",\n    pubFailed:\"Could not reach the service. Use the manual block below instead.\",\n    pubAdminOnly:\"Only an admin can publish product changes.\",\n    pubHelp:\"Publishing sends these changes to the Claimont service. Both portals pick them up the next time they load \u2014 you don't need to touch WordPress. Orders already confirmed keep exactly the prices and details they were placed with.\",\n    pubHelpStaff:\"Only an admin can publish. Send your changes to an admin, or use the manual block below.\",\n    pubManual:\"Publish by hand instead\",\n    regNeedRep:\"Enter the representative who owns this account.\",\n    regNeedMail:\"Enter that representative's email address.\",\n    gridBrand:\"Brand\", gridFlavour:\"Flavour \/ description\",\n    activity:\"Activity\", markRead:\"Mark all read\", noActivity:\"Nothing yet.\",\n    actOrder:\"Order\", actDraft:\"Draft\", actFirst:\"First sign-in\", actOpen:\"Opened\", actMsg:\"Message\",\n    messages:\"Messages\", msgSend:\"Send\", msgYouShort:\"You\",\n    msgNoThreads:\"No conversations yet. Open a customer below to start one.\",\n    msgEmptyThread:\"Nothing here yet \u2014 write the first message.\",\n    msgPlaceholder:\"Write to this customer\u2026\", msgFailed:\"That didn't send. Try again.\",\n    msgWrite:\"Message\",\n    draftPill:\"Draft\", draftTitle:\"Unsent draft order\",\n    draftNote:\"This order has been started by the customer but not sent yet.\",\n    master:\"Master edit\",\n    masterOn:\"Master edit is on\",\n    masterCount:\"{n} products changed \u2014 not published yet\",\n    masterCount1:\"1 product changed \u2014 not published yet\",\n    masterNone:\"Click any cell to change it. Nothing is published until you copy the block.\",\n    masterPublish:\"Show the block to publish\",\n    masterDone:\"Done\",\n    oldTitle:\"The Claimont service needs updating\",\n    oldText:\"This portal is talking to an older version of the backend script, so some features \u2014 past orders, order detail \u2014 will not work. In Apps Script: paste the latest claimont-backend.gs, then Deploy \u2192 Manage deployments \u2192 \u270f\ufe0f \u2192 Version: New version \u2192 Deploy.\",\n    floorLoaded:\"Floor loaded\", palletised:\"Palletised\", palletsShort:\"pallets\",\n    palSettings:\"Pallet settings\", palSize:\"Pallet size\",\n    palWeight:\"Weight of one empty pallet (kg)\",\n    palNote:\"Slots are single-stacked pallets per container. Change the pallet size if yours differs, and tell Claimont if these figures don't match your forwarder's.\",\n    palletsWhole:\"Pallets\", loading:\"Loading\", order2:\"Order sheet\", pricelist2:\"Price list 2026\", productsWord:\"products\",\n    live:\"ECB rate\", fallback:\"fixed rate\", manual:\"your rate\", fxLoading:\"loading\u2026\",\n    noteshd:\"Notes\",\n    notes:[\n      \"All prices are <strong>ex-works<\/strong> and exclude taxes, FOB and freight charges.\",\n      \"EUR prices are converted from USD at the rate shown top-right. Edit the rate to override it for this session.\",\n      \"Enter a quantity in <strong>cartons<\/strong>; units, pallets, volume, weights and totals calculate automatically.\",\n      \"Switch between <strong>Floor loaded<\/strong> and <strong>Palletised<\/strong> below the table. Floor loading measures the container by volume (20' DV 29 m\u00b3 \u00b7 40' HC 76.3 m\u00b3 \u00b7 45' HC 85.6 m\u00b3 \u00b7 Tautliner truck 90 m\u00b3). Palletised rounds each product up to whole pallets, adds the empty-pallet weight, and measures the container in pallet places.\",\n      \"<span class='flag'>Check before quoting:<\/span> some items share a unit barcode and carton barcodes are not yet recorded. Items flagged with a dot have a barcode that is duplicated or missing.\",\n      \"<strong>Add product<\/strong> adds a new item, and clicking any item number opens it for editing. Changes show here immediately but live only in your own browser \u2014 the portal gives you a block of code to paste into WordPress to make them permanent for everyone.\"\n    ],\n    printsub:\"Ex-works price list \u00b7 generated\",\n    add:\"+ Add product\", edit:\"Edit product\", addTitle:\"Add product\",\n    save:\"Save product\", cancel:\"Cancel\", close:\"Close\", remove:\"Remove\",\n    gIdentity:\"Identity\", gPhoto:\"Photo\", gPack:\"Packing & dimensions\",\n    gWeights:\"Weights\", gCodes:\"Codes & storage\", gPrices:\"Prices (USD, ex-works)\",\n    fields:{id:\"Item number\",fam:\"Brand family (filter chip)\",famTr:\"Brand family \u2014 Turkish\",\n      brand:\"Brand line\",brandTr:\"Brand line \u2014 Turkish\",name:\"Flavour \/ description\",\n      nameTr:\"Flavour \/ description \u2014 Turkish\",g:\"Grammage (g)\",upc:\"Units per carton\",\n      cpp:\"Cartons per pallet\",l:\"Carton length (cm)\",w:\"Carton width (cm)\",h:\"Carton height (cm)\",\n      cbm:\"CBM per carton\",net:\"Net weight per carton (kg)\",tare:\"Empty carton weight (kg)\",\n      gross:\"Gross weight per carton (kg)\",shelf:\"Shelf life\",temp:\"Storage temperature\",\n      hs:\"HS code\",bc:\"Unit barcode\",cbc:\"Carton barcode\",pu:\"Unit price\",pc:\"Carton price\"},\n    autoHint:\"calculated \u2014 type to override\",\n    photoPick:\"Choose image\u2026\", photoNone:\"No photo yet\", photoHint:\"PNG or JPG. Resized automatically.\",\n    errId:\"Item number is required and must not already exist.\",\n    errName:\"Brand line and flavour are required.\",\n    errPhoto:\"A photo is required.\",\n    codeTitle:\"Code to paste into WordPress\",\n    codeCount:n=>`${n} change${n===1?\"\":\"s\"} to publish`,\n    codeHelp:\"Your changes are live in this browser only. To make them permanent for everyone, open the page in WordPress, find the two blocks marked <strong>EXTRA<\/strong> and <strong>OVERRIDES<\/strong> near the top of the code, and replace them with the text below. Then update the page.\",\n    copy:\"Copy data\", copied:\"Copied\",\n    pubOn:\"Visible\", pubOff:\"Internal\",\n    fPub:\"Show this product to customers\",\n    syncLive:\"Shared data\", syncBuiltin:\"Built-in data\", syncLoading:\"Checking\u2026\",\n    syncLiveTip:\"Reading the shared data page \u2014 the customer portal sees the same thing\",\n    syncBuiltinTip:\"The shared data page could not be read. Showing the version built into this file.\",\n    gTitle:\"Sign in\", gText:\"Enter your personal staff code. Sami issues one per person.\",\n    gUnset:\"This portal is not connected to Claimont's system yet. The ENDPOINT_URL setting at the top of the page still needs filling in.\", gGo:\"Sign in\", gChecking:\"Checking\u2026\", gEmpty:\"Enter your code to continue.\",\n    gBad:\"That code isn't recognised, or it has been switched off.\",\n    gOffline:\"Can't reach the Claimont service right now. Try again in a moment.\",\n    myCustomers:\"My customers\", noCustomers:\"No customers assigned to you yet.\",\n    noOrdersYet:\"No orders yet.\", ordersWord:\"orders\", cartonsWord:\"cartons\",\n    oWhen:\"Placed\", oCompany:\"Company\", oContact:\"Contact\", oEmail:\"Email\",\n    oPhone:\"Phone\", oCountry:\"Destination\", oNotes:\"Notes\",\n    capNote:\"(you may give up to {n}%)\",\n    overLimit:\"That is above your limit of {n}%. Ask an admin to raise it, or to set the discount for you.\",\n    regCustomers:\"Customers\", regUsers:\"Staff\", regNew:\"New\", regEmpty:\"Nothing here yet.\",\n    reg:{ref:\"Ref\",code:\"Code\",customer:\"Customer\",rep:\"Contact person (at the customer)\",repMail:\"Contact email\",cPhone:\"Contact phone\",cTitle:\"Title on their business card\",country:\"Country\",discount:\"Discount\",status:\"Status\",\n         opens:\"Opens\",lastAccess:\"Last opened\",orders:\"Orders\",lastOrder:\"Last order\",\n         staffName:\"Name\",role:\"Role\",maxDisc:\"Max disc.\",created:\"Created\",owner:\"Created by\",\n         userEmail:\"Email\",userPhone:\"Phone\",ownerSel:\"Assigned user \u2014 their Claimont rep\",\n         moqSel:\"Maximum different products (SKU cap)\",moqCol:\"SKU cap\"},\n    moqNone:\"No limit \u2014 open\", moqOpt:\"Up to {n} SKU per container\/truck\",\n    mwSteps:[\"Shipment\",\"Products\",\"Desk\"], mwNext:\"Next &#8594;\",\n    qtBtn:\"Customer PDF\", qtTitle:\"Prepare the customer's order\", qtAgreed:\"Agreed $\/unit\",\n\n    qtItemsH:\"Products in this order \u2014 adjust the agreed price per unit where needed (the carton price follows)\",\n    qtNotes:\"Notes on the document\", qtPrint:\"Print \/ Save as PDF\",\n    qtSaveBtn:\"Save to customer's orders\", qtSaving:\"Saving\u2026\",\n    qtSavedMsg:\"Saved as {id} \u2014 it now shows under this customer here and in their portal.\",\n    qtPickFirst:\"Pick which customer this order belongs to first.\",\n    qtSaveFail:\"Could not save \u2014 try again.\",\n    qtHint:\"Pick a customer to prefill, or type freely. Changed prices are highlighted and used only on this document.\",\n    qtPickNone:\"\u2014 pick a customer \u2014\", qtDocSub:\"Customer order \u00b7 prepared for you\",\n    qtFoot:\"Ex-works prices in USD, excluding taxes, FOB and freight. Valid 14 days unless agreed otherwise.\",\n    viewActive:\"Active\", viewArch:\"Archived\", regEmptyArch:\"Nothing archived \u2014 everything is in the active list.\",\n    regNeedCPhone:\"Add the contact person's phone number.\", regNeedCTitle:\"Add the contact person's title (as on their business card).\",\n    regNeedCountry:\"Add the customer's country.\",\n    regNeedUserMail:\"Every user needs an email \u2014 their customers see it as the direct contact.\",\n    regNeedUserPhone:\"Every user needs a phone number \u2014 their customers see it as the direct contact.\",\n    pdfBtn:\"Download PDF\", pdfWait:\"Building the PDF\u2026\", pdfFailed:\"The PDF could not be made \u2014 try again.\",\n    statusOn:\"Active\", statusOff:\"Off\", never:\"never\",\n    regNeedName:\"Give this record a name first.\",\n    save2:\"Save\", saving:\"Saving\u2026\", savedOk:\"Saved\", createdOk:\"Created\",\n    saveFailed:\"Couldn't save. Check your connection and try again.\",\n    listFailed:\"Couldn't load the list. Check your connection and try again.\",\n    loadingList:\"Loading\u2026\",\n    codeNoteCust:\"Give this code to the customer \u2014 it is the only thing they need to open the order portal. It stays valid until you switch this record off.\",\n    codeNoteUser:\"Give this code to the person. It signs them in here. Switch the record off to remove their access.\",\n    esign:\"signed in as\", regBack:\"Back to list\", activeLabel:\"Active \u2014 the code works\",\n    csTitle:\"New customer code\", csBtn:\"Customer code\", csRef:\"Reference\", csGen:\"Generate\", csCopy:\"Copy line\",\n    csCodeLbl:\"Code for the customer\",\n    csHelp:\"Give the code above to the customer. Paste the line below into the <strong>CODES<\/strong> block near the top of the customer portal page in WordPress, then update the page. The code itself is never stored \u2014 only this fingerprint of it, so keep your own record of who has which code.\",\n    csNeedRef:\"Give this customer a short reference first.\",\n    csNoCrypto:\"This page must be opened over https for codes to be generated.\",\n    codeTitle2:\"Publish to the shared data page\",\n    codeHelp2:\"Your changes are live in this browser only. To publish them to <strong>both portals at once<\/strong>, copy the block below, open the <strong>claimont-data<\/strong> page in WordPress, replace everything in its Custom HTML block with it, and update the page.\"\n  },\n  tr:{\n    sub:\"Dahili \u00b7 Fiyat listesi\", search:\"\u00dcr\u00fcn, kod, barkod ara\u2026\", all:\"T\u00fcm\u00fc\",\n    columns:\"S\u00fctunlar\", colhd:\"Detay gruplar\u0131\", pack:\"Ambalaj ve \u00f6l\u00e7\u00fcler\", wt:\"A\u011f\u0131rl\u0131klar\",\n    comp:\"Kodlar ve saklama\", unit:\"Birim fiyatlar\", calc:\"Sipari\u015f toplamlar\u0131\",\n    reset:\"S\u0131f\u0131rla\", csv:\"Excel\", print:\"PDF \/ Yazd\u0131r\",\n    cols:{idx:\"#\",ref:\"Referans\",photo:\"Foto\u011fraf\",name:\"\u00dcr\u00fcn\",pub:\"M\u00fc\u015fteriler\",shelf:\"Raf \u00f6mr\u00fc\",g:\"Gramaj\",upc:\"Koli i\u00e7i adet\",\n      cpp:\"Palet ba\u015f\u0131na koli\",l:\"U cm\",w:\"G cm\",h:\"Y cm\",cbm:\"Koli hacmi m\u00b3\",hs:\"GT\u0130P kodu\",bc:\"\u00dcr\u00fcn barkodu\",\n      cbc:\"Koli barkodu\",temp:\"Saklama\",net:\"Net kg \/ koli\",tare:\"Dara kg\",gross:\"Br\u00fct kg \/ koli\",\n      pu:\"Birim USD\",pue:\"Birim EUR\",pc:\"Koli USD\",pce:\"Koli EUR\",qty:\"Koli\",\n      units:\"Adet\",pallets:\"Palet\",tcbm:\"Toplam m\u00b3\",tnet:\"Toplam net kg\",tgross:\"Toplam br\u00fct kg\",\n      tusd:\"Toplam USD\",teur:\"Toplam EUR\"},\n    stats:{lines:\"Kalem\",cartons:\"Koli\",units:\"Adet\",pallets:\"Palet\",cbm:\"Toplam m\u00b3\",\n      net:\"Net a\u011f\u0131rl\u0131k\",gross:\"Br\u00fct a\u011f\u0131rl\u0131k\",usd:\"Fabrika teslim USD\",eur:\"Fabrika teslim EUR\"},\n    contlbl:\"Konteyner doluluk\", empty:\"Araman\u0131za uyan \u00fcr\u00fcn bulunamad\u0131.\",\n    contlbl2:\"Konteyner planlama\",\n    shipIn:\"Sevkiyat \u015fekli\", howMany:\"Ka\u00e7 adet\", whatMean:\"Bunlar ne demek?\",\n    skuCapL:\"Konteyner ba\u015f\u0131na azami SKU\", skuNoLimit:\"S\u0131n\u0131rs\u0131z\",\n    skuOkMsg:\"\u2713 {have} \/ azami {max} SKU\",\n    skuOverMsg:\"\u26a0 SKU say\u0131s\u0131 fazla \u2014 {have} \/ azami {max}. Sipari\u015fi b\u00f6l\u00fcn ya da limiti art\u0131r\u0131n.\",\n    wouldNeed:\"{n} adet gerekir\",\n    c3dTitle:\"Canl\u0131 y\u00fck g\u00f6r\u00fcn\u00fcm\u00fc \u2014 d\u00f6nd\u00fcrmek i\u00e7in s\u00fcr\u00fckleyin\", c3dExtra:\"daha gerekli\",\n    fitBarOk:\"{n} \u00d7 {type} \u00b7 %{pct} dolu\",\n    fitBarOver:\"\u26a0 {n} \u00d7 {type} i\u00e7ine SI\u011eMAYACAK \u2014 {need} gerekiyor. Konteyner ekleyin ya da adetleri azalt\u0131n.\",\n    fitBarW:\"\u26a0 {n} \u00d7 {type} i\u00e7in a\u011f\u0131rl\u0131k s\u0131n\u0131r\u0131 a\u015f\u0131l\u0131yor. Konteyner ekleyin ya da adetleri azalt\u0131n.\",\n    fitIdle:\"Yukar\u0131dan miktar girin; sipari\u015fin se\u00e7ti\u011finiz konteyneri doldurup doldurmad\u0131\u011f\u0131n\u0131 burada g\u00f6receksiniz.\",\n    fitOver:\"Bu s\u0131\u011fmaz. {need} gerekir veya {over} daha az y\u00fckleme yapmal\u0131s\u0131n\u0131z.\",\n    fitFull:\"Tam konteyner y\u00fck\u00fc \u2014 alan\u0131n {pct} kadar\u0131 kullan\u0131ld\u0131.\",\n    fitNear:\"S\u0131\u011f\u0131yor, doluluk {pct}. Yakla\u015f\u0131k {room} kadar daha yer var.\",\n    fitLight:\"Tam konteynerden hayli uzak \u2014 yaln\u0131zca {pct} kullan\u0131ld\u0131. Yakla\u015f\u0131k {room} bo\u015f gidecek.\",\n    fitWeight:\"Ayr\u0131ca {kg} ta\u015f\u0131ma s\u0131n\u0131r\u0131n\u0131n \u00fczerinde; hacimden \u00f6nce a\u011f\u0131rl\u0131k s\u0131n\u0131rlayacakt\u0131r.\",\n    infoTitle:\"Konteynerler ve paletler\",     infoCont:\"Konteyner\", infoInner:\"\u0130\u00e7 \u00f6l\u00e7\u00fc\", infoVol:\"Kullan\u0131labilir hacim\",\n    infoPal100:\"Palet 100\u00d7120\", infoPalEuro:\"Palet 80\u00d7120\", infoPayload:\"Azami y\u00fck\",\n    infoIntro:\"Deniz ta\u015f\u0131mac\u0131l\u0131\u011f\u0131 a\u011f\u0131rl\u0131kla de\u011fil konteynerle sat\u0131l\u0131r; ama\u00e7 konteyneri olabildi\u011fince doldurmakt\u0131r. Kulland\u0131\u011f\u0131m\u0131z \u00fc\u00e7 tip \u015funlard\u0131r:\",\n    infoFloor:\"<b>Zemine y\u00fckleme<\/b>, kolilerin do\u011frudan elle konteynere istiflenmesidir. Alan\u0131 en verimli kullan\u0131r, daha \u00e7ok mal s\u0131\u011far; ancak y\u00fckleme ve bo\u015faltma daha uzun s\u00fcrer.\",\n    infoPallet:\"<b>Paletli<\/b> y\u00fckleme, kolilerin ah\u015fap paletlere istiflenip forkliftle ta\u015f\u0131nmas\u0131d\u0131r. Elle\u00e7lemesi h\u0131zl\u0131 ve mal i\u00e7in daha g\u00fcvenlidir; ancak paletler yer kaplar ve her biri yakla\u015f\u0131k 25 kg ekler, bu y\u00fczden konteynere daha az mal s\u0131\u011far.\",\n    infoCaveat:\"Hacim ve palet say\u0131lar\u0131 planlama i\u00e7indir. Nihai y\u00fckleme plan\u0131na nakliyeciniz karar verir.\",\n    signOut:\"\u00c7\u0131k\u0131\u015f\",\n    idHint:\"\u00dcr\u00fcn numaras\u0131. De\u011fi\u015ftirildi\u011finde fiyatlar\u0131 ve foto\u011fraf\u0131 da ta\u015f\u0131n\u0131r.\",\n    idTaken:\"{n} numaras\u0131 ba\u015fka bir \u00fcr\u00fcnde kullan\u0131l\u0131yor.\",\n    photoHint:\"Bu foto\u011fraf\u0131 de\u011fi\u015ftir\",\n    roles:{admin:\"y\u00f6netici\", super:\"s\u00fcper kullan\u0131c\u0131\", user:\"kullan\u0131c\u0131\"},\n    roleHelp:{admin:\"Her \u015fey \u2014 personel, m\u00fc\u015fteriler, \u00fcr\u00fcnler, ar\u015fivleme.\",\n              super:\"M\u00fc\u015fteri kodlar\u0131 ve \u00fcr\u00fcn verisi olu\u015fturma\/d\u00fczenleme.\",\n              user:\"Yaln\u0131zca m\u00fc\u015fteri kodlar\u0131.\"},\n    notAllowed:\"Hesab\u0131n\u0131z bunu yapamaz. Bir y\u00f6neticiye dan\u0131\u015f\u0131n.\",\n    archive:\"Ar\u015fivle\", restore:\"Geri al\", archived:\"Ar\u015fivlendi\",\n    showArchived:\"Ar\u015fivi g\u00f6ster\", hideArchived:\"Ar\u015fivi gizle\",\n    archiveAsk:\"{name} ar\u015fivlensin mi? \u0130ki portaldan da kaybolur ama sayfada kal\u0131r ve geri alabilirsiniz.\",\n    lastAdmin:\"Bu kalan tek y\u00f6netici \u2014 \u00f6nce ba\u015fka birini y\u00fckseltin.\",\n    catAdmin:\"Portal belgeleri\", catUpload:\"Y\u00fckle\u2026\",\n    docCatalogue:\"\u00dcr\u00fcn katalo\u011fu (PDF)\",\n    docImages:\"\u00dcr\u00fcn foto\u011fraflar\u0131 (g\u00f6rsel dosyas\u0131)\",\n    catNotImg:\"Bu foto\u011fraf dosyas\u0131 de\u011fil (.csv, .txt veya .json).\", docPricePdf:\"Fiyat listesi (PDF)\", docPriceXlsx:\"Fiyat listesi (Excel)\",\n    catNotXlsx:\"Bu bir .xlsx dosyas\u0131 de\u011fil.\",\n    catCurrent:\"Ge\u00e7erli katalog\", catOpenCur:\"Mevcut olan\u0131 a\u00e7\",\n    catNone:\"Hen\u00fcz katalog y\u00fcklenmedi.\",\n    imgNone:\"Hen\u00fcz foto\u011fraf dosyas\u0131 y\u00fcklenmedi \u2014 \u00fcr\u00fcn resimleri yerle\u015fik setten gelir.\",\n    catByUrl:\"Bunun yerine adres kullan\", catUrlLb:\"Katalog PDF adresi\",\n    catPagesLb:\"Anl\u0131k g\u00f6r\u00fcnt\u00fc resim adresi\", catSave:\"Kaydet\",\n    catReading:\"Dosya okunuyor\u2026\", catSending:\"Servise g\u00f6nderiliyor\u2026\",\n    catUploaded:\"Y\u00fcklendi. M\u00fc\u015fteriler bundan sonra yeni katalo\u011fu g\u00f6r\u00fcr.\",\n    catReplaced:\"De\u011fi\u015ftirildi. \u00d6nceki s\u00fcr\u00fcm gerekirse Drive \u00e7\u00f6p kutusunda.\",\n    catFailed:\"G\u00f6nderilemedi. Tekrar deneyin veya bir adres yap\u0131\u015ft\u0131r\u0131n.\",\n    catSaved:\"Kaydedildi.\", catAdminOnly:\"Katalo\u011fu yaln\u0131zca bir y\u00f6netici de\u011fi\u015ftirebilir.\",\n    catNotPdf:\"Bu bir PDF de\u011fil.\",\n    catTooBig:\"Bu dosya {mb} MB, bu yolla g\u00f6ndermek i\u00e7in \u00e7ok b\u00fcy\u00fck. WordPress'e y\u00fckleyip adresini yap\u0131\u015ft\u0131r\u0131n.\",\n    qtyResize:\"Kolon geni\u015fli\u011fini ayarlamak i\u00e7in s\u00fcr\u00fckleyin\",\n    qtyBox:\"Koli kutusu\",\n    msgCollapse:\"Mesajlar\u0131 gizle\", msgExpand:\"Mesajlar\u0131 g\u00f6ster\",\n    pubNow:\"Herkese yay\u0131nla\", pubSending:\"Yay\u0131nlan\u0131yor\u2026\",\n    pubDone:\"Yay\u0131nland\u0131. {n} \u00fcr\u00fcn de\u011fi\u015fikli\u011fi art\u0131k iki portalda da ge\u00e7erli.\",\n    pubDone1:\"Yay\u0131nland\u0131. Bu de\u011fi\u015fiklik art\u0131k iki portalda da ge\u00e7erli.\",\n    pubFailed:\"Servise ula\u015f\u0131lamad\u0131. Bunun yerine a\u015fa\u011f\u0131daki blo\u011fu kullan\u0131n.\",\n    pubAdminOnly:\"\u00dcr\u00fcn de\u011fi\u015fikliklerini yaln\u0131zca bir y\u00f6netici yay\u0131nlayabilir.\",\n    pubHelp:\"Yay\u0131nlamak bu de\u011fi\u015fiklikleri Claimont servisine g\u00f6nderir. Her iki portal da bir sonraki a\u00e7\u0131l\u0131\u015fta al\u0131r \u2014 WordPress'e dokunman\u0131z gerekmez. Onaylanm\u0131\u015f sipari\u015fler verildikleri fiyat ve bilgilerle aynen kal\u0131r.\",\n    pubHelpStaff:\"Yaln\u0131zca y\u00f6netici yay\u0131nlayabilir. De\u011fi\u015fikliklerinizi bir y\u00f6neticiye iletin veya a\u015fa\u011f\u0131daki blo\u011fu kullan\u0131n.\",\n    pubManual:\"Bunun yerine elle yay\u0131nla\",\n    regNeedRep:\"Bu hesab\u0131n sorumlusu olan temsilciyi girin.\",\n    regNeedMail:\"Bu temsilcinin e-posta adresini girin.\",\n    gridBrand:\"Marka\", gridFlavour:\"Aroma \/ a\u00e7\u0131klama\",\n    activity:\"Hareketler\", markRead:\"T\u00fcm\u00fcn\u00fc okundu i\u015faretle\", noActivity:\"Hen\u00fcz bir \u015fey yok.\",\n    actOrder:\"Sipari\u015f\", actDraft:\"Taslak\", actFirst:\"\u0130lk giri\u015f\", actOpen:\"A\u00e7t\u0131\", actMsg:\"Mesaj\",\n    messages:\"Mesajlar\", msgSend:\"G\u00f6nder\", msgYouShort:\"Siz\",\n    msgNoThreads:\"Hen\u00fcz g\u00f6r\u00fc\u015fme yok. Ba\u015flatmak i\u00e7in a\u015fa\u011f\u0131dan bir m\u00fc\u015fteri a\u00e7\u0131n.\",\n    msgEmptyThread:\"Burada hen\u00fcz bir \u015fey yok \u2014 ilk mesaj\u0131 yaz\u0131n.\",\n    msgPlaceholder:\"Bu m\u00fc\u015fteriye yaz\u0131n\u2026\", msgFailed:\"G\u00f6nderilemedi. Tekrar deneyin.\",\n    msgWrite:\"Mesaj\",\n    draftPill:\"Taslak\", draftTitle:\"G\u00f6nderilmemi\u015f taslak sipari\u015f\",\n    draftNote:\"M\u00fc\u015fteri bu sipari\u015fi olu\u015fturmaya ba\u015flad\u0131 ancak hen\u00fcz g\u00f6ndermedi.\",\n    master:\"Toplu d\u00fczenleme\",\n    masterOn:\"Toplu d\u00fczenleme a\u00e7\u0131k\",\n    masterCount:\"{n} \u00fcr\u00fcn de\u011fi\u015fti \u2014 hen\u00fcz yay\u0131nlanmad\u0131\",\n    masterCount1:\"1 \u00fcr\u00fcn de\u011fi\u015fti \u2014 hen\u00fcz yay\u0131nlanmad\u0131\",\n    masterNone:\"De\u011fi\u015ftirmek i\u00e7in herhangi bir h\u00fccreye t\u0131klay\u0131n. Blo\u011fu kopyalayana kadar hi\u00e7bir \u015fey yay\u0131nlanmaz.\",\n    masterPublish:\"Yay\u0131nlanacak blo\u011fu g\u00f6ster\",\n    masterDone:\"Bitti\",\n    oldTitle:\"Claimont servisinin g\u00fcncellenmesi gerekiyor\",\n    oldText:\"Bu portal, arka u\u00e7 script'in eski bir s\u00fcr\u00fcm\u00fcyle konu\u015fuyor; ge\u00e7mi\u015f sipari\u015fler ve sipari\u015f detay\u0131 gibi baz\u0131 \u00f6zellikler \u00e7al\u0131\u015fmaz. Apps Script'te en g\u00fcncel claimont-backend.gs dosyas\u0131n\u0131 yap\u0131\u015ft\u0131r\u0131n, ard\u0131ndan Deploy \u2192 Manage deployments \u2192 \u270f\ufe0f \u2192 Version: New version \u2192 Deploy yap\u0131n.\",\n    floorLoaded:\"Zemine y\u00fckleme\", palletised:\"Paletli\", palletsShort:\"palet\",\n    palSettings:\"Palet ayarlar\u0131\", palSize:\"Palet \u00f6l\u00e7\u00fcs\u00fc\",\n    palWeight:\"Bo\u015f palet a\u011f\u0131rl\u0131\u011f\u0131 (kg)\",\n    palNote:\"Kapasiteler, konteyner ba\u015f\u0131na tek s\u0131ra (\u00fcst \u00fcste koymadan) palet say\u0131s\u0131d\u0131r. Palet \u00f6l\u00e7\u00fcn\u00fcz farkl\u0131ysa de\u011fi\u015ftirin; rakamlar nakliyecinizinkiyle uyu\u015fmuyorsa Claimont'a bildirin.\",\n    palletsWhole:\"Palet\", loading:\"Y\u00fckleme\", order2:\"Sipari\u015f formu\", pricelist2:\"Fiyat listesi 2026\", productsWord:\"\u00fcr\u00fcn\",\n    live:\"AMB kuru\", fallback:\"sabit kur\", manual:\"girdi\u011finiz kur\", fxLoading:\"y\u00fckleniyor\u2026\",\n    noteshd:\"Notlar\",\n    notes:[\n      \"T\u00fcm fiyatlar <strong>fabrika teslim (ex-works)<\/strong> olup vergiler, FOB ve navlun masraflar\u0131 hari\u00e7tir.\",\n      \"EUR fiyatlar\u0131, sa\u011f \u00fcstte g\u00f6sterilen kur ile USD \u00fczerinden hesaplan\u0131r. Kuru de\u011fi\u015ftirerek bu oturum i\u00e7in ge\u00e7ersiz k\u0131labilirsiniz.\",\n      \"Miktar\u0131 <strong>koli<\/strong> olarak girin; adet, palet, hacim, a\u011f\u0131rl\u0131k ve toplamlar otomatik hesaplan\u0131r.\",\n      \"Tablonun alt\u0131ndan <strong>Zemine y\u00fckleme<\/strong> ve <strong>Paletli<\/strong> aras\u0131nda ge\u00e7i\u015f yap\u0131n. Zemine y\u00fcklemede konteyner hacimle \u00f6l\u00e7\u00fcl\u00fcr (20' DV 29 m\u00b3 \u00b7 40' HC 76,3 m\u00b3 \u00b7 45' HC 85,6 m\u00b3 \u00b7 Tautliner t\u0131r 90 m\u00b3). Paletli se\u00e7ildi\u011finde her \u00fcr\u00fcn tam palete yuvarlan\u0131r, bo\u015f palet a\u011f\u0131rl\u0131\u011f\u0131 eklenir ve konteyner palet yeri \u00fczerinden \u00f6l\u00e7\u00fcl\u00fcr.\",\n      \"<span class='flag'>Teklif \u00f6ncesi kontrol edin:<\/span> baz\u0131 \u00fcr\u00fcnler ayn\u0131 \u00fcr\u00fcn barkodunu payla\u015f\u0131yor ve koli barkodlar\u0131 hen\u00fcz kay\u0131tl\u0131 de\u011fil. Nokta ile i\u015faretli \u00fcr\u00fcnlerin barkodu tekrarlanm\u0131\u015f veya eksiktir.\",\n      \"<strong>\u00dcr\u00fcn ekle<\/strong> ile yeni \u00fcr\u00fcn eklenir, \u00fcr\u00fcn numaras\u0131na t\u0131klayarak mevcut \u00fcr\u00fcn\u00fc d\u00fczenleyebilirsiniz. De\u011fi\u015fiklikler an\u0131nda g\u00f6r\u00fcn\u00fcr ancak yaln\u0131zca kendi taray\u0131c\u0131n\u0131zda ge\u00e7erlidir \u2014 portal, herkes i\u00e7in kal\u0131c\u0131 olmas\u0131 ad\u0131na WordPress'e yap\u0131\u015ft\u0131rman\u0131z gereken kod blo\u011funu size verir.\"\n    ],\n    printsub:\"Fabrika teslim fiyat listesi \u00b7 olu\u015fturulma\",\n    add:\"+ \u00dcr\u00fcn ekle\", edit:\"\u00dcr\u00fcn\u00fc d\u00fczenle\", addTitle:\"\u00dcr\u00fcn ekle\",\n    save:\"\u00dcr\u00fcn\u00fc kaydet\", cancel:\"Vazge\u00e7\", close:\"Kapat\", remove:\"Kald\u0131r\",\n    gIdentity:\"Tan\u0131m\", gPhoto:\"Foto\u011fraf\", gPack:\"Ambalaj ve \u00f6l\u00e7\u00fcler\",\n    gWeights:\"A\u011f\u0131rl\u0131klar\", gCodes:\"Kodlar ve saklama\", gPrices:\"Fiyatlar (USD, fabrika teslim)\",\n    fields:{id:\"\u00dcr\u00fcn numaras\u0131\",fam:\"Marka ailesi (filtre etiketi)\",famTr:\"Marka ailesi \u2014 T\u00fcrk\u00e7e\",\n      brand:\"Marka sat\u0131r\u0131\",brandTr:\"Marka sat\u0131r\u0131 \u2014 T\u00fcrk\u00e7e\",name:\"Aroma \/ a\u00e7\u0131klama\",\n      nameTr:\"Aroma \/ a\u00e7\u0131klama \u2014 T\u00fcrk\u00e7e\",g:\"Gramaj (g)\",upc:\"Koli i\u00e7i adet\",\n      cpp:\"Palet ba\u015f\u0131na koli\",l:\"Koli uzunlu\u011fu (cm)\",w:\"Koli geni\u015fli\u011fi (cm)\",h:\"Koli y\u00fcksekli\u011fi (cm)\",\n      cbm:\"Koli hacmi (m\u00b3)\",net:\"Koli net a\u011f\u0131rl\u0131\u011f\u0131 (kg)\",tare:\"Bo\u015f koli a\u011f\u0131rl\u0131\u011f\u0131 (kg)\",\n      gross:\"Koli br\u00fct a\u011f\u0131rl\u0131\u011f\u0131 (kg)\",shelf:\"Raf \u00f6mr\u00fc\",temp:\"Saklama s\u0131cakl\u0131\u011f\u0131\",\n      hs:\"GT\u0130P kodu\",bc:\"\u00dcr\u00fcn barkodu\",cbc:\"Koli barkodu\",pu:\"Birim fiyat\",pc:\"Koli fiyat\u0131\"},\n    autoHint:\"hesaplan\u0131r \u2014 de\u011fi\u015ftirmek i\u00e7in yaz\u0131n\",\n    photoPick:\"G\u00f6rsel se\u00e7\u2026\", photoNone:\"Hen\u00fcz foto\u011fraf yok\", photoHint:\"PNG veya JPG. Otomatik boyutland\u0131r\u0131l\u0131r.\",\n    errId:\"\u00dcr\u00fcn numaras\u0131 zorunludur ve daha \u00f6nce kullan\u0131lmam\u0131\u015f olmal\u0131d\u0131r.\",\n    errName:\"Marka sat\u0131r\u0131 ve aroma zorunludur.\",\n    errPhoto:\"Foto\u011fraf zorunludur.\",\n    codeTitle:\"WordPress'e yap\u0131\u015ft\u0131r\u0131lacak kod\",\n    codeCount:n=>`${n} de\u011fi\u015fiklik yay\u0131nlanacak`,\n    codeHelp:\"De\u011fi\u015fiklikleriniz yaln\u0131zca bu taray\u0131c\u0131da ge\u00e7erlidir. Herkes i\u00e7in kal\u0131c\u0131 olmas\u0131 ad\u0131na sayfay\u0131 WordPress'te a\u00e7\u0131n, kodun ba\u015f\u0131ndaki <strong>EXTRA<\/strong> ve <strong>OVERRIDES<\/strong> bloklar\u0131n\u0131 bulun ve a\u015fa\u011f\u0131daki metinle de\u011fi\u015ftirin. Ard\u0131ndan sayfay\u0131 g\u00fcncelleyin.\",\n    copy:\"Veriyi kopyala\", copied:\"Kopyaland\u0131\",\n    pubOn:\"G\u00f6r\u00fcn\u00fcr\", pubOff:\"Dahili\",\n    fPub:\"Bu \u00fcr\u00fcn\u00fc m\u00fc\u015fterilere g\u00f6ster\",\n    syncLive:\"Ortak veri\", syncBuiltin:\"Dosya i\u00e7i veri\", syncLoading:\"Kontrol ediliyor\u2026\",\n    syncLiveTip:\"Ortak veri sayfas\u0131 okunuyor \u2014 m\u00fc\u015fteri portal\u0131 da ayn\u0131s\u0131n\u0131 g\u00f6r\u00fcyor\",\n    syncBuiltinTip:\"Ortak veri sayfas\u0131 okunamad\u0131. Bu dosyaya g\u00f6m\u00fcl\u00fc s\u00fcr\u00fcm g\u00f6steriliyor.\",\n    gTitle:\"Giri\u015f\", gText:\"Ki\u015fisel personel kodunuzu girin. Kodlar\u0131 Sami verir.\",\n    gUnset:\"Bu portal hen\u00fcz Claimont sistemine ba\u011fl\u0131 de\u011fil. Sayfan\u0131n ba\u015f\u0131ndaki ENDPOINT_URL ayar\u0131n\u0131n doldurulmas\u0131 gerekiyor.\", gGo:\"Giri\u015f\", gChecking:\"Kontrol ediliyor\u2026\", gEmpty:\"Devam etmek i\u00e7in kodunuzu girin.\",\n    gBad:\"Bu kod tan\u0131nmad\u0131 veya kapat\u0131lm\u0131\u015f.\",\n    gOffline:\"Claimont servisine \u015fu anda ula\u015f\u0131lam\u0131yor. Birazdan tekrar deneyin.\",\n    myCustomers:\"M\u00fc\u015fterilerim\", noCustomers:\"Size atanm\u0131\u015f m\u00fc\u015fteri yok.\",\n    noOrdersYet:\"Hen\u00fcz sipari\u015f yok.\", ordersWord:\"sipari\u015f\", cartonsWord:\"koli\",\n    oWhen:\"Tarih\", oCompany:\"Firma\", oContact:\"Yetkili\", oEmail:\"E-posta\",\n    oPhone:\"Telefon\", oCountry:\"Var\u0131\u015f\", oNotes:\"Notlar\",\n    capNote:\"(en fazla %{n} verebilirsiniz)\",\n    overLimit:\"Bu oran %{n} olan limitinizin \u00fczerinde. Bir y\u00f6neticiden limitinizi y\u00fckseltmesini veya indirimi kendisinin girmesini isteyin.\",\n    regCustomers:\"M\u00fc\u015fteriler\", regUsers:\"Personel\", regNew:\"Yeni\", regEmpty:\"Hen\u00fcz kay\u0131t yok.\",\n    reg:{ref:\"Ref\",code:\"Kod\",customer:\"M\u00fc\u015fteri\",rep:\"\u0130lgili ki\u015fi (m\u00fc\u015fteri taraf\u0131)\",repMail:\"\u0130lgili e-posta\",cPhone:\"\u0130lgili telefon\",cTitle:\"Kartvizit unvan\u0131\",country:\"\u00dclke\",discount:\"\u0130ndirim\",status:\"Durum\",\n         opens:\"A\u00e7\u0131l\u0131\u015f\",lastAccess:\"Son a\u00e7\u0131l\u0131\u015f\",orders:\"Sipari\u015f\",lastOrder:\"Son sipari\u015f\",\n         staffName:\"Ad\",role:\"Rol\",maxDisc:\"Azami ind.\",created:\"Olu\u015fturma\",owner:\"Olu\u015fturan\",\n         userEmail:\"E-posta\",userPhone:\"Telefon\",ownerSel:\"Atanan kullan\u0131c\u0131 \u2014 Claimont temsilcisi\",\n         moqSel:\"Azami farkl\u0131 \u00fcr\u00fcn (SKU s\u0131n\u0131r\u0131)\",moqCol:\"SKU s\u0131n\u0131r\u0131\"},\n    moqNone:\"S\u0131n\u0131r yok \u2014 a\u00e7\u0131k\", moqOpt:\"Konteyner\/t\u0131r ba\u015f\u0131na en fazla {n} SKU\",\n    mwSteps:[\"Sevkiyat\",\"\u00dcr\u00fcnler\",\"Masa\"], mwNext:\"\u0130leri &#8594;\",\n    qtBtn:\"M\u00fc\u015fteri PDF'i\", qtTitle:\"M\u00fc\u015fteri sipari\u015fini haz\u0131rla\", qtAgreed:\"Anla\u015f\u0131lan $\/adet\",\n\n    qtItemsH:\"Bu sipari\u015fteki \u00fcr\u00fcnler \u2014 gerekirse anla\u015f\u0131lan birim fiyat\u0131 d\u00fczenleyin (koli fiyat\u0131 otomatik hesaplan\u0131r)\",\n    qtNotes:\"Belge \u00fczerindeki notlar\", qtPrint:\"Yazd\u0131r \/ PDF kaydet\",\n    qtSaveBtn:\"M\u00fc\u015fterinin sipari\u015flerine kaydet\", qtSaving:\"Kaydediliyor\u2026\",\n    qtSavedMsg:\"{id} olarak kaydedildi \u2014 art\u0131k burada bu m\u00fc\u015fterinin alt\u0131nda ve m\u00fc\u015fterinin portal\u0131nda g\u00f6r\u00fcn\u00fcyor.\",\n    qtPickFirst:\"\u00d6nce bu sipari\u015fin hangi m\u00fc\u015fteriye ait oldu\u011funu se\u00e7in.\",\n    qtSaveFail:\"Kaydedilemedi \u2014 tekrar deneyin.\",\n    qtHint:\"\u00d6n doldurmak i\u00e7in m\u00fc\u015fteri se\u00e7in ya da serbest\u00e7e yaz\u0131n. De\u011fi\u015fen fiyatlar vurgulan\u0131r ve yaln\u0131zca bu belgede kullan\u0131l\u0131r.\",\n    qtPickNone:\"\u2014 m\u00fc\u015fteri se\u00e7in \u2014\", qtDocSub:\"M\u00fc\u015fteri sipari\u015fi \u00b7 sizin i\u00e7in haz\u0131rland\u0131\",\n    qtFoot:\"Fiyatlar USD ve fabrika teslimidir; vergi, FOB ve navlun hari\u00e7tir. Aksi kararla\u015ft\u0131r\u0131lmad\u0131k\u00e7a 14 g\u00fcn ge\u00e7erlidir.\",\n    viewActive:\"Aktif\", viewArch:\"Ar\u015fiv\", regEmptyArch:\"Ar\u015fivde kay\u0131t yok \u2014 her \u015fey aktif listede.\",\n    regNeedCPhone:\"\u0130lgili ki\u015finin telefon numaras\u0131n\u0131 girin.\", regNeedCTitle:\"\u0130lgili ki\u015finin unvan\u0131n\u0131 girin (kartvizitteki gibi).\",\n    regNeedCountry:\"M\u00fc\u015fterinin \u00fclkesini girin.\",\n    regNeedUserMail:\"Her kullan\u0131c\u0131n\u0131n bir e-postas\u0131 olmal\u0131 \u2014 m\u00fc\u015fterileri bunu do\u011frudan ileti\u015fim olarak g\u00f6r\u00fcr.\",\n    regNeedUserPhone:\"Her kullan\u0131c\u0131n\u0131n bir telefon numaras\u0131 olmal\u0131 \u2014 m\u00fc\u015fterileri bunu do\u011frudan ileti\u015fim olarak g\u00f6r\u00fcr.\",\n    pdfBtn:\"PDF indir\", pdfWait:\"PDF haz\u0131rlan\u0131yor\u2026\", pdfFailed:\"PDF olu\u015fturulamad\u0131 \u2014 tekrar deneyin.\",\n    statusOn:\"Aktif\", statusOff:\"Kapal\u0131\", never:\"hi\u00e7\",\n    regNeedName:\"\u00d6nce bu kayda bir ad verin.\",\n    save2:\"Kaydet\", saving:\"Kaydediliyor\u2026\", savedOk:\"Kaydedildi\", createdOk:\"Olu\u015fturuldu\",\n    saveFailed:\"Kaydedilemedi. Ba\u011flant\u0131n\u0131z\u0131 kontrol edip tekrar deneyin.\",\n    listFailed:\"Liste y\u00fcklenemedi. Ba\u011flant\u0131n\u0131z\u0131 kontrol edip tekrar deneyin.\",\n    loadingList:\"Y\u00fckleniyor\u2026\",\n    codeNoteCust:\"Bu kodu m\u00fc\u015fteriye verin \u2014 sipari\u015f portal\u0131n\u0131 a\u00e7mak i\u00e7in ihtiyac\u0131 olan tek \u015fey budur. Kayd\u0131 kapatana kadar ge\u00e7erlidir.\",\n    codeNoteUser:\"Bu kodu ilgili ki\u015fiye verin. Buraya bu kodla giri\u015f yapar. Eri\u015fimi kald\u0131rmak i\u00e7in kayd\u0131 kapat\u0131n.\",\n    esign:\"giri\u015f yapan\", regBack:\"Listeye d\u00f6n\", activeLabel:\"Aktif \u2014 kod \u00e7al\u0131\u015f\u0131yor\",\n    csTitle:\"Yeni m\u00fc\u015fteri kodu\", csBtn:\"M\u00fc\u015fteri kodu\", csRef:\"Referans\", csGen:\"Olu\u015ftur\", csCopy:\"Sat\u0131r\u0131 kopyala\",\n    csCodeLbl:\"M\u00fc\u015fteriye verilecek kod\",\n    csHelp:\"Yukar\u0131daki kodu m\u00fc\u015fteriye verin. A\u015fa\u011f\u0131daki sat\u0131r\u0131 WordPress'te m\u00fc\u015fteri portal\u0131 sayfas\u0131n\u0131n ba\u015f\u0131ndaki <strong>CODES<\/strong> blo\u011funa yap\u0131\u015ft\u0131r\u0131n ve sayfay\u0131 g\u00fcncelleyin. Kodun kendisi hi\u00e7bir yerde saklanmaz \u2014 yaln\u0131zca parmak izi tutulur, bu y\u00fczden hangi kodun kimde oldu\u011funu kendiniz kaydedin.\",\n    csNeedRef:\"\u00d6nce bu m\u00fc\u015fteri i\u00e7in k\u0131sa bir referans girin.\",\n    csNoCrypto:\"Kod \u00fcretebilmek i\u00e7in sayfan\u0131n https \u00fczerinden a\u00e7\u0131lmas\u0131 gerekir.\",\n    codeTitle2:\"Ortak veri sayfas\u0131na yay\u0131nla\",\n    codeHelp2:\"De\u011fi\u015fiklikleriniz yaln\u0131zca bu taray\u0131c\u0131da ge\u00e7erli. <strong>Her iki portala birden<\/strong> yay\u0131nlamak i\u00e7in a\u015fa\u011f\u0131daki blo\u011fu kopyalay\u0131n, WordPress'te <strong>claimont-data<\/strong> sayfas\u0131n\u0131 a\u00e7\u0131n, \u00d6zel HTML blo\u011fundaki her \u015feyi bununla de\u011fi\u015ftirin ve sayfay\u0131 g\u00fcncelleyin.\"\n  }\n};\n\nconst CONTAINERS = [\n  {key:\"20dv\", name:\"20' DV\", cbm:29,   slots:{std:10, euro:11}, payload:28200, inner:\"5.90 \u00d7 2.35 \u00d7 2.39 m\"},\n  {key:\"40hc\", name:\"40' HC\", cbm:76.3, slots:{std:21, euro:24}, payload:28600, inner:\"12.03 \u00d7 2.35 \u00d7 2.69 m\"},\n  {key:\"45hc\", name:\"45' HC\", cbm:85.6, slots:{std:24, euro:27}, payload:27600, inner:\"13.56 \u00d7 2.35 \u00d7 2.69 m\"},\n  {key:\"taut\", name:\"Tautliner 13.6 m\", cbm:90, slots:{std:26, euro:33}, payload:24500, inner:\"13.60 \\u00d7 2.50 \\u00d7 2.65 m\"}\n];\nlet contType=\"40hc\", contCount=1;\n\/* the desk's own SKU-per-container allowance \u2014 a planning aid, remembered per browser *\/\nlet deskMoq=0;\ntry{ deskMoq=Math.max(0,+(localStorage.getItem(\"clm-desk-moq\")||0)||0); }catch(e){}\nfunction container(){ return CONTAINERS.find(c=>c.key===contType) || CONTAINERS[1]; }\n\/* floor loading keeps a ~10% packing allowance in reserve: real-world loading\n   never quite reaches the paper volume, and a container that \"just fits\" on\n   screen but not at the ramp makes nobody happy *\/\nconst FLOOR_ALLOWANCE = 0.9;\nfunction capacityPer(){ const c=container(); return palletised ? c.slots[palletType] : c.cbm*FLOOR_ALLOWANCE; }\nfunction fitReport(t){\n  const c=container(), per=capacityPer(), used=palletised?t.pallets:t.cbm;\n  const cap=per*Math.max(1,contCount);\n  const need=used>0?Math.ceil(used\/per):0;\n  const pct=cap?used\/cap*100:0;\n  const overWeight=t.gross>c.payload*Math.max(1,contCount);\n  let state=\"idle\";\n  if(used<=0) state=\"idle\";\n  else if(pct>100) state=\"over\";\n  else if(pct>=90) state=\"full\";\n  else if(pct>=70) state=\"near\";\n  else state=\"light\";\n  return {c, per, cap, used, need, pct, state, overWeight};\n}\nconst PALLET_TYPES = { std:\"100 \u00d7 120 cm\", euro:\"80 \u00d7 120 cm (Euro)\" };\nlet palletised=false, palletType=\"std\", palletKg=25;\n\nconst COLS = [\n  {k:\"idx\",   g:null,     cls:\"c-idx\"},\n  {k:\"ref\",   g:null,     cls:\"c-ref\"},\n  {k:\"photo\", g:null,     cls:\"c-photo\"},\n  {k:\"name\",  g:null,     cls:\"c-name\"},\n  {k:\"pub\",   g:null,     cls:\"c-pub\"},\n  {k:\"g\",     g:null,     n:1},\n  {k:\"upc\",   g:null,     n:1},\n  {k:\"pu\",    g:null,     n:1},\n  {k:\"pue\",   g:null,     n:1},\n  {k:\"pc\",    g:null,     n:1},\n  {k:\"pce\",   g:null,     n:1},\n  {k:\"qty\",   g:null,     cls:\"c-qty\", n:1},\n  {k:\"tusd\",  g:\"g-calc\", n:1},\n  {k:\"teur\",  g:\"g-calc\", n:1},\n  {k:\"units\", g:\"g-calc\", n:1},\n  {k:\"pallets\",g:\"g-calc\",n:1},\n  {k:\"tcbm\",  g:\"g-calc\", n:1},\n  {k:\"tnet\",  g:\"g-calc\", n:1},\n  {k:\"tgross\",g:\"g-calc\", n:1},\n  {k:\"cpp\",   g:\"g-pack\", n:1},\n  {k:\"l\",     g:\"g-pack\", n:1},\n  {k:\"w\",     g:\"g-pack\", n:1},\n  {k:\"h\",     g:\"g-pack\", n:1},\n  {k:\"cbm\",   g:\"g-pack\", n:1},\n  {k:\"net\",   g:\"g-wt\",   n:1},\n  {k:\"tare\",  g:\"g-wt\",   n:1},\n  {k:\"gross\", g:\"g-wt\",   n:1},\n  {k:\"shelf\", g:\"g-comp\"},\n  {k:\"temp\",  g:\"g-comp\"},\n  {k:\"hs\",    g:\"g-comp\"},\n  {k:\"bc\",    g:\"g-comp\"},\n  {k:\"cbc\",   g:\"g-comp\"}\n];\n\nlet lang = \"en\";\nlet rate = 0.87;\nlet rateSource = \"fallback\";\nlet rateDate = \"\";\nconst qty = {};\nlet filter = \"all\";\nlet query = \"\";\n\n\/\/ flag items whose unit barcode is missing or shared with another item\nfunction recomputeFlags(){\n  const c={};\n  DATA.forEach(d=>{ if(d.bc) c[d.bc]=(c[d.bc]||0)+1; });\n  DATA.forEach(d=>{ d.flag = !!d.bc && c[d.bc] > 1; });\n}\nrecomputeFlags();\n\n\/\/ pristine copy of every product as published, so an edit emits only what changed\nconst ORIGINAL = {};\nfunction snapshotOriginals(){ DATA.forEach(d=>{ ORIGINAL[d.id] = Object.assign({}, d); }); }\nsnapshotOriginals();\n\n\/\/ everything currently published, plus anything changed in this browser session\nconst draft = { added:{}, edited:{}, prices:{}, pub:{} };\nlet publishedSnapshot = \"\";\nfunction seedDraft(j){\n  if(j.prices) Object.assign(draft.prices, j.prices);\n  if(j.public) Object.assign(draft.pub, j.public);\n  if(j.overrides) Object.assign(draft.edited, j.overrides);\n  if(Array.isArray(j.extra)) j.extra.forEach(e=>{ draft.added[e.id]=e; });\n  publishedSnapshot = draftJSON();\n}\n\nconst $ = s => document.querySelector(s);\nconst BACKEND_MIN = 17;\n\/* Which product list this build was made for. Published changes carry the same\n   tag; anything tagged for a different list is ignored rather than applied to\n   products that now mean something else. *\/\nconst DATASET = 4;\nfunction checkVersion(v){\n  const el=$(\"#oldver\"), t=T[lang];\n  const ok = Number(v) >= BACKEND_MIN;\n  el.hidden = ok;\n  if(!ok) el.innerHTML = `<b>${t.oldTitle}<\/b>${t.oldText}`;\n}\nconst esc = v => String(v==null?\"\":v).replace(\/[&<>\"]\/g,c=>({\"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\"}[c]));\nconst fmt = (v,d=0) => v==null||isNaN(v) ? \"\u2014\" :\n  new Intl.NumberFormat(lang===\"tr\"?\"tr-TR\":\"en-US\",{minimumFractionDigits:d,maximumFractionDigits:d}).format(v);\nconst money = (v,d=2) => fmt(v,d);\n\nfunction families(){\n  const seen=[];\n  DATA.forEach(d=>{ const f=lang===\"tr\"?d.famTr:d.fam; if(!seen.some(x=>x.k===d.fam)) seen.push({k:d.fam,label:f,n:0}); });\n  seen.forEach(s=>s.n=DATA.filter(d=>d.fam===s.k).length);\n  return seen;\n}\n\nfunction visible(){\n  const q=query.trim().toLowerCase();\n  const rows=DATA.filter(d=>{\n    if(filter!==\"all\" && d.fam!==filter) return false;\n    if(!q) return true;\n    const hay=[d.id,d.ref,d.brand,d.brandTr,d.name,d.nameTr,d.hs,d.bc,d.g].join(\" \").toLowerCase();\n    return hay.includes(q);\n  });\n  \/* the basket floats to the top \u2014 but only re-sorted once quantity entry has\n     finished, so rows never jump under the cursor (and never in master edit) *\/\n  if(master) return rows;\n  return rows.map((d,i)=>[d,i]).sort((a,b)=>((qty[b[0].id]>0)-(qty[a[0].id]>0))||(a[1]-b[1])).map(x=>x[0]);\n}\n\n\/* Which columns master edit opens up, and how each one is typed. Anything not\n   listed here stays read-only: row number, photo, cartons, and every total that\n   is calculated from cartons. *\/\nconst GRID = {\n  idx:{t:\"id\"}, photo:{t:\"photo\"}, ref:{t:\"text\"},\n  name:{t:\"text\",wide:1}, pub:{t:\"bool\"},\n  g:{t:\"num\",step:\"any\"}, upc:{t:\"num\",step:\"1\"},\n  pu:{t:\"num\",step:\"any\"}, pc:{t:\"num\",step:\"any\"},\n  cpp:{t:\"num\",step:\"1\"}, l:{t:\"num\",step:\"any\"}, w:{t:\"num\",step:\"any\"}, h:{t:\"num\",step:\"any\"},\n  cbm:{t:\"num\",step:\"any\"}, net:{t:\"num\",step:\"any\"}, tare:{t:\"num\",step:\"any\"}, gross:{t:\"num\",step:\"any\"},\n  shelf:{t:\"text\"}, temp:{t:\"text\"}, hs:{t:\"text\"}, bc:{t:\"text\"}, cbc:{t:\"text\"}\n};\n\/* a derived cell stops auto-filling once someone types into it directly *\/\nconst typedIn = new Set();\nlet master = false;\nfunction gridCell(d,k){\n  const g=GRID[k], t=T[lang];\n  if(!g) return null;\n  if(g.t===\"id\")\n    return `<input class=\"gedit n idedit\" type=\"number\" step=\"1\" min=\"1\" data-id=\"${d.id}\" data-k=\"idx\" `\n         + `value=\"${d.id}\" aria-label=\"${t.cols.idx}\" title=\"${t.idHint}\">`;\n  if(g.t===\"photo\")\n    return `<button class=\"photoedit\" data-photo=\"${d.id}\" title=\"${t.photoHint}\" aria-label=\"${t.photoHint}\">`\n         + (d.img ? `<img decoding=\"async\" class=\"thumb\" src=\"${d.img}\" alt=\"\">` : `<span class=\"thumb nophoto\"><\/span>`)\n         + `<span class=\"pen2\">\\u270E<\/span><\/button>`;\n  if(k===\"name\"){\n    const bk=lang===\"tr\"?\"brandTr\":\"brand\", nk=lang===\"tr\"?\"nameTr\":\"name\";\n    return `<div class=\"nameedit\">`\n         + `<input class=\"gedit\" data-id=\"${d.id}\" data-k=\"${bk}\" value=\"${esc(d[bk]||\"\")}\" `\n         + `placeholder=\"${t.gridBrand}\" aria-label=\"${t.gridBrand}\">`\n         + `<input class=\"gedit\" data-id=\"${d.id}\" data-k=\"${nk}\" value=\"${esc(d[nk]||\"\")}\" `\n         + `placeholder=\"${t.gridFlavour}\" aria-label=\"${t.gridFlavour}\">`\n         + `<\/div>`;\n  }\n  if(g.t===\"bool\"){\n    return `<select class=\"gedit\" data-id=\"${d.id}\" data-k=\"pub\" aria-label=\"${t.cols.pub}\">`\n         + `<option value=\"1\"${d.pub?\" selected\":\"\"}>${t.pubOn}<\/option>`\n         + `<option value=\"0\"${d.pub?\"\":\" selected\"}>${t.pubOff}<\/option><\/select>`;\n  }\n  const v = d[k]==null ? \"\" : d[k];\n  if(g.t===\"num\")\n    return `<input class=\"gedit n\" type=\"number\" step=\"${g.step}\" data-id=\"${d.id}\" data-k=\"${k}\" `\n         + `value=\"${v}\" aria-label=\"${t.cols[k]||k}\">`;\n  return `<input class=\"gedit\" data-id=\"${d.id}\" data-k=\"${k}\" value=\"${esc(v)}\" aria-label=\"${t.cols[k]||k}\">`;\n}\nfunction cell(d,k){\n  const c=qty[d.id]||0;\n  if(master){ const g=gridCell(d,k); if(g!==null) return g; }\n  switch(k){\n    case \"pub\": return `<span class=\"pub ${d.pub?\"on\":\"off\"}\">${d.pub?T[lang].pubOn:T[lang].pubOff}<\/span>`;\n    case \"ref\": return `<span class=\"refcode\">${esc(d.ref||\"\u2014\")}<\/span>`;\n    case \"idx\": return `<button class=\"rowedit\" data-edit=\"${d.id}\" title=\"${T[lang].edit}\">${String(d.id).padStart(2,\"0\")}<svg class=\"pen\" viewBox=\"0 0 24 24\"><path d=\"M4 20h4L19 9a2.8 2.8 0 0 0-4-4L4 16v4z\"\/><\/svg><\/button>`;\n    case \"photo\": return d.img ? `<img decoding=\"async\" class=\"thumb\" src=\"${d.img}\" alt=\"\" loading=\"lazy\" data-full=\"${d.img}\">` : `<span class=\"thumb nophoto\"><\/span>`;\n    case \"name\": return `<div class=\"pname\"><span class=\"b\">${lang===\"tr\"?d.brandTr:d.brand}<\/span><span class=\"f\">${lang===\"tr\"?d.nameTr:d.name}<\/span><\/div>`;\n    case \"g\": return fmt(d.g)+\" g\";\n    case \"upc\": return fmt(d.upc);\n    case \"qty\": return `<span class=\"qtywrap\"><button type=\"button\" class=\"qstep qminus\" data-id=\"${d.id}\" aria-label=\"Less\" tabindex=\"-1\">&#8722;<\/button><input class=\"qty num\" type=\"number\" min=\"0\" step=\"1\" inputmode=\"numeric\" value=\"${c||\"\"}\" data-id=\"${d.id}\" placeholder=\"0\" aria-label=\"Cartons\"><button type=\"button\" class=\"qstep qplus\" data-id=\"${d.id}\" aria-label=\"More\" tabindex=\"-1\">+<\/button><\/span>`;\n    case \"pc\": return \"$\"+money(d.pc);\n    case \"pce\": return \"\u20ac\"+money(d.pc*rate);\n    case \"pu\": return \"$\"+money(d.pu,3);\n    case \"pue\": return \"\u20ac\"+money(d.pu*rate,3);\n    case \"units\": return c? `<span class=\"calc\">${fmt(c*d.upc)}<\/span>` : `<span class=\"muted\">\u2014<\/span>`;\n    case \"pallets\": return c? `<span class=\"calc\">${fmt(linePallets(d,c), palletised?0:2)}<\/span>` : `<span class=\"muted\">\u2014<\/span>`;\n    case \"tcbm\": return c? `<span class=\"calc\">${fmt(c*d.cbm,3)}<\/span>` : `<span class=\"muted\">\u2014<\/span>`;\n    case \"tnet\": return c? `<span class=\"calc\">${fmt(c*d.net,1)}<\/span>` : `<span class=\"muted\">\u2014<\/span>`;\n    case \"tgross\": return c? `<span class=\"calc\">${fmt(c*d.gross + (palletised?Math.ceil(c\/d.cpp)*palletKg:0),1)}<\/span>` : `<span class=\"muted\">\u2014<\/span>`;\n    case \"tusd\": return c? `<span class=\"calc\">$${money(c*d.pc)}<\/span>` : `<span class=\"muted\">\u2014<\/span>`;\n    case \"teur\": return c? `<span class=\"calc\">\u20ac${money(c*d.pc*rate)}<\/span>` : `<span class=\"muted\">\u2014<\/span>`;\n    case \"cpp\": return fmt(d.cpp);\n    case \"l\": return fmt(d.l,1); case \"w\": return fmt(d.w,1); case \"h\": return fmt(d.h,1);\n    case \"cbm\": return fmt(d.cbm,4);\n    case \"net\": return fmt(d.net,3); case \"tare\": return fmt(d.tare,2); case \"gross\": return fmt(d.gross,3);\n    case \"shelf\": return d.shelf||\"\u2014\";\n    case \"temp\": return d.temp? `<span class=\"mono\">${d.temp.replace(\" to \",\"\u2013\").replace(\/\\s*C$\/,\"\u00b0C\")}<\/span>` : \"\u2014\";\n    case \"hs\": return d.hs? `<span class=\"mono\">${d.hs}<\/span>` : \"\u2014\";\n    case \"bc\": return d.bc? `<span class=\"mono\">${d.bc}<\/span>${d.flag?'<span class=\"warnflag\" title=\"duplicate barcode\"><\/span>':\"\"}`\n                          : `<span class=\"muted\">\u2014<\/span><span class=\"warnflag\"><\/span>`;\n    case \"cbc\": return d.cbc? `<span class=\"mono\">${d.cbc}<\/span>` : `<span class=\"muted\">\u2014<\/span>`;\n  }\n  return \"\";\n}\n\n\/* ---------- a Cartons column you can drag wider -----------------------------\n   The number people type is the one thing they must be able to read back, and\n   how much room that needs depends on their quantities, so it is theirs to set. *\/\nconst QTY_MIN=84, QTY_MAX=320, QTYW_KEY=\"claimont-qtyw\";\nfunction setQtyWidth(px,save){\n  const w=Math.max(QTY_MIN,Math.min(QTY_MAX,Math.round(px)));\n  document.documentElement.style.setProperty(\"--qtyw\",w+\"px\");\n  const v=document.getElementById(\"qty-val\"); if(v) v.textContent=w;\n  if(save){ try{ localStorage.setItem(QTYW_KEY,w); }catch(e){} }\n  return w;\n}\nfunction qtyWidthNow(){\n  return parseFloat(getComputedStyle(document.documentElement).getPropertyValue(\"--qtyw\"))||104;\n}\n\/* Keep the bar clear of whatever sticky chrome is above it, measured rather\n   than guessed, so it stays reachable at any zoom or window width. *\/\nfunction syncStickyTop(){\n  const mast=document.querySelector(\".mast\"), ctl=document.querySelector(\".controls\");\n  const h=(mast?mast.offsetHeight:0)+(ctl?ctl.offsetHeight:0);\n  document.documentElement.style.setProperty(\"--stickytop\", h+\"px\");\n}\nwindow.addEventListener(\"resize\",syncStickyTop);\n\/* Grow the column to fit the longest number entered, so a six-figure quantity is\n   never half-hidden. It only ever raises the floor \u2014 a wider manual setting wins. *\/\nfunction fitQtyWidth(){\n  let longest=0;\n  for (const id in qty){ const n=String(qty[id]||\"\"); if(n.length>longest) longest=n.length; }\n  const px = longest ? Math.min(QTY_MAX, 46 + longest*11) : 0;\n  document.documentElement.style.setProperty(\"--qtyfit\", px+\"px\");\n}\n(function(){ try{ const v=+localStorage.getItem(QTYW_KEY); if(v) setQtyWidth(v,false); }catch(e){} })();\n\nfunction attachQtyStepper(){\n  const box=document.getElementById(\"qtyctl\");\n  if(!box || box.dataset.on) return;\n  box.dataset.on=\"1\";\n  document.getElementById(\"qty-narrow\").addEventListener(\"click\",()=>setQtyWidth(qtyWidthNow()-16,true));\n  document.getElementById(\"qty-wide\").addEventListener(\"click\",()=>setQtyWidth(qtyWidthNow()+16,true));\n  document.getElementById(\"qty-val\").textContent=qtyWidthNow();\n}\nfunction attachColGrip(){\n  const th=document.querySelector(\"th.c-qty\");\n  if(!th || th.querySelector(\".colgrip\")) return;\n  const grip=document.createElement(\"span\");\n  grip.className=\"colgrip\"; grip.title=T[lang].qtyResize;\n  grip.setAttribute(\"role\",\"separator\"); grip.setAttribute(\"aria-orientation\",\"vertical\");\n  grip.tabIndex=0;\n  th.appendChild(grip);\n\n  let startX=0, startW=0;\n  const current=qtyWidthNow;\n  const move=e=>{\n    const x=(e.touches?e.touches[0].clientX:e.clientX);\n    setQtyWidth(startW+(x-startX),false);\n  };\n  const stop=()=>{\n    document.removeEventListener(\"pointermove\",move);\n    document.removeEventListener(\"pointerup\",stop);\n    document.body.classList.remove(\"colsizing\"); grip.classList.remove(\"on\");\n    setQtyWidth(current(),true);\n    requestAnimationFrame(syncScrollbars);\n  };\n  grip.addEventListener(\"pointerdown\",e=>{\n    e.preventDefault(); e.stopPropagation();\n    startX=e.clientX; startW=current();\n    grip.classList.add(\"on\"); document.body.classList.add(\"colsizing\");\n    document.addEventListener(\"pointermove\",move);\n    document.addEventListener(\"pointerup\",stop);\n  });\n  \/* keyboard, because a drag handle nobody can tab to is not a control *\/\n  grip.addEventListener(\"keydown\",e=>{\n    const step=e.shiftKey?24:8;\n    if(e.key===\"ArrowLeft\"){ e.preventDefault(); setQtyWidth(current()-step,true); }\n    if(e.key===\"ArrowRight\"){ e.preventDefault(); setQtyWidth(current()+step,true); }\n    if(e.key===\"Home\"){ e.preventDefault(); setQtyWidth(104,true); }\n  });\n  grip.addEventListener(\"dblclick\",()=>setQtyWidth(104,true));\n}\nfunction renderHead(){\n  $(\"#hrow\").innerHTML = COLS.map(c=>{\n    const lbl=T[lang].cols[c.k];\n    return `<th class=\"${c.g||\"\"} ${c.n?\"n\":\"\"} ${c.cls||\"\"}\">${lbl}<\/th>`;\n  }).join(\"\");\n  attachColGrip(); attachQtyStepper(); syncStickyTop();\n}\n\nfunction renderBody(){\n  const rows=visible();\n  const tb=$(\"#tbody\");\n  if(!rows.length){ tb.innerHTML=\"\"; $(\"#empty\").hidden=false; $(\"#empty\").textContent=T[lang].empty; return; }\n  $(\"#empty\").hidden=true;\n  tb.innerHTML = rows.map(d=>{\n    const c=qty[d.id]||0;\n    return `<tr class=\"${c?\"has-qty\":\"\"} ${d.pub?\"\":\"internal\"}\" data-id=\"${d.id}\">`+COLS.map(col=>\n      `<td class=\"${col.g||\"\"} ${col.n?\"n\":\"\"} ${col.cls||\"\"} k-${col.k}\" data-label=\"${T[lang].cols[col.k]}\">${cell(d,col.k)}<\/td>`\n    ).join(\"\")+`<\/tr>`;\n  }).join(\"\");\n}\n\nfunction renderChips(){\n  const fams=families();\n  const total=DATA.length;\n  $(\"#chips\").innerHTML =\n    `<button class=\"chip\" data-f=\"all\" aria-pressed=\"${filter===\"all\"}\">${T[lang].all}<span class=\"c\">${total}<\/span><\/button>`+\n    fams.map(f=>`<button class=\"chip\" data-f=\"${f.k}\" aria-pressed=\"${filter===f.k}\">${f.label}<span class=\"c\">${f.n}<\/span><\/button>`).join(\"\");\n}\n\nfunction linePallets(d,c){ return palletised ? Math.ceil(c\/d.cpp) : c\/d.cpp; }\nfunction totals(){\n  const t={lines:0,cartons:0,units:0,pallets:0,cbm:0,net:0,goods:0,gross:0,usd:0,palletKg:0};\n  DATA.forEach(d=>{ const c=qty[d.id]||0; if(!c) return;\n    t.lines++; t.cartons+=c; t.units+=c*d.upc; t.pallets+=linePallets(d,c);\n    t.cbm+=c*d.cbm; t.net+=c*d.net; t.goods+=c*d.gross; t.usd+=c*d.pc; });\n  \/\/ a loaded pallet carries its own weight; floor-loaded cargo does not\n  t.palletKg = palletised ? t.pallets*palletKg : 0;\n  t.gross = t.goods + t.palletKg;\n  return t;\n}\n\nfunction renderStats(){\n  fitQtyWidth();\n  const t=totals(), s=T[lang].stats;\n  const mt=$(\"#mw-tot\");\n  if(mt) mt.textContent = t.lines\n    ? `${fmt(t.lines)} \u00b7 ${fmt(t.cartons)} \u00b7 $${fmt(t.usd,2)}` : \"\";\n  const bq=$(\"#btn-quote\"); if(bq) bq.disabled = t.lines===0;\n  $(\"#stats\").innerHTML = [\n    [s.lines,fmt(t.lines),\"\"],\n    [s.cartons,fmt(t.cartons),\"\"],\n    [s.units,fmt(t.units),\"\"],\n    ...(palletised?[[s.pallets, fmt(t.pallets,0), T[lang].palletsWhole]]:[]),\n    [s.cbm,fmt(t.cbm,2)+\" m\u00b3\",\"\"],\n    [s.net,fmt(t.net,1)+\" kg\",\"\"],\n    [s.gross,fmt(t.gross,1)+\" kg\", t.palletKg?`+${fmt(t.palletKg,0)} kg ${T[lang].palletsShort}`:\"\"],\n    [s.usd,\"$\"+money(t.usd),\"\",\"money\"],\n    [s.eur,\"\u20ac\"+money(t.usd*rate),`@ ${rate.toFixed(4)}`,\"money\"]\n  ].map(([k,v,sub,cls])=>`<div class=\"stat ${cls||\"\"}\"><div class=\"k\">${k}<\/div><div class=\"v\">${v}<\/div>${sub?`<div class=\"sub\">${sub}<\/div>`:\"\"}<\/div>`).join(\"\");\n\n  renderMeters(t);\n  renderFitbar(t);\n  renderSkuCap(t);\n  syncSecbars();\n}\nfunction renderSkuCap(t){\n  const el=$(\"#skumsg\"); if(!el) return;\n  if(!deskMoq || !t.lines){ el.hidden=true; el.className=\"skumsg\"; return; }\n  const L=T[lang], max=deskMoq*Math.max(1,contCount), over=t.lines>max;\n  el.hidden=false;\n  el.className=\"skumsg\"+(over?\" over\":\"\");\n  el.textContent=(over?L.skuOverMsg:L.skuOkMsg)\n    .replace(\"{have}\",fmt(t.lines)).replace(\"{max}\",fmt(max));\n}\n\/* the mobile wizard's fixed readout: how full the requested containers are,\n   turning amber near the limit and flashing red when the order won't fit *\/\nfunction renderFitbar(t){\n  const fb=$(\"#fitbar\"); if(!fb) return;\n  const on=document.body.classList.contains(\"mwiz\") && mstep>=2 && t.lines>0;\n  if(!on){ fb.hidden=true; return; }\n  const L=T[lang], f=fitReport(t), over=f.state===\"over\"||f.overWeight;\n  fb.hidden=false;\n  fb.className=\"fitbar noprint\"+(over?\" over\":(f.pct>85?\" warn\":\"\"));\n  if(over){\n    fb.textContent=(f.overWeight&&f.state!==\"over\"?L.fitBarW:L.fitBarOver)\n      .replace(\"{n}\",fmt(Math.max(1,contCount))).replace(\"{type}\",f.c.name)\n      .replace(\"{need}\",fmt(f.need)+\" \u00d7 \"+f.c.name);\n  } else {\n    fb.textContent=L.fitBarOk.replace(\"{n}\",fmt(Math.max(1,contCount)))\n      .replace(\"{type}\",f.c.name).replace(\"{pct}\",fmt(f.pct,0));\n  }\n}\n\nfunction renderMeters(t){\n  const tt=T[lang], f=fitReport(t);\n  const unit = palletised ? tt.palletsShort : \"m\u00b3\";\n  $(\"#meters\").innerHTML = CONTAINERS.map(c=>{\n    const per = palletised ? c.slots[palletType] : c.cbm;\n    const chosen = c.key===contType;\n    const cap = per*(chosen?Math.max(1,contCount):1);\n    const pct = cap ? f.used\/cap*100 : 0;\n    const cls = pct>100?\"over\":pct>85?\"warn\":\"\";\n    const need = f.used>0?Math.ceil(f.used\/per):0;\n    return `<div class=\"meter ${cls} ${chosen?\"\":\"dim\"}\">\n      <div class=\"row\"><span>${chosen?\"<b>\"+c.name+\" \u00d7 \"+Math.max(1,contCount)+\"<\/b>\":c.name}<\/span>\n        <span class=\"pc\">${fmt(pct,0)}%<\/span><\/div>\n      <div class=\"bar\"><div class=\"fill\" style=\"width:${Math.min(100,pct)}%\"><\/div><\/div>\n      <div class=\"row\" style=\"margin:3px 0 0\"><span class=\"alt\">${fmt(f.used, palletised?0:2)} \/ ${fmt(cap, palletised?0:1)} ${unit}${\n        chosen?\"\":` \u00b7 ${tt.wouldNeed.replace(\"{n}\",fmt(need))}`}<\/span><\/div>\n    <\/div>`;\n  }).join(\"\");\n  render3D(f);\n  renderFit(f);\n}\n\/* \u2500\u2500 the 3D live load view: one box per requested container, filling in\n      sequence as quantities grow; red dashed ghosts when more are needed \u2500\u2500 *\/\nlet c3dRy=-32;\nfunction render3D(f){\n  const el=$(\"#c3d\"); if(!el) return;\n  const L=T[lang], n=Math.max(1,contCount), per=f.per, used=f.used;\n  const shown=Math.min(n,6), extra=Math.max(0,f.need-n), exShown=Math.min(extra,3);\n  let h=`<p class=\"c3dtitle\">${L.c3dTitle}<\/p><div class=\"c3dtrack\" id=\"c3dtrack\" style=\"--ry:${c3dRy}deg\">`;\n  for(let i=0;i<shown;i++){\n    const fill=Math.max(0,Math.min(100, per>0?(used-i*per)\/per*100:0));\n    h+=`<div class=\"c3du\"><div class=\"c3dbox ${f.overWeight?\"c3dw\":\"\"}\">\n      <div class=\"c3df cf\"><div class=\"lvl\" style=\"height:${fill}%\"><\/div><\/div>\n      <div class=\"c3df cs\"><div class=\"lvl\" style=\"height:${fill}%\"><\/div><\/div>\n      <div class=\"c3df ct ${fill>=99.9?\"full\":\"\"}\"><\/div>\n    <\/div><span class=\"c3dlab\">${esc(f.c.name)} #${i+1} \u00b7 ${fmt(fill,0)}%<\/span><\/div>`;\n  }\n  if(n>shown) h+=`<span class=\"c3dmore\">+${fmt(n-shown)}<\/span>`;\n  for(let i=0;i<exShown;i++){\n    h+=`<div class=\"c3du\"><div class=\"c3dbox c3dx\">\n      <div class=\"c3df cf\"><\/div><div class=\"c3df cs\"><\/div><div class=\"c3df ct\"><\/div>\n    <\/div><span class=\"c3dlab miss\">+1 ${L.c3dExtra}<\/span><\/div>`;\n  }\n  if(extra>exShown) h+=`<span class=\"c3dmore miss\">+${fmt(extra-exShown)}<\/span>`;\n  el.innerHTML=h+`<\/div>`;\n}\n(function(){\n  const el=$(\"#c3d\"); if(!el) return; let dn=null;\n  el.addEventListener(\"pointerdown\",e=>{ dn={x:e.clientX,ry:c3dRy}; try{el.setPointerCapture(e.pointerId);}catch(_){}});\n  el.addEventListener(\"pointermove\",e=>{ if(!dn) return;\n    c3dRy=Math.max(-75,Math.min(15, dn.ry+(e.clientX-dn.x)*0.4));\n    const tr=$(\"#c3dtrack\"); if(tr) tr.style.setProperty(\"--ry\",c3dRy+\"deg\"); });\n  window.addEventListener(\"pointerup\",()=>{ dn=null; });\n})();\n\/* \u2500\u2500 left-column sections: minimize and drag-to-reorder, remembered locally \u2500\u2500 *\/\nconst SEC_IDS=[\"side\",\"msgside\",\"rail\",\"catadmin\"];\nconst SEC_LBL={side:\"#contlbl\",msgside:\"#msglbl\",rail:\"#rail-title\",catadmin:\"#catadmin-lb\"};\nconst SEC_KEY=\"clm-desk-leftcol\";\nlet secState={order:[],min:{}}, secDragEl=null;\nfunction secSave(){ try{ localStorage.setItem(SEC_KEY,JSON.stringify(secState)); }catch(e){} }\nfunction syncSecbars(){\n  SEC_IDS.forEach(id=>{\n    const el=document.getElementById(id); if(!el) return;\n    const t=el.querySelector(\".sectitle\"), l=document.querySelector(SEC_LBL[id]);\n    if(t&&l) t.textContent=l.textContent;\n  });\n}\nfunction initLeftcol(){\n  const col=$(\"#leftcol\"); if(!col) return;\n  try{ secState=Object.assign(secState,JSON.parse(localStorage.getItem(SEC_KEY)||\"{}\")); }catch(e){}\n  (secState.order||[]).forEach(id=>{ if(SEC_IDS.includes(id)){ const el=document.getElementById(id); if(el) col.appendChild(el); }});\n  SEC_IDS.forEach(id=>{\n    const el=document.getElementById(id); if(!el) return;\n    const bar=document.createElement(\"div\"); bar.className=\"secbar noprint\";\n    bar.innerHTML=`<span class=\"secgrip\" title=\"\u21c5\">\u283f<\/span><span class=\"sectitle\"><\/span><button class=\"secfold\" type=\"button\" aria-label=\"Minimize\">\u25be<\/button>`;\n    el.prepend(bar);\n    if(secState.min[id]) el.classList.add(\"secmin-on\");\n    bar.querySelector(\".secfold\").addEventListener(\"click\",()=>{\n      el.classList.toggle(\"secmin-on\");\n      secState.min[id]=el.classList.contains(\"secmin-on\");\n      secSave(); syncSecbars();\n    });\n    bar.querySelector(\".secgrip\").addEventListener(\"mousedown\",()=>el.setAttribute(\"draggable\",\"true\"));\n    el.addEventListener(\"dragstart\",e=>{\n      if(el.getAttribute(\"draggable\")!==\"true\"){ e.preventDefault(); return; }\n      secDragEl=el; el.classList.add(\"secdrag\");\n      e.dataTransfer.effectAllowed=\"move\";\n      try{ e.dataTransfer.setData(\"text\/plain\",id); }catch(_){}\n    });\n    el.addEventListener(\"dragend\",()=>{\n      el.classList.remove(\"secdrag\"); el.removeAttribute(\"draggable\"); secDragEl=null;\n      secState.order=[...col.children].map(c=>c.id).filter(Boolean); secSave();\n    });\n  });\n  window.addEventListener(\"mouseup\",()=>{ SEC_IDS.forEach(id=>{ const el=document.getElementById(id); if(el&&!secDragEl) el.removeAttribute(\"draggable\"); }); });\n  col.addEventListener(\"dragover\",e=>{\n    if(!secDragEl) return; e.preventDefault(); e.dataTransfer.dropEffect=\"move\";\n    const after=[...col.children].filter(c=>c!==secDragEl).find(c=>{\n      const r=c.getBoundingClientRect(); return e.clientY < r.top+r.height\/2; });\n    if(after) col.insertBefore(secDragEl,after); else col.appendChild(secDragEl);\n  });\n  col.addEventListener(\"drop\",e=>e.preventDefault());\n  syncSecbars();\n}\ninitLeftcol();\nfunction renderFit(f){\n  const t=T[lang], el=$(\"#fitmsg\");\n  const unit = palletised ? t.palletsShort : \"m\u00b3\";\n  el.className=\"fitmsg \"+f.state;\n  let msg;\n  if(f.state===\"idle\") msg = t.fitIdle;\n  else if(f.state===\"over\"){\n    const short=f.used-f.cap;\n    msg = t.fitOver.replace(\"{need}\",`<b>${fmt(f.need)} \u00d7 ${f.c.name}<\/b>`)\n                   .replace(\"{over}\",`<b>${fmt(short, palletised?0:2)} ${unit}<\/b>`);\n  } else if(f.state===\"full\") msg = t.fitFull.replace(\"{pct}\",`<b>${fmt(f.pct,0)}%<\/b>`);\n  else if(f.state===\"near\")   msg = t.fitNear.replace(\"{pct}\",`<b>${fmt(f.pct,0)}%<\/b>`)\n                   .replace(\"{room}\",`<b>${fmt(f.cap-f.used, palletised?0:2)} ${unit}<\/b>`);\n  else msg = t.fitLight.replace(\"{pct}\",`<b>${fmt(f.pct,0)}%<\/b>`)\n                   .replace(\"{room}\",`<b>${fmt(f.cap-f.used, palletised?0:2)} ${unit}<\/b>`);\n  if(f.overWeight) msg += \" \" + t.fitWeight.replace(\"{kg}\",`<b>${fmt(f.c.payload*Math.max(1,contCount)\/1000,1)} t<\/b>`);\n  el.innerHTML = `<span class=\"dot2\"><\/span><span>${msg}<\/span>`;\n}\nfunction renderPalletUI(){\n  const t=T[lang];\n  $(\"#lm-floor\").textContent=t.floorLoaded;\n  $(\"#lm-pal\").textContent=t.palletised;\n  $(\"#lm-floor\").setAttribute(\"aria-pressed\",!palletised);\n  $(\"#lm-pal\").setAttribute(\"aria-pressed\",palletised);\n  $(\"#palbox\").hidden=!palletised;\n  $(\"#palbtn\").textContent=t.palSettings;\n  $(\"#l-paltype\").textContent=t.palSize;\n  $(\"#l-palkg\").textContent=t.palWeight;\n  $(\"#pal-note\").textContent=t.palNote;\n  const sel=$(\"#pal-type\");\n  if(sel.options.length!==Object.keys(PALLET_TYPES).length){\n    sel.innerHTML=Object.keys(PALLET_TYPES).map(k=>`<option value=\"${k}\">${PALLET_TYPES[k]}<\/option>`).join(\"\");\n  }\n  sel.value=palletType;\n  $(\"#pal-slots\").innerHTML=CONTAINERS.map(c=>`<span>${c.name} <b>${c.slots[palletType]}<\/b><\/span>`).join(\"\");\n  const cs=$(\"#cont-type\");\n  if(cs.options.length!==CONTAINERS.length)\n    cs.innerHTML=CONTAINERS.map(c=>`<option value=\"${c.key}\">${c.name}<\/option>`).join(\"\");\n  cs.value=contType;\n  $(\"#cont-n\").value=contCount;\n  $(\"#l-conttype\").textContent=t.shipIn;\n  $(\"#l-contn\").textContent=t.howMany;\n  $(\"#l-skucap\").textContent=t.skuCapL;\n  $(\"#sku-cap option[value='0']\").textContent=t.skuNoLimit;\n  $(\"#btn-continfo\").textContent=t.whatMean;\n}\nfunction showContainerInfo(){\n  const t=T[lang];\n  $(\"#info-title\").textContent=t.infoTitle;\n  $(\"#info-body\").innerHTML = `<p>${t.infoIntro}<\/p>\n    <table class=\"ctable\"><tr><th>${t.infoCont}<\/th><th>${t.infoInner}<\/th>\n      <th class=\"n\">${t.infoVol}<\/th><th class=\"n\">${t.infoPal100}<\/th>\n      <th class=\"n\">${t.infoPalEuro}<\/th><th class=\"n\">${t.infoPayload}<\/th><\/tr>\n      ${CONTAINERS.map(c=>`<tr><td><b>${c.name}<\/b><\/td><td>${c.inner}<\/td>\n        <td class=\"n\">${fmt(c.cbm,1)} m\u00b3<\/td><td class=\"n\">${c.slots.std}<\/td>\n        <td class=\"n\">${c.slots.euro}<\/td><td class=\"n\">${fmt(c.payload\/1000,1)} t<\/td><\/tr>`).join(\"\")}\n    <\/table>\n    <p style=\"margin-top:14px\">${t.infoFloor}<\/p>\n    <p>${t.infoPallet}<\/p>\n    <p style=\"color:var(--ink-3);font-size:12.5px\">${t.infoCaveat}<\/p>`;\n  $(\"#infosheet\").classList.add(\"on\"); document.body.style.overflow=\"hidden\";\n}\nfunction setLoading(pal){\n  palletised=pal;\n  renderPalletUI(); renderBody(); renderStats();\n}\n\nfunction syncScrollbars(){\n  const tw=$(\"#tablewrap\"), st=$(\"#scrolltop\"), sp=$(\"#scrollspacer\");\n  if(!tw||!st) return;\n  sp.style.width = tw.scrollWidth + \"px\";\n  st.hidden = tw.scrollWidth <= tw.clientWidth + 4;\n}\nfunction renderAll(){ renderHead(); renderBody(); renderStats(); renderPalletUI(); requestAnimationFrame(syncScrollbars); }\n\nfunction renderSync(){\n  const el=$(\"#sync\"), t=T[lang];\n  el.className=\"sync\"+(sharedState===\"live\"?\" live\":sharedState===\"builtin\"?\" builtin\":\"\");\n  el.textContent = sharedState===\"live\" ? (t.syncLive+(sharedDate?\" \u00b7 \"+sharedDate:\"\"))\n                 : sharedState===\"builtin\" ? t.syncBuiltin : t.syncLoading;\n  el.title = sharedState===\"live\" ? t.syncLiveTip : sharedState===\"builtin\" ? t.syncBuiltinTip : \"\";\n}\n\nfunction applyLang(){\n  const t=T[lang];\n  document.documentElement.lang = lang;\n  $(\"#masthead-sub\").textContent=t.sub;\n  $(\"#q\").placeholder=t.search; if(document.body.classList.contains(\"mwiz\")) setMStep(mstep,true);\n  $(\"#colbtn\").textContent=t.columns;\n  $(\"#colhd\").textContent=t.colhd;\n  $(\"#lbl-pack\").textContent=t.pack; $(\"#lbl-wt\").textContent=t.wt;\n  $(\"#lbl-comp\").textContent=t.comp; $(\"#lbl-unit\").textContent=t.unit; $(\"#lbl-calc\").textContent=t.calc;\n  $(\"#btn-reset\").textContent=t.reset; $(\"#btn-csv\").textContent=t.csv; $(\"#btn-print\").textContent=t.print; $(\"#btn-quote\").textContent=t.qtBtn;\n  $(\"#btn-master\").textContent=t.master; renderMastbar(); renderBell();\n  $(\"#qtyctl-lb\").textContent=t.qtyBox;\n  if(me.role) applyRole();\n  $(\"#msgtext\").placeholder=t.msgPlaceholder; $(\"#msgsend\").textContent=t.msgSend;\n  if(!msgOpenRef) renderThreads();\n  $(\"#contlbl\").textContent=t.contlbl2;\n  $(\"#btn-signout\").textContent=t.signOut;\n  $(\"#info-x\").textContent=t.close;\n  $(\"#noteshd\").textContent=t.noteshd;\n  renderSync();\n  $(\"#btn-add\").textContent=t.add;\n  $(\"#btn-customers\").textContent=t.regCustomers;\n  $(\"#btn-users\").textContent=t.regUsers;\n  $(\"#g-sub\").textContent=t.sub; $(\"#g-title\").textContent=t.gTitle; $(\"#g-text\").textContent=t.gText;\n  $(\"#g-go\").textContent=t.gGo;\n  $(\"#g-en\").setAttribute(\"aria-pressed\",lang===\"en\"); $(\"#g-tr\").setAttribute(\"aria-pressed\",lang===\"tr\");\n  $(\"#who\").innerHTML = me.name ? `${esc(me.name)} <span class=\"role\">${esc((T[lang].roles||{})[me.role]||me.role||\"\")}<\/span>` : \"\";\n  $(\"#reg-x\").textContent=t.close; $(\"#reg-new\").textContent=t.regNew;\n  $(\"#reg-save\").textContent=t.save2; $(\"#reg-back\").textContent=t.regBack||t.close;\n  $(\"#rf-l-rep\").textContent=t.reg.rep; $(\"#rf-l-mail\").textContent=t.reg.repMail;\n  $(\"#rf-l-disc\").textContent=t.reg.discount;\n  $(\"#rf-l-role\").textContent=t.reg.role; $(\"#rf-l-active\").textContent=t.activeLabel;\n  $(\"#rf-l-max\").textContent=t.reg.maxDisc; $(\"#past-x\").textContent=t.close;\n  $(\"#btn-rail\").innerHTML=`${t.myCustomers} <span class=\"n\">${railCusts.length}<\/span>`;\n  $(\"#rf-codelbl\").textContent=t.reg.code;\n  $(\"#reg-title\").textContent = regMode===\"customers\"?t.regCustomers:t.regUsers;\n  if(regRows.length) renderRegistry();\n  $(\"#sheet-save\").textContent=t.save; $(\"#sheet-cancel\").textContent=t.cancel;\n  $(\"#sheet-x\").textContent=t.close; $(\"#sheet-del\").textContent=t.remove;\n  if($(\"#sheet\").classList.contains(\"on\")) openSheet(editing);\n  renderCode();\n  $(\"#noteslist\").innerHTML=t.notes.map(n=>`<li>${n}<\/li>`).join(\"\");\n  $(\"#lang-en\").setAttribute(\"aria-pressed\", lang===\"en\");\n  $(\"#lang-tr\").setAttribute(\"aria-pressed\", lang===\"tr\");\n  $(\"#printsub\").textContent=`${t.printsub} ${new Date().toLocaleDateString(lang===\"tr\"?\"tr-TR\":\"en-GB\")} \u00b7 ${t.loading}: ${palletised?t.palletised:t.floorLoaded} \u00b7 USD\u2192EUR ${rate.toFixed(4)}`;\n  updateFxLabel();\n  renderChips(); renderAll();\n}\n\nfunction updateFxLabel(){\n  const box=$(\"#fxbox\"), t=T[lang];\n  box.classList.toggle(\"live\",rateSource===\"live\");\n  box.classList.toggle(\"fallback\",rateSource!==\"live\");\n  $(\"#fxsrc\").textContent = rateSource===\"live\" ? `${t.live} ${rateDate}`\n                          : rateSource===\"manual\" ? t.manual : t.fallback;\n}\n\n\/* ---- events ---- *\/\n$(\"#q\").addEventListener(\"input\",e=>{query=e.target.value;renderBody();});\n$(\"#chips\").addEventListener(\"click\",e=>{\n  const b=e.target.closest(\".chip\"); if(!b)return;\n  filter=b.dataset.f; renderChips(); renderBody();\n});\n$(\"#btn-master\").addEventListener(\"click\",()=>setMaster(!master));\n$(\"#gridphoto\").addEventListener(\"change\",onGridPhoto);\n$(\"#tbody\").addEventListener(\"click\",e=>{\n  const pb=e.target.closest(\".photoedit\");\n  if(pb){ e.preventDefault(); pickGridPhoto(pb.dataset.photo); }\n});\nfunction flashGrid(msg){\n  const bar=$(\"#mastbar\");\n  if(bar.hidden) return;\n  const old=bar.innerHTML;\n  bar.innerHTML=`<b>${esc(msg)}<\/b>`;\n  setTimeout(()=>{ renderMastbar(); },2600);\n}\n$(\"#btn-bell\").addEventListener(\"click\",e=>{ e.stopPropagation(); openBell(); });\n[\"images\",\"catalogue\",\"pricePdf\",\"priceXlsx\"].forEach(kind=>{\n  $(\"#docfile-\"+kind).addEventListener(\"change\",e=>{\n    const f=e.target.files&&e.target.files[0];\n    e.target.value=\"\";                    \/\/ so the same file can be picked again\n    uploadDoc(kind,f);\n  });\n});\n$(\"#catadmin-save\").addEventListener(\"click\",async()=>{\n  const t=T[lang];\n  try{\n    const r=await api({action:\"saveSettings\", admin:me.code, settings:{\n      catalogueUrl:$(\"#caturl\").value.trim(), cataloguePagesUrl:$(\"#catpages\").value.trim()}});\n    if(r && (r.error===\"admin_only\"||r.error===\"not_allowed\")){ catMsg(t.catAdminOnly,\"bad\"); return; }\n    if(!r||!r.ok) throw 0;\n    settings=r.settings||settings; renderCatAdmin(); catMsg(t.catSaved,\"good\");\n  }catch(e){ catMsg(t.catFailed,\"bad\"); }\n});\n$(\"#msgbody\").addEventListener(\"click\",e=>{\n  const row=e.target.closest(\".threadrow\");\n  if(row) openThread(row.dataset.ref);\n});\n$(\"#msg-back\").addEventListener(\"click\",()=>{ renderThreads(); loadThreads(); });\n$(\"#msgfold\").addEventListener(\"click\",()=>setMsgFold(!document.getElementById(\"msgside\").classList.contains(\"folded\"),true));\n$(\"#msgsend\").addEventListener(\"click\",sendMessage);\n$(\"#msgtext\").addEventListener(\"keydown\",e=>{\n  if(e.key===\"Enter\" && (e.metaKey||e.ctrlKey)) sendMessage();\n});\n$(\"#bellpanel\").addEventListener(\"click\",e=>{\n  e.stopPropagation();\n  const c=e.target.closest(\".actcard\");\n  if(c) return openActivity(c.dataset.ev, c.dataset.ref, c.dataset.detail);\n});\n$(\"#bell-clear\").addEventListener(\"click\",e=>{\n  e.stopPropagation();\n  if(feedItems.length) feedSeen=String(feedItems[0].when);\n  saveSeen(); renderBell();\n});\ndocument.addEventListener(\"click\",()=>openBell(false));\ndocument.addEventListener(\"keydown\",e=>{ if(e.key===\"Escape\") openBell(false); });\n$(\"#tbody\").addEventListener(\"change\",e=>{\n  const el=e.target.closest(\".gedit\"); if(!el) return;\n  const id=el.dataset.id, k=el.dataset.k;\n  const d=DATA.find(x=>String(x.id)===String(id)); if(!d) return;\n  if(k===\"idx\"){\n    const res=renumber(id, el.value);\n    if(!res.ok){ el.value=id; if(res.why) flashGrid(res.why); return; }\n    renderBody(); renderStats(); renderMastbar(); renderCode();\n    return;\n  }\n  if(k===\"pub\")            d.pub = el.value===\"1\";\n  else if(el.type===\"number\"){ const v=parseFloat(el.value); d[k]= isNaN(v)?0:v; typedIn.add(id+\":\"+k); }\n  else                     d[k] = el.value;\n  const also=gridDerive(d,k);\n  recordEdit(id); recomputeFlags();\n  \/\/ repaint only the cells that actually changed, so focus and typing survive\n  const tr=el.closest(\"tr\");\n  [k===\"pub\"?\"pub\":null].concat(also).filter(Boolean).forEach(key=>{\n    const i=COLS.findIndex(c=>c.k===key);\n    if(i>=0 && tr.children[i] && !tr.children[i].contains(document.activeElement))\n      tr.children[i].innerHTML=cell(d,key);\n  });\n  tr.classList.toggle(\"internal\",!d.pub);\n  also.concat([k]).forEach(key=>{\n    const i=COLS.findIndex(c=>c.k===key); if(i>=0&&tr.children[i]) tr.children[i].classList.add(\"dirty\");\n  });\n  renderStats(); renderMastbar(); renderCode();\n});\n$(\"#tbody\").addEventListener(\"change\",e=>{\n  if(!e.target.closest(\".qty\") || master) return;\n  setTimeout(()=>{\n    const ae=document.activeElement;\n    if(ae && ae.closest && ae.closest(\"#tbody\") && ae.classList && ae.classList.contains(\"qty\")) return;\n    renderBody();\n  },80);\n});\n$(\"#tbody\").addEventListener(\"click\",e=>{\n  const b=e.target.closest(\".qstep\"); if(!b) return;\n  const wrap=b.closest(\".qtywrap\"), inp=wrap&&wrap.querySelector(\".qty\"); if(!inp) return;\n  const v=Math.max(0,(Math.floor(+inp.value)||0)+(b.classList.contains(\"qplus\")?1:-1));\n  inp.value=v||\"\";\n  inp.dispatchEvent(new Event(\"input\",{bubbles:true}));\n});\n$(\"#tbody\").addEventListener(\"input\",e=>{\n  const i=e.target.closest(\".qty\"); if(!i)return;\n  const id=+i.dataset.id;\n  const v=Math.max(0,Math.floor(+i.value||0));\n  qty[id]=v;\n  const tr=i.closest(\"tr\");\n  tr.classList.toggle(\"has-qty\",v>0);\n  const d=DATA.find(x=>x.id===id);\n  [\"units\",\"pallets\",\"tcbm\",\"tnet\",\"tgross\",\"tusd\",\"teur\"].forEach(k=>{\n    const idx=COLS.findIndex(c=>c.k===k);\n    if(idx>=0) tr.children[idx].innerHTML=cell(d,k);\n  });\n  renderStats();\n});\n$(\"#tbody\").addEventListener(\"click\",e=>{\n  const img=e.target.closest(\".thumb\"); if(!img)return;\n  $(\"#lbimg\").src=img.dataset.full; $(\"#lb\").classList.add(\"on\");\n});\n$(\"#lb\").addEventListener(\"click\",()=>$(\"#lb\").classList.remove(\"on\"));\ndocument.addEventListener(\"keydown\",e=>{\n  if(e.key!==\"Escape\")return;\n  $(\"#lb\").classList.remove(\"on\");\n  if($(\"#sheet\").classList.contains(\"on\")) closeSheet();\n  if($(\"#regsheet\").classList.contains(\"on\")) closeRegistry();\n  if($(\"#pastsheet\").classList.contains(\"on\")){ $(\"#pastsheet\").classList.remove(\"on\"); document.body.style.overflow=\"\"; }\n});\n\n$(\"#btn-signout\").addEventListener(\"click\",()=>{\n  try{ sessionStorage.removeItem(\"claimont-staff\"); }catch(e){}\n  document.body.classList.remove(\"mwiz\"); wizOn=null; const mwv=$(\"#mwnav\"); if(mwv) mwv.hidden=true;\n  location.reload();\n});\n$(\"#lang-en\").addEventListener(\"click\",()=>{lang=\"en\";applyLang();});\n$(\"#lang-tr\").addEventListener(\"click\",()=>{lang=\"tr\";applyLang();});\n\n(function(){\n  const tw=$(\"#tablewrap\"), st=$(\"#scrolltop\");\n  let lock=false;\n  tw.addEventListener(\"scroll\",()=>{ if(lock)return; lock=true; st.scrollLeft=tw.scrollLeft; lock=false; });\n  st.addEventListener(\"scroll\",()=>{ if(lock)return; lock=true; tw.scrollLeft=st.scrollLeft; lock=false; });\n  window.addEventListener(\"resize\",syncScrollbars);\n})();\n$(\"#cont-type\").addEventListener(\"change\",e=>{ contType=e.target.value; renderStats(); });\n$(\"#cont-n\").addEventListener(\"input\",e=>{ contCount=Math.max(1,Math.floor(+e.target.value||1)); renderStats(); });\n$(\"#sku-cap\").value=String(deskMoq||0);\n$(\"#sku-cap\").addEventListener(\"change\",e=>{\n  deskMoq=Math.max(0,+e.target.value||0);\n  try{ localStorage.setItem(\"clm-desk-moq\",String(deskMoq)); }catch(err){}\n  renderStats();\n});\n$(\"#btn-continfo\").addEventListener(\"click\",showContainerInfo);\n$(\"#info-x\").addEventListener(\"click\",()=>{ $(\"#infosheet\").classList.remove(\"on\"); document.body.style.overflow=\"\"; });\n$(\"#infosheet\").addEventListener(\"click\",e=>{ if(e.target.id===\"infosheet\"){ $(\"#infosheet\").classList.remove(\"on\"); document.body.style.overflow=\"\"; }});\n$(\"#lm-floor\").addEventListener(\"click\",()=>setLoading(false));\n$(\"#lm-pal\").addEventListener(\"click\",()=>setLoading(true));\n$(\"#pal-type\").addEventListener(\"change\",e=>{ palletType=e.target.value; renderPalletUI(); renderStats(); });\n$(\"#pal-kg\").addEventListener(\"input\",e=>{ const v=parseFloat(e.target.value); palletKg=isNaN(v)?0:Math.max(0,v); renderBody(); renderStats(); });\n$(\"#btn-reset\").addEventListener(\"click\",()=>{\n  Object.keys(qty).forEach(k=>delete qty[k]);\n  query=\"\"; $(\"#q\").value=\"\"; filter=\"all\";\n  renderChips(); renderAll();\n});\n\n[[\"cg-pack\",\"hide-pack\"],[\"cg-wt\",\"hide-wt\"],[\"cg-comp\",\"hide-comp\"],[\"cg-unit\",\"hide-unit\"],[\"cg-calc\",\"hide-calc\"]]\n.forEach(([id,cls])=>{\n  $(\"#\"+id).addEventListener(\"change\",e=>{\n    $(\"#tablewrap\").classList.toggle(cls,!e.target.checked);\n  });\n});\n\n$(\"#fxrate\").addEventListener(\"change\",e=>{\n  const v=parseFloat(e.target.value);\n  if(v>0){ rate=v; rateSource=\"manual\"; updateFxLabel(); renderBody(); renderStats(); }\n});\n\n\/* \u2500\u2500 the customer-order builder: agreed prices per line, printable PDF \u2500\u2500\u2500\u2500\u2500\u2500 *\/\nconst dealPrice={};   \/* agreed UNIT price per product, for this document only *\/\nfunction dpU(d){ return dealPrice[d.id]!=null ? dealPrice[d.id] : d.pu; }\nfunction dp(d){ return dealPrice[d.id]!=null ? dealPrice[d.id]*d.upc : d.pc; }\nfunction quoteRows(){ return DATA.filter(d=>qty[d.id]>0); }\nfunction quoteTotals(){\n  const t={lines:0,cartons:0,units:0,cbm:0,gross:0,usd:0};\n  quoteRows().forEach(d=>{ const c=qty[d.id];\n    t.lines++; t.cartons+=c; t.units+=c*d.upc; t.cbm+=c*d.cbm; t.gross+=c*d.gross; t.usd+=c*dp(d); });\n  return t;\n}\nfunction quoteFoot(){\n  const tt=quoteTotals(), q=quoteRows();\n  const tp=q.reduce((a,x)=>a+linePallets(x,qty[x.id]),0);\n  return `<tr><td colspan=\"4\"><\/td>\n    ${palletised?`<td class=\"n\"><b>${fmt(tp,0)}<\/b><\/td>`:\"\"}\n    <td class=\"n\"><b>${fmt(tt.cartons)}<\/b><\/td><td class=\"n\"><b>${fmt(tt.units)}<\/b><\/td>\n    <td><\/td><td><\/td><td class=\"n\"><b>$${fmt(tt.usd,2)}<\/b><\/td><\/tr>`;\n}\nfunction renderQuoteItems(){\n  const t=T[lang], q=quoteRows();\n  $(\"#qt-table thead\").innerHTML=`<tr><th>${t.cols.ref}<\/th><th>${t.cols.name}<\/th>\n    <th class=\"n\">${t.cols.g}<\/th><th class=\"n\">${t.cols.upc}<\/th>\n    ${palletised?`<th class=\"n\">${t.stats.pallets}<\/th>`:\"\"}\n    <th class=\"n\">${t.cols.qty}<\/th><th class=\"n\">${t.cols.units}<\/th>\n    <th class=\"n\">${t.qtAgreed}<\/th><th class=\"n\">${t.cols.pc}<\/th><th class=\"n\">${t.cols.tusd}<\/th><\/tr>`;\n  $(\"#qt-table tbody\").innerHTML=q.map(d=>`<tr data-id=\"${d.id}\">\n    <td class=\"code\">${esc(d.ref)}<\/td>\n    <td>${esc(lang===\"tr\"?d.brandTr+\" \"+d.nameTr:d.brand+\" \"+d.name)}<\/td>\n    <td class=\"n\">${fmt(d.g)} g<\/td><td class=\"n\">${fmt(d.upc)}<\/td>\n    ${palletised?`<td class=\"n\">${fmt(linePallets(d,qty[d.id]),0)}<\/td>`:\"\"}\n    <td class=\"n\">${fmt(qty[d.id])}<\/td><td class=\"n\">${fmt(qty[d.id]*d.upc)}<\/td>\n    <td class=\"n\"><input class=\"dprice ${dealPrice[d.id]!=null?\"changed\":\"\"}\" data-id=\"${d.id}\"\n      type=\"number\" step=\"0.001\" min=\"0\" value=\"${dpU(d).toFixed(3)}\"><\/td>\n    <td class=\"n qctn\">$${fmt(dp(d),2)}<\/td>\n    <td class=\"n qline\">$${fmt(qty[d.id]*dp(d),2)}<\/td><\/tr>`).join(\"\");\n  $(\"#qt-table tfoot\").innerHTML=quoteFoot();\n}\nfunction openQuote(){\n  const t=T[lang];\n  $(\"#qt-title\").textContent=t.qtTitle;\n  $(\"#qt-l-pick\").textContent=t.reg.customer; $(\"#qt-l-company\").textContent=t.oCompany;\n  $(\"#qt-l-contact\").textContent=t.oContact; $(\"#qt-l-email\").textContent=t.oEmail;\n  $(\"#qt-l-phone\").textContent=t.oPhone; $(\"#qt-l-country\").textContent=t.oCountry;\n  $(\"#qt-l-notes\").textContent=t.qtNotes; $(\"#qt-items-h\").textContent=t.qtItemsH;\n  $(\"#qt-print\").textContent=t.qtPrint; $(\"#qt-hint\").textContent=t.qtHint;\n  $(\"#qt-save\").textContent=t.qtSaveBtn; $(\"#qt-save\").disabled=false;\n  const pick=$(\"#qt-pick\");\n  pick.innerHTML=`<option value=\"\">${t.qtPickNone}<\/option>`+railCusts.map(c=>\n    `<option value=\"${esc(c.ref)}\">${esc(c.name)}<\/option>`).join(\"\");\n  renderQuoteItems();\n  $(\"#quotesheet\").classList.add(\"on\"); document.body.style.overflow=\"hidden\";\n}\n$(\"#qt-pick\").addEventListener(\"change\",()=>{\n  const c=railCusts.find(x=>x.ref===$(\"#qt-pick\").value); if(!c) return;\n  $(\"#qt-company\").value=c.name||\"\"; $(\"#qt-contact\").value=c.rep||\"\";\n  $(\"#qt-email\").value=c.repEmail||\"\"; $(\"#qt-phone\").value=c.contactPhone||\"\";\n  $(\"#qt-country\").value=c.country||\"\";\n});\n$(\"#qt-table\").addEventListener(\"input\",e=>{\n  const i=e.target.closest(\".dprice\"); if(!i) return;\n  const id=+i.dataset.id, v=parseFloat(i.value);\n  const d=DATA.find(x=>x.id===id); if(!d) return;\n  if(isNaN(v)||v<0||Math.abs(v-d.pu)<0.0005){ delete dealPrice[id]; i.classList.remove(\"changed\"); }\n  else { dealPrice[id]=v; i.classList.add(\"changed\"); }\n  const tr=i.closest(\"tr\");\n  tr.querySelector(\".qctn\").textContent=\"$\"+fmt(dp(d),2);\n  tr.querySelector(\".qline\").textContent=\"$\"+fmt(qty[id]*dp(d),2);\n  $(\"#qt-table tfoot\").innerHTML=quoteFoot();\n});\n$(\"#qt-x\").addEventListener(\"click\",()=>{ $(\"#quotesheet\").classList.remove(\"on\"); document.body.style.overflow=\"\"; });\n\/* save the prepared order under the chosen customer \u2014 it lands in the Orders\n   sheet like any portal order, so it shows in both portals from then on *\/\nfunction quotePayload(){\n  const g=id=>($(\"#\"+id).value||\"\").trim();\n  const q=quoteRows(), tt=quoteTotals();\n  const tp=q.reduce((a,d)=>a+linePallets(d,qty[d.id]),0);\n  return {\n    company:g(\"qt-company\"), contact:g(\"qt-contact\"), email:g(\"qt-email\"),\n    phone:g(\"qt-phone\"), country:g(\"qt-country\"), notes:g(\"qt-notes\"),\n    loading: palletised ? `Palletised (${PALLET_TYPES[palletType]}, ${palletKg} kg)` : \"Floor loaded\",\n    lines:tt.lines, cartons:tt.cartons, pallets:+tp.toFixed(palletised?0:2),\n    cbm:+tt.cbm.toFixed(3), grossKg:+tt.gross.toFixed(1),\n    listUSD:+q.reduce((a,d)=>a+qty[d.id]*d.pc,0).toFixed(2), totalUSD:+tt.usd.toFixed(2),\n    items:q.map(d=>({\n      id:d.id, ref:d.ref, name:(lang===\"tr\"?d.brandTr+\" \"+d.nameTr:d.brand+\" \"+d.name),\n      g:d.g, upc:d.upc, cartons:qty[d.id], units:qty[d.id]*d.upc,\n      listCartonUSD:+(+d.pc).toFixed(4),\n      unitUSD:+dpU(d).toFixed(4), cartonUSD:+dp(d).toFixed(4),\n      cbm:+(qty[d.id]*d.cbm).toFixed(3),\n      grossKg:+(qty[d.id]*d.gross).toFixed(1),\n      total:+(qty[d.id]*dp(d)).toFixed(2)\n    }))\n  };\n}\n$(\"#qt-save\").addEventListener(\"click\",async ()=>{\n  const t=T[lang], btn=$(\"#qt-save\"), hint=$(\"#qt-hint\");\n  const ref=$(\"#qt-pick\").value;\n  if(!ref){ hint.textContent=t.qtPickFirst; return; }\n  btn.disabled=true; btn.textContent=t.qtSaving;\n  try{\n    const r=await api({action:\"staffOrder\", admin:me.code, ref:ref, order:quotePayload()});\n    if(!r||!r.ok) throw 0;\n    hint.textContent=t.qtSavedMsg.replace(\"{id}\", r.orderId);\n    btn.textContent=t.qtSaveBtn;\n    \/* the customer's order list in the rail is live-fetched \u2014 refresh it if open *\/\n    if(railOpen[ref]){ railOpen[ref]=false; toggleCustomerOrders(ref); }\n  }catch(e){\n    hint.textContent=t.qtSaveFail; btn.disabled=false; btn.textContent=t.qtSaveBtn;\n  }\n});\n$(\"#quotesheet\").addEventListener(\"click\",e=>{ if(e.target.id===\"quotesheet\"){ $(\"#quotesheet\").classList.remove(\"on\"); document.body.style.overflow=\"\"; }});\n$(\"#btn-quote\").addEventListener(\"click\",openQuote);\n$(\"#qt-print\").addEventListener(\"click\",()=>{\n  const t=T[lang], q=quoteRows(), tt=quoteTotals();\n  const g=id=>($(\"#\"+id).value||\"\").trim();\n  const A=\"#0E5F58\", MUT=\"#54564D\";\n  const fact=(k,v)=>v?`<td style=\"padding:4px 9px;border:0.6pt solid #E1DFD8;vertical-align:top\">\n      <span style=\"display:block;font-size:6pt;letter-spacing:.07em;text-transform:uppercase;color:${MUT}\">${k}<\/span>\n      <b style=\"font-size:8.5pt\">${esc(v)}<\/b><\/td>`:\"\";\n  $(\"#quoteprint\").hidden=false;\n  $(\"#quoteprint\").innerHTML=`\n   <div style=\"font:8.5pt\/1.35 Helvetica,Arial,sans-serif;color:#191A16\">\n    <table style=\"width:100%;border-collapse:collapse;border-bottom:2pt solid ${A};margin-bottom:8px\"><tr>\n      <td><div style=\"font-size:16pt;font-weight:800;color:${A}\">CLAIMONT<\/div>\n        <div style=\"font-size:7pt;letter-spacing:.1em;color:${MUT};text-transform:uppercase\">${t.qtDocSub}<\/div><\/td>\n      <td style=\"text-align:right;font-size:7pt;color:${MUT}\">${esc(me.name)} \u00b7 ${new Date().toISOString().slice(0,10)}<\/td>\n    <\/tr><\/table>\n    <table style=\"width:100%;border-collapse:collapse;margin-bottom:9px\"><tr>\n      ${fact(t.oCompany,g(\"qt-company\"))}${fact(t.oContact,g(\"qt-contact\"))}${fact(t.oEmail,g(\"qt-email\"))}\n      ${fact(t.oPhone,g(\"qt-phone\"))}${fact(t.oCountry,g(\"qt-country\"))}${fact(t.loading,palletised?t.palletised:t.floorLoaded)}\n    <\/tr><\/table>\n    <table style=\"width:100%;border-collapse:collapse\">\n      <thead><tr>${[\"#\",t.cols.ref,\"\",t.cols.name,t.cols.g,t.cols.upc,...(palletised?[t.stats.pallets]:[]),t.cols.qty,t.cols.units,t.qtAgreed,t.cols.pc,t.cols.tusd]\n        .map(h=>`<th style=\"background:${A};color:#fff;font-size:6.4pt;text-transform:uppercase;letter-spacing:.05em;padding:4px 5px;text-align:left\">${h}<\/th>`).join(\"\")}<\/tr><\/thead>\n      <tbody>${q.map((d,i)=>`<tr style=\"page-break-inside:avoid\">\n        <td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1\">${i+1}<\/td>\n        <td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1;font-weight:700\">${esc(d.ref)}<\/td>\n        <td style=\"padding:2px 5px;border-bottom:.5pt solid #E9E7E1\">${d.img?`<img decoding=\"async\" src=\"${d.img}\" style=\"height:26pt;width:auto\">`:\"\"}<\/td>\n        <td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1\"><b>${esc(lang===\"tr\"?d.brandTr:d.brand)}<\/b> ${esc(lang===\"tr\"?d.nameTr:d.name)}<\/td>\n        <td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1;text-align:right\">${fmt(d.g)} g<\/td>\n        <td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1;text-align:right\">${fmt(d.upc)}<\/td>\n        ${palletised?`<td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1;text-align:right\">${fmt(linePallets(d,qty[d.id]),0)}<\/td>`:\"\"}\n        <td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1;text-align:right\">${fmt(qty[d.id])}<\/td>\n        <td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1;text-align:right\">${fmt(qty[d.id]*d.upc)}<\/td>\n        <td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1;text-align:right\">$${fmt(dpU(d),3)}<\/td>\n        <td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1;text-align:right\">$${fmt(dp(d),2)}<\/td>\n        <td style=\"padding:3px 5px;border-bottom:.5pt solid #E9E7E1;text-align:right\"><b>$${fmt(qty[d.id]*dp(d),2)}<\/b><\/td><\/tr>`).join(\"\")}\n      <\/tbody><\/table>\n    <table style=\"width:100%;border-collapse:collapse;border-top:1.4pt solid ${A};margin-top:8px\"><tr>\n      ${[[t.stats.lines,fmt(tt.lines)],[t.stats.cartons,fmt(tt.cartons)],[t.stats.units,fmt(tt.units)],\n         ...(palletised?[[t.stats.pallets,fmt(q.reduce((a,d)=>a+linePallets(d,qty[d.id]),0),0)]]:[]),\n         [t.stats.cbm,fmt(tt.cbm,2)+\" m\u00b3\"],[t.stats.gross,fmt(tt.gross,1)+\" kg\"]]\n        .map(([k,v])=>`<td style=\"padding:5px 8px 0\"><span style=\"display:block;font-size:6pt;letter-spacing:.07em;text-transform:uppercase;color:${MUT}\">${k}<\/span><b>${v}<\/b><\/td>`).join(\"\")}\n      <td style=\"padding:5px 8px 0;text-align:right\"><span style=\"display:block;font-size:6pt;letter-spacing:.07em;text-transform:uppercase;color:${MUT}\">${t.stats.usd}<\/span>\n        <span style=\"font-size:13pt;font-weight:800;color:${A}\">$${fmt(tt.usd,2)}<\/span><\/td>\n    <\/tr><\/table>\n    ${g(\"qt-notes\")?`<div style=\"margin-top:8px;padding:5px 8px;background:#F4F3EF;border-left:3pt solid ${A}\"><b>${t.qtNotes}:<\/b> ${esc(g(\"qt-notes\"))}<\/div>`:\"\"}\n    <div style=\"margin-top:9px;color:#8D8F86;font-size:6.6pt\">${t.qtFoot}<\/div>\n   <\/div>`;\n  document.body.classList.add(\"print-quote\");\n  const done=()=>{ document.body.classList.remove(\"print-quote\"); $(\"#quoteprint\").hidden=true; window.removeEventListener(\"afterprint\",done); };\n  window.addEventListener(\"afterprint\",done);\n  window.print();\n});\n$(\"#btn-print\").addEventListener(\"click\",()=>{\n  const t=T[lang], tt=totals();\n  const sel=tt.lines>0;\n  document.body.classList.remove(\"print-all\",\"print-selected\");\n  document.body.classList.add(sel?\"print-selected\":\"print-all\");\n  $(\"#printtitle\").textContent = sel ? \"CLAIMONT \u2014 \"+t.order2 : \"CLAIMONT \u2014 \"+t.pricelist2;\n  $(\"#printfoot\").innerHTML = sel\n    ? `${t.stats.cartons}: ${fmt(tt.cartons)} \u00b7 ${t.stats.units}: ${fmt(tt.units)} \u00b7 ${palletised?`${t.stats.pallets}: ${fmt(tt.pallets,0)} \u00b7 `:\"\"}${t.stats.cbm}: ${fmt(tt.cbm,2)} m\u00b3 \u00b7 ${t.stats.gross}: ${fmt(tt.gross,1)} kg \u00b7 <strong>${t.stats.usd}: $${fmt(tt.usd,2)} \/ ${t.stats.eur}: \u20ac${fmt(tt.usd*rate,2)}<\/strong>`\n    : `${DATA.length} ${t.productsWord} \u00b7 ${t.notes[0].replace(\/<[^>]+>\/g,\"\")}`;\n  window.print();\n});\n\n$(\"#btn-csv\").addEventListener(\"click\",()=>{\n  \/* the master workbook \u2014 always rebuilt from the live product list, so a\n     product added or republished a minute ago is already in the download *\/\n  saveXlsx(masterXlsx(), \"CLAIMONT PRICE LIST 2026.xlsx\");\n});\nfunction saveXlsx(buf, name){\n  const blob=new Blob([buf],{type:\"application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"});\n  const a=document.createElement(\"a\");\n  a.href=URL.createObjectURL(blob); a.download=name;\n  document.body.appendChild(a); a.click(); a.remove();\n  setTimeout(()=>URL.revokeObjectURL(a.href),2000);\n}\n\n\/* ---- printing: keep only the portal on the page ---------------------------\n   Everything else in the WordPress document (theme header, footer, floating\n   chat button) is hidden by marking each sibling along our ancestor chain. *\/\nfunction markPrintChrome(on){\n  document.querySelectorAll('[data-clhide]').forEach(function(e){ e.removeAttribute('data-clhide'); });\n  if(!on) return;\n  var el = document.getElementById('app') || document.body.firstElementChild;\n  while (el && el.parentElement && el !== document.documentElement){\n    var kids = el.parentElement.children;\n    for (var i=0;i<kids.length;i++) if (kids[i] !== el) kids[i].setAttribute('data-clhide','');\n    el = el.parentElement;\n  }\n}\nwindow.addEventListener('beforeprint', function(){ markPrintChrome(true); });\nwindow.addEventListener('afterprint',  function(){ markPrintChrome(false); });\n\n\/* ---------- a real .xlsx, written by hand ----------------------------------\n   Excel opens a semicolon CSV as one column with a \"possible data loss\"\n   warning, and a CSV cannot carry column widths, number formats or a frozen\n   header. So we emit a genuine workbook instead: a ZIP holding a handful of\n   XML parts. Entries are STOREd rather than deflated, which is perfectly\n   valid and keeps this dependency-free.                                     *\/\nfunction xlsxBuild(opts){\n  var enc = new TextEncoder();\n\n  \/* ---- zip (store only) ---- *\/\n  var CRC = (function(){\n    var t = new Uint32Array(256);\n    for (var n=0;n<256;n++){ var c=n;\n      for (var k=0;k<8;k++) c = c&1 ? 0xEDB88320 ^ (c>>>1) : c>>>1;\n      t[n]=c>>>0; }\n    return t;\n  })();\n  function crc32(b){ var c=0xFFFFFFFF;\n    for (var i=0;i<b.length;i++) c = CRC[(c ^ b[i]) & 0xFF] ^ (c>>>8);\n    return (c ^ 0xFFFFFFFF)>>>0; }\n\n  function zip(files){\n    var parts=[], central=[], offset=0;\n    function u16(v){ return [v&255,(v>>8)&255]; }\n    function u32(v){ return [v&255,(v>>8)&255,(v>>16)&255,(v>>>24)&255]; }\n    files.forEach(function(f){\n      var name = enc.encode(f.name), data = enc.encode(f.data), crc = crc32(data);\n      var local = [].concat([0x50,0x4b,0x03,0x04], u16(20), u16(0), u16(0),\n                            u16(0), u16(0), u32(crc), u32(data.length), u32(data.length),\n                            u16(name.length), u16(0));\n      parts.push(new Uint8Array(local), name, data);\n      central.push([].concat([0x50,0x4b,0x01,0x02], u16(20), u16(20), u16(0), u16(0),\n                             u16(0), u16(0), u32(crc), u32(data.length), u32(data.length),\n                             u16(name.length), u16(0), u16(0), u16(0), u16(0), u32(0),\n                             u32(offset)), name);\n      offset += local.length + name.length + data.length;\n    });\n    var cdir=[], cstart=offset;\n    central.forEach(function(c){\n      if (Array.isArray(c)) { cdir.push(new Uint8Array(c)); offset += c.length; }\n      else { cdir.push(c); offset += c.length; }\n    });\n    var end = new Uint8Array([].concat([0x50,0x4b,0x05,0x06], u16(0), u16(0),\n      u16(files.length), u16(files.length), u32(offset-cstart), u32(cstart), u16(0)));\n    var all = parts.concat(cdir, [end]);\n    var total = all.reduce(function(a,x){return a+x.length;},0);\n    var out = new Uint8Array(total), p=0;\n    all.forEach(function(x){ out.set(x,p); p+=x.length; });\n    return out;\n  }\n\n  \/* ---- helpers ---- *\/\n  function esc(v){ return String(v==null?'':v)\n    .replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;')\n    .replace(\/\"\/g,'&quot;').replace(\/\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\/g,''); }\n  function colName(i){ var s=''; i++; while(i>0){ var m=(i-1)%26; s=String.fromCharCode(65+m)+s; i=(i-m-1)\/26; } return s; }\n\n  var cols = opts.columns, rows = opts.rows;\n\n  \/* style ids, in the order they are written into cellXfs below *\/\n  var S = { text:0, head:1, int:2, dec2:3, dec3:4, usd:5, eur:6, title:7, sub:8, totLbl:9, totVal:10, totUsd:11 };\n\n  function cell(ref, v, style, type){\n    if (v===null || v===undefined || v==='')\n      return '<c r=\"'+ref+'\" s=\"'+style+'\"\/>';\n    if (type==='n')\n      return '<c r=\"'+ref+'\" s=\"'+style+'\"><v>'+v+'<\/v><\/c>';\n    return '<c r=\"'+ref+'\" s=\"'+style+'\" t=\"inlineStr\"><is><t xml:space=\"preserve\">'+esc(v)+'<\/t><\/is><\/c>';\n  }\n\n  var xml=[], r=1;\n  \/* title block *\/\n  xml.push('<row r=\"'+r+'\" ht=\"22\" customHeight=\"1\">'+cell('A'+r,opts.title,S.title)+'<\/row>'); r++;\n  if (opts.subtitle){ xml.push('<row r=\"'+r+'\">'+cell('A'+r,opts.subtitle,S.sub)+'<\/row>'); r++; }\n  r++;                                             \/* one blank row *\/\n  var headRow = r;\n  xml.push('<row r=\"'+r+'\" ht=\"30\" customHeight=\"1\">' +\n    cols.map(function(c,i){ return cell(colName(i)+r, c.title, S.head); }).join('') + '<\/row>');\n  r++;\n  var firstData = r;\n  rows.forEach(function(d){\n    xml.push('<row r=\"'+r+'\">' + cols.map(function(c,i){\n      var v = d[c.key], ref = colName(i)+r;\n      if (c.type && c.type!=='text'){\n        if (v===null||v===undefined||v==='') return cell(ref,null,S[c.type]);\n        return cell(ref, Number(v), S[c.type], 'n');\n      }\n      return cell(ref, v, S.text);\n    }).join('') + '<\/row>');\n    r++;\n  });\n  var lastData = r-1;\n  \/* totals *\/\n  if (opts.totals && opts.totals.length){\n    r++;\n    opts.totals.forEach(function(t){\n      xml.push('<row r=\"'+r+'\">' + cell('A'+r, t.label, S.totLbl) +\n        cell('B'+r, t.value, t.style==='usd'?S.totUsd:S.totVal, typeof t.value==='number'?'n':undefined) +\n        '<\/row>');\n      r++;\n    });\n  }\n\n  var accent = (opts.accent||'0E5F58').replace('#','');\n  var sheet =\n    '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>' +\n    '<worksheet xmlns=\"http:\/\/schemas.openxmlformats.org\/spreadsheetml\/2006\/main\">' +\n    '<sheetPr><outlinePr\/><\/sheetPr>' +\n    '<sheetViews><sheetView workbookViewId=\"0\" showGridLines=\"0\">' +\n      '<pane ySplit=\"'+headRow+'\" topLeftCell=\"A'+(headRow+1)+'\" activePane=\"bottomLeft\" state=\"frozen\"\/>' +\n    '<\/sheetView><\/sheetViews>' +\n    '<sheetFormatPr defaultRowHeight=\"15\"\/>' +\n    '<cols>' + cols.map(function(c,i){\n      return '<col min=\"'+(i+1)+'\" max=\"'+(i+1)+'\" width=\"'+(c.w||12)+'\" customWidth=\"1\"\/>'; }).join('') +\n    '<\/cols>' +\n    '<sheetData>' + xml.join('') + '<\/sheetData>' +\n    (lastData>=firstData\n      ? '<autoFilter ref=\"A'+headRow+':'+colName(cols.length-1)+lastData+'\"\/>' : '') +\n    '<pageMargins left=\"0.3\" right=\"0.3\" top=\"0.4\" bottom=\"0.4\" header=\"0.2\" footer=\"0.2\"\/>' +\n    '<pageSetup orientation=\"landscape\" fitToWidth=\"1\" fitToHeight=\"0\" paperSize=\"9\"\/>' +\n    '<\/worksheet>';\n\n  var styles =\n    '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>' +\n    '<styleSheet xmlns=\"http:\/\/schemas.openxmlformats.org\/spreadsheetml\/2006\/main\">' +\n    '<numFmts count=\"5\">' +\n      '<numFmt numFmtId=\"164\" formatCode=\"#,##0\"\/>' +\n      '<numFmt numFmtId=\"165\" formatCode=\"#,##0.00\"\/>' +\n      '<numFmt numFmtId=\"166\" formatCode=\"#,##0.000\"\/>' +\n      '<numFmt numFmtId=\"167\" formatCode=\"&quot;$&quot;#,##0.00\"\/>' +\n      '<numFmt numFmtId=\"168\" formatCode=\"&quot;\u20ac&quot;#,##0.00\"\/>' +\n    '<\/numFmts>' +\n    '<fonts count=\"5\">' +\n      '<font><sz val=\"10\"\/><name val=\"Calibri\"\/><\/font>' +\n      '<font><b\/><sz val=\"10\"\/><color rgb=\"FFFFFFFF\"\/><name val=\"Calibri\"\/><\/font>' +\n      '<font><b\/><sz val=\"14\"\/><color rgb=\"FF'+accent+'\"\/><name val=\"Calibri\"\/><\/font>' +\n      '<font><sz val=\"9\"\/><color rgb=\"FF7A7A72\"\/><name val=\"Calibri\"\/><\/font>' +\n      '<font><b\/><sz val=\"10\"\/><name val=\"Calibri\"\/><\/font>' +\n    '<\/fonts>' +\n    '<fills count=\"3\">' +\n      '<fill><patternFill patternType=\"none\"\/><\/fill>' +\n      '<fill><patternFill patternType=\"gray125\"\/><\/fill>' +\n      '<fill><patternFill patternType=\"solid\"><fgColor rgb=\"FF'+accent+'\"\/>' +\n        '<bgColor indexed=\"64\"\/><\/patternFill><\/fill>' +\n    '<\/fills>' +\n    '<borders count=\"2\"><border><left\/><right\/><top\/><bottom\/><diagonal\/><\/border>' +\n      '<border><left\/><right\/><top\/><bottom style=\"thin\">' +\n        '<color rgb=\"FFDDDDDD\"\/><\/bottom><diagonal\/><\/border><\/borders>' +\n    '<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"\/><\/cellStyleXfs>' +\n    '<cellXfs count=\"12\">' +\n      '<xf numFmtId=\"0\"   fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyBorder=\"1\"\/>' +                       \/* 0 text  *\/\n      '<xf numFmtId=\"0\"   fontId=\"1\" fillId=\"2\" borderId=\"0\" xfId=\"0\" applyFont=\"1\" applyFill=\"1\" applyAlignment=\"1\">' +\n        '<alignment vertical=\"center\" wrapText=\"1\"\/><\/xf>' +                                                     \/* 1 head  *\/\n      '<xf numFmtId=\"164\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\"\/>' +  \/* 2 int   *\/\n      '<xf numFmtId=\"165\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\"\/>' +  \/* 3 dec2  *\/\n      '<xf numFmtId=\"166\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\"\/>' +  \/* 4 dec3  *\/\n      '<xf numFmtId=\"167\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\"\/>' +  \/* 5 usd   *\/\n      '<xf numFmtId=\"168\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\"\/>' +  \/* 6 eur   *\/\n      '<xf numFmtId=\"0\"   fontId=\"2\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\"\/>' +                          \/* 7 title *\/\n      '<xf numFmtId=\"0\"   fontId=\"3\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\"\/>' +                          \/* 8 sub   *\/\n      '<xf numFmtId=\"0\"   fontId=\"4\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\"\/>' +                          \/* 9 totLbl*\/\n      '<xf numFmtId=\"165\" fontId=\"4\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\" applyNumberFormat=\"1\"\/>' +    \/*10 totVal*\/\n      '<xf numFmtId=\"167\" fontId=\"2\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\" applyNumberFormat=\"1\"\/>' +    \/*11 totUsd*\/\n    '<\/cellXfs>' +\n    '<cellStyles count=\"1\"><cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\"\/><\/cellStyles>' +\n    '<\/styleSheet>';\n\n  var files = [\n    { name:'[Content_Types].xml', data:\n      '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>' +\n      '<Types xmlns=\"http:\/\/schemas.openxmlformats.org\/package\/2006\/content-types\">' +\n      '<Default Extension=\"rels\" ContentType=\"application\/vnd.openxmlformats-package.relationships+xml\"\/>' +\n      '<Default Extension=\"xml\" ContentType=\"application\/xml\"\/>' +\n      '<Override PartName=\"\/xl\/workbook.xml\" ContentType=\"application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"\/>' +\n      '<Override PartName=\"\/xl\/worksheets\/sheet1.xml\" ContentType=\"application\/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"\/>' +\n      '<Override PartName=\"\/xl\/styles.xml\" ContentType=\"application\/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\"\/>' +\n      '<\/Types>' },\n    { name:'_rels\/.rels', data:\n      '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>' +\n      '<Relationships xmlns=\"http:\/\/schemas.openxmlformats.org\/package\/2006\/relationships\">' +\n      '<Relationship Id=\"rId1\" Type=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\/officeDocument\" Target=\"xl\/workbook.xml\"\/>' +\n      '<\/Relationships>' },\n    { name:'xl\/workbook.xml', data:\n      '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>' +\n      '<workbook xmlns=\"http:\/\/schemas.openxmlformats.org\/spreadsheetml\/2006\/main\" ' +\n      'xmlns:r=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\">' +\n      '<sheets><sheet name=\"'+esc((opts.sheet||'Sheet1').slice(0,31))+'\" sheetId=\"1\" r:id=\"rId1\"\/><\/sheets>' +\n      '<\/workbook>' },\n    { name:'xl\/_rels\/workbook.xml.rels', data:\n      '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>' +\n      '<Relationships xmlns=\"http:\/\/schemas.openxmlformats.org\/package\/2006\/relationships\">' +\n      '<Relationship Id=\"rId1\" Type=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\/worksheet\" Target=\"worksheets\/sheet1.xml\"\/>' +\n      '<Relationship Id=\"rId2\" Type=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\/styles\" Target=\"styles.xml\"\/>' +\n      '<\/Relationships>' },\n    { name:'xl\/styles.xml', data: styles },\n    { name:'xl\/worksheets\/sheet1.xml', data: sheet }\n  ];\n  return zip(files);\n}\n\n\n\/* \u2550\u2550\u2550 the master price-list workbook \u2014 same layout as the office file:\n       planner on top, live formulas, photos, one row per product. Built\n       from DATA at click time, so it always carries the latest products. \u2550\u2550\u2550 *\/\nfunction masterXlsx(){\n  const enc=new TextEncoder();\n  const CRC=(()=>{const t=new Uint32Array(256);\n    for(let n=0;n<256;n++){let c=n;for(let k=0;k<8;k++)c=c&1?0xEDB88320^(c>>>1):c>>>1;t[n]=c>>>0;}return t;})();\n  const crc32=b=>{let c=0xFFFFFFFF;for(let i=0;i<b.length;i++)c=CRC[(c^b[i])&0xFF]^(c>>>8);return (c^0xFFFFFFFF)>>>0;};\n  function zip(files){\n    const parts=[],central=[];let offset=0;\n    const u16=v=>[v&255,(v>>8)&255], u32=v=>[v&255,(v>>8)&255,(v>>16)&255,(v>>>24)&255];\n    files.forEach(f=>{\n      const name=enc.encode(f.name), data=(f.data instanceof Uint8Array)?f.data:enc.encode(f.data), crc=crc32(data);\n      const local=[].concat([0x50,0x4b,0x03,0x04],u16(20),u16(0),u16(0),u16(0),u16(0),\n        u32(crc),u32(data.length),u32(data.length),u16(name.length),u16(0));\n      parts.push(new Uint8Array(local),name,data);\n      central.push(new Uint8Array([].concat([0x50,0x4b,0x01,0x02],u16(20),u16(20),u16(0),u16(0),u16(0),u16(0),\n        u32(crc),u32(data.length),u32(data.length),u16(name.length),u16(0),u16(0),u16(0),u16(0),u32(0),u32(offset))),name);\n      offset+=local.length+name.length+data.length;\n    });\n    const cstart=offset;let clen=0;\n    central.forEach(c=>clen+=c.length);\n    const end=new Uint8Array([].concat([0x50,0x4b,0x05,0x06],u16(0),u16(0),\n      u16(files.length),u16(files.length),u32(clen),u32(cstart),u16(0)));\n    const all=parts.concat(central,[end]);\n    const out=new Uint8Array(all.reduce((a,x)=>a+x.length,0));let p=0;\n    all.forEach(x=>{out.set(x,p);p+=x.length;});\n    return out;\n  }\n  const X=v=>String(v==null?\"\":v).replace(\/&\/g,\"&amp;\").replace(\/<\/g,\"&lt;\").replace(\/>\/g,\"&gt;\").replace(\/\"\/g,\"&quot;\");\n  const b64u8=uri=>{const b=atob(uri.slice(uri.indexOf(\",\")+1));const u=new Uint8Array(b.length);\n    for(let i=0;i<b.length;i++)u[i]=b.charCodeAt(i);return u;};\n  const CL=i=>{let s=\"\";i++;while(i>0){const m=(i-1)%26;s=String.fromCharCode(65+m)+s;i=(i-m-1)\/26;}return s;};\n\n  \/* styles *\/\n  const ST={txt:0,wrap:1,gen:2,int:3,dec2:4,cbm:5,usd3:6,usd2:7,eur3:8,eur2:9,\n    head:10,title:11,sub:12,band:13,subhd:14,lbl:15,inp:16,val:17,pct:18,sta:19,\n    ghdr:20,gcell:21,note:22,totL:23,totI:24,totD:25,totU:26,totE:27,qty:28,tag:29,rate:30};\n  const c=(ref,v,s,ty)=>{\n    if(v===null||v===undefined||v===\"\")return `<c r=\"${ref}\" s=\"${s}\"\/>`;\n    if(ty===\"n\")return `<c r=\"${ref}\" s=\"${s}\"><v>${v}<\/v><\/c>`;\n    if(ty===\"f\")return `<c r=\"${ref}\" s=\"${s}\"><f>${X(v)}<\/f><\/c>`;\n    return `<c r=\"${ref}\" s=\"${s}\" t=\"inlineStr\"><is><t xml:space=\"preserve\">${X(v)}<\/t><\/is><\/c>`;\n  };\n  const prods=DATA.slice().sort((a,b)=>a.id-b.id);\n  const N=prods.length, R0=15, RT=R0+N;               \/\/ first product row, total row\n  const RATE=\"$AB$3\", TBL=\"$L$7:$R$10\";\n  const JR=`$J$${R0}:$J$${RT-1}`, HR=`$H$${R0}:$H$${RT-1}`;\n\n  const HDRS=[\"NUMBER\",\"Product Ref. No.\",\"PHOTO\",\"DESCRIPTION\",\"SHELFLIFE\",\"GRAMMAGE\",\"UNITS \/ CARTON\",\n   \"CARTON \/ PALLET\",\"QUANTITY UNITS\",\"QUANTITY CARTONS\",\"PALLETS (IF NOT FLOOR LOADED)\",\"L (cm)\",\"W (cm)\",\"H (cm)\",\n   \"CBM (m3)\",\"TOTAL CBM\",\"HS CODE\",\"UNIT BARCODE\",\"CARTON BARCODE\",\"STORAGE TEMPERATURE\",\"LOT NUMBER\",\n   \"PRODUCTION DATE\",\"EXPIRATION DATE\",\"NET WEIGHT KG\",\"CARTON WEIGHT (EMPTY) KG\",\"GROSS WEIGHT KG\",\n   \"TOTAL NET WEIGHT KG\",\"TOTAL GROSS WEIGHT KG\",\"UNIT PRICE EXWORKS (USD)\",\"CARTON PRICE EXWORKS (USD)\",\n   \"TOTAL ORDERED PRICE EXWORKS (USD)\",\"UNIT PRICE EXWORKS (EURO)\",\"CARTON PRICE EXWORKS (EURO)\",\n   \"TOTAL ORDERED PRICE EXWORKS (EURO)\",\"CUSTOMER PORTAL\"];\n  const W=[8,12,9,32,11,10,10,10,11,11,11,8,8,8,9,10,17,15,15,12,10,11,11,10,10,10,11,11,12,12,14,12,12,14,13];\n\n  const rows=[];\n  rows.push(`<row r=\"1\" ht=\"24\" customHeight=\"1\">${c(\"A1\",\"CLAIMONT \u2014 PRODUCT INFORMATION AND PRICE LIST 2026\",ST.title)}<\/row>`);\n  rows.push(`<row r=\"2\">${c(\"A2\",\"Downloaded from the internal portal \u00b7 \"+new Date().toISOString().slice(0,10)+\" \u00b7 \"+N+\" products\",ST.sub)}<\/row>`);\n  rows.push(`<row r=\"3\">${c(\"Z3\",\"USD \u2192 EUR (ECB \"+(typeof rateDate!==\"undefined\"&&rateDate?rateDate:\"fixed\")+\")\",ST.lbl)}${c(\"AB3\",+(+rate).toFixed(4),ST.rate,\"n\")}<\/row>`);\n  \/* planner *\/\n  const bandRow=(r,c0,c1,txt,s)=>{let h=c(c0+r,txt,s);\n    for(let i=CL(0).charCodeAt(0),a=colIdx(c0)+1;a<=colIdx(c1);a++)h+=c(CL(a)+r,null,s);return h;};\n  function colIdx(L){let n=0;for(let i=0;i<L.length;i++)n=n*26+(L.charCodeAt(i)-64);return n-1;}\n  rows.push(`<row r=\"4\" ht=\"26\" customHeight=\"1\">${bandRow(4,\"A\",\"R\",\"SHIPMENT PLANNER\",ST.band)}<\/row>`);\n  rows.push(`<row r=\"5\" ht=\"16\" customHeight=\"1\">${bandRow(5,\"A\",\"D\",\"YOUR SHIPMENT \u2014 type in the highlighted cells\",ST.subhd)}${bandRow(5,\"F\",\"J\",\"LIVE CHECK\",ST.subhd)}${bandRow(5,\"L\",\"R\",\"CONTAINER & TRUCK GUIDE\",ST.subhd)}<\/row>`);\n  const GU=[[\"20' DV\",\"5.90 \u00d7 2.35 \u00d7 2.39\",29,28200,10,11],\n            [\"40' HC\",\"12.03 \u00d7 2.35 \u00d7 2.69\",76.3,28600,21,24],\n            [\"45' HC\",\"13.56 \u00d7 2.35 \u00d7 2.69\",85.6,27600,24,27],\n            [\"Tautliner 13.6 m\",\"13.60 \u00d7 2.50 \u00d7 2.65\",90,24500,26,33]];\n  const g=(r,i)=>c(\"L\"+r,GU[i][0],ST.gcell)+c(\"M\"+r,GU[i][1],ST.gcell)+c(\"N\"+r,GU[i][2],ST.gcell,\"n\")+\n    c(\"O\"+r,`N${r}*0.9`,ST.gcell,\"f\")+c(\"P\"+r,GU[i][3],ST.gcell,\"n\")+c(\"Q\"+r,GU[i][4],ST.gcell,\"n\")+c(\"R\"+r,GU[i][5],ST.gcell,\"n\");\n  rows.push(`<row r=\"6\" ht=\"26\" customHeight=\"1\">${c(\"A6\",\"Ship in\",ST.lbl)}${c(\"B6\",null,ST.lbl)}${c(\"C6\",null,ST.lbl)}${c(\"D6\",\"40' HC\",ST.inp)}${c(\"F6\",\"Capacity used\",ST.lbl)}${c(\"H6\",`TEXT(AK8,\"#,##0.0\")&\" \/ \"&TEXT(AK9,\"#,##0.0\")&IF($D$8=\"Palletised\",\" pallets\",\" m\u00b3\")`,ST.val,\"f\")}${c(\"L6\",\"Vehicle\",ST.ghdr)}${c(\"M6\",\"Inside L\u00d7W\u00d7H (m)\",ST.ghdr)}${c(\"N6\",\"Volume m\u00b3\",ST.ghdr)}${c(\"O6\",\"Usable m\u00b3 *\",ST.ghdr)}${c(\"P6\",\"Payload kg\",ST.ghdr)}${c(\"Q6\",\"Pallet slots 100\u00d7120\",ST.ghdr)}${c(\"R6\",\"Pallet slots 80\u00d7120 (Euro)\",ST.ghdr)}${c(\"AK6\",`IF($D$8=\"Palletised\",IF($D$9=\"80 \u00d7 120 cm (Euro)\",VLOOKUP($D$6,${TBL},7,0),VLOOKUP($D$6,${TBL},6,0)),VLOOKUP($D$6,${TBL},4,0))`,ST.txt,\"f\")}<\/row>`);\n  rows.push(`<row r=\"7\" ht=\"18\" customHeight=\"1\">${c(\"A7\",\"How many\",ST.lbl)}${c(\"B7\",null,ST.lbl)}${c(\"C7\",null,ST.lbl)}${c(\"D7\",1,ST.inp,\"n\")}${c(\"F7\",\"Container fill\",ST.lbl)}${c(\"H7\",\"IF(AK9=0,0,AK8\/AK9)\",ST.pct,\"f\")}${g(7,0)}${c(\"AK7\",`SUMPRODUCT(CEILING(${JR}\/${HR},1))`,ST.txt,\"f\")}<\/row>`);\n  rows.push(`<row r=\"8\" ht=\"18\" customHeight=\"1\">${c(\"A8\",\"Loading\",ST.lbl)}${c(\"B8\",null,ST.lbl)}${c(\"C8\",null,ST.lbl)}${c(\"D8\",\"Floor loaded\",ST.inp)}${c(\"F8\",\"Containers needed\",ST.lbl)}${c(\"H8\",\"IF(AK8=0,0,CEILING(AK8\/AK6,1))\",ST.val,\"f\")}${g(8,1)}${c(\"AK8\",`IF($D$8=\"Palletised\",AK7,P$${RT})`,ST.txt,\"f\")}<\/row>`);\n  rows.push(`<row r=\"9\" ht=\"18\" customHeight=\"1\">${c(\"A9\",\"Pallet type (if palletised)\",ST.lbl)}${c(\"B9\",null,ST.lbl)}${c(\"C9\",null,ST.lbl)}${c(\"D9\",\"100 \u00d7 120 cm\",ST.inp)}${c(\"F9\",\"Volume status\",ST.lbl)}${c(\"H9\",`IF(AK8=0,\"\u2014\",IF(AK8>AK9,\"OVER capacity \u2014 needs \"&H8&\" \u00d7 \"&$D$6,IF(AK8\/AK9>0.85,\"Nearly full \u2014 \"&TEXT(AK8\/AK9,\"0%\")&\" of the space\",\"OK \u2014 fits in \"&MAX(1,$D$7)&\" \u00d7 \"&$D$6)))`,ST.sta,\"f\")}${c(\"I9\",null,ST.sta)}${c(\"J9\",null,ST.sta)}${g(9,2)}${c(\"AK9\",\"AK6*MAX(1,$D$7)\",ST.txt,\"f\")}<\/row>`);\n  rows.push(`<row r=\"10\" ht=\"18\" customHeight=\"1\">${c(\"A10\",\"Empty pallet weight (kg)\",ST.lbl)}${c(\"B10\",null,ST.lbl)}${c(\"C10\",null,ST.lbl)}${c(\"D10\",25,ST.inp,\"n\")}${c(\"F10\",\"Weight\",ST.lbl)}${c(\"H10\",`IF(AK11=0,\"\u2014\",IF(AK11>AK10,\"OVERWEIGHT by \"&TEXT(AK11-AK10,\"#,##0\")&\" kg (limit \"&TEXT(AK10,\"#,##0\")&\" kg)\",TEXT(AK11,\"#,##0\")&\" \/ \"&TEXT(AK10,\"#,##0\")&\" kg \u2014 OK\"))`,ST.sta,\"f\")}${c(\"I10\",null,ST.sta)}${c(\"J10\",null,ST.sta)}${g(10,3)}${c(\"AK10\",`VLOOKUP($D$6,${TBL},5,0)*MAX(1,$D$7)`,ST.txt,\"f\")}<\/row>`);\n  rows.push(`<row r=\"11\" ht=\"18\" customHeight=\"1\">${c(\"A11\",\"Max SKUs per container\",ST.lbl)}${c(\"B11\",null,ST.lbl)}${c(\"C11\",null,ST.lbl)}${c(\"D11\",deskMoq||0,ST.inp,\"n\")}${c(\"E11\",\"0 = no limit\",ST.note)}${c(\"F11\",\"SKU check\",ST.lbl)}${c(\"H11\",`IF($D$11=0,COUNTIF(${JR},\">0\")&\" SKUs (no limit set)\",IF(COUNTIF(${JR},\">0\")>$D$11*MAX(1,$D$7),\"TOO MANY SKUs \u2014 \"&COUNTIF(${JR},\">0\")&\" of max \"&$D$11*MAX(1,$D$7),COUNTIF(${JR},\">0\")&\" of max \"&$D$11*MAX(1,$D$7)&\" SKUs \u2014 OK\"))`,ST.sta,\"f\")}${c(\"I11\",null,ST.sta)}${c(\"J11\",null,ST.sta)}${c(\"L11\",\"* usable volume keeps a ~10% packing allowance in reserve\",ST.note)}${c(\"AK11\",`AB$${RT}+IF($D$8=\"Palletised\",AK7*$D$10,0)`,ST.txt,\"f\")}<\/row>`);\n  rows.push(`<row r=\"12\" ht=\"14\" customHeight=\"1\">${bandRow(12,\"A\",\"R\",\"Real loading never reaches the paper volume \u2014 the final load is always confirmed at loading. Palletised mode rounds every product up to whole pallets and adds the empty-pallet weight.\",ST.note)}<\/row>`);\n  \/* table header *\/\n  rows.push(`<row r=\"14\" ht=\"46\" customHeight=\"1\">${HDRS.map((h,i)=>c(CL(i)+\"14\",h,ST.head)).join(\"\")}<\/row>`);\n  \/* products *\/\n  const imgs=[];\n  prods.forEach((d,i)=>{\n    const r=R0+i, q=qty[d.id]||0;\n    if(d.img&&\/^data:image\\\/(png|jpe?g)\/.test(d.img)) imgs.push({row:r-1, uri:d.img});\n    rows.push(`<row r=\"${r}\" ht=\"46\" customHeight=\"1\">`\n      +c(\"A\"+r,d.id,ST.int,\"n\")+c(\"B\"+r,d.ref||\"\",ST.txt)+c(\"C\"+r,null,ST.txt)\n      +c(\"D\"+r,(d.brand||\"\")+\"\\n\"+(d.name||\"\"),ST.wrap)+c(\"E\"+r,d.shelf||\"\",ST.txt)\n      +c(\"F\"+r,d.g,ST.gen,\"n\")+c(\"G\"+r,d.upc,ST.int,\"n\")+c(\"H\"+r,d.cpp,ST.int,\"n\")\n      +c(\"I\"+r,`J${r}*G${r}`,ST.int,\"f\")+c(\"J\"+r,q,ST.qty,\"n\")+c(\"K\"+r,`J${r}\/H${r}`,ST.dec2,\"f\")\n      +c(\"L\"+r,d.l,ST.gen,\"n\")+c(\"M\"+r,d.w,ST.gen,\"n\")+c(\"N\"+r,d.h,ST.gen,\"n\")\n      +c(\"O\"+r,`L${r}*M${r}*N${r}\/1000000`,ST.cbm,\"f\")+c(\"P\"+r,`O${r}*J${r}`,ST.dec2,\"f\")\n      +c(\"Q\"+r,d.hs||\"\",ST.txt)+c(\"R\"+r,d.bc||\"\",ST.txt)+c(\"S\"+r,d.cbc||\"\",ST.txt)\n      +c(\"T\"+r,d.temp||\"\",ST.txt)+c(\"U\"+r,null,ST.txt)+c(\"V\"+r,null,ST.txt)+c(\"W\"+r,null,ST.txt)\n      +c(\"X\"+r,`(F${r}*G${r})\/1000`,ST.dec2,\"f\")+c(\"Y\"+r,d.tare!=null?d.tare:\"\",ST.dec2,d.tare!=null?\"n\":undefined)\n      +c(\"Z\"+r,`X${r}+Y${r}`,ST.dec2,\"f\")+c(\"AA\"+r,`X${r}*J${r}`,ST.dec2,\"f\")+c(\"AB\"+r,`Z${r}*J${r}`,ST.dec2,\"f\")\n      +c(\"AC\"+r,d.pu,ST.usd3,\"n\")+c(\"AD\"+r,`AC${r}*G${r}`,ST.usd2,\"f\")+c(\"AE\"+r,`AD${r}*J${r}`,ST.usd2,\"f\")\n      +c(\"AF\"+r,`AC${r}*${RATE}`,ST.eur3,\"f\")+c(\"AG\"+r,`AD${r}*${RATE}`,ST.eur2,\"f\")+c(\"AH\"+r,`AE${r}*${RATE}`,ST.eur2,\"f\")\n      +c(\"AI\"+r,d.pub?\"Visible\":\"Internal\",ST.tag)+`<\/row>`);\n  });\n  const SR=(col)=>`SUM(${col}${R0}:${col}${RT-1})`;\n  rows.push(`<row r=\"${RT}\" ht=\"19\" customHeight=\"1\">${c(\"A\"+RT,\"TOTAL\",ST.totL)}${c(\"I\"+RT,SR(\"I\"),ST.totI,\"f\")}${c(\"J\"+RT,SR(\"J\"),ST.totI,\"f\")}${c(\"K\"+RT,SR(\"K\"),ST.totD,\"f\")}${c(\"P\"+RT,SR(\"P\"),ST.totD,\"f\")}${c(\"AA\"+RT,SR(\"AA\"),ST.totD,\"f\")}${c(\"AB\"+RT,SR(\"AB\"),ST.totD,\"f\")}${c(\"AD\"+RT,\"TOTAL EXWORKS PRICE\",ST.totL)}${c(\"AE\"+RT,SR(\"AE\"),ST.totU,\"f\")}${c(\"AG\"+RT,\"TOTAL EXWORKS PRICE\",ST.totL)}${c(\"AH\"+RT,SR(\"AH\"),ST.totE,\"f\")}<\/row>`);\n  const tax=[[\"TAXES\",RT+1],[\"FOB CHARGES\",RT+2],[\"OTHER FREIGHT CHARGES\",RT+3]];\n  tax.forEach(([lb,r])=>rows.push(`<row r=\"${r}\">${c(\"AD\"+r,lb,ST.totL)}${c(\"AE\"+r,0,ST.totU,\"n\")}${c(\"AG\"+r,lb,ST.totL)}${c(\"AH\"+r,`AE${r}*${RATE}`,ST.totE,\"f\")}<\/row>`));\n  rows.push(`<row r=\"${RT+4}\">${c(\"AD\"+(RT+4),\"TOTAL\",ST.totL)}${c(\"AE\"+(RT+4),`SUM(AE${RT}:AE${RT+3})`,ST.totU,\"f\")}${c(\"AG\"+(RT+4),\"TOTAL\",ST.totL)}${c(\"AH\"+(RT+4),`SUM(AH${RT}:AH${RT+3})`,ST.totE,\"f\")}<\/row>`);\n\n  const merges=['A4:R4','A5:D5','F5:J5','L5:R5','H9:J9','H10:J10','H11:J11','A12:R12','A6:C6','A7:C7','A8:C8','A9:C9','A10:C10','A11:C11'];\n  const cf=\n   `<conditionalFormatting sqref=\"H7\"><cfRule type=\"cellIs\" dxfId=\"0\" priority=\"1\" operator=\"greaterThan\"><formula>1<\/formula><\/cfRule><cfRule type=\"cellIs\" dxfId=\"1\" priority=\"2\" operator=\"greaterThan\"><formula>0.85<\/formula><\/cfRule><cfRule type=\"cellIs\" dxfId=\"2\" priority=\"3\" operator=\"greaterThan\"><formula>0<\/formula><\/cfRule><\/conditionalFormatting>`+\n   `<conditionalFormatting sqref=\"H9:J9\"><cfRule type=\"containsText\" dxfId=\"0\" priority=\"4\" operator=\"containsText\" text=\"OVER\"><formula>NOT(ISERROR(SEARCH(\"OVER\",H9)))<\/formula><\/cfRule><cfRule type=\"containsText\" dxfId=\"1\" priority=\"5\" operator=\"containsText\" text=\"Nearly\"><formula>NOT(ISERROR(SEARCH(\"Nearly\",H9)))<\/formula><\/cfRule><cfRule type=\"containsText\" dxfId=\"2\" priority=\"6\" operator=\"containsText\" text=\"OK\"><formula>NOT(ISERROR(SEARCH(\"OK\",H9)))<\/formula><\/cfRule><\/conditionalFormatting>`+\n   `<conditionalFormatting sqref=\"H10:J10\"><cfRule type=\"containsText\" dxfId=\"0\" priority=\"7\" operator=\"containsText\" text=\"OVERWEIGHT\"><formula>NOT(ISERROR(SEARCH(\"OVERWEIGHT\",H10)))<\/formula><\/cfRule><cfRule type=\"containsText\" dxfId=\"2\" priority=\"8\" operator=\"containsText\" text=\"OK\"><formula>NOT(ISERROR(SEARCH(\"OK\",H10)))<\/formula><\/cfRule><\/conditionalFormatting>`+\n   `<conditionalFormatting sqref=\"H11:J11\"><cfRule type=\"containsText\" dxfId=\"0\" priority=\"9\" operator=\"containsText\" text=\"TOO MANY\"><formula>NOT(ISERROR(SEARCH(\"TOO MANY\",H11)))<\/formula><\/cfRule><cfRule type=\"containsText\" dxfId=\"2\" priority=\"10\" operator=\"containsText\" text=\"OK\"><formula>NOT(ISERROR(SEARCH(\"OK\",H11)))<\/formula><\/cfRule><\/conditionalFormatting>`;\n  const dv=\n   `<dataValidations count=\"5\">`+\n   `<dataValidation type=\"list\" allowBlank=\"1\" showInputMessage=\"1\" showErrorMessage=\"1\" sqref=\"D6\"><formula1>$L$7:$L$10<\/formula1><\/dataValidation>`+\n   `<dataValidation type=\"whole\" operator=\"between\" allowBlank=\"1\" showInputMessage=\"1\" showErrorMessage=\"1\" sqref=\"D7\"><formula1>1<\/formula1><formula2>99<\/formula2><\/dataValidation>`+\n   `<dataValidation type=\"list\" allowBlank=\"1\" showInputMessage=\"1\" showErrorMessage=\"1\" sqref=\"D8\"><formula1>\"Floor loaded,Palletised\"<\/formula1><\/dataValidation>`+\n   `<dataValidation type=\"list\" allowBlank=\"1\" showInputMessage=\"1\" showErrorMessage=\"1\" sqref=\"D9\"><formula1>\"100 \u00d7 120 cm,80 \u00d7 120 cm (Euro)\"<\/formula1><\/dataValidation>`+\n   `<dataValidation type=\"whole\" operator=\"between\" allowBlank=\"1\" showInputMessage=\"1\" showErrorMessage=\"1\" sqref=\"D11\"><formula1>0<\/formula1><formula2>10<\/formula2><\/dataValidation>`+\n   `<\/dataValidations>`;\n\n  const sheet='<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n   '<worksheet xmlns=\"http:\/\/schemas.openxmlformats.org\/spreadsheetml\/2006\/main\" xmlns:r=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\">'+\n   `<dimension ref=\"A1:AK${RT+4}\"\/>`+\n   `<sheetViews><sheetView workbookViewId=\"0\" showGridLines=\"0\"><pane ySplit=\"14\" topLeftCell=\"A15\" activePane=\"bottomLeft\" state=\"frozen\"\/><\/sheetView><\/sheetViews>`+\n   '<sheetFormatPr defaultRowHeight=\"15\"\/>'+\n   '<cols>'+W.map((w,i)=>`<col min=\"${i+1}\" max=\"${i+1}\" width=\"${w}\" customWidth=\"1\"\/>`).join(\"\")+'<col min=\"37\" max=\"37\" width=\"4\" customWidth=\"1\"\/><\/cols>'+\n   '<sheetData>'+rows.join(\"\")+'<\/sheetData>'+\n   `<mergeCells count=\"${merges.length}\">`+merges.map(m=>`<mergeCell ref=\"${m}\"\/>`).join(\"\")+'<\/mergeCells>'+\n   cf+dv+\n   '<pageMargins left=\"0.3\" right=\"0.3\" top=\"0.4\" bottom=\"0.4\" header=\"0.2\" footer=\"0.2\"\/>'+\n   '<pageSetup orientation=\"landscape\" fitToWidth=\"1\" fitToHeight=\"0\" paperSize=\"9\"\/>'+\n   (imgs.length?'<drawing r:id=\"rId1\"\/>':'')+\n   '<\/worksheet>';\n\n  const T='FF0E5F58', LT='FFDCEBE8';\n  const styles='<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n   '<styleSheet xmlns=\"http:\/\/schemas.openxmlformats.org\/spreadsheetml\/2006\/main\">'+\n   '<numFmts count=\"9\">'+\n   '<numFmt numFmtId=\"164\" formatCode=\"#,##0\"\/><numFmt numFmtId=\"165\" formatCode=\"#,##0.00\"\/>'+\n   '<numFmt numFmtId=\"166\" formatCode=\"0%\"\/><numFmt numFmtId=\"167\" formatCode=\"&quot;$&quot;#,##0.000\"\/>'+\n   '<numFmt numFmtId=\"168\" formatCode=\"&quot;$&quot;#,##0.00\"\/><numFmt numFmtId=\"169\" formatCode=\"&quot;\u20ac&quot;#,##0.000\"\/>'+\n   '<numFmt numFmtId=\"170\" formatCode=\"&quot;\u20ac&quot;#,##0.00\"\/><numFmt numFmtId=\"171\" formatCode=\"0.0000\"\/>'+\n   '<numFmt numFmtId=\"172\" formatCode=\"#,##0.###\"\/><\/numFmts>'+\n   '<fonts count=\"12\">'+\n   '<font><sz val=\"10\"\/><name val=\"Tahoma\"\/><\/font>'+                                   \/*0*\/\n   '<font><b\/><sz val=\"9\"\/><color rgb=\"FFFFFFFF\"\/><name val=\"Tahoma\"\/><\/font>'+         \/*1 head\/ghdr*\/\n   `<font><b\/><sz val=\"15\"\/><color rgb=\"${T}\"\/><name val=\"Tahoma\"\/><\/font>`+            \/*2 title*\/\n   '<font><sz val=\"9\"\/><color rgb=\"FF7A7A72\"\/><name val=\"Tahoma\"\/><\/font>'+             \/*3 sub*\/\n   '<font><b\/><sz val=\"14\"\/><color rgb=\"FFFFFFFF\"\/><name val=\"Tahoma\"\/><\/font>'+        \/*4 band*\/\n   `<font><b\/><sz val=\"10\"\/><color rgb=\"${T}\"\/><name val=\"Tahoma\"\/><\/font>`+            \/*5 subhd*\/\n   '<font><sz val=\"10\"\/><color rgb=\"FF404040\"\/><name val=\"Tahoma\"\/><\/font>'+            \/*6 lbl*\/\n   '<font><b\/><sz val=\"11\"\/><name val=\"Tahoma\"\/><\/font>'+                               \/*7 val\/inp\/sta*\/\n   `<font><b\/><sz val=\"13\"\/><color rgb=\"${T}\"\/><name val=\"Tahoma\"\/><\/font>`+            \/*8 pct*\/\n   '<font><i\/><sz val=\"9\"\/><color rgb=\"FF7F7F7F\"\/><name val=\"Tahoma\"\/><\/font>'+         \/*9 note*\/\n   '<font><b\/><sz val=\"10\"\/><name val=\"Tahoma\"\/><\/font>'+                               \/*10 total*\/\n   '<font><sz val=\"9\"\/><color rgb=\"FF404040\"\/><name val=\"Tahoma\"\/><\/font>'+             \/*11 gcell*\/\n   '<\/fonts>'+\n   '<fills count=\"6\">'+\n   '<fill><patternFill patternType=\"none\"\/><\/fill><fill><patternFill patternType=\"gray125\"\/><\/fill>'+\n   `<fill><patternFill patternType=\"solid\"><fgColor rgb=\"${T}\"\/><bgColor indexed=\"64\"\/><\/patternFill><\/fill>`+\n   `<fill><patternFill patternType=\"solid\"><fgColor rgb=\"${LT}\"\/><bgColor indexed=\"64\"\/><\/patternFill><\/fill>`+\n   '<fill><patternFill patternType=\"solid\"><fgColor rgb=\"FFDDEBF7\"\/><bgColor indexed=\"64\"\/><\/patternFill><\/fill>'+\n   '<fill><patternFill patternType=\"solid\"><fgColor rgb=\"FFFFF2CC\"\/><bgColor indexed=\"64\"\/><\/patternFill><\/fill>'+\n   '<\/fills>'+\n   '<borders count=\"3\"><border><left\/><right\/><top\/><bottom\/><diagonal\/><\/border>'+\n   '<border><left style=\"thin\"><color rgb=\"FFE3E1D9\"\/><\/left><right style=\"thin\"><color rgb=\"FFE3E1D9\"\/><\/right><top style=\"thin\"><color rgb=\"FFE3E1D9\"\/><\/top><bottom style=\"thin\"><color rgb=\"FFE3E1D9\"\/><\/bottom><diagonal\/><\/border>'+\n   `<border><left\/><right\/><top style=\"medium\"><color rgb=\"${T}\"\/><\/top><bottom\/><diagonal\/><\/border><\/borders>`+\n   '<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"\/><\/cellStyleXfs>'+\n   '<cellXfs count=\"31\">'+\n   '<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"left\" vertical=\"center\" wrapText=\"1\"\/><\/xf>'+\n   '<xf numFmtId=\"172\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"164\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"165\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"171\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"167\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"168\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"169\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"170\" fontId=\"0\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"1\" fillId=\"2\" borderId=\"1\" xfId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\" wrapText=\"1\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"2\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\"\/>'+\n   '<xf numFmtId=\"0\" fontId=\"3\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\"\/>'+\n   '<xf numFmtId=\"0\" fontId=\"4\" fillId=\"2\" borderId=\"0\" xfId=\"0\" applyFont=\"1\" applyFill=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"5\" fillId=\"3\" borderId=\"0\" xfId=\"0\" applyFont=\"1\" applyFill=\"1\" applyAlignment=\"1\"><alignment horizontal=\"left\" vertical=\"center\" indent=\"1\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"6\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\" applyAlignment=\"1\"><alignment horizontal=\"left\" vertical=\"center\" indent=\"1\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"7\" fillId=\"4\" borderId=\"1\" xfId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"7\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\" applyAlignment=\"1\"><alignment horizontal=\"left\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"166\" fontId=\"8\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyNumberFormat=\"1\" applyFont=\"1\" applyAlignment=\"1\"><alignment horizontal=\"left\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"7\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\" applyAlignment=\"1\"><alignment horizontal=\"left\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"1\" fillId=\"2\" borderId=\"1\" xfId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\" wrapText=\"1\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"11\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyFont=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"9\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\" applyAlignment=\"1\"><alignment horizontal=\"left\" vertical=\"center\" indent=\"1\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"10\" fillId=\"0\" borderId=\"2\" xfId=\"0\" applyFont=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"right\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"164\" fontId=\"10\" fillId=\"0\" borderId=\"2\" xfId=\"0\" applyNumberFormat=\"1\" applyFont=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"165\" fontId=\"10\" fillId=\"0\" borderId=\"2\" xfId=\"0\" applyNumberFormat=\"1\" applyFont=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"168\" fontId=\"10\" fillId=\"0\" borderId=\"2\" xfId=\"0\" applyNumberFormat=\"1\" applyFont=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"170\" fontId=\"10\" fillId=\"0\" borderId=\"2\" xfId=\"0\" applyNumberFormat=\"1\" applyFont=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"164\" fontId=\"7\" fillId=\"5\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"0\" fontId=\"11\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyFont=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<xf numFmtId=\"171\" fontId=\"7\" fillId=\"4\" borderId=\"1\" xfId=\"0\" applyNumberFormat=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"center\"\/><\/xf>'+\n   '<\/cellXfs>'+\n   '<cellStyles count=\"1\"><cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\"\/><\/cellStyles>'+\n   '<dxfs count=\"3\">'+\n   '<dxf><font><color rgb=\"FF9C0006\"\/><\/font><fill><patternFill><bgColor rgb=\"FFFFC7CE\"\/><\/patternFill><\/fill><\/dxf>'+\n   '<dxf><font><color rgb=\"FF9C6500\"\/><\/font><fill><patternFill><bgColor rgb=\"FFFFEB9C\"\/><\/patternFill><\/fill><\/dxf>'+\n   '<dxf><font><color rgb=\"FF006100\"\/><\/font><fill><patternFill><bgColor rgb=\"FFC6EFCE\"\/><\/patternFill><\/fill><\/dxf>'+\n   '<\/dxfs><\/styleSheet>';\n\n  \/* drawing: one anchored photo per product row *\/\n  const media=[], drels=[], anchors=[];\n  imgs.forEach((im,k)=>{\n    const png=\/^data:image\\\/png\/.test(im.uri);\n    const name=`image${k+1}.`+(png?'png':'jpeg');\n    media.push({name:'xl\/media\/'+name, data:b64u8(im.uri)});\n    drels.push(`<Relationship Id=\"rId${k+1}\" Type=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\/image\" Target=\"..\/media\/${name}\"\/>`);\n    anchors.push(`<xdr:oneCellAnchor><xdr:from><xdr:col>2<\/xdr:col><xdr:colOff>76200<\/xdr:colOff><xdr:row>${im.row}<\/xdr:row><xdr:rowOff>38100<\/xdr:rowOff><\/xdr:from>`+\n     `<xdr:ext cx=\"400050\" cy=\"514350\"\/>`+\n     `<xdr:pic><xdr:nvPicPr><xdr:cNvPr id=\"${k+2}\" name=\"p${k+1}\"\/><xdr:cNvPicPr\/><\/xdr:nvPicPr>`+\n     `<xdr:blipFill><a:blip r:embed=\"rId${k+1}\"\/><a:stretch><a:fillRect\/><\/a:stretch><\/xdr:blipFill>`+\n     `<xdr:spPr><a:xfrm><a:off x=\"0\" y=\"0\"\/><a:ext cx=\"400050\" cy=\"514350\"\/><\/a:xfrm><a:prstGeom prst=\"rect\"><a:avLst\/><\/a:prstGeom><\/xdr:spPr><\/xdr:pic>`+\n     `<xdr:clientData\/><\/xdr:oneCellAnchor>`);\n  });\n  const drawing='<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n   '<xdr:wsDr xmlns:xdr=\"http:\/\/schemas.openxmlformats.org\/drawingml\/2006\/spreadsheetDrawing\" xmlns:a=\"http:\/\/schemas.openxmlformats.org\/drawingml\/2006\/main\" xmlns:r=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\">'+\n   anchors.join(\"\")+'<\/xdr:wsDr>';\n\n  const files=[\n   {name:'[Content_Types].xml', data:\n    '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n    '<Types xmlns=\"http:\/\/schemas.openxmlformats.org\/package\/2006\/content-types\">'+\n    '<Default Extension=\"rels\" ContentType=\"application\/vnd.openxmlformats-package.relationships+xml\"\/>'+\n    '<Default Extension=\"xml\" ContentType=\"application\/xml\"\/>'+\n    '<Default Extension=\"png\" ContentType=\"image\/png\"\/>'+\n    '<Default Extension=\"jpeg\" ContentType=\"image\/jpeg\"\/>'+\n    '<Override PartName=\"\/xl\/workbook.xml\" ContentType=\"application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"\/>'+\n    '<Override PartName=\"\/xl\/worksheets\/sheet1.xml\" ContentType=\"application\/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"\/>'+\n    '<Override PartName=\"\/xl\/styles.xml\" ContentType=\"application\/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\"\/>'+\n    (imgs.length?'<Override PartName=\"\/xl\/drawings\/drawing1.xml\" ContentType=\"application\/vnd.openxmlformats-officedocument.drawing+xml\"\/>':'')+\n    '<\/Types>'},\n   {name:'_rels\/.rels', data:\n    '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n    '<Relationships xmlns=\"http:\/\/schemas.openxmlformats.org\/package\/2006\/relationships\">'+\n    '<Relationship Id=\"rId1\" Type=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\/officeDocument\" Target=\"xl\/workbook.xml\"\/>'+\n    '<\/Relationships>'},\n   {name:'xl\/workbook.xml', data:\n    '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n    '<workbook xmlns=\"http:\/\/schemas.openxmlformats.org\/spreadsheetml\/2006\/main\" xmlns:r=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\">'+\n    '<sheets><sheet name=\"PRICE LIST\" sheetId=\"1\" r:id=\"rId1\"\/><\/sheets><calcPr fullCalcOnLoad=\"1\"\/><\/workbook>'},\n   {name:'xl\/_rels\/workbook.xml.rels', data:\n    '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n    '<Relationships xmlns=\"http:\/\/schemas.openxmlformats.org\/package\/2006\/relationships\">'+\n    '<Relationship Id=\"rId1\" Type=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\/worksheet\" Target=\"worksheets\/sheet1.xml\"\/>'+\n    '<Relationship Id=\"rId2\" Type=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\/styles\" Target=\"styles.xml\"\/>'+\n    '<\/Relationships>'},\n   {name:'xl\/styles.xml', data:styles},\n   {name:'xl\/worksheets\/sheet1.xml', data:sheet}\n  ];\n  if(imgs.length){\n    files.push({name:'xl\/worksheets\/_rels\/sheet1.xml.rels', data:\n     '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n     '<Relationships xmlns=\"http:\/\/schemas.openxmlformats.org\/package\/2006\/relationships\">'+\n     '<Relationship Id=\"rId1\" Type=\"http:\/\/schemas.openxmlformats.org\/officeDocument\/2006\/relationships\/drawing\" Target=\"..\/drawings\/drawing1.xml\"\/>'+\n     '<\/Relationships>'});\n    files.push({name:'xl\/drawings\/drawing1.xml', data:drawing});\n    files.push({name:'xl\/drawings\/_rels\/drawing1.xml.rels', data:\n     '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n     '<Relationships xmlns=\"http:\/\/schemas.openxmlformats.org\/package\/2006\/relationships\">'+drels.join(\"\")+'<\/Relationships>'});\n    media.forEach(m=>files.push(m));\n  }\n  return zip(files);\n}\n\n\/* ---- live FX ---- *\/\n$(\"#fxsrc\").textContent=T.en.fxLoading;\nfetch(\"https:\/\/api.frankfurter.dev\/v1\/latest?base=USD&symbols=EUR\")\n  .then(r=>r.ok?r.json():Promise.reject())\n  .then(j=>{\n    if(j&&j.rates&&j.rates.EUR){\n      rate=j.rates.EUR; rateSource=\"live\"; rateDate=j.date;\n      $(\"#fxrate\").value=rate.toFixed(4);\n      updateFxLabel(); renderBody(); renderStats();\n    } else throw 0;\n  })\n  .catch(()=>{ rateSource=\"fallback\"; updateFxLabel(); });\n\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 add \/ edit product form \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\nconst FORM_GROUPS = [\n  [\"gIdentity\",[[\"id\",\"number\"],[\"fam\",\"text\"],[\"famTr\",\"text\"],[\"brand\",\"text\"],[\"brandTr\",\"text\"],[\"name\",\"text\"],[\"nameTr\",\"text\"]]],\n  [\"gPack\",[[\"g\",\"number\"],[\"upc\",\"number\"],[\"cpp\",\"number\"],[\"l\",\"number\"],[\"w\",\"number\"],[\"h\",\"number\"],[\"cbm\",\"number\",\"auto\"]]],\n  [\"gWeights\",[[\"net\",\"number\"],[\"tare\",\"number\"],[\"gross\",\"number\",\"auto\"]]],\n  [\"gCodes\",[[\"shelf\",\"text\"],[\"temp\",\"text\"],[\"hs\",\"text\"],[\"bc\",\"text\"],[\"cbc\",\"text\"]]],\n  [\"gPrices\",[[\"pu\",\"number\"],[\"pc\",\"number\",\"auto\"]]]\n];\nconst STEP = {g:1,upc:1,cpp:1,l:.1,w:.1,h:.1,cbm:.000001,net:.001,tare:.01,gross:.001,pu:.001,pc:.01,id:1};\nlet editing = null;      \/\/ id being edited, or null when adding\nlet photoData = null;    \/\/ data URI for the pending photo\nconst touched = new Set();\n\nfunction buildForm(d){\n  const t=T[lang];\n  touched.clear();\n  photoData = d ? d.img : null;\n  const fams=[...new Set(DATA.map(x=>x.fam))].sort();\n  let html = `<fieldset class=\"fset\"><legend>${t.cols.pub}<\/legend>\n    <label style=\"display:flex;gap:9px;align-items:center;font-size:14px;cursor:pointer\">\n      <input type=\"checkbox\" id=\"f-pub\" ${(!d||d.pub)?\"checked\":\"\"}> <span>${t.fPub}<\/span>\n    <\/label><\/fieldset>\n    <fieldset class=\"fset\"><legend>${t.gPhoto}<\/legend>\n    <div class=\"photorow\">\n      <div class=\"photoprev\" id=\"photoprev\">${photoData?`<img decoding=\"async\" src=\"${photoData}\" alt=\"\">`:`<span>${t.photoNone}<\/span>`}<\/div>\n      <div class=\"f\">\n        <label for=\"f-photo\">${t.gPhoto}<\/label>\n        <input type=\"file\" id=\"f-photo\" accept=\"image\/png,image\/jpeg,image\/webp\" hidden>\n        <button type=\"button\" class=\"btn\" id=\"f-photo-btn\">${t.photoPick}<\/button>\n        <span class=\"hint\">${t.photoHint}<\/span>\n      <\/div>\n    <\/div><\/fieldset>`;\n  FORM_GROUPS.forEach(([gk,fields])=>{\n    html += `<fieldset class=\"fset\"><legend>${t[gk]}<\/legend><div class=\"grid\">`;\n    fields.forEach(([k,type,auto])=>{\n      const v = d ? (d[k]??\"\") : \"\";\n      const list = k===\"fam\" ? ` list=\"famlist\"` : \"\";\n      html += `<div class=\"f${auto?\" auto\":\"\"}\">\n        <label for=\"f-${k}\">${t.fields[k]}<\/label>\n        <input id=\"f-${k}\" data-k=\"${k}\" type=\"${type}\"${type===\"number\"?` step=\"${STEP[k]||1}\" min=\"0\"`:\"\"}${list} value=\"${String(v).replace(\/\"\/g,\"&quot;\")}\">\n        ${auto?`<span class=\"hint\">${t.autoHint}<\/span>`:\"\"}\n      <\/div>`;\n    });\n    html += `<\/div><\/fieldset>`;\n  });\n  html += `<datalist id=\"famlist\">${fams.map(f=>`<option value=\"${f}\">`).join(\"\")}<\/datalist>`;\n  $(\"#sheetbody\").innerHTML = html;\n\n  FORM_GROUPS.flatMap(g=>g[1]).forEach(([k,,auto])=>{\n    if(auto) $(\"#f-\"+k).addEventListener(\"input\",()=>touched.add(k));\n  });\n  \/\/ each calculated field only refreshes when one of its own inputs changes\n  DERIVED.forEach(([target,drivers])=>{\n    drivers.forEach(k=>$(\"#f-\"+k).addEventListener(\"input\",()=>recalc(target)));\n  });\n  $(\"#f-photo\").addEventListener(\"change\",onPhoto);\n  $(\"#f-photo-btn\").addEventListener(\"click\",()=>$(\"#f-photo\").click());\n}\n\nconst DERIVED = [[\"cbm\",[\"l\",\"w\",\"h\"]],[\"gross\",[\"net\",\"tare\"]],[\"pc\",[\"pu\",\"upc\"]]];\n\n\/* ---------- master edit ----------------------------------------------------\n   Edits go through exactly the same draft object the row editor uses, so the\n   \"Copy data\" block at the bottom stays the single way changes are published. *\/\nfunction recordEdit(id){\n  const d=DATA.find(x=>String(x.id)===String(id)); if(!d) return;\n  if(draft.added[id]){ draft.added[id]=Object.assign({},d); return; }\n  const base=ORIGINAL[id]||{}, diff={};\n  KEY_ORDER.forEach(k=>{ if(k!==\"id\"&&k!==\"pu\"&&k!==\"pc\"&&k!==\"pub\" && d[k]!==base[k]) diff[k]=d[k]; });\n  if(Object.keys(diff).length) draft.edited[id]=diff; else delete draft.edited[id];\n  if(d.pu!==base.pu || d.pc!==base.pc) draft.prices[id]=[d.pu,d.pc]; else delete draft.prices[id];\n  if(!!d.pub !== !!base.pub) draft.pub[id]=!!d.pub; else delete draft.pub[id];\n}\nfunction gridDerive(d,k){\n  const done=[];\n  const set=(t,v)=>{ if(typedIn.has(d.id+\":\"+t)) return; d[t]=v?+v.toFixed(9):0; done.push(t); };\n  if(k===\"l\"||k===\"w\"||k===\"h\") set(\"cbm\",(d.l||0)*(d.w||0)*(d.h||0)\/1e6);\n  if(k===\"net\"||k===\"tare\")     set(\"gross\",(d.net||0)+(d.tare||0));\n  if(k===\"pu\"||k===\"upc\")       set(\"pc\",(d.pu||0)*(d.upc||0));\n  return done;\n}\n\/* Renaming a product's number: the number is the key that prices, photos and\n   the published block are filed under, so every reference moves with it. An\n   order already placed is untouched \u2014 it keeps its own copy of what was sold. *\/\nfunction renumber(oldId, newId){\n  const t=T[lang];\n  oldId=String(oldId); newId=String(Math.max(1,Math.floor(+newId||0)));\n  if(newId===oldId || newId===\"0\") return {ok:false};\n  if(DATA.some(x=>String(x.id)===newId)) return {ok:false, why:t.idTaken.replace(\"{n}\",newId)};\n  const d=DATA.find(x=>String(x.id)===oldId); if(!d) return {ok:false};\n  d.id=+newId;\n  const move=o=>{ if(o && Object.prototype.hasOwnProperty.call(o,oldId)){ o[newId]=o[oldId]; delete o[oldId]; } };\n  move(draft.edited); move(draft.prices); move(draft.pub); move(draft.added); move(qty);\n  if(ORIGINAL[oldId]){ ORIGINAL[newId]=ORIGINAL[oldId]; delete ORIGINAL[oldId]; }\n  if(draft.added[newId]) draft.added[newId].id=+newId;\n  [...typedIn].forEach(k=>{ if(k.indexOf(oldId+\":\")===0){ typedIn.delete(k); typedIn.add(newId+k.slice(oldId.length)); } });\n  DATA.sort((a,b)=>a.id-b.id);\n  recordEdit(newId);\n  return {ok:true};\n}\n\/* replacing a photo straight from the grid, same resizing as the row editor *\/\nlet gridPhotoId=null;\nfunction pickGridPhoto(id){\n  gridPhotoId=id;\n  const inp=$(\"#gridphoto\"); inp.value=\"\"; inp.click();\n}\nfunction onGridPhoto(e){\n  const file=e.target.files&&e.target.files[0], id=gridPhotoId;\n  if(!file||id==null) return;\n  const rd=new FileReader();\n  rd.onload=()=>{\n    const im=new Image();\n    im.onload=()=>{\n      const H=260, W=Math.max(1,Math.round(im.width*H\/im.height));\n      const c=document.createElement(\"canvas\"); c.width=W; c.height=H;\n      const g=c.getContext(\"2d\");\n      g.fillStyle=\"#ffffff\"; g.fillRect(0,0,W,H);\n      g.drawImage(im,0,0,W,H);\n      let out;\n      try{ out=c.toDataURL(\"image\/webp\",0.8); }catch(err){ out=null; }\n      if(!out||out.indexOf(\"data:image\/webp\")!==0) out=c.toDataURL(\"image\/jpeg\",0.85);\n      const d=DATA.find(x=>String(x.id)===String(id));\n      if(d){ d.img=out; recordEdit(id); renderBody(); renderMastbar(); renderCode(); }\n    };\n    im.src=rd.result;\n  };\n  rd.readAsDataURL(file);\n}\n\nfunction masterCount(){\n  return new Set([].concat(Object.keys(draft.edited),Object.keys(draft.prices),\n                           Object.keys(draft.pub),Object.keys(draft.added))).size;\n}\nfunction renderMastbar(){\n  const t=T[lang], bar=$(\"#mastbar\");\n  bar.hidden=!master;\n  if(!master) return;\n  const n=masterCount();\n  const msg = n===0 ? t.masterNone : n===1 ? t.masterCount1 : t.masterCount.replace(\"{n}\",n);\n  bar.innerHTML = `<b>${t.masterOn}<\/b><span>${msg}<\/span>`\n    + `<span class=\"spacer\"><\/span>`\n    + `<button class=\"btn\" id=\"mast-code\">${t.masterPublish}<\/button>`\n    + `<button class=\"btn\" id=\"mast-off\">${t.masterDone}<\/button>`;\n  $(\"#mast-off\").addEventListener(\"click\",()=>setMaster(false));\n  $(\"#mast-code\").addEventListener(\"click\",()=>{\n    renderCode();\n    const cp=$(\"#codepanel\"); cp.hidden=false; cp.scrollIntoView({behavior:\"smooth\",block:\"start\"});\n  });\n}\nfunction setMaster(on){\n  master=on;\n  document.body.classList.toggle(\"masteredit\",on);\n  $(\"#btn-master\").setAttribute(\"aria-pressed\",on?\"true\":\"false\");\n  renderBody(); renderMastbar(); requestAnimationFrame(syncScrollbars);\n}\nfunction num(k){ const el=$(\"#f-\"+k); const v=parseFloat(el.value); return isNaN(v)?0:v; }\nfunction recalc(target){\n  if(touched.has(target)) return;\n  let v=0;\n  if(target===\"cbm\")   v=num(\"l\")*num(\"w\")*num(\"h\")\/1e6;\n  if(target===\"gross\") v=num(\"net\")+num(\"tare\");\n  if(target===\"pc\")    v=num(\"pu\")*num(\"upc\");\n  $(\"#f-\"+target).value = v ? +v.toFixed(9) : \"\";\n}\n\nfunction onPhoto(e){\n  const file=e.target.files&&e.target.files[0];\n  if(!file) return;\n  const rd=new FileReader();\n  rd.onload=()=>{\n    const im=new Image();\n    im.onload=()=>{\n      const H=260, W=Math.max(1,Math.round(im.width*H\/im.height));\n      const c=document.createElement(\"canvas\"); c.width=W; c.height=H;\n      const g=c.getContext(\"2d\");\n      g.fillStyle=\"#ffffff\"; g.fillRect(0,0,W,H);\n      g.drawImage(im,0,0,W,H);\n      let out;\n      try{ out=c.toDataURL(\"image\/webp\",0.8); }catch(err){ out=null; }\n      if(!out||out.indexOf(\"data:image\/webp\")!==0) out=c.toDataURL(\"image\/jpeg\",0.85);\n      photoData=out;\n      $(\"#photoprev\").innerHTML=`<img decoding=\"async\" src=\"${photoData}\" alt=\"\">`;\n    };\n    im.src=rd.result;\n  };\n  rd.readAsDataURL(file);\n}\n\nfunction openSheet(id){\n  const t=T[lang];\n  editing = id==null ? null : id;\n  const d = id==null ? null : DATA.find(x=>String(x.id)===String(id));\n  $(\"#sheettitle\").textContent = d ? `${t.edit} \u2014 ${String(d.id).padStart(2,\"0\")}` : t.addTitle;\n  $(\"#sheet-del\").hidden = !(d && draft.added[d.id]);\n  $(\"#sheet-err\").textContent=\"\";\n  buildForm(d);\n  if(!d){\n    $(\"#f-id\").value = Math.max(0,...DATA.map(x=>+x.id||0)) + 1;\n    $(\"#f-shelf\").value = \"12 Months\";\n    $(\"#f-temp\").value = \"18 to 25 C\";\n    $(\"#f-hs\").value = \"1905.90.55.00.00\";\n  }\n  $(\"#sheet\").classList.add(\"on\");\n  document.body.style.overflow=\"hidden\";\n  $(\"#f-brand\").focus();\n}\nfunction closeSheet(){\n  $(\"#sheet\").classList.remove(\"on\");\n  document.body.style.overflow=\"\";\n}\n\nfunction saveSheet(){\n  const t=T[lang], err=$(\"#sheet-err\");\n  const val=k=>$(\"#f-\"+k).value.trim();\n  const id=parseInt(val(\"id\"),10);\n  if(!id || (editing==null && DATA.some(x=>+x.id===id))){ err.textContent=t.errId; return; }\n  if(!val(\"brand\") || !val(\"name\")){ err.textContent=t.errName; return; }\n  if(!photoData){ err.textContent=t.errPhoto; return; }\n  const o={\n    id, fam:val(\"fam\")||val(\"brand\"), famTr:val(\"famTr\")||val(\"fam\")||val(\"brand\"),\n    brand:val(\"brand\"), brandTr:val(\"brandTr\")||val(\"brand\"),\n    name:val(\"name\"), nameTr:val(\"nameTr\")||val(\"name\"),\n    shelf:val(\"shelf\"), temp:val(\"temp\"), hs:val(\"hs\"),\n    bc:val(\"bc\")||null, cbc:val(\"cbc\")||null,\n    g:num(\"g\"), upc:num(\"upc\"), cpp:num(\"cpp\")||1,\n    l:num(\"l\"), w:num(\"w\"), h:num(\"h\"), cbm:num(\"cbm\"),\n    net:num(\"net\"), tare:num(\"tare\"), gross:num(\"gross\"),\n    pu:num(\"pu\"), pc:num(\"pc\"), img:photoData,\n    pub: $(\"#f-pub\").checked\n  };\n  if(editing==null){\n    DATA.push(o); draft.added[id]=o;\n  }else{\n    const d=DATA.find(x=>String(x.id)===String(editing));\n    Object.assign(d,o);\n    if(draft.added[editing]){\n      draft.added[editing]=Object.assign({},d);\n    }else{\n      const base=ORIGINAL[editing]||{}, diff={};\n      KEY_ORDER.forEach(k=>{ if(k!==\"id\"&&k!==\"pu\"&&k!==\"pc\"&&k!==\"pub\" && d[k]!==base[k]) diff[k]=d[k]; });\n      if(Object.keys(diff).length) draft.edited[editing]=diff; else delete draft.edited[editing];\n      if(d.pu!==base.pu || d.pc!==base.pc) draft.prices[editing]=[d.pu,d.pc];\n      else delete draft.prices[editing];\n      if(!!d.pub !== !!base.pub) draft.pub[editing]=!!d.pub;\n      else delete draft.pub[editing];\n    }\n  }\n  DATA.sort((a,b)=>a.id-b.id);\n  recomputeFlags();\n  closeSheet();\n  renderChips(); renderAll(); renderCode();\n}\n\nfunction removeDraft(){\n  if(editing==null) return;\n  const i=DATA.findIndex(x=>String(x.id)===String(editing));\n  if(i>=0) DATA.splice(i,1);\n  delete draft.added[editing]; delete draft.prices[editing]; delete draft.pub[editing];\n  closeSheet();\n  recomputeFlags(); renderChips(); renderAll(); renderCode();\n}\n\nconst KEY_ORDER=[\"id\",\"ref\",\"fam\",\"famTr\",\"brand\",\"brandTr\",\"name\",\"nameTr\",\"shelf\",\"g\",\"upc\",\"cpp\",\n  \"l\",\"w\",\"h\",\"cbm\",\"hs\",\"bc\",\"cbc\",\"temp\",\"net\",\"tare\",\"gross\",\"pu\",\"pc\",\"pub\",\"img\"];\nfunction serialise(o){\n  const parts=KEY_ORDER.filter(k=>o[k]!==undefined).map(k=>{\n    const v=o[k];\n    const val = v===null ? \"null\" : typeof v===\"number\" ? String(v) : JSON.stringify(v);\n    return `    ${k}: ${val}`;\n  });\n  return \"  {\\n\"+parts.join(\",\\n\")+\"\\n  }\";\n}\nfunction draftJSON(){\n  return JSON.stringify({prices:draft.prices,public:draft.pub,overrides:draft.edited,extra:Object.values(draft.added)});\n}\n\/* Publishing writes the changes to the service, so both portals pick them up\n   on their next load. Confirmed orders are untouched \u2014 each one stores its own\n   copy of what was ordered. *\/\nasync function publishToEveryone(){\n  const t=T[lang], btn=$(\"#btn-publish\"), msg=$(\"#pubmsg\");\n  if(!btn) return;\n  btn.disabled=true; btn.textContent=t.pubSending;\n  msg.hidden=false; msg.className=\"pubmsg\"; msg.textContent=t.pubSending;\n  try{\n    const r=await api({action:\"publishData\", admin:me.code, dataset:DATASET, changes:{\n      prices:draft.prices, overrides:draft.edited, pub:draft.pub, added:draft.added\n    }});\n    if(r && (r.error===\"admin_only\"||r.error===\"not_allowed\")){\n      msg.className=\"pubmsg bad\"; msg.textContent=t.pubAdminOnly; return; }\n    if(!r||!r.ok) throw 0;\n    publishedSnapshot = draftJSON();\n    sharedDate = r.updated || sharedDate;\n    msg.className=\"pubmsg good\";\n    msg.textContent = (r.count===1) ? t.pubDone1 : t.pubDone.replace(\"{n}\", fmt(r.count||0));\n    renderSync(); renderMastbar();\n    setTimeout(()=>{ renderCode(); }, 2500);\n  }catch(e){\n    msg.className=\"pubmsg bad\"; msg.textContent=t.pubFailed;\n  }finally{ btn.disabled=false; btn.textContent=t.pubNow; }\n}\n\nfunction renderCode(){\n  const t=T[lang];\n  const added=Object.values(draft.added);\n  const total=added.length+Object.keys(draft.edited).length+Object.keys(draft.prices).length+Object.keys(draft.pub).length;\n  const panel=$(\"#codepanel\"), pending=$(\"#btn-pending\");\n  const dirty = draftJSON()!==publishedSnapshot;\n  if(!total || !dirty){ panel.hidden=true; panel.innerHTML=\"\"; pending.hidden=true; return; }\n  pending.hidden=false; pending.textContent=t.codeCount(total);\n\n  const pad=x=>String(x).padStart(2,\"0\");\n  const now=new Date();\n  const block={\n    dataset:DATASET,\n    updated:`${now.getFullYear()}-${pad(now.getMonth()+1)}-${pad(now.getDate())}`,\n    prices:draft.prices,\n    public:draft.pub,\n    overrides:draft.edited,\n    extra:added\n  };\n  const code='<pre id=\"claimont-data\">\\n'+JSON.stringify(block,null,1)+'\\n<\/pre>';\n  panel.hidden=false;\n  panel.innerHTML=`<div class=\"codewrap\">\n    <div class=\"codehd\"><span class=\"t\">${t.codeTitle2}<\/span><span class=\"n\">${t.codeCount(total)}<\/span>\n      ${may(\"products_publish\")?`<button class=\"btn btn-primary\" id=\"btn-publish\">${t.pubNow}<\/button>`:\"\"}\n      <button class=\"btn\" id=\"btn-copy\">${t.copy}<\/button><\/div>\n    <div class=\"codebody\">\n      <p>${may(\"products_publish\")?t.pubHelp:t.pubHelpStaff}<\/p>\n      <div class=\"pubmsg\" id=\"pubmsg\" hidden><\/div>\n      <details class=\"pubfall\"><summary>${t.pubManual}<\/summary>\n        <p>${t.codeHelp2}<\/p>\n        <textarea id=\"codebox\" readonly spellcheck=\"false\"><\/textarea><\/details>\n    <\/div><\/div>`;\n  $(\"#codebox\").value=code;\n  if($(\"#btn-publish\")) $(\"#btn-publish\").addEventListener(\"click\",publishToEveryone);\n  $(\"#btn-copy\").addEventListener(\"click\",()=>{\n    const box=$(\"#codebox\");\n    box.select(); box.setSelectionRange(0,box.value.length);\n    let done=false;\n    try{ done=document.execCommand(\"copy\"); }catch(e){}\n    if(navigator.clipboard&&!done) navigator.clipboard.writeText(box.value).catch(()=>{});\n    $(\"#btn-copy\").textContent=T[lang].copied;\n    setTimeout(()=>{ $(\"#btn-copy\").textContent=T[lang].copy; },1800);\n  });\n}\n\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 sign-in \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\nlet signing=false;\n\/* \u2500\u2500 the mobile wizard: Shipment \u2192 Products \u2192 Desk (same flow as the customer portal) \u2500\u2500 *\/\nlet mstep=1, wizOn=null;\nconst isPhone=()=>window.matchMedia(\"(max-width:860px)\").matches;\nfunction setMStep(n,noScroll){\n  mstep=Math.max(1,Math.min(3,n));\n  document.body.classList.remove(\"mstep-1\",\"mstep-2\",\"mstep-3\");\n  document.body.classList.add(\"mstep-\"+mstep);\n  const t=T[lang];\n  $(\"#mw-lbl\").textContent=`${mstep}\/3 \u00b7 ${t.mwSteps[mstep-1]}`;\n  [...document.querySelectorAll(\".mwdots span\")].forEach((d,i)=>d.classList.toggle(\"on\",i<mstep));\n  $(\"#mw-back\").disabled = mstep===1;\n  $(\"#mw-next\").hidden = mstep===3;\n  $(\"#mw-next\").innerHTML = t.mwNext;\n  if(!noScroll) window.scrollTo(0,0);\n  renderStats();\n}\nfunction applyWizard(){\n  const on = isPhone() && !$(\"#app\").hidden;\n  if(on===wizOn) return;   \/* phone URL bars fire resize mid-scroll \u2014 ignore *\/\n  wizOn=on;\n  document.body.classList.toggle(\"mwiz\",on);\n  $(\"#mwnav\").hidden=!on;\n  if(!on) $(\"#fitbar\").hidden=true;\n  if(on) setMStep(mstep,true);\n}\n$(\"#mw-back\").addEventListener(\"click\",()=>setMStep(mstep-1));\n$(\"#mw-next\").addEventListener(\"click\",()=>setMStep(mstep+1));\nwindow.addEventListener(\"resize\",()=>{ clearTimeout(window.__mwR); window.__mwR=setTimeout(applyWizard,150); });\n\nasync function signIn(){\n  const t=T[lang], v=$(\"#g-code\").value.trim().toUpperCase();\n  const err=$(\"#g-err\"), btn=$(\"#g-go\");\n  if(!v){ err.textContent=t.gEmpty; return; }\n  if(signing) return;\n  signing=true; btn.disabled=true; btn.textContent=t.gChecking; err.textContent=\"\";\n  try{\n    \/* one round trip: sign-in, settings, catalogue changes, threads and the bell *\/\n    let r=await api({action:\"bootStaff\", code:v});\n    if(r && !r.ok && r.error===\"unknown_action\") r=await api({action:\"signin\", code:v});\n    const g=(r&&r.signin)?r.signin:r;\n    if(!g||!g.ok){ err.textContent=t.gBad; return; }\n    const bootS=(r&&r.signin)?r:null;\n    me={code:v, name:g.name||\"\", role:g.role||\"user\", ref:g.ref||\"\",\n        can:g.can||{}, maxDiscount:g.maxDiscount};\n    try{ sessionStorage.setItem(\"claimont-staff\",v); }catch(e){}\n    $(\"#gate\").hidden=true; $(\"#gate\").style.display=\"none\";\n    $(\"#app\").hidden=false;\n    me.maxDiscount = Number(g.maxDiscount)||0;\n    checkVersion(g.version);\n    $(\"#btn-users\").hidden = !may(\"staff_manage\");\n    applyCompact(); applyLang(); applyRole();\n    if(bootS){\n      settings=bootS.settings||{}; renderCatAdmin();\n      try{ applySharedData(bootS.data); }catch(e){ loadSharedPage(); }\n      seedThreads(bootS.threads); seedFeed(bootS.feed);\n      loadRail();\n    }else{\n      loadShared(); loadRail(); loadFeed(); loadThreads(); loadSettings();\n    }\n    loadImages();\n    mstep=1; wizOn=null; applyWizard();\n    \/* a quiet poll \u2014 the sheet stays the source of truth, this only refreshes the bell *\/\n    clearInterval(window.__feedTimer);\n    window.__feedTimer = setInterval(()=>{ loadFeed(); loadThreads(); }, 90000);   \/\/ the FX rate loads on page load\n  }catch(e){ err.textContent = e && e.message===\"no_endpoint\" ? t.gUnset : t.gOffline; }\n  finally{ signing=false; btn.disabled=false; btn.textContent=t.gGo; }\n}\n$(\"#g-go\").addEventListener(\"click\",signIn);\n$(\"#g-code\").addEventListener(\"keydown\",e=>{ if(e.key===\"Enter\") signIn(); });\n$(\"#g-en\").addEventListener(\"click\",()=>{lang=\"en\";applyLang();});\n$(\"#g-tr\").addEventListener(\"click\",()=>{lang=\"tr\";applyLang();});\n\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 my customers rail \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\nlet railCusts=[], railOpen={};\n\/* ---------- the catalogue file --------------------------------------------\n   An admin replaces the PDF from here. It goes to the service, which keeps it\n   in Drive and records the address, so the customer portal links to the new\n   edition without anyone editing WordPress. *\/\nlet settings={};\nconst CAT_MAX_MB = 22;\n\nfunction loadSettings(){\n  return api({action:\"getSettings\"})\n    .then(r=>{ if(r&&r.ok){ settings=r.settings||{}; renderCatAdmin(); } })\n    .catch(()=>{});\n}\nconst DOCS=[[\"images\",\"docImages\"],[\"catalogue\",\"docCatalogue\"],[\"pricePdf\",\"docPricePdf\"],[\"priceXlsx\",\"docPriceXlsx\"]];\nfunction renderCatAdmin(){\n  const t=T[lang], box=$(\"#catadmin\");\n  box.hidden = !may(\"settings_manage\");\n  if(box.hidden) return;\n  $(\"#catadmin-lb\").textContent=t.catAdmin;\n  $(\"#catadmin-alt\").textContent=t.catByUrl;\n  $(\"#catadmin-urllb\").textContent=t.catUrlLb;\n  $(\"#catadmin-pageslb\").textContent=t.catPagesLb;\n  $(\"#catadmin-save\").textContent=t.catSave;\n  $(\"#caturl\").value=settings.catalogueUrl||\"\";\n  $(\"#catpages\").value=settings.cataloguePagesUrl||\"\";\n  DOCS.forEach(([kind,label])=>{\n    $(\"#docpick-\"+kind).textContent=t.catUpload;\n    const url=settings[kind+\"Url\"], name=settings[kind+\"Name\"], up=settings[kind+\"Updated\"];\n    $(\"#doccur-\"+kind).innerHTML = `<b>${t[label]}<\/b><br>` + (url\n      ? `${esc(name||\"\")} \u00b7 <a href=\"${esc(url)}\" target=\"_blank\" rel=\"noopener\">${t.catOpenCur}<\/a>`\n        + (up?` <span class=\"muted\">\u00b7 ${esc(String(up).slice(0,10))}<\/span>`:\"\")\n      : `<span class=\"muted\">${kind===\"images\"?t.imgNone:t.catNone}<\/span>`);\n  });\n}\nfunction catMsg(text,kind){\n  const el=$(\"#catadmin-msg\");\n  el.hidden=false; el.className=\"catmsg\"+(kind?\" \"+kind:\"\"); el.textContent=text;\n}\nasync function uploadDoc(kind, file){\n  const t=T[lang];\n  if(!file) return;\n  const okType = kind===\"priceXlsx\" ? \/\\.xlsx$\/i.test(file.name)\n               : kind===\"images\"     ? \/\\.(csv|txt|json)$\/i.test(file.name)\n               : (\/pdf$\/i.test(file.name) || file.type===\"application\/pdf\");\n  if(!okType){ catMsg(kind===\"priceXlsx\"? t.catNotXlsx : kind===\"images\"? t.catNotImg : t.catNotPdf,\"bad\"); return; }\n  const mb=file.size\/1048576;\n  if(mb*1.37 > CAT_MAX_MB){ catMsg(t.catTooBig.replace(\"{mb}\",Math.round(mb)),\"bad\"); return; }\n\n  const prog=$(\"#catadmin-prog\"), bar=prog.querySelector(\"span\"), pc=$(\"#catadmin-pc\");\n  prog.hidden=false; bar.style.width=\"8%\"; pc.textContent=t.catReading;\n  catMsg(t.catSending);\n  try{\n    const b64=await new Promise((res,rej)=>{\n      const rd=new FileReader();\n      rd.onerror=()=>rej();\n      rd.onprogress=e=>{ if(e.lengthComputable) bar.style.width=Math.round(8+e.loaded\/e.total*32)+\"%\"; };\n      rd.onload=()=>res(String(rd.result).split(\",\")[1]||\"\");\n      rd.readAsDataURL(file);\n    });\n    bar.style.width=\"55%\"; pc.textContent=t.catSending;\n    const r=await api({action:\"uploadDoc\", kind:kind, admin:me.code, name:file.name, b64:b64});\n    if(r && (r.error===\"admin_only\"||r.error===\"not_allowed\")){ catMsg(t.catAdminOnly,\"bad\"); return; }\n    if(!r||!r.ok) throw 0;\n    bar.style.width=\"100%\"; pc.textContent=\"\";\n    settings[kind+\"Url\"]=r.url; settings[kind+\"Name\"]=r.name; settings[kind+\"Updated\"]=r.updated;\n    renderCatAdmin();\n    catMsg(r.replaced? t.catReplaced : t.catUploaded, \"good\");\n  }catch(e){\n    catMsg(t.catFailed,\"bad\");\n  }finally{\n    setTimeout(()=>{ $(\"#catadmin-prog\").hidden=true; },1200);\n  }\n}\n\n\/* ---------- messages ------------------------------------------------------\n   A list of conversations, each opening into the thread with that customer.\n   Same Messages tab the customer portal writes into. *\/\nlet threads=[], msgOpenRef=\"\", msgs=[], msgSending=false;\n\nfunction seedThreads(r){\n  if(!r||!r.ok) return;\n  threads=r.threads||[];\n  if(!msgOpenRef) renderThreads();\n  renderMsgCount();\n}\nasync function loadThreads(){\n  try{ seedThreads(await api({action:\"listThreads\", admin:me.code})); }catch(e){}\n}\nfunction renderMsgCount(){\n  const n=threads.reduce((a,t)=>a+(t.unread||0),0);\n  $(\"#msgn\").hidden=!n; $(\"#msgn\").textContent=n>99?\"99+\":n;\n}\nfunction renderThreads(){\n  const t=T[lang];\n  msgOpenRef=\"\";\n  $(\"#msglbl\").textContent=t.messages;\n  $(\"#msg-back\").hidden=true;\n  $(\"#msgform\").hidden=true;\n  $(\"#msgbody\").innerHTML = threads.length ? threads.map(th=>`\n    <button class=\"threadrow\" data-ref=\"${esc(th.ref)}\">\n      <span class=\"tn\">${th.unread?`<span class=\"dotu\"><\/span>`:\"\"}${esc(th.customer)}<\/span>\n      <span class=\"tl\">${th.lastFrom===\"staff\"?t.msgYouShort+\": \":\"\"}${esc(th.last)}<\/span>\n      <span class=\"tw\">${esc(String(th.when).slice(5,16))}<\/span>\n    <\/button>`).join(\"\") : `<div class=\"msgempty\">${t.msgNoThreads}<\/div>`;\n}\nasync function openThread(ref){\n  const t=T[lang];\n  msgOpenRef=ref;\n  const th=threads.find(x=>x.ref===ref);\n  $(\"#msglbl\").textContent = th ? th.customer : t.messages;\n  $(\"#msg-back\").hidden=false;\n  $(\"#msgform\").hidden=false;\n  $(\"#msgbody\").innerHTML=`<div class=\"msgempty\">${t.loadingList}<\/div>`;\n  try{\n    const r=await api({action:\"listMessages\", admin:me.code, ref:ref});\n    if(!r||!r.ok) throw 0;\n    msgs=r.messages||[];\n    renderThreadBody();\n    if(r.unread){\n      await api({action:\"readMessages\", admin:me.code, ref:ref});\n      const hit=threads.find(x=>x.ref===ref); if(hit) hit.unread=0;\n      renderMsgCount();\n    }\n  }catch(e){ $(\"#msgbody\").innerHTML=`<div class=\"msgempty\">${t.listFailed}<\/div>`; }\n}\nfunction renderThreadBody(){\n  const t=T[lang], body=$(\"#msgbody\");\n  body.innerHTML = msgs.length ? msgs.map(m=>`\n    <div class=\"bub ${m.from===\"staff\"?\"mine\":\"\"}\">${esc(m.text)}\n      <span class=\"meta\">${m.from===\"staff\"?esc(m.author||t.msgYouShort):esc(m.author||\"\")} \u00b7 ${esc(String(m.when).slice(5,16))}<\/span>\n    <\/div>`).join(\"\") : `<div class=\"msgempty\">${t.msgEmptyThread}<\/div>`;\n  body.scrollTop=body.scrollHeight;\n}\nasync function sendMessage(){\n  const box=$(\"#msgtext\"), text=box.value.trim(), t=T[lang];\n  if(!text || !msgOpenRef || msgSending) return;\n  msgSending=true; $(\"#msgsend\").disabled=true;\n  try{\n    const r=await api({action:\"sendMessage\", admin:me.code, ref:msgOpenRef, text:text});\n    if(!r||!r.ok) throw 0;\n    box.value=\"\";\n    await openThread(msgOpenRef);\n    loadThreads();\n  }catch(e){ box.placeholder=t.msgFailed; }\n  finally{ msgSending=false; $(\"#msgsend\").disabled=false; }\n}\n\/* start a conversation with a customer who has never written *\/\nfunction messageCustomer(ref, name){\n  if(!threads.some(x=>x.ref===ref))\n    threads.unshift({ref:ref, customer:name||ref, unread:0, last:\"\", lastFrom:\"\", when:\"\"});\n  openThread(ref);\n  $(\"#msgtext\").focus();\n}\n\n\/* ---- collapse \/ expand the conversation panel ---- *\/\nconst MSGFOLD_KEY=\"claimont-msgfold\";\nfunction setMsgFold(on,save){\n  const side=document.getElementById(\"msgside\");\n  if(!side) return;\n  side.classList.toggle(\"folded\",!!on);\n  const btn=document.getElementById(\"msgfold\");\n  if(btn){\n    btn.setAttribute(\"aria-expanded\",on?\"false\":\"true\");\n    btn.setAttribute(\"aria-label\", on ? T[lang].msgExpand : T[lang].msgCollapse);\n  }\n  if(save){ try{ localStorage.setItem(MSGFOLD_KEY,on?\"1\":\"0\"); }catch(e){} }\n}\n(function(){ try{ if(localStorage.getItem(MSGFOLD_KEY)===\"1\")\n  document.addEventListener(\"DOMContentLoaded\",()=>setMsgFold(true,false)); }catch(e){} })();\n\/* ---------- activity bell -------------------------------------------------\n   The backend keeps the log; the portal remembers the timestamp of the newest\n   line this person has already seen, so a refresh does not re-flag old news. *\/\nlet feedItems=[], feedSeen=\"\", railDrafts=[];\n\/* What this person may do, as the service reported it. The portal hides what\n   they cannot do; the service refuses it regardless, so this is presentation. *\/\nfunction may(what){ return !!(me.can && me.can[what]); }\nfunction applyRole(){\n  const t=T[lang];\n  $(\"#btn-users\").hidden      = !may(\"staff_manage\");\n  $(\"#btn-master\").hidden     = !may(\"products_edit\");\n  $(\"#btn-add\").hidden        = !may(\"products_edit\");\n  if(master && !may(\"products_edit\")) setMaster(false);\n  $(\"#who\").innerHTML = me.name\n    ? `${esc(me.name)} <span class=\"role\">${esc(t.roles[me.role]||me.role||\"\")}<\/span>` : \"\";\n  renderCatAdmin();\n}\nconst SEEN_KEY=\"claimont-feed-seen\";\ntry{ feedSeen = sessionStorage.getItem(SEEN_KEY) || localStorage.getItem(SEEN_KEY) || \"\"; }catch(e){}\n\nfunction feedUnread(){ return feedItems.filter(a=>String(a.when)>feedSeen).length; }\nfunction renderBell(){\n  const t=T[lang], n=feedUnread(), badge=$(\"#belln\");\n  badge.hidden = n===0; badge.textContent = n>99?\"99+\":n;\n  $(\"#bell-title\").textContent=t.activity;\n  $(\"#bell-clear\").textContent=t.markRead;\n  const label={order:t.actOrder, draft:t.actDraft, \"portal-first-open\":t.actFirst, \"portal-open\":t.actOpen, message:t.actMsg};\n  const tag  ={order:\"tag-order\", draft:\"tag-draft\", \"portal-first-open\":\"tag-open\", \"portal-open\":\"tag-open\", message:\"tag-msg\"};\n  $(\"#bell-body\").innerHTML = feedItems.length ? feedItems.map(a=>`\n    <button class=\"actcard ${String(a.when)>feedSeen?\"unread\":\"\"}\" data-ev=\"${esc(a.event)}\"\n            data-ref=\"${esc(a.ref||\"\")}\" data-detail=\"${esc(a.detail||\"\")}\">\n      <span class=\"who\"><span class=\"tagd ${tag[a.event]||\"tag-open\"}\">${esc(label[a.event]||a.event)}<\/span>${esc(a.name||a.ref||\"\")}<\/span>\n      ${a.detail?`<span class=\"what\">${esc(a.detail)}<\/span>`:\"\"}\n      <span class=\"when\">${esc(a.when)}<\/span>\n    <\/button>`).join(\"\") : `<div class=\"railempty\">${t.noActivity}<\/div>`;\n}\nfunction seedFeed(r){\n  if(!r||!r.ok) return;\n  feedItems=r.items||[];\n  if(!feedSeen && r.newest){ feedSeen=r.newest; saveSeen(); }   \/\/ first run: start quiet\n  renderBell();\n}\nasync function loadFeed(){\n  try{ seedFeed(await api({action:\"feed\", admin:me.code, since:\"\"})); }catch(e){}\n}\nfunction saveSeen(){ try{ localStorage.setItem(SEEN_KEY,feedSeen); }catch(e){} }\nfunction openBell(on){\n  const panel=$(\"#bellpanel\");\n  panel.hidden = on===false ? true : (on===true ? false : !panel.hidden);\n  $(\"#btn-bell\").setAttribute(\"aria-expanded\", panel.hidden?\"false\":\"true\");\n}\n\/* clicking an entry takes you to the thing it is about *\/\nasync function openActivity(ev, ref, detail){\n  openBell(false);\n  if(ev===\"order\"){\n    const id=String(detail||\"\").split(\" \")[0];\n    if(id) return showOrder(id);\n  }\n  if(ev===\"draft\") return showDraft(ref);\n  if(ev===\"message\") return messageCustomer(ref, (feedItems.find(f=>f.ref===ref)||{}).name);\n  if(ref){ railOpen[ref]=false; return toggleCustomerOrders(ref); }\n}\nasync function showDraft(ref){\n  const t=T[lang];\n  $(\"#past-title\").textContent=t.draftTitle;\n  $(\"#past-body\").innerHTML=`<div class=\"railempty\">${t.loadingList}<\/div>`;\n  $(\"#pastsheet\").classList.add(\"on\"); document.body.style.overflow=\"hidden\";\n  try{\n    const r=await api({action:\"draftDetail\", admin:me.code, ref:ref});\n    if(!r||!r.ok) throw 0;\n    const d=r.draft, line=(k,v)=>v?`<dt>${k}<\/dt><dd>${esc(v)}<\/dd>`:\"\";\n    $(\"#past-body\").innerHTML=`\n      <div class=\"railempty draftline\">${t.draftNote}<\/div>\n      <dl class=\"clist\">\n        ${line(t.oWhen,d.updated)}${line(t.reg.customer,d.customer)}${line(t.oCompany,d.company)}\n        ${line(t.oContact,d.contact)}${line(t.oEmail,d.email)}${line(t.oPhone,d.phone)}\n        ${line(t.oCountry,d.country)}${line(t.loading,d.loading)}${line(t.fNotes,d.notes)}\n        <dt>${t.stats.cartons}<\/dt><dd>${fmt(d.cartons)}<\/dd>\n        <dt>${t.stats.cbm}<\/dt><dd>${fmt(d.cbm,2)} m\u00b3<\/dd>\n        <dt>${t.stats.gross}<\/dt><dd>${fmt(d.grossKg,1)} kg<\/dd>\n        <dt>${t.stats.usd}<\/dt><dd class=\"total\">$${fmt(d.totalUSD,2)}<\/dd>\n      <\/dl>\n      <div class=\"regwrap\" style=\"margin-top:14px\"><table class=\"regtbl\">\n        <thead><tr><th>#<\/th><th>${t.cols.ref}<\/th><th>${t.cols.name}<\/th><th class=\"n\">${t.cols.qty}<\/th>\n          <th class=\"n\">${t.cols.units}<\/th><th class=\"n\">${t.cols.tusd}<\/th><\/tr><\/thead>\n        <tbody>${(d.items||[]).map(i=>`<tr><td>${esc(i.id)}<\/td><td class=\"code\">${esc(lineRef(i))}<\/td><td>${esc(i.name)}<\/td>\n          <td class=\"n\">${fmt(i.cartons)}<\/td><td class=\"n\">${fmt(i.units)}<\/td>\n          <td class=\"n\">$${fmt(i.total,2)}<\/td><\/tr>`).join(\"\")}<\/tbody><\/table><\/div>`;\n  }catch(e){ $(\"#past-body\").innerHTML=`<div class=\"railempty\">${t.listFailed}<\/div>`; }\n}\n\nfunction loadRail(){\n  return api({action:\"listCustomers\", admin:me.code})\n    .then(r=>{\n      if(!r||!r.ok) throw 0;\n      if(r.you && typeof r.you.maxDiscount===\"number\") me.maxDiscount=r.you.maxDiscount;\n      const all=r.customers||[];\n      api({action:\"listDrafts\", admin:me.code})\n        .then(dr=>{ if(dr&&dr.ok){ railDrafts=dr.drafts||[]; renderRail(); } })\n        .catch(()=>{});\n      \/\/ the service already scopes the list: admins get everyone (with owner),\n      \/\/ users and super users get only the customers they created\n      railCusts = all;\n      renderRail();\n    })\n    .catch(()=>{ $(\"#rail-body\").innerHTML=`<div class=\"railempty\">${T[lang].listFailed}<\/div>`; });\n}\nfunction renderRail(){\n  const t=T[lang];\n  $(\"#rail-title\").innerHTML=`${t.myCustomers} <span class=\"railcount\">${railCusts.length}<\/span>`;\n  $(\"#btn-rail\").innerHTML=`${t.myCustomers} <span class=\"n\">${railCusts.length}<\/span>`;\n  if(!railCusts.length){ $(\"#rail-body\").innerHTML=`<div class=\"railempty\">${t.noCustomers}<\/div>`; return; }\n  $(\"#rail-body\").innerHTML=railCusts.map(c=>`\n    <div>\n      <button class=\"custcard ${c.active?\"\":\"off\"}\" data-ref=\"${esc(c.ref)}\">\n        <span class=\"cn\">${esc(c.name)}<\/span>\n        <span class=\"cmeta\">\n          <span class=\"pill ${c.orders?\"has\":\"\"}\">${fmt(c.orders)} ${t.ordersWord}<\/span>\n          ${c.discount?`<span class=\"pill disc\">\u2212${fmt(c.discount, c.discount%1?1:0)}%<\/span>`:\"\"}\n          ${me.role===\"admin\"&&c.owner?`<span class=\"pill owner\">${esc(c.owner)}<\/span>`:\"\"}\n          ${railDrafts.some(d=>d.ref===c.ref)?`<span class=\"pill draft\">${t.draftPill}<\/span>`:\"\"}\n          <span>${c.lastOrder?esc(String(c.lastOrder).slice(0,10)):t.never}<\/span>\n        <\/span>\n      <\/button>\n      <button class=\"linkbtn msgstart\" data-msg=\"${esc(c.ref)}\" data-name=\"${esc(c.name)}\">${t.msgWrite}<\/button>\n      ${railDrafts.filter(d=>d.ref===c.ref).map(d=>`\n        <button class=\"ordercard draftcard\" data-draft=\"${esc(c.ref)}\">\n          <span class=\"oid2\">${t.draftPill}<\/span><br>\n          <span class=\"when\">${esc(d.updated)}<\/span><br>\n          <span class=\"amt\">$${fmt(d.totalUSD,2)}<\/span>\n          <span class=\"when\">\u00b7 ${fmt(d.cartons)} ${t.cartonsWord}<\/span>\n        <\/button>`).join(\"\")}\n      <div class=\"olist\" id=\"ol-${esc(c.ref)}\" hidden><\/div>\n    <\/div>`).join(\"\");\n}\nasync function toggleCustomerOrders(ref){\n  const box=$(\"#ol-\"+ref), t=T[lang];\n  if(railOpen[ref]){ box.hidden=true; railOpen[ref]=false; return; }\n  railOpen[ref]=true; box.hidden=false;\n  box.innerHTML=`<div class=\"railempty\">${t.loadingList}<\/div>`;\n  try{\n    const r=await api({action:\"listOrders\", admin:me.code, ref:ref});\n    if(!r||!r.ok) throw 0;\n    box.innerHTML = r.orders.length ? r.orders.map(o=>`\n      <button class=\"ordercard\" data-oid=\"${esc(o.orderId)}\">\n        <span class=\"oid2\">${esc(o.orderId)}<\/span><br>\n        <span class=\"when\">${esc(o.when)}<\/span><br>\n        <span class=\"amt\">$${fmt(o.totalUSD,2)}<\/span>\n        <span class=\"when\">\u00b7 ${fmt(o.cartons)} ${t.cartonsWord}<\/span>\n      <\/button>`).join(\"\") : `<div class=\"railempty\">${t.noOrdersYet}<\/div>`;\n  }catch(e){ box.innerHTML=`<div class=\"railempty\">${t.listFailed}<\/div>`; }\n}\n\/* every report shows the product reference: from the stored line if it has one,\n   else looked up from the current list by product number *\/\nfunction lineRef(it){\n  if(it && it.ref!=null && String(it.ref)!==\"\") return String(it.ref);\n  const d=DATA.find(x=>x.id===it.id);\n  return d?String(d.ref):\"\";\n}\nasync function showOrder(id){\n  const t=T[lang];\n  $(\"#past-title\").textContent=id;\n  $(\"#past-body\").innerHTML=`<div class=\"railempty\">${t.loadingList}<\/div>`;\n  $(\"#pastsheet\").classList.add(\"on\"); document.body.style.overflow=\"hidden\";\n  try{\n    const r=await api({action:\"orderDetail\", admin:me.code, orderId:id});\n    if(!r||!r.ok) throw 0;\n    const o=r.order, line=(k,v)=>v?`<dt>${k}<\/dt><dd>${esc(v)}<\/dd>`:\"\";\n    $(\"#past-body\").innerHTML=`\n      <dl class=\"clist\">\n        ${line(t.oWhen,o.when)}${line(t.reg.customer,o.customer)}${line(t.oCompany,o.company)}\n        ${line(t.oContact,o.contact)}${line(t.oEmail,o.email)}${line(t.oPhone,o.phone)}\n        ${line(t.oCountry,o.country)}${line(t.loading,o.loading)}\n        <dt>${t.stats.cartons}<\/dt><dd>${fmt(o.cartons)}<\/dd>\n        <dt>${t.stats.cbm}<\/dt><dd>${fmt(o.cbm,2)} m\u00b3<\/dd>\n        <dt>${t.stats.gross}<\/dt><dd>${fmt(o.grossKg,1)} kg<\/dd>\n        <dt>${t.stats.usd}<\/dt><dd class=\"total\">${o.discount?`<span class=\"was2\">$${fmt(o.listUSD,2)}<\/span>`:\"\"}$${fmt(o.totalUSD,2)}${o.discount?` (\u2212${fmt(o.discount,o.discount%1?1:0)}%)`:\"\"}<\/dd>\n      <\/dl>\n      <div class=\"regwrap\" style=\"margin-top:14px\"><table class=\"regtbl\">\n        <thead><tr><th>#<\/th><th>${t.cols.ref}<\/th><th>${t.cols.name}<\/th><th class=\"n\">${t.cols.g}<\/th>\n          <th class=\"n\">${t.cols.qty}<\/th><th class=\"n\">${t.cols.units}<\/th>\n          <th class=\"n\">${t.cols.pc}<\/th><th class=\"n\">${t.cols.tusd}<\/th><\/tr><\/thead>\n        <tbody>${(o.items||[]).map(it=>`<tr><td>${it.id}<\/td><td class=\"code\">${esc(lineRef(it))}<\/td><td>${esc(it.name)}<\/td>\n          <td class=\"n\">${fmt(it.g)} g<\/td><td class=\"n\">${fmt(it.cartons)}<\/td>\n          <td class=\"n\">${fmt(it.units)}<\/td><td class=\"n\">$${fmt(it.cartonUSD,2)}<\/td>\n          <td class=\"n\">$${fmt(it.total,2)}<\/td><\/tr>`).join(\"\")}<\/tbody><\/table><\/div>\n      ${o.notes?`<p style=\"margin-top:12px\"><strong>${t.oNotes}:<\/strong> ${esc(o.notes)}<\/p>`:\"\"}\n      <div style=\"margin-top:14px\"><button class=\"btn btn-primary\" id=\"past-pdf\">${t.pdfBtn}<\/button><\/div>`;\n    $(\"#past-pdf\").addEventListener(\"click\",e=>orderPdfDownload(id,e.target));\n  }catch(e){ $(\"#past-body\").innerHTML=`<div class=\"railempty\">${t.listFailed}<\/div>`; }\n}\n\/* the same PDF that rides on the order email, fetched on demand *\/\nasync function orderPdfDownload(id,btn){\n  const t=T[lang], was=btn.textContent;\n  btn.disabled=true; btn.textContent=t.pdfWait;\n  try{\n    const r=await api({action:\"orderPdf\", admin:me&&me.code, code:(typeof unlockCode!==\"undefined\"&&unlockCode)||undefined, orderId:id});\n    if(!r||!r.ok||!r.b64) throw 0;\n    const a=document.createElement(\"a\");\n    a.href=\"data:application\/pdf;base64,\"+r.b64;\n    a.download=r.name||(\"Claimont order \"+id+\".pdf\");\n    document.body.appendChild(a); a.click(); a.remove();\n    btn.textContent=was;\n  }catch(e){ btn.textContent=t.pdfFailed; setTimeout(()=>{btn.textContent=was;},4000); }\n  finally{ btn.disabled=false; }\n}\n$(\"#btn-rail\").addEventListener(\"click\",()=>$(\"#rail\").classList.toggle(\"on\"));\n$(\"#rail-x\").addEventListener(\"click\",()=>$(\"#rail\").classList.remove(\"on\"));\n$(\"#rail-body\").addEventListener(\"click\",e=>{\n  const oc=e.target.closest(\".ordercard\");\n  if(oc){ $(\"#rail\").classList.remove(\"on\"); showOrder(oc.dataset.oid); return; }\n  const ms=e.target.closest(\".msgstart\");\n  if(ms){ messageCustomer(ms.dataset.msg, ms.dataset.name); return; }\n  const cc=e.target.closest(\".custcard\");\n  if(cc) toggleCustomerOrders(cc.dataset.ref);\n});\n$(\"#past-x\").addEventListener(\"click\",()=>{ $(\"#pastsheet\").classList.remove(\"on\"); document.body.style.overflow=\"\"; });\n$(\"#pastsheet\").addEventListener(\"click\",e=>{ if(e.target.id===\"pastsheet\"){ $(\"#pastsheet\").classList.remove(\"on\"); document.body.style.overflow=\"\"; }});\n\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 customer + staff registry \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\nlet regMode=\"customers\", regRows=[], regEditing=null;\nconst CUST_COLS=[[\"ref\",\"ref\"],[\"code\",\"code\"],[\"name\",\"customer\"],[\"rep\",\"rep\"],[\"discount\",\"discount\"],\n  [\"active\",\"status\"],[\"opens\",\"opens\"],[\"lastAccess\",\"lastAccess\"],[\"orders\",\"orders\"],[\"lastOrder\",\"lastOrder\"]];\nconst USER_COLS=[[\"ref\",\"ref\"],[\"code\",\"code\"],[\"name\",\"staffName\"],[\"role\",\"role\"],[\"email\",\"userEmail\"],[\"phone\",\"userPhone\"],[\"maxDiscount\",\"maxDisc\"],[\"active\",\"status\"],[\"created\",\"created\"]];\n\nlet regView=\"active\";\nasync function openRegistry(mode){\n  regMode=mode; regEditing=null; regView=\"active\";\n  const t=T[lang];\n  $(\"#reg-title\").textContent = mode===\"customers\" ? t.regCustomers : t.regUsers;\n  $(\"#regsheet\").classList.add(\"on\"); document.body.style.overflow=\"hidden\";\n  showRegList();\n  $(\"#reg-status\").textContent=t.loadingList;\n  try{\n    const r=await api({action: mode===\"customers\"?\"listCustomers\":\"listUsers\", admin:me.code,\n                      includeArchived:may(\"customers_archive\")});\n    if(!r||!r.ok) throw 0;\n    regRows = mode===\"customers\" ? r.customers : r.users;\n    renderRegistry();\n    $(\"#reg-status\").textContent=\"\";\n  }catch(e){\n    $(\"#reg-status\").textContent=\"\";\n    $(\"#reg-err\").textContent=T[lang].listFailed;\n  }\n}\nfunction closeRegistry(){ $(\"#regsheet\").classList.remove(\"on\"); document.body.style.overflow=\"\"; }\n\/* Archiving is reversible and says so; nothing here deletes a row. *\/\nasync function archiveEntry(ref,name,restore){\n  const t=T[lang];\n  if(!restore && !confirm(t.archiveAsk.replace(\"{name}\",name||ref))) return;\n  const wasArchView = regView===\"archived\";\n  try{\n    const r=await api({action: regMode===\"customers\"?\"archiveCustomer\":\"archiveUser\",\n                       admin:me.code, ref:ref, restore:!!restore});\n    if(r && r.error===\"not_allowed\"){ $(\"#reg-err\").textContent=t.notAllowed; return; }\n    if(r && r.error===\"last_admin\"){ $(\"#reg-err\").textContent=t.lastAdmin; return; }\n    if(!r||!r.ok) throw 0;\n    staffList=null;                                  \/\/ owner dropdown may have changed\n    await openRegistry(regMode); loadRail();\n    regView = wasArchView ? \"archived\" : \"active\"; renderRegistry();\n  }catch(e){ $(\"#reg-err\").textContent=t.listFailed; }\n}\nfunction showRegList(){\n  $(\"#reg-form\").hidden=true; $(\".regwrap\").hidden=false;\n  $(\"#reg-new\").hidden=false; $(\"#reg-save\").hidden=true; $(\"#reg-back\").hidden=true;\n  $(\"#reg-err\").textContent=\"\";\n}\nfunction showRegForm(){\n  $(\"#reg-form\").hidden=false; $(\".regwrap\").hidden=true; $(\"#reg-empty\").hidden=true;\n  $(\"#reg-new\").hidden=true; $(\"#reg-save\").hidden=false; $(\"#reg-back\").hidden=false;\n}\nfunction renderRegistry(){\n  const t=T[lang];\n  const canArch = regMode===\"customers\" ? may(\"customers_archive\") : may(\"staff_manage\");\n  \/* the archived pile lives behind its own tab \u2014 never mixed into the working list *\/\n  const shown = regRows.filter(r=> regView===\"archived\" ? r.archived : !r.archived);\n  const nArch = regRows.filter(r=>r.archived).length;\n  $(\"#reg-views\").hidden = !canArch;\n  $(\"#reg-v-active\").textContent=t.viewActive;\n  $(\"#reg-v-arch\").textContent=`${t.viewArch}${nArch?` (${nArch})`:\"\"}`;\n  $(\"#reg-v-active\").setAttribute(\"aria-pressed\", regView!==\"archived\");\n  $(\"#reg-v-arch\").setAttribute(\"aria-pressed\", regView===\"archived\");\n  $(\"#reg-new\").hidden = regView===\"archived\";\n  let cols = regMode===\"customers\"?CUST_COLS:USER_COLS;\n  if(regMode===\"customers\" && me.role===\"admin\")\n    cols = cols.flatMap(c=>c[0]===\"rep\"?[c,[\"owner\",\"owner\"]]:c[0]===\"discount\"?[c,[\"moq\",\"moqCol\"]]:[c]);\n  $(\"#reg-head\").innerHTML = cols.map(([k,lbl])=>`<th class=\"${[\"discount\",\"opens\",\"orders\",\"maxDiscount\"].includes(k)?\"n\":\"\"}\">${t.reg[lbl]}<\/th>`).join(\"\")\n    + (canArch ? `<th><\/th>` : \"\");\n  if(!shown.length){ $(\"#reg-body\").innerHTML=\"\"; $(\"#reg-empty\").hidden=false;\n    $(\"#reg-empty\").textContent = regView===\"archived\"?t.regEmptyArch:t.regEmpty; return; }\n  $(\"#reg-empty\").hidden=true;\n  $(\"#reg-body\").innerHTML = shown.map(r=>`<tr class=\"${r.active?\"\":\"off\"} ${r.archived?\"arch\":\"\"}\" data-ref=\"${r.ref}\">`+\n    cols.map(([k])=>{\n      let v=r[k];\n      if(k===\"code\")     return `<td class=\"code\">${esc(v)}<\/td>`;\n      if(k===\"active\")   return `<td><span class=\"tag ${v?\"yes\":\"no\"}\">${v?t.statusOn:t.statusOff}<\/span><\/td>`;\n      if(k===\"maxDiscount\") return `<td class=\"n\">${v?fmt(v,0)+\"%\":`<span class=\"never\">\u2014<\/span>`}<\/td>`;\n      if(k===\"discount\") return `<td class=\"n\">${v?`<span class=\"tag disc\">\u2212${fmt(v, v%1?1:0)}%<\/span>`:`<span class=\"never\">\u2014<\/span>`}<\/td>`;\n      if(k===\"moq\")      return `<td class=\"n\">${v?`<span class=\"tag\">${v} SKU<\/span>`:`<span class=\"never\">\u2014<\/span>`}<\/td>`;\n      if(k===\"opens\"||k===\"orders\") return `<td class=\"n\">${v?fmt(v):`<span class=\"never\">0<\/span>`}<\/td>`;\n      if(k===\"lastAccess\"||k===\"lastOrder\") return `<td>${v?esc(String(v)):`<span class=\"never\">${t.never}<\/span>`}<\/td>`;\n      if(k===\"role\")     return `<td>${esc((t.roles||{})[v]||v||\"\")}<\/td>`;\n      return `<td>${esc(v||\"\")}<\/td>`;\n    }).join(\"\")\n    + (canArch\n        ? `<td class=\"rowact\">${r.archived\n            ? `<button class=\"linkbtn\" data-restore=\"${esc(r.ref)}\">${t.restore}<\/button>`\n            : `<button class=\"linkbtn warn\" data-archive=\"${esc(r.ref)}\" data-name=\"${esc(r.name||r.ref)}\">${t.archive}<\/button>`}<\/td>`\n        : \"\")\n    +`<\/tr>`).join(\"\");\n}\n$(\"#reg-v-active\").addEventListener(\"click\",()=>{ regView=\"active\"; renderRegistry(); });\n$(\"#reg-v-arch\").addEventListener(\"click\",()=>{ regView=\"archived\"; renderRegistry(); });\nlet staffList=null;\nasync function fillOwnerList(selName){\n  const sel=$(\"#rf-owner\");\n  if(!staffList){\n    sel.innerHTML=`<option>\u2026<\/option>`;\n    try{ const r=await api({action:\"listUsers\", admin:me.code});\n         if(r&&r.ok) staffList=(r.users||[]).filter(u=>u.active&&!u.archived); }catch(e){}\n    if(!staffList) staffList=[];\n  }\n  sel.innerHTML=staffList.map(u=>`<option value=\"${esc(u.ref)}\">${esc(u.name)} (${esc((T[lang].roles||{})[u.role]||u.role)})<\/option>`).join(\"\");\n  const hit=staffList.find(u=>String(u.name).trim().toLowerCase()===String(selName||\"\").trim().toLowerCase());\n  if(hit) sel.value=hit.ref;\n}\nfunction openRegForm(ref){\n  const t=T[lang];\n  regEditing = ref ? regRows.find(r=>r.ref===ref) : null;\n  const isCust = regMode===\"customers\";\n  $(\"#rf-legend\").textContent = regEditing ? `${regEditing.ref} \u2014 ${regEditing.code}` : t.regNew;\n  $(\"#rf-name\").value = regEditing? (regEditing.name||\"\") : \"\";\n  $(\"#rf-rep\").value  = regEditing? (regEditing.rep||\"\")  : \"\";\n  $(\"#rf-mail\").value = regEditing? (regEditing.repEmail||\"\") : \"\";\n  $(\"#rf-cphone\").value = regEditing? (regEditing.contactPhone||\"\") : \"\";\n  $(\"#rf-ctitle\").value = regEditing? (regEditing.contactTitle||\"\") : \"\";\n  $(\"#rf-country\").value = regEditing? (regEditing.country||\"\") : \"\";\n  $(\"#rf-l-country\").textContent=t.reg.country;\n  $(\"#rf-l-rep\").textContent=t.reg.rep; $(\"#rf-l-mail\").textContent=t.reg.repMail;\n  $(\"#rf-l-cphone\").textContent=t.reg.cPhone; $(\"#rf-l-ctitle\").textContent=t.reg.cTitle;\n  $(\"#rf-disc\").value = regEditing? (regEditing.discount||0) : 0;\n  const cap = me.role===\"admin\" ? 90 : (me.maxDiscount||0);\n  $(\"#rf-disc\").max = cap;\n  $(\"#rf-l-disc\").innerHTML = `${t.reg.discount} <span class=\"muted\">${t.capNote.replace(\"{n}\",fmt(cap,0))}<\/span>`;\n  $(\"#rf-role\").value = regEditing? (regEditing.role||\"staff\") : \"staff\";\n  $(\"#rf-max\").value  = regEditing? (regEditing.maxDiscount||0) : 0;\n  $(\"#rf-uemail\").value = regEditing? (regEditing.email||\"\") : \"\";\n  $(\"#rf-uphone\").value = regEditing? (regEditing.phone||\"\") : \"\";\n  $(\"#rf-l-uemail\").textContent=t.reg.userEmail; $(\"#rf-l-uphone\").textContent=t.reg.userPhone;\n  $(\"#rf-active\").checked = regEditing ? !!regEditing.active : true;\n  $(\"#rf-l-name\").textContent = isCust ? t.reg.customer : t.reg.staffName;\n  $(\"#rf-rep\").closest(\".f\").hidden = !isCust;\n  $(\"#rf-mail\").closest(\".f\").hidden = !isCust;\n  $(\"#rf-cphone\").closest(\".f\").hidden = !isCust;\n  $(\"#rf-ctitle\").closest(\".f\").hidden = !isCust;\n  $(\"#rf-country\").closest(\".f\").hidden = !isCust;\n  $(\"#rf-disc\").closest(\".f\").hidden = !isCust;\n  $(\"#rf-role\").closest(\".f\").hidden = isCust;\n  $(\"#rf-max\").closest(\".f\").hidden = isCust;\n  $(\"#rf-uemail\").closest(\".f\").hidden = isCust;\n  $(\"#rf-uphone\").closest(\".f\").hidden = isCust;\n  \/* only the admin re-assigns customers or sets a purchase minimum *\/\n  const adminCust = isCust && me.role===\"admin\";\n  $(\"#rf-owner\").closest(\".f\").hidden = !adminCust;\n  $(\"#rf-moq\").closest(\".f\").hidden = !adminCust;\n  if(adminCust){\n    $(\"#rf-l-owner\").textContent=t.reg.ownerSel;\n    $(\"#rf-l-moq\").textContent=t.reg.moqSel;\n    const mo=$(\"#rf-moq\");\n    mo.options[0].textContent=t.moqNone;\n    for(let i=1;i<mo.options.length;i++) mo.options[i].textContent=t.moqOpt.replace(\"{n}\", mo.options[i].value);\n    mo.value=String((regEditing&&regEditing.moq)||0);\n    fillOwnerList(regEditing?regEditing.owner:me.name);\n  }\n  $(\"#rf-newcode\").hidden = !regEditing;\n  if(regEditing){\n    $(\"#rf-code\").textContent = regEditing.code;\n    $(\"#rf-codenote\").textContent = isCust ? t.codeNoteCust : t.codeNoteUser;\n  }\n  $(\"#replist\").innerHTML = [...new Set(regRows.map(r=>r.rep).filter(Boolean))].map(r=>`<option value=\"${esc(r)}\">`).join(\"\");\n  showRegForm();\n  $(\"#rf-name\").focus();\n}\nasync function saveReg(){\n  const t=T[lang], btn=$(\"#reg-save\"), err=$(\"#reg-err\");\n  const name=$(\"#rf-name\").value.trim();\n  if(!name){ err.textContent=t.regNeedName; $(\"#rf-name\").focus(); return; }\n  if(regMode===\"customers\"){\n    \/* a code with nobody's name and address against it is a code nobody chases *\/\n    if(!$(\"#rf-rep\").value.trim()){ err.textContent=t.regNeedRep; $(\"#rf-rep\").focus(); return; }\n    if(!\/^[^@\\s]+@[^@\\s.]+\\.[^@\\s]{2,}$\/.test($(\"#rf-mail\").value.trim())){\n      err.textContent=t.regNeedMail; $(\"#rf-mail\").focus(); return; }\n    if(!$(\"#rf-cphone\").value.trim()){ err.textContent=t.regNeedCPhone; $(\"#rf-cphone\").focus(); return; }\n    if(!$(\"#rf-ctitle\").value.trim()){ err.textContent=t.regNeedCTitle; $(\"#rf-ctitle\").focus(); return; }\n    if(!$(\"#rf-country\").value.trim()){ err.textContent=t.regNeedCountry; $(\"#rf-country\").focus(); return; }\n  }\n  if(regMode!==\"customers\"){\n    \/* users are their customers' direct contact \u2014 no email or phone, no user *\/\n    if(!\/^[^@\\s]+@[^@\\s.]+\\.[^@\\s]{2,}$\/.test($(\"#rf-uemail\").value.trim())){\n      err.textContent=t.regNeedUserMail; $(\"#rf-uemail\").focus(); return; }\n    if(!$(\"#rf-uphone\").value.trim()){ err.textContent=t.regNeedUserPhone; $(\"#rf-uphone\").focus(); return; }\n  }\n  err.textContent=\"\"; btn.disabled=true; btn.textContent=t.saving;\n  const payload = regMode===\"customers\"\n    ? {action:\"saveCustomer\", admin:me.code, ref:regEditing?regEditing.ref:\"\", name,\n       rep:$(\"#rf-rep\").value.trim(), repEmail:$(\"#rf-mail\").value.trim(),\n       contactPhone:$(\"#rf-cphone\").value.trim(), contactTitle:$(\"#rf-ctitle\").value.trim(),\n       country:$(\"#rf-country\").value.trim(),\n       discount:parseFloat($(\"#rf-disc\").value)||0, active:$(\"#rf-active\").checked,\n       ...(me.role===\"admin\"?{owner:$(\"#rf-owner\").value||\"\", moq:parseInt($(\"#rf-moq\").value)||0}:{})}\n    : {action:\"saveUser\", admin:me.code, ref:regEditing?regEditing.ref:\"\", name,\n       email:$(\"#rf-uemail\").value.trim(), phone:$(\"#rf-uphone\").value.trim(),\n       role:$(\"#rf-role\").value, maxDiscount:parseFloat($(\"#rf-max\").value)||0, active:$(\"#rf-active\").checked};\n  try{\n    const r=await api(payload);\n    if(r && r.error===\"over_limit\"){ err.textContent=t.overLimit.replace(\"{n}\",fmt(r.cap,0)); return; }\n    if(r && r.error===\"rep_required\"){ err.textContent=t.regNeedRep; return; }\n    if(r && r.error===\"rep_email_required\"){ err.textContent=t.regNeedMail; return; }\n    if(r && r.error===\"contact_phone_required\"){ err.textContent=t.regNeedCPhone; return; }\n    if(r && r.error===\"contact_title_required\"){ err.textContent=t.regNeedCTitle; return; }\n    if(r && r.error===\"country_required\"){ err.textContent=t.regNeedCountry; return; }\n    if(r && r.error===\"user_email_required\"){ err.textContent=t.regNeedUserMail; return; }\n    if(r && r.error===\"user_phone_required\"){ err.textContent=t.regNeedUserPhone; return; }\n    if(r && r.error===\"not_allowed\"){ err.textContent=t.notAllowed; return; }\n    if(r && r.error===\"last_admin\"){ err.textContent=t.lastAdmin; return; }\n    if(!r||!r.ok) throw 0;\n    if(r.created){\n      $(\"#rf-legend\").textContent=`${r.ref} \u2014 ${r.code}`;\n      $(\"#rf-code\").textContent=r.code;\n      $(\"#rf-codenote\").textContent = regMode===\"customers\"?t.codeNoteCust:t.codeNoteUser;\n      $(\"#rf-newcode\").hidden=false;\n      regEditing={ref:r.ref, code:r.code, name, active:$(\"#rf-active\").checked};\n      err.textContent=\"\";\n      $(\"#reg-status\").textContent=t.createdOk;\n    }else{\n      $(\"#reg-status\").textContent=t.savedOk;\n      showRegList(); loadRail();\n    }\n    const rr=await api({action: regMode===\"customers\"?\"listCustomers\":\"listUsers\", admin:me.code,\n                       includeArchived:may(\"customers_archive\")});\n    if(rr&&rr.ok){ regRows = regMode===\"customers\"?rr.customers:rr.users; renderRegistry(); }\n  }catch(e){ err.textContent=t.saveFailed; }\n  finally{ btn.disabled=false; btn.textContent=t.save2; }\n}\n$(\"#btn-customers\").addEventListener(\"click\",()=>openRegistry(\"customers\"));\n$(\"#btn-users\").addEventListener(\"click\",()=>openRegistry(\"users\"));\n$(\"#reg-x\").addEventListener(\"click\",closeRegistry);\n$(\"#reg-new\").addEventListener(\"click\",()=>openRegForm(null));\n$(\"#reg-back\").addEventListener(\"click\",showRegList);\n$(\"#reg-save\").addEventListener(\"click\",saveReg);\n$(\"#reg-body\").addEventListener(\"click\",e=>{\n  const ar=e.target.closest(\"[data-archive]\");\n  if(ar){ e.stopPropagation(); return archiveEntry(ar.dataset.archive, ar.dataset.name, false); }\n  const rs=e.target.closest(\"[data-restore]\");\n  if(rs){ e.stopPropagation(); return archiveEntry(rs.dataset.restore, \"\", true); }\n  const tr=e.target.closest(\"tr\"); if(!tr || tr.classList.contains(\"arch\")) return;\n  openRegForm(tr.dataset.ref);\n});\n$(\"#regsheet\").addEventListener(\"click\",e=>{ if(e.target.id===\"regsheet\") closeRegistry(); });\n\n$(\"#btn-add\").addEventListener(\"click\",()=>openSheet(null));\n$(\"#btn-pending\").addEventListener(\"click\",()=>{\n  $(\"#codepanel\").scrollIntoView({behavior:\"smooth\",block:\"center\"});\n});\n$(\"#sheet-x\").addEventListener(\"click\",closeSheet);\n$(\"#sheet-cancel\").addEventListener(\"click\",closeSheet);\n$(\"#sheet-save\").addEventListener(\"click\",saveSheet);\n$(\"#sheet-del\").addEventListener(\"click\",removeDraft);\n$(\"#sheet\").addEventListener(\"click\",e=>{ if(e.target.id===\"sheet\") closeSheet(); });\n$(\"#tbody\").addEventListener(\"click\",e=>{\n  const b=e.target.closest(\".rowedit\"); if(!b)return;\n  openSheet(b.dataset.edit);\n});\n\nfunction applyCompact(){\n  if(window.innerWidth<=860){\n    [[\"cg-pack\",\"hide-pack\"],[\"cg-wt\",\"hide-wt\"],[\"cg-comp\",\"hide-comp\"],[\"cg-unit\",\"hide-unit\"]]\n      .forEach(([id,cls])=>{ $(\"#\"+id).checked=false; $(\"#tablewrap\").classList.add(cls); });\n  }\n}\napplyLang();\n(function(){\n  let saved=null;\n  try{ saved=sessionStorage.getItem(\"claimont-staff\"); }catch(e){}\n  if(saved){ $(\"#g-code\").value=saved; signIn(); }\n})();\n<\/script>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>","protected":false},"excerpt":{"rendered":"<p>Claimont Price Desk CLAIMONT Internal \u00b7 Price list Sign in Enter your personal staff code. Sami issues one per person. Sign in English T\u00fcrk\u00e7e CLAIMONT Export Desk USD \u2192 EUR 0 Activity Mark all read Sign out EN TR Columns Detail groups Packing &amp; dimensions Weights Codes &amp; storage Unit prices Order totals My customers [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_joinchat":[],"footnotes":""},"class_list":["post-4858","page","type-page","status-publish","hentry"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":8}},"_links":{"self":[{"href":"https:\/\/claimont.com\/tr\/wp-json\/wp\/v2\/pages\/4858","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/claimont.com\/tr\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/claimont.com\/tr\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/claimont.com\/tr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/claimont.com\/tr\/wp-json\/wp\/v2\/comments?post=4858"}],"version-history":[{"count":64,"href":"https:\/\/claimont.com\/tr\/wp-json\/wp\/v2\/pages\/4858\/revisions"}],"predecessor-version":[{"id":5507,"href":"https:\/\/claimont.com\/tr\/wp-json\/wp\/v2\/pages\/4858\/revisions\/5507"}],"wp:attachment":[{"href":"https:\/\/claimont.com\/tr\/wp-json\/wp\/v2\/media?parent=4858"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}