{
  "version": 3,
  "sources": ["/cdn/shop/t/1064/assets/nt-artwork-data.js?auto=format%2Ccompress"],
  "sourcesContent": ["/* ============================================================================\n   nt-artwork-data.js \u2014 SHARED ARTWORK LIBRARY DATA LAYER\n\n   The customer's artwork feed (uploads + purchases), normalised, deduped and\n   session-cached. Extracted so the v2 Artwork Library modal\n   (snippets/artwork-library-v2.liquid) does not fork the data logic that\n   snippets/my-designs-panel.liquid has accumulated.\n\n   \u26A0 MIGRATION NOTE: my-designs-panel.liquid still carries its OWN copy of this\n   logic. That is deliberate for now \u2014 v2 is opt-in and must not be able to\n   regress the live picker/portal surfaces while it is being iterated on. When\n   v2 is promoted, my-designs-panel must be migrated onto this module and its\n   private copy deleted. Do NOT let the two drift in the meantime: any fix made\n   here must be mirrored there, and vice versa.\n\n   Ported verbatim (do not \"simplify\" \u2014 each carries a shipped bug fix):\n     - combineDuplicateDesigns  server-vs-server dedupe (Owen 2026-07-09)\n     - the sessionStorage SWR cache keyed per customer\n     - thumbUrl's per-type imgix params (vector conversion, gang-sheet fit,\n       raster trim=colorUnlessAlpha)\n     - archive's two photo_id flavours (upload photo_id vs purchase basename)\n\n   \u26A0 This module returns METADATA. For artwork DIMENSIONS use window.NTMeasure\n   (assets/nt-measure.js) \u2014 the one sanctioned measurement path. Do not add a\n   private dimension path here.\n   ========================================================================= */\n(function () {\n  'use strict';\n  if (window.NTArtworkData) return;\n\n  var API = 'https://hpz51rjda5.execute-api.us-east-1.amazonaws.com/production';\n\n  /* STAFF LOOKUP MODE (Justin 2026-09-30). The internal customer-artwork page\n     renders ONE customer's library to a signed-in employee. Two of the six\n     feeds in fetchServerResults identify the VIEWER rather than the subject \u2014\n     the Gang Sheet Builder's saved-designs proxy (Shopify signs the request\n     and the builder reads logged_in_customer_id) and the Shopify-orders\n     fallback (Liquid, the signed-in customer's own orders). Left on, both\n     would splice the EMPLOYEE's sheets and orders into the customer's\n     library, which reads as the customer's own data and is wrong in the one\n     way nobody would catch by looking. They are skipped here instead of at\n     the call site so every caller inherits it.\n     Writes are refused for the same reason: this surface is read-only, and\n     archiving or deleting another person's artwork from a lookup page is not\n     a mistake we want to be one click away from. The buttons are hidden in\n     the section too; this is the backstop, not the only guard. */\n  function lookupMode() { return !!window.__ntArtworkLookup; }\n  var IMGIX_HOST = 'ninjauploads-production.imgix.net';\n  var S3_HOST = 'ninja-services-production-ninjauploadss3bucket-zks2mguobhe4.s3.amazonaws.com';\n  /* \u26A0 The bucket suffix is NOT stable. Real purchase records are served from\n     ...ninjauploadss3bucket-pj1r4ls6dsdh, so matching the literal S3_HOST above\n     silently fails: the imgix params get appended to an S3 URL, S3 ignores\n     unknown query params, and the FULL-SIZE original is served as the\n     thumbnail. It looks fine and quietly costs megabytes per tile.\n     Match the bucket by shape instead of by name.\n     \u26A0 The same stale literal is in live's my-designs-panel.liquid and\n     bysize-v4.js \u2014 this fixes v2 only. */\n  var S3_HOST_RE = /ninja-services-production-ninjauploadss3bucket-[a-z0-9]+\\.s3\\.amazonaws\\.com/;\n  function toImgixHost(url) { return String(url || '').replace(S3_HOST_RE, IMGIX_HOST); }\n\n  /* Gang Sheet Builder (Printfly app). Saved sheets live in ITS backend and\n     re-open through its app-proxy route \u2014 verified live 2026-09-15. */\n  /* App Proxy route (builder team, v0.174.0, 2026-09-18): Shopify signs the\n     request and the builder verifies the HMAC, so the customer comes from\n     logged_in_customer_id \u2014 NEVER pass customerId here (it would reopen the\n     hole this closes). Same response shape as the old direct endpoint. The\n     old `gangsheet.ninjatransfers.com/api/saved-designs?customerId=` path is\n     being retired once we confirm this cutover. */\n  var GSB_SAVED_API = '/apps/ninja-gang-sheet/saved-designs';\n  /* `return` (builder team, 2026-09-17): a PATH ONLY \u2014 the builder's Back\n     returns the customer to it; anything with a scheme/authority is rejected\n     there and falls back to their default. Captured before their self-clean. */\n  function gangSaveEditUrl(design, returnPath) {\n    var url = '/apps/ninja-gang-sheet/saved-designs/' + encodeURIComponent((design && design.gangSaveId) || '') + '/open';\n    var rp = String(returnPath || '');\n    if (rp && rp.charAt(0) === '/' && rp.indexOf('//') !== 0) url += '?return=' + encodeURIComponent(rp);\n    return url;\n  }\n\n  /* Every image a customer puts on a Gang Sheet Builder sheet is one of their\n     uploads, ordered or not (Justin 2026-10-27; first built 7-8 in the legacy\n     my-designs-panel, never carried into this library). The builder's feed\n     lists them as source === 'builder' (it also mirrors our own uploads and\n     purchases, which the API feeds already supply). \u26A0 It takes customerId in\n     the URL; Justin OK'd that for now \u2014 swap to an app-proxy route once the\n     builder team ships one, like GSB_SAVED_API above. */\n  var GSB_UPLOADS_API = 'https://gangsheet.ninjatransfers.com/api/customer/by-size-uploads?customerId=';\n  /* The builder feed has no archive/delete. Their state lives in a\n     per-customer ledger on this browser \u2014 the SAME key the legacy panel used,\n     so states set there carry over. Builder rows get a synthetic photoId\n     ('builder:<file key>') so the library's Archive/Delete controls work;\n     setArchived/deleteDesign route those ids to the ledger, never the API. */\n  var BUILDER_PID = 'builder:';\n  function isBuilderPid(pid) { return String(pid || '').indexOf(BUILDER_PID) === 0; }\n  function builderLedgerKey(customerId) { return 'nt-md-builder-archived:' + customerId; }\n  function getBuilderLedger(customerId) {\n    try { return JSON.parse(localStorage.getItem(builderLedgerKey(customerId))) || {}; } catch (e) { return {}; }\n  }\n  function markBuilder(customerId, pid, state) {\n    var key = String(pid || '').slice(BUILDER_PID.length);\n    if (!key) return;\n    var l = getBuilderLedger(customerId);\n    if (state) l[key] = state; else delete l[key];\n    try { localStorage.setItem(builderLedgerKey(customerId), JSON.stringify(l)); } catch (e) {}\n  }\n\n  /* Name for \"same design\" checks across the builder and our uploads:\n     lowercased, extension and copy suffixes (\" (1)\", \"-2\", \"copy\") dropped,\n     separators collapsed. '' for generic names, which never merge. */\n  var GENERIC_NAME = /^((logo|image|img|photo|picture|pic|untitled|unnamed|download|file|design|artwork|art|screenshot|scan|test|new|copy|final|original)\\d*|\\d{0,5})$/;\n  function looseName(name) {\n    var n = stripUploadSuffix(String(name || '')).toLowerCase().trim()\n      .replace(/\\.[a-z0-9]{1,5}$/, '')\n      .replace(/([\\s_\\-.]*(\\(\\d+\\)|copy))+$/g, '')\n      .replace(/[\\s_\\-.()]+/g, '');\n    return (!n || n === 'undefined' || GENERIC_NAME.test(n)) ? '' : n;\n  }\n\n  var VECTOR_EXTS = ['ai', 'eps', 'pdf', 'svg', 'tif', 'tiff', 'psd'];\n  var REMOTE_PREVIEW_EXTS = ['ai', 'eps', 'pdf', 'svg', 'tif', 'tiff', 'psd'];\n\n  /* ---------------------------------------------------------------- helpers */\n\n  function extractFileName(url) {\n    var name = url;\n    if (url.indexOf('imgix.net') > -1) {\n      name = url.replace('https://', '').split('?')[0].split('/')[1] || name;\n    } else if (url.indexOf('upload.cloudlift.app') > -1) {\n      name = url.split('transferss/')[1] || name;\n    } else if (url.indexOf('ninja-services-production') > -1) {\n      name = url.replace('https://', '').split('?')[0].split('/')[1] || name;\n    } else if (url.indexOf('amazonaws') > -1) {\n      name = url.replace('https://', '').split('?')[0].split('/')[2] || name;\n    }\n    name = stripUploadSuffix(name);\n    try { name = decodeURIComponent(name); } catch (e) {}\n    return name;\n  }\n\n  /* \u26A0 Strip the internal \"____image_<ts>_<n>\" suffix EVERYWHERE a name is\n     produced. It has now been missed twice, once per source:\n       - it lived inside extractFileName's imgix branch only, so S3-hosted\n         purchases rendered \"nt-logo____image_...12.svg\";\n       - then processItem used the feed's raw file_name VERBATIM for uploads,\n         which bypasses extractFileName entirely \u2014 so on the first real-theme\n         render every upload showed \"qa-eiffel____image_1787870701664_183.png\".\n     One function, called from both paths. If a third name source ever appears,\n     it goes through here too. */\n  function stripUploadSuffix(name) {\n    if (!name || name.indexOf('____image') === -1) return name;\n    var ext = name.split('.').pop();\n    return name.split('____image')[0] + (ext && ext !== name ? '.' + ext : '');\n  }\n\n  function rawExt(url) {\n    try { return (url || '').split('?')[0].split('.').pop().toLowerCase(); }\n    catch (e) { return ''; }\n  }\n\n  function fileExt(url) {\n    var ext = rawExt(url);\n    if (!ext || ext.length > 5) return '';\n    return ext.toUpperCase();\n  }\n\n  function isVectorFile(url) { return VECTOR_EXTS.indexOf(rawExt(url)) > -1; }\n  function needsRemotePreview(url) { return REMOTE_PREVIEW_EXTS.indexOf(rawExt(url)) > -1; }\n\n  /* Bare imgix URL (no params) \u2014 what NTMeasure wants. */\n  function imgixUrl(url) {\n    return toImgixHost(url).split('?')[0];\n  }\n\n  /* \u26A0 Thumbs are built from the BARE file URL \u2014 stored params stripped BEFORE\n     the recipe (Owen 2026-09-11). Two reasons, both billing/cache-real:\n     1. Stored URLs can carry processing params (bg-remove=true on ix/pc-era\n        order records). Appending the recipe to those made the 300px THUMBNAIL\n        an AI render \u2014 1 imgix credit per cache-expired load, same price as a\n        full background removal. 2 of 24 tiles on one audited page.\n     2. Stored trim=colorUnlessAlpha doubled with the recipe's, and other\n        surfaces appended recipes without trim \u2014 same pixels under 2-3 distinct\n        URL strings = 2-3 separate renders and cache entries. One canonical\n        string (bare + this recipe, this param order) collapses them; the\n        legacy PDP list builders were unified to the identical string.\n     The details/zoom view (imgixUrl) still shows the stored render with its\n     params \u2014 there the processed look IS the point; the thumb's job is cheap\n     recognition.\n     CARRIED REMOVAL (Justin 2026-09-14): a design the customer saved with the\n     background removed keeps that look on its tiles and zoom. The stored URL's\n     bg-remove=true (+ the model that produced it, + cs=strip on Lambda\n     outputs) is re-appended AFTER the recipe, so the string is still one\n     canonical shape per design and the zoom equals the PDP hero string\n     exactly (cache hit). Carrying the model matters: bg-remove=true without\n     bg-remove-model=4 would ask imgix's DEFAULT model for a render the\n     customer never made \u2014 a fresh premium credit. upscale is never carried\n     (a 600px tile does not need it). Cost profile: standard renders while\n     imgix holds the customer's AI output (a long-lived separate cache per the\n     rep); only a design whose AI output has aged out re-bills a removal. */\n  function carriedToggles(url) {\n    var q = String(url || '').split('?')[1] || '';\n    if (!q) return '';\n    var out = '';\n    var m;\n    if (/(^|&)bg-remove=true(&|$)/.test(q)) {\n      out += '&bg-remove=true';\n      m = q.match(/(?:^|&)bg-remove-model=(\\d+)(?:&|$)/);\n      if (m) out += '&bg-remove-model=' + m[1];\n    }\n    if (/(^|&)cs=strip(&|$)/.test(q)) out += '&cs=strip';\n    return out;\n  }\n  function thumbUrl(url, isGang) {\n    var compressed = toImgixHost(url).split('?')[0];\n    if (needsRemotePreview(url)) {\n      /* AI/EPS/PDF/SVG/TIF: convert to PNG \u2014 no trim/dpi, they break conversion */\n      if (isGang) return compressed + '?fm=png&auto=compress&q=50&w=600&h=600&fit=clip';\n      return compressed + '?fm=png&auto=compress&q=50&w=600' + carriedToggles(url);\n    }\n    if (isGang) {\n      /* Gang sheets: fit the full layout in 600x600, no trim */\n      return compressed + '?fm=png&auto=compress&q=50&w=600&h=600&fit=clip';\n    }\n    return compressed + '?trim=colorUnlessAlpha&fm=png&auto=compress&q=50&w=600' + carriedToggles(url);\n  }\n\n  /* ZOOM tier (imgix audit 2026-09-11): one w=2000 string per design, the\n     same parameter set the v4 PDP hero renders, so a zoom anywhere is a cache\n     hit on the render the customer already saw. Gang sheets stay in a\n     2000x2000 clip box (a 40 ft sheet at w=2000 would exceed imgix's max\n     output height). Medium tier above = w=600, small tier (_cartImg) = h=150. */\n  function zoomUrl(url, isGang) {\n    var bare = toImgixHost(url).split('?')[0];\n    if (isGang) return bare + '?fm=png&w=2000&h=2000&fit=clip';\n    return bare + '?trim=colorUnlessAlpha&fm=png&w=2000' + carriedToggles(url); // == the v4 hero string for that design\n  }\n\n  function normalizeFileKey(url) {\n    try {\n      var clean = (url || '').split('?')[0];\n      var parts = clean.split('/');\n      return decodeURIComponent(parts[parts.length - 1] || clean);\n    } catch (e) {\n      return (url || '').split('?')[0];\n    }\n  }\n\n  function makeUploadMatchKey(fileOrKey, isGangSheet) {\n    var sourceValue = '';\n    if (typeof fileOrKey === 'string') sourceValue = fileOrKey;\n    /* matchFile: the canonical file of a same-content upload group\n       (aliasSameFileUploads) \u2014 the design's identity; .file stays the record's\n       own artwork. */\n    else if (fileOrKey) sourceValue = fileOrKey.matchFile || fileOrKey.file || fileOrKey.key || fileOrKey.s3File || '';\n    return normalizeFileKey(sourceValue) + '|' + (isGangSheet ? '1' : '0');\n  }\n\n  function smartFileName(name, maxLen) {\n    if (!name) return '';\n    maxLen = maxLen || 28;\n    var dotIdx = name.lastIndexOf('.');\n    var ext = dotIdx > -1 ? name.substring(dotIdx + 1).toLowerCase() : '';\n    var base = dotIdx > -1 ? name.substring(0, dotIdx) : name;\n    var suffix = ext ? '.' + ext : '';\n    var totalMax = maxLen - suffix.length;\n    if (totalMax < 6) totalMax = 6;\n    if (base.length > totalMax) base = base.substring(0, totalMax - 3) + '...';\n    return base + suffix;\n  }\n\n  /* ------------------------------------------------------------ normalising */\n\n  var STUDIO_STATE_MARKER = 'design-studio-state-'; /* legacy: 600px preview, NOT print art */\n  var STUDIO_PRINT_MARKER = 'design-studio-save-';  /* 9-14 print-safe: the registered PNG IS the print export */\n  /* '' | 'state' | 'save' \u2014 flat `design-studio-<ts>` exports return '' on\n     purpose: they have no state JSON beside them, so there is nothing to\n     re-open in the studio; they stay plain uploads. */\n  function studioRowKind(raw) {\n    var base = String((raw && (raw.file_name || raw.file)) || '').split('?')[0].split('/').pop();\n    if (base.indexOf(STUDIO_STATE_MARKER) === 0) return 'state';\n    if (base.indexOf(STUDIO_PRINT_MARKER) === 0) return 'save';\n    return '';\n  }\n\n  /* The studio appends the design's name as a slug: \u2026-<rand>--test-2.png.\n     Titlecased words from the slug (\"Test 2\"); '' when a save has no slug \u2014\n     the caller falls back to the filename. */\n  function studioDisplayName(raw) {\n    var base = String((raw && (raw.file_name || raw.file)) || '').split('?')[0].split('/').pop();\n    var m = /--([a-z0-9-]+)\\.[a-z0-9]+$/i.exec(base);\n    if (!m) return '';\n    return m[1].replace(/-/g, ' ').replace(/\\b\\w/g, function (c) { return c.toUpperCase(); });\n  }\n\n  /* Continue-editing target: the state JSON sits next to the save PNG (same\n     basename, .json) on the S3 host \u2014 imgix does not serve JSON, so the host\n     is swapped back. The studio page's mount() validates the host and boots\n     from ?ds_state= (same contract my-designs-panel uses). */\n  function studioEditUrl(design) {\n    var stateUrl = String((design && design.file) || '').split('?')[0]\n      .split(IMGIX_HOST).join(S3_HOST)\n      .replace(/\\.png$/i, '.json');\n    return '/pages/design-studio?view=design-studio-v3&ds_state=' + encodeURIComponent(stateUrl);\n  }\n\n  function processItem(raw, source, isGang) {\n    var gang = typeof raw.gangsheet !== 'undefined' ? !!raw.gangsheet : !!isGang;\n\n    var fileName = (raw.file_name && raw.file_name.length > 0)\n      ? stripUploadSuffix(raw.file_name)\n      : extractFileName(raw.file || '');\n\n    var dateStr = raw.uploaded_date || raw.order_date || raw.purchased_at || '';\n    if (typeof dateStr !== 'string') dateStr = '';\n    if (source === 'upload' && dateStr.indexOf('Purchased') > -1) {\n      dateStr = dateStr.replace('Purchased', 'Uploaded');\n    }\n\n    /* \u26A0 Purchases have NO id of their own. orderDataNew rows carry only\n       order_name / variant_title / file / dates / product_id \u2014 no id, no\n       photo_id \u2014 so the old `|| ''` fallback gave EVERY purchased design the\n       same empty id. byId('') then resolved to whichever design came first:\n       opening any purchase showed the first purchase's details, and the\n       reorder Add posted the first purchase's artwork. Found live on the\n       sandbox (\"adding something but not what I see in my designs\").\n       The file URL is unique per record and stable across loads, so it is the\n       fallback identity. Prefixed by source so an upload and a purchase of the\n       same file never collide either. */\n    var id = raw.photo_id || raw.id ||\n             (source + ':' + normalizeFileKey(raw.file || '') + ':' + String(raw.formatted_date || ''));\n    if (!id && raw.file) id = source + '-' + raw.file.split('/').pop().split('?')[0];\n    if (!id) id = source + '-' + Math.random().toString(36).substr(2, 9);\n\n    var ts = 0;\n    if (typeof raw.formatted_date === 'number') {\n      ts = raw.formatted_date;\n    } else if (typeof raw.formatted_date === 'string' && raw.formatted_date.length > 0) {\n      ts = new Date(raw.formatted_date).getTime() / 1000 || 0;\n    }\n\n    return {\n      id: id,\n      photoId: raw.photo_id || '',\n      file: raw.file || '',\n      s3File: isVectorFile(raw.file || '') ? imgixUrl(raw.file || '') : '',\n      fileName: fileName,\n      thumb: thumbUrl(raw.file || '', gang),\n      date: dateStr,\n      timestamp: ts,\n      gangsheet: gang,\n      source: source,\n      variantTitle: raw.variant_title || '',\n      /* \u26A0 The API HAS returned this all along; processItem simply never read\n         it, which is why the method looked unknowable. Verified against a live\n         response: purchase rows carry order_name, variant_title, file,\n         order_date, purchased_at, formatted_date, file_name, product_id,\n         archived. It is what tells DTF from UV \u2014 the gangsheet flag only\n         separates gang sheets. */\n      productId: raw.product_id ? String(raw.product_id) : '',\n      /* crc32 of the uploaded bytes (upload rows since ~Sep 2026) \u2014 the\n         same-file signal aliasSameFileUploads groups on. */\n      crc: normCrc(raw.file_crc),\n      orderName: raw.order_name || '',\n      /* units on the order line \u2014 only the Shopify-order rows carry it (the\n         backend feed has none; processServerResults borrows it for them) */\n      quantity: parseInt(raw.quantity, 10) || 0,\n      archived: !!raw.archived\n    };\n  }\n\n  /* One spelling per checksum. Most uploaders store crc32 as unpadded\n     lowercase hex (\"32fc827c\"); the studio stores it in DECIMAL\n     (\"2768762064\"). A crc32 is at most 8 hex digits, so an all-digit value of\n     9\u201310 digits is decimal and is converted; anything else is hex, lowercased,\n     leading zeros dropped. */\n  function normCrc(v) {\n    var c = String(v == null ? '' : v).trim().toLowerCase();\n    if (!c || c === '0' || c === 'null' || c === 'undefined') return '';\n    if (/^\\d{9,10}$/.test(c)) c = (parseInt(c, 10) >>> 0).toString(16);\n    return c.replace(/^0+(?=.)/, '');\n  }\n\n  /* The same file uploaded again is the same design (Justin 2026-09-29).\n     Every upload is stored under a fresh ____image_ name, so a re-upload of art\n     the customer already bought read as a new \"Uploaded\" design and the\n     purchase stayed behind on the old one. Uploads with the same content\n     checksum (file_crc, the crc32 of the bytes) and extension are grouped:\n     every member's matchFile points at ONE canonical file \u2014 the one an order\n     line used (newest such order) when there is one, else the oldest upload \u2014\n     so the dedupe, the purchase twin, the card date, the order history and the\n     last-used sort all treat them as one design, and the newest upload is the\n     card that shows. Uploads without a checksum are untouched: no name\n     guessing, two different \"logo.png\"s must never merge. */\n  function aliasSameFileUploads(designs) {\n    var boughtAt = {};\n    designs.forEach(function (d) {\n      if (d.source !== 'purchase') return;\n      var k = makeUploadMatchKey(d, !!d.gangsheet);\n      boughtAt[k] = Math.max(boughtAt[k] || 0, d.timestamp || 0);\n    });\n    var groups = {};\n    designs.forEach(function (d) {\n      if (d.source !== 'upload' || !d.crc) return;\n      var g = d.crc + '|' + fileExt(d.file || '').toLowerCase() + '|' + (d.gangsheet ? '1' : '0');\n      (groups[g] || (groups[g] = [])).push(d);\n    });\n    Object.keys(groups).forEach(function (g) {\n      var members = groups[g];\n      if (members.length < 2) return;\n      var canon = null, canonTs = -1;\n      members.forEach(function (d) {\n        var bought = boughtAt[makeUploadMatchKey(d, !!d.gangsheet)];\n        if (bought != null && bought > canonTs) { canon = d; canonTs = bought; }\n      });\n      if (!canon) canon = members.slice().sort(function (a, b) { return (a.timestamp || 0) - (b.timestamp || 0); })[0];\n      members.forEach(function (d) { if (d !== canon) d.matchFile = canon.file; });\n    });\n\n    /* One version per design in Saved (Justin 2026-10-13): uploads that share a display name\n       and extension are versions of one design (re-uploads, Add Text / edit saves) and show\n       as ONE card \u2014 the newest (combineDuplicates), with every copy's photo_id in\n       dupePhotoIds so Delete removes them all. Anchored on an ordered copy when there is one\n       (the purchase twin), else the oldest. Generic names (logo, image, IMG_1234, Untitled,\n       download\u2026) are left alone: different designs routinely share those. */\n    var GENERIC = /^(logo|image|img|photo|picture|pic|untitled|unnamed|download|file|design|artwork|art|screenshot|screen ?shot|scan|test|new|copy|final)?[\\s_\\-.()]*(copy)?[\\s_\\-.()]*\\d*[\\s_\\-.()]*(copy)?$/i;\n    var byName = {};\n    designs.forEach(function (d) {\n      if (d.source !== 'upload' || d.gangsheet) return;\n      var nm = String(d.fileName || '').trim().toLowerCase();\n      var stem = nm.replace(/\\.[a-z0-9]{1,5}$/, '');\n      if (!nm || nm === 'undefined' || GENERIC.test(stem)) return;\n      var g = nm + '|' + fileExt(d.file || '').toLowerCase();\n      (byName[g] || (byName[g] = [])).push(d);\n    });\n    Object.keys(byName).forEach(function (g) {\n      var members = byName[g];\n      if (members.length < 2) return;\n      var canon = members.filter(function (d) { return boughtAt[makeUploadMatchKey(d, false)] != null; })[0] ||\n        members.slice().sort(function (a, b) { return (a.timestamp || 0) - (b.timestamp || 0); })[0];\n      var target = canon.matchFile || canon.file;\n      members.forEach(function (d) { if (d !== canon) d.matchFile = target; });\n    });\n    /* the name pass can re-point a crc group's canon \u2014 follow every alias to its end */\n    var byFile = {};\n    designs.forEach(function (d) { if (d.source === 'upload' && d.file) byFile[d.file] = d; });\n    designs.forEach(function (d) {\n      for (var hop = 0; d.matchFile && hop < 5; hop++) {\n        var next = byFile[d.matchFile];\n        if (!next || !next.matchFile || next.matchFile === d.matchFile || next === d) break;\n        d.matchFile = next.matchFile;\n      }\n    });\n\n    /* Fallback for GANG uploads the crc pass could not pair (Owen 2026-09-30).\n       The uploads API returns file_crc = null for gang-sheet uploads, so the crc\n       pass above never groups a re-upload of the same sheet: every upload lands\n       under a fresh S3 key, and combineDuplicates (which, with no matchFile,\n       keys on the S3 basename) then renders each re-upload as its own\n       identical-looking card. Deleting one left its twins on the server and the\n       design \"came back\" on refresh \u2014 screen-verified on the sandbox: deleting\n       qa-gang-22x24-300.png (photo_id 5931a18c\u2026) left an identical 108771d2\u2026\n       behind, same file_name. With no usable content checksum, the only\n       same-design signal left is the display file_name (its ____image_ suffix\n       already stripped by processItem), so group these by fileName + gangsheet\n       and point each copy's matchFile at one canonical file. combineDuplicates\n       then collapses them to one card and carries every copy's photo_id in\n       dupePhotoIds, so a single delete removes the whole set.\n\n       Records that ARE part of a real same-content crc group (>=2 members with\n       one crc) are left to the crc pass \u2014 this fallback only takes the ones it\n       could not pair: crc-less uploads, and a stray upload whose crc is unique\n       (a QA re-upload straddling the crc rollout \u2014 otherwise it would linger as\n       a second identical-named card and still \"come back\").\n       \u26A0 Guarded: empty and literal \"undefined\" names are skipped \u2014 several gang\n       uploads carry file_name \"undefined\", and merging genuinely different\n       designs behind such a placeholder would over-collapse (and over-delete).\n       A real shared name is the accepted residual risk (Owen's call); the\n       structural fix is the backend populating file_crc. Scoped to gang uploads\n       only, so the Uploads tab (which carries real crcs) is untouched. */\n    var gangCrcCount = {};\n    designs.forEach(function (d) {\n      if (d.source === 'upload' && d.gangsheet && d.crc) gangCrcCount[d.crc] = (gangCrcCount[d.crc] || 0) + 1;\n    });\n    var byName = {};\n    designs.forEach(function (d) {\n      if (d.source !== 'upload' || !d.gangsheet) return;\n      if (d.crc && gangCrcCount[d.crc] >= 2) return;   /* real same-content group \u2014 leave to the crc pass */\n      var nm = String(d.fileName || '').trim();\n      if (!nm || nm.toLowerCase() === 'undefined') return;\n      var g = nm.toLowerCase() + '|' + (d.gangsheet ? '1' : '0');\n      (byName[g] || (byName[g] = [])).push(d);\n    });\n    Object.keys(byName).forEach(function (g) {\n      var members = byName[g];\n      if (members.length < 2) return;\n      /* Canon = a member whose file basename is the most common in the group.\n         Some copies of the same S3 file come back with file_name \"undefined\"\n         (skipped above) and are held together only by that shared basename in\n         combineDuplicates; picking the majority basename as canon keeps them in\n         this same card instead of orphaning them to a different key. */\n      var baseCount = {};\n      members.forEach(function (d) { var b = normalizeFileKey(d.file || ''); baseCount[b] = (baseCount[b] || 0) + 1; });\n      var canon = members.slice().sort(function (a, b) {\n        var byBase = (baseCount[normalizeFileKey(b.file || '')] || 0) - (baseCount[normalizeFileKey(a.file || '')] || 0);\n        return byBase || ((a.timestamp || 0) - (b.timestamp || 0));\n      })[0];\n      members.forEach(function (d) { if (d !== canon && !d.matchFile) d.matchFile = canon.file; });\n    });\n  }\n\n  /* Combine duplicate uploads within the fetched feed (Owen 2026-07-09). The\n     feed can carry the same image more than once (re-uploaded, or mirrored\n     across the native + Members-area feeds). Keyed by SOURCE too, so an upload\n     and a purchase of the same filename are NOT collapsed \u2014 the tabs filter by\n     source, and merging them would drop the design from one tab.\n     Keep-preference: the record WITH a photo_id wins (so Archive/Delete still\n     resolve), then the newest timestamp. */\n  function combineDuplicates(designs) {\n    function keyOf(d) { return (d.source || '') + '|' + makeUploadMatchKey(d, !!d.gangsheet); }\n    var bestByKey = {}, allByKey = {};\n    designs.forEach(function (d) {\n      var key = keyOf(d), prev = bestByKey[key];\n      (allByKey[key] || (allByKey[key] = [])).push(d);\n      if (!prev) { bestByKey[key] = d; return; }\n      var dPid = !!d.photoId, prevPid = !!prev.photoId;\n      if (dPid !== prevPid) { if (dPid) bestByKey[key] = d; return; }\n      if ((d.timestamp || 0) > (prev.timestamp || 0)) bestByKey[key] = d;\n    });\n    var emitted = {}, out = [];\n    designs.forEach(function (d) {\n      var key = keyOf(d);\n      if (emitted[key]) return;\n      emitted[key] = true;\n      var best = bestByKey[key];\n      /* \u26A0 Keep what the collapse discards. The dedupe exists so the GRID shows\n         one card per piece of artwork, not five \u2014 but each discarded record is\n         a real event with its own date and, for purchases, its own ordered\n         size in variant_title. Dropping them threw away the entire order\n         history and left only \"last ordered\".\n\n         Attached to the kept record rather than emitted as extra cards, so the\n         grid is untouched and only the details panel reads it. Newest first,\n         matching every other date in the UI. */\n      /* \u26A0 Orders only. Upload records in the real feed carry a junk\n         variant_title (a signed token, not a size), so letting them into\n         history rendered fake \"Orders with this design\" rows on designs that\n         were never bought \u2014 with a live Add button on garbage data. */\n      best.history = allByKey[key].filter(function (r) {\n        return r.source === 'purchase';\n      }).sort(function (a, b) {\n        return (b.timestamp || 0) - (a.timestamp || 0);\n      }).map(function (r) {\n        return {\n          timestamp: r.timestamp || 0,\n          date: r.date || '',\n          variantTitle: r.variantTitle || '',\n          orderName: r.orderName || '',\n          productId: r.productId || '',\n          quantity: r.quantity || 0,\n          /* \u26A0 Each line's OWN stored artwork, not the survivor's. Two orders of\n             the same design can differ \u2014 one with bg-remove baked in, one\n             without \u2014 and a reorder must reproduce the line it came from. */\n          artUrl: r.file || ''\n        };\n      });\n      /* \u26A0 Same-CONTENT upload copies (aliasSameFileUploads groups re-uploads of\n         one file by crc+ext) collapse into this single card, and the other\n         copies are dropped from the grid. Delete/Archive must act on EVERY\n         copy's photo_id \u2014 deleting only the survivor's leaves the rest on the\n         server, and on the next load they re-form the group so the design\n         \"comes back\" (Owen 2026-09-30: uploaded gang sheets would not delete).\n         Carry the discarded upload copies' photo_ids so deleteDesign can remove\n         the whole group in one action. */\n      best.dupePhotoIds = allByKey[key].filter(function (r) {\n        return r.source === 'upload' && r.photoId && r.photoId !== best.photoId;\n      }).map(function (r) { return r.photoId; });\n      out.push(best);\n    });\n    return out;\n  }\n\n  function processServerResults(results, cartLooks, customerId) {\n    var uploadData = results[0] && results[0].data ? results[0].data : results[0];\n    var purchaseBySize = results[1] && results[1].data ? results[1].data : results[1];\n    var purchaseGang = results[2] && results[2].data ? results[2].data : results[2];\n    /* Shopify-order fallback rows (fetchShopifyOrders): an order the backend\n       feed already carries is left to the backend entirely \u2014 its row may name\n       a processed copy of the file, so matching line by line would list the\n       same purchase twice. Only orders the backend is missing are added. */\n    var shopifyOrders = Array.isArray(results[5]) ? results[5] : [];\n    var lookupArt = lookupMode() && Array.isArray(results[6]) ? results[6] : null;\n    if (lookupArt && !shopifyOrders.length) shopifyOrders = productionArtRows(lookupArt);\n    if (shopifyOrders.length) {\n      var digits = function (v) { return String(v || '').replace(/\\D/g, ''); };\n      var backendOrders = {};\n      purchaseBySize = Array.isArray(purchaseBySize) ? purchaseBySize.slice() : [];\n      purchaseBySize.forEach(function (r) { backendOrders[digits(r && r.order_name)] = true; });\n      /* The backend rows carry no quantity; the Shopify line for the same\n         order does (the Details panel's \"Qty 24\"). Matched on the order and\n         the file's basename, or the order alone when it has one design line.\n         No match \u2192 no Qty shown, never a guess. */\n      var byOrder = {};\n      shopifyOrders.forEach(function (r) {\n        if (r && r.file) (byOrder[digits(r.order_name)] = byOrder[digits(r.order_name)] || []).push(r);\n      });\n      purchaseBySize = purchaseBySize.map(function (r) {\n        var lines = r && !r.quantity && byOrder[digits(r.order_name)];\n        if (!lines) return r;\n        var key = makeUploadMatchKey(r.file || '', false);\n        var hit = lines.filter(function (s) { return makeUploadMatchKey(s.file, false) === key; })[0] ||\n                  (lines.length === 1 ? lines[0] : null);\n        return hit && hit.quantity ? Object.assign({}, r, { quantity: hit.quantity }) : r;\n      });\n      shopifyOrders.forEach(function (r) {\n        if (r && r.file && !backendOrders[digits(r.order_name)]) purchaseBySize.push(r);\n      });\n    }\n\n    var designs = [];\n    /* Design Studio saves are TAGGED, not dropped (the library grew its studio\n       tab, 2026-09-15). Two generations, both with the re-editable state JSON\n       beside the PNG (same basename, .json \u2014 contract: studio persistence.js):\n       - studio:'save'  (design-studio-save-, 9-14 print-safe): the registered\n         PNG IS the print-resolution Use Design export \u2014 ordinary orderable\n         artwork that ALSO re-opens in the studio.\n       - studio:'state' (design-studio-state-, legacy): the PNG is a 600px\n         preview. \"Use\" hands that thumbnail to the order flow \u2014 the 9-14\n         sales audit found 10 orders (NT-2566702 alone ~26 lines at ~60 dpi)\n         printed from it \u2014 so the component quarantines these rows to the\n         Design Studio tab and never lets them select or order; their only\n         forward action is Continue Editing.\n       The component's matchesSource owns the quarantine; this layer only\n       tags. */\n    function tagStudio(d, raw) {\n      var kind = studioRowKind(raw);\n      if (kind) {\n        d.studio = kind;\n        /* Display-only: \"Test 2\" beats \"design-studio-save-1789\u2026--test-2\".\n           d.fileName stays the real filename \u2014 dedupe keys, order handoffs\n           and hover titles still need it. */\n        var nm = studioDisplayName(raw);\n        if (nm) d.studioName = nm;\n      }\n      return d;\n    }\n    if (Array.isArray(uploadData)) uploadData.forEach(function (i) { designs.push(tagStudio(processItem(i, 'upload'), i)); });\n    if (Array.isArray(purchaseBySize)) purchaseBySize.forEach(function (i) { designs.push(tagStudio(processItem(i, 'purchase', false), i)); });\n    if (Array.isArray(purchaseGang)) purchaseGang.forEach(function (i) { designs.push(tagStudio(processItem(i, 'purchase', true), i)); });\n    /* Gang-sheet UPLOADS (results[4], present only on gang surfaces \u2014 see\n       fetchServerResults): tagged gang (isGang=true) so the gangsheet filter\n       surfaces the customer's finished sheets, matching the live gang upload's\n       fetchDataNew?gangsheet=true. combineDuplicates below dedupes any overlap. */\n    var gangUploadData = results[4] && results[4].data ? results[4].data : results[4];\n    if (Array.isArray(gangUploadData)) gangUploadData.forEach(function (i) { designs.push(tagStudio(processItem(i, 'upload', true), i)); });\n    /* Gang Sheet Builder images (results[7]) -> Uploads; see GSB_UPLOADS_API. */\n    var builderFeed = results[7];\n    if (builderFeed && builderFeed.success && Array.isArray(builderFeed.items)) {\n      var bLedger = getBuilderLedger(customerId);\n      /* No duplicates (Justin 2026-10-27): a builder image whose loose name\n         matches one of our uploads IS that upload (customers re-pick their\n         library in the builder; the builder renames \"x (1).jpg\" -> \"x.jpg\"),\n         so it is skipped, and repeat builder copies keep only the newest.\n         Generic names (image, original, download\u2026) are never merged on name. */\n      var seenLoose = {};\n      designs.forEach(function (d) {\n        if (d.source === 'upload' && !d.gangsheet) { var k = looseName(d.fileName); if (k) seenLoose[k] = 1; }\n      });\n      builderFeed.items.slice().sort(function (x, y) { return (y && y.uploadedAt || 0) - (x && x.uploadedAt || 0); }).forEach(function (it) {\n        if (!it || it.source !== 'builder' || !it.sourceUrl) return;\n        var bKey = normalizeFileKey(it.sourceUrl);\n        if (bLedger[bKey] === 'deleted') return;\n        var loose = looseName(it.fileName || extractFileName(it.sourceUrl));\n        if (loose) { if (seenLoose[loose]) return; seenLoose[loose] = 1; }\n        var d = processItem({\n          id: it.id, file: it.sourceUrl, file_name: it.fileName || '',\n          formatted_date: it.uploadedAt || 0\n        }, 'upload');\n        d.photoId = BUILDER_PID + bKey;\n        d.builder = true;\n        d.archived = bLedger[bKey] === 'archived';\n        if (d.timestamp) d.date = 'Uploaded: ' + new Date(d.timestamp * 1000).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });\n        designs.push(d);\n      });\n    }\n\n    aliasSameFileUploads(designs);\n    designs = combineDuplicates(designs);\n    applyUsageLooks(designs, cartLooks || {});\n    applyProductionArt(designs, lookupArt || undefined);\n\n    /* Gang Sheet Builder saves (2026-09-15): ALL saved sheets \u2014 same list the\n       builder's own My Gang Sheets modal shows. The saved-but-never-purchased\n       funnel is the motivating case, but a purchased sheet's SAVE is still\n       the editable version (its purchase row only reorders as-is), so both\n       kinds carry Continue Editing. Not orderable artwork here: the component\n       quarantines them to the Gang Sheets tab; the forward action is the\n       builder's /saved-designs/<id>/open deep link. Pushed AFTER dedupe/\n       usage-looks on purpose \u2014 they share nothing with the uploads feed. */\n    var gangSavedRaw = results[3];\n    var gangSaved = Array.isArray(gangSavedRaw)\n      ? gangSavedRaw\n      : ((gangSavedRaw && (gangSavedRaw.designs || gangSavedRaw.data)) || []);\n    gangSaved.forEach(function (s) {\n      if (!s || !s.id) return;\n      var ts = Date.parse(s.updatedAt || s.createdAt || '') || 0;\n      /* ORDERED = the builder's `orderedAt` (written by its orders/create\n         webhook, first order wins; shipped 2026-09-16 in their #624/#629).\n         \u26A0 NOT `purchasedAt` \u2014 that is \"reached a cart at least once\"\n         (verified 2026-09-17: 8 flagged saves, 0 orders); it is deprecated in\n         place and kept here only as informational `cartedAt`. Absent\n         `orderedAt` = unordered, which fails OPEN to editable \u2014 the safe\n         direction, and the right one until their historical backfill runs.\n         `orderId` / `orderName` ride along when they expose them. */\n      var orderedTs = s.orderedAt ? (Date.parse(s.orderedAt) || 0) : 0;\n      var cartedTs = s.purchasedAt ? (Date.parse(s.purchasedAt) || 0) : 0;\n      function fmt(t) { return new Date(t).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); }\n      designs.push({\n        id: 'gangsave-' + s.id,\n        gangSaveId: s.id,\n        source: 'gangsave',\n        gangsheet: true,\n        archived: false,\n        ordered: !!orderedTs,\n        orderedAt: orderedTs || undefined,\n        orderId: s.orderId || undefined,\n        orderName: s.orderName || undefined,\n        cartedAt: cartedTs || undefined,\n        fileName: s.name || 'Untitled Gang Sheet',\n        file: s.previewUrl || '',\n        thumb: s.previewUrl || '',\n        timestamp: ts,\n        whenLabel: orderedTs ? 'Ordered: ' + fmt(orderedTs) : (ts ? 'Updated: ' + fmt(ts) : ''),\n        sheetCount: s.sheetCount,\n        totalImageCount: s.totalImageCount\n      });\n    });\n    /* Join ordered builder saves to their order lines (builder team 2026-09-18:\n       `orderName` = first order, flat beside `orderedAt`). The order feed\n       carries no build signal of its own, so this is the only way a gang ORDER\n       LINE can wear the Builder tag and the design's real name. Keyed on the\n       order number's digits \u2014 \"#1042\" and \"NT-1042\" are the same order \u2014 and\n       only for gang order lines, so a match can't leak across kinds. Absent\n       orderName (unordered saves, pre-backfill history) simply joins nothing. */\n    var builtByOrder = Object.create(null);\n    function orderDigits(v) { return String(v || '').replace(/\\D/g, ''); }\n    designs.forEach(function (d) {\n      if (d.source !== 'gangsave' || !d.ordered) return;\n      var k = orderDigits(d.orderName);\n      if (k && !builtByOrder[k]) builtByOrder[k] = d;\n    });\n    designs.forEach(function (d) {\n      if (d.source !== 'purchase' || !d.gangsheet) return;\n      var hit = builtByOrder[orderDigits(d.orderName)];\n      if (hit) d.builderSave = { id: hit.gangSaveId, name: hit.fileName };\n    });\n\n    designs.sort(function (a, b) { return (b.timestamp || 0) - (a.timestamp || 0); });\n    return designs;\n  }\n\n  /* ------------------------------------------------------ usage looks */\n  /* A design shows the way the customer LAST USED it (Justin 2026-09-14): an\n     upload that went into the cart or an order with Remove Background on keeps\n     that removal on its tiles and zoom; one that was only uploaded shows the\n     plain file. The v4 uploader writes the removal onto the line's _cartImg /\n     Upload URL on the SAME file key as the upload (\u2026&bg-remove=true\n     &bg-remove-model=N \u2014 every model is imgix-served since 2026-07-29), so a\n     line matches its design through makeUploadMatchKey and carriedToggles\n     lifts exactly what the tile recipe allows (bg-remove, its model, cs=strip;\n     never upscale). Precedence: a live cart line is the newest usage, then the\n     newest order. A purchase record already IS its newest line's look, so only\n     upload records are re-skinned; gang sheets are skipped (their line art is\n     a sheet render, not the upload). The cart is read fresh on every load and\n     never cached \u2014 the cached first paint carries order looks only. */\n  function cartLooksFromItems(items) {\n    var looks = {};\n    (Array.isArray(items) ? items : []).forEach(function (it) {\n      var p = (it && it.properties) || {};\n      var url = p['_cartImg'] || p['Upload (Vector Files Preferred)'] || '';\n      if (typeof url !== 'string' || !url) return;\n      var key = makeUploadMatchKey(url, false);\n      if (!looks[key]) looks[key] = url; /* /cart.js lists the newest line first */\n    });\n    return looks;\n  }\n  function fetchCartLooks() {\n    try {\n      return fetch('/cart.js', { credentials: 'same-origin' })\n        .then(function (r) { return r.json(); })\n        .then(function (c) { return cartLooksFromItems(c && c.items); })\n        .catch(function () { return {}; });\n    } catch (e) { return Promise.resolve({}); }\n  }\n  function applyUsageLooks(designs, cartLooks) {\n    var newestOrder = {};\n    designs.forEach(function (d) {\n      if (d.source !== 'purchase' || d.gangsheet) return;\n      var key = makeUploadMatchKey(d, false);\n      var line = (d.history && d.history[0]) || null;\n      var url = (line && line.artUrl) || d.file || '';\n      var ts = (line && line.timestamp) || d.timestamp || 0;\n      if (url && (!newestOrder[key] || ts > newestOrder[key].ts)) newestOrder[key] = { url: url, ts: ts };\n    });\n    designs.forEach(function (d) {\n      if (d.gangsheet || d.source === 'purchase') return;\n      var key = makeUploadMatchKey(d, false);\n      var use = (cartLooks && cartLooks[key]) || (newestOrder[key] && newestOrder[key].url) || '';\n      if (!use || normalizeFileKey(use) !== normalizeFileKey(d.file || '')) return; /* same file only */\n      d.lookFile = use;\n      d.thumb = thumbUrl(use, false);\n    });\n    return designs;\n  }\n\n  /* ---------------------------------------------------- production art */\n  /* Production art (production-art-sync, Justin 2026-10-12): once an order\n     ships, the print-ready file our art team made for each line is copied to\n     our own bucket with a 600 px preview, and the customer metafield\n     custom.production_art lists them (artwork-library-v2 renders it into\n     script[data-nt-production-art]). Each linked purchase gains a separate\n     printReady design (the Print Ready Files side) holding our file in .file /\n     .prod; the purchase itself is left showing the customer's image. Each\n     history line still notes its own order's file (prodUrl / prodPreview).\n     Joined on the order number's digits plus the line's file key: items[].k\n     lists normalizeFileKey of the line's _Upload / _Print Ready File /\n     _Original Image / _cartImg / _Preview. A reorder of production art sends our\n     file as the new line's upload and the art team makes a new file for the new\n     order, whose k then lists the older file's key. Every file linked that way is\n     the same design, and only the LARGEST is kept on record (Justin 2026-10-12:\n     tallest, then widest), whichever order made it. Absent metafield or no match\n     = the record as before. */\n  function productionArtItems() {\n    /* Staff lookup: the data island is the VIEWER's own list (Liquid only knows the signed-in\n       customer); the subject's comes from the app proxy instead (results[6], fetchLookupArt). */\n    if (lookupMode()) return [];\n    /* nt-print-ready.js unpacks the stored list (grouped by order, short links) */\n    if (window.ntPrintReady && window.ntPrintReady.items) return window.ntPrintReady.items();\n    try {\n      var el = document.querySelector('script[data-nt-production-art]');\n      var data = el ? JSON.parse(el.textContent || 'null') : null;\n      return data && Array.isArray(data.items) ? data.items : [];\n    } catch (e) { return []; }\n  }\n  /* Production files always live under Print Ready Files (Justin 2026-10-13): a purchase\n     whose own artwork is one of our production files (assets/nt-print-ready.js hosts) but\n     that no production_art item claims becomes a Print Ready card itself. */\n  function markProductionFiles(designs) {\n    var isPR = window.ntPrintReady && window.ntPrintReady.isPrintReady;\n    if (!isPR) return designs;\n    designs.forEach(function (d) {\n      if (d.source !== 'purchase' || d.printReady || d.prTwin || !isPR(d.file || '')) return;\n      d.printReady = true;\n      d.prod = d.prod || { url: String(d.file).split('?')[0], preview: '', order: d.orderName };\n      (d.history || []).forEach(function (h) { h.printReady = true; });\n    });\n    return designs;\n  }\n  function applyProductionArt(designs, items) {\n    items = items || productionArtItems();\n    if (!items.length) return markProductionFiles(designs);\n    var prByKey = {}, prList = [];\n    function digits(v) { return String(v || '').replace(/\\D/g, ''); }\n    function hasKey(it, key) { return !!key && Array.isArray(it.k) && it.k.indexOf(key) > -1; }\n    function lineArt(orderName, fileUrl) {\n      var o = digits(orderName), key = normalizeFileKey(fileUrl || '');\n      for (var i = 0; o && i < items.length; i++) {\n        if (digits(items[i].o) === o && (hasKey(items[i], key) || normalizeFileKey(items[i].u || '') === key)) return items[i];\n      }\n      return null;\n    }\n    designs.forEach(function (d) {\n      if (d.source !== 'purchase') return;\n      var lines = d.history && d.history.length ? d.history : [{ orderName: d.orderName, artUrl: d.file }];\n      var found = null;\n      lines.forEach(function (h) {\n        var it = lineArt(h.orderName, h.artUrl || d.file);\n        if (!it) return;\n        h.prodUrl = it.u;\n        h.prodPreview = it.p || '';\n        if (!found) found = it; /* history is newest first */\n      });\n      if (!found) return;\n      /* the largest file linked to it by reuse (assets/nt-print-ready.js, shared with My Orders) */\n      var best = window.ntPrintReady && window.ntPrintReady.largestLinked ? window.ntPrintReady.largestLinked(found, items) : found;\n      /* Print Ready Files (Justin 2026-10-13): the purchase keeps the customer's own image\n         (tiles, zoom, Add to Cart / Order as all send THEIR file, and that is a fresh order,\n         not a reorder). Our file is its OWN card, one per largest file, flagged printReady:\n         it carries the order lines (artUrl = our file, the upload in uploadUrl), so its\n         Add to Cart / Order as send the print-ready file tagged as a reorder. */\n      var key = normalizeFileKey(best.u);\n      var pr = prByKey[key];\n      var prLines = lines.map(function (h) {\n        return Object.assign({}, h, { artUrl: best.u, uploadUrl: h.artUrl || d.file, printReady: true });\n      });\n      if (!pr) {\n        pr = prByKey[key] = Object.assign({}, d, {\n          id: 'pr:' + key,\n          photoId: '',\n          dupePhotoIds: [],\n          file: best.u,\n          s3File: '',\n          thumb: best.p || thumbUrl(best.u, !!d.gangsheet),\n          lookFile: best.p || '',\n          printReady: true,\n          prod: { url: best.u, preview: best.p || '', order: best.o, crm: best.c, area: best.a, w: best.w, h: best.h },\n          history: prLines\n        });\n        prList.push(pr);\n      } else {\n        pr.history = pr.history.concat(prLines).sort(function (x, y) { return (y.timestamp || 0) - (x.timestamp || 0); });\n        if ((d.timestamp || 0) > (pr.timestamp || 0)) { pr.timestamp = d.timestamp; pr.date = d.date; }\n      }\n      /* The product page reads the printed size + order from here to write the reorder note\n         (assets/nt-print-ready.js). */\n      if (window.ntPrintReady) window.ntPrintReady.remember([{ url: best.u, o: best.o, c: best.c, a: best.a, w: best.w, h: best.h, p: best.p }]);\n    });\n    /* Every production file has a card (Justin 2026-10-13): one no purchase claimed \u2014 a Gang\n       Sheet Builder order (only its save carries the order), or an order the feeds miss \u2014\n       becomes its own Print Ready card. A builder save on the same order lends its name and\n       date; gang (it.g / a 22in-wide sheet) routes Add to Cart to the gang product. */\n    var saveByOrder = {};\n    designs.forEach(function (d) { if (d.source === 'gangsave' && d.orderName) saveByOrder[digits(d.orderName)] = d; });\n    items.forEach(function (it) {\n      if (!it || !it.u) return;\n      var best = window.ntPrintReady && window.ntPrintReady.largestLinked ? window.ntPrintReady.largestLinked(it, items) : it;\n      var key = normalizeFileKey(best.u);\n      var line = { orderName: it.o, artUrl: best.u, printReady: true, prodUrl: it.u, prodPreview: it.p || '',\n                   variantTitle: it.w && it.h ? it.w + 'x' + it.h : '', quantity: parseInt(it.q, 10) || 0,\n                   timestamp: Math.floor((Date.parse(it.d || '') || 0) / 1000) };\n      var pr = prByKey[key];\n      if (pr) {\n        if (!pr.history.some(function (h) { return digits(h.orderName) === digits(it.o); })) pr.history.push(line);\n        return;\n      }\n      var save = saveByOrder[digits(it.o)];\n      var w = Number(best.w) || 0;\n      var gang = !!(it.g || save || (w >= 21.5 && w <= 22.5));\n      var ts = (save && save.timestamp) || line.timestamp || 0;\n      pr = prByKey[key] = {\n        id: 'pr:' + key, photoId: '', dupePhotoIds: [], source: 'purchase', printReady: true,\n        file: best.u, s3File: '', thumb: best.p || thumbUrl(best.u, gang), lookFile: best.p || '',\n        fileName: (save && save.fileName) || ('Order ' + it.o + (w && best.h ? ' \u00B7 ' + w + '\u00D7' + best.h + '\"' : '')),\n        date: '', timestamp: ts, gangsheet: gang, variantTitle: line.variantTitle, productId: '',\n        orderName: it.o, quantity: line.quantity, archived: false, crc: '',\n        prod: { url: best.u, preview: best.p || '', order: best.o, crm: best.c, area: best.a, w: best.w, h: best.h },\n        history: [line]\n      };\n      prList.push(pr);\n      if (window.ntPrintReady) window.ntPrintReady.remember([{ url: best.u, o: best.o, c: best.c, a: best.a, w: best.w, h: best.h, p: best.p }]);\n    });\n    /* A purchase whose own artwork IS one of our files (a reorder from Print Ready Files) is\n       that card's order, already in its history \u2014 it doesn't show again under Purchased. */\n    designs.forEach(function (d) { if (d.source === 'purchase' && prByKey[normalizeFileKey(d.file || '')]) d.prTwin = true; });\n    prList.forEach(function (pr) { designs.push(pr); });\n    markProductionFiles(designs);\n    return designs;\n  }\n\n  /* ------------------------------------------------------------------ cache */\n  /* sessionStorage SWR cache of the RAW server results, keyed per customer. The\n     metadata payload is ~0.5 KB/design (>1 MB for power users) and was\n     otherwise re-fetched in full on every open. */\n\n  function cacheKey(customerId) { return 'mdDesignCache_' + customerId; }\n\n  function readCache(customerId) {\n    try {\n      var raw = sessionStorage.getItem(cacheKey(customerId));\n      if (!raw) return null;\n      var obj = JSON.parse(raw);\n      return (obj && obj.results) ? obj.results : null;\n    } catch (e) { return null; }\n  }\n\n  function writeCache(customerId, results) {\n    try {\n      sessionStorage.setItem(cacheKey(customerId), JSON.stringify({ results: results, ts: Date.now() }));\n    } catch (e) {}\n  }\n\n  function clearCache(customerId) {\n    try { sessionStorage.removeItem(cacheKey(customerId)); } catch (e) {}\n  }\n\n  /* ------------------------------------------------------------------ fetch */\n\n  function fetchServerResults(customerId, includeGangUploads) {\n    return Promise.all([\n      fetch(API + '/uploads/fetchDataNew?customer_id=' + customerId + '&archived=true')\n        .then(function (r) { return r.json(); }).catch(function () { return []; }),\n      fetch(API + '/uploads/orderDataNew?customer_id=' + customerId + '&gangsheet=false')\n        .then(function (r) { return r.json(); }).catch(function () { return []; }),\n      fetch(API + '/uploads/orderDataNew?customer_id=' + customerId + '&gangsheet=true')\n        .then(function (r) { return r.json(); }).catch(function () { return []; }),\n      /* Gang Sheet Builder saved sheets \u2014 the BUILDER's backend, not the\n         uploads feed (its My Gang Sheets modal reads the same endpoint;\n         CORS admits this origin). Failure degrades to an empty list, never\n         a broken library. */\n      lookupMode()\n        ? Promise.resolve([])   /* viewer-scoped \u2014 see lookupMode() */\n        : fetch(GSB_SAVED_API, { credentials: 'same-origin' })\n            .then(function (r) { return r.json(); }).catch(function () { return []; }),\n      /* Gang-sheet UPLOADS (results[4]): the base fetchDataNew above returns\n         only non-gang uploads (no gangsheet param -> server default), so a\n         gang-sheet upload surface would show none of the customer's finished\n         sheets. The live gang upload fetches fetchDataNew?gangsheet=true for\n         exactly this. Requested ONLY when the surface forces the gangsheet\n         type, so ordinary by-size libraries pay no extra call. */\n      includeGangUploads\n        ? fetch(API + '/uploads/fetchDataNew?customer_id=' + customerId + '&archived=true&gangsheet=true')\n            .then(function (r) { return r.json(); }).catch(function () { return []; })\n        : Promise.resolve([]),\n      /* The customer's own recent Shopify orders (results[5]) \u2014 see fetchShopifyOrders. */\n      fetchShopifyOrders(),\n      /* Staff lookup only (results[6]): the looked-up customer's print-ready files. */\n      fetchLookupArt(customerId),\n      /* Gang Sheet Builder images (results[7]) \u2014 see GSB_UPLOADS_API. */\n      fetch(GSB_UPLOADS_API + encodeURIComponent(customerId), { credentials: 'include' })\n        .then(function (r) { return r.json(); }).catch(function () { return null; })\n    ]);\n  }\n\n  /* Staff lookup (Justin 2026-10-13): the looked-up customer's production art, from the\n     Production Art Sync app's proxy. Shopify signs the request and names the signed-in viewer;\n     the app answers staff only (production-art-sync src/proxy.mjs). Any failure \u2192 null, the\n     library as before. */\n  function fetchLookupArt(customerId) {\n    if (!lookupMode()) return Promise.resolve(null);\n    return fetch('/apps/production-art/customer?id=' + encodeURIComponent(customerId), { credentials: 'same-origin', headers: { Accept: 'application/json' } })\n      .then(function (r) { return r.ok ? r.json() : null; })\n      .then(function (j) { return j && Array.isArray(j.items) ? j.items : null; })\n      .catch(function () { return null; });\n  }\n  /* Purchase rows (orderDataNew shape, like the Shopify-orders feed) for print-ready files whose\n     order the uploads API never recorded (after 2026-05-27): the file itself is the design.\n     Files a reprint replaced (r) are left out, the reprint has its own entry. */\n  function productionArtRows(items) {\n    return items.filter(function (it) { return it && it.u && it.o && !it.r; }).map(function (it) {\n      var t = Date.parse(it.d || '') || 0;\n      return {\n        order_name: it.o, product_id: '', quantity: 0,\n        variant_title: it.w && it.h ? it.w + ' X ' + it.h : '',\n        /* the version the customer added to cart (k[0] = the line's _Upload key, on our uploads\n           host) \u2014 our file shows on its own under Print Ready Files (Justin 2026-10-13) */\n        file: cartArtOf(it),\n        formatted_date: t ? Math.floor(t / 1000) : '',\n        order_date: t ? 'Purchased ' + new Date(t).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC' }) : '',\n        file_name: it.o + (it.t ? ' \u00B7 ' + it.t : ''),\n        gangsheet: !!it.g || /gang sheet/i.test(it.t || ''),\n        quantity: parseInt(it.q, 10) || 0,\n        archived: false\n      };\n    });\n  }\n  function cartArtOf(it) {\n    var k = Array.isArray(it.k) && it.k[0];\n    if (!k || /\\//.test(k) || k === normalizeFileKey(it.u)) return it.u;\n    return 'https://' + IMGIX_HOST + '/' + encodeURIComponent(k);\n  }\n\n  /* Shopify's own orders as a purchase fallback (Justin 2026-09-29). The uploads\n     API's orderDataNew stopped recording orders after 2026-05-27, so designs\n     bought since then read as \"Uploaded\" with no history and the wrong\n     \"Order as \u2026\" product. templates/page.nt-orders-feed.liquid renders the\n     signed-in customer's newest 50 orders' design lines in the orderDataNew\n     row shape; processServerResults adds the ones the backend does not have.\n     preview_theme_id is passed through so a sandbox session reads the\n     sandbox template. Any failure \u2192 [] (the backend feed alone, as before). */\n  var SHOPIFY_ORDERS_URL = '/pages/welcome?view=nt-orders-feed';\n  function fetchShopifyOrders() {\n    if (lookupMode()) return Promise.resolve([]);   /* viewer-scoped \u2014 see lookupMode() */\n    var url = SHOPIFY_ORDERS_URL;\n    try {\n      var pv = new URLSearchParams(window.location.search).get('preview_theme_id');\n      if (pv) url += '&preview_theme_id=' + encodeURIComponent(pv);\n    } catch (e) {}\n    return fetch(url, { credentials: 'same-origin' })\n      .then(function (r) { return r.ok ? r.text() : ''; })\n      .then(function (html) {\n        var m = /<script[^>]*id=\"nt-orders-feed\"[^>]*>([\\s\\S]*?)<\\/script>/.exec(html || '');\n        var rows = m ? JSON.parse(m[1]) : [];\n        return Array.isArray(rows) ? rows : [];\n      })\n      .catch(function () { return []; });\n  }\n\n  /**\n   * Load the customer's artwork.\n   *\n   * @param {string|number} customerId\n   * @param {Object} [opts]\n   * @param {Function} [opts.onCached] called with designs[] if a cached paint\n   *                   is available, BEFORE the network result lands. Lets the\n   *                   modal paint instantly and revalidate behind it.\n   * @returns {Promise<Array>} the authoritative (network) designs array.\n   */\n  function load(customerId, opts) {\n    opts = opts || {};\n    /* the live cart is the newest 'how they used it' signal (applyUsageLooks) */\n    var cartLooks = fetchCartLooks();\n    if (typeof opts.onCached === 'function') {\n      var cached = readCache(customerId);\n      if (cached) {\n        try { opts.onCached(processServerResults(cached, null, customerId)); } catch (e) {}\n      }\n    }\n    return Promise.all([fetchServerResults(customerId, !!opts.gang), cartLooks]).then(function (r) {\n      writeCache(customerId, r[0]);\n      return processServerResults(r[0], r[1], customerId);\n    });\n  }\n\n  /* ---------------------------------------------------------------- archive */\n  /* Archive state lives on the server. Two photo_id flavours, picked by source:\n       upload   -> server-issued photo_id from fetchDataNew\n       purchase -> the raw URL basename (NOT fileName, which strips the\n                   \"____image_...\" suffix for display), plus shopify=1 so the\n                   endpoint treats photo_id as a Shopify-side filename. */\n\n  function archivePhotoIdFor(d) {\n    if (!d) return '';\n    if (d.source === 'purchase') return normalizeFileKey(d.file || '');\n    return d.photoId || '';\n  }\n\n  function setArchived(customerId, design, restore) {\n    /* read-only in staff lookup mode \u2014 see lookupMode() */\n    if (lookupMode()) return Promise.reject(new Error('read-only: staff lookup'));\n    var photoId = archivePhotoIdFor(design);\n    if (!photoId) return;\n    if (isBuilderPid(photoId)) {\n      markBuilder(customerId, photoId, restore ? '' : 'archived');\n      clearCache(customerId);\n      try {\n        window.dispatchEvent(new CustomEvent('nt-archive-changed', {\n          detail: { source: 'artwork-library-v2', ids: [String(design.id)], action: restore ? 'unarchive' : 'archive' }\n        }));\n      } catch (e) {}\n      return Promise.resolve();\n    }\n    var url = API + '/uploads/archiveData?customer_id=' + encodeURIComponent(customerId) +\n      '&photo_id=' + encodeURIComponent(photoId);\n    if (design.source === 'purchase') url += '&shopify=1';\n    if (restore) url += '&restore=1';\n    var req = Promise.resolve();\n    try { req = fetch(url).then(function () {}, function () {}); } catch (e) {}\n    clearCache(customerId);\n    try {\n      window.dispatchEvent(new CustomEvent('nt-archive-changed', {\n        detail: {\n          source: 'artwork-library-v2',\n          ids: [String(design.id)],\n          action: restore ? 'unarchive' : 'archive'\n        }\n      }));\n    } catch (e) {}\n    /* 2026-09-10: returns the (always-settled) request so a caller that\n       mirrors this change to another library instance can wait for the\n       server before that instance refetches. Existing callers ignore it. */\n    return req;\n  }\n\n  /* Permanent delete. Mirrors the live panel's call exactly:\n     /uploads/deleteData?customer_id=&photo_id=\n\n     \u26A0 Uses the RAW photoId, not archivePhotoIdFor(). Archive substitutes a\n     purchase's file basename because the archive endpoint accepts it; the\n     delete endpoint does not, and the live panel guards on photo_id for the\n     same reason. Anything without one is refused here rather than fired off\n     and silently doing nothing \u2014 the caller needs to know, because unlike\n     archive there is no Undo to fall back on.\n\n     Returns the fetch promise so the caller can wait before claiming success.\n     setArchived returns a settled promise too (since 2026-09-10; it used not to, because archive is reversible and a\n     failed call costs an out-of-date row; a failed delete that reported\n     success would show the design as gone until the next load. */\n  function deleteDesign(customerId, design) {\n    /* read-only in staff lookup mode \u2014 see lookupMode() */\n    if (lookupMode()) return Promise.reject(new Error('read-only: staff lookup'));\n    /* Delete EVERY same-content copy, not just the survivor. A re-uploaded file\n       collapses into one card (aliasSameFileUploads / combineDuplicates); the\n       dropped copies carry their own photo_ids in dupePhotoIds. Deleting only\n       the survivor left the rest behind and the design re-appeared on reload\n       (Owen 2026-09-30, uploaded gang sheets). */\n    var photoIds = [];\n    if (design && design.photoId) photoIds.push(design.photoId);\n    (design && design.dupePhotoIds || []).forEach(function (p) {\n      if (p && photoIds.indexOf(p) === -1) photoIds.push(p);\n    });\n    if (!photoIds.length) return Promise.reject(new Error('no photo_id'));\n    clearCache(customerId);\n    /* builder rows: ledger only (see BUILDER_PID); the API never had them */\n    photoIds = photoIds.filter(function (p) {\n      if (!isBuilderPid(p)) return true;\n      markBuilder(customerId, p, 'deleted');\n      return false;\n    });\n    if (!photoIds.length) {\n      try {\n        window.dispatchEvent(new CustomEvent('nt-archive-changed', {\n          detail: { source: 'artwork-library-v2', ids: [String(design.id)], action: 'delete' }\n        }));\n      } catch (e) {}\n      return Promise.resolve(true);\n    }\n    function call(pid) {\n      return fetch(API + '/uploads/deleteData?customer_id=' + encodeURIComponent(customerId) +\n        '&photo_id=' + encodeURIComponent(pid)).then(function (r) {\n        if (!r.ok) throw new Error('delete failed: ' + r.status);\n        return true;\n      });\n    }\n    /* \u26A0 API semantics, endpoint-verified 2026-09-03: on an ARCHIVED record\n       the first deleteData removes only its ARCHIVE row \u2014 the upload\n       survives, un-archived (QA: 'deleted' archives reappeared under Uploads\n       and every count grew). A second call deletes the record itself. */\n    function deleteRow(pid, archived) {\n      var c = call(pid);\n      if (archived) c = c.then(function () { return call(pid); });\n      return c;\n    }\n    var attempted = {};\n    photoIds.forEach(function (p) { attempted[p] = 1; });\n    var chain = Promise.all(photoIds.map(function (pid) {\n      return deleteRow(pid, !!(design && design.archived));\n    }));\n    /* \u26A0 The copies above are only the ones this client could SEE. The feed\n       returns ONE row per file_crc and prefers an unarchived one, so a file\n       re-uploaded N times is N server rows of which the grid shows one; delete\n       that one and the next copy surfaces on the following fetch (Owen\n       2026-10-01: \"I delete one and another of the dupes makes it reappear\" \u2014\n       qa-gang-22x24-300.png: c5aea6a4 \u2192 201ed006 \u2192 f439a07d, same crc). So\n       after the visible copies go, re-fetch the RAW feed, delete any remaining\n       row of the same file, and repeat until the feed shows none. \"Same file\"\n       = same crc, else same file basename, else \u2014 gang only \u2014 same display\n       name; a matched row's crc/basename widen the match for the next round.\n       A row the server will not delete would loop forever, so a round that\n       re-finds only rows already deleted stops and rejects \u2014 the UI then says\n       it could not delete rather than showing a success the server never\n       made. The cap is generous because it is per COPY: the QA account's\n       qa-gang had well over eight (c5aea6a4, 201ed006, f439a07d, d9a34dd6, \u2026,\n       one surfacing per delete); progress, not the cap, is the normal stop.\n       Reads raw; never writes the SWR cache; clears it again at the end. */\n    var MAX_ROUNDS = 30;\n    var gang = !!(design && design.gangsheet);\n    var sig = { crcs: {}, bases: {}, names: {} };\n    if (design && design.crc) sig.crcs[design.crc] = 1;\n    if (design && design.file) sig.bases[normalizeFileKey(design.file)] = 1;\n    if (gang) {\n      var nm0 = String((design && design.fileName) || '').trim().toLowerCase();\n      if (nm0 && nm0 !== 'undefined') sig.names[nm0] = 1;\n    }\n    function matches(raw) {\n      if (!raw) return false;\n      var c = normCrc(raw.file_crc);\n      if (c && sig.crcs[c]) return true;\n      var b = normalizeFileKey(raw.file || '');\n      if (b && sig.bases[b]) return true;\n      if (gang && raw.gangsheet) {\n        var n = String(stripUploadSuffix(raw.file_name || '')).trim().toLowerCase();\n        if (n && n !== 'undefined' && sig.names[n]) return true;\n      }\n      return false;\n    }\n    function widen(raw) {\n      var c = normCrc(raw.file_crc); if (c) sig.crcs[c] = 1;\n      var b = normalizeFileKey(raw.file || ''); if (b) sig.bases[b] = 1;\n    }\n    function fetchRows() {\n      var base = API + '/uploads/fetchDataNew?customer_id=' + encodeURIComponent(customerId) + '&archived=true';\n      /* the base and gangsheet=true feeds return DIFFERENT gang row sets\n         (20 vs 25 on QA) \u2014 read both for a gang design */\n      var urls = gang ? [base, base + '&gangsheet=true'] : [base];\n      return Promise.all(urls.map(function (u) {\n        return fetch(u).then(function (r) {\n          if (!r.ok) throw new Error('feed failed: ' + r.status);\n          return r.json();\n        });\n      })).then(function (parts) {\n        var rows = [];\n        parts.forEach(function (p) {\n          var d = p && p.data ? p.data : p;\n          if (Array.isArray(d)) rows = rows.concat(d);\n        });\n        return rows;\n      });\n    }\n    var rounds = 0;\n    function round() {\n      if (rounds >= MAX_ROUNDS) throw new Error('delete incomplete');\n      rounds++;\n      return fetchRows().then(function (rows) {\n        var hit = rows.filter(matches);\n        hit.forEach(widen);\n        hit = rows.filter(matches);\n        var seen = {}, left = [], fresh = false;\n        hit.forEach(function (r) {\n          if (!r.photo_id || seen[r.photo_id]) return;\n          seen[r.photo_id] = 1;\n          left.push(r);\n          if (!attempted[r.photo_id]) fresh = true;\n        });\n        if (!left.length) return;                              /* gone \u2014 done */\n        if (!fresh) throw new Error('delete refused');         /* server kept rows we already deleted */\n        return Promise.all(left.map(function (r) {\n          attempted[r.photo_id] = 1;\n          return deleteRow(r.photo_id, !!r.archived);\n        })).then(round);\n      });\n    }\n    return chain.then(round).then(function () {\n      clearCache(customerId);\n      try {\n        window.dispatchEvent(new CustomEvent('nt-archive-changed', {\n          detail: { source: 'artwork-library-v2', ids: [String(design.id)], action: 'delete' }\n        }));\n      } catch (e) {}\n      return true;\n    });\n  }\n\n  /* Delete an UNORDERED builder save through the app proxy (builder v0.201.0,\n     PR #705): POST /apps/ninja-gang-sheet/saved-designs/<id>/delete \u2014 same\n     HMAC/customer-from-session contract as the saved-designs list and /open,\n     no body. Builder saves live in the builder's system (gangSaveId), not our\n     uploads DB, so this cannot go through /uploads/deleteData. Hard delete, no\n     restore. 200 = deleted OR already gone (idempotent); 409 = the server\n     refused an ordered save (it enforces this too), surfaced as err.code\n     'ordered' so the UI can re-lock it; 401/403 bubble as generic failures.\n     credentials:'same-origin' sends the customer session the proxy needs. */\n  function deleteGangSave(customerId, design) {\n    var id = design && design.gangSaveId;\n    if (!id) return Promise.reject(new Error('no gangSaveId'));\n    clearCache(customerId);\n    return fetch('/apps/ninja-gang-sheet/saved-designs/' + encodeURIComponent(id) + '/delete',\n      { method: 'POST', credentials: 'same-origin' }).then(function (r) {\n      if (r.status === 409) { var e = new Error('ordered'); e.code = 'ordered'; throw e; }\n      if (!r.ok) throw new Error('delete failed: ' + r.status);\n      try {\n        window.dispatchEvent(new CustomEvent('nt-archive-changed', {\n          detail: { source: 'artwork-library-v2', ids: [String(design.id)], action: 'delete' }\n        }));\n      } catch (e) {}\n      return true;\n    });\n  }\n\n  /* Ordered size out of a variant title: \"4x6\", \"10.5 x 12\", \"12x12 - 300 dpi\".\n     Ported verbatim from the live panel's extractDimensions so the two cannot\n     disagree about what a size string means. Returns null when the title is\n     not a size \u2014 \"custom\" and gang-sheet titles both land there, and the\n     caller shows the date alone rather than inventing dimensions. */\n  function parseOrderedSize(str) {\n    if (!str) return null;\n    var m = String(str).match(/([\\d.]+)[^0-9.]*([\\d.]+)/);\n    if (!m) return null;\n    var w = parseFloat(m[1]), h = parseFloat(m[2]);\n    if (!(w > 0 && h > 0)) return null;\n    return { width: w, height: h };\n  }\n\n  /* The file URL a reorder must hand to the product page.\n\n     \u26A0 Not simply design.file. Ported from the live panel's\n     getOriginalOrderFile, and the branch matters:\n       ai / eps / pdf / psd -> S3. The DTF page runs these through\n         sendApiRequest, which expects the S3 (or full) URL; hand it an imgix\n         URL and the conversion never happens.\n       everything else      -> imgix, so the browser can render it via imgix's\n         own conversion (tif/svg have no special handler on that page).\n     Query strings are stripped either way \u2014 the destination builds its own. */\n  function orderFileUrl(design) {\n    if (!design) return '';\n    /* a Print Ready Files card (applyProductionArt) sends our print-ready file */\n    if (design.prod && design.prod.url) return String(design.prod.url).split('?')[0];\n    var ext = fileExt(design.file || '').toLowerCase();\n    var needsS3 = ['ai', 'eps', 'pdf', 'psd'].indexOf(ext) > -1;\n    if (needsS3) {\n      if (design.s3File) return String(design.s3File).split('?')[0];\n      return String(design.file || '').replace(IMGIX_HOST, S3_HOST).split('?')[0];\n    }\n    return String(design.file || '').split('?')[0];\n  }\n\n  /* ------------------------------------------------------------- upload\n     Upload a file INTO the library (no product page, no cart): the same\n     presign -> S3 PUT -> saveData contract my-designs-panel's upload tiles\n     use (kept in step with uploadFileToLibrary there \u2014 the 1500ms settle, the\n     ____image_ suffix, product_id 'my-designs', and the $.ajax-equivalent\n     urlencoded POST body the endpoint expects). */\n  function crc32FromArrayBuffer(arrayBuffer) {\n    var table = crc32FromArrayBuffer.table || (function () {\n      var c, t = [];\n      for (var n = 0; n < 256; n++) {\n        c = n;\n        for (var k = 0; k < 8; k++) c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));\n        t[n] = c >>> 0;\n      }\n      crc32FromArrayBuffer.table = t;\n      return t;\n    })();\n    var crc = 0 ^ (-1);\n    var bytes = new Uint8Array(arrayBuffer);\n    for (var i = 0; i < bytes.length; i++) crc = (crc >>> 8) ^ table[(crc ^ bytes[i]) & 0xFF];\n    return ((crc ^ (-1)) >>> 0).toString(16);\n  }\n\n  function sanitizeUploadName(name) {\n    return (name || 'upload')\n      .replace(/[^a-z0-9\\s]/gi, '')\n      .replace(/[_\\s]+/g, '-')\n      .replace(/^-+|-+$/g, '')\n      .toLowerCase() || 'upload';\n  }\n\n  function uploadToLibrary(customerId, file, isGangSheet) {\n    /* Staff lookup ALLOWS uploads (Justin 2026-10-12; refused 9-30\u201310-12): the\n       caller passes the LOOKED-UP customer's id, so staff upload into that\n       customer's library on their behalf. Delete/archive stay refused. */\n    var ext = (/\\.[a-z0-9]{1,5}$/i.test(file.name)\n      ? file.name.split('.').pop()\n      : ({ 'image/png': 'png', 'image/jpeg': 'jpg', 'image/webp': 'webp', 'image/gif': 'gif', 'image/svg+xml': 'svg', 'application/pdf': 'pdf', 'application/postscript': 'eps', 'image/heic': 'heic', 'image/heif': 'heif', 'image/avif': 'avif', 'image/bmp': 'bmp' }[file.type] || 'png')).toLowerCase();\n    var randomName = sanitizeUploadName(file.name.split('.').slice(0, -1).join('.') || file.name) +\n      '____image_' + Date.now() + '_' + Math.floor(Math.random() * 1000) + (ext ? '.' + ext : '');\n    var presign;\n    return fetch(API + '/uploads/getPresignedUploadUrl?file_name=' + encodeURIComponent(randomName) +\n        '&file_type=' + encodeURIComponent(file.type || 'application/octet-stream'))\n      .then(function (r) { if (!r.ok) throw new Error('Failed to get upload URL'); return r.json(); })\n      .then(function (data) {\n        presign = data;\n        if (!presign || !presign.url || !presign.sourceUrl) throw new Error('Upload URL was not returned');\n        return fetch(presign.url, { method: 'PUT', body: file });\n      })\n      .then(function (put) {\n        if (!put.ok) throw new Error('Upload failed (S3 PUT ' + put.status + ')');\n        return file.arrayBuffer().then(crc32FromArrayBuffer)['catch'](function () { return ''; });\n      })\n      .then(function (fileCrc) {\n        var filePath = toImgixHost(presign.sourceUrl) || ('https://' + IMGIX_HOST + '/' + randomName);\n        /* saveData indexes the S3 object after the PUT; the panel found the\n           record intermittently missing without a settle. Same 1500ms. */\n        return new Promise(function (res) { setTimeout(res, 1500); }).then(function () {\n          return fetch(API + '/uploads/saveData', {\n            method: 'POST',\n            headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },\n            body: JSON.stringify([{\n              variant_title: 'custom',\n              file: filePath,\n              customer_id: customerId,\n              file_name: file.name,\n              file_crc: fileCrc,\n              product_id: 'my-designs',\n              gangsheet: !!isGangSheet\n            }])\n          }).then(function (r) {\n            if (!r.ok) throw new Error('Failed to save upload (' + r.status + ')');\n            clearCache(customerId);\n            return { file: filePath, s3File: presign.sourceUrl, fileName: file.name, gangsheet: !!isGangSheet };\n          });\n        });\n      });\n  }\n\n  window.NTArtworkData = Object.freeze({\n    load: load,\n    uploadToLibrary: uploadToLibrary,\n    clearCache: clearCache,\n    setArchived: setArchived,\n    parseOrderedSize: parseOrderedSize,\n    orderFileUrl: orderFileUrl,\n    deleteDesign: deleteDesign,\n    deleteGangSave: deleteGangSave,\n    /* helpers shared with the view layer */\n    imgixUrl: imgixUrl,\n    thumbUrl: thumbUrl,\n    zoomUrl: zoomUrl,\n    fileExt: fileExt,\n    rawExt: rawExt,\n    isVectorFile: isVectorFile,\n    needsRemotePreview: needsRemotePreview,\n    extractFileName: extractFileName,\n    smartFileName: smartFileName,\n    normalizeFileKey: normalizeFileKey,\n    makeUploadMatchKey: makeUploadMatchKey,\n    studioEditUrl: studioEditUrl,\n    gangSaveEditUrl: gangSaveEditUrl,\n    /* usage looks (cart / order line -> design tile), exposed for tests and other surfaces */\n    cartLooksFromItems: cartLooksFromItems,\n    applyUsageLooks: applyUsageLooks,\n    applyProductionArt: applyProductionArt\n  });\n})();\n"],
  "mappings": "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",
  "names": []
}
