← back to Designer Wallcoverings
collections: add background hero image (dedicated section, staged on dev theme) + audit of 66 collections missing collection.image
f001170724e91ea56d6a4f22dde35c90248076ee · 2026-06-23 12:45:07 -0700 · Steve
Files touched
M .gitignoreA shopify/audit-collection-hero-images.pyA shopify/audit/collection-hero-gap.jsonA shopify/push-collection-hero-to-dev-theme.pyA shopify/sections/dw-collection-hero.liquid
Diff
commit f001170724e91ea56d6a4f22dde35c90248076ee
Author: Steve <steve@designerwallcoverings.com>
Date: Tue Jun 23 12:45:07 2026 -0700
collections: add background hero image (dedicated section, staged on dev theme) + audit of 66 collections missing collection.image
---
.gitignore | 1 +
shopify/audit-collection-hero-images.py | 103 +++++++
shopify/audit/collection-hero-gap.json | 405 +++++++++++++++++++++++++++
shopify/push-collection-hero-to-dev-theme.py | 104 +++++++
shopify/sections/dw-collection-hero.liquid | 69 +++++
5 files changed, 682 insertions(+)
diff --git a/.gitignore b/.gitignore
index f34e79d8..f5b36f4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,3 +71,4 @@ DW-Programming/room-setting-app/data/gallery/renders.json
DW-Programming/data/color-clean-ledger.jsonl
shopify/scripts/gmc-race-clean/out/
shopify/scripts/cadence/stock-2026-guard.latest.json
+shopify/theme-backups/
diff --git a/shopify/audit-collection-hero-images.py b/shopify/audit-collection-hero-images.py
new file mode 100644
index 00000000..97663a14
--- /dev/null
+++ b/shopify/audit-collection-hero-images.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+"""
+READ-ONLY audit: which DW Shopify collections lack a background/hero image
+(collection.image == null). Covers BOTH custom_collections and smart_collections.
+
+Enforces standing rule (Steve 2026-06-23): every collection page must have a
+background "bg" hero image. A collection with image==null will render the
+template's CSS fallback gradient instead of a real hero → flagged here.
+
+Usage:
+ THEME_TOKEN=shpat_xxx python3 audit-collection-hero-images.py
+ # or relies on SHOPIFY_THEME_TOKEN / SHOPIFY_ADMIN_TOKEN in secrets-manager/.env
+No writes. Outputs a summary + writes audit/collection-hero-gap.json.
+"""
+import sys, os, json, urllib.request, urllib.parse, urllib.error, datetime
+
+STORE = "designer-laboratory-sandbox.myshopify.com"
+API = "2024-10"
+SECRETS = os.path.expanduser("~/Projects/secrets-manager/.env")
+
+
+def load_token():
+ t = os.environ.get("THEME_TOKEN")
+ if t:
+ return t
+ if os.path.exists(SECRETS):
+ for line in open(SECRETS):
+ for k in ("SHOPIFY_THEME_TOKEN", "SHOPIFY_ADMIN_TOKEN", "SHOPIFY_ORDERS_TOKEN"):
+ if line.startswith(k + "="):
+ return line.split("=", 1)[1].strip().strip('"').strip("'")
+ sys.exit("No Shopify token. Run: THEME_TOKEN=shpat_xxx python3 audit-collection-hero-images.py")
+
+
+TOK = load_token()
+H = {"X-Shopify-Access-Token": TOK, "Content-Type": "application/json"}
+
+
+def get(url):
+ req = urllib.request.Request(url, headers=H)
+ resp = urllib.request.urlopen(req)
+ body = json.load(resp)
+ link = resp.headers.get("Link", "")
+ nxt = None
+ for part in link.split(","):
+ if 'rel="next"' in part:
+ nxt = part[part.find("<") + 1:part.find(">")]
+ return body, nxt
+
+
+def fetch_all(resource):
+ out = []
+ url = f"https://{STORE}/admin/api/{API}/{resource}.json?limit=250&fields=id,handle,title,image,published_scope"
+ while url:
+ try:
+ body, url = get(url)
+ except urllib.error.HTTPError as e:
+ print(f" {resource} HTTP {e.code}: {e.read().decode()[:200]}")
+ break
+ out.extend(body.get(resource, []))
+ return out
+
+
+print(f"token …{TOK[-4:]} store {STORE}\n")
+custom = fetch_all("custom_collections")
+smart = fetch_all("smart_collections")
+print(f"custom_collections: {len(custom)}")
+print(f"smart_collections: {len(smart)}")
+
+rows = []
+for kind, coll in (("custom", custom), ("smart", smart)):
+ for c in coll:
+ has_img = bool(c.get("image"))
+ rows.append({
+ "kind": kind,
+ "id": c["id"],
+ "handle": c.get("handle"),
+ "title": c.get("title"),
+ "has_image": has_img,
+ "image_src": (c.get("image") or {}).get("src"),
+ })
+
+total = len(rows)
+missing = [r for r in rows if not r["has_image"]]
+have = total - len(missing)
+print(f"\n=== HERO-IMAGE AUDIT ===")
+print(f"total collections : {total}")
+print(f"WITH hero image : {have}")
+print(f"MISSING hero image: {len(missing)} ({(len(missing)/total*100 if total else 0):.1f}%)")
+print(f"\nFirst 40 missing (handle — title):")
+for r in missing[:40]:
+ print(f" /collections/{r['handle']} — {r['title']} [{r['kind']}]")
+if len(missing) > 40:
+ print(f" … and {len(missing)-40} more")
+
+os.makedirs("audit", exist_ok=True)
+out = {
+ "generated_at": datetime.datetime.now().isoformat(),
+ "store": STORE,
+ "total": total, "with_image": have, "missing_image": len(missing),
+ "missing": [{"handle": r["handle"], "title": r["title"], "kind": r["kind"], "id": r["id"]} for r in missing],
+}
+json.dump(out, open("audit/collection-hero-gap.json", "w"), indent=2)
+print(f"\nwrote audit/collection-hero-gap.json ({len(missing)} flagged)")
diff --git a/shopify/audit/collection-hero-gap.json b/shopify/audit/collection-hero-gap.json
new file mode 100644
index 00000000..e34d66a4
--- /dev/null
+++ b/shopify/audit/collection-hero-gap.json
@@ -0,0 +1,405 @@
+{
+ "generated_at": "2026-06-23T12:37:52.255570",
+ "store": "designer-laboratory-sandbox.myshopify.com",
+ "total": 665,
+ "with_image": 599,
+ "missing_image": 66,
+ "missing": [
+ {
+ "handle": "1838",
+ "title": "1838",
+ "kind": "custom",
+ "id": 299219812403
+ },
+ {
+ "handle": "fentucci-naturals",
+ "title": "Fentucci Naturals",
+ "kind": "custom",
+ "id": 299921047603
+ },
+ {
+ "handle": "hollywood-vinyls-vol-1",
+ "title": "Hollywood Vinyls Vol. 1",
+ "kind": "custom",
+ "id": 298973855795
+ },
+ {
+ "handle": "wallpapersback",
+ "title": "WALLPAPERSBACK",
+ "kind": "custom",
+ "id": 301681508403
+ },
+ {
+ "handle": "3d-decibel",
+ "title": "3d Decibel",
+ "kind": "smart",
+ "id": 299576885299
+ },
+ {
+ "handle": "anima",
+ "title": "Anima",
+ "kind": "smart",
+ "id": 299576950835
+ },
+ {
+ "handle": "anthology-wallcoverings",
+ "title": "Anthology Wallcoverings",
+ "kind": "smart",
+ "id": 299575148595
+ },
+ {
+ "handle": "aracne",
+ "title": "Aracne",
+ "kind": "smart",
+ "id": 299576983603
+ },
+ {
+ "handle": "artisan-by-bodo-sperlein",
+ "title": "Artisan By Bodo Sperlein",
+ "kind": "smart",
+ "id": 299577016371
+ },
+ {
+ "handle": "artmura",
+ "title": "Artmura",
+ "kind": "smart",
+ "id": 301429850163
+ },
+ {
+ "handle": "bn-studio-collection",
+ "title": "Bn Studio Collection",
+ "kind": "smart",
+ "id": 299576492083
+ },
+ {
+ "handle": "bn-walls",
+ "title": "BN Walls",
+ "kind": "smart",
+ "id": 299577409587
+ },
+ {
+ "handle": "botanika",
+ "title": "Botanika",
+ "kind": "smart",
+ "id": 299577081907
+ },
+ {
+ "handle": "carnegie-wallcoverings",
+ "title": "Carnegie Wallcoverings",
+ "kind": "smart",
+ "id": 299575246899
+ },
+ {
+ "handle": "central-saint-martins-rest-time",
+ "title": "Central Saint Martins Rest Time",
+ "kind": "smart",
+ "id": 299577147443
+ },
+ {
+ "handle": "christian-fischbacher",
+ "title": "Christian Fischbacher",
+ "kind": "smart",
+ "id": 299576852531
+ },
+ {
+ "handle": "coco-d-vez-colortherapills",
+ "title": "Coco D Vez Colortherapills",
+ "kind": "smart",
+ "id": 299577180211
+ },
+ {
+ "handle": "color-stories-new",
+ "title": "Color Stories New",
+ "kind": "smart",
+ "id": 299576557619
+ },
+ {
+ "handle": "cotswolds-ybarra-amp-serret-for-coordonn",
+ "title": "Cotswolds Ybarra Amp Serret For Coordonn",
+ "kind": "smart",
+ "id": 299577212979
+ },
+ {
+ "handle": "cowtan-tout-wallpaper-collection",
+ "title": "Cowtan & Tout Wallcovering Collection",
+ "kind": "smart",
+ "id": 299575279667
+ },
+ {
+ "handle": "creative-lab",
+ "title": "Creative Lab",
+ "kind": "smart",
+ "id": 299576590387
+ },
+ {
+ "handle": "cubiq",
+ "title": "Cubiq",
+ "kind": "smart",
+ "id": 299576623155
+ },
+ {
+ "handle": "damaskus",
+ "title": "Damaskus",
+ "kind": "smart",
+ "id": 299577245747
+ },
+ {
+ "handle": "de-gournay-wallcoverings",
+ "title": "De Gournay",
+ "kind": "smart",
+ "id": 298974445619
+ },
+ {
+ "handle": "debn-studio-collection",
+ "title": "Debn Studio Collection",
+ "kind": "smart",
+ "id": 299576655923
+ },
+ {
+ "handle": "dedoodleedo",
+ "title": "Dedoodleedo",
+ "kind": "smart",
+ "id": 299576688691
+ },
+ {
+ "handle": "defiore",
+ "title": "Defiore",
+ "kind": "smart",
+ "id": 299576721459
+ },
+ {
+ "handle": "degrand-safari",
+ "title": "Degrand Safari",
+ "kind": "smart",
+ "id": 299576754227
+ },
+ {
+ "handle": "degrounded",
+ "title": "Degrounded",
+ "kind": "smart",
+ "id": 299576786995
+ },
+ {
+ "handle": "delinen-stories",
+ "title": "Delinen Stories",
+ "kind": "smart",
+ "id": 299576819763
+ },
+ {
+ "handle": "fabric-backed",
+ "title": "Fabric Backed Wallcoverings",
+ "kind": "smart",
+ "id": 299576459315
+ },
+ {
+ "handle": "fallingstar",
+ "title": "FallingStar Studio",
+ "kind": "smart",
+ "id": 301565804595
+ },
+ {
+ "handle": "fromental-wallcoverings",
+ "title": "Fromental Wallcoverings",
+ "kind": "smart",
+ "id": 299575377971
+ },
+ {
+ "handle": "groundworks-wallcoverings",
+ "title": "Groundworks Wallcoverings",
+ "kind": "smart",
+ "id": 299575410739
+ },
+ {
+ "handle": "knoll-textiles",
+ "title": "Knoll Wallcoverings",
+ "kind": "smart",
+ "id": 299574657075
+ },
+ {
+ "handle": "la-walls",
+ "title": "LA Walls",
+ "kind": "smart",
+ "id": 301587922995
+ },
+ {
+ "handle": "maharam-wallcoverings",
+ "title": "Maharam Wallcoverings",
+ "kind": "smart",
+ "id": 299575476275
+ },
+ {
+ "handle": "malibu-walls",
+ "title": "Malibu Walls",
+ "kind": "smart",
+ "id": 299962368051
+ },
+ {
+ "handle": "malibu-walls-abstract",
+ "title": "Malibu Walls \u2014 Abstract",
+ "kind": "smart",
+ "id": 299962630195
+ },
+ {
+ "handle": "malibu-walls-bedroom",
+ "title": "Malibu Walls \u2014 Bedroom",
+ "kind": "smart",
+ "id": 299962794035
+ },
+ {
+ "handle": "malibu-walls-coastal",
+ "title": "Malibu Walls \u2014 Coastal",
+ "kind": "smart",
+ "id": 299962433587
+ },
+ {
+ "handle": "malibu-walls-contemporary",
+ "title": "Malibu Walls \u2014 Contemporary",
+ "kind": "smart",
+ "id": 299962466355
+ },
+ {
+ "handle": "malibu-walls-floral",
+ "title": "Malibu Walls \u2014 Floral & Botanical",
+ "kind": "smart",
+ "id": 299962695731
+ },
+ {
+ "handle": "malibu-walls-geometric",
+ "title": "Malibu Walls \u2014 Geometric",
+ "kind": "smart",
+ "id": 299962728499
+ },
+ {
+ "handle": "malibu-walls-grasscloth",
+ "title": "Malibu Walls \u2014 Grasscloth & Woven",
+ "kind": "smart",
+ "id": 299962662963
+ },
+ {
+ "handle": "malibu-walls-living-room",
+ "title": "Malibu Walls \u2014 Living Room",
+ "kind": "smart",
+ "id": 299962826803
+ },
+ {
+ "handle": "malibu-walls-minimalist",
+ "title": "Malibu Walls \u2014 Minimalist",
+ "kind": "smart",
+ "id": 299962597427
+ },
+ {
+ "handle": "malibu-walls-scandinavian",
+ "title": "Malibu Walls \u2014 Scandinavian",
+ "kind": "smart",
+ "id": 299962564659
+ },
+ {
+ "handle": "malibu-walls-stripes",
+ "title": "Malibu Walls \u2014 Stripes",
+ "kind": "smart",
+ "id": 299962761267
+ },
+ {
+ "handle": "malibu-walls-traditional",
+ "title": "Malibu Walls \u2014 Traditional",
+ "kind": "smart",
+ "id": 299962499123
+ },
+ {
+ "handle": "malibu-walls-transitional",
+ "title": "Malibu Walls \u2014 Transitional",
+ "kind": "smart",
+ "id": 299962531891
+ },
+ {
+ "handle": "matthew-williamson-wallcoverings",
+ "title": "Matthew Williamson Wallcoverings",
+ "kind": "smart",
+ "id": 299575509043
+ },
+ {
+ "handle": "mc-escher",
+ "title": "MC Escher",
+ "kind": "smart",
+ "id": 299534286899
+ },
+ {
+ "handle": "mdc-wallcoverings",
+ "title": "MDC Wallcoverings",
+ "kind": "smart",
+ "id": 299575541811
+ },
+ {
+ "handle": "mr-perswall-wallcoverings",
+ "title": "Mr Perswall Wallcoverings",
+ "kind": "smart",
+ "id": 299575574579
+ },
+ {
+ "handle": "mural-source",
+ "title": "Mural Source",
+ "kind": "smart",
+ "id": 299577376819
+ },
+ {
+ "handle": "sanderson",
+ "title": "Sanderson Wallcoverings",
+ "kind": "smart",
+ "id": 299574591539
+ },
+ {
+ "handle": "sanderson-wallcoverings",
+ "title": "Sanderson Wallcoverings",
+ "kind": "smart",
+ "id": 299575672883
+ },
+ {
+ "handle": "schumacher",
+ "title": "Schumacher",
+ "kind": "smart",
+ "id": 301431095347
+ },
+ {
+ "handle": "showroom-lines",
+ "title": "Showroom Lines",
+ "kind": "smart",
+ "id": 301540147251
+ },
+ {
+ "handle": "spoonflower",
+ "title": "Spoonflower Wallcoverings",
+ "kind": "smart",
+ "id": 299577344051
+ },
+ {
+ "handle": "stout-wallpaper",
+ "title": "Stout Textiles Wallcoverings",
+ "kind": "smart",
+ "id": 299574689843
+ },
+ {
+ "handle": "stout-wallcoverings",
+ "title": "Stout Wallcoverings",
+ "kind": "smart",
+ "id": 298974543923
+ },
+ {
+ "handle": "stroheim-wallcoverings",
+ "title": "Stroheim Wallcoverings",
+ "kind": "smart",
+ "id": 299575705651
+ },
+ {
+ "handle": "tres-tintas",
+ "title": "Tres Tintas",
+ "kind": "smart",
+ "id": 301569179699
+ },
+ {
+ "handle": "zuber-wallcoverings",
+ "title": "Zuber Wallcoverings",
+ "kind": "smart",
+ "id": 299575803955
+ }
+ ]
+}
\ No newline at end of file
diff --git a/shopify/push-collection-hero-to-dev-theme.py b/shopify/push-collection-hero-to-dev-theme.py
new file mode 100644
index 00000000..1e40d691
--- /dev/null
+++ b/shopify/push-collection-hero-to-dev-theme.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+"""
+Stage the DW collection BACKGROUND HERO on the DEV theme only
+("Updated copy of NewWall Template [Dev]", id 143794536499).
+
+Standing rule (Steve 2026-06-23): every collection page must have a background
+"bg" hero image. The DW collection page is Boost-app-rendered (the native
+sections/collection.liquid is JS/CSS/schema only — it emits no visible HTML), so
+the hero is a DEDICATED section (sections/dw-collection-hero.liquid) placed FIRST
+in templates/collection.json "order", rendering server-side above the Boost grid.
+It shows collection.image as a cover background (title + breadcrumbs overlaid);
+collections with no image yet get a branded fallback gradient. The audit script
+(audit-collection-hero-images.py) lists which collections still need a real image.
+
+Idempotent: re-uploads the section and ensures it's first in order without
+duplicating. Backs up collection.json each run. NEVER touches the live/main theme.
+Live promotion stays with Steve (publish the dev theme or port to the main theme).
+
+Usage:
+ THEME_TOKEN=shpat_xxx python3 push-collection-hero-to-dev-theme.py
+ python3 push-collection-hero-to-dev-theme.py --remove # unwire the hero
+ python3 push-collection-hero-to-dev-theme.py --verify-only # read-only check
+"""
+import sys, os, json, urllib.request, urllib.parse, datetime, time
+
+STORE = "designer-laboratory-sandbox.myshopify.com"
+API = "2024-10"
+TID = 143794536499
+SECRETS = os.path.expanduser("~/Projects/secrets-manager/.env")
+SECTION_KEY = "sections/dw-collection-hero.liquid"
+TEMPLATE_KEY = "templates/collection.json"
+HERO_ID = "dw_collection_hero"
+HERO_TYPE = "dw-collection-hero"
+REMOVE = "--remove" in sys.argv
+VERIFY = "--verify-only" in sys.argv
+
+
+def token():
+ t = os.environ.get("THEME_TOKEN")
+ if t:
+ return t
+ for line in open(SECRETS):
+ if line.startswith("SHOPIFY_THEME_TOKEN="):
+ return line.split("=", 1)[1].strip().strip('"').strip("'")
+ sys.exit("No theme token. Run: THEME_TOKEN=shpat_xxx python3 " + os.path.basename(__file__))
+
+
+TOK = token()
+H = {"X-Shopify-Access-Token": TOK, "Content-Type": "application/json"}
+
+
+def get(k):
+ q = urllib.parse.urlencode({"asset[key]": k})
+ return json.load(urllib.request.urlopen(urllib.request.Request(
+ f"https://{STORE}/admin/api/{API}/themes/{TID}/assets.json?{q}", headers=H)))["asset"]["value"]
+
+
+def put(k, v):
+ req = urllib.request.Request(f"https://{STORE}/admin/api/{API}/themes/{TID}/assets.json",
+ headers=H, data=json.dumps({"asset": {"key": k, "value": v}}).encode(), method="PUT")
+ return json.load(urllib.request.urlopen(req))
+
+
+themes = json.load(urllib.request.urlopen(urllib.request.Request(
+ f"https://{STORE}/admin/api/{API}/themes.json", headers=H)))["themes"]
+role = {t["id"]: t["role"] for t in themes}.get(TID)
+if role == "main":
+ sys.exit("Refusing: target theme is the LIVE main theme.")
+print(f"token …{TOK[-4:]} target {TID} role={role} (live untouched)")
+
+cj = json.loads(get(TEMPLATE_KEY))
+order = cj.get("order", [])
+wired = HERO_ID in cj.get("sections", {}) and len(order) > 0 and order[0] == HERO_ID
+print(f"currently wired (hero present + first in order): {wired}")
+
+if VERIFY:
+ sys.exit(0)
+
+os.makedirs("theme-backups", exist_ok=True)
+stamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
+open(f"theme-backups/collection.json.dev-{TID}.{stamp}.bak", "w").write(json.dumps(cj, indent=2))
+
+if REMOVE:
+ cj["sections"].pop(HERO_ID, None)
+ cj["order"] = [o for o in cj.get("order", []) if o != HERO_ID]
+ put(TEMPLATE_KEY, json.dumps(cj, indent=2))
+ print("removed hero from collection.json order (section asset left in place).")
+ sys.exit(0)
+
+# upload/refresh the section
+here = os.path.dirname(os.path.abspath(__file__))
+put(SECTION_KEY, open(os.path.join(here, SECTION_KEY)).read())
+# ensure wired + first in order
+cj.setdefault("sections", {})[HERO_ID] = {"type": HERO_TYPE, "settings": {"show_description": True}}
+cj["order"] = [HERO_ID] + [o for o in cj.get("order", []) if o != HERO_ID]
+put(TEMPLATE_KEY, json.dumps(cj, indent=2))
+
+time.sleep(2)
+back = json.loads(get(TEMPLATE_KEY))
+ok = HERO_ID in back["sections"] and back["order"][0] == HERO_ID
+print(f"staged on dev. verify: {'OK' if ok else 'FAILED'} order={back['order']}")
+print("\nPREVIEW (open while logged into Shopify admin — unpublished theme):")
+for h in ("artmura", "de-gournay-wallcoverings"):
+ print(f" https://www.designerwallcoverings.com/collections/{h}?preview_theme_id={TID}")
diff --git a/shopify/sections/dw-collection-hero.liquid b/shopify/sections/dw-collection-hero.liquid
new file mode 100644
index 00000000..c8d61d01
--- /dev/null
+++ b/shopify/sections/dw-collection-hero.liquid
@@ -0,0 +1,69 @@
+{%- comment -%}
+ DW Collection Hero — Steve standing rule (2026-06-23): every collection page
+ must have a background "bg" hero image. Renders collection.image as a full-bleed
+ cover background with the title + breadcrumbs overlaid (gradient scrim for
+ legibility). Collections with no image yet fall back to a branded gradient so
+ the page is never broken; the audit (audit-collection-hero-images.py) lists
+ which collections still need a real image.
+
+ Added as its own section so it can be toggled by removing it from
+ templates/collection.json "order". Renders above the Boost-app product grid.
+{%- endcomment -%}
+{%- liquid
+ assign dw_has_hero = false
+ if collection.image
+ assign dw_has_hero = true
+ endif
+-%}
+<div class="dw-collection-hero{% unless dw_has_hero %} dw-collection-hero--fallback{% endunless %}"
+ {% if dw_has_hero %}style="background-image:url({{ collection.image | img_url: '2048x' }});"{% endif %}
+ data-dw-collection-hero>
+ <div class="dw-collection-hero__scrim"></div>
+ <div class="dw-collection-hero__inner page-width">
+ <nav class="dw-collection-hero__crumbs" aria-label="Breadcrumb">
+ <a href="/">Home</a> <span aria-hidden="true">/</span>
+ <a href="/collections">Collections</a> <span aria-hidden="true">/</span>
+ <span aria-current="page">{{ collection.title }}</span>
+ </nav>
+ <h1 class="dw-collection-hero__title">{{ collection.title }}</h1>
+ {%- if section.settings.show_description and collection.description != blank -%}
+ <div class="dw-collection-hero__desc">{{ collection.description | strip_html | truncatewords: 32 }}</div>
+ {%- endif -%}
+ </div>
+</div>
+<style>
+ .dw-collection-hero{position:relative;min-height:clamp(220px,30vw,400px);display:flex;
+ align-items:flex-end;background-size:cover;background-position:center;background-repeat:no-repeat;
+ margin:0 0 1.5rem;overflow:hidden;}
+ .dw-collection-hero--fallback{background:linear-gradient(135deg,#1c1c1c 0%,#3a3a3a 55%,#2a2320 100%);}
+ .dw-collection-hero__scrim{position:absolute;inset:0;pointer-events:none;
+ background:linear-gradient(180deg,rgba(0,0,0,0) 28%,rgba(0,0,0,.6) 100%);}
+ .dw-collection-hero__inner{position:relative;z-index:1;width:100%;padding:2rem 2.25rem;color:#fff;}
+ .dw-collection-hero__crumbs{font-size:.78rem;letter-spacing:.04em;text-transform:uppercase;
+ opacity:.9;margin:0 0 .4rem;}
+ .dw-collection-hero__crumbs a,.dw-collection-hero__crumbs span{color:#fff;text-decoration:none;}
+ .dw-collection-hero__crumbs a:hover{text-decoration:underline;}
+ .dw-collection-hero__title{color:#fff;font-size:clamp(1.8rem,3.4vw,3rem);margin:.1rem 0 0;
+ letter-spacing:.5px;text-shadow:0 1px 18px rgba(0,0,0,.45);}
+ .dw-collection-hero__desc{color:#fff;max-width:62ch;margin:.6rem 0 0;opacity:.95;
+ font-size:.95rem;line-height:1.5;text-shadow:0 1px 10px rgba(0,0,0,.4);}
+ /* hero now carries title + breadcrumbs: hide any legacy duplicates on collection pages */
+ .template-collection .breadcrumbs{display:none;}
+</style>
+
+{% schema %}
+{
+ "name": "DW Collection Hero",
+ "settings": [
+ {
+ "type": "checkbox",
+ "id": "show_description",
+ "label": "Show collection description in hero",
+ "default": true
+ }
+ ],
+ "presets": [
+ { "name": "DW Collection Hero" }
+ ]
+}
+{% endschema %}
← d7042d8c Audit: repeat+match are OPTIONAL specs (plain/free-match rol
·
back to Designer Wallcoverings
·
auto-save: 2026-06-23T12:51:44 (8 files) — shopify/scripts/c ec1ab72f →