[object Object]

← back to Designer Wallcoverings

auto-save: 2026-07-08T12:35:41 (6 files) — pending-approval/boost-filter-consolidation-2026-06-25 shopify/scripts/catalog-push-to-kamatera.sh vendor-scrapers/china-seas-refresh shopify/scripts/audits/harmonize-wallquest-units-before.jsonl shopify/scripts/harmonize-wallquest-length-units.py

8db74464490b88e96b1c21942933ea9e1214e2d7 · 2026-07-08 12:35:46 -0700 · Steve Abrams

Files touched

Diff

commit 8db74464490b88e96b1c21942933ea9e1214e2d7
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 8 12:35:46 2026 -0700

    auto-save: 2026-07-08T12:35:41 (6 files) — pending-approval/boost-filter-consolidation-2026-06-25 shopify/scripts/catalog-push-to-kamatera.sh vendor-scrapers/china-seas-refresh shopify/scripts/audits/harmonize-wallquest-units-before.jsonl shopify/scripts/harmonize-wallquest-length-units.py
---
 .../audits/harmonize-wallquest-units-before.jsonl  | 107 +++++++++
 shopify/scripts/catalog-push-to-kamatera.sh        |   5 +-
 .../scripts/harmonize-wallquest-length-units.py    | 113 ++++++++++
 .../sections/main-product-high-variant.liquid      |  50 +++++
 .../snippets/color-dots.liquid                     | 245 +++++++++++++++++++++
 .../snippets/color-palette.liquid                  | 205 +++++++++++++++++
 .../snippets/colorway-siblings.liquid              | 117 ++++++++++
 .../snippets/other-colorways.liquid                | 163 ++++++++++++++
 .../snippets/product-gallery.liquid                | 226 +++++++++++++++++++
 9 files changed, 1229 insertions(+), 2 deletions(-)

diff --git a/shopify/scripts/audits/harmonize-wallquest-units-before.jsonl b/shopify/scripts/audits/harmonize-wallquest-units-before.jsonl
new file mode 100644
index 00000000..25b20779
--- /dev/null
+++ b/shopify/scripts/audits/harmonize-wallquest-units-before.jsonl
@@ -0,0 +1,107 @@
+{"id": "gid://shopify/Product/1497990135920", "handle": "yagishiri-island-koi-fish-wallpaper-cda-96718", "sr": "16.5'", "dr": "33'", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.5\" \u00d7 16.5'. Double roll: 20.5\" \u00d7 33'."}
+{"id": "gid://shopify/Product/1497993674864", "handle": "mitsu-gingko-tree-wallpaper-cda-96728", "sr": "16.5'", "dr": "33'", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.5\" \u00d7 16.5'. Double roll: 20.5\" \u00d7 33'."}
+{"id": "gid://shopify/Product/1498001834096", "handle": "rebun-island-lattice-trellis-wallpaper-cda-96752", "sr": "16.5'", "dr": "33'", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27\" \u00d7 16.5'. Double roll: 27\" \u00d7 33'."}
+{"id": "gid://shopify/Product/7292603596851", "handle": "dwqw-57545-handle", "sr": "4.425ft", "dr": "8.85ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 98.4in x 4.425ft \u00d7 4.425ft. Double roll: 98.4in x 4.425ft \u00d7 8.85ft."}
+{"id": "gid://shopify/Product/7297268744243", "handle": "dwqw-58288-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297268973619", "handle": "dwqw-58290-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297269137459", "handle": "dwqw-58291-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297269301299", "handle": "dwqw-58292-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297269497907", "handle": "dwqw-58293-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297269694515", "handle": "dwqw-58294-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297269825587", "handle": "dwqw-58295-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297269956659", "handle": "dwqw-58296-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297270218803", "handle": "dwqw-58297-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297270579251", "handle": "dwqw-58300-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297271103539", "handle": "dwqw-58304-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297281392691", "handle": "dwqw-58372-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297281490995", "handle": "dwqw-58373-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297281589299", "handle": "dwqw-58374-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297281785907", "handle": "dwqw-58376-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297281916979", "handle": "dwqw-58377-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297282048051", "handle": "dwqw-58378-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297282179123", "handle": "dwqw-58379-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297282310195", "handle": "dwqw-58380-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.5ft \u00d7 16.5ft. Double roll: 20.9in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297294794803", "handle": "dwqw-58442-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297295089715", "handle": "dwqw-58443-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297295351859", "handle": "dwqw-58444-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297295614003", "handle": "dwqw-58445-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297296302131", "handle": "dwqw-58448-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297296498739", "handle": "dwqw-58449-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297296728115", "handle": "dwqw-58450-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297296957491", "handle": "dwqw-58451-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297297186867", "handle": "dwqw-58452-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297297350707", "handle": "dwqw-58453-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297297580083", "handle": "dwqw-58454-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297298137139", "handle": "dwqw-58457-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297298464819", "handle": "dwqw-58459-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297298595891", "handle": "dwqw-58460-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297298759731", "handle": "dwqw-58461-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297298989107", "handle": "dwqw-58462-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297299120179", "handle": "dwqw-58463-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297299349555", "handle": "dwqw-58464-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297299513395", "handle": "dwqw-58465-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297300529203", "handle": "dwqw-58469-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297300856883", "handle": "dwqw-58470-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297301184563", "handle": "dwqw-58471-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297301381171", "handle": "dwqw-58472-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297301610547", "handle": "dwqw-58473-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297301872691", "handle": "dwqw-58474-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297302102067", "handle": "dwqw-58475-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297302265907", "handle": "dwqw-58476-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297302593587", "handle": "dwqw-58477-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297302855731", "handle": "dwqw-58478-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297303117875", "handle": "dwqw-58479-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297303445555", "handle": "dwqw-58480-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297303838771", "handle": "dwqw-58481-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297304035379", "handle": "dwqw-58482-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297304592435", "handle": "dwqw-58484-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297304789043", "handle": "dwqw-58485-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297305051187", "handle": "dwqw-58486-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297305280563", "handle": "dwqw-58487-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297305509939", "handle": "dwqw-58488-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297305804851", "handle": "dwqw-58489-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297306001459", "handle": "dwqw-58490-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297306230835", "handle": "dwqw-58491-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297306558515", "handle": "dwqw-58492-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297306820659", "handle": "dwqw-58493-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297311834163", "handle": "dwqw-58508-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297312129075", "handle": "dwqw-58509-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297312522291", "handle": "dwqw-58510-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297312817203", "handle": "dwqw-58511-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297313112115", "handle": "dwqw-58512-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297313374259", "handle": "dwqw-58513-handle", "sr": "16.4041666666667ft", "dr": "32.808ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 20.9in x 16.4041666666667ft \u00d7 16.4041666666667ft. Double roll: 20.9in x 16.4041666666667ft \u00d7 32.808ft."}
+{"id": "gid://shopify/Product/7297328283699", "handle": "dwqw-58564-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297328611379", "handle": "dwqw-58565-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297329004595", "handle": "dwqw-58566-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297329365043", "handle": "dwqw-58567-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297329725491", "handle": "dwqw-58568-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297330118707", "handle": "dwqw-58569-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297330479155", "handle": "dwqw-58570-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297330741299", "handle": "dwqw-58571-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297330937907", "handle": "dwqw-58572-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297331200051", "handle": "dwqw-58573-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297331429427", "handle": "dwqw-58574-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297331626035", "handle": "dwqw-58575-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297332019251", "handle": "dwqw-58576-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297332314163", "handle": "dwqw-58577-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297332609075", "handle": "dwqw-58578-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297332871219", "handle": "dwqw-58579-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297333133363", "handle": "dwqw-58580-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297333362739", "handle": "dwqw-58581-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297333592115", "handle": "dwqw-58582-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297333854259", "handle": "dwqw-58583-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297334575155", "handle": "dwqw-58586-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297334870067", "handle": "dwqw-58587-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297335197747", "handle": "dwqw-58588-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297335459891", "handle": "dwqw-58589-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297335689267", "handle": "dwqw-58590-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297336016947", "handle": "dwqw-58591-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297336279091", "handle": "dwqw-58592-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297336803379", "handle": "dwqw-58594-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297336999987", "handle": "dwqw-58595-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297337196595", "handle": "dwqw-58596-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297337524275", "handle": "dwqw-58597-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297337819187", "handle": "dwqw-58598-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297338081331", "handle": "dwqw-58599-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297338441779", "handle": "dwqw-58600-handle", "sr": "16.5ft", "dr": "33ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.5ft \u00d7 16.5ft. Double roll: 27.5in x 16.5ft \u00d7 33ft."}
+{"id": "gid://shopify/Product/7297338703923", "handle": "dwqw-58601-handle", "sr": "16.485ft", "dr": "32.97ft", "uom": "Priced per single roll \u2014 packaged in double rolls only. Single roll: 27.5in x 16.485ft \u00d7 16.485ft. Double roll: 27.5in x 16.485ft \u00d7 32.97ft."}
diff --git a/shopify/scripts/catalog-push-to-kamatera.sh b/shopify/scripts/catalog-push-to-kamatera.sh
index 998debc7..70a884b4 100755
--- a/shopify/scripts/catalog-push-to-kamatera.sh
+++ b/shopify/scripts/catalog-push-to-kamatera.sh
@@ -28,8 +28,9 @@ KAM='postgresql://dw_admin@127.0.0.1:5432/dw_unified'
 psql "$MAC3" -tAc 'select 1' >/dev/null 2>&1 || { echo "mac3 dw_unified unreachable — abort"; exit 1; }
 ssh -o ConnectTimeout=15 my-server "psql '$KAM' -tAc 'select 1'" >/dev/null 2>&1 || { echo "Kamatera unreachable — abort"; exit 1; }
 
-# every *_catalog table on mac3
-mapfile -t TABLES < <(psql "$MAC3" -tAc "select tablename from pg_tables where schemaname='public' and tablename ~ '^[a-z0-9_]+_catalog\$' order by 1")
+# every *_catalog table on mac3 (bash 3.2-safe array read — macOS /bin/bash lacks mapfile)
+TABLES=()
+while IFS= read -r line; do [ -n "$line" ] && TABLES+=("$line"); done < <(psql "$MAC3" -tAc "select tablename from pg_tables where schemaname='public' and tablename ~ '^[a-z0-9_]+_catalog\$' order by 1")
 [ "${#TABLES[@]}" -eq 0 ] && { echo "no *_catalog tables on mac3 — abort"; exit 1; }
 ARGS=(); for t in "${TABLES[@]}"; do ARGS+=(-t "$t"); done
 echo "syncing ${#TABLES[@]} catalog tables"
diff --git a/shopify/scripts/harmonize-wallquest-length-units.py b/shopify/scripts/harmonize-wallquest-length-units.py
new file mode 100644
index 00000000..090bebf6
--- /dev/null
+++ b/shopify/scripts/harmonize-wallquest-length-units.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+"""
+Harmonize WallQuest (Malibu Wallpaper) S/R + D/R length UNITS to yards (DTD verdict A, 2026-07-08).
+
+The double-roll length pass left units mixed: most rows show yards ('5.5 yd / 11 yd'), a CDA subset
+shows the equivalent in feet ('16.5\\' / 33\\'') because their source length field held a "W x L"
+string in feet. Values are correct; this converts feet -> yards (÷3) so the whole line is consistent.
+
+Idempotent: only touches single_roll_length / double_roll_length that are expressed in FEET (a
+trailing ' or 'ft'/'feet', no 'yd'). Recomputes the unit_of_measure copy from the yard values.
+Values only change UNIT, not magnitude (16.5 ft = 5.5 yd). Before-state -> audits/ for rollback.
+
+Default --dry ; --live to apply.  Run: SHOPIFY_ADMIN_TOKEN=... python3 harmonize-wallquest-length-units.py [--live]
+"""
+import json, os, re, sys, time, urllib.request, urllib.error
+
+TOKEN = os.environ["SHOPIFY_ADMIN_TOKEN"]
+SHOP  = os.environ.get("SHOPIFY_SHOP", "designer-laboratory-sandbox.myshopify.com")
+GQL   = f"https://{SHOP}/admin/api/2024-10/graphql.json"
+LIVE  = "--live" in sys.argv
+VENDOR = "Malibu Wallpaper"
+HERE  = os.path.dirname(os.path.abspath(__file__))
+BEFORE = os.path.join(HERE, "audits", "harmonize-wallquest-units-before.jsonl")
+os.makedirs(os.path.dirname(BEFORE), exist_ok=True)
+
+# a length in feet: a number followed by ' or ft/feet (and NOT already yards)
+FEET_RE = re.compile(r"^\s*\d+(?:\.\d+)?\s*(?:'|ft|feet)\s*$", re.I)
+
+def gql(q, v=None):
+    body = json.dumps({"query": q, "variables": v or {}}).encode()
+    req = urllib.request.Request(GQL, data=body, headers={"X-Shopify-Access-Token": TOKEN, "Content-Type": "application/json"})
+    for _ in range(8):
+        try:
+            with urllib.request.urlopen(req) as r: d = json.load(r)
+            if d.get("errors"):
+                s = json.dumps(d["errors"])
+                if "THROTTLED" in s: time.sleep(2.5); continue
+                raise SystemExit("GQL ERR: " + s)
+            return d["data"]
+        except urllib.error.HTTPError as e:
+            if e.code == 429: time.sleep(2.5); continue
+            raise
+    raise SystemExit("retries exhausted")
+
+def fmt(x):
+    return str(int(x)) if abs(x-round(x)) < 1e-9 else f"{round(x,3):g}"
+
+def feet_to_yards(s):
+    """'16.5\\'' / '33 ft' -> '5.5 yd' / '11 yd'. None if not a feet value."""
+    if not s or not FEET_RE.match(str(s)): return None
+    m = re.search(r"(\d+(?:\.\d+)?)", str(s))
+    return f"{fmt(float(m.group(1))/3)} yd"
+
+PAGE = """
+query($v:String!,$cursor:String){
+  products(first:80, after:$cursor, query:$v){
+    pageInfo{ hasNextPage endCursor }
+    nodes{ id handle
+      w:  metafield(namespace:"global", key:"width"){ value }
+      sr: metafield(namespace:"global", key:"single_roll_length"){ value }
+      dr: metafield(namespace:"global", key:"double_roll_length"){ value }
+      uom:metafield(namespace:"global", key:"unit_of_measure"){ value } }
+  }
+}"""
+SET = """mutation($mfs:[MetafieldsSetInput!]!){ metafieldsSet(metafields:$mfs){ userErrors{ field message } } }"""
+
+def mf(owner, key, val):
+    return {"ownerId": owner, "namespace": "global", "key": key, "type": "single_line_text_field", "value": val}
+
+def main():
+    prods, cursor = [], None
+    vq = f"vendor:'{VENDOR}' status:active,draft"
+    while True:
+        d = gql(PAGE, {"v": vq, "cursor": cursor})["products"]
+        prods.extend(d["nodes"]); sys.stderr.write(f"\rscanned {len(prods)}")
+        if not d["pageInfo"]["hasNextPage"]: break
+        cursor = d["pageInfo"]["endCursor"]; time.sleep(0.25)
+    sys.stderr.write("\n")
+
+    inputs, converted, samples = [], 0, []
+    bf = open(BEFORE, "w")
+    for p in prods:
+        sr = (p["sr"] or {}).get("value"); dr = (p["dr"] or {}).get("value")
+        nsr = feet_to_yards(sr); ndr = feet_to_yards(dr)
+        if not (nsr or ndr): continue
+        converted += 1
+        bf.write(json.dumps({"id": p["id"], "handle": p["handle"], "sr": sr, "dr": dr, "uom": (p["uom"] or {}).get("value")}) + "\n")
+        fsr = nsr or sr; fdr = ndr or dr
+        if nsr: inputs.append(mf(p["id"], "single_roll_length", nsr))
+        if ndr: inputs.append(mf(p["id"], "double_roll_length", ndr))
+        W = (p["w"] or {}).get("value") or ""
+        copy = (f"Priced per single roll — packaged in double rolls only. "
+                f"Single roll: {W} × {fsr}. Double roll: {W} × {fdr}.")
+        if (p["uom"] or {}).get("value") != copy:
+            inputs.append(mf(p["id"], "unit_of_measure", copy))
+        if len(samples) < 8: samples.append(f"{p['handle'][:42]:42} S/R {sr!r}->{nsr!r}  D/R {dr!r}->{ndr!r}")
+    bf.close()
+
+    print(f"{VENDOR}: scanned {len(prods)} | feet->yd products {converted} | writes {len(inputs)}")
+    for s in samples: print("   ", s)
+    print("before-state:", BEFORE)
+    if not LIVE:
+        print("\nDRY RUN — no writes. Re-run with --live to apply."); return
+    done = errs = 0
+    for i in range(0, len(inputs), 25):
+        b = inputs[i:i+25]; d = gql(SET, {"mfs": b})
+        ue = d["metafieldsSet"]["userErrors"]
+        if ue: errs += len(ue); print("userErrors:", ue[:3])
+        done += len(b); time.sleep(0.3)
+    print(f"DONE. wrote {done} metafields, userErrors={errs}")
+
+if __name__ == "__main__":
+    main()
diff --git a/shopify/theme-LIVE-591-pull-20260708/sections/main-product-high-variant.liquid b/shopify/theme-LIVE-591-pull-20260708/sections/main-product-high-variant.liquid
new file mode 100644
index 00000000..1ef0cf5a
--- /dev/null
+++ b/shopify/theme-LIVE-591-pull-20260708/sections/main-product-high-variant.liquid
@@ -0,0 +1,50 @@
+{% render 'breadcrumbs' %}
+
+{% capture slot_gallery %}
+  {% content_for 'block', type: '_section-flex-pdp-media-gallery', id: 'section-flex-pdp-media-gallery' %}
+{% endcapture %}
+
+{% capture slot_details %}
+  {% content_for 'blocks' %}
+{% endcapture %}
+
+{%- render 'section.flex-pdp', slot_gallery: slot_gallery, slot_details: slot_details -%}
+
+{% schema %}
+{
+  "name": "t:flex_pdp.section.high_variant.name",
+  "blocks": [
+    {"type": "@app"},
+    {"type": "@theme"},
+    {"type": "_section-flex-pdp-buy-buttons"},
+    {"type": "_section-flex-pdp-description"},
+    {"type": "_section-flex-pdp-divider"},
+    {"type": "_section-flex-pdp-policies"},
+    {"type": "_section-flex-pdp-price"},
+    {"type": "_section-flex-pdp-quantity-picker"},
+    {"type": "_section-flex-pdp-sku"},
+    {"type": "_section-flex-pdp-title"},
+    {"type": "_section-flex-pdp-variant-picker"},
+    {"type": "_section-flex-pdp-vendor"},
+    {"type": "_section-flex-pdp-pick-up"},
+    {"type": "_section-flex-pdp-installments"}
+  ],
+  "presets": [
+    {
+      "name": "t:flex_pdp.section.high_variant.name",
+      "blocks": [
+        {"type": "_section-flex-pdp-title"},
+        {"type": "_section-flex-pdp-vendor"},
+        {"type": "_section-flex-pdp-price"},
+        {"type": "_section-flex-pdp-installments"},
+        {"type": "_section-flex-pdp-divider"},
+        {"type": "_section-flex-pdp-variant-picker"},
+        {"type": "_section-flex-pdp-quantity-picker"},
+        {"type": "_section-flex-pdp-buy-buttons"},
+        {"type": "_section-flex-pdp-pick-up"},
+        {"type": "_section-flex-pdp-description"}
+      ]
+    }
+  ]
+}
+{% endschema %}
\ No newline at end of file
diff --git a/shopify/theme-LIVE-591-pull-20260708/snippets/color-dots.liquid b/shopify/theme-LIVE-591-pull-20260708/snippets/color-dots.liquid
new file mode 100644
index 00000000..3b97e2c2
--- /dev/null
+++ b/shopify/theme-LIVE-591-pull-20260708/snippets/color-dots.liquid
@@ -0,0 +1,245 @@
+{% assign color_dots_json_val = product.metafields.custom.color_dots_json.value %}
+{% assign color_details_val = product.metafields.custom.color_details.value %}
+{% if color_dots_json_val != blank %}
+  {% assign color_details_raw = color_dots_json_val | json %}
+{% elsif color_details_val != blank %}
+  {% assign color_details_raw = color_details_val | json %}
+{% else %}
+  {% assign color_details_raw = blank %}
+{% endif %}
+{% assign color_hex = product.metafields.custom.color_hex.value %}
+{% assign primary_hex = product.metafields.custom.primary_color_hex.value %}
+{% assign ai_colors_raw = product.metafields.dwc.ai_generated_colors.value | json %}
+{% assign color_name = product.metafields.custom.color_name.value %}
+
+{%- comment -%}
+  Color Dots v3 — 3-tier color system
+  Tier 1: color_details metafield (Gemini-enriched)
+  Tier 2: primary_color_hex + ai_generated_colors
+  Tier 3: Canvas pixel extraction from product image (onload)
+{%- endcomment -%}
+
+<div class="dw-color-dots" id="dw-color-dots-wrapper" style="display:flex;justify-content:center;gap:10px;padding:12px 0 8px;flex-wrap:wrap;min-height:30px;">
+  <div id="dw-color-dots-container" style="display:flex;justify-content:center;gap:10px;flex-wrap:wrap;"
+    {% if color_details_raw != blank and color_details_raw != 'null' %}data-colors='{{ color_details_raw | json }}'{% endif %}
+    {% if primary_hex != blank %}data-primary-hex="{{ primary_hex }}"{% endif %}
+    {% if ai_colors_raw != blank and ai_colors_raw != 'null' %}data-ai-colors='{{ ai_colors_raw }}'{% endif %}
+    {% if color_name != blank %}data-color-name="{{ color_name }}"{% endif %}
+    {% if color_hex != blank %}data-color-hex="{{ color_hex }}"{% endif %}
+    {% if product.featured_image %}data-product-image="{{ product.featured_image | img_url: '200x200' }}"{% endif %}
+  ></div>
+</div>
+
+<script>
+(function(){
+  function init() {
+   try {
+    var container = document.getElementById('dw-color-dots-container');
+    if (!container || container.dataset.rendered) return;
+    container.dataset.rendered = '1';
+
+    var C = {
+      'red':'red-wallpaper-collection','crimson':'red-wallpaper-collection','burgundy':'red-wallpaper-collection','wine':'red-wallpaper-collection','maroon':'red-wallpaper-collection',
+      'blue':'blue-wallpaper-collection','navy':'blue-wallpaper-collection','cobalt':'blue-wallpaper-collection','indigo':'blue-wallpaper-collection','sky blue':'blue-wallpaper-collection','steel blue':'blue-wallpaper-collection','royal blue':'blue-wallpaper-collection',
+      'green':'green-wallpaper-collection','sage':'green-wallpaper-collection','olive':'green-wallpaper-collection','forest green':'green-wallpaper-collection','emerald':'green-wallpaper-collection','mint':'green-wallpaper-collection','moss':'green-wallpaper-collection',
+      'gold':'gold-wallpaper','golden':'gold-wallpaper','amber':'gold-wallpaper',
+      'yellow':'yellow-wallpaper-collection','mustard':'yellow-wallpaper-collection',
+      'orange':'orange','rust':'orange','terracotta':'orange',
+      'pink':'pink-wallcovering-2','blush':'pink-wallcovering-2','rose':'pink-wallcovering-2','salmon':'pink-wallcovering-2','fuchsia':'pink-wallcovering-2',
+      'purple':'purple','violet':'purple','plum':'purple','lavender':'purple','lilac':'purple','mauve':'purple',
+      'black':'black','charcoal':'black','ebony':'black','onyx':'black',
+      'white':'white-wallpaper-collection','ivory':'white-wallpaper-collection','cream':'white-wallpaper-collection','pearl':'white-wallpaper-collection','off-white':'white-wallpaper-collection',
+      'gray':'grey-wallcovering','grey':'grey-wallcovering','silver':'grey-silver','slate':'grey-wallcovering',
+      'brown':'brown-wallpaper-collection','chocolate':'brown-wallpaper-collection','espresso':'brown-wallpaper-collection','walnut':'brown-wallpaper-collection','mocha':'brown-wallpaper-collection','sienna':'brown-wallpaper-collection',
+      'beige':'beige-cream-wallpaper-collection','tan':'beige-cream-wallpaper-collection','taupe':'beige-cream-wallpaper-collection','sand':'beige-cream-wallpaper-collection','khaki':'beige-cream-wallpaper-collection','camel':'beige-cream-wallpaper-collection','oatmeal':'beige-cream-wallpaper-collection','linen':'beige-cream-wallpaper-collection',
+      'coral':'coral','peach':'coral',
+      'teal':'turquoise','aqua':'turquoise','turquoise':'turquoise','cyan':'turquoise',
+      'metallic':'metallic-wallpaper-collections','copper':'metallic-wallpaper-collections','bronze':'metallic-wallpaper-collections'
+    };
+
+    var N = {
+      'red':'#DC2626','crimson':'#DC143C','burgundy':'#800020','wine':'#722F37','maroon':'#800000',
+      'blue':'#2563EB','navy':'#1B2A4A','cobalt':'#0047AB','indigo':'#3F51B5','sky blue':'#87CEEB','steel blue':'#4682B4','royal blue':'#4169E1',
+      'green':'#16A34A','sage':'#87AE73','olive':'#808000','forest green':'#228B22','emerald':'#50C878','mint':'#98FF98','moss':'#8A9A5B',
+      'gold':'#D4AF37','golden':'#FFD700','amber':'#FFBF00',
+      'yellow':'#EAB308','mustard':'#FFDB58',
+      'orange':'#EA580C','rust':'#B7410E','terracotta':'#E2725B',
+      'pink':'#EC4899','blush':'#DE5D83','rose':'#FF007F','salmon':'#FA8072','fuchsia':'#FF00FF',
+      'purple':'#9333EA','violet':'#7C3AED','plum':'#8E4585','lavender':'#E6E6FA','lilac':'#C8A2C8','mauve':'#E0B0FF',
+      'black':'#1A1A1A','charcoal':'#36454F','ebony':'#555D50','onyx':'#353839',
+      'white':'#FAFAFA','ivory':'#FFFFF0','cream':'#FFFDD0','pearl':'#F0EAD6','off-white':'#FAF9F6',
+      'gray':'#6B7280','grey':'#6B7280','silver':'#C0C0C0','slate':'#708090',
+      'brown':'#92400E','chocolate':'#7B3F00','espresso':'#3C1414','walnut':'#5C3A1D','mocha':'#967969','sienna':'#A0522D',
+      'beige':'#F5F5DC','tan':'#D2B48C','taupe':'#483C32','sand':'#C2B280','khaki':'#F0E68C','camel':'#C19A6B','oatmeal':'#B8AB8C','linen':'#FAF0E6',
+      'coral':'#FF6F61','peach':'#FFCBA4',
+      'teal':'#0D9488','aqua':'#00FFFF','turquoise':'#40E0D0','cyan':'#06B6D4',
+      'metallic':'#AAA9AD','copper':'#B87333','bronze':'#CD7F32',
+      'deep indigo':'#1B2A4A','dark navy':'#1B2A4A','midnight':'#191970'
+    };
+
+    function findColl(name) {
+      var l = (name||'').toLowerCase();
+      if (C[l]) return C[l];
+      for (var k in C) { if (l.indexOf(k) > -1) return C[k]; }
+      return null;
+    }
+
+    function makeDot(hex, name, pct) {
+      try {
+        var coll = findColl(name);
+        var a = document.createElement('a');
+        a.href = coll ? '/collections/' + coll + '?sort_by=created-descending' : '/search?q=' + encodeURIComponent(name||hex) + '&sort_by=created-descending';
+        a.title = (coll?'Shop ':'Search ') + (name||'color') + ' (' + hex + ')';
+        a.style.textDecoration = 'none';
+        var d = document.createElement('div');
+        var p = (pct == null ? 20 : pct);
+        var sz=Math.max(22,Math.min(52,16+p*0.6));d.style.cssText='width:'+sz+'px;height:'+sz+'px;border-radius:50%;background:'+hex+';border:2px solid #eee;box-shadow:0 1px 3px rgba(0,0,0,0.1);cursor:pointer;transition:transform 0.15s,box-shadow 0.15s;flex-shrink:0;';
+        d.onmouseenter = function(){this.style.transform='scale(1.3)';this.style.boxShadow='0 2px 8px rgba(0,0,0,0.2)';};
+        d.onmouseleave = function(){this.style.transform='scale(1)';this.style.boxShadow='0 1px 3px rgba(0,0,0,0.1)';};
+        a.appendChild(d);
+        return a;
+      } catch(e) { return null; }
+    }
+
+    function renderDots(colors) {
+      colors.forEach(function(c){ var el = makeDot(c.hex, c.name, (c.pct || c.percentage)); if (el) container.appendChild(el); });
+    }
+
+    /* Canvas color refs */
+    var REF = {
+      'red':[220,38,38],'navy':[27,42,74],'blue':[37,99,235],'green':[22,163,74],'sage':[135,174,115],
+      'gold':[212,175,55],'yellow':[234,179,8],'orange':[234,88,12],'pink':[236,72,153],
+      'purple':[147,51,234],'black':[26,26,26],'charcoal':[54,69,79],'white':[250,250,250],
+      'ivory':[255,255,240],'cream':[255,253,208],'gray':[107,114,128],'silver':[192,192,192],
+      'brown':[146,64,14],'beige':[245,245,220],'tan':[210,180,140],'taupe':[72,60,50],
+      'teal':[13,148,136],'coral':[255,111,97],'olive':[128,128,0],'rust':[183,65,14],
+      'burgundy':[128,0,32],'slate':[112,128,144],'sand':[194,178,128],'mint':[152,255,152],
+      'turquoise':[64,224,208],'copper':[184,115,51],'bronze':[205,127,50],'mauve':[224,176,255]
+    };
+
+    function closestName(r,g,b) {
+      var best='',bestD=1e9;
+      for(var n in REF){var c=REF[n],d=Math.sqrt(Math.pow(r-c[0],2)+Math.pow(g-c[1],2)+Math.pow(b-c[2],2));if(d<bestD){bestD=d;best=n;}}
+      return best;
+    }
+    function rgbHex(r,g,b){return '#'+[r,g,b].map(function(x){return x.toString(16).padStart(2,'0');}).join('');}
+
+    function extractFromCanvas(imgUrl) {
+      var img = new Image();
+      img.crossOrigin = 'anonymous';
+      img.onload = function() {
+        try {
+        var cv = document.createElement('canvas'), sz = 50;
+        cv.width=sz; cv.height=sz;
+        var ctx=cv.getContext('2d');
+        ctx.drawImage(img,0,0,sz,sz);
+        var px=ctx.getImageData(0,0,sz,sz).data;
+        var bk={};
+        for(var i=0;i<px.length;i+=4){
+          var kr=Math.round(px[i]/32)*32,kg=Math.round(px[i+1]/32)*32,kb=Math.round(px[i+2]/32)*32;
+          var key=kr+','+kg+','+kb;
+          if(!bk[key])bk[key]={r:0,g:0,b:0,n:0};
+          bk[key].r+=px[i];bk[key].g+=px[i+1];bk[key].b+=px[i+2];bk[key].n++;
+        }
+        var sorted=Object.values(bk).sort(function(a,b){return b.n-a.n;});
+        var tot=sz*sz,colors=[],seen={};
+        for(var j=0;j<Math.min(sorted.length,8);j++){
+          var s=sorted[j],ar=Math.round(s.r/s.n),ag=Math.round(s.g/s.n),ab=Math.round(s.b/s.n);
+          var nm=closestName(ar,ag,ab);
+          if(seen[nm])continue; seen[nm]=true;
+          colors.push({name:nm,hex:rgbHex(ar,ag,ab),percentage:Math.round(s.n/tot*100)});
+          if(colors.length>=5)break;
+        }
+        if(colors.length>0) renderDots(colors);
+        } catch(e) {
+          /* CORS or canvas security error — try without crossOrigin */
+          var img2 = new Image();
+          img2.onload = function() {
+            try {
+              var cv2 = document.createElement('canvas'), sz2 = 50;
+              cv2.width=sz2; cv2.height=sz2;
+              var ctx2=cv2.getContext('2d');
+              ctx2.drawImage(img2,0,0,sz2,sz2);
+              /* Cannot getImageData without CORS — use image dominant color via 1x1 scale */
+              cv2.width=1; cv2.height=1;
+              ctx2.drawImage(img2,0,0,1,1);
+              var p=ctx2.getImageData(0,0,1,1).data;
+              var nm=closestName(p[0],p[1],p[2]);
+              renderDots([{name:nm,hex:rgbHex(p[0],p[1],p[2]),percentage:100}]);
+            } catch(e2) {}
+          };
+          img2.src = imgUrl;
+        }
+      };
+      img.onerror = function(){};
+      img.src = imgUrl;
+    }
+
+    function getImageUrl() {
+      var url = container.dataset.productImage;
+      if (url && url.length > 5) return url.indexOf('//') === 0 ? 'https:' + url : url;
+      var sels = [
+        '.product-gallery--viewport img[src]',
+        '.product-gallery img[src]',
+        '[data-product-gallery] img[src]',
+        '.product-gallery--viewport--figure img[src]',
+        '.product__media img[src]',
+        '.product-single__photo img[src]'
+      ];
+      for (var i = 0; i < sels.length; i++) {
+        var el = document.querySelector(sels[i]);
+        if (el && el.src) return el.src;
+      }
+      return null;
+    }
+
+    /* ── Tier 1: color_details metafield ── */
+    var colorsData = container.dataset.colors;
+    if (colorsData) {
+      try {
+        /* Fix Shopify Liquid Ruby hash syntax: => becomes : */
+        var fixed = colorsData.replace(/=>/g, ':');
+        renderDots(JSON.parse(fixed));
+        return;
+      } catch(e) {}
+    }
+
+    /* ── Tier 2: primary_color_hex + ai_generated_colors ── */
+    var ph = container.dataset.primaryHex;
+    var aiRaw = container.dataset.aiColors;
+    if (ph || aiRaw) {
+      var added = {};
+      if (ph) { var pd=makeDot(ph, container.dataset.colorName||'primary'); if(pd)container.appendChild(pd); added[ph.toLowerCase()]=true; }
+      try {
+        var ai = JSON.parse((aiRaw||'[]').replace(/=>/g, ':'));
+        ai.forEach(function(nm){ var h=N[nm.toLowerCase()]; if(h&&!added[h.toLowerCase()]){var ad=makeDot(h,nm); if(ad)container.appendChild(ad);added[h.toLowerCase()]=true;} });
+      } catch(e) {}
+      if (container.children.length > 0) return;
+    }
+
+    /* ── Tier 2.5: single color_hex ── */
+    var sh = container.dataset.colorHex;
+    if (sh) { var shd=makeDot(sh, container.dataset.colorName||'color'); if(shd)container.appendChild(shd); return; }
+
+    /* ── Tier 3: Canvas extraction from product image ── */
+    var imgUrl = getImageUrl();
+    if (imgUrl) {
+      extractFromCanvas(imgUrl);
+    } else {
+      var obs = new MutationObserver(function(m, o) {
+        var url = getImageUrl();
+        if (url) { o.disconnect(); extractFromCanvas(url); }
+      });
+      obs.observe(document.body, { childList: true, subtree: true });
+      setTimeout(function(){ obs.disconnect(); }, 5000);
+    }
+   } catch(e) { /* never let color-dot rendering abort other page init */ }
+  }
+
+  if (document.readyState === 'loading') {
+    document.addEventListener('DOMContentLoaded', init);
+  } else {
+    init();
+  }
+})();
+</script>
diff --git a/shopify/theme-LIVE-591-pull-20260708/snippets/color-palette.liquid b/shopify/theme-LIVE-591-pull-20260708/snippets/color-palette.liquid
new file mode 100644
index 00000000..37f81db8
--- /dev/null
+++ b/shopify/theme-LIVE-591-pull-20260708/snippets/color-palette.liquid
@@ -0,0 +1,205 @@
+{% comment %}
+  color-palette — "Colors In This Pattern" big-swatch-card breakdown.
+  Shows ALL colors in the pattern with a % coverage under each card.
+
+  Data tiers (mirrors color-dots.liquid, kept in sync):
+    Tier 1  custom.color_dots_json / custom.color_details  (Gemini-enriched JSON: [{hex,name,pct}])
+    Tier 2  custom.primary_color_hex + dwc.ai_generated_colors (name list → hex map)
+    Tier 3  custom.color_hex (single)
+    Tier 4  Canvas pixel extraction from the product image (always yields real % — reliable fallback)
+
+  Replaces the small "color-dots" strip. Percentages come from the metafield
+  `pct`/`percentage` field when present, else are computed live from the image.
+{% endcomment %}
+
+{% comment %} Read the authoritative enriched field FIRST (color_details); legacy
+   color_dots_json is only a fallback so it can never shadow fresh enrichment. {% endcomment %}
+{% assign color_dots_json_val = product.metafields.custom.color_dots_json.value %}
+{% assign color_details_val = product.metafields.custom.color_details.value %}
+{% if color_details_val != blank %}
+  {% assign color_details_raw = color_details_val | json %}
+{% elsif color_dots_json_val != blank %}
+  {% assign color_details_raw = color_dots_json_val | json %}
+{% else %}
+  {% assign color_details_raw = blank %}
+{% endif %}
+{% assign color_hex = product.metafields.custom.color_hex.value %}
+{% assign primary_hex = product.metafields.custom.primary_color_hex.value %}
+{% assign ai_colors_raw = product.metafields.dwc.ai_generated_colors.value | json %}
+{% assign color_name = product.metafields.custom.color_name.value %}
+
+<div class="dw-color-palette" data-dw-color-palette
+  {% if color_details_raw != blank and color_details_raw != 'null' %}data-colors='{{ color_details_raw | escape }}'{% endif %}
+  {% if primary_hex != blank %}data-primary-hex="{{ primary_hex }}"{% endif %}
+  {% if ai_colors_raw != blank and ai_colors_raw != 'null' %}data-ai-colors='{{ ai_colors_raw }}'{% endif %}
+  {% if color_name != blank %}data-color-name="{{ color_name }}"{% endif %}
+  {% if color_hex != blank %}data-color-hex="{{ color_hex }}"{% endif %}
+  {% if product.featured_image %}data-product-image="{{ product.featured_image | img_url: '400x400' }}"{% endif %}
+>
+  <p class="dw-color-palette__title">Colors In This Pattern</p>
+  <div class="dw-color-palette__cards" data-dw-color-palette-cards aria-live="polite"></div>
+</div>
+
+<style>
+  .dw-color-palette{padding:16px 0 10px;text-align:center;min-height:10px;}
+  .dw-color-palette__title{font-family:Lora,serif;font-size:15px;font-weight:500;color:#3D4246;margin:0 0 12px;letter-spacing:-0.01em;}
+  /* swatches shrunk to ~1/3 (84px -> 28px), chrome scaled down to match (Steve 2026-07-08) */
+  .dw-color-palette__cards{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;max-width:640px;margin:0 auto;}
+  .dw-color-palette__card{display:flex;flex-direction:column;align-items:center;gap:3px;text-decoration:none;width:auto;min-width:28px;max-width:66px;}
+  a.dw-color-palette__card{cursor:pointer;}
+  .dw-color-palette__swatch{width:28px;height:28px;border-radius:4px;border:1px solid #e5e2dc;box-shadow:0 1px 3px rgba(0,0,0,.06);transition:transform .15s ease,border-color .15s ease,box-shadow .15s ease;position:relative;overflow:hidden;}
+  .dw-color-palette__card:hover .dw-color-palette__swatch{transform:translateY(-1px);border-color:#3D4246;box-shadow:0 3px 8px rgba(0,0,0,.14);}
+  .dw-color-palette__name{font-family:Lora,serif;font-size:10px;color:#3D4246;line-height:1.2;max-width:64px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-transform:capitalize;}
+  .dw-color-palette__pct{font-size:10px;font-weight:600;color:#8a8577;letter-spacing:.02em;}
+  .dw-color-palette__bar{display:flex;height:4px;border-radius:3px;overflow:hidden;max-width:640px;margin:12px auto 0;box-shadow:inset 0 0 0 1px rgba(0,0,0,.04);}
+  .dw-color-palette__bar span{display:block;height:100%;}
+  .dw-color-palette:empty{display:none;}
+  @media (max-width:600px){
+    .dw-color-palette__cards{gap:6px;}
+    .dw-color-palette__card{max-width:56px;}
+    .dw-color-palette__swatch{width:22px;height:22px;}
+  }
+</style>
+
+<script>
+(function(){
+  function init(){
+    var root = document.querySelector('[data-dw-color-palette]');
+    if(!root || root.dataset.rendered) return;
+    var cards = root.querySelector('[data-dw-color-palette-cards]');
+    if(!cards) return;
+    root.dataset.rendered = '1';
+
+    /* name -> hex fallback map (kept in sync with color-dots.liquid) */
+    var N = {
+      'red':'#DC2626','crimson':'#DC143C','burgundy':'#800020','wine':'#722F37','maroon':'#800000',
+      'blue':'#2563EB','navy':'#1B2A4A','cobalt':'#0047AB','indigo':'#3F51B5','sky blue':'#87CEEB','steel blue':'#4682B4','royal blue':'#4169E1','blue frost':'#BcorD','deep indigo':'#1B2A4A','dark navy':'#1B2A4A','midnight':'#191970',
+      'green':'#16A34A','sage':'#87AE73','olive':'#808000','forest green':'#228B22','emerald':'#50C878','mint':'#98FF98','moss':'#8A9A5B','sea glass':'#C6D8CE',
+      'gold':'#D4AF37','golden':'#FFD700','amber':'#FFBF00',
+      'yellow':'#EAB308','mustard':'#FFDB58',
+      'orange':'#EA580C','rust':'#B7410E','terracotta':'#E2725B','melon':'#FDBCB4','soft melon':'#F6C9A8',
+      'pink':'#EC4899','blush':'#DE5D83','rose':'#FF007F','salmon':'#FA8072','fuchsia':'#FF00FF',
+      'purple':'#9333EA','violet':'#7C3AED','plum':'#8E4585','lavender':'#E6E6FA','lilac':'#C8A2C8','mauve':'#E0B0FF',
+      'black':'#1A1A1A','charcoal':'#36454F','ebony':'#555D50','onyx':'#353839',
+      'white':'#FAFAFA','ivory':'#FFFFF0','cream':'#FFFDD0','pearl':'#F0EAD6','off-white':'#FAF9F6','eggshell':'#F0EAD6',
+      'gray':'#6B7280','grey':'#6B7280','silver':'#C0C0C0','slate':'#708090','metallic silver':'#BFC1C2',
+      'brown':'#92400E','chocolate':'#7B3F00','espresso':'#3C1414','walnut':'#5C3A1D','mocha':'#967969','sienna':'#A0522D',
+      'beige':'#F5F5DC','tan':'#D2B48C','taupe':'#483C32','sand':'#C2B280','khaki':'#F0E68C','camel':'#C19A6B','oatmeal':'#B8AB8C','linen':'#FAF0E6',
+      'coral':'#FF6F61','peach':'#FFCBA4',
+      'teal':'#0D9488','aqua':'#00FFFF','turquoise':'#40E0D0','cyan':'#06B6D4',
+      'metallic':'#AAA9AD','copper':'#B87333','bronze':'#CD7F32'
+    };
+    /* fix bad placeholder above */
+    N['blue frost']='#C4D3E0';
+
+    function esc(s){return (s||'').toString().replace(/[<>&"]/g,function(c){return {'<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;'}[c];});}
+    function pctOf(c){ var p = (c.pct!=null?c.pct:(c.percentage!=null?c.percentage:null)); if(p==null) return null; p=parseFloat(p); return isNaN(p)?null:Math.round(p); }
+
+    /* Build a card. Receives the WHOLE color object (fixes the color-dots `c` bug). */
+    function makeCard(c){
+      var hex = c.hex || N[(c.name||'').toLowerCase()] || '#ccc';
+      var name = c.name || '';
+      var pct = pctOf(c);
+      /* Link each color to ALL published ("pushed") SKUs of that color via the storefront
+         search — Shopify search only indexes published products, so "if pushed" is inherent.
+         No name -> not linkable, render a plain swatch. (Steve 2026-07-08) */
+      var card;
+      if(name){
+        card = document.createElement('a');
+        card.href = '/search?q=' + encodeURIComponent(name) + '&type=product';
+        card.title = 'View all ' + name + ' wallcoverings' + (pct!=null? ' — '+pct+'% here':'') + ' ('+hex+')';
+      } else {
+        card = document.createElement('div');
+        card.title = (pct!=null? pct+'% ':'') + '('+hex+')';
+      }
+      card.className = 'dw-color-palette__card';
+      var sw = document.createElement('div');
+      sw.className = 'dw-color-palette__swatch';
+      sw.style.background = hex;
+      card.appendChild(sw);
+      if(name){ var nm=document.createElement('span'); nm.className='dw-color-palette__name'; nm.textContent=name; card.appendChild(nm); }
+      if(pct!=null){ var pc=document.createElement('span'); pc.className='dw-color-palette__pct'; pc.textContent=pct+'%'; card.appendChild(pc); }
+      return card;
+    }
+
+    function render(colors){
+      if(!colors || !colors.length) return false;
+      /* de-dupe by hex, sort by pct desc when available */
+      var seen={}, list=[];
+      colors.forEach(function(c){
+        if(!c) return;
+        var key=(c.hex|| c.name ||'').toString().toLowerCase();
+        if(!key || seen[key]) return; seen[key]=1; list.push(c);
+      });
+      if(!list.length) return false;
+      var hasPct = list.some(function(c){return pctOf(c)!=null;});
+      if(hasPct) list.sort(function(a,b){return (pctOf(b)||0)-(pctOf(a)||0);});
+      list = list.slice(0,8);
+      list.forEach(function(c){ cards.appendChild(makeCard(c)); });
+      /* proportion bar when we have percentages */
+      if(hasPct){
+        var bar=document.createElement('div'); bar.className='dw-color-palette__bar';
+        var tot=list.reduce(function(s,c){return s+(pctOf(c)||0);},0)||1;
+        list.forEach(function(c){ var s=document.createElement('span'); s.style.background=c.hex||N[(c.name||'').toLowerCase()]||'#ccc'; s.style.flex=(pctOf(c)||0)/tot; bar.appendChild(s); });
+        root.appendChild(bar);
+      }
+      return true;
+    }
+
+    /* Metafield fallbacks — used ONLY if canvas extraction yields nothing.
+       (A single color_hex alone is a worse answer than a multi-color canvas read
+       for the "all colors with %" goal, so these are demoted below canvas.) */
+    function renderMeta(){
+      var ph=root.dataset.primaryHex, aiRaw=root.dataset.aiColors, sh=root.dataset.colorHex, list2=[];
+      if(ph) list2.push({hex:ph, name:root.dataset.colorName||'Primary'});
+      try { JSON.parse((aiRaw||'[]').replace(/=>/g,':')).forEach(function(nm){ var h=N[(''+nm).toLowerCase()]; if(h) list2.push({hex:h,name:nm}); }); } catch(e){}
+      if(list2.length && render(list2)) return true;
+      if(sh) return render([{hex:sh, name:root.dataset.colorName||'Color'}]);
+      return false;
+    }
+
+    /* ── Tier 1: color_details / color_dots_json metafield (BEST — local-vision enriched) ── */
+    var raw = root.dataset.colors;
+    if(raw){
+      try { if(render(JSON.parse(raw.replace(/=>/g,':')))) return; } catch(e){}
+    }
+
+    /* ── Tier 2: Canvas extraction from the product image (multi-color + %), meta as fallback ── */
+    var REF={'red':[190,55,55],'crimson':[176,40,60],'navy':[30,45,80],'blue':[70,110,175],'slate blue':[95,120,150],'powder blue':[170,196,214],'green':[70,130,80],'sage':[150,168,138],'celadon':[176,192,168],'eucalyptus':[130,146,128],'moss':[120,138,90],'olive':[124,124,70],'gold':[200,168,90],'ochre':[190,150,80],'yellow':[224,186,90],'orange':[220,120,70],'terracotta':[196,110,85],'coral':[224,140,120],'pink':[220,150,165],'blush':[224,190,190],'purple':[140,100,160],'lavender':[190,180,205],'black':[40,40,40],'charcoal':[70,74,78],'white':[248,246,240],'ivory':[240,236,224],'cream':[236,228,206],'eggshell':[224,216,196],'gray':[140,140,142],'greige':[176,168,154],'silver':[196,196,198],'brown':[130,95,70],'walnut':[110,80,55],'taupe':[150,138,120],'beige':[214,202,178],'tan':[196,176,140],'sand':[200,184,150],'stone':[186,180,166],'teal':[70,140,140],'turquoise':[110,180,175]};
+    function closestName(r,g,b){var best='',bd=1e9;for(var n in REF){var c=REF[n],d=Math.pow(r-c[0],2)+Math.pow(g-c[1],2)+Math.pow(b-c[2],2);if(d<bd){bd=d;best=n;}}return best;}
+    function hx(r,g,b){return '#'+[r,g,b].map(function(x){return x.toString(16).padStart(2,'0');}).join('');}
+    function fromCanvas(url){
+      var img=new Image(); img.crossOrigin='anonymous';
+      img.onload=function(){
+        try{
+          var sz=120,cv=document.createElement('canvas');cv.width=sz;cv.height=sz;
+          var ctx=cv.getContext('2d');ctx.drawImage(img,0,0,sz,sz);
+          var px=ctx.getImageData(0,0,sz,sz).data,bk={};
+          for(var i=0;i<px.length;i+=4){var kr=Math.round(px[i]/22)*22,kg=Math.round(px[i+1]/22)*22,kb=Math.round(px[i+2]/22)*22,k=kr+','+kg+','+kb;if(!bk[k])bk[k]={r:0,g:0,b:0,n:0};bk[k].r+=px[i];bk[k].g+=px[i+1];bk[k].b+=px[i+2];bk[k].n++;}
+          var sorted=Object.keys(bk).map(function(k){return bk[k];}).sort(function(a,b){return b.n-a.n;});
+          var tot=sz*sz,out=[],seen={};
+          for(var j=0;j<sorted.length && out.length<8;j++){var s=sorted[j],ar=Math.round(s.r/s.n),ag=Math.round(s.g/s.n),ab=Math.round(s.b/s.n),nm=closestName(ar,ag,ab),pct=Math.round(s.n/tot*100);if(seen[nm]||pct<2)continue;seen[nm]=1;out.push({name:nm,hex:hx(ar,ag,ab),pct:pct});}
+          if(!render(out.slice(0,6))) renderMeta();
+        }catch(e){ renderMeta(); }
+      };
+      img.onerror=function(){ renderMeta(); };
+      img.src=url;
+    }
+    function imgUrl(){
+      var u=root.dataset.productImage;
+      if(u&&u.length>5) return u.indexOf('//')===0?'https:'+u:u;
+      var sels=['.product-gallery--viewport img[src]','.product-gallery img[src]','[data-product-gallery] img[src]','.media-gallery__slide img[src]'];
+      for(var i=0;i<sels.length;i++){var el=document.querySelector(sels[i]);if(el&&el.src)return el.src;}
+      return null;
+    }
+    var u=imgUrl();
+    if(u){ fromCanvas(u); }
+    else {
+      var obs=new MutationObserver(function(m,o){var v=imgUrl();if(v){o.disconnect();fromCanvas(v);}});
+      obs.observe(document.body,{childList:true,subtree:true});
+      setTimeout(function(){ obs.disconnect(); if(!cards.children.length) renderMeta(); },5000);
+    }
+  }
+  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',init);}else{init();}
+})();
+</script>
diff --git a/shopify/theme-LIVE-591-pull-20260708/snippets/colorway-siblings.liquid b/shopify/theme-LIVE-591-pull-20260708/snippets/colorway-siblings.liquid
new file mode 100644
index 00000000..f91a4a2f
--- /dev/null
+++ b/shopify/theme-LIVE-591-pull-20260708/snippets/colorway-siblings.liquid
@@ -0,0 +1,117 @@
+{% comment %}
+  Colorway Siblings — shows other colors of the same pattern as clickable thumbnails
+  Uses dwc.pattern_name metafield or parses from title
+{% endcomment %}
+
+{%- assign pattern_name = product.metafields.custom.pattern_name.value | default: product.metafields.dwc.pattern_name.value | default: product.metafields.custom.design_name.value -%}
+
+{%- unless pattern_name != blank -%}
+  {%- assign pattern_parts = product.title | split: " - " -%}
+  {%- if pattern_parts.size >= 2 -%}
+    {%- assign pattern_name = pattern_parts[0] | strip -%}
+  {%- else -%}
+    {%- assign pattern_parts = product.title | split: " – " -%}
+    {%- if pattern_parts.size >= 2 -%}
+      {%- assign pattern_name = pattern_parts[0] | strip -%}
+    {%- else -%}
+      {%- assign pipe_parts = product.title | split: " | " -%}
+      {%- if pipe_parts.size >= 2 -%}
+        {%- assign pattern_name = pipe_parts[0] | strip -%}
+      {%- endif -%}
+    {%- endif -%}
+  {%- endif -%}
+{%- endunless -%}
+
+{%- if pattern_name != blank and pattern_name.size > 2 -%}
+  <div id="dw-colorway-siblings" style="display:none;padding:14px 0 8px;text-align:center;">
+    <p style="font-family:Lora,serif;font-size:15px;font-weight:500;color:#3D4246;margin:0 0 10px;letter-spacing:-0.01em;">
+      Other Colorways
+    </p>
+    <div id="dw-colorway-thumbs" style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap;max-width:600px;margin:0 auto;"></div>
+  </div>
+
+  <script>
+  (function() {
+    var currentHandle = {{ product.handle | json }};
+    var currentVendor = {{ product.vendor | json }};
+    var searchTerm = {{ pattern_name | json }};
+    if (!searchTerm || searchTerm.length < 3) return;
+
+    fetch('/search/suggest.json?q=' + encodeURIComponent(searchTerm) + '&resources[type]=product&resources[limit]=24', { credentials: 'same-origin' })
+      .then(function(r) { return r.ok ? r.json() : null; })
+      .then(function(data) {
+        if (!data || !data.resources || !data.resources.results) return;
+        var products = data.resources.results.products || [];
+        var matchLower = searchTerm.toLowerCase();
+        var container = document.getElementById('dw-colorway-thumbs');
+        var section = document.getElementById('dw-colorway-siblings');
+        if (!container || !section) return;
+
+        var siblings = [];
+        for (var i = 0; i < products.length; i++) {
+          var p = products[i];
+          /* Skip current product */
+          if (p.handle === currentHandle) continue;
+          /* Must match pattern name in title */
+          if ((p.title || '').toLowerCase().indexOf(matchLower) < 0) continue;
+          /* Must match vendor to avoid cross-vendor contamination */
+          if (currentVendor && (p.vendor || '').toLowerCase() !== currentVendor.toLowerCase()) continue;
+          /* Must have an image */
+          if (!p.image && !(p.featured_image && p.featured_image.url)) continue;
+
+          var imgUrl = (p.featured_image && p.featured_image.url) ? p.featured_image.url : p.image;
+
+          /* Extract color: remove pattern name and vendor */
+          var label = (p.title || '');
+          var pipeIdx = label.indexOf(' | ');
+          if (pipeIdx > 0) label = label.substring(0, pipeIdx);
+          var dashIdx = label.indexOf(' - ');
+          if (dashIdx > 0) {
+            label = label.substring(dashIdx + 3).trim();
+          } else {
+            var pLower = label.toLowerCase().indexOf(matchLower);
+            if (pLower === 0) label = label.substring(searchTerm.length).trim();
+          }
+          label = label.replace(/\s*(Wallcoverings?|Fabrics?|Murals?|Commercial)\s*/gi, '').trim();
+          if (!label) label = 'View';
+
+          siblings.push({ color: label, image: imgUrl, url: p.url || ('/products/' + p.handle) });
+        }
+
+        if (siblings.length === 0) return;
+        siblings.sort(function(a, b) { return a.color.localeCompare(b.color); });
+
+        for (var j = 0; j < siblings.length; j++) {
+          var s = siblings[j];
+          var a = document.createElement('a');
+          a.href = s.url;
+          a.title = s.color;
+          a.style.cssText = 'display:flex;flex-direction:column;align-items:center;gap:4px;text-decoration:none;width:72px;';
+
+          var wrap = document.createElement('div');
+          wrap.style.cssText = 'width:64px;height:64px;border-radius:8px;overflow:hidden;border:2px solid #e5e2dc;transition:border-color 0.15s,box-shadow 0.15s;';
+          a.onmouseover = function() { this.firstChild.style.borderColor = '#3D4246'; this.firstChild.style.boxShadow = '0 2px 8px rgba(0,0,0,0.1)'; };
+          a.onmouseout = function() { this.firstChild.style.borderColor = '#e5e2dc'; this.firstChild.style.boxShadow = 'none'; };
+
+          var img = document.createElement('img');
+          img.src = s.image;
+          img.alt = s.color;
+          img.loading = 'lazy';
+          img.style.cssText = 'width:100%;height:100%;object-fit:cover;';
+          wrap.appendChild(img);
+          a.appendChild(wrap);
+
+          var nameSpan = document.createElement('span');
+          nameSpan.textContent = s.color;
+          nameSpan.style.cssText = 'font-size:10px;color:#666;line-height:1.2;max-width:72px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;text-align:center;';
+          a.appendChild(nameSpan);
+
+          container.appendChild(a);
+        }
+
+        section.style.display = '';
+      })
+      .catch(function() {});
+  })();
+  </script>
+{%- endif -%}
diff --git a/shopify/theme-LIVE-591-pull-20260708/snippets/other-colorways.liquid b/shopify/theme-LIVE-591-pull-20260708/snippets/other-colorways.liquid
new file mode 100644
index 00000000..7141878e
--- /dev/null
+++ b/shopify/theme-LIVE-591-pull-20260708/snippets/other-colorways.liquid
@@ -0,0 +1,163 @@
+{% comment %}
+  Other Colorways — shows sibling products with the same pattern name
+  Uses Shopify Predictive Search API to find products sharing the pattern.
+  Reads dwc.pattern_name metafield; falls back to parsing title before " - " or " | ".
+{% endcomment %}
+
+{% assign pattern_name = product.metafields.dwc.pattern_name.value %}
+{% unless pattern_name != blank %}
+  {% assign title_parts = product.title | split: ' | ' %}
+  {% assign before_pipe = title_parts[0] %}
+  {% assign dash_parts = before_pipe | split: ' - ' %}
+  {% if dash_parts.size > 1 %}
+    {% assign pattern_name = dash_parts[0] | strip %}
+  {% else %}
+    {% assign pattern_name = before_pipe | strip %}
+  {% endif %}
+{% endunless %}
+
+{% if pattern_name != blank %}
+<div id="dw-other-colorways" data-pattern="{{ pattern_name | escape }}" data-current="{{ product.handle }}" data-vendor="{{ product.vendor | escape }}" style="display:none;">
+  <style>
+    .dw-colorways-section {
+      margin: 24px 0 32px;
+      padding: 0 20px;
+    }
+    .dw-colorways-heading {
+      font-family: 'Lora', serif;
+      font-size: 18px;
+      font-weight: 500;
+      margin: 0 0 14px;
+      color: #1a1a1a;
+      letter-spacing: -0.01em;
+    }
+    .dw-colorways-scroll {
+      display: flex;
+      gap: 12px;
+      overflow-x: auto;
+      padding-bottom: 8px;
+      scroll-snap-type: x mandatory;
+      -webkit-overflow-scrolling: touch;
+    }
+    .dw-colorways-scroll::-webkit-scrollbar { height: 4px; }
+    .dw-colorways-scroll::-webkit-scrollbar-track { background: #f0ede8; border-radius: 2px; }
+    .dw-colorways-scroll::-webkit-scrollbar-thumb { background: #ccc; border-radius: 2px; }
+    .dw-colorway-card {
+      flex: 0 0 140px;
+      scroll-snap-align: start;
+      text-decoration: none;
+      color: inherit;
+      border: 1px solid #e5e2dc;
+      border-radius: 8px;
+      overflow: hidden;
+      background: #fff;
+      transition: border-color 0.15s, box-shadow 0.15s;
+    }
+    .dw-colorway-card:hover {
+      border-color: #bbb;
+      box-shadow: 0 2px 10px rgba(0,0,0,0.06);
+    }
+    .dw-colorway-card.dw-current {
+      border-color: #3D4246;
+      border-width: 2px;
+    }
+    .dw-colorway-card img {
+      width: 100%;
+      aspect-ratio: 1 / 1;
+      object-fit: cover;
+      display: block;
+      background: #f2f0ec;
+    }
+    .dw-colorway-label {
+      padding: 8px 10px;
+      font-size: 12px;
+      line-height: 1.3;
+      color: #3D4246;
+      font-weight: 500;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
+  </style>
+
+  <div class="dw-colorways-section">
+    <h3 class="dw-colorways-heading">Other Colorways</h3>
+    <div class="dw-colorways-scroll" id="dw-colorways-list"></div>
+  </div>
+</div>
+
+<script>
+(function() {
+  var wrapper = document.getElementById('dw-other-colorways');
+  if (!wrapper) return;
+  var pattern = wrapper.dataset.pattern;
+  var currentHandle = wrapper.dataset.current;
+  var currentVendor = wrapper.dataset.vendor;
+  if (!pattern) return;
+
+  var url = '/search/suggest.json?q=' + encodeURIComponent(pattern) + '&resources[type]=product&resources[limit]=24';
+
+  fetch(url)
+    .then(function(r) { return r.json(); })
+    .then(function(data) {
+      var products = (data.resources && data.resources.results && data.resources.results.products) || [];
+
+      // Filter: same vendor, has image, and title contains the pattern name
+      var patternLower = pattern.toLowerCase();
+      var vendorLower = (currentVendor || '').toLowerCase();
+      var siblings = products.filter(function(p) {
+        if (!p.image) return false;
+        var titleLower = (p.title || '').toLowerCase();
+        if (titleLower.indexOf(patternLower) === -1) return false;
+        // Must match vendor to avoid cross-vendor contamination
+        if (vendorLower) {
+          var pVendor = ((p.vendor || '')).toLowerCase();
+          if (pVendor !== vendorLower) return false;
+        }
+        return true;
+      });
+
+      if (siblings.length < 2) return; // Need at least 2 (including current) to show section
+
+      var container = document.getElementById('dw-colorways-list');
+      siblings.forEach(function(p) {
+        var a = document.createElement('a');
+        a.href = p.url;
+        a.className = 'dw-colorway-card';
+        if (p.url.indexOf('/' + currentHandle) !== -1) {
+          a.className += ' dw-current';
+        }
+
+        var img = document.createElement('img');
+        img.src = p.image.replace(/(\.[a-z]+)(\?|$)/, '_300x300$1$2');
+        img.alt = p.title;
+        img.loading = 'lazy';
+        a.appendChild(img);
+
+        // Extract color from title: "Pattern - Color | Vendor" → "Color"
+        var label = p.title || '';
+        var pipeIdx = label.indexOf(' | ');
+        if (pipeIdx > 0) label = label.substring(0, pipeIdx);
+        var dashIdx = label.indexOf(' - ');
+        if (dashIdx > 0) label = label.substring(dashIdx + 3).trim();
+        else {
+          // Try removing pattern name prefix
+          var pi = label.toLowerCase().indexOf(patternLower);
+          if (pi === 0) label = label.substring(pattern.length).trim();
+        }
+        if (!label) label = p.title;
+
+        var labelDiv = document.createElement('div');
+        labelDiv.className = 'dw-colorway-label';
+        labelDiv.textContent = label;
+        a.appendChild(labelDiv);
+
+        container.appendChild(a);
+      });
+
+      wrapper.style.display = 'block';
+    })
+    .catch(function() {});
+})();
+</script>
+{% endif %}
diff --git a/shopify/theme-LIVE-591-pull-20260708/snippets/product-gallery.liquid b/shopify/theme-LIVE-591-pull-20260708/snippets/product-gallery.liquid
new file mode 100644
index 00000000..988fdc82
--- /dev/null
+++ b/shopify/theme-LIVE-591-pull-20260708/snippets/product-gallery.liquid
@@ -0,0 +1,226 @@
+{% comment %}Updated: 2026-03-23T19:12:17.978750{% endcomment %}
+{% comment %}
+@param images_layout
+  Image layout setting - masonry, slideshow or list
+@param use_masonry
+@param product
+@param variant
+@param selected_media
+@param enable_zoom
+{% endcomment %}
+
+<div
+  class="
+    product-images
+    product-gallery
+    {% if images_layout == 'masonry' %}
+      product-images-masonry
+      product-images-masonry-{{ product.media.size }}
+    {% endif %}
+    "
+  {% if images_layout == 'masonry' and product.media.size > 1 %}
+    data-masonry-gallery
+  {% endif %}
+  data-product-gallery
+  data-product-gallery-layout="{{ images_layout }}"
+  {% if enable_zoom %}data-product-gallery-image-zoom{% endif %}
+>
+  {% if images_layout == 'masonry' and product.media.size > 1 %}
+    <div class="product-image-masonry-sizer" data-masonry-image-sizer></div>
+  {% endif %}
+    <div
+      class="
+        product-gallery--viewport
+        {% if images_layout == 'slideshow' and product.media.size > 1 %}product-gallery--viewport--has-navigation{% endif %}
+      "
+      data-product-gallery-viewport
+    >
+      {% assign models = product.media | where: 'media_type', 'model' %}
+      {%- if models.size > 0 -%}
+        <script>
+          window.ShopifyXR=window.ShopifyXR||function(){(ShopifyXR.q=ShopifyXR.q||[]).push(arguments)}
+          ShopifyXR('addModels', {{ models | json }});
+        </script>
+      {%- endif -%}
+      {% assign first_model = models | first %}
+      {% for media in product.media %}
+
+        {% assign use_large_image = false %}
+        {% if product.media.size == 2 %}
+          {% assign use_large_image = true %}
+        {% elsif forloop.first and use_masonry %}
+          {% assign use_large_image = true %}
+        {% endif %}
+
+        {% if media.media_type == 'model' %}
+          {% assign model = media %}
+        {% else %}
+          {% assign model = first_model %}
+        {% endif %}
+
+        {% if model %}
+          {% capture model_view_button %}
+            <button
+              class="product-gallery--viewinyourspace"
+              data-shopify-xr
+              data-shopify-model3d-id="{{ model.id }}"
+              data-shopify-title="{{ product.title }}"
+              data-shopify-xr-hidden
+              data-viewinyourspace
+            >
+              {% render 'icons', id: 'ar' %}
+              {{ 'products.media.view_in_your_space' | t }}
+            </button>
+          {% endcapture %}
+        {% endif %}
+
+        <figure
+          class="product-gallery--viewport--figure {% if use_large_image %}product-image-wide{% endif %}"
+          tabindex="-1"
+          {% if images_layout != 'list' %}
+            {% if selected_media.id != media.id %}
+              aria-hidden="true"
+            {% else %}
+              aria-hidden="false"
+            {% endif %}
+          {% endif %}
+          data-product-gallery-figure="{{ forloop.index0 }}"
+          {% if images_layout == 'slideshow' %}
+            data-product-gallery-selected="{%- if selected_media.id == media.id -%}true{%- else -%}false{%- endif -%}"
+          {% endif %}
+          data-media="{{ media.id }}"
+          data-media-type="{{ media.media_type }}"
+          >
+          <div class="product-gallery--media-wrapper">
+            {% case media.media_type %}
+            {% when 'image' %}
+              {%- capture data_attr -%}
+                {% if enable_zoom %}data-image-zoom="{{ media.id }}"{% endif %}
+              {%- endcapture -%}
+              {%
+                render 'rimg'
+                img: media.preview_image,
+                size: '1024x1024',
+                attr: data_attr,
+                lazy: true,
+              %}
+              {% if enable_zoom %}
+                <div class="product-zoom" data-product-zoom-id="{{ media.id }}"></div>
+              {% endif %}
+            {% when 'model' %}
+              {{ media | model_viewer_tag: image_size: '1024x', reveal: 'interaction' , toggleable: true, interaction-prompt-threshold: 0 }}
+            {% when 'video' %}
+              {{ media | media_tag: image_size: '1024x' }}
+            {% when 'external_video' %}
+              {{ media | media_tag: image_size: '1024x' }}
+            {% else %}
+              {{ media | media_tag }}
+            {% endcase %}
+          </div>
+          {% if images_layout == 'slideshow' %}
+            {{ model_view_button }}
+          {% endif %}
+        </figure>
+        {% if images_layout == 'list' %}
+            {{ model_view_button }}
+        {% endif %}
+      {% else %}
+        <figure
+          class="product-gallery--viewport--figure"
+          data-product-gallery-selected="true"
+        >
+          {{ 'product-1' | placeholder_svg_tag: 'placeholder-svg' }}
+        </figure>
+      {% endfor %}
+
+    </div>
+
+    {% comment %} Colors In This Pattern — big swatch cards w/ % (replaces color-dots). Sits between the product images and Other Colorways. {% endcomment %}
+    {% render 'color-palette' %}
+    {% render 'colorway-siblings' %}
+
+    {% if images_layout == 'slideshow' and product.media.size > 1 %}
+      <div class="product-gallery-navigation-outer-wrapper">
+        {% if product.media.size > 4 %}
+          <span class="product-thumbnails-navigation-previous">&#xe601;</span>
+        {% endif %}
+        <div class="product-gallery--navigation-wrapper">
+          <div
+             class="product-gallery--navigation {% if product.media.size > 4 %}has-side-scroll{% endif %}"
+            data-product-gallery-navigation
+          >
+            {% for media in product.media %}
+              <button
+                class="
+                  product-gallery--media-thumbnail
+                  product-gallery--{{ media.media_type }}-thumbnail
+                "
+                type="button"
+                tab-index="0"
+                aria-label="{{ media.alt }} {{ 'general.accessibility.nav_product_thumbnail' | t }}"
+                data-product-gallery-thumbnail="{{ forloop.index0 }}"
+                data-product-gallery-selected="{%- if selected_media.id == media.id -%}true{%- else -%}false{%- endif -%}"
+                data-media="{{ media.id }}"
+                data-media-type="{{ media.media_type }}"
+              >
+                {%
+                  render 'rimg'
+                  img: media.preview_image,
+                  size: '100x100',
+                  lazy: true
+                %}
+                {% case media.media_type %}
+                {% when 'model' %}
+                  {% render 'icons', id:'model-thumb' %}
+                {% when 'video' %}
+                  {% render 'icons', id: 'play-thumb' %}
+                {% when 'external_video' %}
+                  {% render 'icons', id: 'play-thumb' %}
+                {% endcase %}
+              </button>
+            {% endfor %}
+          </div>
+        </div>
+        {% if product.media.size > 4 %}
+          <span class="product-thumbnails-navigation-next">&#xe600;</span>
+        {% endif %}
+      </div>
+    {% endif %}
+    <div class="product__social" {{ block.shopify_attributes }}>
+      {% render 'share-buttons' %}
+    </div>
+    <div class="product-content__desktop">
+      <h4 style="margin-bottom: 0.25em;"><strong>Pattern Description:</strong></h4>
+
+      {% if product != blank and product.description != blank %}
+        <div class="product-description rte" itemprop="description" style="margin-top: 0;">
+          {{ product.description }}
+        </div>
+      {% elsif product == blank %}
+        <div class="product-description rte" itemprop="description" style="margin-top: 0;">
+          {{ 'products.product.onboarding.description' | t }}
+        </div>
+      {% endif %}
+   </div>
+</div>
+{% if images_layout == 'masonry' and product.media.size > 1 %}
+  <div class="mobile-slider-nav-wrapper">
+    {{ model_view_button }}
+    <div data-mobile-slider-navigation>
+      <button class="mobile-slider-prev-next" data-mobile-slider-button="prev">
+        {% render 'icons', id: 'prev-button' %}
+      </button>
+      <ol data-mobile-slider-dots>
+        {% for media in product.media %}
+          <li class='dot' aria-label="Page dot {{ forloop.index0 }}" data-mobile-slider-dot data-slide-dot-index="{{ forloop.index0 }}"></li>
+        {% endfor %}
+      </ol>
+      <button class="mobile-slider-prev-next" data-mobile-slider-button="next">
+        {% render 'icons', id: 'next-button' %}
+      </button>
+    </div>
+  </div>
+{% endif %}
+
+
+{% render 'full-monte-express' %}

← 59d5c2f8 standing mac3->Kamatera catalog push: additive nightly sync  ·  back to Designer Wallcoverings  ·  auto-save: 2026-07-08T13:05:49 (10 files) — pending-approval 36a54f98 →