[object Object]

← back to Hospitalitywallpaper

snapshot before fleet-grid refine

d0986f0195d6e8fda1d9203425f7a830e2a8e961 · 2026-05-11 00:11:06 -0700 · Steve Abrams

Files touched

Diff

commit d0986f0195d6e8fda1d9203425f7a830e2a8e961
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon May 11 00:11:06 2026 -0700

    snapshot before fleet-grid refine
---
 public/care.html                                |  57 ++
 public/history.html                             |  59 ++
 public/index.html.bak.dwfoot.1778203445670      | 962 +++++++++++++++++++++++
 public/index.html.bak.gtagev.1778426584663      | 972 +++++++++++++++++++++++
 public/index.html.bak.ns-canonical              | 979 ++++++++++++++++++++++++
 public/index.html.bak.nspropagate.1778203385100 | 947 +++++++++++++++++++++++
 public/index.html.bak.nspropagate.1778209715048 | 962 +++++++++++++++++++++++
 public/index.html.bak.nspropagate.1778226815149 | 966 +++++++++++++++++++++++
 public/index.html.bak.nspropagate.1778226888801 | 968 +++++++++++++++++++++++
 public/index.html.pre-sort-frontend             | 852 +++++++++++++++++++++
 public/sourcing.html                            |  59 ++
 public/trade.html                               |  63 ++
 public/vocabulary.html                          |  51 ++
 server.js.pre-sort-skill                        | 159 ++++
 14 files changed, 8056 insertions(+)

diff --git a/public/care.html b/public/care.html
new file mode 100644
index 0000000..0da50fc
--- /dev/null
+++ b/public/care.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<html lang="en"><head>
+<!-- editorial-gen v1 -->
+<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
+<title>Care &amp; installation — hospitalitywallpaper.com</title>
+<meta name="description" content="Care &amp; installation — hospitality, the British way.">
+<link rel="canonical" href="https://hospitalitywallpaper.com/care">
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:ui-sans-serif;background:#FFF;color:#1a1410;line-height:1.65;padding:60px 24px;min-height:100vh}
+.wrap{max-width:720px;margin:0 auto}
+.eyebrow{font-size:10px;letter-spacing:0.22em;text-transform:uppercase;color:#A47C5A;margin-bottom:18px}
+h1{font-family:'Cormorant', serif;font-style:italic;font-size:48px;line-height:1.1;letter-spacing:-0.02em;color:#1a1410;margin-bottom:32px}
+h2{font-family:'Cormorant', serif;font-size:22px;color:#A47C5A;margin:36px 0 12px;font-weight:500}
+p{margin-bottom:16px;color:#3a322c}
+ul{margin:12px 0 20px 18px}
+li{margin-bottom:8px;color:#3a322c}
+strong{color:#1a1410}
+a{color:#A47C5A;text-decoration:underline;text-underline-offset:3px}
+nav.foot{margin-top:56px;padding-top:24px;border-top:1px solid rgba(0,0,0,0.10);font-size:11px;letter-spacing:0.18em;text-transform:uppercase}
+nav.foot a{margin-right:22px;text-decoration:none}
+</style>
+</head><body>
+<div class="wrap">
+<div class="eyebrow">Editorial · care · Heritage Atelier</div>
+<h1>Care &amp; installation</h1>
+<p>Proper installation and maintenance of hospitality wallcoverings ensure their longevity and performance in high-traffic environments. This guide outlines essential steps for substrate preparation, adhesive selection, seam handling, cleaning protocols, light exposure management, and expected durability, tailored to the specific needs of hospitality settings.</p>  
+
+<h2>Substrate Preparation</h2>  
+<p>Begin with a clean, dry, and smooth surface. Remove any existing adhesives, grease, or residue using a mild detergent and water. Ensure the substrate is free from cracks or unevenness; fill gaps with a suitable compound and allow it to cure fully. For porous surfaces, apply a primer to create a stable base. In areas with high humidity, verify that the substrate is moisture-free to prevent future adhesion failures.</p>  
+<ul>  
+  <li>Scrape and sand surfaces to eliminate imperfections.</li>  
+  <li>Use a pH-neutral cleaner to avoid chemical damage.</li>  
+  <li>Allow the substrate to dry completely before proceeding.</li>  
+</ul>  
+
+<h2>Paste Type and Application</h2>  
+<p>Select the correct adhesive based on the wallcovering’s material and the environment. Water-based pastes are ideal for low-traffic areas, offering ease of cleanup. For high-traffic zones, use a starch-based adhesive for enhanced durability and resistance to peeling. Always follow the manufacturer’s instructions for paste consistency and application. Apply paste evenly to the back of the wallcovering, avoiding excess that could cause bubbling or uneven adhesion.</p>  
+<ul>  
+  <li>Use a paste float to spread adhesive uniformly.</li>  
+  <li>Work in small sections to maintain control and avoid dry-out.</li>  
+  <li>Press the wallcovering firmly into place to remove air pockets.</li>  
+</ul>  
+
+<h2>Seam Handling and Alignment</h2>  
+<p>Seams must be aligned precisely to ensure a seamless appearance. Use a seam roller to press seams firmly, ensuring adhesion and minimizing visibility. Avoid stretching the material, as this can cause distortion or buckling. In high-traffic areas, reinforce seams with a seam tape or additional adhesive for added stability. Trim excess material carefully to avoid overhangs that may lift over time.</p>  
+<ul>
+<nav class="foot">
+<a href="/">Browse</a>
+<a href="/history">History</a>
+<a href="/vocabulary">Vocabulary</a>
+<a href="/sourcing">Sourcing</a>
+<a href="/care">Care</a>
+<a href="/trade">Trade</a>
+<a href="/about">About</a>
+</nav>
+</div></body></html>
\ No newline at end of file
diff --git a/public/history.html b/public/history.html
new file mode 100644
index 0000000..b82d712
--- /dev/null
+++ b/public/history.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<html lang="en"><head>
+<!-- editorial-gen v1 -->
+<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
+<title>A short history — hospitalitywallpaper.com</title>
+<meta name="description" content="A short history — hospitality, the British way.">
+<link rel="canonical" href="https://hospitalitywallpaper.com/history">
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:ui-sans-serif;background:#FFF;color:#1a1410;line-height:1.65;padding:60px 24px;min-height:100vh}
+.wrap{max-width:720px;margin:0 auto}
+.eyebrow{font-size:10px;letter-spacing:0.22em;text-transform:uppercase;color:#A47C5A;margin-bottom:18px}
+h1{font-family:'Cormorant', serif;font-style:italic;font-size:48px;line-height:1.1;letter-spacing:-0.02em;color:#1a1410;margin-bottom:32px}
+h2{font-family:'Cormorant', serif;font-size:22px;color:#A47C5A;margin:36px 0 12px;font-weight:500}
+p{margin-bottom:16px;color:#3a322c}
+ul{margin:12px 0 20px 18px}
+li{margin-bottom:8px;color:#3a322c}
+strong{color:#1a1410}
+a{color:#A47C5A;text-decoration:underline;text-underline-offset:3px}
+nav.foot{margin-top:56px;padding-top:24px;border-top:1px solid rgba(0,0,0,0.10);font-size:11px;letter-spacing:0.18em;text-transform:uppercase}
+nav.foot a{margin-right:22px;text-decoration:none}
+</style>
+</head><body>
+<div class="wrap">
+<div class="eyebrow">Editorial · history · Heritage Atelier</div>
+<h1>A short history</h1>
+<p>Hospitality has long been a silent yet eloquent storyteller, its narratives etched into the very walls of spaces designed to welcome, impress, and endure. From the gilded salons of 18th-century Europe to the minimalist lobbies of postwar America, wallcoverings have served as the unsung architects of first impressions, their materials and motifs reflecting the values, ambitions, and aesthetics of those who curated them. This is not merely a history of decoration—it is a chronicle of how hospitality has been physically and culturally expressed through the surfaces that frame its moments.</p>  
+
+<h2>The Grand Tour and the Birth of Ornamental Precision</h2>  
+
+<p>The 18th century marked the rise of wallcoverings as a deliberate craft, driven by the Grand Tour’s obsession with classical aesthetics. In Britain, the demand for imported Italian and French papier-mâché and brocaded papers led to the establishment of domestic mills like Mapp & Nixon, which translated continental opulence into accessible forms. Hotels and inns along the Thames and the West Country adopted these materials, using them to distinguish themselves from mere lodging houses. The dining rooms of these establishments became stages for social performance, their walls adorned with damasked finishes that hinted at refinement. This era laid the groundwork for wallcoverings as both a functional and symbolic element of hospitality, a tradition that would evolve with each new wave of design.</p>  
+
+<h2>The Arts & Crafts Revival: Handcrafted Intimacy</h2>  
+
+<p>By the late 19th century, the Arts & Crafts movement redefined wallcoverings as a medium for moral and artistic integrity. William Morris’s Kelmscott Press, though primarily known for printed books, influenced the texture and craftsmanship of hospitality spaces through its emphasis on handwoven textiles and natural dyes. Hotels and country estates in the UK and US embraced these principles, commissioning bespoke papers that reflected the ethos of “truth to materials.” In this period, the lobby of a railway hotel or the parlor of a grand country house became a canvas for artisanal expression, with papers often featuring floral motifs or geometric patterns that echoed the surrounding architecture. This was hospitality as a curated experience, where every surface contributed to a narrative of quality and care.</p>  
+
+<h2>Bauhaus and the Modernist Shift</h2>  
+
+<p>The early 20th century saw a radical departure from ornamentation, as the Bauhaus school championed functionalism and minimalism. Wallcoverings in this era were stripped of excess, favoring clean lines and monochromatic schemes. Hotels in Germany and the US, such as the iconic Statler Hotels, adopted these principles, using flat, unadorned papers to create spaces that prioritized clarity and utility. The era’s focus on industrial materials and geometric abstraction reflected a broader cultural shift toward modernity, positioning wallcoverings as tools for efficiency rather than embellishment. This period marked a turning point, where hospitality’s visual language became more about the experience of space than the spectacle of decoration.</p>  
+
+<h2>Postwar America: The Rise of the Corporate Aesthetic</h2>  
+
+<p>Following World War II, the hospitality industry in America underwent a transformation driven by the rise of chain hotels and the need for uniformity. Mills like Schumacher and Osborne & Little responded by producing large-scale, repeatable designs that could be deployed across multiple properties. The mid-century modern aesthetic—characterized by bold colors, abstract shapes, and synthetic materials—became the standard for corporate lobbies and dining rooms. This era saw the birth of the “hotel paper,” a category of wallcovering designed to withstand the rigors of high-traffic environments while maintaining a sense of style. The focus shifted from individual craftsmanship to scalable solutions, a reflection of the era’s economic and cultural priorities.</p>  
+
+<h2>Contemporary Hospitality: A Return to Curated Craft</h2>  
+
+<p>Today, the hospitality wallcovering tradition is experiencing a renaissance, blending historical reverence with modern innovation. Ateliers like Heritage Atelier draw on the legacy of Arts & Crafts and Bauhaus principles, but with a focus on bespoke, limited-edition papers that cater to the discerning demands of luxury hotels and boutique inns. Digital printing and advanced weaving techniques allow for intricate, custom-designed finishes that echo the craftsmanship of earlier eras while meeting the practical needs of contemporary spaces. The result is a renewed emphasis on storytelling—each wallcovering is a dialogue between past and present, a testament to the enduring role of surfaces in shaping the guest experience.</p>  
+
+<p>From the salons of the 18th century to the digital lobbies of the 21st, wallcoverings have remained a vital medium for expressing the ethos of hospitality. Their evolution reflects not only changes in design but also shifts in how we define comfort, identity, and connection. In this lineage, Heritage Atelier stands as a custodian of tradition, reimagining the past to serve the present—and the future.</p>
+<nav class="foot">
+<a href="/">Browse</a>
+<a href="/history">History</a>
+<a href="/vocabulary">Vocabulary</a>
+<a href="/sourcing">Sourcing</a>
+<a href="/care">Care</a>
+<a href="/trade">Trade</a>
+<a href="/about">About</a>
+</nav>
+</div></body></html>
\ No newline at end of file
diff --git a/public/index.html.bak.dwfoot.1778203445670 b/public/index.html.bak.dwfoot.1778203445670
new file mode 100644
index 0000000..79a29d5
--- /dev/null
+++ b/public/index.html.bak.dwfoot.1778203445670
@@ -0,0 +1,962 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<!-- Google tag (gtag.js) -->
+<script async src="https://www.googletagmanager.com/gtag/js?id=G-XM0936TL4N"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-XM0936TL4N');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Heritage Atelier — hospitality, the British way.</title>
+<meta name="description" content="Heritage Atelier is a curated atelier dedicated entirely to hospitality. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#FFF">
+<link rel="canonical" href="https://hospitalitywallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600&family=Inter:wght@300;400;500&display=swap" rel="stylesheet">
+<link rel="preload" as="image" href="/hero-bg.jpg" fetchpriority="high">
+<script type="application/ld+json">
+{
+  "@context": "https://schema.org",
+  "@type": "Organization",
+  "name": "Heritage Atelier",
+  "url": "https://hospitalitywallpaper.com/",
+  "email": "info@hospitalitywallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #FFF;
+  --paper: #000;
+  --muted: #8B7866;
+  --line: #A47C5A;
+  --accent: #A47C5A;
+  --bg-soft: #A47C5A;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #000;
+  --paper: #FFF;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #A47C5A;
+  --bg-soft: #2a1f15;
+}
+* { margin:0; padding:0; box-sizing:border-box }
+html { scroll-behavior:smooth }
+body { font-family:'Inter', sans-serif; color:var(--paper); -webkit-font-smoothing:antialiased; background:var(--bg); min-height:100vh; overflow-x:hidden }
+/* DW-FASHION-TEMPLATE-OVERRIDE */
+.section-title .accent, .footer-brand, .center-mark, h1, h2, h3 { font-family:'Cormorant Garamond', Georgia, serif !important; font-weight:500 !important;  }
+
+/* ===== Auto-hide header ===== */
+header { position:fixed; top:0; left:0; right:0; display:flex; justify-content:space-between; align-items:center; padding:22px 32px; z-index:100; background:rgba(0,0,0,0.55); backdrop-filter:blur(10px); border-bottom:1px solid var(--line); transition:transform .3s }
+.h-link { display:flex; align-items:center; gap:10px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); text-decoration:none; cursor:pointer; background:transparent; border:0 }
+.h-link:hover { opacity:0.7 }
+.h-icon { width:18px; height:18px; stroke:currentColor; fill:none; stroke-width:1.5 }
+
+/* ===== Cinema hero ===== */
+.cinema { position:relative; height:100vh; width:100%; overflow:hidden }
+.cinema-bg { position:absolute; inset:0; background-size:cover; background-position:center; background-image:url('/hero-bg.jpg') }
+.cinema-bg::after { content:""; position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.75) 100%) }
+.corner-mark { position:absolute; top:24px; left:32px; font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:#fff; text-shadow:0 1px 3px rgba(0,0,0,0.55), 0 0 1px rgba(0,0,0,0.4); z-index:5 }
+.corner-mark::before { content:"◆ "; margin-right:6px }
+.center-mark { position:absolute; top:clamp(80px,12vh,140px); left:50%; transform:translateX(-50%); font-size:clamp(28px,4vw,56px); font-weight:500; letter-spacing:0.18em; text-transform:uppercase; text-align:center; color:#fff; text-shadow:0 2px 8px rgba(0,0,0,0.65), 0 0 1px rgba(0,0,0,0.5); z-index:5 }
+.center-mark .tm { font-size:14px; vertical-align:super; opacity:0.7; margin-left:0.2em }
+.center-mark .sub { display:block; font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400; font-size:0.4em; letter-spacing:0.04em; text-transform:none; margin-top:14px; opacity:0.85 }
+.meta-line { position:absolute; bottom:32px; left:32px; font-size:10px; letter-spacing:0.28em; text-transform:uppercase; font-weight:700; color:#fff; z-index:5; opacity:0.85 }
+.meta-line .num { font-size:12px; display:block; margin-top:4px; letter-spacing:0.05em }
+.enter { position:absolute; bottom:32px; right:32px; display:flex; align-items:center; gap:14px; font-size:11px; letter-spacing:0.36em; text-transform:uppercase; font-weight:700; color:#fff; text-decoration:none; padding-bottom:6px; border-bottom:1px solid #fff; transition:gap 0.25s; z-index:5 }
+.enter:hover { gap:22px }
+.enter svg { width:24px; height:12px }
+
+/* ===== Section ===== */
+.section { padding:96px 32px }
+.section-header { display:flex; justify-content:space-between; align-items:flex-end; flex-wrap:wrap; gap:24px; margin-bottom:32px; padding-bottom:24px; border-bottom:1px solid var(--line) }
+.section-title { font-size:clamp(36px,5vw,64px); font-weight:300; letter-spacing:-0.02em; line-height:1 }
+.section-title .accent { color: var(--accent); font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400 }
+.section-eyebrow { font-size:10px; letter-spacing:0.4em; text-transform:uppercase; font-weight:700; color:var(--muted); margin-bottom:16px }
+.section-meta { font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:600; color:var(--muted); text-align:right; line-height:1.6 }
+
+/* ===== Filter bar ===== */
+.filters { display:flex; gap:8px; align-items:center; margin-bottom:18px; flex-wrap:wrap }
+.chip { padding:8px 16px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); background:transparent; border:1px solid var(--line); cursor:pointer; transition:all 0.2s; font-family:inherit }
+.chip:hover { border-color:var(--paper) }
+.chip.active { background:var(--paper); color:var(--bg); border-color:var(--paper) }
+.search { flex:0 1 280px; margin-left:auto; display:flex; align-items:center; gap:10px; border-bottom:1px solid var(--line); padding:6px 0 }
+.search input { flex:1; background:transparent; border:0; color:var(--paper); font-family:inherit; font-size:13px; outline:none; letter-spacing:0.04em }
+.search input::placeholder { color:var(--muted) }
+.search svg { width:16px; height:16px; stroke:var(--muted); fill:none; stroke-width:1.5 }
+
+/* ===== Grid-density slider ===== */
+.density { display:flex; align-items:center; gap:14px; padding:6px 0; margin-bottom:24px }
+.density label { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--muted) }
+.density input[type=range] { flex:1; max-width:240px; -webkit-appearance:none; appearance:none; height:1px; background:var(--line); outline:none }
+.density input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50% }
+.density input[type=range]::-moz-range-thumb { width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50%; border:0 }
+.density .ct { font-size:11px; color:var(--muted); letter-spacing:0.18em; text-transform:uppercase; font-weight:600; min-width:80px }
+
+/* ===== Stats line ===== */
+.stat-line { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:600; color:var(--muted); margin-bottom:24px }
+
+/* ===== Product grid (novasuede pattern: flush grid + slide-up overlay) ===== */
+.grid { display:grid; grid-template-columns:repeat(var(--cols), 1fr); gap:0 }
+.card { position:relative; aspect-ratio:1/1.15; cursor:pointer; overflow:hidden; border:1px solid var(--bg); transition:transform 0.4s cubic-bezier(0.2,0.8,0.2,1); background:var(--bg-soft) }
+.card:hover { transform:scale(1.04); z-index:5 }
+.card img { width:100%; height:100%; object-fit:cover; display:block; transition:transform 0.4s ease }
+.card .overlay { position:absolute; left:0; right:0; bottom:0; padding:20px 16px 14px; background:linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.85) 100%); transform:translateY(48%); opacity:0.85; transition:transform 0.3s ease, opacity 0.3s ease }
+.card:hover .overlay { transform:translateY(0); opacity:1 }
+.card .pat { font-size:13px; font-weight:600; letter-spacing:0.02em; color:#fff; line-height:1.25; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
+.card .ven { font-size:9px; letter-spacing:0.18em; text-transform:uppercase; color:#fff; opacity:0.7; font-weight:500; margin-top:4px }
+.card .actions { margin-top:10px; display:flex; gap:6px }
+.card .sample-btn { flex:1; padding:7px 10px; background:#fff; color:#000; font-family:inherit; font-size:10px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; border:0; cursor:pointer; text-align:center; transition:all 0.2s }
+.card .sample-btn:hover { background:var(--accent); color:#fff }
+
+@media (max-width:1024px) { .grid { grid-template-columns:repeat(min(var(--cols), 4), 1fr) } }
+@media (max-width:720px) { .grid { grid-template-columns:repeat(2, 1fr) } .density { display:none } }
+
+.sentinel { height:1px }
+.loading { text-align:center; color:var(--muted); padding:32px; font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700 }
+
+/* ===== Footer ===== */
+footer { padding:64px 32px 32px; border-top:1px solid var(--line); margin-top:32px }
+.footer-grid { max-width:1400px; margin:0 auto; display:grid; grid-template-columns:2fr 1fr 1fr 1fr; gap:48px; margin-bottom:48px }
+.footer-brand { font-size:24px; font-weight:300; letter-spacing:0.32em; text-transform:uppercase; margin-bottom:12px }
+.footer-text { font-size:13px; line-height:1.6; color:var(--muted); max-width:380px }
+.footer-col h4 { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--paper); margin-bottom:18px }
+.footer-col a { display:block; font-size:13px; color:var(--muted); text-decoration:none; margin-bottom:8px; transition:color 0.2s; cursor:pointer; background:transparent; border:0; font-family:inherit; padding:0; text-align:left }
+.footer-col a:hover { color:var(--accent) }
+.footer-bottom { max-width:1400px; margin:0 auto; padding-top:24px; border-top:1px solid var(--line); display:flex; justify-content:space-between; flex-wrap:wrap; gap:16px; font-size:11px; letter-spacing:0.18em; text-transform:uppercase; color:var(--muted) }
+
+@media (max-width:720px) {
+  .corner-mark, .meta-line, .enter { font-size:10px }
+  .center-mark { font-size:24px; letter-spacing:0.12em; top:clamp(60px,9vh,90px) }
+  .section, footer { padding-left:20px; padding-right:20px }
+  .footer-grid { grid-template-columns:1fr; gap:32px }
+  .search { margin-left:0; flex:1 1 100% }
+}
+
+.theme-toggle { background:transparent; border:1px solid var(--line); width:32px; height:32px; cursor:pointer; color:var(--paper); display:inline-flex; align-items:center; justify-content:center; font-size:14px; line-height:1; transition:all .15s; padding:0 }
+.theme-toggle:hover { border-color:var(--accent); color:var(--accent) }
+
+/* ===== WCAG 2.4.7 — keyboard focus indicators ===== */
+/* Strictly :focus-visible so mouse clicks do NOT show the ring */
+a:focus-visible,
+button:focus-visible,
+input:focus-visible,
+select:focus-visible,
+textarea:focus-visible,
+[tabindex]:focus-visible {
+  outline: 2px solid var(--accent);
+  outline-offset: 2px;
+}
+</style>
+<script>
+(function(){ try { var t = localStorage.getItem('hosp_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://hospitalitywallpaper.com/">
+<meta property="og:title" content="Hospitality Wallpaper">
+<meta property="og:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta property="og:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Hospitality Wallpaper">
+<meta property="article:publisher" content="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:title" content="Hospitality Wallpaper">
+<meta name="twitter:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta name="twitter:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<!-- graphics-loop pass 13: footer + fb -->
+</head>
+<body>
+<style id="ns-header-modal-styles">
+        .ns-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; padding: 18px 36px; background: rgba(10,10,10,0.92) !important; backdrop-filter: blur(8px); border-bottom: 1px solid rgba(245,241,232,0.06); }
+        .ns-brand { display: inline-flex; align-items: center; gap: 14px; text-decoration: none; }
+        .ns-dot { width: 28px; height: 28px; border-radius: 50%; background: radial-gradient(circle at 35% 35%, #a98b5b 0%, #5d4c32 60%, #332a1b 100%); box-shadow: 0 0 0 1px rgba(245,241,232,0.10), 0 2px 12px rgba(180,90,60,0.30); flex-shrink: 0; }
+        .ns-name { font-family: -apple-system, "SF Pro Display", "Helvetica Neue", system-ui, sans-serif; font-size: 18px !important; font-weight: 300 !important; letter-spacing: 0.02em !important; color: #f5f1e8 !important; text-transform: none !important; margin: 0 !important; }
+        .ns-name sup { font-size: 0.55em; font-weight: 300; margin-left: 1px; }
+        .ns-nav { display: flex; gap: 32px; align-items: center; list-style: none; padding: 0; margin: 0; }
+        .ns-nav a, .ns-nav button { font-family: -apple-system, "SF Pro Text", system-ui, sans-serif; font-size: 15px !important; font-weight: 400 !important; color: #f5f1e8 !important; text-decoration: none !important; background: none !important; border: 0 !important; cursor: pointer; padding: 0 !important; transition: color 200ms; letter-spacing: 0 !important; text-transform: none !important; }
+        .ns-nav a:hover, .ns-nav button:hover { color: #ffffff !important; }
+        @media (max-width: 820px) { .ns-header { padding: 14px 18px; } .ns-nav { gap: 16px; } .ns-nav a, .ns-nav button { font-size: 13px !important; } }
+        @media (max-width: 760px) {
+          .ns-header { flex-wrap: wrap; }
+          .ns-nav { display: none !important; flex-basis: 100%; flex-direction: column; align-items: flex-start; gap: 6px; padding: 14px 0 4px; }
+          .ns-nav.open { display: flex !important; }
+          .ns-nav a, .ns-nav button { padding: 10px 0 !important; border-bottom: 1px solid rgba(245,241,232,0.08); width: 100%; text-align: left; }
+          .ns-nav a:nth-child(n+5), .ns-nav button:nth-child(n+5) { display: block !important; }
+          .ns-header .mobile-toggle { display: flex !important; }
+        }
+        @media (min-width: 761px) {
+          .ns-header .mobile-toggle { display: none !important; }
+        }
+        .ns-modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.78); z-index: 200; align-items: center; justify-content: center; padding: 24px; backdrop-filter: blur(6px); }
+        .ns-modal.show { display: flex; }
+        .ns-modal-card { max-width: 460px; width: 100%; background: #141414 !important; border: 1px solid rgba(245,241,232,0.14); border-radius: 6px; padding: 28px 30px 30px; position: relative; }
+        .ns-modal-card .close-x { position: absolute; top: 12px; right: 14px; width: 30px; height: 30px; background: none; border: 1px solid rgba(245,241,232,0.18); color: rgba(245,241,232,0.6) !important; border-radius: 50%; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; }
+        .ns-modal-card .close-x:hover { color: #ffffff !important; border-color: #ffffff; }
+        .ns-modal-card h3 { font-family: -apple-system, "SF Pro Display", system-ui; font-weight: 300 !important; font-size: 22px !important; margin: 0 0 6px !important; color: #f5f1e8 !important; }
+        .ns-modal-card .sub { color: rgba(245,241,232,0.65) !important; font-size: 13px; margin: 0 0 22px; }
+        .ns-actions { display: flex; flex-direction: column; gap: 10px; }
+        .ns-action { display: flex; align-items: center; gap: 14px; padding: 14px 16px; background: rgba(245,241,232,0.04) !important; border: 1px solid rgba(245,241,232,0.12) !important; color: #f5f1e8 !important; text-decoration: none !important; cursor: pointer; transition: all 200ms; font: inherit; text-align: left; }
+        .ns-action:hover { background: rgba(245,241,232,0.08) !important; border-color: #d4b683 !important; }
+        .ns-action .ico { width: 32px; height: 32px; border-radius: 50%; background: rgba(212,182,131,0.12); display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
+        .ns-action .txt { flex: 1; }
+        .ns-action .txt b { display: block; font-weight: 500; font-size: 14px; color: #f5f1e8 !important; }
+        .ns-action .txt span { font-size: 12px; color: rgba(245,241,232,0.55) !important; }
+
+        /* ─── FINAL CONTRAST PASS — kill remaining gold-solid + white-island defects ─── */
+        /* Replace all gold-fill accents with off-white (Gucci-aesthetic, no DW gold solids) */
+        .new-badge, .new-arrivals-pill,
+        .color-filter-btn.active,
+        .drapery-btn, .sample-btn-chip, .cb-cta {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        .new-badge:hover, .new-arrivals-pill:hover,
+        .color-filter-btn.active:hover,
+        .drapery-btn:hover, .sample-btn-chip:hover, .cb-cta:hover {
+          background: #fff !important;
+          color: #0a0a0a !important;
+        }
+        /* Gold accents stay only as edge color (links, glyphs) — not fills */
+        a { color: #d4b683; }
+        a:hover { color: #f5d97a; }
+        /* Authorized-dealer footer line — small caps tracked, muted ink, no gold pill */
+        .authorized, .authorized-dealer p {
+          background: transparent !important;
+          color: rgba(245,241,232,0.5) !important;
+          font-size: 10px !important;
+          letter-spacing: 0.22em !important;
+          text-transform: uppercase !important;
+          padding: 0 !important;
+          border: none !important;
+          margin-top: 14px !important;
+        }
+        /* Kill any straggler white bg in info-card / sample-related cards */
+        .info-card, .info-card-link, .care-highlight, .feature-card, .spec-item {
+          background-color: rgba(245,241,232,0.04) !important;
+          border-color: rgba(245,241,232,0.12) !important;
+        }
+        /* Ensure modal content stays readable — Steve's earlier sweep made it #141414 with white text */
+        .modal-content { background: #141414 !important; color: #f5f1e8 !important; }
+        .modal-content * { color: #f5f1e8 !important; }
+        .modal-content input, .modal-content textarea, .modal-content select {
+          background: rgba(245,241,232,0.05) !important;
+          color: #f5f1e8 !important;
+          border-color: rgba(245,241,232,0.2) !important;
+        }
+        .modal-content label { color: rgba(245,241,232,0.6) !important; }
+        /* Force the wide-tracked NOVASUEDE wordmark to stay white */
+        .ns-wordmark, .ns-wordmark sup { color: #f5f1e8 !important; }
+
+        /* ─── Modal-internal contrast (post-QA defects) ─── */
+        /* Backdrop covers full viewport */
+        .modal { width: 100vw !important; height: 100vh !important; left: 0 !important; top: 0 !important; background: rgba(0, 0, 0, 0.78) !important; backdrop-filter: blur(6px); }
+        /* Chip — flip from white-on-white island to dark card */
+        .request-chip {
+          background: rgba(245, 241, 232, 0.06) !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.18) !important;
+          border-radius: 4px !important;
+        }
+        .request-chip * { color: #f5f1e8 !important; }
+        .request-chip .chip-swatch {
+          /* swatch dot ALWAYS displays the inline-style hex from JS — fight any sweep */
+          border: 1px solid rgba(0, 0, 0, 0.4) !important;
+        }
+        /* + Add to request — hairline white-border on transparent (no gold) */
+        .add-to-request-btn {
+          background: transparent !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.6) !important;
+          border-radius: 0 !important;
+          padding: 12px 22px !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 400 !important;
+        }
+        .add-to-request-btn:hover {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        /* Hex caption visible */
+        .preview-hex, #colorPreviewHex {
+          display: block !important;
+          color: rgba(245, 241, 232, 0.55) !important;
+          font-family: ui-monospace, "SF Mono", Menlo, monospace !important;
+          font-size: 11px !important;
+          margin-top: 4px !important;
+          letter-spacing: 0.04em !important;
+          text-transform: lowercase !important;
+        }
+        /* Color preview name — stays single, prominent */
+        #colorPreviewName {
+          color: #f5f1e8 !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 500 !important;
+          display: block !important;
+          margin-top: 12px !important;
+        }
+
+        /* ─── Mobile hamburger nav (replaces the overflow at <760px) ─── */
+        @media (max-width: 760px) {
+          header .nav-container { flex-wrap: wrap; }
+          header nav { display: none; flex-basis: 100%; flex-direction: column; gap: 6px; padding: 16px 0 6px; }
+          header nav.open { display: flex; }
+          header nav a { padding: 10px 0; border-bottom: 1px solid rgba(245,241,232,0.1); }
+          header .mobile-toggle {
+            display: flex !important;
+            flex-direction: column;
+            gap: 5px;
+            background: transparent;
+            border: 0;
+            cursor: pointer;
+            padding: 8px;
+          }
+          header .mobile-toggle span {
+            width: 22px; height: 1.5px;
+            background: #f5f1e8;
+            display: block;
+          }
+        }
+        @media (min-width: 761px) {
+          header .mobile-toggle { display: none !important; }
+        }
+
+    </style>
+<style id="ns-gold-kill">
+    /* novasuede: kill gold-solid fills, off-white instead. Edge color stays gold. */
+    .new-badge, .new-arrivals-pill,
+    .color-filter-btn.active, .drapery-btn,
+    .sample-btn-chip, .cb-cta {
+      background: #f5f1e8 !important;
+      color: #0a0a0a !important;
+      border-color: #f5f1e8 !important;
+    }
+    .new-badge:hover, .new-arrivals-pill:hover,
+    .color-filter-btn.active:hover, .drapery-btn:hover,
+    .sample-btn-chip:hover, .cb-cta:hover {
+      background: #fff !important;
+      color: #0a0a0a !important;
+    }
+  </style>
+<header class="ns-header">
+        <a href="/" class="ns-brand" aria-label="Home">
+            <span class="ns-dot"></span>
+            <span class="ns-name">Heritage Atelier</span>
+        </a>
+        <nav class="ns-nav" id="nsPrimaryNav" aria-label="Primary">
+            <a href="/">Home</a>
+            <a href="/about">About</a>
+            <button type="button" onclick="nsContactOpen()">Contact</button>
+        </nav>
+        <button type="button" class="mobile-toggle" aria-label="Toggle menu" aria-controls="nsPrimaryNav" aria-expanded="false" onclick="nsToggleNav(this)">
+            <span></span><span></span><span></span>
+        </button>
+    </header>
+
+<div class="ns-modal" id="nsContactModal" role="dialog" aria-modal="true" aria-labelledby="nsContactTitle" onclick="if(event.target===this)nsContactClose()">
+        <div class="ns-modal-card">
+            <button type="button" class="close-x" onclick="nsContactClose()" aria-label="Close">×</button>
+            <h3 id="nsContactTitle">How can we help?</h3>
+            <p class="sub">Trade-account replies within one business day.</p>
+            <div class="ns-actions">
+                <a class="ns-action" href="#contact" onclick="nsContactClose()"><span class="ico">📋</span><div class="txt"><b>Get a Quote</b><span>Project specs → priced estimate</span></div></a>
+                <a class="ns-action" href="#contact" onclick="nsContactClose();openModal();"><span class="ico">📦</span><div class="txt"><b>Order a Sample</b><span>Free swatch to your shop</span></div></a>
+                <a class="ns-action" href="mailto:info@novasuede.com?subject=Novasuede%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@novasuede.com</span></div></a>
+                <a class="ns-action" href="tel:888-373-4564"><span class="ico">📞</span><div class="txt"><b>Call Us</b><span>(888) 373-4564 · M–F, 9–5 PT</span></div></a>
+            </div>
+        </div>
+    </div>
+<script>
+  function nsContactOpen() { var m = document.getElementById('nsContactModal'); if (m) m.classList.add('show'); }
+  function nsContactClose() { var m = document.getElementById('nsContactModal'); if (m) m.classList.remove('show'); }
+  function nsToggleNav(btn) {
+    var nav = document.getElementById('nsPrimaryNav');
+    if (!nav) return;
+    var open = nav.classList.toggle('open');
+    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
+  }
+  document.addEventListener('keydown', function(e){ if (e.key === 'Escape') nsContactClose(); });
+</script>
+
+
+
+
+
+<header>
+  <button class="h-link" onclick="dwmOpen('Contact')" aria-label="Contact"><svg class="h-icon" viewBox="0 0 24 24"><path d="M3 7h18M3 12h18M3 17h18"/></svg><span>Contact</span></button>
+  <button class="theme-toggle" id="theme-toggle" aria-label="Theme toggle">☾</button>
+</header>
+
+<section class="cinema">
+  <div class="cinema-bg" id="heroBg"></div>
+  <div class="corner-mark">Trade-Grade</div>
+  <div class="center-mark">Hospitality Wallpaper</div>
+  <div class="meta-line">Hotel · Restaurant · Spa · Class A<span class="num" id="heroNum"></span></div>
+  <a class="enter" href="#shop">Enter <svg viewBox="0 0 24 12" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M0 6h22M16 1l6 5-6 5"/></svg></a>
+</section>
+
+
+<section class="section" id="ideas">
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">New this week</h2>
+    <div class="rail" id="railNewest"></div>
+  </div>
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">Curated picks</h2>
+    <div class="rail" id="railCurated"></div>
+  </div>
+</section>
+
+<section class="section" id="shop">
+  <div class="section-header">
+    <div>
+      <div class="section-eyebrow">The Collection</div>
+      <h2 class="section-title"><span class="accent" id="totalCount">—</span> Patterns.</h2>
+    </div>
+    <div class="section-meta">Hotel · Restaurant · Spa · Class A</div>
+  </div>
+
+  <div class="filters" id="facets">
+    <button class="chip active" data-facet="all">All</button>
+  </div>
+
+  <div class="density">
+    <label>Sort</label>
+    <select id="sortSelect" aria-label="Sort products" style="background:transparent;color:inherit;border:1px solid var(--line,rgba(255,255,255,.2));font:inherit;font-size:11px;letter-spacing:.10em;text-transform:uppercase;padding:4px 8px;cursor:pointer;outline:none;margin-right:14px">
+      <option value="newest">Newest</option>
+      <option value="color">Color</option>
+      <option value="style">Style</option>
+      <option value="sku">SKU A→Z</option>
+      <option value="title">Title A→Z</option>
+      <option value="price-asc">Price ↑</option>
+      <option value="price-desc">Price ↓</option>
+    </select>
+    <label>Grid</label>
+    <input type="range" id="densitySlider" min="4" max="12" step="1" value="6" aria-label="Grid columns">
+    <span class="ct" id="densityLabel">6 cols</span>
+    <div class="search">
+      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-5.5-5.5"/></svg>
+      <input type="text" id="searchInput" placeholder="Search by pattern, color…" autocomplete="off">
+    </div>
+  </div>
+
+  <div class="stat-line" id="statLine">Loading…</div>
+  <div class="grid" id="grid"></div>
+  <div class="loading" id="loading">Loading more…</div>
+  <div class="sentinel" id="sentinel"></div>
+</section>
+
+<footer>
+  <div class="footer-grid">
+    <div>
+      <div class="footer-brand">Hospitality Wallpaper</div>
+      <p class="footer-text">Hospitality Wallpaper is a specialty hospitality archive within the Designer Wallcoverings family. Real samples ship free.</p>
+      <p class="footer-text" style="margin-top:14px;font-size:11px;letter-spacing:0.18em;text-transform:uppercase;font-weight:600;color:var(--paper);opacity:0.7"><a href="/about" style="color:inherit;text-decoration:none;border-bottom:1px solid var(--accent)">About →</a></p>
+    </div>
+    <div class="footer-col">
+      <h4>Aesthetic</h4>
+      <div id="footerFacets"></div>
+    </div>
+    <div class="footer-col">
+      <h4>Trade</h4>
+      <button onclick="dwmOpen('Inquiry')">Project Inquiry</button>
+      <button onclick="dwmOpen('Sample')">Request Sample</button>
+      <button onclick="dwmOpen('Contact')">Contact</button>
+    </div>
+  
+    <div class="footer-col">
+      <h4>Social</h4>
+      <a class="fb-link" href="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings" target="_blank" rel="noopener">Facebook</a>
+    </div>
+  </div>
+  <div class="footer-bottom">
+    <span>hospitalitywallpaper.com · Heritage Atelier</span>
+    <span><a href="mailto:info@hospitalitywallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@hospitalitywallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "hospitalitywallpaper";
+  const NICHES = [
+    ['silkwallpaper','Silk','mat'],['silkwallcoverings','Silk W/C','mat'],['linenwallpaper','Linen','mat'],
+    ['jutewallpaper','Jute','mat'],['raffiawallcoverings','Raffia W/C','mat'],['raffiawalls','Raffia Walls','mat'],
+    ['corkwallcovering','Cork','mat'],['fabricwallpaper','Fabric','mat'],['textilewallpaper','Textile','mat'],
+    ['metallicwallpaper','Metallic','mat'],['silverleafwallpaper','Silver Leaf','mat'],['vinylwallpaper','Vinyl','mat'],
+    ['micawallpaper','Mica','mat'],['madagascarwallpaper','Madagascar','mat'],['mylarwallpaper','Mylar','mat'],
+    ['suedewallpaper','Suede','mat'],
+    ['1800swallpaper','1800s','dec'],['1890swallpaper','1890s','dec'],['1900swallpaper','1900s','dec'],
+    ['1920swallpaper','1920s','dec'],['1930swallpaper','1930s','dec'],['1940swallpaper','1940s','dec'],
+    ['1950swallpaper','1950s','dec'],['1960swallpaper','1960s','dec'],['1970swallpaper','1970s','dec'],
+    ['1980swallpaper','1980s','dec'],['retrowalls','Retro','dec'],['wallpapersback','W. Back','dec'],
+    ['agedwallpaper','Aged','cra'],['handcraftedwallpaper','Handcrafted','cra'],['museumwallpaper','Museum','cra'],
+    ['restorationwallpaper','Restoration','cra'],['pastelwallpaper','Pastel','cra'],['glitterwalls','Glitter','cra'],
+    ['greenwallcoverings','Green','cra'],['naturalwallcoverings','Natural','cra'],['saloonwallpaper','Saloon','cra'],
+    ['contractwallpaper','Contract','use'],['hotelwallcoverings','Hotel','use'],['hospitalitywallpaper','Hospitality','use'],
+    ['healthcarewallpaper','Healthcare','use'],['restaurantwallpaper','Restaurant','use'],['architecturalwallcoverings','Architectural','use']
+  ];
+  const COLOR = { mat:'#c9b687', dec:'#b86a4a', cra:'#6b8e6f', use:'#4a6b8e' };
+  const W = 1080, H = 200, BANDS = ['mat','dec','cra','use'];
+  const groups = { mat:[], dec:[], cra:[], use:[] };
+  for (const n of NICHES) groups[n[2]].push(n);
+  const svg = document.getElementById('miniConst');
+  if (!svg) return;
+  const bandW = W / BANDS.length;
+  let nodes = '';
+  BANDS.forEach((band, bi) => {
+    const list = groups[band];
+    const cx = bi * bandW + bandW / 2;
+    list.forEach((n, i) => {
+      const t = list.length === 1 ? 0.5 : i / (list.length - 1);
+      // deterministic jitter per slug
+      let h = 0; for (let k = 0; k < n[0].length; k++) h = (h * 31 + n[0].charCodeAt(k)) | 0;
+      const jx = ((h & 0xff) / 255 - 0.5) * (bandW * 0.5);
+      const jy = (((h >> 8) & 0xff) / 255 - 0.5) * 6;  // tightened from 14 → 6 to prevent same-band collisions (16 mat nodes / 144px = 9px spacing)
+      const x = cx + jx, y = 28 + t * (H - 56) + jy;
+      const isCurrent = n[0] === SLUG;
+      const r = isCurrent ? 8 : 4;
+      const op = isCurrent ? 1 : 0.55;
+      nodes += `<g class="mc-node" data-slug="${n[0]}" data-label="${n[1]}" style="cursor:pointer">
+        <circle cx="${x}" cy="${y}" r="${r}" fill="url(#dna-${band})" fill-opacity="${op}" stroke="${COLOR[band]}" stroke-opacity="${isCurrent?1:0.7}" stroke-width="${isCurrent?2:1}">
+          <title>${n[1]} — ${n[0]}.com</title>
+        </circle>
+        ${isCurrent ? `<circle cx="${x}" cy="${y}" r="${r+5}" fill="none" stroke="${COLOR[band]}" stroke-opacity="0.4" stroke-width="1"><animate attributeName="r" values="${r+5};${r+12};${r+5}" dur="2.4s" repeatCount="indefinite"/><animate attributeName="stroke-opacity" values="0.4;0;0.4" dur="2.4s" repeatCount="indefinite"/></circle>` : ''}
+      </g>`;
+    });
+  });
+  // append nodes after defs
+  svg.insertAdjacentHTML('beforeend', nodes);
+  svg.querySelectorAll('.mc-node').forEach(n => {
+    n.addEventListener('mouseenter', () => n.querySelector('circle').setAttribute('fill-opacity', '1'));
+    n.addEventListener('mouseleave', e => {
+      const isCurrent = n.dataset.slug === SLUG;
+      n.querySelector('circle').setAttribute('fill-opacity', isCurrent ? '1' : '0.55');
+    });
+    n.addEventListener('click', () => window.open('https://' + n.dataset.slug + '.com', '_blank'));
+  });
+})();
+</script>
+
+<script>
+const state = { q:'', facet:'all', page:1, pages:1, total:0, loading:false, exhausted:false };
+const LABELS = {"all":"All"};
+
+function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c])); }
+// Image-URL allowlist: only DW Shopify CDN + designerwallcoverings.com (defends against XSS via crafted products.json)
+function safeImg(u) { return /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(u || '') ? u : '/hero-bg.jpg'; }
+function cardHTML(p) {
+  const eager = state.page === 1;
+  return '<img loading="' + (eager ? 'eager' : 'lazy') + '"' + (eager ? ' fetchpriority="high"' : '') + ' src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+    + '<div class="overlay">'
+    + '<div class="pat">' + escAttr(p.pattern_name || p.title) + '</div>'
+    + '<div class="ven">' + escAttr((p.vendor || '').replace(/-/g, ' ')) + '</div>'
+    + '<div class="actions">'
+    + '<button class="sample-btn" onclick="event.stopPropagation();dwmOpen(\'Sample\',' + JSON.stringify({sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}).replace(/"/g,'&quot;') + ')">Sample</button>'
+    + '</div></div>';
+}
+
+async function loadFacets() {
+  let f;
+  try {
+    const r = await fetch('/api/facets');
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    f = await r.json();
+  } catch (e) { console.error('loadFacets failed:', e); return; }
+  const el = document.getElementById('facets');
+  for (const [k, v] of Object.entries(f.aesthetics).sort((a,b) => b[1] - a[1])) {
+    const b = document.createElement('button');
+    b.className = 'chip'; b.dataset.facet = k;
+    b.innerHTML = (LABELS[k] || k) + ' <span style="opacity:.55;font-weight:500;margin-left:4px">' + v + '</span>';
+    el.appendChild(b);
+  }
+  el.addEventListener('click', e => {
+    if (e.target.tagName !== 'BUTTON') return;
+    document.querySelectorAll('#facets button').forEach(b => b.classList.remove('active'));
+    e.target.classList.add('active');
+    state.facet = e.target.dataset.facet;
+    resetGrid();
+  });
+  document.getElementById('totalCount').textContent = f.total;
+  document.getElementById('footerStat').textContent = f.total + ' patterns · live archive';
+  // Footer aesthetic links
+  const footerEl = document.getElementById('footerFacets');
+  for (const [k] of Object.entries(f.aesthetics)) {
+    const b = document.createElement('button');
+    b.textContent = LABELS[k] || k;
+    b.onclick = () => { state.facet = k; resetGrid(); document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === k)); document.getElementById('shop').scrollIntoView({behavior:'smooth'}); };
+    footerEl.appendChild(b);
+  }
+}
+
+function resetGrid() {
+  state.page = 1; state.exhausted = false;
+  document.getElementById('grid').innerHTML = '';
+  document.getElementById('loading').textContent = 'Loading…';
+  loadGridPage();
+}
+
+async function loadGridPage() {
+  if (state.loading || state.exhausted) return;
+  state.loading = true;
+  const params = new URLSearchParams({ page:state.page, limit:24 });
+  if (state.q) params.set('q', state.q);
+  if (state.facet !== 'all') params.set('aesthetic', state.facet);
+  let data;
+  try {
+    const r = await fetch('/api/products?' + params);
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    data = await r.json();
+  } catch (e) {
+    console.error('loadGridPage failed:', e);
+    document.getElementById('loading').textContent = '— offline — refresh to retry —';
+    state.loading = false;
+    return;
+  }
+  state.total = data.total; state.pages = data.pages;
+
+  if (state.page === 1) {
+    document.getElementById('statLine').textContent = data.total + ' patterns · ' + (state.facet === 'all' ? 'all aesthetics' : (LABELS[state.facet] || state.facet)) + (state.q ? ' · matching "' + state.q + '"' : '');
+  }
+  const grid = document.getElementById('grid');
+  for (const p of data.items) {
+    const a = document.createElement('a');
+    a.className = 'card'; a.href = '#'; a.onclick = (e) => { e.preventDefault(); dwmOpen('Sample',{sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}); };
+    a.innerHTML = cardHTML(p);
+    grid.appendChild(a);
+  }
+  if (state.page >= state.pages || data.items.length === 0) {
+    state.exhausted = true;
+    document.getElementById('loading').textContent = state.total > 0 ? '— end of archive · ' + state.total + ' patterns —' : '';
+  } else state.page++;
+  state.loading = false;
+}
+
+const io = new IntersectionObserver(es => { for (const e of es) if (e.isIntersecting) loadGridPage(); }, { rootMargin:'600px 0px' });
+io.observe(document.getElementById('sentinel'));
+
+document.getElementById('searchInput').addEventListener('input', e => {
+  state.q = e.target.value.trim();
+  clearTimeout(window._t);
+  window._t = setTimeout(resetGrid, 220);
+});
+
+// Density slider
+const slider = document.getElementById('densitySlider');
+const dlabel = document.getElementById('densityLabel');
+function setDensity(n) {
+  document.documentElement.style.setProperty('--cols', n);
+  dlabel.textContent = n + ' cols';
+  try { localStorage.setItem('hosp_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('hosp_theme_density') || '6');
+if (savedDensity >= 4 && savedDensity <= 12) { slider.value = savedDensity; setDensity(savedDensity); }
+
+// Theme toggle
+const tb = document.getElementById('theme-toggle');
+function setTheme(t){ document.documentElement.dataset.theme = t; try { localStorage.setItem('hosp_theme', t); } catch(e){} tb.textContent = t === 'dark' ? '☾' : '☀'; }
+setTheme(document.documentElement.dataset.theme || 'light');
+tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
+
+loadFacets();
+loadGridPage();
+</script>
+<!-- ============================================================
+     DW UNIVERSAL CONTACT MODULE — fashion-house UX
+     Inject before </body> in every DW-family sister site.
+     Self-contained: CSS + 4 modals + JS submission handlers.
+     Uses host site's CSS vars (--bg, --fg, --gold, --rule).
+     ============================================================ -->
+<style>
+  /* === MODAL BASE === */
+  .dwm{position:fixed;inset:0;background:rgba(0,0,0,0.78);display:none;align-items:center;justify-content:center;z-index:9999;padding:24px;overflow-y:auto}
+  .dwm.open{display:flex}
+  .dwm-box{background:var(--bg);border:1px solid var(--rule);max-width:520px;width:100%;padding:36px 32px;position:relative;max-height:90vh;overflow-y:auto;animation:dwm-in 0.25s ease}
+  @keyframes dwm-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
+  .dwm-box h3{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-weight:400;font-size:32px;line-height:1.05;margin-bottom:6px;color:var(--fg);letter-spacing:-0.01em}
+  .dwm-box .sub{color:var(--muted);font-size:12px;letter-spacing:0.16em;text-transform:uppercase;margin-bottom:24px;font-weight:500}
+  .dwm-close{position:absolute;top:18px;right:18px;background:transparent;border:0;color:var(--muted);font-size:24px;cursor:pointer;width:32px;height:32px;line-height:1;padding:0}
+  .dwm-close:hover{color:var(--gold)}
+  .dwm-preview{display:flex;gap:14px;align-items:center;padding:12px;background:var(--bg-soft);margin-bottom:18px}
+  .dwm-preview img{width:64px;height:64px;object-fit:cover}
+  .dwm-preview .pn{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-size:15px;line-height:1.2;color:var(--fg)}
+  .dwm-preview .pc{font-size:10px;letter-spacing:0.14em;text-transform:uppercase;color:var(--muted);margin-top:4px}
+  .dwm-field{margin-bottom:14px}
+  .dwm-field label{display:block;font-size:10px;letter-spacing:0.18em;text-transform:uppercase;color:var(--muted);margin-bottom:6px;font-weight:500}
+  .dwm-field input,.dwm-field textarea,.dwm-field select{width:100%;border:0;border-bottom:1px solid var(--rule);background:transparent;padding:8px 4px;font-size:14px;font-family:inherit;color:var(--fg);outline:none;transition:border-color 0.2s}
+  .dwm-field input:focus,.dwm-field textarea:focus{border-bottom-color:var(--gold)}
+  .dwm-field textarea{min-height:60px;resize:vertical}
+  .dwm-submit{background:transparent;color:var(--muted, #c9b89e);border:1px solid var(--muted, #c9b89e);padding:14px 28px;font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:700;cursor:pointer;width:100%;margin-top:8px;transition:background 0.15s, color 0.15s}
+  .dwm-submit:hover{background:var(--muted, #c9b89e);color:var(--bg, #000)}
+  
+  .dwm-submit:disabled{opacity:0.5;cursor:default}
+  .dwm-status{margin-top:14px;font-size:11px;letter-spacing:0.16em;text-transform:uppercase;text-align:center;display:none}
+  .dwm-status.ok{color:var(--sage);display:block}
+  .dwm-status.err{color:#e08070;display:block}
+  /* contact-options */
+  .dwm-options{display:flex;flex-direction:column;gap:10px}
+  .dwm-option{display:flex;align-items:center;gap:14px;padding:18px 20px;background:transparent;border:1px solid var(--rule);color:var(--fg);font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:600;cursor:pointer;text-decoration:none;transition:all 0.2s;text-align:left;width:100%}
+  .dwm-option:hover{border-color:var(--gold);color:var(--gold)}
+  .dwm-option svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.5;flex-shrink:0}
+  .dwm-option .lbl{flex:1;display:block}
+  .dwm-option .val{display:block;font-size:10px;letter-spacing:0.14em;text-transform:none;font-weight:500;opacity:0.65;margin-top:4px}
+
+/* graphics-loop pass 11: Ideas rails */
+#ideas { padding: 56px 24px 24px; max-width:1600px; margin:0 auto }
+#ideas .rail-block { margin-bottom:48px }
+#ideas .rail-eyebrow { font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:var(--muted, #888); margin-bottom:8px }
+#ideas .rail-title { font-size:clamp(22px,2.6vw,32px); font-weight:500; letter-spacing:-0.01em; margin:0 0 18px; color:var(--ink,#fff) }
+#ideas .rail { display:flex; gap:14px; overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:8px; scrollbar-width:none }
+#ideas .rail::-webkit-scrollbar { display:none }
+#ideas .rail-card { flex:0 0 240px; scroll-snap-align:start; cursor:pointer; transition:transform 0.2s }
+#ideas .rail-card:hover { transform:translateY(-3px) }
+#ideas .rail-card img { width:100%; aspect-ratio:1; object-fit:cover; display:block; background:var(--card,#222) }
+#ideas .rail-card .rc-title { font-size:13px; font-weight:500; color:var(--paper,#fff); padding:8px 0 2px; line-height:1.3 }
+#ideas .rail-card .rc-meta  { font-size:11px; color:var(--muted,#888); letter-spacing:0.06em }
+@media (max-width:720px) { #ideas .rail-card { flex:0 0 160px } }
+</style>
+
+<!-- Contact options modal -->
+<div class="dwm" id="dwmContact" onclick="if(event.target===this)dwmClose('Contact')">
+  <div class="dwm-box" style="max-width:440px">
+    <button class="dwm-close" onclick="dwmClose('Contact')" aria-label="Close">×</button>
+    <h3>Contact</h3>
+    <p class="sub" id="dwmContactSub">Three ways to reach us</p>
+    <div class="dwm-options">
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Inquiry')">
+        <svg viewBox="0 0 24 24"><path d="M4 4h16v12H7l-3 3z"/></svg>
+        <span class="lbl">Send an Inquiry<span class="val">Project name · scope · all the details</span></span>
+      </button>
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Sample')">
+        <svg viewBox="0 0 24 24"><rect x="4" y="6" width="16" height="14"/><path d="M4 10h16M9 6V3h6v3"/></svg>
+        <span class="lbl">Request a Sample<span class="val">Memo sample · ships free · 3–5 business days</span></span>
+      </button>
+      <a class="dwm-option" id="dwmContactEmailLink" href="mailto:info@hospitalitywallpaper.com">
+        <svg viewBox="0 0 24 24"><path d="M3 6h18v12H3z"/><path d="M3 6l9 7 9-7"/></svg>
+        <span class="lbl">Email Us<span class="val" id="dwmContactEmailLabel">info@hospitalitywallpaper.com</span></span>
+      </a>
+    </div>
+  </div>
+</div>
+
+<!-- Inquiry modal -->
+<div class="dwm" id="dwmInquiry" onclick="if(event.target===this)dwmClose('Inquiry')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Inquiry')" aria-label="Close">×</button>
+    <h3>Project Inquiry</h3>
+    <p class="sub">We'll respond within one business day</p>
+    <form id="dwmInquiryForm" onsubmit="return dwmSubmit(event,'inquiry')">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Phone</label><input type="tel" name="phone"></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Project Name</label><input type="text" name="projectName" required></div>
+      <div class="dwm-field"><label>Project Scope</label><textarea name="projectScope" placeholder="Square footage · room count · timeline" required></textarea></div>
+      <div class="dwm-field"><label>Additional Information</label><textarea name="message" placeholder="Patterns of interest, finish preferences, budget"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Inquiry</button>
+      <div class="dwm-status" id="dwmInquiryStatus"></div>
+    </form>
+  </div>
+</div>
+
+<!-- Sample-request modal -->
+<div class="dwm" id="dwmSample" onclick="if(event.target===this)dwmClose('Sample')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Sample')" aria-label="Close">×</button>
+    <h3>Request a Sample</h3>
+    <p class="sub">Memo sample · ships free · 3–5 business days</p>
+    <div class="dwm-preview" id="dwmSamplePreview" style="display:none">
+      <img id="dwmSampleImg" src="" alt="">
+      <div><div class="pn" id="dwmSampleName"></div><div class="pc" id="dwmSampleSku"></div></div>
+    </div>
+    <form id="dwmSampleForm" onsubmit="return dwmSubmit(event,'sample')">
+      <input type="hidden" name="sku" id="dwmSampleSkuInput">
+      <input type="hidden" name="title" id="dwmSampleTitleInput">
+      <input type="hidden" name="image_url" id="dwmSampleImageInput">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Shipping Address</label><input type="text" name="address" placeholder="Street" required></div>
+      <div class="dwm-field" style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:8px">
+        <input type="text" name="city" placeholder="City" required>
+        <input type="text" name="state" placeholder="State" required>
+        <input type="text" name="zip" placeholder="ZIP" required>
+      </div>
+      <div class="dwm-field"><label>Notes (optional)</label><textarea name="message" placeholder="Project, sq.ft., timing"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Sample Request</button>
+      <div class="dwm-status" id="dwmSampleStatus"></div>
+    </form>
+  </div>
+</div>
+
+<script>
+  // Universal modal control
+  function dwmOpen(name, opts){
+    document.getElementById('dwm' + name).classList.add('open');
+    document.body.style.overflow = 'hidden';
+    if (name === 'Sample' && opts) {
+      document.getElementById('dwmSamplePreview').style.display = 'flex';
+      document.getElementById('dwmSampleImg').src = opts.image_url || '';
+      document.getElementById('dwmSampleName').textContent = opts.title || '';
+      document.getElementById('dwmSampleSku').textContent = opts.sku || '';
+      document.getElementById('dwmSampleSkuInput').value = opts.sku || '';
+      document.getElementById('dwmSampleTitleInput').value = opts.title || '';
+      document.getElementById('dwmSampleImageInput').value = opts.image_url || '';
+    } else if (name === 'Sample') {
+      document.getElementById('dwmSamplePreview').style.display = 'none';
+      document.getElementById('dwmSampleSkuInput').value = '';
+      document.getElementById('dwmSampleTitleInput').value = '';
+      document.getElementById('dwmSampleImageInput').value = '';
+    }
+  }
+  function dwmClose(name){ document.getElementById('dwm'+name).classList.remove('open'); document.body.style.overflow=''; }
+
+  // Universal form submit — POSTs to /api/send-{kind}
+  async function dwmSubmit(e, kind) {
+    e.preventDefault();
+    const form = e.target;
+    const data = Object.fromEntries(new FormData(form).entries());
+    const btn = form.querySelector('.dwm-submit');
+    const status = form.querySelector('.dwm-status');
+    btn.disabled = true; const orig = btn.textContent; btn.textContent = 'Sending…';
+    status.className = 'dwm-status';
+    try {
+      const r = await fetch('/api/send-' + kind, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(data) });
+      if (!r.ok) throw new Error('HTTP '+r.status);
+      const j = await r.json();
+      status.textContent = kind === 'sample' ? 'Sample request sent — ships within 3–5 business days' : 'Inquiry sent — we respond within 1 business day';
+      status.className = 'dwm-status ok';
+      btn.textContent = 'Sent ✓';
+      setTimeout(() => { dwmClose(kind === 'sample' ? 'Sample' : 'Inquiry'); btn.disabled = false; btn.textContent = orig; status.className = 'dwm-status'; form.reset(); }, 2800);
+    } catch (err) {
+      status.textContent = 'Send failed — please email info@designerwallcoverings.com';
+      status.className = 'dwm-status err';
+      btn.disabled = false; btn.textContent = orig;
+    }
+    return false;
+  }
+
+  // Wire up "Memo samples ship free" badge in hero to open sample modal directly
+  document.querySelectorAll('.hero .badge, [data-open-sample]').forEach(el => {
+    el.style.cursor = 'pointer';
+    el.addEventListener('click', () => dwmOpen('Sample'));
+  });
+
+  // Wire nav "Trade" link to inquiry modal
+  document.querySelectorAll('nav a[href*="designerwallcoverings.com"]').forEach(a => {
+    a.removeAttribute('target');
+    a.removeAttribute('href');
+    a.style.cursor = 'pointer';
+    a.addEventListener('click', e => { e.preventDefault(); dwmOpen('Contact'); });
+  });
+
+  // Override product card clicks — open Sample modal pre-filled instead of redirecting to DW
+  document.addEventListener('click', e => {
+    const card = e.target.closest('.card, .rail-card');
+    if (!card) return;
+    if (card.tagName === 'A' && (card.getAttribute('href') || '').startsWith('/sample/')) {
+      e.preventDefault();
+      const img = card.querySelector('img');
+      const pat = card.querySelector('.pat');
+      const sku = card.getAttribute('href').replace('/sample/', '');
+      dwmOpen('Sample', {
+        sku,
+        title: pat ? pat.textContent.trim() : '',
+        image_url: img ? img.src : ''
+      });
+    }
+  }, true);
+// DW STANDARD: hero pulls from products.json[0].image_url so dw-collections-viewer
+// drag-drop / hero-pin updates the live front page on next deploy.
+// Always upgrades to the largest Shopify variant (strips _NxN size suffix) so
+// the full-page hero stays sharp.
+// DW STANDARD: hero rotates through top-20 NEWEST products on each visit
+// (novasuede.com pattern). Fetches /api/products?limit=100, sorts by created_at desc,
+// takes the freshest 20, picks one per visit via localStorage counter.
+// Falls back to static /hero-bg.jpg on any error.
+(async function rotateHero() {
+  try {
+    const r = await fetch('/api/products?limit=100');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || [])
+      .filter(p => p && p.image_url && /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(p.image_url))
+      .sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')))
+      .slice(0, 20);
+    if (!items.length) return;
+    let visits = 0;
+    try {
+      visits = parseInt(localStorage.getItem('hero_visits') || '0', 10) || 0;
+      localStorage.setItem('hero_visits', String(visits + 1));
+    } catch(e) {}
+    const pick = items[visits % items.length];
+    // Strip _NxN size suffix to get the largest CDN variant
+    const url = pick.image_url.replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+    const bg = document.getElementById('heroBg') || document.getElementById('cinemaBg');
+    if (bg) bg.style.backgroundImage = "url('" + url + "')";
+  } catch (e) {}
+})();
+
+
+// DW STANDARD sort-select wire-up (added by fleet patcher)
+(function(){
+  const sortSel = document.getElementById('sortSelect');
+  if (!sortSel) return;
+  const KEY = location.hostname.replace(/\./g, '_') + '_sort';
+  const saved = localStorage.getItem(KEY);
+  if (saved) { try { sortSel.value = saved; } catch(e){} }
+  if (typeof state !== 'undefined') state.sort = sortSel.value;
+  sortSel.addEventListener('change', e => {
+    const v = e.target.value;
+    try { localStorage.setItem(KEY, v); } catch(e){}
+    if (typeof state !== 'undefined') state.sort = v;
+    if (typeof resetGrid === 'function') resetGrid();
+    else location.reload();
+  });
+})();
+
+// graphics-loop pass 11: hydrate Ideas rails from /api/products
+(async function hydrateIdeas() {
+  try {
+    const r = await fetch('/api/products?limit=80');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || []).filter(p => p && p.image_url);
+    if (!items.length) return;
+    const sorted = [...items].sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')));
+    const newest = sorted.slice(0, 12);
+    // Curated = deterministic offset slice (every 5th item starting at idx 3) for variety
+    const curated = items.filter((_, i) => i % 5 === 3).slice(0, 12);
+    function card(p) {
+      const url = (p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+      return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle || p.sku) + '">' +
+        '<img src="' + url + '" alt="' + (p.title || '').replace(/"/g, '&quot;') + '" loading="lazy">' +
+        '<div class="rc-title">' + ((p.title || '').split('|')[0] || '').trim() + '</div>' +
+        '<div class="rc-meta">' + (p.vendor || '') + '</div>' +
+      '</a>';
+    }
+    const r1 = document.getElementById('railNewest');
+    const r2 = document.getElementById('railCurated');
+    if (r1) r1.innerHTML = newest.map(card).join('');
+    if (r2) r2.innerHTML = curated.map(card).join('');
+  } catch(e) {}
+})();
+</script>
+
+</body>
+</html>
diff --git a/public/index.html.bak.gtagev.1778426584663 b/public/index.html.bak.gtagev.1778426584663
new file mode 100644
index 0000000..d622a79
--- /dev/null
+++ b/public/index.html.bak.gtagev.1778426584663
@@ -0,0 +1,972 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+
+<meta charset="utf-8">
+<!-- Google tag (gtag.js) -->
+<script async src="https://www.googletagmanager.com/gtag/js?id=G-XM0936TL4N"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-XM0936TL4N');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Heritage Atelier — hospitality, the British way.</title>
+<meta name="description" content="Heritage Atelier is a curated atelier dedicated entirely to hospitality. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#FFF">
+<link rel="canonical" href="https://hospitalitywallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600&family=Inter:wght@300;400;500&display=swap" rel="stylesheet">
+<link rel="preload" as="image" href="/hero-bg.jpg" fetchpriority="high">
+<script type="application/ld+json">
+{
+  "@context": "https://schema.org",
+  "@type": "Organization",
+  "name": "Heritage Atelier",
+  "url": "https://hospitalitywallpaper.com/",
+  "email": "info@hospitalitywallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #FFF;
+  --paper: #000;
+  --muted: #8B7866;
+  --line: #A47C5A;
+  --accent: #A47C5A;
+  --bg-soft: #A47C5A;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #000;
+  --paper: #FFF;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #A47C5A;
+  --bg-soft: #2a1f15;
+}
+* { margin:0; padding:0; box-sizing:border-box }
+html { scroll-behavior:smooth }
+body { font-family:'Inter', sans-serif; color:var(--paper); -webkit-font-smoothing:antialiased; background:var(--bg); min-height:100vh; overflow-x:hidden }
+/* DW-FASHION-TEMPLATE-OVERRIDE */
+.section-title .accent, .footer-brand, .center-mark, h1, h2, h3 { font-family:'Cormorant Garamond', Georgia, serif !important; font-weight:500 !important;  }
+
+/* ===== Auto-hide header ===== */
+header { position:fixed; top:0; left:0; right:0; display:flex; justify-content:space-between; align-items:center; padding:22px 32px; z-index:100; background:rgba(0,0,0,0.55); backdrop-filter:blur(10px); border-bottom:1px solid var(--line); transition:transform .3s }
+.h-link { display:flex; align-items:center; gap:10px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); text-decoration:none; cursor:pointer; background:transparent; border:0 }
+.h-link:hover { opacity:0.7 }
+.h-icon { width:18px; height:18px; stroke:currentColor; fill:none; stroke-width:1.5 }
+
+/* ===== Cinema hero ===== */
+.cinema { position:relative; height:100vh; width:100%; overflow:hidden }
+.cinema-bg { position:absolute; inset:0; background-size:cover; background-position:center; background-image:url('/hero-bg.jpg') }
+.cinema-bg::after { content:""; position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.75) 100%) }
+.corner-mark { position:absolute; top:24px; left:32px; font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:#fff; text-shadow:0 1px 3px rgba(0,0,0,0.55), 0 0 1px rgba(0,0,0,0.4); z-index:5 }
+.corner-mark::before { content:"◆ "; margin-right:6px }
+.center-mark { position:absolute; top:clamp(80px,12vh,140px); left:50%; transform:translateX(-50%); font-size:clamp(28px,4vw,56px); font-weight:500; letter-spacing:0.18em; text-transform:uppercase; text-align:center; color:#fff; text-shadow:0 2px 8px rgba(0,0,0,0.65), 0 0 1px rgba(0,0,0,0.5); z-index:5 }
+.center-mark .tm { font-size:14px; vertical-align:super; opacity:0.7; margin-left:0.2em }
+.center-mark .sub { display:block; font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400; font-size:0.4em; letter-spacing:0.04em; text-transform:none; margin-top:14px; opacity:0.85 }
+.meta-line { position:absolute; bottom:32px; left:32px; font-size:10px; letter-spacing:0.28em; text-transform:uppercase; font-weight:700; color:#fff; z-index:5; opacity:0.85 }
+.meta-line .num { font-size:12px; display:block; margin-top:4px; letter-spacing:0.05em }
+.enter { position:absolute; bottom:32px; right:32px; display:flex; align-items:center; gap:14px; font-size:11px; letter-spacing:0.36em; text-transform:uppercase; font-weight:700; color:#fff; text-decoration:none; padding-bottom:6px; border-bottom:1px solid #fff; transition:gap 0.25s; z-index:5 }
+.enter:hover { gap:22px }
+.enter svg { width:24px; height:12px }
+
+/* ===== Section ===== */
+.section { padding:96px 32px }
+.section-header { display:flex; justify-content:space-between; align-items:flex-end; flex-wrap:wrap; gap:24px; margin-bottom:32px; padding-bottom:24px; border-bottom:1px solid var(--line) }
+.section-title { font-size:clamp(36px,5vw,64px); font-weight:300; letter-spacing:-0.02em; line-height:1 }
+.section-title .accent { color: var(--accent); font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400 }
+.section-eyebrow { font-size:10px; letter-spacing:0.4em; text-transform:uppercase; font-weight:700; color:var(--muted); margin-bottom:16px }
+.section-meta { font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:600; color:var(--muted); text-align:right; line-height:1.6 }
+
+/* ===== Filter bar ===== */
+.filters { display:flex; gap:8px; align-items:center; margin-bottom:18px; flex-wrap:wrap }
+.chip { padding:8px 16px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); background:transparent; border:1px solid var(--line); cursor:pointer; transition:all 0.2s; font-family:inherit }
+.chip:hover { border-color:var(--paper) }
+.chip.active { background:var(--paper); color:var(--bg); border-color:var(--paper) }
+.search { flex:0 1 280px; margin-left:auto; display:flex; align-items:center; gap:10px; border-bottom:1px solid var(--line); padding:6px 0 }
+.search input { flex:1; background:transparent; border:0; color:var(--paper); font-family:inherit; font-size:13px; outline:none; letter-spacing:0.04em }
+.search input::placeholder { color:var(--muted) }
+.search svg { width:16px; height:16px; stroke:var(--muted); fill:none; stroke-width:1.5 }
+
+/* ===== Grid-density slider ===== */
+.density { display:flex; align-items:center; gap:14px; padding:6px 0; margin-bottom:24px }
+.density label { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--muted) }
+.density input[type=range] { flex:1; max-width:240px; -webkit-appearance:none; appearance:none; height:1px; background:var(--line); outline:none }
+.density input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50% }
+.density input[type=range]::-moz-range-thumb { width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50%; border:0 }
+.density .ct { font-size:11px; color:var(--muted); letter-spacing:0.18em; text-transform:uppercase; font-weight:600; min-width:80px }
+
+/* ===== Stats line ===== */
+.stat-line { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:600; color:var(--muted); margin-bottom:24px }
+
+/* ===== Product grid (novasuede pattern: flush grid + slide-up overlay) ===== */
+.grid { display:grid; grid-template-columns:repeat(var(--cols), 1fr); gap:0 }
+.card { position:relative; aspect-ratio:1/1.15; cursor:pointer; overflow:hidden; border:1px solid var(--bg); transition:transform 0.4s cubic-bezier(0.2,0.8,0.2,1); background:var(--bg-soft) }
+.card:hover { transform:scale(1.04); z-index:5 }
+.card img { width:100%; height:100%; object-fit:cover; display:block; transition:transform 0.4s ease }
+.card .overlay { position:absolute; left:0; right:0; bottom:0; padding:20px 16px 14px; background:linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.85) 100%); transform:translateY(48%); opacity:0.85; transition:transform 0.3s ease, opacity 0.3s ease }
+.card:hover .overlay { transform:translateY(0); opacity:1 }
+.card .pat { font-size:13px; font-weight:600; letter-spacing:0.02em; color:#fff; line-height:1.25; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
+.card .ven { font-size:9px; letter-spacing:0.18em; text-transform:uppercase; color:#fff; opacity:0.7; font-weight:500; margin-top:4px }
+.card .actions { margin-top:10px; display:flex; gap:6px }
+.card .sample-btn { flex:1; padding:7px 10px; background:#fff; color:#000; font-family:inherit; font-size:10px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; border:0; cursor:pointer; text-align:center; transition:all 0.2s }
+.card .sample-btn:hover { background:var(--accent); color:#fff }
+
+@media (max-width:1024px) { .grid { grid-template-columns:repeat(min(var(--cols), 4), 1fr) } }
+@media (max-width:720px) { .grid { grid-template-columns:repeat(2, 1fr) } .density { display:none } }
+
+.sentinel { height:1px }
+.loading { text-align:center; color:var(--muted); padding:32px; font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700 }
+
+/* ===== Footer ===== */
+footer { padding:64px 32px 32px; border-top:1px solid var(--line); margin-top:32px }
+.footer-grid { max-width:1400px; margin:0 auto; display:grid; grid-template-columns:2fr 1fr 1fr 1fr; gap:48px; margin-bottom:48px }
+.footer-brand { font-size:24px; font-weight:300; letter-spacing:0.32em; text-transform:uppercase; margin-bottom:12px }
+.footer-text { font-size:13px; line-height:1.6; color:var(--muted); max-width:380px }
+.footer-col h4 { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--paper); margin-bottom:18px }
+.footer-col a { display:block; font-size:13px; color:var(--muted); text-decoration:none; margin-bottom:8px; transition:color 0.2s; cursor:pointer; background:transparent; border:0; font-family:inherit; padding:0; text-align:left }
+.footer-col a:hover { color:var(--accent) }
+.footer-bottom { max-width:1400px; margin:0 auto; padding-top:24px; border-top:1px solid var(--line); display:flex; justify-content:space-between; flex-wrap:wrap; gap:16px; font-size:11px; letter-spacing:0.18em; text-transform:uppercase; color:var(--muted) }
+
+@media (max-width:720px) {
+  .corner-mark, .meta-line, .enter { font-size:10px }
+  .center-mark { font-size:24px; letter-spacing:0.12em; top:clamp(60px,9vh,90px) }
+  .section, footer { padding-left:20px; padding-right:20px }
+  .footer-grid { grid-template-columns:1fr; gap:32px }
+  .search { margin-left:0; flex:1 1 100% }
+}
+
+.theme-toggle { background:transparent; border:1px solid var(--line); width:32px; height:32px; cursor:pointer; color:var(--paper); display:inline-flex; align-items:center; justify-content:center; font-size:14px; line-height:1; transition:all .15s; padding:0 }
+.theme-toggle:hover { border-color:var(--accent); color:var(--accent) }
+
+/* ===== WCAG 2.4.7 — keyboard focus indicators ===== */
+/* Strictly :focus-visible so mouse clicks do NOT show the ring */
+a:focus-visible,
+button:focus-visible,
+input:focus-visible,
+select:focus-visible,
+textarea:focus-visible,
+[tabindex]:focus-visible {
+  outline: 2px solid var(--accent);
+  outline-offset: 2px;
+}
+</style>
+<script>
+(function(){ try { var t = localStorage.getItem('hosp_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://hospitalitywallpaper.com/">
+<meta property="og:title" content="Hospitality Wallpaper">
+<meta property="og:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta property="og:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Hospitality Wallpaper">
+<meta property="article:publisher" content="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:title" content="Hospitality Wallpaper">
+<meta name="twitter:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta name="twitter:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<!-- graphics-loop pass 13: footer + fb -->
+</head>
+<body>
+<style id="ns-header-modal-styles">
+        .ns-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; padding: 18px 36px; background: rgba(10,10,10,0.92) !important; backdrop-filter: blur(8px); border-bottom: 1px solid rgba(245,241,232,0.06); }
+        .ns-brand { display: inline-flex; align-items: center; gap: 14px; text-decoration: none; }
+        .ns-dot { width: 28px; height: 28px; border-radius: 50%; background: radial-gradient(circle at 35% 35%, #a98b5b 0%, #5d4c32 60%, #332a1b 100%); box-shadow: 0 0 0 1px rgba(245,241,232,0.10), 0 2px 12px rgba(180,90,60,0.30); flex-shrink: 0; }
+        .ns-name { font-family: -apple-system, "SF Pro Display", "Helvetica Neue", system-ui, sans-serif; font-size: 18px !important; font-weight: 300 !important; letter-spacing: 0.02em !important; color: #f5f1e8 !important; text-transform: none !important; margin: 0 !important; }
+        .ns-name sup { font-size: 0.55em; font-weight: 300; margin-left: 1px; }
+        .ns-nav { display: flex; gap: 32px; align-items: center; list-style: none; padding: 0; margin: 0; }
+        .ns-nav a, .ns-nav button { font-family: -apple-system, "SF Pro Text", system-ui, sans-serif; font-size: 15px !important; font-weight: 400 !important; color: #f5f1e8 !important; text-decoration: none !important; background: none !important; border: 0 !important; cursor: pointer; padding: 0 !important; transition: color 200ms; letter-spacing: 0 !important; text-transform: none !important; }
+        .ns-nav a:hover, .ns-nav button:hover { color: #ffffff !important; }
+        @media (max-width: 820px) { .ns-header { padding: 14px 18px; } .ns-nav { gap: 16px; } .ns-nav a, .ns-nav button { font-size: 13px !important; } }
+        @media (max-width: 760px) {
+          .ns-header { flex-wrap: wrap; }
+          .ns-nav { display: none !important; flex-basis: 100%; flex-direction: column; align-items: flex-start; gap: 6px; padding: 14px 0 4px; }
+          .ns-nav.open { display: flex !important; }
+          .ns-nav a, .ns-nav button { padding: 10px 0 !important; border-bottom: 1px solid rgba(245,241,232,0.08); width: 100%; text-align: left; }
+          .ns-nav a:nth-child(n+5), .ns-nav button:nth-child(n+5) { display: block !important; }
+          .ns-header .mobile-toggle { display: flex !important; }
+        }
+        @media (min-width: 761px) {
+          .ns-header .mobile-toggle { display: none !important; }
+        }
+        .ns-modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.78); z-index: 200; align-items: center; justify-content: center; padding: 24px; backdrop-filter: blur(6px); }
+        .ns-modal.show { display: flex; }
+        .ns-modal-card { max-width: 460px; width: 100%; background: #141414 !important; border: 1px solid rgba(245,241,232,0.14); border-radius: 6px; padding: 28px 30px 30px; position: relative; }
+        .ns-modal-card .close-x { position: absolute; top: 12px; right: 14px; width: 30px; height: 30px; background: none; border: 1px solid rgba(245,241,232,0.18); color: rgba(245,241,232,0.6) !important; border-radius: 50%; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; }
+        .ns-modal-card .close-x:hover { color: #ffffff !important; border-color: #ffffff; }
+        .ns-modal-card h3 { font-family: -apple-system, "SF Pro Display", system-ui; font-weight: 300 !important; font-size: 22px !important; margin: 0 0 6px !important; color: #f5f1e8 !important; }
+        .ns-modal-card .sub { color: rgba(245,241,232,0.65) !important; font-size: 13px; margin: 0 0 22px; }
+        .ns-actions { display: flex; flex-direction: column; gap: 10px; }
+        .ns-action { display: flex; align-items: center; gap: 14px; padding: 14px 16px; background: rgba(245,241,232,0.04) !important; border: 1px solid rgba(245,241,232,0.12) !important; color: #f5f1e8 !important; text-decoration: none !important; cursor: pointer; transition: all 200ms; font: inherit; text-align: left; }
+        .ns-action:hover { background: rgba(245,241,232,0.08) !important; border-color: #d4b683 !important; }
+        .ns-action .ico { width: 32px; height: 32px; border-radius: 50%; background: rgba(212,182,131,0.12); display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
+        .ns-action .txt { flex: 1; }
+        .ns-action .txt b { display: block; font-weight: 500; font-size: 14px; color: #f5f1e8 !important; }
+        .ns-action .txt span { font-size: 12px; color: rgba(245,241,232,0.55) !important; }
+
+        /* ─── FINAL CONTRAST PASS — kill remaining gold-solid + white-island defects ─── */
+        /* Replace all gold-fill accents with off-white (Gucci-aesthetic, no DW gold solids) */
+        .new-badge, .new-arrivals-pill,
+        .color-filter-btn.active,
+        .drapery-btn, .sample-btn-chip, .cb-cta {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        .new-badge:hover, .new-arrivals-pill:hover,
+        .color-filter-btn.active:hover,
+        .drapery-btn:hover, .sample-btn-chip:hover, .cb-cta:hover {
+          background: #fff !important;
+          color: #0a0a0a !important;
+        }
+        /* Gold accents stay only as edge color (links, glyphs) — not fills */
+        a { color: #d4b683; }
+        a:hover { color: #f5d97a; }
+        /* Authorized-dealer footer line — small caps tracked, muted ink, no gold pill */
+        .authorized, .authorized-dealer p {
+          background: transparent !important;
+          color: rgba(245,241,232,0.5) !important;
+          font-size: 10px !important;
+          letter-spacing: 0.22em !important;
+          text-transform: uppercase !important;
+          padding: 0 !important;
+          border: none !important;
+          margin-top: 14px !important;
+        }
+        /* Kill any straggler white bg in info-card / sample-related cards */
+        .info-card, .info-card-link, .care-highlight, .feature-card, .spec-item {
+          background-color: rgba(245,241,232,0.04) !important;
+          border-color: rgba(245,241,232,0.12) !important;
+        }
+        /* Ensure modal content stays readable — Steve's earlier sweep made it #141414 with white text */
+        .modal-content { background: #141414 !important; color: #f5f1e8 !important; }
+        .modal-content * { color: #f5f1e8 !important; }
+        .modal-content input, .modal-content textarea, .modal-content select {
+          background: rgba(245,241,232,0.05) !important;
+          color: #f5f1e8 !important;
+          border-color: rgba(245,241,232,0.2) !important;
+        }
+        .modal-content label { color: rgba(245,241,232,0.6) !important; }
+        /* Force the wide-tracked NOVASUEDE wordmark to stay white */
+        .ns-wordmark, .ns-wordmark sup { color: #f5f1e8 !important; }
+
+        /* ─── Modal-internal contrast (post-QA defects) ─── */
+        /* Backdrop covers full viewport */
+        .modal { width: 100vw !important; height: 100vh !important; left: 0 !important; top: 0 !important; background: rgba(0, 0, 0, 0.78) !important; backdrop-filter: blur(6px); }
+        /* Chip — flip from white-on-white island to dark card */
+        .request-chip {
+          background: rgba(245, 241, 232, 0.06) !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.18) !important;
+          border-radius: 4px !important;
+        }
+        .request-chip * { color: #f5f1e8 !important; }
+        .request-chip .chip-swatch {
+          /* swatch dot ALWAYS displays the inline-style hex from JS — fight any sweep */
+          border: 1px solid rgba(0, 0, 0, 0.4) !important;
+        }
+        /* + Add to request — hairline white-border on transparent (no gold) */
+        .add-to-request-btn {
+          background: transparent !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.6) !important;
+          border-radius: 0 !important;
+          padding: 12px 22px !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 400 !important;
+        }
+        .add-to-request-btn:hover {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        /* Hex caption visible */
+        .preview-hex, #colorPreviewHex {
+          display: block !important;
+          color: rgba(245, 241, 232, 0.55) !important;
+          font-family: ui-monospace, "SF Mono", Menlo, monospace !important;
+          font-size: 11px !important;
+          margin-top: 4px !important;
+          letter-spacing: 0.04em !important;
+          text-transform: lowercase !important;
+        }
+        /* Color preview name — stays single, prominent */
+        #colorPreviewName {
+          color: #f5f1e8 !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 500 !important;
+          display: block !important;
+          margin-top: 12px !important;
+        }
+
+        /* ─── Mobile hamburger nav (replaces the overflow at <760px) ─── */
+        @media (max-width: 760px) {
+          header .nav-container { flex-wrap: wrap; }
+          header nav { display: none; flex-basis: 100%; flex-direction: column; gap: 6px; padding: 16px 0 6px; }
+          header nav.open { display: flex; }
+          header nav a { padding: 10px 0; border-bottom: 1px solid rgba(245,241,232,0.1); }
+          header .mobile-toggle {
+            display: flex !important;
+            flex-direction: column;
+            gap: 5px;
+            background: transparent;
+            border: 0;
+            cursor: pointer;
+            padding: 8px;
+          }
+          header .mobile-toggle span {
+            width: 22px; height: 1.5px;
+            background: #f5f1e8;
+            display: block;
+          }
+        }
+        @media (min-width: 761px) {
+          header .mobile-toggle { display: none !important; }
+        }
+
+    </style>
+<style id="ns-gold-kill">
+    /* novasuede: kill gold-solid fills, off-white instead. Edge color stays gold. */
+    .new-badge, .new-arrivals-pill,
+    .color-filter-btn.active, .drapery-btn,
+    .sample-btn-chip, .cb-cta {
+      background: #f5f1e8 !important;
+      color: #0a0a0a !important;
+      border-color: #f5f1e8 !important;
+    }
+    .new-badge:hover, .new-arrivals-pill:hover,
+    .color-filter-btn.active:hover, .drapery-btn:hover,
+    .sample-btn-chip:hover, .cb-cta:hover {
+      background: #fff !important;
+      color: #0a0a0a !important;
+    }
+  </style>
+<header class="ns-header">
+        <a href="/" class="ns-brand" aria-label="Home">
+            <span class="ns-dot"></span>
+            <span class="ns-name">Heritage Atelier</span>
+        </a>
+        <nav class="ns-nav" id="nsPrimaryNav" aria-label="Primary">
+            <a href="/">Home</a>
+            <a href="/about">About</a>
+            <button type="button" onclick="nsContactOpen()">Contact</button>
+        </nav>
+        <button type="button" class="mobile-toggle" aria-label="Toggle menu" aria-controls="nsPrimaryNav" aria-expanded="false" onclick="nsToggleNav(this)">
+            <span></span><span></span><span></span>
+        </button>
+    </header>
+
+<div class="ns-modal" id="nsContactModal" role="dialog" aria-modal="true" aria-labelledby="nsContactTitle" onclick="if(event.target===this)nsContactClose()">
+        <div class="ns-modal-card">
+            <button type="button" class="close-x" onclick="nsContactClose()" aria-label="Close">×</button>
+            <h3 id="nsContactTitle">How can we help?</h3>
+            <p class="sub">Trade-account replies within one business day.</p>
+            <div class="ns-actions">
+                <a class="ns-action" href="#contact" onclick="nsContactClose()"><span class="ico">📋</span><div class="txt"><b>Get a Quote</b><span>Project specs → priced estimate</span></div></a>
+                <a class="ns-action" href="#contact" onclick="nsContactClose();openModal();"><span class="ico">📦</span><div class="txt"><b>Order a Sample</b><span>Free swatch to your shop</span></div></a>
+                <a class="ns-action" href="mailto:info@hospitalitywallpaper.com?subject=Heritage%20Atelier%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@hospitalitywallpaper.com</span></div></a>
+                <a class="ns-action" href="tel:888-373-4564"><span class="ico">📞</span><div class="txt"><b>Call Us</b><span>(888) 373-4564 · M–F, 9–5 PT</span></div></a>
+            </div>
+        </div>
+    </div>
+<script>
+  function nsContactOpen() { var m = document.getElementById('nsContactModal'); if (m) m.classList.add('show'); }
+  function nsContactClose() { var m = document.getElementById('nsContactModal'); if (m) m.classList.remove('show'); }
+  function nsToggleNav(btn) {
+    var nav = document.getElementById('nsPrimaryNav');
+    if (!nav) return;
+    var open = nav.classList.toggle('open');
+    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
+  }
+  document.addEventListener('keydown', function(e){ if (e.key === 'Escape') nsContactClose(); });
+</script>
+
+
+
+
+
+
+
+
+
+
+
+<header>
+  <button class="h-link" onclick="dwmOpen('Contact')" aria-label="Contact"><svg class="h-icon" viewBox="0 0 24 24"><path d="M3 7h18M3 12h18M3 17h18"/></svg><span>Contact</span></button>
+  <button class="theme-toggle" id="theme-toggle" aria-label="Theme toggle">☾</button>
+</header>
+
+<section class="cinema">
+  <div class="cinema-bg" id="heroBg"></div>
+  <div class="corner-mark">Trade-Grade</div>
+  <div class="center-mark">Hospitality Wallpaper</div>
+  <div class="meta-line">Hotel · Restaurant · Spa · Class A<span class="num" id="heroNum"></span></div>
+  <a class="enter" href="#shop">Enter <svg viewBox="0 0 24 12" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M0 6h22M16 1l6 5-6 5"/></svg></a>
+</section>
+
+
+<section class="section" id="ideas">
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">New this week</h2>
+    <div class="rail" id="railNewest"></div>
+  </div>
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">Curated picks</h2>
+    <div class="rail" id="railCurated"></div>
+  </div>
+</section>
+
+<section class="section" id="shop">
+  <div class="section-header">
+    <div>
+      <div class="section-eyebrow">The Collection</div>
+      <h2 class="section-title"><span class="accent" id="totalCount">—</span> Patterns.</h2>
+    </div>
+    <div class="section-meta">Hotel · Restaurant · Spa · Class A</div>
+  </div>
+
+  <div class="filters" id="facets">
+    <button class="chip active" data-facet="all">All</button>
+  </div>
+
+  <div class="density">
+    <label>Sort</label>
+    <select id="sortSelect" aria-label="Sort products" style="background:transparent;color:inherit;border:1px solid var(--line,rgba(255,255,255,.2));font:inherit;font-size:11px;letter-spacing:.10em;text-transform:uppercase;padding:4px 8px;cursor:pointer;outline:none;margin-right:14px">
+      <option value="newest">Newest</option>
+      <option value="color">Color</option>
+      <option value="style">Style</option>
+      <option value="sku">SKU A→Z</option>
+      <option value="title">Title A→Z</option>
+      <option value="price-asc">Price ↑</option>
+      <option value="price-desc">Price ↓</option>
+    </select>
+    <label>Grid</label>
+    <input type="range" id="densitySlider" min="4" max="12" step="1" value="6" aria-label="Grid columns">
+    <span class="ct" id="densityLabel">6 cols</span>
+    <div class="search">
+      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-5.5-5.5"/></svg>
+      <input type="text" id="searchInput" placeholder="Search by pattern, color…" autocomplete="off">
+    </div>
+  </div>
+
+  <div class="stat-line" id="statLine">Loading…</div>
+  <div class="grid" id="grid"></div>
+  <div class="loading" id="loading">Loading more…</div>
+  <div class="sentinel" id="sentinel"></div>
+</section>
+
+<footer>
+  <div class="footer-grid">
+    <div>
+      <div class="footer-brand">Heritage Atelier</div>
+      <p class="footer-text">Heritage Atelier — real samples ship free.</p>
+      <p class="footer-text" style="margin-top:14px;font-size:11px;letter-spacing:0.18em;text-transform:uppercase;font-weight:600;color:var(--paper);opacity:0.7"><a href="/about" style="color:inherit;text-decoration:none;border-bottom:1px solid var(--accent)">About →</a></p>
+    </div>
+    <div class="footer-col">
+      <h4>Aesthetic</h4>
+      <div id="footerFacets"></div>
+    </div>
+    <div class="footer-col">
+      <h4>Trade</h4>
+      <button onclick="dwmOpen('Inquiry')">Project Inquiry</button>
+      <button onclick="dwmOpen('Sample')">Request Sample</button>
+      <button onclick="dwmOpen('Contact')">Contact</button>
+    </div>
+  
+    <div class="footer-col">
+      <h4>Social</h4>
+      <a class="fb-link" href="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings" target="_blank" rel="noopener">Facebook</a>
+    </div>
+  </div>
+  <div class="footer-bottom">
+    <span>hospitalitywallpaper.com · Heritage Atelier</span>
+    <span><a href="mailto:info@hospitalitywallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@hospitalitywallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "hospitalitywallpaper";
+  const NICHES = [
+    ['silkwallpaper','Silk','mat'],['silkwallcoverings','Silk W/C','mat'],['linenwallpaper','Linen','mat'],
+    ['jutewallpaper','Jute','mat'],['raffiawallcoverings','Raffia W/C','mat'],['raffiawalls','Raffia Walls','mat'],
+    ['corkwallcovering','Cork','mat'],['fabricwallpaper','Fabric','mat'],['textilewallpaper','Textile','mat'],
+    ['metallicwallpaper','Metallic','mat'],['silverleafwallpaper','Silver Leaf','mat'],['vinylwallpaper','Vinyl','mat'],
+    ['micawallpaper','Mica','mat'],['madagascarwallpaper','Madagascar','mat'],['mylarwallpaper','Mylar','mat'],
+    ['suedewallpaper','Suede','mat'],
+    ['1800swallpaper','1800s','dec'],['1890swallpaper','1890s','dec'],['1900swallpaper','1900s','dec'],
+    ['1920swallpaper','1920s','dec'],['1930swallpaper','1930s','dec'],['1940swallpaper','1940s','dec'],
+    ['1950swallpaper','1950s','dec'],['1960swallpaper','1960s','dec'],['1970swallpaper','1970s','dec'],
+    ['1980swallpaper','1980s','dec'],['retrowalls','Retro','dec'],['wallpapersback','W. Back','dec'],
+    ['agedwallpaper','Aged','cra'],['handcraftedwallpaper','Handcrafted','cra'],['museumwallpaper','Museum','cra'],
+    ['restorationwallpaper','Restoration','cra'],['pastelwallpaper','Pastel','cra'],['glitterwalls','Glitter','cra'],
+    ['greenwallcoverings','Green','cra'],['naturalwallcoverings','Natural','cra'],['saloonwallpaper','Saloon','cra'],
+    ['contractwallpaper','Contract','use'],['hotelwallcoverings','Hotel','use'],['hospitalitywallpaper','Hospitality','use'],
+    ['healthcarewallpaper','Healthcare','use'],['restaurantwallpaper','Restaurant','use'],['architecturalwallcoverings','Architectural','use']
+  ];
+  const COLOR = { mat:'#c9b687', dec:'#b86a4a', cra:'#6b8e6f', use:'#4a6b8e' };
+  const W = 1080, H = 200, BANDS = ['mat','dec','cra','use'];
+  const groups = { mat:[], dec:[], cra:[], use:[] };
+  for (const n of NICHES) groups[n[2]].push(n);
+  const svg = document.getElementById('miniConst');
+  if (!svg) return;
+  const bandW = W / BANDS.length;
+  let nodes = '';
+  BANDS.forEach((band, bi) => {
+    const list = groups[band];
+    const cx = bi * bandW + bandW / 2;
+    list.forEach((n, i) => {
+      const t = list.length === 1 ? 0.5 : i / (list.length - 1);
+      // deterministic jitter per slug
+      let h = 0; for (let k = 0; k < n[0].length; k++) h = (h * 31 + n[0].charCodeAt(k)) | 0;
+      const jx = ((h & 0xff) / 255 - 0.5) * (bandW * 0.5);
+      const jy = (((h >> 8) & 0xff) / 255 - 0.5) * 6;  // tightened from 14 → 6 to prevent same-band collisions (16 mat nodes / 144px = 9px spacing)
+      const x = cx + jx, y = 28 + t * (H - 56) + jy;
+      const isCurrent = n[0] === SLUG;
+      const r = isCurrent ? 8 : 4;
+      const op = isCurrent ? 1 : 0.55;
+      nodes += `<g class="mc-node" data-slug="${n[0]}" data-label="${n[1]}" style="cursor:pointer">
+        <circle cx="${x}" cy="${y}" r="${r}" fill="url(#dna-${band})" fill-opacity="${op}" stroke="${COLOR[band]}" stroke-opacity="${isCurrent?1:0.7}" stroke-width="${isCurrent?2:1}">
+          <title>${n[1]} — ${n[0]}.com</title>
+        </circle>
+        ${isCurrent ? `<circle cx="${x}" cy="${y}" r="${r+5}" fill="none" stroke="${COLOR[band]}" stroke-opacity="0.4" stroke-width="1"><animate attributeName="r" values="${r+5};${r+12};${r+5}" dur="2.4s" repeatCount="indefinite"/><animate attributeName="stroke-opacity" values="0.4;0;0.4" dur="2.4s" repeatCount="indefinite"/></circle>` : ''}
+      </g>`;
+    });
+  });
+  // append nodes after defs
+  svg.insertAdjacentHTML('beforeend', nodes);
+  svg.querySelectorAll('.mc-node').forEach(n => {
+    n.addEventListener('mouseenter', () => n.querySelector('circle').setAttribute('fill-opacity', '1'));
+    n.addEventListener('mouseleave', e => {
+      const isCurrent = n.dataset.slug === SLUG;
+      n.querySelector('circle').setAttribute('fill-opacity', isCurrent ? '1' : '0.55');
+    });
+    n.addEventListener('click', () => window.open('https://' + n.dataset.slug + '.com', '_blank'));
+  });
+})();
+</script>
+
+<script>
+const state = { q:'', facet:'all', page:1, pages:1, total:0, loading:false, exhausted:false };
+const LABELS = {"all":"All"};
+
+function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c])); }
+// Image-URL allowlist: only DW Shopify CDN + designerwallcoverings.com (defends against XSS via crafted products.json)
+function safeImg(u) { return /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(u || '') ? u : '/hero-bg.jpg'; }
+function cardHTML(p) {
+  const eager = state.page === 1;
+  return '<img loading="' + (eager ? 'eager' : 'lazy') + '"' + (eager ? ' fetchpriority="high"' : '') + ' src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+    + '<div class="overlay">'
+    + '<div class="pat">' + escAttr(p.pattern_name || p.title) + '</div>'
+    + '<div class="ven">' + escAttr((p.vendor || '').replace(/-/g, ' ')) + '</div>'
+    + '<div class="actions">'
+    + '<button class="sample-btn" onclick="event.stopPropagation();dwmOpen(\'Sample\',' + JSON.stringify({sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}).replace(/"/g,'&quot;') + ')">Sample</button>'
+    + '</div></div>';
+}
+
+async function loadFacets() {
+  let f;
+  try {
+    const r = await fetch('/api/facets');
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    f = await r.json();
+  } catch (e) { console.error('loadFacets failed:', e); return; }
+  const el = document.getElementById('facets');
+  for (const [k, v] of Object.entries(f.aesthetics).sort((a,b) => b[1] - a[1])) {
+    const b = document.createElement('button');
+    b.className = 'chip'; b.dataset.facet = k;
+    b.innerHTML = (LABELS[k] || k) + ' <span style="opacity:.55;font-weight:500;margin-left:4px">' + v + '</span>';
+    el.appendChild(b);
+  }
+  el.addEventListener('click', e => {
+    if (e.target.tagName !== 'BUTTON') return;
+    document.querySelectorAll('#facets button').forEach(b => b.classList.remove('active'));
+    e.target.classList.add('active');
+    state.facet = e.target.dataset.facet;
+    resetGrid();
+  });
+  document.getElementById('totalCount').textContent = f.total;
+  document.getElementById('footerStat').textContent = f.total + ' patterns · live archive';
+  // Footer aesthetic links
+  const footerEl = document.getElementById('footerFacets');
+  for (const [k] of Object.entries(f.aesthetics)) {
+    const b = document.createElement('button');
+    b.textContent = LABELS[k] || k;
+    b.onclick = () => { state.facet = k; resetGrid(); document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === k)); document.getElementById('shop').scrollIntoView({behavior:'smooth'}); };
+    footerEl.appendChild(b);
+  }
+}
+
+function resetGrid() {
+  state.page = 1; state.exhausted = false;
+  document.getElementById('grid').innerHTML = '';
+  document.getElementById('loading').textContent = 'Loading…';
+  loadGridPage();
+}
+
+async function loadGridPage() {
+  if (state.loading || state.exhausted) return;
+  state.loading = true;
+  const params = new URLSearchParams({ page:state.page, limit:24 });
+  if (state.q) params.set('q', state.q);
+  if (state.facet !== 'all') params.set('aesthetic', state.facet);
+  let data;
+  try {
+    const r = await fetch('/api/products?' + params);
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    data = await r.json();
+  } catch (e) {
+    console.error('loadGridPage failed:', e);
+    document.getElementById('loading').textContent = '— offline — refresh to retry —';
+    state.loading = false;
+    return;
+  }
+  state.total = data.total; state.pages = data.pages;
+
+  if (state.page === 1) {
+    document.getElementById('statLine').textContent = data.total + ' patterns · ' + (state.facet === 'all' ? 'all aesthetics' : (LABELS[state.facet] || state.facet)) + (state.q ? ' · matching "' + state.q + '"' : '');
+  }
+  const grid = document.getElementById('grid');
+  for (const p of data.items) {
+    const a = document.createElement('a');
+    a.className = 'card'; a.href = '#'; a.onclick = (e) => { e.preventDefault(); dwmOpen('Sample',{sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}); };
+    a.innerHTML = cardHTML(p);
+    grid.appendChild(a);
+  }
+  if (state.page >= state.pages || data.items.length === 0) {
+    state.exhausted = true;
+    document.getElementById('loading').textContent = state.total > 0 ? '— end of archive · ' + state.total + ' patterns —' : '';
+  } else state.page++;
+  state.loading = false;
+}
+
+const io = new IntersectionObserver(es => { for (const e of es) if (e.isIntersecting) loadGridPage(); }, { rootMargin:'600px 0px' });
+io.observe(document.getElementById('sentinel'));
+
+document.getElementById('searchInput').addEventListener('input', e => {
+  state.q = e.target.value.trim();
+  clearTimeout(window._t);
+  window._t = setTimeout(resetGrid, 220);
+});
+
+// Density slider
+const slider = document.getElementById('densitySlider');
+const dlabel = document.getElementById('densityLabel');
+function setDensity(n) {
+  document.documentElement.style.setProperty('--cols', n);
+  dlabel.textContent = n + ' cols';
+  try { localStorage.setItem('hosp_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('hosp_theme_density') || '6');
+if (savedDensity >= 4 && savedDensity <= 12) { slider.value = savedDensity; setDensity(savedDensity); }
+
+// Theme toggle
+const tb = document.getElementById('theme-toggle');
+function setTheme(t){ document.documentElement.dataset.theme = t; try { localStorage.setItem('hosp_theme', t); } catch(e){} tb.textContent = t === 'dark' ? '☾' : '☀'; }
+setTheme(document.documentElement.dataset.theme || 'light');
+tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
+
+loadFacets();
+loadGridPage();
+</script>
+<!-- ============================================================
+     DW UNIVERSAL CONTACT MODULE — fashion-house UX
+     Inject before
+ </body> in every DW-family sister site.
+     Self-contained: CSS + 4 modals + JS submission handlers.
+     Uses host site's CSS vars (--bg, --fg, --gold, --rule).
+     ============================================================ -->
+<style>
+  /* === MODAL BASE === */
+  .dwm{position:fixed;inset:0;background:rgba(0,0,0,0.78);display:none;align-items:center;justify-content:center;z-index:9999;padding:24px;overflow-y:auto}
+  .dwm.open{display:flex}
+  .dwm-box{background:var(--bg);border:1px solid var(--rule);max-width:520px;width:100%;padding:36px 32px;position:relative;max-height:90vh;overflow-y:auto;animation:dwm-in 0.25s ease}
+  @keyframes dwm-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
+  .dwm-box h3{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-weight:400;font-size:32px;line-height:1.05;margin-bottom:6px;color:var(--fg);letter-spacing:-0.01em}
+  .dwm-box .sub{color:var(--muted);font-size:12px;letter-spacing:0.16em;text-transform:uppercase;margin-bottom:24px;font-weight:500}
+  .dwm-close{position:absolute;top:18px;right:18px;background:transparent;border:0;color:var(--muted);font-size:24px;cursor:pointer;width:32px;height:32px;line-height:1;padding:0}
+  .dwm-close:hover{color:var(--gold)}
+  .dwm-preview{display:flex;gap:14px;align-items:center;padding:12px;background:var(--bg-soft);margin-bottom:18px}
+  .dwm-preview img{width:64px;height:64px;object-fit:cover}
+  .dwm-preview .pn{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-size:15px;line-height:1.2;color:var(--fg)}
+  .dwm-preview .pc{font-size:10px;letter-spacing:0.14em;text-transform:uppercase;color:var(--muted);margin-top:4px}
+  .dwm-field{margin-bottom:14px}
+  .dwm-field label{display:block;font-size:10px;letter-spacing:0.18em;text-transform:uppercase;color:var(--muted);margin-bottom:6px;font-weight:500}
+  .dwm-field input,.dwm-field textarea,.dwm-field select{width:100%;border:0;border-bottom:1px solid var(--rule);background:transparent;padding:8px 4px;font-size:14px;font-family:inherit;color:var(--fg);outline:none;transition:border-color 0.2s}
+  .dwm-field input:focus,.dwm-field textarea:focus{border-bottom-color:var(--gold)}
+  .dwm-field textarea{min-height:60px;resize:vertical}
+  .dwm-submit{background:transparent;color:var(--muted, #c9b89e);border:1px solid var(--muted, #c9b89e);padding:14px 28px;font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:700;cursor:pointer;width:100%;margin-top:8px;transition:background 0.15s, color 0.15s}
+  .dwm-submit:hover{background:var(--muted, #c9b89e);color:var(--bg, #000)}
+  
+  .dwm-submit:disabled{opacity:0.5;cursor:default}
+  .dwm-status{margin-top:14px;font-size:11px;letter-spacing:0.16em;text-transform:uppercase;text-align:center;display:none}
+  .dwm-status.ok{color:var(--sage);display:block}
+  .dwm-status.err{color:#e08070;display:block}
+  /* contact-options */
+  .dwm-options{display:flex;flex-direction:column;gap:10px}
+  .dwm-option{display:flex;align-items:center;gap:14px;padding:18px 20px;background:transparent;border:1px solid var(--rule);color:var(--fg);font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:600;cursor:pointer;text-decoration:none;transition:all 0.2s;text-align:left;width:100%}
+  .dwm-option:hover{border-color:var(--gold);color:var(--gold)}
+  .dwm-option svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.5;flex-shrink:0}
+  .dwm-option .lbl{flex:1;display:block}
+  .dwm-option .val{display:block;font-size:10px;letter-spacing:0.14em;text-transform:none;font-weight:500;opacity:0.65;margin-top:4px}
+
+/* graphics-loop pass 11: Ideas rails */
+#ideas { padding: 56px 24px 24px; max-width:1600px; margin:0 auto }
+#ideas .rail-block { margin-bottom:48px }
+#ideas .rail-eyebrow { font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:var(--muted, #888); margin-bottom:8px }
+#ideas .rail-title { font-size:clamp(22px,2.6vw,32px); font-weight:500; letter-spacing:-0.01em; margin:0 0 18px; color:var(--ink,#fff) }
+#ideas .rail { display:flex; gap:14px; overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:8px; scrollbar-width:none }
+#ideas .rail::-webkit-scrollbar { display:none }
+#ideas .rail-card { flex:0 0 240px; scroll-snap-align:start; cursor:pointer; transition:transform 0.2s }
+#ideas .rail-card:hover { transform:translateY(-3px) }
+#ideas .rail-card img { width:100%; aspect-ratio:1; object-fit:cover; display:block; background:var(--card,#222) }
+#ideas .rail-card .rc-title { font-size:13px; font-weight:500; color:var(--paper,#fff); padding:8px 0 2px; line-height:1.3 }
+#ideas .rail-card .rc-meta  { font-size:11px; color:var(--muted,#888); letter-spacing:0.06em }
+@media (max-width:720px) { #ideas .rail-card { flex:0 0 160px } }
+</style>
+
+<!-- Contact options modal -->
+<div class="dwm" id="dwmContact" onclick="if(event.target===this)dwmClose('Contact')">
+  <div class="dwm-box" style="max-width:440px">
+    <button class="dwm-close" onclick="dwmClose('Contact')" aria-label="Close">×</button>
+    <h3>Contact</h3>
+    <p class="sub" id="dwmContactSub">Three ways to reach us</p>
+    <div class="dwm-options">
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Inquiry')">
+        <svg viewBox="0 0 24 24"><path d="M4 4h16v12H7l-3 3z"/></svg>
+        <span class="lbl">Send an Inquiry<span class="val">Project name · scope · all the details</span></span>
+      </button>
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Sample')">
+        <svg viewBox="0 0 24 24"><rect x="4" y="6" width="16" height="14"/><path d="M4 10h16M9 6V3h6v3"/></svg>
+        <span class="lbl">Request a Sample<span class="val">Memo sample · ships free · 3–5 business days</span></span>
+      </button>
+      <a class="dwm-option" id="dwmContactEmailLink" href="mailto:info@hospitalitywallpaper.com">
+        <svg viewBox="0 0 24 24"><path d="M3 6h18v12H3z"/><path d="M3 6l9 7 9-7"/></svg>
+        <span class="lbl">Email Us<span class="val" id="dwmContactEmailLabel">info@hospitalitywallpaper.com</span></span>
+      </a>
+    </div>
+  </div>
+</div>
+
+<!-- Inquiry modal -->
+<div class="dwm" id="dwmInquiry" onclick="if(event.target===this)dwmClose('Inquiry')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Inquiry')" aria-label="Close">×</button>
+    <h3>Project Inquiry</h3>
+    <p class="sub">We'll respond within one business day</p>
+    <form id="dwmInquiryForm" onsubmit="return dwmSubmit(event,'inquiry')">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Phone</label><input type="tel" name="phone"></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Project Name</label><input type="text" name="projectName" required></div>
+      <div class="dwm-field"><label>Project Scope</label><textarea name="projectScope" placeholder="Square footage · room count · timeline" required></textarea></div>
+      <div class="dwm-field"><label>Additional Information</label><textarea name="message" placeholder="Patterns of interest, finish preferences, budget"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Inquiry</button>
+      <div class="dwm-status" id="dwmInquiryStatus"></div>
+    </form>
+  </div>
+</div>
+
+<!-- Sample-request modal -->
+<div class="dwm" id="dwmSample" onclick="if(event.target===this)dwmClose('Sample')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Sample')" aria-label="Close">×</button>
+    <h3>Request a Sample</h3>
+    <p class="sub">Memo sample · ships free · 3–5 business days</p>
+    <div class="dwm-preview" id="dwmSamplePreview" style="display:none">
+      <img id="dwmSampleImg" src="" alt="">
+      <div><div class="pn" id="dwmSampleName"></div><div class="pc" id="dwmSampleSku"></div></div>
+    </div>
+    <form id="dwmSampleForm" onsubmit="return dwmSubmit(event,'sample')">
+      <input type="hidden" name="sku" id="dwmSampleSkuInput">
+      <input type="hidden" name="title" id="dwmSampleTitleInput">
+      <input type="hidden" name="image_url" id="dwmSampleImageInput">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Shipping Address</label><input type="text" name="address" placeholder="Street" required></div>
+      <div class="dwm-field" style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:8px">
+        <input type="text" name="city" placeholder="City" required>
+        <input type="text" name="state" placeholder="State" required>
+        <input type="text" name="zip" placeholder="ZIP" required>
+      </div>
+      <div class="dwm-field"><label>Notes (optional)</label><textarea name="message" placeholder="Project, sq.ft., timing"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Sample Request</button>
+      <div class="dwm-status" id="dwmSampleStatus"></div>
+    </form>
+  </div>
+</div>
+
+<script>
+  // Universal modal control
+  function dwmOpen(name, opts){
+    document.getElementById('dwm' + name).classList.add('open');
+    document.body.style.overflow = 'hidden';
+    if (name === 'Sample' && opts) {
+      document.getElementById('dwmSamplePreview').style.display = 'flex';
+      document.getElementById('dwmSampleImg').src = opts.image_url || '';
+      document.getElementById('dwmSampleName').textContent = opts.title || '';
+      document.getElementById('dwmSampleSku').textContent = opts.sku || '';
+      document.getElementById('dwmSampleSkuInput').value = opts.sku || '';
+      document.getElementById('dwmSampleTitleInput').value = opts.title || '';
+      document.getElementById('dwmSampleImageInput').value = opts.image_url || '';
+    } else if (name === 'Sample') {
+      document.getElementById('dwmSamplePreview').style.display = 'none';
+      document.getElementById('dwmSampleSkuInput').value = '';
+      document.getElementById('dwmSampleTitleInput').value = '';
+      document.getElementById('dwmSampleImageInput').value = '';
+    }
+  }
+  function dwmClose(name){ document.getElementById('dwm'+name).classList.remove('open'); document.body.style.overflow=''; }
+
+  // Universal form submit — POSTs to /api/send-{kind}
+  async function dwmSubmit(e, kind) {
+    e.preventDefault();
+    const form = e.target;
+    const data = Object.fromEntries(new FormData(form).entries());
+    const btn = form.querySelector('.dwm-submit');
+    const status = form.querySelector('.dwm-status');
+    btn.disabled = true; const orig = btn.textContent; btn.textContent = 'Sending…';
+    status.className = 'dwm-status';
+    try {
+      const r = await fetch('/api/send-' + kind, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(data) });
+      if (!r.ok) throw new Error('HTTP '+r.status);
+      const j = await r.json();
+      status.textContent = kind === 'sample' ? 'Sample request sent — ships within 3–5 business days' : 'Inquiry sent — we respond within 1 business day';
+      status.className = 'dwm-status ok';
+      btn.textContent = 'Sent ✓';
+      setTimeout(() => { dwmClose(kind === 'sample' ? 'Sample' : 'Inquiry'); btn.disabled = false; btn.textContent = orig; status.className = 'dwm-status'; form.reset(); }, 2800);
+    } catch (err) {
+      status.textContent = 'Send failed — please email info@designerwallcoverings.com';
+      status.className = 'dwm-status err';
+      btn.disabled = false; btn.textContent = orig;
+    }
+    return false;
+  }
+
+  // Wire up "Memo samples ship free" badge in hero to open sample modal directly
+  document.querySelectorAll('.hero .badge, [data-open-sample]').forEach(el => {
+    el.style.cursor = 'pointer';
+    el.addEventListener('click', () => dwmOpen('Sample'));
+  });
+
+  // Wire nav "Trade" link to inquiry modal
+  document.querySelectorAll('nav a[href*="designerwallcoverings.com"]').forEach(a => {
+    a.removeAttribute('target');
+    a.removeAttribute('href');
+    a.style.cursor = 'pointer';
+    a.addEventListener('click', e => { e.preventDefault(); dwmOpen('Contact'); });
+  });
+
+  // Override product card clicks — open Sample modal pre-filled instead of redirecting to DW
+  document.addEventListener('click', e => {
+    const card = e.target.closest('.card, .rail-card');
+    if (!card) return;
+    if (card.tagName === 'A' && (card.getAttribute('href') || '').startsWith('/sample/')) {
+      e.preventDefault();
+      const img = card.querySelector('img');
+      const pat = card.querySelector('.pat');
+      const sku = card.getAttribute('href').replace('/sample/', '');
+      dwmOpen('Sample', {
+        sku,
+        title: pat ? pat.textContent.trim() : '',
+        image_url: img ? img.src : ''
+      });
+    }
+  }, true);
+// DW STANDARD: hero pulls from products.json[0].image_url so dw-collections-viewer
+// drag-drop / hero-pin updates the live front page on next deploy.
+// Always upgrades to the largest Shopify variant (strips _NxN size suffix) so
+// the full-page hero stays sharp.
+// DW STANDARD: hero rotates through top-20 NEWEST products on each visit
+// (novasuede.com pattern). Fetches /api/products?limit=100, sorts by created_at desc,
+// takes the freshest 20, picks one per visit via localStorage counter.
+// Falls back to static /hero-bg.jpg on any error.
+(async function rotateHero() {
+  try {
+    const r = await fetch('/api/products?limit=100');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || [])
+      .filter(p => p && p.image_url && /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(p.image_url))
+      .sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')))
+      .slice(0, 20);
+    if (!items.length) return;
+    let visits = 0;
+    try {
+      visits = parseInt(localStorage.getItem('hero_visits') || '0', 10) || 0;
+      localStorage.setItem('hero_visits', String(visits + 1));
+    } catch(e) {}
+    const pick = items[visits % items.length];
+    // Strip _NxN size suffix to get the largest CDN variant
+    const url = pick.image_url.replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+    const bg = document.getElementById('heroBg') || document.getElementById('cinemaBg');
+    if (bg) bg.style.backgroundImage = "url('" + url + "')";
+  } catch (e) {}
+})();
+
+
+// DW STANDARD sort-select wire-up (added by fleet patcher)
+(function(){
+  const sortSel = document.getElementById('sortSelect');
+  if (!sortSel) return;
+  const KEY = location.hostname.replace(/\./g, '_') + '_sort';
+  const saved = localStorage.getItem(KEY);
+  if (saved) { try { sortSel.value = saved; } catch(e){} }
+  if (typeof state !== 'undefined') state.sort = sortSel.value;
+  sortSel.addEventListener('change', e => {
+    const v = e.target.value;
+    try { localStorage.setItem(KEY, v); } catch(e){}
+    if (typeof state !== 'undefined') state.sort = v;
+    if (typeof resetGrid === 'function') resetGrid();
+    else location.reload();
+  });
+})();
+
+// graphics-loop pass 11: hydrate Ideas rails from /api/products
+(async function hydrateIdeas() {
+  try {
+    const r = await fetch('/api/products?limit=80');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || []).filter(p => p && p.image_url);
+    if (!items.length) return;
+    const sorted = [...items].sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')));
+    const newest = sorted.slice(0, 12);
+    // Curated = deterministic offset slice (every 5th item starting at idx 3) for variety
+    const curated = items.filter((_, i) => i % 5 === 3).slice(0, 12);
+    function card(p) {
+      const url = (p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+      return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle || p.sku) + '">' +
+        '<img src="' + url + '" alt="' + (p.title || '').replace(/"/g, '&quot;') + '" loading="lazy">' +
+        '<div class="rc-title">' + ((p.title || '').split('|')[0] || '').trim() + '</div>' +
+        '<div class="rc-meta">' + (p.vendor || '') + '</div>' +
+      '</a>';
+    }
+    const r1 = document.getElementById('railNewest');
+    const r2 = document.getElementById('railCurated');
+    if (r1) r1.innerHTML = newest.map(card).join('');
+    if (r2) r2.innerHTML = curated.map(card).join('');
+  } catch(e) {}
+})();
+</script>
+
+<script src="/dw-fleet-nav.js" defer></script>
+</body>
+</html>
diff --git a/public/index.html.bak.ns-canonical b/public/index.html.bak.ns-canonical
new file mode 100644
index 0000000..cda4dc1
--- /dev/null
+++ b/public/index.html.bak.ns-canonical
@@ -0,0 +1,979 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+
+<meta charset="utf-8">
+<!-- Google tag (gtag.js) -->
+<script async src="https://www.googletagmanager.com/gtag/js?id=G-XM0936TL4N"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-XM0936TL4N');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Heritage Atelier — hospitality, the British way.</title>
+<meta name="description" content="Heritage Atelier is a curated atelier dedicated entirely to hospitality. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#FFF">
+<link rel="canonical" href="https://hospitalitywallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600&family=Inter:wght@300;400;500&display=swap" rel="stylesheet">
+<link rel="preload" as="image" href="/hero-bg.jpg" fetchpriority="high">
+<script type="application/ld+json">
+{
+  "@context": "https://schema.org",
+  "@type": "Organization",
+  "name": "Heritage Atelier",
+  "url": "https://hospitalitywallpaper.com/",
+  "email": "info@hospitalitywallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #FFF;
+  --paper: #000;
+  --muted: #8B7866;
+  --line: #A47C5A;
+  --accent: #A47C5A;
+  --bg-soft: #A47C5A;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #000;
+  --paper: #FFF;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #A47C5A;
+  --bg-soft: #2a1f15;
+}
+* { margin:0; padding:0; box-sizing:border-box }
+html { scroll-behavior:smooth }
+body { font-family:'Inter', sans-serif; color:var(--paper); -webkit-font-smoothing:antialiased; background:var(--bg); min-height:100vh; overflow-x:hidden }
+/* DW-FASHION-TEMPLATE-OVERRIDE */
+.section-title .accent, .footer-brand, .center-mark, h1, h2, h3 { font-family:'Cormorant Garamond', Georgia, serif !important; font-weight:500 !important;  }
+
+/* ===== Auto-hide header ===== */
+header { position:fixed; top:0; left:0; right:0; display:flex; justify-content:space-between; align-items:center; padding:22px 32px; z-index:100; background:rgba(0,0,0,0.55); backdrop-filter:blur(10px); border-bottom:1px solid var(--line); transition:transform .3s }
+.h-link { display:flex; align-items:center; gap:10px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); text-decoration:none; cursor:pointer; background:transparent; border:0 }
+.h-link:hover { opacity:0.7 }
+.h-icon { width:18px; height:18px; stroke:currentColor; fill:none; stroke-width:1.5 }
+
+/* ===== Cinema hero ===== */
+.cinema { position:relative; height:100vh; width:100%; overflow:hidden }
+.cinema-bg { position:absolute; inset:0; background-size:cover; background-position:center; background-image:url('/hero-bg.jpg') }
+.cinema-bg::after { content:""; position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.75) 100%) }
+.corner-mark { position:absolute; top:24px; left:32px; font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:#fff; text-shadow:0 1px 3px rgba(0,0,0,0.55), 0 0 1px rgba(0,0,0,0.4); z-index:5 }
+.corner-mark::before { content:"◆ "; margin-right:6px }
+.center-mark { position:absolute; top:clamp(80px,12vh,140px); left:50%; transform:translateX(-50%); font-size:clamp(28px,4vw,56px); font-weight:500; letter-spacing:0.18em; text-transform:uppercase; text-align:center; color:#fff; text-shadow:0 2px 8px rgba(0,0,0,0.65), 0 0 1px rgba(0,0,0,0.5); z-index:5 }
+.center-mark .tm { font-size:14px; vertical-align:super; opacity:0.7; margin-left:0.2em }
+.center-mark .sub { display:block; font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400; font-size:0.4em; letter-spacing:0.04em; text-transform:none; margin-top:14px; opacity:0.85 }
+.meta-line { position:absolute; bottom:32px; left:32px; font-size:10px; letter-spacing:0.28em; text-transform:uppercase; font-weight:700; color:#fff; z-index:5; opacity:0.85 }
+.meta-line .num { font-size:12px; display:block; margin-top:4px; letter-spacing:0.05em }
+.enter { position:absolute; bottom:32px; right:32px; display:flex; align-items:center; gap:14px; font-size:11px; letter-spacing:0.36em; text-transform:uppercase; font-weight:700; color:#fff; text-decoration:none; padding-bottom:6px; border-bottom:1px solid #fff; transition:gap 0.25s; z-index:5 }
+.enter:hover { gap:22px }
+.enter svg { width:24px; height:12px }
+
+/* ===== Section ===== */
+.section { padding:96px 32px }
+.section-header { display:flex; justify-content:space-between; align-items:flex-end; flex-wrap:wrap; gap:24px; margin-bottom:32px; padding-bottom:24px; border-bottom:1px solid var(--line) }
+.section-title { font-size:clamp(36px,5vw,64px); font-weight:300; letter-spacing:-0.02em; line-height:1 }
+.section-title .accent { color: var(--accent); font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400 }
+.section-eyebrow { font-size:10px; letter-spacing:0.4em; text-transform:uppercase; font-weight:700; color:var(--muted); margin-bottom:16px }
+.section-meta { font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:600; color:var(--muted); text-align:right; line-height:1.6 }
+
+/* ===== Filter bar ===== */
+.filters { display:flex; gap:8px; align-items:center; margin-bottom:18px; flex-wrap:wrap }
+.chip { padding:8px 16px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); background:transparent; border:1px solid var(--line); cursor:pointer; transition:all 0.2s; font-family:inherit }
+.chip:hover { border-color:var(--paper) }
+.chip.active { background:var(--paper); color:var(--bg); border-color:var(--paper) }
+.search { flex:0 1 280px; margin-left:auto; display:flex; align-items:center; gap:10px; border-bottom:1px solid var(--line); padding:6px 0 }
+.search input { flex:1; background:transparent; border:0; color:var(--paper); font-family:inherit; font-size:13px; outline:none; letter-spacing:0.04em }
+.search input::placeholder { color:var(--muted) }
+.search svg { width:16px; height:16px; stroke:var(--muted); fill:none; stroke-width:1.5 }
+
+/* ===== Grid-density slider ===== */
+.density { display:flex; align-items:center; gap:14px; padding:6px 0; margin-bottom:24px }
+.density label { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--muted) }
+.density input[type=range] { flex:1; max-width:240px; -webkit-appearance:none; appearance:none; height:1px; background:var(--line); outline:none }
+.density input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50% }
+.density input[type=range]::-moz-range-thumb { width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50%; border:0 }
+.density .ct { font-size:11px; color:var(--muted); letter-spacing:0.18em; text-transform:uppercase; font-weight:600; min-width:80px }
+
+/* ===== Stats line ===== */
+.stat-line { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:600; color:var(--muted); margin-bottom:24px }
+
+/* ===== Product grid (novasuede pattern: flush grid + slide-up overlay) ===== */
+.grid { display:grid; grid-template-columns:repeat(var(--cols), 1fr); gap:0 }
+.card { position:relative; aspect-ratio:1/1.15; cursor:pointer; overflow:hidden; border:1px solid var(--bg); transition:transform 0.4s cubic-bezier(0.2,0.8,0.2,1); background:var(--bg-soft) }
+.card:hover { transform:scale(1.04); z-index:5 }
+.card img { width:100%; height:100%; object-fit:cover; display:block; transition:transform 0.4s ease }
+.card .overlay { position:absolute; left:0; right:0; bottom:0; padding:20px 16px 14px; background:linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.85) 100%); transform:translateY(48%); opacity:0.85; transition:transform 0.3s ease, opacity 0.3s ease }
+.card:hover .overlay { transform:translateY(0); opacity:1 }
+.card .pat { font-size:13px; font-weight:600; letter-spacing:0.02em; color:#fff; line-height:1.25; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
+.card .ven { font-size:9px; letter-spacing:0.18em; text-transform:uppercase; color:#fff; opacity:0.7; font-weight:500; margin-top:4px }
+.card .actions { margin-top:10px; display:flex; gap:6px }
+.card .sample-btn { flex:1; padding:7px 10px; background:#fff; color:#000; font-family:inherit; font-size:10px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; border:0; cursor:pointer; text-align:center; transition:all 0.2s }
+.card .sample-btn:hover { background:var(--accent); color:#fff }
+
+@media (max-width:1024px) { .grid { grid-template-columns:repeat(min(var(--cols), 4), 1fr) } }
+@media (max-width:720px) { .grid { grid-template-columns:repeat(2, 1fr) } .density { display:none } }
+
+.sentinel { height:1px }
+.loading { text-align:center; color:var(--muted); padding:32px; font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700 }
+
+/* ===== Footer ===== */
+footer { padding:64px 32px 32px; border-top:1px solid var(--line); margin-top:32px }
+.footer-grid { max-width:1400px; margin:0 auto; display:grid; grid-template-columns:2fr 1fr 1fr 1fr; gap:48px; margin-bottom:48px }
+.footer-brand { font-size:24px; font-weight:300; letter-spacing:0.32em; text-transform:uppercase; margin-bottom:12px }
+.footer-text { font-size:13px; line-height:1.6; color:var(--muted); max-width:380px }
+.footer-col h4 { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--paper); margin-bottom:18px }
+.footer-col a { display:block; font-size:13px; color:var(--muted); text-decoration:none; margin-bottom:8px; transition:color 0.2s; cursor:pointer; background:transparent; border:0; font-family:inherit; padding:0; text-align:left }
+.footer-col a:hover { color:var(--accent) }
+.footer-bottom { max-width:1400px; margin:0 auto; padding-top:24px; border-top:1px solid var(--line); display:flex; justify-content:space-between; flex-wrap:wrap; gap:16px; font-size:11px; letter-spacing:0.18em; text-transform:uppercase; color:var(--muted) }
+
+@media (max-width:720px) {
+  .corner-mark, .meta-line, .enter { font-size:10px }
+  .center-mark { font-size:24px; letter-spacing:0.12em; top:clamp(60px,9vh,90px) }
+  .section, footer { padding-left:20px; padding-right:20px }
+  .footer-grid { grid-template-columns:1fr; gap:32px }
+  .search { margin-left:0; flex:1 1 100% }
+}
+
+.theme-toggle { background:transparent; border:1px solid var(--line); width:32px; height:32px; cursor:pointer; color:var(--paper); display:inline-flex; align-items:center; justify-content:center; font-size:14px; line-height:1; transition:all .15s; padding:0 }
+.theme-toggle:hover { border-color:var(--accent); color:var(--accent) }
+
+/* ===== WCAG 2.4.7 — keyboard focus indicators ===== */
+/* Strictly :focus-visible so mouse clicks do NOT show the ring */
+a:focus-visible,
+button:focus-visible,
+input:focus-visible,
+select:focus-visible,
+textarea:focus-visible,
+[tabindex]:focus-visible {
+  outline: 2px solid var(--accent);
+  outline-offset: 2px;
+}
+</style>
+<script>
+(function(){ try { var t = localStorage.getItem('hosp_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://hospitalitywallpaper.com/">
+<meta property="og:title" content="Hospitality Wallpaper">
+<meta property="og:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta property="og:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Hospitality Wallpaper">
+<meta property="article:publisher" content="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:title" content="Hospitality Wallpaper">
+<meta name="twitter:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta name="twitter:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<!-- graphics-loop pass 13: footer + fb -->
+</head>
+<body>
+<style id="ns-header-modal-styles">
+        .ns-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; padding: 18px 36px; background: rgba(10,10,10,0.92) !important; backdrop-filter: blur(8px); border-bottom: 1px solid rgba(245,241,232,0.06); }
+        .ns-brand { display: inline-flex; align-items: center; gap: 14px; text-decoration: none; }
+        .ns-dot { width: 28px; height: 28px; border-radius: 50%; background: radial-gradient(circle at 35% 35%, #a98b5b 0%, #5d4c32 60%, #332a1b 100%); box-shadow: 0 0 0 1px rgba(245,241,232,0.10), 0 2px 12px rgba(180,90,60,0.30); flex-shrink: 0; }
+        .ns-name { font-family: -apple-system, "SF Pro Display", "Helvetica Neue", system-ui, sans-serif; font-size: 18px !important; font-weight: 300 !important; letter-spacing: 0.02em !important; color: #f5f1e8 !important; text-transform: none !important; margin: 0 !important; }
+        .ns-name sup { font-size: 0.55em; font-weight: 300; margin-left: 1px; }
+        .ns-nav { display: flex; gap: 32px; align-items: center; list-style: none; padding: 0; margin: 0; }
+        .ns-nav a, .ns-nav button { font-family: -apple-system, "SF Pro Text", system-ui, sans-serif; font-size: 15px !important; font-weight: 400 !important; color: #f5f1e8 !important; text-decoration: none !important; background: none !important; border: 0 !important; cursor: pointer; padding: 0 !important; transition: color 200ms; letter-spacing: 0 !important; text-transform: none !important; }
+        .ns-nav a:hover, .ns-nav button:hover { color: #ffffff !important; }
+        @media (max-width: 820px) { .ns-header { padding: 14px 18px; } .ns-nav { gap: 16px; } .ns-nav a, .ns-nav button { font-size: 13px !important; } }
+        @media (max-width: 760px) {
+          .ns-header { flex-wrap: wrap; }
+          .ns-nav { display: none !important; flex-basis: 100%; flex-direction: column; align-items: flex-start; gap: 6px; padding: 14px 0 4px; }
+          .ns-nav.open { display: flex !important; }
+          .ns-nav a, .ns-nav button { padding: 10px 0 !important; border-bottom: 1px solid rgba(245,241,232,0.08); width: 100%; text-align: left; }
+          .ns-nav a:nth-child(n+5), .ns-nav button:nth-child(n+5) { display: block !important; }
+          .ns-header .mobile-toggle { display: flex !important; }
+        }
+        @media (min-width: 761px) {
+          .ns-header .mobile-toggle { display: none !important; }
+        }
+        .ns-modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.78); z-index: 200; align-items: center; justify-content: center; padding: 24px; backdrop-filter: blur(6px); }
+        .ns-modal.show { display: flex; }
+        .ns-modal-card { max-width: 460px; width: 100%; background: #141414 !important; border: 1px solid rgba(245,241,232,0.14); border-radius: 6px; padding: 28px 30px 30px; position: relative; }
+        .ns-modal-card .close-x { position: absolute; top: 12px; right: 14px; width: 30px; height: 30px; background: none; border: 1px solid rgba(245,241,232,0.18); color: rgba(245,241,232,0.6) !important; border-radius: 50%; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; }
+        .ns-modal-card .close-x:hover { color: #ffffff !important; border-color: #ffffff; }
+        .ns-modal-card h3 { font-family: -apple-system, "SF Pro Display", system-ui; font-weight: 300 !important; font-size: 22px !important; margin: 0 0 6px !important; color: #f5f1e8 !important; }
+        .ns-modal-card .sub { color: rgba(245,241,232,0.65) !important; font-size: 13px; margin: 0 0 22px; }
+        .ns-actions { display: flex; flex-direction: column; gap: 10px; }
+        .ns-action { display: flex; align-items: center; gap: 14px; padding: 14px 16px; background: rgba(245,241,232,0.04) !important; border: 1px solid rgba(245,241,232,0.12) !important; color: #f5f1e8 !important; text-decoration: none !important; cursor: pointer; transition: all 200ms; font: inherit; text-align: left; }
+        .ns-action:hover { background: rgba(245,241,232,0.08) !important; border-color: #d4b683 !important; }
+        .ns-action .ico { width: 32px; height: 32px; border-radius: 50%; background: rgba(212,182,131,0.12); display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
+        .ns-action .txt { flex: 1; }
+        .ns-action .txt b { display: block; font-weight: 500; font-size: 14px; color: #f5f1e8 !important; }
+        .ns-action .txt span { font-size: 12px; color: rgba(245,241,232,0.55) !important; }
+
+        /* ─── FINAL CONTRAST PASS — kill remaining gold-solid + white-island defects ─── */
+        /* Replace all gold-fill accents with off-white (Gucci-aesthetic, no DW gold solids) */
+        .new-badge, .new-arrivals-pill,
+        .color-filter-btn.active,
+        .drapery-btn, .sample-btn-chip, .cb-cta {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        .new-badge:hover, .new-arrivals-pill:hover,
+        .color-filter-btn.active:hover,
+        .drapery-btn:hover, .sample-btn-chip:hover, .cb-cta:hover {
+          background: #fff !important;
+          color: #0a0a0a !important;
+        }
+        /* Gold accents stay only as edge color (links, glyphs) — not fills */
+        a { color: #d4b683; }
+        a:hover { color: #f5d97a; }
+        /* Authorized-dealer footer line — small caps tracked, muted ink, no gold pill */
+        .authorized, .authorized-dealer p {
+          background: transparent !important;
+          color: rgba(245,241,232,0.5) !important;
+          font-size: 10px !important;
+          letter-spacing: 0.22em !important;
+          text-transform: uppercase !important;
+          padding: 0 !important;
+          border: none !important;
+          margin-top: 14px !important;
+        }
+        /* Kill any straggler white bg in info-card / sample-related cards */
+        .info-card, .info-card-link, .care-highlight, .feature-card, .spec-item {
+          background-color: rgba(245,241,232,0.04) !important;
+          border-color: rgba(245,241,232,0.12) !important;
+        }
+        /* Ensure modal content stays readable — Steve's earlier sweep made it #141414 with white text */
+        .modal-content { background: #141414 !important; color: #f5f1e8 !important; }
+        .modal-content * { color: #f5f1e8 !important; }
+        .modal-content input, .modal-content textarea, .modal-content select {
+          background: rgba(245,241,232,0.05) !important;
+          color: #f5f1e8 !important;
+          border-color: rgba(245,241,232,0.2) !important;
+        }
+        .modal-content label { color: rgba(245,241,232,0.6) !important; }
+        /* Force the wide-tracked NOVASUEDE wordmark to stay white */
+        .ns-wordmark, .ns-wordmark sup { color: #f5f1e8 !important; }
+
+        /* ─── Modal-internal contrast (post-QA defects) ─── */
+        /* Backdrop covers full viewport */
+        .modal { width: 100vw !important; height: 100vh !important; left: 0 !important; top: 0 !important; background: rgba(0, 0, 0, 0.78) !important; backdrop-filter: blur(6px); }
+        /* Chip — flip from white-on-white island to dark card */
+        .request-chip {
+          background: rgba(245, 241, 232, 0.06) !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.18) !important;
+          border-radius: 4px !important;
+        }
+        .request-chip * { color: #f5f1e8 !important; }
+        .request-chip .chip-swatch {
+          /* swatch dot ALWAYS displays the inline-style hex from JS — fight any sweep */
+          border: 1px solid rgba(0, 0, 0, 0.4) !important;
+        }
+        /* + Add to request — hairline white-border on transparent (no gold) */
+        .add-to-request-btn {
+          background: transparent !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.6) !important;
+          border-radius: 0 !important;
+          padding: 12px 22px !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 400 !important;
+        }
+        .add-to-request-btn:hover {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        /* Hex caption visible */
+        .preview-hex, #colorPreviewHex {
+          display: block !important;
+          color: rgba(245, 241, 232, 0.55) !important;
+          font-family: ui-monospace, "SF Mono", Menlo, monospace !important;
+          font-size: 11px !important;
+          margin-top: 4px !important;
+          letter-spacing: 0.04em !important;
+          text-transform: lowercase !important;
+        }
+        /* Color preview name — stays single, prominent */
+        #colorPreviewName {
+          color: #f5f1e8 !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 500 !important;
+          display: block !important;
+          margin-top: 12px !important;
+        }
+
+        /* ─── Mobile hamburger nav (replaces the overflow at <760px) ─── */
+        @media (max-width: 760px) {
+          header .nav-container { flex-wrap: wrap; }
+          header nav { display: none; flex-basis: 100%; flex-direction: column; gap: 6px; padding: 16px 0 6px; }
+          header nav.open { display: flex; }
+          header nav a { padding: 10px 0; border-bottom: 1px solid rgba(245,241,232,0.1); }
+          header .mobile-toggle {
+            display: flex !important;
+            flex-direction: column;
+            gap: 5px;
+            background: transparent;
+            border: 0;
+            cursor: pointer;
+            padding: 8px;
+          }
+          header .mobile-toggle span {
+            width: 22px; height: 1.5px;
+            background: #f5f1e8;
+            display: block;
+          }
+        }
+        @media (min-width: 761px) {
+          header .mobile-toggle { display: none !important; }
+        }
+
+    </style>
+<style id="ns-gold-kill">
+    /* novasuede: kill gold-solid fills, off-white instead. Edge color stays gold. */
+    .new-badge, .new-arrivals-pill,
+    .color-filter-btn.active, .drapery-btn,
+    .sample-btn-chip, .cb-cta {
+      background: #f5f1e8 !important;
+      color: #0a0a0a !important;
+      border-color: #f5f1e8 !important;
+    }
+    .new-badge:hover, .new-arrivals-pill:hover,
+    .color-filter-btn.active:hover, .drapery-btn:hover,
+    .sample-btn-chip:hover, .cb-cta:hover {
+      background: #fff !important;
+      color: #0a0a0a !important;
+    }
+  </style>
+<header class="ns-header">
+        <a href="/" class="ns-brand" aria-label="Home">
+            <span class="ns-dot"></span>
+            <span class="ns-name">Heritage Atelier</span>
+        </a>
+        <nav class="ns-nav" id="nsPrimaryNav" aria-label="Primary">
+            <a href="/">Home</a>
+            <a href="/about">About</a>
+            <button type="button" onclick="nsContactOpen()">Contact</button>
+        </nav>
+        <button type="button" class="mobile-toggle" aria-label="Toggle menu" aria-controls="nsPrimaryNav" aria-expanded="false" onclick="nsToggleNav(this)">
+            <span></span><span></span><span></span>
+        </button>
+    </header>
+
+<div class="ns-modal" id="nsContactModal" role="dialog" aria-modal="true" aria-labelledby="nsContactTitle" onclick="if(event.target===this)nsContactClose()">
+        <div class="ns-modal-card">
+            <button type="button" class="close-x" onclick="nsContactClose()" aria-label="Close">×</button>
+            <h3 id="nsContactTitle">How can we help?</h3>
+            <p class="sub">Trade-account replies within one business day.</p>
+            <div class="ns-actions">
+                <a class="ns-action" href="#contact" onclick="nsContactClose()"><span class="ico">📋</span><div class="txt"><b>Get a Quote</b><span>Project specs → priced estimate</span></div></a>
+                <a class="ns-action" href="#contact" onclick="nsContactClose();openModal();"><span class="ico">📦</span><div class="txt"><b>Order a Sample</b><span>Free swatch to your shop</span></div></a>
+                <a class="ns-action" href="mailto:info@hospitalitywallpaper.com?subject=Heritage%20Atelier%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@hospitalitywallpaper.com</span></div></a>
+                <a class="ns-action" href="tel:888-373-4564"><span class="ico">📞</span><div class="txt"><b>Call Us</b><span>(888) 373-4564 · M–F, 9–5 PT</span></div></a>
+            </div>
+        </div>
+    </div>
+<script>
+  function nsContactOpen() { var m = document.getElementById('nsContactModal'); if (m) m.classList.add('show'); }
+  function nsContactClose() { var m = document.getElementById('nsContactModal'); if (m) m.classList.remove('show'); }
+  function nsToggleNav(btn) {
+    var nav = document.getElementById('nsPrimaryNav');
+    if (!nav) return;
+    var open = nav.classList.toggle('open');
+    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
+  }
+  document.addEventListener('keydown', function(e){ if (e.key === 'Escape') nsContactClose(); });
+</script>
+
+
+
+
+
+
+
+
+
+
+
+<header>
+  <button class="h-link" onclick="dwmOpen('Contact')" aria-label="Contact"><svg class="h-icon" viewBox="0 0 24 24"><path d="M3 7h18M3 12h18M3 17h18"/></svg><span>Contact</span></button>
+  <button class="theme-toggle" id="theme-toggle" aria-label="Theme toggle">☾</button>
+</header>
+
+<section class="cinema">
+  <div class="cinema-bg" id="heroBg"></div>
+  <div class="corner-mark">Trade-Grade</div>
+  <div class="center-mark">Hospitality Wallpaper</div>
+  <div class="meta-line">Hotel · Restaurant · Spa · Class A<span class="num" id="heroNum"></span></div>
+  <a class="enter" href="#shop">Enter <svg viewBox="0 0 24 12" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M0 6h22M16 1l6 5-6 5"/></svg></a>
+</section>
+
+
+<section class="section" id="ideas">
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">New this week</h2>
+    <div class="rail" id="railNewest"></div>
+  </div>
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">Curated picks</h2>
+    <div class="rail" id="railCurated"></div>
+  </div>
+</section>
+
+<section class="section" id="shop">
+  <div class="section-header">
+    <div>
+      <div class="section-eyebrow">The Collection</div>
+      <h2 class="section-title"><span class="accent" id="totalCount">—</span> Patterns.</h2>
+    </div>
+    <div class="section-meta">Hotel · Restaurant · Spa · Class A</div>
+  </div>
+
+  <div class="filters" id="facets">
+    <button class="chip active" data-facet="all">All</button>
+  </div>
+
+  <div class="density">
+    <label>Sort</label>
+    <select id="sortSelect" aria-label="Sort products" style="background:transparent;color:inherit;border:1px solid var(--line,rgba(255,255,255,.2));font:inherit;font-size:11px;letter-spacing:.10em;text-transform:uppercase;padding:4px 8px;cursor:pointer;outline:none;margin-right:14px">
+      <option value="newest">Newest</option>
+      <option value="color">Color</option>
+      <option value="style">Style</option>
+      <option value="sku">SKU A→Z</option>
+      <option value="title">Title A→Z</option>
+      <option value="price-asc">Price ↑</option>
+      <option value="price-desc">Price ↓</option>
+    </select>
+    <label>Grid</label>
+    <input type="range" id="densitySlider" min="4" max="12" step="1" value="6" aria-label="Grid columns">
+    <span class="ct" id="densityLabel">6 cols</span>
+    <div class="search">
+      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-5.5-5.5"/></svg>
+      <input type="text" id="searchInput" placeholder="Search by pattern, color…" autocomplete="off">
+    </div>
+  </div>
+
+  <div class="stat-line" id="statLine">Loading…</div>
+  <div class="grid" id="grid"></div>
+  <div class="loading" id="loading">Loading more…</div>
+  <div class="sentinel" id="sentinel"></div>
+</section>
+
+<footer>
+  <div class="footer-grid">
+    <div>
+      <div class="footer-brand">Heritage Atelier</div>
+      <p class="footer-text">Heritage Atelier — real samples ship free.</p>
+      <p class="footer-text" style="margin-top:14px;font-size:11px;letter-spacing:0.18em;text-transform:uppercase;font-weight:600;color:var(--paper);opacity:0.7"><a href="/about" style="color:inherit;text-decoration:none;border-bottom:1px solid var(--accent)">About →</a></p>
+    </div>
+    <div class="footer-col">
+      <h4>Aesthetic</h4>
+      <div id="footerFacets"></div>
+    </div>
+    <div class="footer-col">
+      <h4>Trade</h4>
+      <button onclick="dwmOpen('Inquiry')">Project Inquiry</button>
+      <button onclick="dwmOpen('Sample')">Request Sample</button>
+      <button onclick="dwmOpen('Contact')">Contact</button>
+    </div>
+  
+    <div class="footer-col">
+      <h4>Social</h4>
+      <a class="fb-link" href="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings" target="_blank" rel="noopener">Facebook</a>
+    </div>
+  </div>
+  <div class="footer-bottom">
+    <span>hospitalitywallpaper.com · Heritage Atelier</span>
+    <span><a href="mailto:info@hospitalitywallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@hospitalitywallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "hospitalitywallpaper";
+  const NICHES = [
+    ['silkwallpaper','Silk','mat'],['silkwallcoverings','Silk W/C','mat'],['linenwallpaper','Linen','mat'],
+    ['jutewallpaper','Jute','mat'],['raffiawallcoverings','Raffia W/C','mat'],['raffiawalls','Raffia Walls','mat'],
+    ['corkwallcovering','Cork','mat'],['fabricwallpaper','Fabric','mat'],['textilewallpaper','Textile','mat'],
+    ['metallicwallpaper','Metallic','mat'],['silverleafwallpaper','Silver Leaf','mat'],['vinylwallpaper','Vinyl','mat'],
+    ['micawallpaper','Mica','mat'],['madagascarwallpaper','Madagascar','mat'],['mylarwallpaper','Mylar','mat'],
+    ['suedewallpaper','Suede','mat'],
+    ['1800swallpaper','1800s','dec'],['1890swallpaper','1890s','dec'],['1900swallpaper','1900s','dec'],
+    ['1920swallpaper','1920s','dec'],['1930swallpaper','1930s','dec'],['1940swallpaper','1940s','dec'],
+    ['1950swallpaper','1950s','dec'],['1960swallpaper','1960s','dec'],['1970swallpaper','1970s','dec'],
+    ['1980swallpaper','1980s','dec'],['retrowalls','Retro','dec'],['wallpapersback','W. Back','dec'],
+    ['agedwallpaper','Aged','cra'],['handcraftedwallpaper','Handcrafted','cra'],['museumwallpaper','Museum','cra'],
+    ['restorationwallpaper','Restoration','cra'],['pastelwallpaper','Pastel','cra'],['glitterwalls','Glitter','cra'],
+    ['greenwallcoverings','Green','cra'],['naturalwallcoverings','Natural','cra'],['saloonwallpaper','Saloon','cra'],
+    ['contractwallpaper','Contract','use'],['hotelwallcoverings','Hotel','use'],['hospitalitywallpaper','Hospitality','use'],
+    ['healthcarewallpaper','Healthcare','use'],['restaurantwallpaper','Restaurant','use'],['architecturalwallcoverings','Architectural','use']
+  ];
+  const COLOR = { mat:'#c9b687', dec:'#b86a4a', cra:'#6b8e6f', use:'#4a6b8e' };
+  const W = 1080, H = 200, BANDS = ['mat','dec','cra','use'];
+  const groups = { mat:[], dec:[], cra:[], use:[] };
+  for (const n of NICHES) groups[n[2]].push(n);
+  const svg = document.getElementById('miniConst');
+  if (!svg) return;
+  const bandW = W / BANDS.length;
+  let nodes = '';
+  BANDS.forEach((band, bi) => {
+    const list = groups[band];
+    const cx = bi * bandW + bandW / 2;
+    list.forEach((n, i) => {
+      const t = list.length === 1 ? 0.5 : i / (list.length - 1);
+      // deterministic jitter per slug
+      let h = 0; for (let k = 0; k < n[0].length; k++) h = (h * 31 + n[0].charCodeAt(k)) | 0;
+      const jx = ((h & 0xff) / 255 - 0.5) * (bandW * 0.5);
+      const jy = (((h >> 8) & 0xff) / 255 - 0.5) * 6;  // tightened from 14 → 6 to prevent same-band collisions (16 mat nodes / 144px = 9px spacing)
+      const x = cx + jx, y = 28 + t * (H - 56) + jy;
+      const isCurrent = n[0] === SLUG;
+      const r = isCurrent ? 8 : 4;
+      const op = isCurrent ? 1 : 0.55;
+      nodes += `<g class="mc-node" data-slug="${n[0]}" data-label="${n[1]}" style="cursor:pointer">
+        <circle cx="${x}" cy="${y}" r="${r}" fill="url(#dna-${band})" fill-opacity="${op}" stroke="${COLOR[band]}" stroke-opacity="${isCurrent?1:0.7}" stroke-width="${isCurrent?2:1}">
+          <title>${n[1]} — ${n[0]}.com</title>
+        </circle>
+        ${isCurrent ? `<circle cx="${x}" cy="${y}" r="${r+5}" fill="none" stroke="${COLOR[band]}" stroke-opacity="0.4" stroke-width="1"><animate attributeName="r" values="${r+5};${r+12};${r+5}" dur="2.4s" repeatCount="indefinite"/><animate attributeName="stroke-opacity" values="0.4;0;0.4" dur="2.4s" repeatCount="indefinite"/></circle>` : ''}
+      </g>`;
+    });
+  });
+  // append nodes after defs
+  svg.insertAdjacentHTML('beforeend', nodes);
+  svg.querySelectorAll('.mc-node').forEach(n => {
+    n.addEventListener('mouseenter', () => n.querySelector('circle').setAttribute('fill-opacity', '1'));
+    n.addEventListener('mouseleave', e => {
+      const isCurrent = n.dataset.slug === SLUG;
+      n.querySelector('circle').setAttribute('fill-opacity', isCurrent ? '1' : '0.55');
+    });
+    n.addEventListener('click', () => window.open('https://' + n.dataset.slug + '.com', '_blank'));
+  });
+})();
+</script>
+
+<script>
+const state = { q:'', facet:'all', page:1, pages:1, total:0, loading:false, exhausted:false };
+const LABELS = {"all":"All"};
+
+function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c])); }
+// Image-URL allowlist: only DW Shopify CDN + designerwallcoverings.com (defends against XSS via crafted products.json)
+function safeImg(u) { return /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(u || '') ? u : '/hero-bg.jpg'; }
+function cardHTML(p) {
+  const eager = state.page === 1;
+  return '<img loading="' + (eager ? 'eager' : 'lazy') + '"' + (eager ? ' fetchpriority="high"' : '') + ' src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+    + '<div class="overlay">'
+    + '<div class="pat">' + escAttr(p.pattern_name || p.title) + '</div>'
+    + '<div class="ven">' + escAttr((p.vendor || '').replace(/-/g, ' ')) + '</div>'
+    + '<div class="actions">'
+    + '<button class="sample-btn" onclick="event.stopPropagation();dwmOpen(\'Sample\',' + JSON.stringify({sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}).replace(/"/g,'&quot;') + ')">Sample</button>'
+    + '</div></div>';
+}
+
+async function loadFacets() {
+  let f;
+  try {
+    const r = await fetch('/api/facets');
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    f = await r.json();
+  } catch (e) { console.error('loadFacets failed:', e); return; }
+  const el = document.getElementById('facets');
+  for (const [k, v] of Object.entries(f.aesthetics).sort((a,b) => b[1] - a[1])) {
+    const b = document.createElement('button');
+    b.className = 'chip'; b.dataset.facet = k;
+    b.innerHTML = (LABELS[k] || k) + ' <span style="opacity:.55;font-weight:500;margin-left:4px">' + v + '</span>';
+    el.appendChild(b);
+  }
+  el.addEventListener('click', e => {
+    if (e.target.tagName !== 'BUTTON') return;
+    document.querySelectorAll('#facets button').forEach(b => b.classList.remove('active'));
+    e.target.classList.add('active');
+    state.facet = e.target.dataset.facet;
+    resetGrid();
+  });
+  document.getElementById('totalCount').textContent = f.total;
+  document.getElementById('footerStat').textContent = f.total + ' patterns · live archive';
+  // Footer aesthetic links
+  const footerEl = document.getElementById('footerFacets');
+  for (const [k] of Object.entries(f.aesthetics)) {
+    const b = document.createElement('button');
+    b.textContent = LABELS[k] || k;
+    b.onclick = () => { state.facet = k; resetGrid(); document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === k)); document.getElementById('shop').scrollIntoView({behavior:'smooth'}); };
+    footerEl.appendChild(b);
+  }
+}
+
+function resetGrid() {
+  state.page = 1; state.exhausted = false;
+  document.getElementById('grid').innerHTML = '';
+  document.getElementById('loading').textContent = 'Loading…';
+  loadGridPage();
+}
+
+async function loadGridPage() {
+  if (state.loading || state.exhausted) return;
+  state.loading = true;
+  const params = new URLSearchParams({ page:state.page, limit:24 });
+  if (state.q) params.set('q', state.q);
+  if (state.facet !== 'all') params.set('aesthetic', state.facet);
+  let data;
+  try {
+    const r = await fetch('/api/products?' + params);
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    data = await r.json();
+  } catch (e) {
+    console.error('loadGridPage failed:', e);
+    document.getElementById('loading').textContent = '— offline — refresh to retry —';
+    state.loading = false;
+    return;
+  }
+  state.total = data.total; state.pages = data.pages;
+
+  if (state.page === 1) {
+    document.getElementById('statLine').textContent = data.total + ' patterns · ' + (state.facet === 'all' ? 'all aesthetics' : (LABELS[state.facet] || state.facet)) + (state.q ? ' · matching "' + state.q + '"' : '');
+  }
+  const grid = document.getElementById('grid');
+  for (const p of data.items) {
+    const a = document.createElement('a');
+    a.className = 'card'; a.href = '#'; a.onclick = (e) => { e.preventDefault(); dwmOpen('Sample',{sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}); };
+    a.innerHTML = cardHTML(p);
+    grid.appendChild(a);
+  }
+  if (state.page >= state.pages || data.items.length === 0) {
+    state.exhausted = true;
+    document.getElementById('loading').textContent = state.total > 0 ? '— end of archive · ' + state.total + ' patterns —' : '';
+  } else state.page++;
+  state.loading = false;
+}
+
+const io = new IntersectionObserver(es => { for (const e of es) if (e.isIntersecting) loadGridPage(); }, { rootMargin:'600px 0px' });
+io.observe(document.getElementById('sentinel'));
+
+document.getElementById('searchInput').addEventListener('input', e => {
+  state.q = e.target.value.trim();
+  clearTimeout(window._t);
+  window._t = setTimeout(resetGrid, 220);
+});
+
+// Density slider
+const slider = document.getElementById('densitySlider');
+const dlabel = document.getElementById('densityLabel');
+function setDensity(n) {
+  document.documentElement.style.setProperty('--cols', n);
+  dlabel.textContent = n + ' cols';
+  try { localStorage.setItem('hosp_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('hosp_theme_density') || '6');
+if (savedDensity >= 4 && savedDensity <= 12) { slider.value = savedDensity; setDensity(savedDensity); }
+
+// Theme toggle
+const tb = document.getElementById('theme-toggle');
+function setTheme(t){ document.documentElement.dataset.theme = t; try { localStorage.setItem('hosp_theme', t); } catch(e){} tb.textContent = t === 'dark' ? '☾' : '☀'; }
+setTheme(document.documentElement.dataset.theme || 'light');
+tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
+
+loadFacets();
+loadGridPage();
+</script>
+<!-- ============================================================
+     DW UNIVERSAL CONTACT MODULE — fashion-house UX
+     Inject before
+ </body> in every DW-family sister site.
+     Self-contained: CSS + 4 modals + JS submission handlers.
+     Uses host site's CSS vars (--bg, --fg, --gold, --rule).
+     ============================================================ -->
+<style>
+  /* === MODAL BASE === */
+  .dwm{position:fixed;inset:0;background:rgba(0,0,0,0.78);display:none;align-items:center;justify-content:center;z-index:9999;padding:24px;overflow-y:auto}
+  .dwm.open{display:flex}
+  .dwm-box{background:var(--bg);border:1px solid var(--rule);max-width:520px;width:100%;padding:36px 32px;position:relative;max-height:90vh;overflow-y:auto;animation:dwm-in 0.25s ease}
+  @keyframes dwm-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
+  .dwm-box h3{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-weight:400;font-size:32px;line-height:1.05;margin-bottom:6px;color:var(--fg);letter-spacing:-0.01em}
+  .dwm-box .sub{color:var(--muted);font-size:12px;letter-spacing:0.16em;text-transform:uppercase;margin-bottom:24px;font-weight:500}
+  .dwm-close{position:absolute;top:18px;right:18px;background:transparent;border:0;color:var(--muted);font-size:24px;cursor:pointer;width:32px;height:32px;line-height:1;padding:0}
+  .dwm-close:hover{color:var(--gold)}
+  .dwm-preview{display:flex;gap:14px;align-items:center;padding:12px;background:var(--bg-soft);margin-bottom:18px}
+  .dwm-preview img{width:64px;height:64px;object-fit:cover}
+  .dwm-preview .pn{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-size:15px;line-height:1.2;color:var(--fg)}
+  .dwm-preview .pc{font-size:10px;letter-spacing:0.14em;text-transform:uppercase;color:var(--muted);margin-top:4px}
+  .dwm-field{margin-bottom:14px}
+  .dwm-field label{display:block;font-size:10px;letter-spacing:0.18em;text-transform:uppercase;color:var(--muted);margin-bottom:6px;font-weight:500}
+  .dwm-field input,.dwm-field textarea,.dwm-field select{width:100%;border:0;border-bottom:1px solid var(--rule);background:transparent;padding:8px 4px;font-size:14px;font-family:inherit;color:var(--fg);outline:none;transition:border-color 0.2s}
+  .dwm-field input:focus,.dwm-field textarea:focus{border-bottom-color:var(--gold)}
+  .dwm-field textarea{min-height:60px;resize:vertical}
+  .dwm-submit{background:transparent;color:var(--muted, #c9b89e);border:1px solid var(--muted, #c9b89e);padding:14px 28px;font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:700;cursor:pointer;width:100%;margin-top:8px;transition:background 0.15s, color 0.15s}
+  .dwm-submit:hover{background:var(--muted, #c9b89e);color:var(--bg, #000)}
+  
+  .dwm-submit:disabled{opacity:0.5;cursor:default}
+  .dwm-status{margin-top:14px;font-size:11px;letter-spacing:0.16em;text-transform:uppercase;text-align:center;display:none}
+  .dwm-status.ok{color:var(--sage);display:block}
+  .dwm-status.err{color:#e08070;display:block}
+  /* contact-options */
+  .dwm-options{display:flex;flex-direction:column;gap:10px}
+  .dwm-option{display:flex;align-items:center;gap:14px;padding:18px 20px;background:transparent;border:1px solid var(--rule);color:var(--fg);font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:600;cursor:pointer;text-decoration:none;transition:all 0.2s;text-align:left;width:100%}
+  .dwm-option:hover{border-color:var(--gold);color:var(--gold)}
+  .dwm-option svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.5;flex-shrink:0}
+  .dwm-option .lbl{flex:1;display:block}
+  .dwm-option .val{display:block;font-size:10px;letter-spacing:0.14em;text-transform:none;font-weight:500;opacity:0.65;margin-top:4px}
+
+/* graphics-loop pass 11: Ideas rails */
+#ideas { padding: 56px 24px 24px; max-width:1600px; margin:0 auto }
+#ideas .rail-block { margin-bottom:48px }
+#ideas .rail-eyebrow { font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:var(--muted, #888); margin-bottom:8px }
+#ideas .rail-title { font-size:clamp(22px,2.6vw,32px); font-weight:500; letter-spacing:-0.01em; margin:0 0 18px; color:var(--ink,#fff) }
+#ideas .rail { display:flex; gap:14px; overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:8px; scrollbar-width:none }
+#ideas .rail::-webkit-scrollbar { display:none }
+#ideas .rail-card { flex:0 0 240px; scroll-snap-align:start; cursor:pointer; transition:transform 0.2s }
+#ideas .rail-card:hover { transform:translateY(-3px) }
+#ideas .rail-card img { width:100%; aspect-ratio:1; object-fit:cover; display:block; background:var(--card,#222) }
+#ideas .rail-card .rc-title { font-size:13px; font-weight:500; color:var(--paper,#fff); padding:8px 0 2px; line-height:1.3 }
+#ideas .rail-card .rc-meta  { font-size:11px; color:var(--muted,#888); letter-spacing:0.06em }
+@media (max-width:720px) { #ideas .rail-card { flex:0 0 160px } }
+</style>
+
+<!-- Contact options modal -->
+<div class="dwm" id="dwmContact" onclick="if(event.target===this)dwmClose('Contact')">
+  <div class="dwm-box" style="max-width:440px">
+    <button class="dwm-close" onclick="dwmClose('Contact')" aria-label="Close">×</button>
+    <h3>Contact</h3>
+    <p class="sub" id="dwmContactSub">Three ways to reach us</p>
+    <div class="dwm-options">
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Inquiry')">
+        <svg viewBox="0 0 24 24"><path d="M4 4h16v12H7l-3 3z"/></svg>
+        <span class="lbl">Send an Inquiry<span class="val">Project name · scope · all the details</span></span>
+      </button>
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Sample')">
+        <svg viewBox="0 0 24 24"><rect x="4" y="6" width="16" height="14"/><path d="M4 10h16M9 6V3h6v3"/></svg>
+        <span class="lbl">Request a Sample<span class="val">Memo sample · ships free · 3–5 business days</span></span>
+      </button>
+      <a class="dwm-option" id="dwmContactEmailLink" href="mailto:info@hospitalitywallpaper.com">
+        <svg viewBox="0 0 24 24"><path d="M3 6h18v12H3z"/><path d="M3 6l9 7 9-7"/></svg>
+        <span class="lbl">Email Us<span class="val" id="dwmContactEmailLabel">info@hospitalitywallpaper.com</span></span>
+      </a>
+    </div>
+  </div>
+</div>
+
+<!-- Inquiry modal -->
+<div class="dwm" id="dwmInquiry" onclick="if(event.target===this)dwmClose('Inquiry')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Inquiry')" aria-label="Close">×</button>
+    <h3>Project Inquiry</h3>
+    <p class="sub">We'll respond within one business day</p>
+    <form id="dwmInquiryForm" onsubmit="return dwmSubmit(event,'inquiry')">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Phone</label><input type="tel" name="phone"></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Project Name</label><input type="text" name="projectName" required></div>
+      <div class="dwm-field"><label>Project Scope</label><textarea name="projectScope" placeholder="Square footage · room count · timeline" required></textarea></div>
+      <div class="dwm-field"><label>Additional Information</label><textarea name="message" placeholder="Patterns of interest, finish preferences, budget"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Inquiry</button>
+      <div class="dwm-status" id="dwmInquiryStatus"></div>
+    </form>
+  </div>
+</div>
+
+<!-- Sample-request modal -->
+<div class="dwm" id="dwmSample" onclick="if(event.target===this)dwmClose('Sample')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Sample')" aria-label="Close">×</button>
+    <h3>Request a Sample</h3>
+    <p class="sub">Memo sample · ships free · 3–5 business days</p>
+    <div class="dwm-preview" id="dwmSamplePreview" style="display:none">
+      <img id="dwmSampleImg" src="" alt="">
+      <div><div class="pn" id="dwmSampleName"></div><div class="pc" id="dwmSampleSku"></div></div>
+    </div>
+    <form id="dwmSampleForm" onsubmit="return dwmSubmit(event,'sample')">
+      <input type="hidden" name="sku" id="dwmSampleSkuInput">
+      <input type="hidden" name="title" id="dwmSampleTitleInput">
+      <input type="hidden" name="image_url" id="dwmSampleImageInput">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Shipping Address</label><input type="text" name="address" placeholder="Street" required></div>
+      <div class="dwm-field" style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:8px">
+        <input type="text" name="city" placeholder="City" required>
+        <input type="text" name="state" placeholder="State" required>
+        <input type="text" name="zip" placeholder="ZIP" required>
+      </div>
+      <div class="dwm-field"><label>Notes (optional)</label><textarea name="message" placeholder="Project, sq.ft., timing"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Sample Request</button>
+      <div class="dwm-status" id="dwmSampleStatus"></div>
+    </form>
+  </div>
+</div>
+
+<script>
+  // Universal modal control
+  function dwmOpen(name, opts){
+    document.getElementById('dwm' + name).classList.add('open');
+    document.body.style.overflow = 'hidden';
+    try { if (typeof gtag === 'function') gtag('event', 'modal_open', { modal_name: name, sku: (opts && opts.sku) || '' }); } catch(_){}
+    if (name === 'Sample' && opts) {
+      document.getElementById('dwmSamplePreview').style.display = 'flex';
+      document.getElementById('dwmSampleImg').src = opts.image_url || '';
+      document.getElementById('dwmSampleName').textContent = opts.title || '';
+      document.getElementById('dwmSampleSku').textContent = opts.sku || '';
+      document.getElementById('dwmSampleSkuInput').value = opts.sku || '';
+      document.getElementById('dwmSampleTitleInput').value = opts.title || '';
+      document.getElementById('dwmSampleImageInput').value = opts.image_url || '';
+    } else if (name === 'Sample') {
+      document.getElementById('dwmSamplePreview').style.display = 'none';
+      document.getElementById('dwmSampleSkuInput').value = '';
+      document.getElementById('dwmSampleTitleInput').value = '';
+      document.getElementById('dwmSampleImageInput').value = '';
+    }
+  }
+  function dwmClose(name){ document.getElementById('dwm'+name).classList.remove('open'); document.body.style.overflow=''; }
+
+  // Universal form submit — POSTs to /api/send-{kind}
+  async function dwmSubmit(e, kind) {
+    e.preventDefault();
+    const form = e.target;
+    const data = Object.fromEntries(new FormData(form).entries());
+    const btn = form.querySelector('.dwm-submit');
+    const status = form.querySelector('.dwm-status');
+    btn.disabled = true; const orig = btn.textContent; btn.textContent = 'Sending…';
+    status.className = 'dwm-status';
+    try {
+      const r = await fetch('/api/send-' + kind, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(data) });
+      if (!r.ok) throw new Error('HTTP '+r.status);
+      const j = await r.json();
+      try {
+        if (typeof gtag === 'function') {
+          if (kind === 'sample') gtag('event', 'memo_request', { sku: data.sku || '', title: data.title || '' });
+          else gtag('event', 'lead', { form_type: kind });
+        }
+      } catch(_){}
+      status.textContent = kind === 'sample' ? 'Sample request sent — ships within 3–5 business days' : 'Inquiry sent — we respond within 1 business day';
+      status.className = 'dwm-status ok';
+      btn.textContent = 'Sent ✓';
+      setTimeout(() => { dwmClose(kind === 'sample' ? 'Sample' : 'Inquiry'); btn.disabled = false; btn.textContent = orig; status.className = 'dwm-status'; form.reset(); }, 2800);
+    } catch (err) {
+      status.textContent = 'Send failed — please email info@designerwallcoverings.com';
+      status.className = 'dwm-status err';
+      btn.disabled = false; btn.textContent = orig;
+    }
+    return false;
+  }
+
+  // Wire up "Memo samples ship free" badge in hero to open sample modal directly
+  document.querySelectorAll('.hero .badge, [data-open-sample]').forEach(el => {
+    el.style.cursor = 'pointer';
+    el.addEventListener('click', () => dwmOpen('Sample'));
+  });
+
+  // Wire nav "Trade" link to inquiry modal
+  document.querySelectorAll('nav a[href*="designerwallcoverings.com"]').forEach(a => {
+    a.removeAttribute('target');
+    a.removeAttribute('href');
+    a.style.cursor = 'pointer';
+    a.addEventListener('click', e => { e.preventDefault(); dwmOpen('Contact'); });
+  });
+
+  // Override product card clicks — open Sample modal pre-filled instead of redirecting to DW
+  document.addEventListener('click', e => {
+    const card = e.target.closest('.card, .rail-card');
+    if (!card) return;
+    if (card.tagName === 'A' && (card.getAttribute('href') || '').startsWith('/sample/')) {
+      e.preventDefault();
+      const img = card.querySelector('img');
+      const pat = card.querySelector('.pat');
+      const sku = card.getAttribute('href').replace('/sample/', '');
+      dwmOpen('Sample', {
+        sku,
+        title: pat ? pat.textContent.trim() : '',
+        image_url: img ? img.src : ''
+      });
+    }
+  }, true);
+// DW STANDARD: hero pulls from products.json[0].image_url so dw-collections-viewer
+// drag-drop / hero-pin updates the live front page on next deploy.
+// Always upgrades to the largest Shopify variant (strips _NxN size suffix) so
+// the full-page hero stays sharp.
+// DW STANDARD: hero rotates through top-20 NEWEST products on each visit
+// (novasuede.com pattern). Fetches /api/products?limit=100, sorts by created_at desc,
+// takes the freshest 20, picks one per visit via localStorage counter.
+// Falls back to static /hero-bg.jpg on any error.
+(async function rotateHero() {
+  try {
+    const r = await fetch('/api/products?limit=100');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || [])
+      .filter(p => p && p.image_url && /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(p.image_url))
+      .sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')))
+      .slice(0, 20);
+    if (!items.length) return;
+    let visits = 0;
+    try {
+      visits = parseInt(localStorage.getItem('hero_visits') || '0', 10) || 0;
+      localStorage.setItem('hero_visits', String(visits + 1));
+    } catch(e) {}
+    const pick = items[visits % items.length];
+    // Strip _NxN size suffix to get the largest CDN variant
+    const url = pick.image_url.replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+    const bg = document.getElementById('heroBg') || document.getElementById('cinemaBg');
+    if (bg) bg.style.backgroundImage = "url('" + url + "')";
+  } catch (e) {}
+})();
+
+
+// DW STANDARD sort-select wire-up (added by fleet patcher)
+(function(){
+  const sortSel = document.getElementById('sortSelect');
+  if (!sortSel) return;
+  const KEY = location.hostname.replace(/\./g, '_') + '_sort';
+  const saved = localStorage.getItem(KEY);
+  if (saved) { try { sortSel.value = saved; } catch(e){} }
+  if (typeof state !== 'undefined') state.sort = sortSel.value;
+  sortSel.addEventListener('change', e => {
+    const v = e.target.value;
+    try { localStorage.setItem(KEY, v); } catch(e){}
+    if (typeof state !== 'undefined') state.sort = v;
+    if (typeof resetGrid === 'function') resetGrid();
+    else location.reload();
+  });
+})();
+
+// graphics-loop pass 11: hydrate Ideas rails from /api/products
+(async function hydrateIdeas() {
+  try {
+    const r = await fetch('/api/products?limit=80');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || []).filter(p => p && p.image_url);
+    if (!items.length) return;
+    const sorted = [...items].sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')));
+    const newest = sorted.slice(0, 12);
+    // Curated = deterministic offset slice (every 5th item starting at idx 3) for variety
+    const curated = items.filter((_, i) => i % 5 === 3).slice(0, 12);
+    function card(p) {
+      const url = (p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+      return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle || p.sku) + '">' +
+        '<img src="' + url + '" alt="' + (p.title || '').replace(/"/g, '&quot;') + '" loading="lazy">' +
+        '<div class="rc-title">' + ((p.title || '').split('|')[0] || '').trim() + '</div>' +
+        '<div class="rc-meta">' + (p.vendor || '') + '</div>' +
+      '</a>';
+    }
+    const r1 = document.getElementById('railNewest');
+    const r2 = document.getElementById('railCurated');
+    if (r1) r1.innerHTML = newest.map(card).join('');
+    if (r2) r2.innerHTML = curated.map(card).join('');
+  } catch(e) {}
+})();
+</script>
+
+<script src="/dw-fleet-nav.js" defer></script>
+</body>
+</html>
diff --git a/public/index.html.bak.nspropagate.1778203385100 b/public/index.html.bak.nspropagate.1778203385100
new file mode 100644
index 0000000..20ef31f
--- /dev/null
+++ b/public/index.html.bak.nspropagate.1778203385100
@@ -0,0 +1,947 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<!-- Google tag (gtag.js) -->
+<script async src="https://www.googletagmanager.com/gtag/js?id=G-XM0936TL4N"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-XM0936TL4N');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Heritage Atelier — hospitality, the British way.</title>
+<meta name="description" content="Heritage Atelier is a curated atelier dedicated entirely to hospitality. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#FFF">
+<link rel="canonical" href="https://hospitalitywallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600&family=Inter:wght@300;400;500&display=swap" rel="stylesheet">
+<link rel="preload" as="image" href="/hero-bg.jpg" fetchpriority="high">
+<script type="application/ld+json">
+{
+  "@context": "https://schema.org",
+  "@type": "Organization",
+  "name": "Heritage Atelier",
+  "url": "https://hospitalitywallpaper.com/",
+  "email": "info@hospitalitywallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #FFF;
+  --paper: #000;
+  --muted: #8B7866;
+  --line: #A47C5A;
+  --accent: #A47C5A;
+  --bg-soft: #A47C5A;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #000;
+  --paper: #FFF;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #A47C5A;
+  --bg-soft: #2a1f15;
+}
+* { margin:0; padding:0; box-sizing:border-box }
+html { scroll-behavior:smooth }
+body { font-family:'Inter', sans-serif; color:var(--paper); -webkit-font-smoothing:antialiased; background:var(--bg); min-height:100vh; overflow-x:hidden }
+/* DW-FASHION-TEMPLATE-OVERRIDE */
+.section-title .accent, .footer-brand, .center-mark, h1, h2, h3 { font-family:'Cormorant Garamond', Georgia, serif !important; font-weight:500 !important;  }
+
+/* ===== Auto-hide header ===== */
+header { position:fixed; top:0; left:0; right:0; display:flex; justify-content:space-between; align-items:center; padding:22px 32px; z-index:100; background:rgba(0,0,0,0.55); backdrop-filter:blur(10px); border-bottom:1px solid var(--line); transition:transform .3s }
+.h-link { display:flex; align-items:center; gap:10px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); text-decoration:none; cursor:pointer; background:transparent; border:0 }
+.h-link:hover { opacity:0.7 }
+.h-icon { width:18px; height:18px; stroke:currentColor; fill:none; stroke-width:1.5 }
+
+/* ===== Cinema hero ===== */
+.cinema { position:relative; height:100vh; width:100%; overflow:hidden }
+.cinema-bg { position:absolute; inset:0; background-size:cover; background-position:center; background-image:url('/hero-bg.jpg') }
+.cinema-bg::after { content:""; position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.75) 100%) }
+.corner-mark { position:absolute; top:24px; left:32px; font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:#fff; text-shadow:0 1px 3px rgba(0,0,0,0.55), 0 0 1px rgba(0,0,0,0.4); z-index:5 }
+.corner-mark::before { content:"◆ "; margin-right:6px }
+.center-mark { position:absolute; top:clamp(80px,12vh,140px); left:50%; transform:translateX(-50%); font-size:clamp(28px,4vw,56px); font-weight:500; letter-spacing:0.18em; text-transform:uppercase; text-align:center; color:#fff; text-shadow:0 2px 8px rgba(0,0,0,0.65), 0 0 1px rgba(0,0,0,0.5); z-index:5 }
+.center-mark .tm { font-size:14px; vertical-align:super; opacity:0.7; margin-left:0.2em }
+.center-mark .sub { display:block; font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400; font-size:0.4em; letter-spacing:0.04em; text-transform:none; margin-top:14px; opacity:0.85 }
+.meta-line { position:absolute; bottom:32px; left:32px; font-size:10px; letter-spacing:0.28em; text-transform:uppercase; font-weight:700; color:#fff; z-index:5; opacity:0.85 }
+.meta-line .num { font-size:12px; display:block; margin-top:4px; letter-spacing:0.05em }
+.enter { position:absolute; bottom:32px; right:32px; display:flex; align-items:center; gap:14px; font-size:11px; letter-spacing:0.36em; text-transform:uppercase; font-weight:700; color:#fff; text-decoration:none; padding-bottom:6px; border-bottom:1px solid #fff; transition:gap 0.25s; z-index:5 }
+.enter:hover { gap:22px }
+.enter svg { width:24px; height:12px }
+
+/* ===== Section ===== */
+.section { padding:96px 32px }
+.section-header { display:flex; justify-content:space-between; align-items:flex-end; flex-wrap:wrap; gap:24px; margin-bottom:32px; padding-bottom:24px; border-bottom:1px solid var(--line) }
+.section-title { font-size:clamp(36px,5vw,64px); font-weight:300; letter-spacing:-0.02em; line-height:1 }
+.section-title .accent { color: var(--accent); font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400 }
+.section-eyebrow { font-size:10px; letter-spacing:0.4em; text-transform:uppercase; font-weight:700; color:var(--muted); margin-bottom:16px }
+.section-meta { font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:600; color:var(--muted); text-align:right; line-height:1.6 }
+
+/* ===== Filter bar ===== */
+.filters { display:flex; gap:8px; align-items:center; margin-bottom:18px; flex-wrap:wrap }
+.chip { padding:8px 16px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); background:transparent; border:1px solid var(--line); cursor:pointer; transition:all 0.2s; font-family:inherit }
+.chip:hover { border-color:var(--paper) }
+.chip.active { background:var(--paper); color:var(--bg); border-color:var(--paper) }
+.search { flex:0 1 280px; margin-left:auto; display:flex; align-items:center; gap:10px; border-bottom:1px solid var(--line); padding:6px 0 }
+.search input { flex:1; background:transparent; border:0; color:var(--paper); font-family:inherit; font-size:13px; outline:none; letter-spacing:0.04em }
+.search input::placeholder { color:var(--muted) }
+.search svg { width:16px; height:16px; stroke:var(--muted); fill:none; stroke-width:1.5 }
+
+/* ===== Grid-density slider ===== */
+.density { display:flex; align-items:center; gap:14px; padding:6px 0; margin-bottom:24px }
+.density label { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--muted) }
+.density input[type=range] { flex:1; max-width:240px; -webkit-appearance:none; appearance:none; height:1px; background:var(--line); outline:none }
+.density input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50% }
+.density input[type=range]::-moz-range-thumb { width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50%; border:0 }
+.density .ct { font-size:11px; color:var(--muted); letter-spacing:0.18em; text-transform:uppercase; font-weight:600; min-width:80px }
+
+/* ===== Stats line ===== */
+.stat-line { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:600; color:var(--muted); margin-bottom:24px }
+
+/* ===== Product grid (novasuede pattern: flush grid + slide-up overlay) ===== */
+.grid { display:grid; grid-template-columns:repeat(var(--cols), 1fr); gap:0 }
+.card { position:relative; aspect-ratio:1/1.15; cursor:pointer; overflow:hidden; border:1px solid var(--bg); transition:transform 0.4s cubic-bezier(0.2,0.8,0.2,1); background:var(--bg-soft) }
+.card:hover { transform:scale(1.04); z-index:5 }
+.card img { width:100%; height:100%; object-fit:cover; display:block; transition:transform 0.4s ease }
+.card .overlay { position:absolute; left:0; right:0; bottom:0; padding:20px 16px 14px; background:linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.85) 100%); transform:translateY(48%); opacity:0.85; transition:transform 0.3s ease, opacity 0.3s ease }
+.card:hover .overlay { transform:translateY(0); opacity:1 }
+.card .pat { font-size:13px; font-weight:600; letter-spacing:0.02em; color:#fff; line-height:1.25; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
+.card .ven { font-size:9px; letter-spacing:0.18em; text-transform:uppercase; color:#fff; opacity:0.7; font-weight:500; margin-top:4px }
+.card .actions { margin-top:10px; display:flex; gap:6px }
+.card .sample-btn { flex:1; padding:7px 10px; background:#fff; color:#000; font-family:inherit; font-size:10px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; border:0; cursor:pointer; text-align:center; transition:all 0.2s }
+.card .sample-btn:hover { background:var(--accent); color:#fff }
+
+@media (max-width:1024px) { .grid { grid-template-columns:repeat(min(var(--cols), 4), 1fr) } }
+@media (max-width:720px) { .grid { grid-template-columns:repeat(2, 1fr) } .density { display:none } }
+
+.sentinel { height:1px }
+.loading { text-align:center; color:var(--muted); padding:32px; font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700 }
+
+/* ===== Footer ===== */
+footer { padding:64px 32px 32px; border-top:1px solid var(--line); margin-top:32px }
+.footer-grid { max-width:1400px; margin:0 auto; display:grid; grid-template-columns:2fr 1fr 1fr 1fr; gap:48px; margin-bottom:48px }
+.footer-brand { font-size:24px; font-weight:300; letter-spacing:0.32em; text-transform:uppercase; margin-bottom:12px }
+.footer-text { font-size:13px; line-height:1.6; color:var(--muted); max-width:380px }
+.footer-col h4 { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--paper); margin-bottom:18px }
+.footer-col a { display:block; font-size:13px; color:var(--muted); text-decoration:none; margin-bottom:8px; transition:color 0.2s; cursor:pointer; background:transparent; border:0; font-family:inherit; padding:0; text-align:left }
+.footer-col a:hover { color:var(--accent) }
+.footer-bottom { max-width:1400px; margin:0 auto; padding-top:24px; border-top:1px solid var(--line); display:flex; justify-content:space-between; flex-wrap:wrap; gap:16px; font-size:11px; letter-spacing:0.18em; text-transform:uppercase; color:var(--muted) }
+
+@media (max-width:720px) {
+  .corner-mark, .meta-line, .enter { font-size:10px }
+  .center-mark { font-size:24px; letter-spacing:0.12em; top:clamp(60px,9vh,90px) }
+  .section, footer { padding-left:20px; padding-right:20px }
+  .footer-grid { grid-template-columns:1fr; gap:32px }
+  .search { margin-left:0; flex:1 1 100% }
+}
+
+.theme-toggle { background:transparent; border:1px solid var(--line); width:32px; height:32px; cursor:pointer; color:var(--paper); display:inline-flex; align-items:center; justify-content:center; font-size:14px; line-height:1; transition:all .15s; padding:0 }
+.theme-toggle:hover { border-color:var(--accent); color:var(--accent) }
+
+/* ===== WCAG 2.4.7 — keyboard focus indicators ===== */
+/* Strictly :focus-visible so mouse clicks do NOT show the ring */
+a:focus-visible,
+button:focus-visible,
+input:focus-visible,
+select:focus-visible,
+textarea:focus-visible,
+[tabindex]:focus-visible {
+  outline: 2px solid var(--accent);
+  outline-offset: 2px;
+}
+</style>
+<script>
+(function(){ try { var t = localStorage.getItem('hosp_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://hospitalitywallpaper.com/">
+<meta property="og:title" content="Hospitality Wallpaper">
+<meta property="og:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta property="og:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Hospitality Wallpaper">
+<meta property="article:publisher" content="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:title" content="Hospitality Wallpaper">
+<meta name="twitter:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta name="twitter:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<!-- graphics-loop pass 13: footer + fb -->
+</head>
+<body>
+<style id="ns-header-modal-styles">
+        .ns-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; padding: 18px 36px; background: rgba(10,10,10,0.92) !important; backdrop-filter: blur(8px); border-bottom: 1px solid rgba(245,241,232,0.06); }
+        .ns-brand { display: inline-flex; align-items: center; gap: 14px; text-decoration: none; }
+        .ns-dot { width: 28px; height: 28px; border-radius: 50%; background: radial-gradient(circle at 35% 35%, #a98b5b 0%, #5d4c32 60%, #332a1b 100%); box-shadow: 0 0 0 1px rgba(245,241,232,0.10), 0 2px 12px rgba(180,90,60,0.30); flex-shrink: 0; }
+        .ns-name { font-family: -apple-system, "SF Pro Display", "Helvetica Neue", system-ui, sans-serif; font-size: 18px !important; font-weight: 300 !important; letter-spacing: 0.02em !important; color: #f5f1e8 !important; text-transform: none !important; margin: 0 !important; }
+        .ns-name sup { font-size: 0.55em; font-weight: 300; margin-left: 1px; }
+        .ns-nav { display: flex; gap: 32px; align-items: center; list-style: none; padding: 0; margin: 0; }
+        .ns-nav a, .ns-nav button { font-family: -apple-system, "SF Pro Text", system-ui, sans-serif; font-size: 15px !important; font-weight: 400 !important; color: #f5f1e8 !important; text-decoration: none !important; background: none !important; border: 0 !important; cursor: pointer; padding: 0 !important; transition: color 200ms; letter-spacing: 0 !important; text-transform: none !important; }
+        .ns-nav a:hover, .ns-nav button:hover { color: #ffffff !important; }
+        @media (max-width: 820px) { .ns-header { padding: 14px 18px; } .ns-nav { gap: 16px; } .ns-nav a, .ns-nav button { font-size: 13px !important; } }
+        @media (max-width: 760px) {
+          .ns-header { flex-wrap: wrap; }
+          .ns-nav { display: none !important; flex-basis: 100%; flex-direction: column; align-items: flex-start; gap: 6px; padding: 14px 0 4px; }
+          .ns-nav.open { display: flex !important; }
+          .ns-nav a, .ns-nav button { padding: 10px 0 !important; border-bottom: 1px solid rgba(245,241,232,0.08); width: 100%; text-align: left; }
+          .ns-nav a:nth-child(n+5), .ns-nav button:nth-child(n+5) { display: block !important; }
+          .ns-header .mobile-toggle { display: flex !important; }
+        }
+        @media (min-width: 761px) {
+          .ns-header .mobile-toggle { display: none !important; }
+        }
+        .ns-modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.78); z-index: 200; align-items: center; justify-content: center; padding: 24px; backdrop-filter: blur(6px); }
+        .ns-modal.show { display: flex; }
+        .ns-modal-card { max-width: 460px; width: 100%; background: #141414 !important; border: 1px solid rgba(245,241,232,0.14); border-radius: 6px; padding: 28px 30px 30px; position: relative; }
+        .ns-modal-card .close-x { position: absolute; top: 12px; right: 14px; width: 30px; height: 30px; background: none; border: 1px solid rgba(245,241,232,0.18); color: rgba(245,241,232,0.6) !important; border-radius: 50%; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; }
+        .ns-modal-card .close-x:hover { color: #ffffff !important; border-color: #ffffff; }
+        .ns-modal-card h3 { font-family: -apple-system, "SF Pro Display", system-ui; font-weight: 300 !important; font-size: 22px !important; margin: 0 0 6px !important; color: #f5f1e8 !important; }
+        .ns-modal-card .sub { color: rgba(245,241,232,0.65) !important; font-size: 13px; margin: 0 0 22px; }
+        .ns-actions { display: flex; flex-direction: column; gap: 10px; }
+        .ns-action { display: flex; align-items: center; gap: 14px; padding: 14px 16px; background: rgba(245,241,232,0.04) !important; border: 1px solid rgba(245,241,232,0.12) !important; color: #f5f1e8 !important; text-decoration: none !important; cursor: pointer; transition: all 200ms; font: inherit; text-align: left; }
+        .ns-action:hover { background: rgba(245,241,232,0.08) !important; border-color: #d4b683 !important; }
+        .ns-action .ico { width: 32px; height: 32px; border-radius: 50%; background: rgba(212,182,131,0.12); display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
+        .ns-action .txt { flex: 1; }
+        .ns-action .txt b { display: block; font-weight: 500; font-size: 14px; color: #f5f1e8 !important; }
+        .ns-action .txt span { font-size: 12px; color: rgba(245,241,232,0.55) !important; }
+
+        /* ─── FINAL CONTRAST PASS — kill remaining gold-solid + white-island defects ─── */
+        /* Replace all gold-fill accents with off-white (Gucci-aesthetic, no DW gold solids) */
+        .new-badge, .new-arrivals-pill,
+        .color-filter-btn.active,
+        .drapery-btn, .sample-btn-chip, .cb-cta {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        .new-badge:hover, .new-arrivals-pill:hover,
+        .color-filter-btn.active:hover,
+        .drapery-btn:hover, .sample-btn-chip:hover, .cb-cta:hover {
+          background: #fff !important;
+          color: #0a0a0a !important;
+        }
+        /* Gold accents stay only as edge color (links, glyphs) — not fills */
+        a { color: #d4b683; }
+        a:hover { color: #f5d97a; }
+        /* Authorized-dealer footer line — small caps tracked, muted ink, no gold pill */
+        .authorized, .authorized-dealer p {
+          background: transparent !important;
+          color: rgba(245,241,232,0.5) !important;
+          font-size: 10px !important;
+          letter-spacing: 0.22em !important;
+          text-transform: uppercase !important;
+          padding: 0 !important;
+          border: none !important;
+          margin-top: 14px !important;
+        }
+        /* Kill any straggler white bg in info-card / sample-related cards */
+        .info-card, .info-card-link, .care-highlight, .feature-card, .spec-item {
+          background-color: rgba(245,241,232,0.04) !important;
+          border-color: rgba(245,241,232,0.12) !important;
+        }
+        /* Ensure modal content stays readable — Steve's earlier sweep made it #141414 with white text */
+        .modal-content { background: #141414 !important; color: #f5f1e8 !important; }
+        .modal-content * { color: #f5f1e8 !important; }
+        .modal-content input, .modal-content textarea, .modal-content select {
+          background: rgba(245,241,232,0.05) !important;
+          color: #f5f1e8 !important;
+          border-color: rgba(245,241,232,0.2) !important;
+        }
+        .modal-content label { color: rgba(245,241,232,0.6) !important; }
+        /* Force the wide-tracked NOVASUEDE wordmark to stay white */
+        .ns-wordmark, .ns-wordmark sup { color: #f5f1e8 !important; }
+
+        /* ─── Modal-internal contrast (post-QA defects) ─── */
+        /* Backdrop covers full viewport */
+        .modal { width: 100vw !important; height: 100vh !important; left: 0 !important; top: 0 !important; background: rgba(0, 0, 0, 0.78) !important; backdrop-filter: blur(6px); }
+        /* Chip — flip from white-on-white island to dark card */
+        .request-chip {
+          background: rgba(245, 241, 232, 0.06) !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.18) !important;
+          border-radius: 4px !important;
+        }
+        .request-chip * { color: #f5f1e8 !important; }
+        .request-chip .chip-swatch {
+          /* swatch dot ALWAYS displays the inline-style hex from JS — fight any sweep */
+          border: 1px solid rgba(0, 0, 0, 0.4) !important;
+        }
+        /* + Add to request — hairline white-border on transparent (no gold) */
+        .add-to-request-btn {
+          background: transparent !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.6) !important;
+          border-radius: 0 !important;
+          padding: 12px 22px !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 400 !important;
+        }
+        .add-to-request-btn:hover {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        /* Hex caption visible */
+        .preview-hex, #colorPreviewHex {
+          display: block !important;
+          color: rgba(245, 241, 232, 0.55) !important;
+          font-family: ui-monospace, "SF Mono", Menlo, monospace !important;
+          font-size: 11px !important;
+          margin-top: 4px !important;
+          letter-spacing: 0.04em !important;
+          text-transform: lowercase !important;
+        }
+        /* Color preview name — stays single, prominent */
+        #colorPreviewName {
+          color: #f5f1e8 !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 500 !important;
+          display: block !important;
+          margin-top: 12px !important;
+        }
+
+        /* ─── Mobile hamburger nav (replaces the overflow at <760px) ─── */
+        @media (max-width: 760px) {
+          header .nav-container { flex-wrap: wrap; }
+          header nav { display: none; flex-basis: 100%; flex-direction: column; gap: 6px; padding: 16px 0 6px; }
+          header nav.open { display: flex; }
+          header nav a { padding: 10px 0; border-bottom: 1px solid rgba(245,241,232,0.1); }
+          header .mobile-toggle {
+            display: flex !important;
+            flex-direction: column;
+            gap: 5px;
+            background: transparent;
+            border: 0;
+            cursor: pointer;
+            padding: 8px;
+          }
+          header .mobile-toggle span {
+            width: 22px; height: 1.5px;
+            background: #f5f1e8;
+            display: block;
+          }
+        }
+        @media (min-width: 761px) {
+          header .mobile-toggle { display: none !important; }
+        }
+
+    </style>
+<header class="ns-header">
+        <a href="#home" class="ns-brand" aria-label="Heritage Atelier home">
+            <span class="ns-dot"></span>
+            <span class="ns-name">Heritage Atelier</span>
+        </a>
+        <nav class="ns-nav" id="nsPrimaryNav" aria-label="Primary">
+            <a href="#home">Home</a>
+            <a href="#colors">Colors</a>
+            <a href="#specifications">Specifications</a>
+            <a href="fire-ratings.html">Fire Ratings</a>
+            <a href="faq.html">FAQ</a>
+            <a href="about.html">About</a>
+            <button type="button" onclick="nsContactOpen()">Contact</button>
+        </nav>
+        <button type="button" class="mobile-toggle" aria-label="Toggle menu" aria-controls="nsPrimaryNav" aria-expanded="false" onclick="nsToggleNav(this)">
+            <span></span><span></span><span></span>
+        </button>
+    </header>
+<div class="ns-modal" id="nsContactModal" role="dialog" aria-modal="true" aria-labelledby="nsContactTitle" onclick="if(event.target===this)nsContactClose()">
+        <div class="ns-modal-card">
+            <button type="button" class="close-x" onclick="nsContactClose()" aria-label="Close">×</button>
+            <h3 id="nsContactTitle">How can we help?</h3>
+            <p class="sub">Trade-account replies within one business day.</p>
+            <div class="ns-actions">
+                <a class="ns-action" href="#contact" onclick="nsContactClose()"><span class="ico">📋</span><div class="txt"><b>Get a Quote</b><span>Project specs → priced estimate</span></div></a>
+                <a class="ns-action" href="#contact" onclick="nsContactClose();openModal();"><span class="ico">📦</span><div class="txt"><b>Order a Sample</b><span>Free swatch to your shop</span></div></a>
+                <a class="ns-action" href="mailto:info@novasuede.com?subject=Novasuede%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@novasuede.com · Designer Wallcoverings</span></div></a>
+                <a class="ns-action" href="tel:888-373-4564"><span class="ico">📞</span><div class="txt"><b>Call Us</b><span>(888) 373-4564 · M–F, 9–5 PT</span></div></a>
+            </div>
+        </div>
+    </div>
+<script>
+  function nsContactOpen() { var m = document.getElementById('nsContactModal'); if (m) m.classList.add('show'); }
+  function nsContactClose() { var m = document.getElementById('nsContactModal'); if (m) m.classList.remove('show'); }
+  function nsToggleNav(btn) {
+    var nav = document.getElementById('nsPrimaryNav');
+    if (!nav) return;
+    var open = nav.classList.toggle('open');
+    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
+  }
+  document.addEventListener('keydown', function(e){ if (e.key === 'Escape') nsContactClose(); });
+</script>
+
+
+
+<header>
+  <button class="h-link" onclick="dwmOpen('Contact')" aria-label="Contact"><svg class="h-icon" viewBox="0 0 24 24"><path d="M3 7h18M3 12h18M3 17h18"/></svg><span>Contact</span></button>
+  <button class="theme-toggle" id="theme-toggle" aria-label="Theme toggle">☾</button>
+</header>
+
+<section class="cinema">
+  <div class="cinema-bg" id="heroBg"></div>
+  <div class="corner-mark">Trade-Grade</div>
+  <div class="center-mark">Hospitality Wallpaper</div>
+  <div class="meta-line">Hotel · Restaurant · Spa · Class A<span class="num" id="heroNum"></span></div>
+  <a class="enter" href="#shop">Enter <svg viewBox="0 0 24 12" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M0 6h22M16 1l6 5-6 5"/></svg></a>
+</section>
+
+
+<section class="section" id="ideas">
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">New this week</h2>
+    <div class="rail" id="railNewest"></div>
+  </div>
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">Curated picks</h2>
+    <div class="rail" id="railCurated"></div>
+  </div>
+</section>
+
+<section class="section" id="shop">
+  <div class="section-header">
+    <div>
+      <div class="section-eyebrow">The Collection</div>
+      <h2 class="section-title"><span class="accent" id="totalCount">—</span> Patterns.</h2>
+    </div>
+    <div class="section-meta">Hotel · Restaurant · Spa · Class A</div>
+  </div>
+
+  <div class="filters" id="facets">
+    <button class="chip active" data-facet="all">All</button>
+  </div>
+
+  <div class="density">
+    <label>Sort</label>
+    <select id="sortSelect" aria-label="Sort products" style="background:transparent;color:inherit;border:1px solid var(--line,rgba(255,255,255,.2));font:inherit;font-size:11px;letter-spacing:.10em;text-transform:uppercase;padding:4px 8px;cursor:pointer;outline:none;margin-right:14px">
+      <option value="newest">Newest</option>
+      <option value="color">Color</option>
+      <option value="style">Style</option>
+      <option value="sku">SKU A→Z</option>
+      <option value="title">Title A→Z</option>
+      <option value="price-asc">Price ↑</option>
+      <option value="price-desc">Price ↓</option>
+    </select>
+    <label>Grid</label>
+    <input type="range" id="densitySlider" min="4" max="12" step="1" value="6" aria-label="Grid columns">
+    <span class="ct" id="densityLabel">6 cols</span>
+    <div class="search">
+      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-5.5-5.5"/></svg>
+      <input type="text" id="searchInput" placeholder="Search by pattern, color…" autocomplete="off">
+    </div>
+  </div>
+
+  <div class="stat-line" id="statLine">Loading…</div>
+  <div class="grid" id="grid"></div>
+  <div class="loading" id="loading">Loading more…</div>
+  <div class="sentinel" id="sentinel"></div>
+</section>
+
+<footer>
+  <div class="footer-grid">
+    <div>
+      <div class="footer-brand">Hospitality Wallpaper</div>
+      <p class="footer-text">Hospitality Wallpaper is a specialty hospitality archive within the Designer Wallcoverings family. Real samples ship free.</p>
+      <p class="footer-text" style="margin-top:14px;font-size:11px;letter-spacing:0.18em;text-transform:uppercase;font-weight:600;color:var(--paper);opacity:0.7"><a href="/about" style="color:inherit;text-decoration:none;border-bottom:1px solid var(--accent)">About →</a></p>
+    </div>
+    <div class="footer-col">
+      <h4>Aesthetic</h4>
+      <div id="footerFacets"></div>
+    </div>
+    <div class="footer-col">
+      <h4>Trade</h4>
+      <button onclick="dwmOpen('Inquiry')">Project Inquiry</button>
+      <button onclick="dwmOpen('Sample')">Request Sample</button>
+      <button onclick="dwmOpen('Contact')">Contact</button>
+    </div>
+  
+    <div class="footer-col">
+      <h4>Social</h4>
+      <a class="fb-link" href="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings" target="_blank" rel="noopener">Facebook</a>
+    </div>
+  </div>
+  <div class="footer-bottom">
+    <span>hospitalitywallpaper.com · Heritage Atelier</span>
+    <span><a href="mailto:info@hospitalitywallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@hospitalitywallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "hospitalitywallpaper";
+  const NICHES = [
+    ['silkwallpaper','Silk','mat'],['silkwallcoverings','Silk W/C','mat'],['linenwallpaper','Linen','mat'],
+    ['jutewallpaper','Jute','mat'],['raffiawallcoverings','Raffia W/C','mat'],['raffiawalls','Raffia Walls','mat'],
+    ['corkwallcovering','Cork','mat'],['fabricwallpaper','Fabric','mat'],['textilewallpaper','Textile','mat'],
+    ['metallicwallpaper','Metallic','mat'],['silverleafwallpaper','Silver Leaf','mat'],['vinylwallpaper','Vinyl','mat'],
+    ['micawallpaper','Mica','mat'],['madagascarwallpaper','Madagascar','mat'],['mylarwallpaper','Mylar','mat'],
+    ['suedewallpaper','Suede','mat'],
+    ['1800swallpaper','1800s','dec'],['1890swallpaper','1890s','dec'],['1900swallpaper','1900s','dec'],
+    ['1920swallpaper','1920s','dec'],['1930swallpaper','1930s','dec'],['1940swallpaper','1940s','dec'],
+    ['1950swallpaper','1950s','dec'],['1960swallpaper','1960s','dec'],['1970swallpaper','1970s','dec'],
+    ['1980swallpaper','1980s','dec'],['retrowalls','Retro','dec'],['wallpapersback','W. Back','dec'],
+    ['agedwallpaper','Aged','cra'],['handcraftedwallpaper','Handcrafted','cra'],['museumwallpaper','Museum','cra'],
+    ['restorationwallpaper','Restoration','cra'],['pastelwallpaper','Pastel','cra'],['glitterwalls','Glitter','cra'],
+    ['greenwallcoverings','Green','cra'],['naturalwallcoverings','Natural','cra'],['saloonwallpaper','Saloon','cra'],
+    ['contractwallpaper','Contract','use'],['hotelwallcoverings','Hotel','use'],['hospitalitywallpaper','Hospitality','use'],
+    ['healthcarewallpaper','Healthcare','use'],['restaurantwallpaper','Restaurant','use'],['architecturalwallcoverings','Architectural','use']
+  ];
+  const COLOR = { mat:'#c9b687', dec:'#b86a4a', cra:'#6b8e6f', use:'#4a6b8e' };
+  const W = 1080, H = 200, BANDS = ['mat','dec','cra','use'];
+  const groups = { mat:[], dec:[], cra:[], use:[] };
+  for (const n of NICHES) groups[n[2]].push(n);
+  const svg = document.getElementById('miniConst');
+  if (!svg) return;
+  const bandW = W / BANDS.length;
+  let nodes = '';
+  BANDS.forEach((band, bi) => {
+    const list = groups[band];
+    const cx = bi * bandW + bandW / 2;
+    list.forEach((n, i) => {
+      const t = list.length === 1 ? 0.5 : i / (list.length - 1);
+      // deterministic jitter per slug
+      let h = 0; for (let k = 0; k < n[0].length; k++) h = (h * 31 + n[0].charCodeAt(k)) | 0;
+      const jx = ((h & 0xff) / 255 - 0.5) * (bandW * 0.5);
+      const jy = (((h >> 8) & 0xff) / 255 - 0.5) * 6;  // tightened from 14 → 6 to prevent same-band collisions (16 mat nodes / 144px = 9px spacing)
+      const x = cx + jx, y = 28 + t * (H - 56) + jy;
+      const isCurrent = n[0] === SLUG;
+      const r = isCurrent ? 8 : 4;
+      const op = isCurrent ? 1 : 0.55;
+      nodes += `<g class="mc-node" data-slug="${n[0]}" data-label="${n[1]}" style="cursor:pointer">
+        <circle cx="${x}" cy="${y}" r="${r}" fill="url(#dna-${band})" fill-opacity="${op}" stroke="${COLOR[band]}" stroke-opacity="${isCurrent?1:0.7}" stroke-width="${isCurrent?2:1}">
+          <title>${n[1]} — ${n[0]}.com</title>
+        </circle>
+        ${isCurrent ? `<circle cx="${x}" cy="${y}" r="${r+5}" fill="none" stroke="${COLOR[band]}" stroke-opacity="0.4" stroke-width="1"><animate attributeName="r" values="${r+5};${r+12};${r+5}" dur="2.4s" repeatCount="indefinite"/><animate attributeName="stroke-opacity" values="0.4;0;0.4" dur="2.4s" repeatCount="indefinite"/></circle>` : ''}
+      </g>`;
+    });
+  });
+  // append nodes after defs
+  svg.insertAdjacentHTML('beforeend', nodes);
+  svg.querySelectorAll('.mc-node').forEach(n => {
+    n.addEventListener('mouseenter', () => n.querySelector('circle').setAttribute('fill-opacity', '1'));
+    n.addEventListener('mouseleave', e => {
+      const isCurrent = n.dataset.slug === SLUG;
+      n.querySelector('circle').setAttribute('fill-opacity', isCurrent ? '1' : '0.55');
+    });
+    n.addEventListener('click', () => window.open('https://' + n.dataset.slug + '.com', '_blank'));
+  });
+})();
+</script>
+
+<script>
+const state = { q:'', facet:'all', page:1, pages:1, total:0, loading:false, exhausted:false };
+const LABELS = {"all":"All"};
+
+function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c])); }
+// Image-URL allowlist: only DW Shopify CDN + designerwallcoverings.com (defends against XSS via crafted products.json)
+function safeImg(u) { return /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(u || '') ? u : '/hero-bg.jpg'; }
+function cardHTML(p) {
+  const eager = state.page === 1;
+  return '<img loading="' + (eager ? 'eager' : 'lazy') + '"' + (eager ? ' fetchpriority="high"' : '') + ' src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+    + '<div class="overlay">'
+    + '<div class="pat">' + escAttr(p.pattern_name || p.title) + '</div>'
+    + '<div class="ven">' + escAttr((p.vendor || '').replace(/-/g, ' ')) + '</div>'
+    + '<div class="actions">'
+    + '<button class="sample-btn" onclick="event.stopPropagation();dwmOpen(\'Sample\',' + JSON.stringify({sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}).replace(/"/g,'&quot;') + ')">Sample</button>'
+    + '</div></div>';
+}
+
+async function loadFacets() {
+  let f;
+  try {
+    const r = await fetch('/api/facets');
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    f = await r.json();
+  } catch (e) { console.error('loadFacets failed:', e); return; }
+  const el = document.getElementById('facets');
+  for (const [k, v] of Object.entries(f.aesthetics).sort((a,b) => b[1] - a[1])) {
+    const b = document.createElement('button');
+    b.className = 'chip'; b.dataset.facet = k;
+    b.innerHTML = (LABELS[k] || k) + ' <span style="opacity:.55;font-weight:500;margin-left:4px">' + v + '</span>';
+    el.appendChild(b);
+  }
+  el.addEventListener('click', e => {
+    if (e.target.tagName !== 'BUTTON') return;
+    document.querySelectorAll('#facets button').forEach(b => b.classList.remove('active'));
+    e.target.classList.add('active');
+    state.facet = e.target.dataset.facet;
+    resetGrid();
+  });
+  document.getElementById('totalCount').textContent = f.total;
+  document.getElementById('footerStat').textContent = f.total + ' patterns · live archive';
+  // Footer aesthetic links
+  const footerEl = document.getElementById('footerFacets');
+  for (const [k] of Object.entries(f.aesthetics)) {
+    const b = document.createElement('button');
+    b.textContent = LABELS[k] || k;
+    b.onclick = () => { state.facet = k; resetGrid(); document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === k)); document.getElementById('shop').scrollIntoView({behavior:'smooth'}); };
+    footerEl.appendChild(b);
+  }
+}
+
+function resetGrid() {
+  state.page = 1; state.exhausted = false;
+  document.getElementById('grid').innerHTML = '';
+  document.getElementById('loading').textContent = 'Loading…';
+  loadGridPage();
+}
+
+async function loadGridPage() {
+  if (state.loading || state.exhausted) return;
+  state.loading = true;
+  const params = new URLSearchParams({ page:state.page, limit:24 });
+  if (state.q) params.set('q', state.q);
+  if (state.facet !== 'all') params.set('aesthetic', state.facet);
+  let data;
+  try {
+    const r = await fetch('/api/products?' + params);
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    data = await r.json();
+  } catch (e) {
+    console.error('loadGridPage failed:', e);
+    document.getElementById('loading').textContent = '— offline — refresh to retry —';
+    state.loading = false;
+    return;
+  }
+  state.total = data.total; state.pages = data.pages;
+
+  if (state.page === 1) {
+    document.getElementById('statLine').textContent = data.total + ' patterns · ' + (state.facet === 'all' ? 'all aesthetics' : (LABELS[state.facet] || state.facet)) + (state.q ? ' · matching "' + state.q + '"' : '');
+  }
+  const grid = document.getElementById('grid');
+  for (const p of data.items) {
+    const a = document.createElement('a');
+    a.className = 'card'; a.href = '#'; a.onclick = (e) => { e.preventDefault(); dwmOpen('Sample',{sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}); };
+    a.innerHTML = cardHTML(p);
+    grid.appendChild(a);
+  }
+  if (state.page >= state.pages || data.items.length === 0) {
+    state.exhausted = true;
+    document.getElementById('loading').textContent = state.total > 0 ? '— end of archive · ' + state.total + ' patterns —' : '';
+  } else state.page++;
+  state.loading = false;
+}
+
+const io = new IntersectionObserver(es => { for (const e of es) if (e.isIntersecting) loadGridPage(); }, { rootMargin:'600px 0px' });
+io.observe(document.getElementById('sentinel'));
+
+document.getElementById('searchInput').addEventListener('input', e => {
+  state.q = e.target.value.trim();
+  clearTimeout(window._t);
+  window._t = setTimeout(resetGrid, 220);
+});
+
+// Density slider
+const slider = document.getElementById('densitySlider');
+const dlabel = document.getElementById('densityLabel');
+function setDensity(n) {
+  document.documentElement.style.setProperty('--cols', n);
+  dlabel.textContent = n + ' cols';
+  try { localStorage.setItem('hosp_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('hosp_theme_density') || '6');
+if (savedDensity >= 4 && savedDensity <= 12) { slider.value = savedDensity; setDensity(savedDensity); }
+
+// Theme toggle
+const tb = document.getElementById('theme-toggle');
+function setTheme(t){ document.documentElement.dataset.theme = t; try { localStorage.setItem('hosp_theme', t); } catch(e){} tb.textContent = t === 'dark' ? '☾' : '☀'; }
+setTheme(document.documentElement.dataset.theme || 'light');
+tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
+
+loadFacets();
+loadGridPage();
+</script>
+<!-- ============================================================
+     DW UNIVERSAL CONTACT MODULE — fashion-house UX
+     Inject before </body> in every DW-family sister site.
+     Self-contained: CSS + 4 modals + JS submission handlers.
+     Uses host site's CSS vars (--bg, --fg, --gold, --rule).
+     ============================================================ -->
+<style>
+  /* === MODAL BASE === */
+  .dwm{position:fixed;inset:0;background:rgba(0,0,0,0.78);display:none;align-items:center;justify-content:center;z-index:9999;padding:24px;overflow-y:auto}
+  .dwm.open{display:flex}
+  .dwm-box{background:var(--bg);border:1px solid var(--rule);max-width:520px;width:100%;padding:36px 32px;position:relative;max-height:90vh;overflow-y:auto;animation:dwm-in 0.25s ease}
+  @keyframes dwm-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
+  .dwm-box h3{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-weight:400;font-size:32px;line-height:1.05;margin-bottom:6px;color:var(--fg);letter-spacing:-0.01em}
+  .dwm-box .sub{color:var(--muted);font-size:12px;letter-spacing:0.16em;text-transform:uppercase;margin-bottom:24px;font-weight:500}
+  .dwm-close{position:absolute;top:18px;right:18px;background:transparent;border:0;color:var(--muted);font-size:24px;cursor:pointer;width:32px;height:32px;line-height:1;padding:0}
+  .dwm-close:hover{color:var(--gold)}
+  .dwm-preview{display:flex;gap:14px;align-items:center;padding:12px;background:var(--bg-soft);margin-bottom:18px}
+  .dwm-preview img{width:64px;height:64px;object-fit:cover}
+  .dwm-preview .pn{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-size:15px;line-height:1.2;color:var(--fg)}
+  .dwm-preview .pc{font-size:10px;letter-spacing:0.14em;text-transform:uppercase;color:var(--muted);margin-top:4px}
+  .dwm-field{margin-bottom:14px}
+  .dwm-field label{display:block;font-size:10px;letter-spacing:0.18em;text-transform:uppercase;color:var(--muted);margin-bottom:6px;font-weight:500}
+  .dwm-field input,.dwm-field textarea,.dwm-field select{width:100%;border:0;border-bottom:1px solid var(--rule);background:transparent;padding:8px 4px;font-size:14px;font-family:inherit;color:var(--fg);outline:none;transition:border-color 0.2s}
+  .dwm-field input:focus,.dwm-field textarea:focus{border-bottom-color:var(--gold)}
+  .dwm-field textarea{min-height:60px;resize:vertical}
+  .dwm-submit{background:transparent;color:var(--muted, #c9b89e);border:1px solid var(--muted, #c9b89e);padding:14px 28px;font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:700;cursor:pointer;width:100%;margin-top:8px;transition:background 0.15s, color 0.15s}
+  .dwm-submit:hover{background:var(--muted, #c9b89e);color:var(--bg, #000)}
+  
+  .dwm-submit:disabled{opacity:0.5;cursor:default}
+  .dwm-status{margin-top:14px;font-size:11px;letter-spacing:0.16em;text-transform:uppercase;text-align:center;display:none}
+  .dwm-status.ok{color:var(--sage);display:block}
+  .dwm-status.err{color:#e08070;display:block}
+  /* contact-options */
+  .dwm-options{display:flex;flex-direction:column;gap:10px}
+  .dwm-option{display:flex;align-items:center;gap:14px;padding:18px 20px;background:transparent;border:1px solid var(--rule);color:var(--fg);font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:600;cursor:pointer;text-decoration:none;transition:all 0.2s;text-align:left;width:100%}
+  .dwm-option:hover{border-color:var(--gold);color:var(--gold)}
+  .dwm-option svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.5;flex-shrink:0}
+  .dwm-option .lbl{flex:1;display:block}
+  .dwm-option .val{display:block;font-size:10px;letter-spacing:0.14em;text-transform:none;font-weight:500;opacity:0.65;margin-top:4px}
+
+/* graphics-loop pass 11: Ideas rails */
+#ideas { padding: 56px 24px 24px; max-width:1600px; margin:0 auto }
+#ideas .rail-block { margin-bottom:48px }
+#ideas .rail-eyebrow { font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:var(--muted, #888); margin-bottom:8px }
+#ideas .rail-title { font-size:clamp(22px,2.6vw,32px); font-weight:500; letter-spacing:-0.01em; margin:0 0 18px; color:var(--ink,#fff) }
+#ideas .rail { display:flex; gap:14px; overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:8px; scrollbar-width:none }
+#ideas .rail::-webkit-scrollbar { display:none }
+#ideas .rail-card { flex:0 0 240px; scroll-snap-align:start; cursor:pointer; transition:transform 0.2s }
+#ideas .rail-card:hover { transform:translateY(-3px) }
+#ideas .rail-card img { width:100%; aspect-ratio:1; object-fit:cover; display:block; background:var(--card,#222) }
+#ideas .rail-card .rc-title { font-size:13px; font-weight:500; color:var(--paper,#fff); padding:8px 0 2px; line-height:1.3 }
+#ideas .rail-card .rc-meta  { font-size:11px; color:var(--muted,#888); letter-spacing:0.06em }
+@media (max-width:720px) { #ideas .rail-card { flex:0 0 160px } }
+</style>
+
+<!-- Contact options modal -->
+<div class="dwm" id="dwmContact" onclick="if(event.target===this)dwmClose('Contact')">
+  <div class="dwm-box" style="max-width:440px">
+    <button class="dwm-close" onclick="dwmClose('Contact')" aria-label="Close">×</button>
+    <h3>Contact</h3>
+    <p class="sub" id="dwmContactSub">Three ways to reach us</p>
+    <div class="dwm-options">
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Inquiry')">
+        <svg viewBox="0 0 24 24"><path d="M4 4h16v12H7l-3 3z"/></svg>
+        <span class="lbl">Send an Inquiry<span class="val">Project name · scope · all the details</span></span>
+      </button>
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Sample')">
+        <svg viewBox="0 0 24 24"><rect x="4" y="6" width="16" height="14"/><path d="M4 10h16M9 6V3h6v3"/></svg>
+        <span class="lbl">Request a Sample<span class="val">Memo sample · ships free · 3–5 business days</span></span>
+      </button>
+      <a class="dwm-option" id="dwmContactEmailLink" href="mailto:info@hospitalitywallpaper.com">
+        <svg viewBox="0 0 24 24"><path d="M3 6h18v12H3z"/><path d="M3 6l9 7 9-7"/></svg>
+        <span class="lbl">Email Us<span class="val" id="dwmContactEmailLabel">info@hospitalitywallpaper.com</span></span>
+      </a>
+    </div>
+  </div>
+</div>
+
+<!-- Inquiry modal -->
+<div class="dwm" id="dwmInquiry" onclick="if(event.target===this)dwmClose('Inquiry')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Inquiry')" aria-label="Close">×</button>
+    <h3>Project Inquiry</h3>
+    <p class="sub">We'll respond within one business day</p>
+    <form id="dwmInquiryForm" onsubmit="return dwmSubmit(event,'inquiry')">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Phone</label><input type="tel" name="phone"></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Project Name</label><input type="text" name="projectName" required></div>
+      <div class="dwm-field"><label>Project Scope</label><textarea name="projectScope" placeholder="Square footage · room count · timeline" required></textarea></div>
+      <div class="dwm-field"><label>Additional Information</label><textarea name="message" placeholder="Patterns of interest, finish preferences, budget"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Inquiry</button>
+      <div class="dwm-status" id="dwmInquiryStatus"></div>
+    </form>
+  </div>
+</div>
+
+<!-- Sample-request modal -->
+<div class="dwm" id="dwmSample" onclick="if(event.target===this)dwmClose('Sample')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Sample')" aria-label="Close">×</button>
+    <h3>Request a Sample</h3>
+    <p class="sub">Memo sample · ships free · 3–5 business days</p>
+    <div class="dwm-preview" id="dwmSamplePreview" style="display:none">
+      <img id="dwmSampleImg" src="" alt="">
+      <div><div class="pn" id="dwmSampleName"></div><div class="pc" id="dwmSampleSku"></div></div>
+    </div>
+    <form id="dwmSampleForm" onsubmit="return dwmSubmit(event,'sample')">
+      <input type="hidden" name="sku" id="dwmSampleSkuInput">
+      <input type="hidden" name="title" id="dwmSampleTitleInput">
+      <input type="hidden" name="image_url" id="dwmSampleImageInput">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Shipping Address</label><input type="text" name="address" placeholder="Street" required></div>
+      <div class="dwm-field" style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:8px">
+        <input type="text" name="city" placeholder="City" required>
+        <input type="text" name="state" placeholder="State" required>
+        <input type="text" name="zip" placeholder="ZIP" required>
+      </div>
+      <div class="dwm-field"><label>Notes (optional)</label><textarea name="message" placeholder="Project, sq.ft., timing"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Sample Request</button>
+      <div class="dwm-status" id="dwmSampleStatus"></div>
+    </form>
+  </div>
+</div>
+
+<script>
+  // Universal modal control
+  function dwmOpen(name, opts){
+    document.getElementById('dwm' + name).classList.add('open');
+    document.body.style.overflow = 'hidden';
+    if (name === 'Sample' && opts) {
+      document.getElementById('dwmSamplePreview').style.display = 'flex';
+      document.getElementById('dwmSampleImg').src = opts.image_url || '';
+      document.getElementById('dwmSampleName').textContent = opts.title || '';
+      document.getElementById('dwmSampleSku').textContent = opts.sku || '';
+      document.getElementById('dwmSampleSkuInput').value = opts.sku || '';
+      document.getElementById('dwmSampleTitleInput').value = opts.title || '';
+      document.getElementById('dwmSampleImageInput').value = opts.image_url || '';
+    } else if (name === 'Sample') {
+      document.getElementById('dwmSamplePreview').style.display = 'none';
+      document.getElementById('dwmSampleSkuInput').value = '';
+      document.getElementById('dwmSampleTitleInput').value = '';
+      document.getElementById('dwmSampleImageInput').value = '';
+    }
+  }
+  function dwmClose(name){ document.getElementById('dwm'+name).classList.remove('open'); document.body.style.overflow=''; }
+
+  // Universal form submit — POSTs to /api/send-{kind}
+  async function dwmSubmit(e, kind) {
+    e.preventDefault();
+    const form = e.target;
+    const data = Object.fromEntries(new FormData(form).entries());
+    const btn = form.querySelector('.dwm-submit');
+    const status = form.querySelector('.dwm-status');
+    btn.disabled = true; const orig = btn.textContent; btn.textContent = 'Sending…';
+    status.className = 'dwm-status';
+    try {
+      const r = await fetch('/api/send-' + kind, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(data) });
+      if (!r.ok) throw new Error('HTTP '+r.status);
+      const j = await r.json();
+      status.textContent = kind === 'sample' ? 'Sample request sent — ships within 3–5 business days' : 'Inquiry sent — we respond within 1 business day';
+      status.className = 'dwm-status ok';
+      btn.textContent = 'Sent ✓';
+      setTimeout(() => { dwmClose(kind === 'sample' ? 'Sample' : 'Inquiry'); btn.disabled = false; btn.textContent = orig; status.className = 'dwm-status'; form.reset(); }, 2800);
+    } catch (err) {
+      status.textContent = 'Send failed — please email info@designerwallcoverings.com';
+      status.className = 'dwm-status err';
+      btn.disabled = false; btn.textContent = orig;
+    }
+    return false;
+  }
+
+  // Wire up "Memo samples ship free" badge in hero to open sample modal directly
+  document.querySelectorAll('.hero .badge, [data-open-sample]').forEach(el => {
+    el.style.cursor = 'pointer';
+    el.addEventListener('click', () => dwmOpen('Sample'));
+  });
+
+  // Wire nav "Trade" link to inquiry modal
+  document.querySelectorAll('nav a[href*="designerwallcoverings.com"]').forEach(a => {
+    a.removeAttribute('target');
+    a.removeAttribute('href');
+    a.style.cursor = 'pointer';
+    a.addEventListener('click', e => { e.preventDefault(); dwmOpen('Contact'); });
+  });
+
+  // Override product card clicks — open Sample modal pre-filled instead of redirecting to DW
+  document.addEventListener('click', e => {
+    const card = e.target.closest('.card, .rail-card');
+    if (!card) return;
+    if (card.tagName === 'A' && (card.getAttribute('href') || '').startsWith('/sample/')) {
+      e.preventDefault();
+      const img = card.querySelector('img');
+      const pat = card.querySelector('.pat');
+      const sku = card.getAttribute('href').replace('/sample/', '');
+      dwmOpen('Sample', {
+        sku,
+        title: pat ? pat.textContent.trim() : '',
+        image_url: img ? img.src : ''
+      });
+    }
+  }, true);
+// DW STANDARD: hero pulls from products.json[0].image_url so dw-collections-viewer
+// drag-drop / hero-pin updates the live front page on next deploy.
+// Always upgrades to the largest Shopify variant (strips _NxN size suffix) so
+// the full-page hero stays sharp.
+// DW STANDARD: hero rotates through top-20 NEWEST products on each visit
+// (novasuede.com pattern). Fetches /api/products?limit=100, sorts by created_at desc,
+// takes the freshest 20, picks one per visit via localStorage counter.
+// Falls back to static /hero-bg.jpg on any error.
+(async function rotateHero() {
+  try {
+    const r = await fetch('/api/products?limit=100');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || [])
+      .filter(p => p && p.image_url && /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(p.image_url))
+      .sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')))
+      .slice(0, 20);
+    if (!items.length) return;
+    let visits = 0;
+    try {
+      visits = parseInt(localStorage.getItem('hero_visits') || '0', 10) || 0;
+      localStorage.setItem('hero_visits', String(visits + 1));
+    } catch(e) {}
+    const pick = items[visits % items.length];
+    // Strip _NxN size suffix to get the largest CDN variant
+    const url = pick.image_url.replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+    const bg = document.getElementById('heroBg') || document.getElementById('cinemaBg');
+    if (bg) bg.style.backgroundImage = "url('" + url + "')";
+  } catch (e) {}
+})();
+
+
+// DW STANDARD sort-select wire-up (added by fleet patcher)
+(function(){
+  const sortSel = document.getElementById('sortSelect');
+  if (!sortSel) return;
+  const KEY = location.hostname.replace(/\./g, '_') + '_sort';
+  const saved = localStorage.getItem(KEY);
+  if (saved) { try { sortSel.value = saved; } catch(e){} }
+  if (typeof state !== 'undefined') state.sort = sortSel.value;
+  sortSel.addEventListener('change', e => {
+    const v = e.target.value;
+    try { localStorage.setItem(KEY, v); } catch(e){}
+    if (typeof state !== 'undefined') state.sort = v;
+    if (typeof resetGrid === 'function') resetGrid();
+    else location.reload();
+  });
+})();
+
+// graphics-loop pass 11: hydrate Ideas rails from /api/products
+(async function hydrateIdeas() {
+  try {
+    const r = await fetch('/api/products?limit=80');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || []).filter(p => p && p.image_url);
+    if (!items.length) return;
+    const sorted = [...items].sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')));
+    const newest = sorted.slice(0, 12);
+    // Curated = deterministic offset slice (every 5th item starting at idx 3) for variety
+    const curated = items.filter((_, i) => i % 5 === 3).slice(0, 12);
+    function card(p) {
+      const url = (p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+      return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle || p.sku) + '">' +
+        '<img src="' + url + '" alt="' + (p.title || '').replace(/"/g, '&quot;') + '" loading="lazy">' +
+        '<div class="rc-title">' + ((p.title || '').split('|')[0] || '').trim() + '</div>' +
+        '<div class="rc-meta">' + (p.vendor || '') + '</div>' +
+      '</a>';
+    }
+    const r1 = document.getElementById('railNewest');
+    const r2 = document.getElementById('railCurated');
+    if (r1) r1.innerHTML = newest.map(card).join('');
+    if (r2) r2.innerHTML = curated.map(card).join('');
+  } catch(e) {}
+})();
+</script>
+
+</body>
+</html>
diff --git a/public/index.html.bak.nspropagate.1778209715048 b/public/index.html.bak.nspropagate.1778209715048
new file mode 100644
index 0000000..77ceeb2
--- /dev/null
+++ b/public/index.html.bak.nspropagate.1778209715048
@@ -0,0 +1,962 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<!-- Google tag (gtag.js) -->
+<script async src="https://www.googletagmanager.com/gtag/js?id=G-XM0936TL4N"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-XM0936TL4N');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Heritage Atelier — hospitality, the British way.</title>
+<meta name="description" content="Heritage Atelier is a curated atelier dedicated entirely to hospitality. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#FFF">
+<link rel="canonical" href="https://hospitalitywallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600&family=Inter:wght@300;400;500&display=swap" rel="stylesheet">
+<link rel="preload" as="image" href="/hero-bg.jpg" fetchpriority="high">
+<script type="application/ld+json">
+{
+  "@context": "https://schema.org",
+  "@type": "Organization",
+  "name": "Heritage Atelier",
+  "url": "https://hospitalitywallpaper.com/",
+  "email": "info@hospitalitywallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #FFF;
+  --paper: #000;
+  --muted: #8B7866;
+  --line: #A47C5A;
+  --accent: #A47C5A;
+  --bg-soft: #A47C5A;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #000;
+  --paper: #FFF;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #A47C5A;
+  --bg-soft: #2a1f15;
+}
+* { margin:0; padding:0; box-sizing:border-box }
+html { scroll-behavior:smooth }
+body { font-family:'Inter', sans-serif; color:var(--paper); -webkit-font-smoothing:antialiased; background:var(--bg); min-height:100vh; overflow-x:hidden }
+/* DW-FASHION-TEMPLATE-OVERRIDE */
+.section-title .accent, .footer-brand, .center-mark, h1, h2, h3 { font-family:'Cormorant Garamond', Georgia, serif !important; font-weight:500 !important;  }
+
+/* ===== Auto-hide header ===== */
+header { position:fixed; top:0; left:0; right:0; display:flex; justify-content:space-between; align-items:center; padding:22px 32px; z-index:100; background:rgba(0,0,0,0.55); backdrop-filter:blur(10px); border-bottom:1px solid var(--line); transition:transform .3s }
+.h-link { display:flex; align-items:center; gap:10px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); text-decoration:none; cursor:pointer; background:transparent; border:0 }
+.h-link:hover { opacity:0.7 }
+.h-icon { width:18px; height:18px; stroke:currentColor; fill:none; stroke-width:1.5 }
+
+/* ===== Cinema hero ===== */
+.cinema { position:relative; height:100vh; width:100%; overflow:hidden }
+.cinema-bg { position:absolute; inset:0; background-size:cover; background-position:center; background-image:url('/hero-bg.jpg') }
+.cinema-bg::after { content:""; position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.75) 100%) }
+.corner-mark { position:absolute; top:24px; left:32px; font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:#fff; text-shadow:0 1px 3px rgba(0,0,0,0.55), 0 0 1px rgba(0,0,0,0.4); z-index:5 }
+.corner-mark::before { content:"◆ "; margin-right:6px }
+.center-mark { position:absolute; top:clamp(80px,12vh,140px); left:50%; transform:translateX(-50%); font-size:clamp(28px,4vw,56px); font-weight:500; letter-spacing:0.18em; text-transform:uppercase; text-align:center; color:#fff; text-shadow:0 2px 8px rgba(0,0,0,0.65), 0 0 1px rgba(0,0,0,0.5); z-index:5 }
+.center-mark .tm { font-size:14px; vertical-align:super; opacity:0.7; margin-left:0.2em }
+.center-mark .sub { display:block; font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400; font-size:0.4em; letter-spacing:0.04em; text-transform:none; margin-top:14px; opacity:0.85 }
+.meta-line { position:absolute; bottom:32px; left:32px; font-size:10px; letter-spacing:0.28em; text-transform:uppercase; font-weight:700; color:#fff; z-index:5; opacity:0.85 }
+.meta-line .num { font-size:12px; display:block; margin-top:4px; letter-spacing:0.05em }
+.enter { position:absolute; bottom:32px; right:32px; display:flex; align-items:center; gap:14px; font-size:11px; letter-spacing:0.36em; text-transform:uppercase; font-weight:700; color:#fff; text-decoration:none; padding-bottom:6px; border-bottom:1px solid #fff; transition:gap 0.25s; z-index:5 }
+.enter:hover { gap:22px }
+.enter svg { width:24px; height:12px }
+
+/* ===== Section ===== */
+.section { padding:96px 32px }
+.section-header { display:flex; justify-content:space-between; align-items:flex-end; flex-wrap:wrap; gap:24px; margin-bottom:32px; padding-bottom:24px; border-bottom:1px solid var(--line) }
+.section-title { font-size:clamp(36px,5vw,64px); font-weight:300; letter-spacing:-0.02em; line-height:1 }
+.section-title .accent { color: var(--accent); font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400 }
+.section-eyebrow { font-size:10px; letter-spacing:0.4em; text-transform:uppercase; font-weight:700; color:var(--muted); margin-bottom:16px }
+.section-meta { font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:600; color:var(--muted); text-align:right; line-height:1.6 }
+
+/* ===== Filter bar ===== */
+.filters { display:flex; gap:8px; align-items:center; margin-bottom:18px; flex-wrap:wrap }
+.chip { padding:8px 16px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); background:transparent; border:1px solid var(--line); cursor:pointer; transition:all 0.2s; font-family:inherit }
+.chip:hover { border-color:var(--paper) }
+.chip.active { background:var(--paper); color:var(--bg); border-color:var(--paper) }
+.search { flex:0 1 280px; margin-left:auto; display:flex; align-items:center; gap:10px; border-bottom:1px solid var(--line); padding:6px 0 }
+.search input { flex:1; background:transparent; border:0; color:var(--paper); font-family:inherit; font-size:13px; outline:none; letter-spacing:0.04em }
+.search input::placeholder { color:var(--muted) }
+.search svg { width:16px; height:16px; stroke:var(--muted); fill:none; stroke-width:1.5 }
+
+/* ===== Grid-density slider ===== */
+.density { display:flex; align-items:center; gap:14px; padding:6px 0; margin-bottom:24px }
+.density label { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--muted) }
+.density input[type=range] { flex:1; max-width:240px; -webkit-appearance:none; appearance:none; height:1px; background:var(--line); outline:none }
+.density input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50% }
+.density input[type=range]::-moz-range-thumb { width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50%; border:0 }
+.density .ct { font-size:11px; color:var(--muted); letter-spacing:0.18em; text-transform:uppercase; font-weight:600; min-width:80px }
+
+/* ===== Stats line ===== */
+.stat-line { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:600; color:var(--muted); margin-bottom:24px }
+
+/* ===== Product grid (novasuede pattern: flush grid + slide-up overlay) ===== */
+.grid { display:grid; grid-template-columns:repeat(var(--cols), 1fr); gap:0 }
+.card { position:relative; aspect-ratio:1/1.15; cursor:pointer; overflow:hidden; border:1px solid var(--bg); transition:transform 0.4s cubic-bezier(0.2,0.8,0.2,1); background:var(--bg-soft) }
+.card:hover { transform:scale(1.04); z-index:5 }
+.card img { width:100%; height:100%; object-fit:cover; display:block; transition:transform 0.4s ease }
+.card .overlay { position:absolute; left:0; right:0; bottom:0; padding:20px 16px 14px; background:linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.85) 100%); transform:translateY(48%); opacity:0.85; transition:transform 0.3s ease, opacity 0.3s ease }
+.card:hover .overlay { transform:translateY(0); opacity:1 }
+.card .pat { font-size:13px; font-weight:600; letter-spacing:0.02em; color:#fff; line-height:1.25; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
+.card .ven { font-size:9px; letter-spacing:0.18em; text-transform:uppercase; color:#fff; opacity:0.7; font-weight:500; margin-top:4px }
+.card .actions { margin-top:10px; display:flex; gap:6px }
+.card .sample-btn { flex:1; padding:7px 10px; background:#fff; color:#000; font-family:inherit; font-size:10px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; border:0; cursor:pointer; text-align:center; transition:all 0.2s }
+.card .sample-btn:hover { background:var(--accent); color:#fff }
+
+@media (max-width:1024px) { .grid { grid-template-columns:repeat(min(var(--cols), 4), 1fr) } }
+@media (max-width:720px) { .grid { grid-template-columns:repeat(2, 1fr) } .density { display:none } }
+
+.sentinel { height:1px }
+.loading { text-align:center; color:var(--muted); padding:32px; font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700 }
+
+/* ===== Footer ===== */
+footer { padding:64px 32px 32px; border-top:1px solid var(--line); margin-top:32px }
+.footer-grid { max-width:1400px; margin:0 auto; display:grid; grid-template-columns:2fr 1fr 1fr 1fr; gap:48px; margin-bottom:48px }
+.footer-brand { font-size:24px; font-weight:300; letter-spacing:0.32em; text-transform:uppercase; margin-bottom:12px }
+.footer-text { font-size:13px; line-height:1.6; color:var(--muted); max-width:380px }
+.footer-col h4 { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--paper); margin-bottom:18px }
+.footer-col a { display:block; font-size:13px; color:var(--muted); text-decoration:none; margin-bottom:8px; transition:color 0.2s; cursor:pointer; background:transparent; border:0; font-family:inherit; padding:0; text-align:left }
+.footer-col a:hover { color:var(--accent) }
+.footer-bottom { max-width:1400px; margin:0 auto; padding-top:24px; border-top:1px solid var(--line); display:flex; justify-content:space-between; flex-wrap:wrap; gap:16px; font-size:11px; letter-spacing:0.18em; text-transform:uppercase; color:var(--muted) }
+
+@media (max-width:720px) {
+  .corner-mark, .meta-line, .enter { font-size:10px }
+  .center-mark { font-size:24px; letter-spacing:0.12em; top:clamp(60px,9vh,90px) }
+  .section, footer { padding-left:20px; padding-right:20px }
+  .footer-grid { grid-template-columns:1fr; gap:32px }
+  .search { margin-left:0; flex:1 1 100% }
+}
+
+.theme-toggle { background:transparent; border:1px solid var(--line); width:32px; height:32px; cursor:pointer; color:var(--paper); display:inline-flex; align-items:center; justify-content:center; font-size:14px; line-height:1; transition:all .15s; padding:0 }
+.theme-toggle:hover { border-color:var(--accent); color:var(--accent) }
+
+/* ===== WCAG 2.4.7 — keyboard focus indicators ===== */
+/* Strictly :focus-visible so mouse clicks do NOT show the ring */
+a:focus-visible,
+button:focus-visible,
+input:focus-visible,
+select:focus-visible,
+textarea:focus-visible,
+[tabindex]:focus-visible {
+  outline: 2px solid var(--accent);
+  outline-offset: 2px;
+}
+</style>
+<script>
+(function(){ try { var t = localStorage.getItem('hosp_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://hospitalitywallpaper.com/">
+<meta property="og:title" content="Hospitality Wallpaper">
+<meta property="og:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta property="og:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Hospitality Wallpaper">
+<meta property="article:publisher" content="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:title" content="Hospitality Wallpaper">
+<meta name="twitter:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta name="twitter:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<!-- graphics-loop pass 13: footer + fb -->
+</head>
+<body>
+<style id="ns-header-modal-styles">
+        .ns-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; padding: 18px 36px; background: rgba(10,10,10,0.92) !important; backdrop-filter: blur(8px); border-bottom: 1px solid rgba(245,241,232,0.06); }
+        .ns-brand { display: inline-flex; align-items: center; gap: 14px; text-decoration: none; }
+        .ns-dot { width: 28px; height: 28px; border-radius: 50%; background: radial-gradient(circle at 35% 35%, #a98b5b 0%, #5d4c32 60%, #332a1b 100%); box-shadow: 0 0 0 1px rgba(245,241,232,0.10), 0 2px 12px rgba(180,90,60,0.30); flex-shrink: 0; }
+        .ns-name { font-family: -apple-system, "SF Pro Display", "Helvetica Neue", system-ui, sans-serif; font-size: 18px !important; font-weight: 300 !important; letter-spacing: 0.02em !important; color: #f5f1e8 !important; text-transform: none !important; margin: 0 !important; }
+        .ns-name sup { font-size: 0.55em; font-weight: 300; margin-left: 1px; }
+        .ns-nav { display: flex; gap: 32px; align-items: center; list-style: none; padding: 0; margin: 0; }
+        .ns-nav a, .ns-nav button { font-family: -apple-system, "SF Pro Text", system-ui, sans-serif; font-size: 15px !important; font-weight: 400 !important; color: #f5f1e8 !important; text-decoration: none !important; background: none !important; border: 0 !important; cursor: pointer; padding: 0 !important; transition: color 200ms; letter-spacing: 0 !important; text-transform: none !important; }
+        .ns-nav a:hover, .ns-nav button:hover { color: #ffffff !important; }
+        @media (max-width: 820px) { .ns-header { padding: 14px 18px; } .ns-nav { gap: 16px; } .ns-nav a, .ns-nav button { font-size: 13px !important; } }
+        @media (max-width: 760px) {
+          .ns-header { flex-wrap: wrap; }
+          .ns-nav { display: none !important; flex-basis: 100%; flex-direction: column; align-items: flex-start; gap: 6px; padding: 14px 0 4px; }
+          .ns-nav.open { display: flex !important; }
+          .ns-nav a, .ns-nav button { padding: 10px 0 !important; border-bottom: 1px solid rgba(245,241,232,0.08); width: 100%; text-align: left; }
+          .ns-nav a:nth-child(n+5), .ns-nav button:nth-child(n+5) { display: block !important; }
+          .ns-header .mobile-toggle { display: flex !important; }
+        }
+        @media (min-width: 761px) {
+          .ns-header .mobile-toggle { display: none !important; }
+        }
+        .ns-modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.78); z-index: 200; align-items: center; justify-content: center; padding: 24px; backdrop-filter: blur(6px); }
+        .ns-modal.show { display: flex; }
+        .ns-modal-card { max-width: 460px; width: 100%; background: #141414 !important; border: 1px solid rgba(245,241,232,0.14); border-radius: 6px; padding: 28px 30px 30px; position: relative; }
+        .ns-modal-card .close-x { position: absolute; top: 12px; right: 14px; width: 30px; height: 30px; background: none; border: 1px solid rgba(245,241,232,0.18); color: rgba(245,241,232,0.6) !important; border-radius: 50%; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; }
+        .ns-modal-card .close-x:hover { color: #ffffff !important; border-color: #ffffff; }
+        .ns-modal-card h3 { font-family: -apple-system, "SF Pro Display", system-ui; font-weight: 300 !important; font-size: 22px !important; margin: 0 0 6px !important; color: #f5f1e8 !important; }
+        .ns-modal-card .sub { color: rgba(245,241,232,0.65) !important; font-size: 13px; margin: 0 0 22px; }
+        .ns-actions { display: flex; flex-direction: column; gap: 10px; }
+        .ns-action { display: flex; align-items: center; gap: 14px; padding: 14px 16px; background: rgba(245,241,232,0.04) !important; border: 1px solid rgba(245,241,232,0.12) !important; color: #f5f1e8 !important; text-decoration: none !important; cursor: pointer; transition: all 200ms; font: inherit; text-align: left; }
+        .ns-action:hover { background: rgba(245,241,232,0.08) !important; border-color: #d4b683 !important; }
+        .ns-action .ico { width: 32px; height: 32px; border-radius: 50%; background: rgba(212,182,131,0.12); display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
+        .ns-action .txt { flex: 1; }
+        .ns-action .txt b { display: block; font-weight: 500; font-size: 14px; color: #f5f1e8 !important; }
+        .ns-action .txt span { font-size: 12px; color: rgba(245,241,232,0.55) !important; }
+
+        /* ─── FINAL CONTRAST PASS — kill remaining gold-solid + white-island defects ─── */
+        /* Replace all gold-fill accents with off-white (Gucci-aesthetic, no DW gold solids) */
+        .new-badge, .new-arrivals-pill,
+        .color-filter-btn.active,
+        .drapery-btn, .sample-btn-chip, .cb-cta {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        .new-badge:hover, .new-arrivals-pill:hover,
+        .color-filter-btn.active:hover,
+        .drapery-btn:hover, .sample-btn-chip:hover, .cb-cta:hover {
+          background: #fff !important;
+          color: #0a0a0a !important;
+        }
+        /* Gold accents stay only as edge color (links, glyphs) — not fills */
+        a { color: #d4b683; }
+        a:hover { color: #f5d97a; }
+        /* Authorized-dealer footer line — small caps tracked, muted ink, no gold pill */
+        .authorized, .authorized-dealer p {
+          background: transparent !important;
+          color: rgba(245,241,232,0.5) !important;
+          font-size: 10px !important;
+          letter-spacing: 0.22em !important;
+          text-transform: uppercase !important;
+          padding: 0 !important;
+          border: none !important;
+          margin-top: 14px !important;
+        }
+        /* Kill any straggler white bg in info-card / sample-related cards */
+        .info-card, .info-card-link, .care-highlight, .feature-card, .spec-item {
+          background-color: rgba(245,241,232,0.04) !important;
+          border-color: rgba(245,241,232,0.12) !important;
+        }
+        /* Ensure modal content stays readable — Steve's earlier sweep made it #141414 with white text */
+        .modal-content { background: #141414 !important; color: #f5f1e8 !important; }
+        .modal-content * { color: #f5f1e8 !important; }
+        .modal-content input, .modal-content textarea, .modal-content select {
+          background: rgba(245,241,232,0.05) !important;
+          color: #f5f1e8 !important;
+          border-color: rgba(245,241,232,0.2) !important;
+        }
+        .modal-content label { color: rgba(245,241,232,0.6) !important; }
+        /* Force the wide-tracked NOVASUEDE wordmark to stay white */
+        .ns-wordmark, .ns-wordmark sup { color: #f5f1e8 !important; }
+
+        /* ─── Modal-internal contrast (post-QA defects) ─── */
+        /* Backdrop covers full viewport */
+        .modal { width: 100vw !important; height: 100vh !important; left: 0 !important; top: 0 !important; background: rgba(0, 0, 0, 0.78) !important; backdrop-filter: blur(6px); }
+        /* Chip — flip from white-on-white island to dark card */
+        .request-chip {
+          background: rgba(245, 241, 232, 0.06) !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.18) !important;
+          border-radius: 4px !important;
+        }
+        .request-chip * { color: #f5f1e8 !important; }
+        .request-chip .chip-swatch {
+          /* swatch dot ALWAYS displays the inline-style hex from JS — fight any sweep */
+          border: 1px solid rgba(0, 0, 0, 0.4) !important;
+        }
+        /* + Add to request — hairline white-border on transparent (no gold) */
+        .add-to-request-btn {
+          background: transparent !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.6) !important;
+          border-radius: 0 !important;
+          padding: 12px 22px !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 400 !important;
+        }
+        .add-to-request-btn:hover {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        /* Hex caption visible */
+        .preview-hex, #colorPreviewHex {
+          display: block !important;
+          color: rgba(245, 241, 232, 0.55) !important;
+          font-family: ui-monospace, "SF Mono", Menlo, monospace !important;
+          font-size: 11px !important;
+          margin-top: 4px !important;
+          letter-spacing: 0.04em !important;
+          text-transform: lowercase !important;
+        }
+        /* Color preview name — stays single, prominent */
+        #colorPreviewName {
+          color: #f5f1e8 !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 500 !important;
+          display: block !important;
+          margin-top: 12px !important;
+        }
+
+        /* ─── Mobile hamburger nav (replaces the overflow at <760px) ─── */
+        @media (max-width: 760px) {
+          header .nav-container { flex-wrap: wrap; }
+          header nav { display: none; flex-basis: 100%; flex-direction: column; gap: 6px; padding: 16px 0 6px; }
+          header nav.open { display: flex; }
+          header nav a { padding: 10px 0; border-bottom: 1px solid rgba(245,241,232,0.1); }
+          header .mobile-toggle {
+            display: flex !important;
+            flex-direction: column;
+            gap: 5px;
+            background: transparent;
+            border: 0;
+            cursor: pointer;
+            padding: 8px;
+          }
+          header .mobile-toggle span {
+            width: 22px; height: 1.5px;
+            background: #f5f1e8;
+            display: block;
+          }
+        }
+        @media (min-width: 761px) {
+          header .mobile-toggle { display: none !important; }
+        }
+
+    </style>
+<style id="ns-gold-kill">
+    /* novasuede: kill gold-solid fills, off-white instead. Edge color stays gold. */
+    .new-badge, .new-arrivals-pill,
+    .color-filter-btn.active, .drapery-btn,
+    .sample-btn-chip, .cb-cta {
+      background: #f5f1e8 !important;
+      color: #0a0a0a !important;
+      border-color: #f5f1e8 !important;
+    }
+    .new-badge:hover, .new-arrivals-pill:hover,
+    .color-filter-btn.active:hover, .drapery-btn:hover,
+    .sample-btn-chip:hover, .cb-cta:hover {
+      background: #fff !important;
+      color: #0a0a0a !important;
+    }
+  </style>
+<header class="ns-header">
+        <a href="/" class="ns-brand" aria-label="Home">
+            <span class="ns-dot"></span>
+            <span class="ns-name">Heritage Atelier</span>
+        </a>
+        <nav class="ns-nav" id="nsPrimaryNav" aria-label="Primary">
+            <a href="/">Home</a>
+            <a href="/about">About</a>
+            <button type="button" onclick="nsContactOpen()">Contact</button>
+        </nav>
+        <button type="button" class="mobile-toggle" aria-label="Toggle menu" aria-controls="nsPrimaryNav" aria-expanded="false" onclick="nsToggleNav(this)">
+            <span></span><span></span><span></span>
+        </button>
+    </header>
+
+<div class="ns-modal" id="nsContactModal" role="dialog" aria-modal="true" aria-labelledby="nsContactTitle" onclick="if(event.target===this)nsContactClose()">
+        <div class="ns-modal-card">
+            <button type="button" class="close-x" onclick="nsContactClose()" aria-label="Close">×</button>
+            <h3 id="nsContactTitle">How can we help?</h3>
+            <p class="sub">Trade-account replies within one business day.</p>
+            <div class="ns-actions">
+                <a class="ns-action" href="#contact" onclick="nsContactClose()"><span class="ico">📋</span><div class="txt"><b>Get a Quote</b><span>Project specs → priced estimate</span></div></a>
+                <a class="ns-action" href="#contact" onclick="nsContactClose();openModal();"><span class="ico">📦</span><div class="txt"><b>Order a Sample</b><span>Free swatch to your shop</span></div></a>
+                <a class="ns-action" href="mailto:info@novasuede.com?subject=Novasuede%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@novasuede.com</span></div></a>
+                <a class="ns-action" href="tel:888-373-4564"><span class="ico">📞</span><div class="txt"><b>Call Us</b><span>(888) 373-4564 · M–F, 9–5 PT</span></div></a>
+            </div>
+        </div>
+    </div>
+<script>
+  function nsContactOpen() { var m = document.getElementById('nsContactModal'); if (m) m.classList.add('show'); }
+  function nsContactClose() { var m = document.getElementById('nsContactModal'); if (m) m.classList.remove('show'); }
+  function nsToggleNav(btn) {
+    var nav = document.getElementById('nsPrimaryNav');
+    if (!nav) return;
+    var open = nav.classList.toggle('open');
+    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
+  }
+  document.addEventListener('keydown', function(e){ if (e.key === 'Escape') nsContactClose(); });
+</script>
+
+
+
+
+
+<header>
+  <button class="h-link" onclick="dwmOpen('Contact')" aria-label="Contact"><svg class="h-icon" viewBox="0 0 24 24"><path d="M3 7h18M3 12h18M3 17h18"/></svg><span>Contact</span></button>
+  <button class="theme-toggle" id="theme-toggle" aria-label="Theme toggle">☾</button>
+</header>
+
+<section class="cinema">
+  <div class="cinema-bg" id="heroBg"></div>
+  <div class="corner-mark">Trade-Grade</div>
+  <div class="center-mark">Hospitality Wallpaper</div>
+  <div class="meta-line">Hotel · Restaurant · Spa · Class A<span class="num" id="heroNum"></span></div>
+  <a class="enter" href="#shop">Enter <svg viewBox="0 0 24 12" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M0 6h22M16 1l6 5-6 5"/></svg></a>
+</section>
+
+
+<section class="section" id="ideas">
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">New this week</h2>
+    <div class="rail" id="railNewest"></div>
+  </div>
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">Curated picks</h2>
+    <div class="rail" id="railCurated"></div>
+  </div>
+</section>
+
+<section class="section" id="shop">
+  <div class="section-header">
+    <div>
+      <div class="section-eyebrow">The Collection</div>
+      <h2 class="section-title"><span class="accent" id="totalCount">—</span> Patterns.</h2>
+    </div>
+    <div class="section-meta">Hotel · Restaurant · Spa · Class A</div>
+  </div>
+
+  <div class="filters" id="facets">
+    <button class="chip active" data-facet="all">All</button>
+  </div>
+
+  <div class="density">
+    <label>Sort</label>
+    <select id="sortSelect" aria-label="Sort products" style="background:transparent;color:inherit;border:1px solid var(--line,rgba(255,255,255,.2));font:inherit;font-size:11px;letter-spacing:.10em;text-transform:uppercase;padding:4px 8px;cursor:pointer;outline:none;margin-right:14px">
+      <option value="newest">Newest</option>
+      <option value="color">Color</option>
+      <option value="style">Style</option>
+      <option value="sku">SKU A→Z</option>
+      <option value="title">Title A→Z</option>
+      <option value="price-asc">Price ↑</option>
+      <option value="price-desc">Price ↓</option>
+    </select>
+    <label>Grid</label>
+    <input type="range" id="densitySlider" min="4" max="12" step="1" value="6" aria-label="Grid columns">
+    <span class="ct" id="densityLabel">6 cols</span>
+    <div class="search">
+      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-5.5-5.5"/></svg>
+      <input type="text" id="searchInput" placeholder="Search by pattern, color…" autocomplete="off">
+    </div>
+  </div>
+
+  <div class="stat-line" id="statLine">Loading…</div>
+  <div class="grid" id="grid"></div>
+  <div class="loading" id="loading">Loading more…</div>
+  <div class="sentinel" id="sentinel"></div>
+</section>
+
+<footer>
+  <div class="footer-grid">
+    <div>
+      <div class="footer-brand">Heritage Atelier</div>
+      <p class="footer-text">Heritage Atelier — real samples ship free.</p>
+      <p class="footer-text" style="margin-top:14px;font-size:11px;letter-spacing:0.18em;text-transform:uppercase;font-weight:600;color:var(--paper);opacity:0.7"><a href="/about" style="color:inherit;text-decoration:none;border-bottom:1px solid var(--accent)">About →</a></p>
+    </div>
+    <div class="footer-col">
+      <h4>Aesthetic</h4>
+      <div id="footerFacets"></div>
+    </div>
+    <div class="footer-col">
+      <h4>Trade</h4>
+      <button onclick="dwmOpen('Inquiry')">Project Inquiry</button>
+      <button onclick="dwmOpen('Sample')">Request Sample</button>
+      <button onclick="dwmOpen('Contact')">Contact</button>
+    </div>
+  
+    <div class="footer-col">
+      <h4>Social</h4>
+      <a class="fb-link" href="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings" target="_blank" rel="noopener">Facebook</a>
+    </div>
+  </div>
+  <div class="footer-bottom">
+    <span>hospitalitywallpaper.com · Heritage Atelier</span>
+    <span><a href="mailto:info@hospitalitywallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@hospitalitywallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "hospitalitywallpaper";
+  const NICHES = [
+    ['silkwallpaper','Silk','mat'],['silkwallcoverings','Silk W/C','mat'],['linenwallpaper','Linen','mat'],
+    ['jutewallpaper','Jute','mat'],['raffiawallcoverings','Raffia W/C','mat'],['raffiawalls','Raffia Walls','mat'],
+    ['corkwallcovering','Cork','mat'],['fabricwallpaper','Fabric','mat'],['textilewallpaper','Textile','mat'],
+    ['metallicwallpaper','Metallic','mat'],['silverleafwallpaper','Silver Leaf','mat'],['vinylwallpaper','Vinyl','mat'],
+    ['micawallpaper','Mica','mat'],['madagascarwallpaper','Madagascar','mat'],['mylarwallpaper','Mylar','mat'],
+    ['suedewallpaper','Suede','mat'],
+    ['1800swallpaper','1800s','dec'],['1890swallpaper','1890s','dec'],['1900swallpaper','1900s','dec'],
+    ['1920swallpaper','1920s','dec'],['1930swallpaper','1930s','dec'],['1940swallpaper','1940s','dec'],
+    ['1950swallpaper','1950s','dec'],['1960swallpaper','1960s','dec'],['1970swallpaper','1970s','dec'],
+    ['1980swallpaper','1980s','dec'],['retrowalls','Retro','dec'],['wallpapersback','W. Back','dec'],
+    ['agedwallpaper','Aged','cra'],['handcraftedwallpaper','Handcrafted','cra'],['museumwallpaper','Museum','cra'],
+    ['restorationwallpaper','Restoration','cra'],['pastelwallpaper','Pastel','cra'],['glitterwalls','Glitter','cra'],
+    ['greenwallcoverings','Green','cra'],['naturalwallcoverings','Natural','cra'],['saloonwallpaper','Saloon','cra'],
+    ['contractwallpaper','Contract','use'],['hotelwallcoverings','Hotel','use'],['hospitalitywallpaper','Hospitality','use'],
+    ['healthcarewallpaper','Healthcare','use'],['restaurantwallpaper','Restaurant','use'],['architecturalwallcoverings','Architectural','use']
+  ];
+  const COLOR = { mat:'#c9b687', dec:'#b86a4a', cra:'#6b8e6f', use:'#4a6b8e' };
+  const W = 1080, H = 200, BANDS = ['mat','dec','cra','use'];
+  const groups = { mat:[], dec:[], cra:[], use:[] };
+  for (const n of NICHES) groups[n[2]].push(n);
+  const svg = document.getElementById('miniConst');
+  if (!svg) return;
+  const bandW = W / BANDS.length;
+  let nodes = '';
+  BANDS.forEach((band, bi) => {
+    const list = groups[band];
+    const cx = bi * bandW + bandW / 2;
+    list.forEach((n, i) => {
+      const t = list.length === 1 ? 0.5 : i / (list.length - 1);
+      // deterministic jitter per slug
+      let h = 0; for (let k = 0; k < n[0].length; k++) h = (h * 31 + n[0].charCodeAt(k)) | 0;
+      const jx = ((h & 0xff) / 255 - 0.5) * (bandW * 0.5);
+      const jy = (((h >> 8) & 0xff) / 255 - 0.5) * 6;  // tightened from 14 → 6 to prevent same-band collisions (16 mat nodes / 144px = 9px spacing)
+      const x = cx + jx, y = 28 + t * (H - 56) + jy;
+      const isCurrent = n[0] === SLUG;
+      const r = isCurrent ? 8 : 4;
+      const op = isCurrent ? 1 : 0.55;
+      nodes += `<g class="mc-node" data-slug="${n[0]}" data-label="${n[1]}" style="cursor:pointer">
+        <circle cx="${x}" cy="${y}" r="${r}" fill="url(#dna-${band})" fill-opacity="${op}" stroke="${COLOR[band]}" stroke-opacity="${isCurrent?1:0.7}" stroke-width="${isCurrent?2:1}">
+          <title>${n[1]} — ${n[0]}.com</title>
+        </circle>
+        ${isCurrent ? `<circle cx="${x}" cy="${y}" r="${r+5}" fill="none" stroke="${COLOR[band]}" stroke-opacity="0.4" stroke-width="1"><animate attributeName="r" values="${r+5};${r+12};${r+5}" dur="2.4s" repeatCount="indefinite"/><animate attributeName="stroke-opacity" values="0.4;0;0.4" dur="2.4s" repeatCount="indefinite"/></circle>` : ''}
+      </g>`;
+    });
+  });
+  // append nodes after defs
+  svg.insertAdjacentHTML('beforeend', nodes);
+  svg.querySelectorAll('.mc-node').forEach(n => {
+    n.addEventListener('mouseenter', () => n.querySelector('circle').setAttribute('fill-opacity', '1'));
+    n.addEventListener('mouseleave', e => {
+      const isCurrent = n.dataset.slug === SLUG;
+      n.querySelector('circle').setAttribute('fill-opacity', isCurrent ? '1' : '0.55');
+    });
+    n.addEventListener('click', () => window.open('https://' + n.dataset.slug + '.com', '_blank'));
+  });
+})();
+</script>
+
+<script>
+const state = { q:'', facet:'all', page:1, pages:1, total:0, loading:false, exhausted:false };
+const LABELS = {"all":"All"};
+
+function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c])); }
+// Image-URL allowlist: only DW Shopify CDN + designerwallcoverings.com (defends against XSS via crafted products.json)
+function safeImg(u) { return /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(u || '') ? u : '/hero-bg.jpg'; }
+function cardHTML(p) {
+  const eager = state.page === 1;
+  return '<img loading="' + (eager ? 'eager' : 'lazy') + '"' + (eager ? ' fetchpriority="high"' : '') + ' src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+    + '<div class="overlay">'
+    + '<div class="pat">' + escAttr(p.pattern_name || p.title) + '</div>'
+    + '<div class="ven">' + escAttr((p.vendor || '').replace(/-/g, ' ')) + '</div>'
+    + '<div class="actions">'
+    + '<button class="sample-btn" onclick="event.stopPropagation();dwmOpen(\'Sample\',' + JSON.stringify({sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}).replace(/"/g,'&quot;') + ')">Sample</button>'
+    + '</div></div>';
+}
+
+async function loadFacets() {
+  let f;
+  try {
+    const r = await fetch('/api/facets');
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    f = await r.json();
+  } catch (e) { console.error('loadFacets failed:', e); return; }
+  const el = document.getElementById('facets');
+  for (const [k, v] of Object.entries(f.aesthetics).sort((a,b) => b[1] - a[1])) {
+    const b = document.createElement('button');
+    b.className = 'chip'; b.dataset.facet = k;
+    b.innerHTML = (LABELS[k] || k) + ' <span style="opacity:.55;font-weight:500;margin-left:4px">' + v + '</span>';
+    el.appendChild(b);
+  }
+  el.addEventListener('click', e => {
+    if (e.target.tagName !== 'BUTTON') return;
+    document.querySelectorAll('#facets button').forEach(b => b.classList.remove('active'));
+    e.target.classList.add('active');
+    state.facet = e.target.dataset.facet;
+    resetGrid();
+  });
+  document.getElementById('totalCount').textContent = f.total;
+  document.getElementById('footerStat').textContent = f.total + ' patterns · live archive';
+  // Footer aesthetic links
+  const footerEl = document.getElementById('footerFacets');
+  for (const [k] of Object.entries(f.aesthetics)) {
+    const b = document.createElement('button');
+    b.textContent = LABELS[k] || k;
+    b.onclick = () => { state.facet = k; resetGrid(); document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === k)); document.getElementById('shop').scrollIntoView({behavior:'smooth'}); };
+    footerEl.appendChild(b);
+  }
+}
+
+function resetGrid() {
+  state.page = 1; state.exhausted = false;
+  document.getElementById('grid').innerHTML = '';
+  document.getElementById('loading').textContent = 'Loading…';
+  loadGridPage();
+}
+
+async function loadGridPage() {
+  if (state.loading || state.exhausted) return;
+  state.loading = true;
+  const params = new URLSearchParams({ page:state.page, limit:24 });
+  if (state.q) params.set('q', state.q);
+  if (state.facet !== 'all') params.set('aesthetic', state.facet);
+  let data;
+  try {
+    const r = await fetch('/api/products?' + params);
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    data = await r.json();
+  } catch (e) {
+    console.error('loadGridPage failed:', e);
+    document.getElementById('loading').textContent = '— offline — refresh to retry —';
+    state.loading = false;
+    return;
+  }
+  state.total = data.total; state.pages = data.pages;
+
+  if (state.page === 1) {
+    document.getElementById('statLine').textContent = data.total + ' patterns · ' + (state.facet === 'all' ? 'all aesthetics' : (LABELS[state.facet] || state.facet)) + (state.q ? ' · matching "' + state.q + '"' : '');
+  }
+  const grid = document.getElementById('grid');
+  for (const p of data.items) {
+    const a = document.createElement('a');
+    a.className = 'card'; a.href = '#'; a.onclick = (e) => { e.preventDefault(); dwmOpen('Sample',{sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}); };
+    a.innerHTML = cardHTML(p);
+    grid.appendChild(a);
+  }
+  if (state.page >= state.pages || data.items.length === 0) {
+    state.exhausted = true;
+    document.getElementById('loading').textContent = state.total > 0 ? '— end of archive · ' + state.total + ' patterns —' : '';
+  } else state.page++;
+  state.loading = false;
+}
+
+const io = new IntersectionObserver(es => { for (const e of es) if (e.isIntersecting) loadGridPage(); }, { rootMargin:'600px 0px' });
+io.observe(document.getElementById('sentinel'));
+
+document.getElementById('searchInput').addEventListener('input', e => {
+  state.q = e.target.value.trim();
+  clearTimeout(window._t);
+  window._t = setTimeout(resetGrid, 220);
+});
+
+// Density slider
+const slider = document.getElementById('densitySlider');
+const dlabel = document.getElementById('densityLabel');
+function setDensity(n) {
+  document.documentElement.style.setProperty('--cols', n);
+  dlabel.textContent = n + ' cols';
+  try { localStorage.setItem('hosp_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('hosp_theme_density') || '6');
+if (savedDensity >= 4 && savedDensity <= 12) { slider.value = savedDensity; setDensity(savedDensity); }
+
+// Theme toggle
+const tb = document.getElementById('theme-toggle');
+function setTheme(t){ document.documentElement.dataset.theme = t; try { localStorage.setItem('hosp_theme', t); } catch(e){} tb.textContent = t === 'dark' ? '☾' : '☀'; }
+setTheme(document.documentElement.dataset.theme || 'light');
+tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
+
+loadFacets();
+loadGridPage();
+</script>
+<!-- ============================================================
+     DW UNIVERSAL CONTACT MODULE — fashion-house UX
+     Inject before </body> in every DW-family sister site.
+     Self-contained: CSS + 4 modals + JS submission handlers.
+     Uses host site's CSS vars (--bg, --fg, --gold, --rule).
+     ============================================================ -->
+<style>
+  /* === MODAL BASE === */
+  .dwm{position:fixed;inset:0;background:rgba(0,0,0,0.78);display:none;align-items:center;justify-content:center;z-index:9999;padding:24px;overflow-y:auto}
+  .dwm.open{display:flex}
+  .dwm-box{background:var(--bg);border:1px solid var(--rule);max-width:520px;width:100%;padding:36px 32px;position:relative;max-height:90vh;overflow-y:auto;animation:dwm-in 0.25s ease}
+  @keyframes dwm-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
+  .dwm-box h3{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-weight:400;font-size:32px;line-height:1.05;margin-bottom:6px;color:var(--fg);letter-spacing:-0.01em}
+  .dwm-box .sub{color:var(--muted);font-size:12px;letter-spacing:0.16em;text-transform:uppercase;margin-bottom:24px;font-weight:500}
+  .dwm-close{position:absolute;top:18px;right:18px;background:transparent;border:0;color:var(--muted);font-size:24px;cursor:pointer;width:32px;height:32px;line-height:1;padding:0}
+  .dwm-close:hover{color:var(--gold)}
+  .dwm-preview{display:flex;gap:14px;align-items:center;padding:12px;background:var(--bg-soft);margin-bottom:18px}
+  .dwm-preview img{width:64px;height:64px;object-fit:cover}
+  .dwm-preview .pn{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-size:15px;line-height:1.2;color:var(--fg)}
+  .dwm-preview .pc{font-size:10px;letter-spacing:0.14em;text-transform:uppercase;color:var(--muted);margin-top:4px}
+  .dwm-field{margin-bottom:14px}
+  .dwm-field label{display:block;font-size:10px;letter-spacing:0.18em;text-transform:uppercase;color:var(--muted);margin-bottom:6px;font-weight:500}
+  .dwm-field input,.dwm-field textarea,.dwm-field select{width:100%;border:0;border-bottom:1px solid var(--rule);background:transparent;padding:8px 4px;font-size:14px;font-family:inherit;color:var(--fg);outline:none;transition:border-color 0.2s}
+  .dwm-field input:focus,.dwm-field textarea:focus{border-bottom-color:var(--gold)}
+  .dwm-field textarea{min-height:60px;resize:vertical}
+  .dwm-submit{background:transparent;color:var(--muted, #c9b89e);border:1px solid var(--muted, #c9b89e);padding:14px 28px;font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:700;cursor:pointer;width:100%;margin-top:8px;transition:background 0.15s, color 0.15s}
+  .dwm-submit:hover{background:var(--muted, #c9b89e);color:var(--bg, #000)}
+  
+  .dwm-submit:disabled{opacity:0.5;cursor:default}
+  .dwm-status{margin-top:14px;font-size:11px;letter-spacing:0.16em;text-transform:uppercase;text-align:center;display:none}
+  .dwm-status.ok{color:var(--sage);display:block}
+  .dwm-status.err{color:#e08070;display:block}
+  /* contact-options */
+  .dwm-options{display:flex;flex-direction:column;gap:10px}
+  .dwm-option{display:flex;align-items:center;gap:14px;padding:18px 20px;background:transparent;border:1px solid var(--rule);color:var(--fg);font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:600;cursor:pointer;text-decoration:none;transition:all 0.2s;text-align:left;width:100%}
+  .dwm-option:hover{border-color:var(--gold);color:var(--gold)}
+  .dwm-option svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.5;flex-shrink:0}
+  .dwm-option .lbl{flex:1;display:block}
+  .dwm-option .val{display:block;font-size:10px;letter-spacing:0.14em;text-transform:none;font-weight:500;opacity:0.65;margin-top:4px}
+
+/* graphics-loop pass 11: Ideas rails */
+#ideas { padding: 56px 24px 24px; max-width:1600px; margin:0 auto }
+#ideas .rail-block { margin-bottom:48px }
+#ideas .rail-eyebrow { font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:var(--muted, #888); margin-bottom:8px }
+#ideas .rail-title { font-size:clamp(22px,2.6vw,32px); font-weight:500; letter-spacing:-0.01em; margin:0 0 18px; color:var(--ink,#fff) }
+#ideas .rail { display:flex; gap:14px; overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:8px; scrollbar-width:none }
+#ideas .rail::-webkit-scrollbar { display:none }
+#ideas .rail-card { flex:0 0 240px; scroll-snap-align:start; cursor:pointer; transition:transform 0.2s }
+#ideas .rail-card:hover { transform:translateY(-3px) }
+#ideas .rail-card img { width:100%; aspect-ratio:1; object-fit:cover; display:block; background:var(--card,#222) }
+#ideas .rail-card .rc-title { font-size:13px; font-weight:500; color:var(--paper,#fff); padding:8px 0 2px; line-height:1.3 }
+#ideas .rail-card .rc-meta  { font-size:11px; color:var(--muted,#888); letter-spacing:0.06em }
+@media (max-width:720px) { #ideas .rail-card { flex:0 0 160px } }
+</style>
+
+<!-- Contact options modal -->
+<div class="dwm" id="dwmContact" onclick="if(event.target===this)dwmClose('Contact')">
+  <div class="dwm-box" style="max-width:440px">
+    <button class="dwm-close" onclick="dwmClose('Contact')" aria-label="Close">×</button>
+    <h3>Contact</h3>
+    <p class="sub" id="dwmContactSub">Three ways to reach us</p>
+    <div class="dwm-options">
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Inquiry')">
+        <svg viewBox="0 0 24 24"><path d="M4 4h16v12H7l-3 3z"/></svg>
+        <span class="lbl">Send an Inquiry<span class="val">Project name · scope · all the details</span></span>
+      </button>
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Sample')">
+        <svg viewBox="0 0 24 24"><rect x="4" y="6" width="16" height="14"/><path d="M4 10h16M9 6V3h6v3"/></svg>
+        <span class="lbl">Request a Sample<span class="val">Memo sample · ships free · 3–5 business days</span></span>
+      </button>
+      <a class="dwm-option" id="dwmContactEmailLink" href="mailto:info@hospitalitywallpaper.com">
+        <svg viewBox="0 0 24 24"><path d="M3 6h18v12H3z"/><path d="M3 6l9 7 9-7"/></svg>
+        <span class="lbl">Email Us<span class="val" id="dwmContactEmailLabel">info@hospitalitywallpaper.com</span></span>
+      </a>
+    </div>
+  </div>
+</div>
+
+<!-- Inquiry modal -->
+<div class="dwm" id="dwmInquiry" onclick="if(event.target===this)dwmClose('Inquiry')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Inquiry')" aria-label="Close">×</button>
+    <h3>Project Inquiry</h3>
+    <p class="sub">We'll respond within one business day</p>
+    <form id="dwmInquiryForm" onsubmit="return dwmSubmit(event,'inquiry')">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Phone</label><input type="tel" name="phone"></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Project Name</label><input type="text" name="projectName" required></div>
+      <div class="dwm-field"><label>Project Scope</label><textarea name="projectScope" placeholder="Square footage · room count · timeline" required></textarea></div>
+      <div class="dwm-field"><label>Additional Information</label><textarea name="message" placeholder="Patterns of interest, finish preferences, budget"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Inquiry</button>
+      <div class="dwm-status" id="dwmInquiryStatus"></div>
+    </form>
+  </div>
+</div>
+
+<!-- Sample-request modal -->
+<div class="dwm" id="dwmSample" onclick="if(event.target===this)dwmClose('Sample')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Sample')" aria-label="Close">×</button>
+    <h3>Request a Sample</h3>
+    <p class="sub">Memo sample · ships free · 3–5 business days</p>
+    <div class="dwm-preview" id="dwmSamplePreview" style="display:none">
+      <img id="dwmSampleImg" src="" alt="">
+      <div><div class="pn" id="dwmSampleName"></div><div class="pc" id="dwmSampleSku"></div></div>
+    </div>
+    <form id="dwmSampleForm" onsubmit="return dwmSubmit(event,'sample')">
+      <input type="hidden" name="sku" id="dwmSampleSkuInput">
+      <input type="hidden" name="title" id="dwmSampleTitleInput">
+      <input type="hidden" name="image_url" id="dwmSampleImageInput">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Shipping Address</label><input type="text" name="address" placeholder="Street" required></div>
+      <div class="dwm-field" style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:8px">
+        <input type="text" name="city" placeholder="City" required>
+        <input type="text" name="state" placeholder="State" required>
+        <input type="text" name="zip" placeholder="ZIP" required>
+      </div>
+      <div class="dwm-field"><label>Notes (optional)</label><textarea name="message" placeholder="Project, sq.ft., timing"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Sample Request</button>
+      <div class="dwm-status" id="dwmSampleStatus"></div>
+    </form>
+  </div>
+</div>
+
+<script>
+  // Universal modal control
+  function dwmOpen(name, opts){
+    document.getElementById('dwm' + name).classList.add('open');
+    document.body.style.overflow = 'hidden';
+    if (name === 'Sample' && opts) {
+      document.getElementById('dwmSamplePreview').style.display = 'flex';
+      document.getElementById('dwmSampleImg').src = opts.image_url || '';
+      document.getElementById('dwmSampleName').textContent = opts.title || '';
+      document.getElementById('dwmSampleSku').textContent = opts.sku || '';
+      document.getElementById('dwmSampleSkuInput').value = opts.sku || '';
+      document.getElementById('dwmSampleTitleInput').value = opts.title || '';
+      document.getElementById('dwmSampleImageInput').value = opts.image_url || '';
+    } else if (name === 'Sample') {
+      document.getElementById('dwmSamplePreview').style.display = 'none';
+      document.getElementById('dwmSampleSkuInput').value = '';
+      document.getElementById('dwmSampleTitleInput').value = '';
+      document.getElementById('dwmSampleImageInput').value = '';
+    }
+  }
+  function dwmClose(name){ document.getElementById('dwm'+name).classList.remove('open'); document.body.style.overflow=''; }
+
+  // Universal form submit — POSTs to /api/send-{kind}
+  async function dwmSubmit(e, kind) {
+    e.preventDefault();
+    const form = e.target;
+    const data = Object.fromEntries(new FormData(form).entries());
+    const btn = form.querySelector('.dwm-submit');
+    const status = form.querySelector('.dwm-status');
+    btn.disabled = true; const orig = btn.textContent; btn.textContent = 'Sending…';
+    status.className = 'dwm-status';
+    try {
+      const r = await fetch('/api/send-' + kind, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(data) });
+      if (!r.ok) throw new Error('HTTP '+r.status);
+      const j = await r.json();
+      status.textContent = kind === 'sample' ? 'Sample request sent — ships within 3–5 business days' : 'Inquiry sent — we respond within 1 business day';
+      status.className = 'dwm-status ok';
+      btn.textContent = 'Sent ✓';
+      setTimeout(() => { dwmClose(kind === 'sample' ? 'Sample' : 'Inquiry'); btn.disabled = false; btn.textContent = orig; status.className = 'dwm-status'; form.reset(); }, 2800);
+    } catch (err) {
+      status.textContent = 'Send failed — please email info@designerwallcoverings.com';
+      status.className = 'dwm-status err';
+      btn.disabled = false; btn.textContent = orig;
+    }
+    return false;
+  }
+
+  // Wire up "Memo samples ship free" badge in hero to open sample modal directly
+  document.querySelectorAll('.hero .badge, [data-open-sample]').forEach(el => {
+    el.style.cursor = 'pointer';
+    el.addEventListener('click', () => dwmOpen('Sample'));
+  });
+
+  // Wire nav "Trade" link to inquiry modal
+  document.querySelectorAll('nav a[href*="designerwallcoverings.com"]').forEach(a => {
+    a.removeAttribute('target');
+    a.removeAttribute('href');
+    a.style.cursor = 'pointer';
+    a.addEventListener('click', e => { e.preventDefault(); dwmOpen('Contact'); });
+  });
+
+  // Override product card clicks — open Sample modal pre-filled instead of redirecting to DW
+  document.addEventListener('click', e => {
+    const card = e.target.closest('.card, .rail-card');
+    if (!card) return;
+    if (card.tagName === 'A' && (card.getAttribute('href') || '').startsWith('/sample/')) {
+      e.preventDefault();
+      const img = card.querySelector('img');
+      const pat = card.querySelector('.pat');
+      const sku = card.getAttribute('href').replace('/sample/', '');
+      dwmOpen('Sample', {
+        sku,
+        title: pat ? pat.textContent.trim() : '',
+        image_url: img ? img.src : ''
+      });
+    }
+  }, true);
+// DW STANDARD: hero pulls from products.json[0].image_url so dw-collections-viewer
+// drag-drop / hero-pin updates the live front page on next deploy.
+// Always upgrades to the largest Shopify variant (strips _NxN size suffix) so
+// the full-page hero stays sharp.
+// DW STANDARD: hero rotates through top-20 NEWEST products on each visit
+// (novasuede.com pattern). Fetches /api/products?limit=100, sorts by created_at desc,
+// takes the freshest 20, picks one per visit via localStorage counter.
+// Falls back to static /hero-bg.jpg on any error.
+(async function rotateHero() {
+  try {
+    const r = await fetch('/api/products?limit=100');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || [])
+      .filter(p => p && p.image_url && /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(p.image_url))
+      .sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')))
+      .slice(0, 20);
+    if (!items.length) return;
+    let visits = 0;
+    try {
+      visits = parseInt(localStorage.getItem('hero_visits') || '0', 10) || 0;
+      localStorage.setItem('hero_visits', String(visits + 1));
+    } catch(e) {}
+    const pick = items[visits % items.length];
+    // Strip _NxN size suffix to get the largest CDN variant
+    const url = pick.image_url.replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+    const bg = document.getElementById('heroBg') || document.getElementById('cinemaBg');
+    if (bg) bg.style.backgroundImage = "url('" + url + "')";
+  } catch (e) {}
+})();
+
+
+// DW STANDARD sort-select wire-up (added by fleet patcher)
+(function(){
+  const sortSel = document.getElementById('sortSelect');
+  if (!sortSel) return;
+  const KEY = location.hostname.replace(/\./g, '_') + '_sort';
+  const saved = localStorage.getItem(KEY);
+  if (saved) { try { sortSel.value = saved; } catch(e){} }
+  if (typeof state !== 'undefined') state.sort = sortSel.value;
+  sortSel.addEventListener('change', e => {
+    const v = e.target.value;
+    try { localStorage.setItem(KEY, v); } catch(e){}
+    if (typeof state !== 'undefined') state.sort = v;
+    if (typeof resetGrid === 'function') resetGrid();
+    else location.reload();
+  });
+})();
+
+// graphics-loop pass 11: hydrate Ideas rails from /api/products
+(async function hydrateIdeas() {
+  try {
+    const r = await fetch('/api/products?limit=80');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || []).filter(p => p && p.image_url);
+    if (!items.length) return;
+    const sorted = [...items].sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')));
+    const newest = sorted.slice(0, 12);
+    // Curated = deterministic offset slice (every 5th item starting at idx 3) for variety
+    const curated = items.filter((_, i) => i % 5 === 3).slice(0, 12);
+    function card(p) {
+      const url = (p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+      return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle || p.sku) + '">' +
+        '<img src="' + url + '" alt="' + (p.title || '').replace(/"/g, '&quot;') + '" loading="lazy">' +
+        '<div class="rc-title">' + ((p.title || '').split('|')[0] || '').trim() + '</div>' +
+        '<div class="rc-meta">' + (p.vendor || '') + '</div>' +
+      '</a>';
+    }
+    const r1 = document.getElementById('railNewest');
+    const r2 = document.getElementById('railCurated');
+    if (r1) r1.innerHTML = newest.map(card).join('');
+    if (r2) r2.innerHTML = curated.map(card).join('');
+  } catch(e) {}
+})();
+</script>
+
+</body>
+</html>
diff --git a/public/index.html.bak.nspropagate.1778226815149 b/public/index.html.bak.nspropagate.1778226815149
new file mode 100644
index 0000000..6db524b
--- /dev/null
+++ b/public/index.html.bak.nspropagate.1778226815149
@@ -0,0 +1,966 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<!-- Google tag (gtag.js) -->
+<script async src="https://www.googletagmanager.com/gtag/js?id=G-XM0936TL4N"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-XM0936TL4N');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Heritage Atelier — hospitality, the British way.</title>
+<meta name="description" content="Heritage Atelier is a curated atelier dedicated entirely to hospitality. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#FFF">
+<link rel="canonical" href="https://hospitalitywallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600&family=Inter:wght@300;400;500&display=swap" rel="stylesheet">
+<link rel="preload" as="image" href="/hero-bg.jpg" fetchpriority="high">
+<script type="application/ld+json">
+{
+  "@context": "https://schema.org",
+  "@type": "Organization",
+  "name": "Heritage Atelier",
+  "url": "https://hospitalitywallpaper.com/",
+  "email": "info@hospitalitywallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #FFF;
+  --paper: #000;
+  --muted: #8B7866;
+  --line: #A47C5A;
+  --accent: #A47C5A;
+  --bg-soft: #A47C5A;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #000;
+  --paper: #FFF;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #A47C5A;
+  --bg-soft: #2a1f15;
+}
+* { margin:0; padding:0; box-sizing:border-box }
+html { scroll-behavior:smooth }
+body { font-family:'Inter', sans-serif; color:var(--paper); -webkit-font-smoothing:antialiased; background:var(--bg); min-height:100vh; overflow-x:hidden }
+/* DW-FASHION-TEMPLATE-OVERRIDE */
+.section-title .accent, .footer-brand, .center-mark, h1, h2, h3 { font-family:'Cormorant Garamond', Georgia, serif !important; font-weight:500 !important;  }
+
+/* ===== Auto-hide header ===== */
+header { position:fixed; top:0; left:0; right:0; display:flex; justify-content:space-between; align-items:center; padding:22px 32px; z-index:100; background:rgba(0,0,0,0.55); backdrop-filter:blur(10px); border-bottom:1px solid var(--line); transition:transform .3s }
+.h-link { display:flex; align-items:center; gap:10px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); text-decoration:none; cursor:pointer; background:transparent; border:0 }
+.h-link:hover { opacity:0.7 }
+.h-icon { width:18px; height:18px; stroke:currentColor; fill:none; stroke-width:1.5 }
+
+/* ===== Cinema hero ===== */
+.cinema { position:relative; height:100vh; width:100%; overflow:hidden }
+.cinema-bg { position:absolute; inset:0; background-size:cover; background-position:center; background-image:url('/hero-bg.jpg') }
+.cinema-bg::after { content:""; position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.75) 100%) }
+.corner-mark { position:absolute; top:24px; left:32px; font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:#fff; text-shadow:0 1px 3px rgba(0,0,0,0.55), 0 0 1px rgba(0,0,0,0.4); z-index:5 }
+.corner-mark::before { content:"◆ "; margin-right:6px }
+.center-mark { position:absolute; top:clamp(80px,12vh,140px); left:50%; transform:translateX(-50%); font-size:clamp(28px,4vw,56px); font-weight:500; letter-spacing:0.18em; text-transform:uppercase; text-align:center; color:#fff; text-shadow:0 2px 8px rgba(0,0,0,0.65), 0 0 1px rgba(0,0,0,0.5); z-index:5 }
+.center-mark .tm { font-size:14px; vertical-align:super; opacity:0.7; margin-left:0.2em }
+.center-mark .sub { display:block; font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400; font-size:0.4em; letter-spacing:0.04em; text-transform:none; margin-top:14px; opacity:0.85 }
+.meta-line { position:absolute; bottom:32px; left:32px; font-size:10px; letter-spacing:0.28em; text-transform:uppercase; font-weight:700; color:#fff; z-index:5; opacity:0.85 }
+.meta-line .num { font-size:12px; display:block; margin-top:4px; letter-spacing:0.05em }
+.enter { position:absolute; bottom:32px; right:32px; display:flex; align-items:center; gap:14px; font-size:11px; letter-spacing:0.36em; text-transform:uppercase; font-weight:700; color:#fff; text-decoration:none; padding-bottom:6px; border-bottom:1px solid #fff; transition:gap 0.25s; z-index:5 }
+.enter:hover { gap:22px }
+.enter svg { width:24px; height:12px }
+
+/* ===== Section ===== */
+.section { padding:96px 32px }
+.section-header { display:flex; justify-content:space-between; align-items:flex-end; flex-wrap:wrap; gap:24px; margin-bottom:32px; padding-bottom:24px; border-bottom:1px solid var(--line) }
+.section-title { font-size:clamp(36px,5vw,64px); font-weight:300; letter-spacing:-0.02em; line-height:1 }
+.section-title .accent { color: var(--accent); font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400 }
+.section-eyebrow { font-size:10px; letter-spacing:0.4em; text-transform:uppercase; font-weight:700; color:var(--muted); margin-bottom:16px }
+.section-meta { font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:600; color:var(--muted); text-align:right; line-height:1.6 }
+
+/* ===== Filter bar ===== */
+.filters { display:flex; gap:8px; align-items:center; margin-bottom:18px; flex-wrap:wrap }
+.chip { padding:8px 16px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); background:transparent; border:1px solid var(--line); cursor:pointer; transition:all 0.2s; font-family:inherit }
+.chip:hover { border-color:var(--paper) }
+.chip.active { background:var(--paper); color:var(--bg); border-color:var(--paper) }
+.search { flex:0 1 280px; margin-left:auto; display:flex; align-items:center; gap:10px; border-bottom:1px solid var(--line); padding:6px 0 }
+.search input { flex:1; background:transparent; border:0; color:var(--paper); font-family:inherit; font-size:13px; outline:none; letter-spacing:0.04em }
+.search input::placeholder { color:var(--muted) }
+.search svg { width:16px; height:16px; stroke:var(--muted); fill:none; stroke-width:1.5 }
+
+/* ===== Grid-density slider ===== */
+.density { display:flex; align-items:center; gap:14px; padding:6px 0; margin-bottom:24px }
+.density label { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--muted) }
+.density input[type=range] { flex:1; max-width:240px; -webkit-appearance:none; appearance:none; height:1px; background:var(--line); outline:none }
+.density input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50% }
+.density input[type=range]::-moz-range-thumb { width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50%; border:0 }
+.density .ct { font-size:11px; color:var(--muted); letter-spacing:0.18em; text-transform:uppercase; font-weight:600; min-width:80px }
+
+/* ===== Stats line ===== */
+.stat-line { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:600; color:var(--muted); margin-bottom:24px }
+
+/* ===== Product grid (novasuede pattern: flush grid + slide-up overlay) ===== */
+.grid { display:grid; grid-template-columns:repeat(var(--cols), 1fr); gap:0 }
+.card { position:relative; aspect-ratio:1/1.15; cursor:pointer; overflow:hidden; border:1px solid var(--bg); transition:transform 0.4s cubic-bezier(0.2,0.8,0.2,1); background:var(--bg-soft) }
+.card:hover { transform:scale(1.04); z-index:5 }
+.card img { width:100%; height:100%; object-fit:cover; display:block; transition:transform 0.4s ease }
+.card .overlay { position:absolute; left:0; right:0; bottom:0; padding:20px 16px 14px; background:linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.85) 100%); transform:translateY(48%); opacity:0.85; transition:transform 0.3s ease, opacity 0.3s ease }
+.card:hover .overlay { transform:translateY(0); opacity:1 }
+.card .pat { font-size:13px; font-weight:600; letter-spacing:0.02em; color:#fff; line-height:1.25; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
+.card .ven { font-size:9px; letter-spacing:0.18em; text-transform:uppercase; color:#fff; opacity:0.7; font-weight:500; margin-top:4px }
+.card .actions { margin-top:10px; display:flex; gap:6px }
+.card .sample-btn { flex:1; padding:7px 10px; background:#fff; color:#000; font-family:inherit; font-size:10px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; border:0; cursor:pointer; text-align:center; transition:all 0.2s }
+.card .sample-btn:hover { background:var(--accent); color:#fff }
+
+@media (max-width:1024px) { .grid { grid-template-columns:repeat(min(var(--cols), 4), 1fr) } }
+@media (max-width:720px) { .grid { grid-template-columns:repeat(2, 1fr) } .density { display:none } }
+
+.sentinel { height:1px }
+.loading { text-align:center; color:var(--muted); padding:32px; font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700 }
+
+/* ===== Footer ===== */
+footer { padding:64px 32px 32px; border-top:1px solid var(--line); margin-top:32px }
+.footer-grid { max-width:1400px; margin:0 auto; display:grid; grid-template-columns:2fr 1fr 1fr 1fr; gap:48px; margin-bottom:48px }
+.footer-brand { font-size:24px; font-weight:300; letter-spacing:0.32em; text-transform:uppercase; margin-bottom:12px }
+.footer-text { font-size:13px; line-height:1.6; color:var(--muted); max-width:380px }
+.footer-col h4 { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--paper); margin-bottom:18px }
+.footer-col a { display:block; font-size:13px; color:var(--muted); text-decoration:none; margin-bottom:8px; transition:color 0.2s; cursor:pointer; background:transparent; border:0; font-family:inherit; padding:0; text-align:left }
+.footer-col a:hover { color:var(--accent) }
+.footer-bottom { max-width:1400px; margin:0 auto; padding-top:24px; border-top:1px solid var(--line); display:flex; justify-content:space-between; flex-wrap:wrap; gap:16px; font-size:11px; letter-spacing:0.18em; text-transform:uppercase; color:var(--muted) }
+
+@media (max-width:720px) {
+  .corner-mark, .meta-line, .enter { font-size:10px }
+  .center-mark { font-size:24px; letter-spacing:0.12em; top:clamp(60px,9vh,90px) }
+  .section, footer { padding-left:20px; padding-right:20px }
+  .footer-grid { grid-template-columns:1fr; gap:32px }
+  .search { margin-left:0; flex:1 1 100% }
+}
+
+.theme-toggle { background:transparent; border:1px solid var(--line); width:32px; height:32px; cursor:pointer; color:var(--paper); display:inline-flex; align-items:center; justify-content:center; font-size:14px; line-height:1; transition:all .15s; padding:0 }
+.theme-toggle:hover { border-color:var(--accent); color:var(--accent) }
+
+/* ===== WCAG 2.4.7 — keyboard focus indicators ===== */
+/* Strictly :focus-visible so mouse clicks do NOT show the ring */
+a:focus-visible,
+button:focus-visible,
+input:focus-visible,
+select:focus-visible,
+textarea:focus-visible,
+[tabindex]:focus-visible {
+  outline: 2px solid var(--accent);
+  outline-offset: 2px;
+}
+</style>
+<script>
+(function(){ try { var t = localStorage.getItem('hosp_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://hospitalitywallpaper.com/">
+<meta property="og:title" content="Hospitality Wallpaper">
+<meta property="og:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta property="og:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Hospitality Wallpaper">
+<meta property="article:publisher" content="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:title" content="Hospitality Wallpaper">
+<meta name="twitter:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta name="twitter:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<!-- graphics-loop pass 13: footer + fb -->
+</head>
+<body>
+<style id="ns-header-modal-styles">
+        .ns-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; padding: 18px 36px; background: rgba(10,10,10,0.92) !important; backdrop-filter: blur(8px); border-bottom: 1px solid rgba(245,241,232,0.06); }
+        .ns-brand { display: inline-flex; align-items: center; gap: 14px; text-decoration: none; }
+        .ns-dot { width: 28px; height: 28px; border-radius: 50%; background: radial-gradient(circle at 35% 35%, #a98b5b 0%, #5d4c32 60%, #332a1b 100%); box-shadow: 0 0 0 1px rgba(245,241,232,0.10), 0 2px 12px rgba(180,90,60,0.30); flex-shrink: 0; }
+        .ns-name { font-family: -apple-system, "SF Pro Display", "Helvetica Neue", system-ui, sans-serif; font-size: 18px !important; font-weight: 300 !important; letter-spacing: 0.02em !important; color: #f5f1e8 !important; text-transform: none !important; margin: 0 !important; }
+        .ns-name sup { font-size: 0.55em; font-weight: 300; margin-left: 1px; }
+        .ns-nav { display: flex; gap: 32px; align-items: center; list-style: none; padding: 0; margin: 0; }
+        .ns-nav a, .ns-nav button { font-family: -apple-system, "SF Pro Text", system-ui, sans-serif; font-size: 15px !important; font-weight: 400 !important; color: #f5f1e8 !important; text-decoration: none !important; background: none !important; border: 0 !important; cursor: pointer; padding: 0 !important; transition: color 200ms; letter-spacing: 0 !important; text-transform: none !important; }
+        .ns-nav a:hover, .ns-nav button:hover { color: #ffffff !important; }
+        @media (max-width: 820px) { .ns-header { padding: 14px 18px; } .ns-nav { gap: 16px; } .ns-nav a, .ns-nav button { font-size: 13px !important; } }
+        @media (max-width: 760px) {
+          .ns-header { flex-wrap: wrap; }
+          .ns-nav { display: none !important; flex-basis: 100%; flex-direction: column; align-items: flex-start; gap: 6px; padding: 14px 0 4px; }
+          .ns-nav.open { display: flex !important; }
+          .ns-nav a, .ns-nav button { padding: 10px 0 !important; border-bottom: 1px solid rgba(245,241,232,0.08); width: 100%; text-align: left; }
+          .ns-nav a:nth-child(n+5), .ns-nav button:nth-child(n+5) { display: block !important; }
+          .ns-header .mobile-toggle { display: flex !important; }
+        }
+        @media (min-width: 761px) {
+          .ns-header .mobile-toggle { display: none !important; }
+        }
+        .ns-modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.78); z-index: 200; align-items: center; justify-content: center; padding: 24px; backdrop-filter: blur(6px); }
+        .ns-modal.show { display: flex; }
+        .ns-modal-card { max-width: 460px; width: 100%; background: #141414 !important; border: 1px solid rgba(245,241,232,0.14); border-radius: 6px; padding: 28px 30px 30px; position: relative; }
+        .ns-modal-card .close-x { position: absolute; top: 12px; right: 14px; width: 30px; height: 30px; background: none; border: 1px solid rgba(245,241,232,0.18); color: rgba(245,241,232,0.6) !important; border-radius: 50%; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; }
+        .ns-modal-card .close-x:hover { color: #ffffff !important; border-color: #ffffff; }
+        .ns-modal-card h3 { font-family: -apple-system, "SF Pro Display", system-ui; font-weight: 300 !important; font-size: 22px !important; margin: 0 0 6px !important; color: #f5f1e8 !important; }
+        .ns-modal-card .sub { color: rgba(245,241,232,0.65) !important; font-size: 13px; margin: 0 0 22px; }
+        .ns-actions { display: flex; flex-direction: column; gap: 10px; }
+        .ns-action { display: flex; align-items: center; gap: 14px; padding: 14px 16px; background: rgba(245,241,232,0.04) !important; border: 1px solid rgba(245,241,232,0.12) !important; color: #f5f1e8 !important; text-decoration: none !important; cursor: pointer; transition: all 200ms; font: inherit; text-align: left; }
+        .ns-action:hover { background: rgba(245,241,232,0.08) !important; border-color: #d4b683 !important; }
+        .ns-action .ico { width: 32px; height: 32px; border-radius: 50%; background: rgba(212,182,131,0.12); display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
+        .ns-action .txt { flex: 1; }
+        .ns-action .txt b { display: block; font-weight: 500; font-size: 14px; color: #f5f1e8 !important; }
+        .ns-action .txt span { font-size: 12px; color: rgba(245,241,232,0.55) !important; }
+
+        /* ─── FINAL CONTRAST PASS — kill remaining gold-solid + white-island defects ─── */
+        /* Replace all gold-fill accents with off-white (Gucci-aesthetic, no DW gold solids) */
+        .new-badge, .new-arrivals-pill,
+        .color-filter-btn.active,
+        .drapery-btn, .sample-btn-chip, .cb-cta {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        .new-badge:hover, .new-arrivals-pill:hover,
+        .color-filter-btn.active:hover,
+        .drapery-btn:hover, .sample-btn-chip:hover, .cb-cta:hover {
+          background: #fff !important;
+          color: #0a0a0a !important;
+        }
+        /* Gold accents stay only as edge color (links, glyphs) — not fills */
+        a { color: #d4b683; }
+        a:hover { color: #f5d97a; }
+        /* Authorized-dealer footer line — small caps tracked, muted ink, no gold pill */
+        .authorized, .authorized-dealer p {
+          background: transparent !important;
+          color: rgba(245,241,232,0.5) !important;
+          font-size: 10px !important;
+          letter-spacing: 0.22em !important;
+          text-transform: uppercase !important;
+          padding: 0 !important;
+          border: none !important;
+          margin-top: 14px !important;
+        }
+        /* Kill any straggler white bg in info-card / sample-related cards */
+        .info-card, .info-card-link, .care-highlight, .feature-card, .spec-item {
+          background-color: rgba(245,241,232,0.04) !important;
+          border-color: rgba(245,241,232,0.12) !important;
+        }
+        /* Ensure modal content stays readable — Steve's earlier sweep made it #141414 with white text */
+        .modal-content { background: #141414 !important; color: #f5f1e8 !important; }
+        .modal-content * { color: #f5f1e8 !important; }
+        .modal-content input, .modal-content textarea, .modal-content select {
+          background: rgba(245,241,232,0.05) !important;
+          color: #f5f1e8 !important;
+          border-color: rgba(245,241,232,0.2) !important;
+        }
+        .modal-content label { color: rgba(245,241,232,0.6) !important; }
+        /* Force the wide-tracked NOVASUEDE wordmark to stay white */
+        .ns-wordmark, .ns-wordmark sup { color: #f5f1e8 !important; }
+
+        /* ─── Modal-internal contrast (post-QA defects) ─── */
+        /* Backdrop covers full viewport */
+        .modal { width: 100vw !important; height: 100vh !important; left: 0 !important; top: 0 !important; background: rgba(0, 0, 0, 0.78) !important; backdrop-filter: blur(6px); }
+        /* Chip — flip from white-on-white island to dark card */
+        .request-chip {
+          background: rgba(245, 241, 232, 0.06) !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.18) !important;
+          border-radius: 4px !important;
+        }
+        .request-chip * { color: #f5f1e8 !important; }
+        .request-chip .chip-swatch {
+          /* swatch dot ALWAYS displays the inline-style hex from JS — fight any sweep */
+          border: 1px solid rgba(0, 0, 0, 0.4) !important;
+        }
+        /* + Add to request — hairline white-border on transparent (no gold) */
+        .add-to-request-btn {
+          background: transparent !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.6) !important;
+          border-radius: 0 !important;
+          padding: 12px 22px !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 400 !important;
+        }
+        .add-to-request-btn:hover {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        /* Hex caption visible */
+        .preview-hex, #colorPreviewHex {
+          display: block !important;
+          color: rgba(245, 241, 232, 0.55) !important;
+          font-family: ui-monospace, "SF Mono", Menlo, monospace !important;
+          font-size: 11px !important;
+          margin-top: 4px !important;
+          letter-spacing: 0.04em !important;
+          text-transform: lowercase !important;
+        }
+        /* Color preview name — stays single, prominent */
+        #colorPreviewName {
+          color: #f5f1e8 !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 500 !important;
+          display: block !important;
+          margin-top: 12px !important;
+        }
+
+        /* ─── Mobile hamburger nav (replaces the overflow at <760px) ─── */
+        @media (max-width: 760px) {
+          header .nav-container { flex-wrap: wrap; }
+          header nav { display: none; flex-basis: 100%; flex-direction: column; gap: 6px; padding: 16px 0 6px; }
+          header nav.open { display: flex; }
+          header nav a { padding: 10px 0; border-bottom: 1px solid rgba(245,241,232,0.1); }
+          header .mobile-toggle {
+            display: flex !important;
+            flex-direction: column;
+            gap: 5px;
+            background: transparent;
+            border: 0;
+            cursor: pointer;
+            padding: 8px;
+          }
+          header .mobile-toggle span {
+            width: 22px; height: 1.5px;
+            background: #f5f1e8;
+            display: block;
+          }
+        }
+        @media (min-width: 761px) {
+          header .mobile-toggle { display: none !important; }
+        }
+
+    </style>
+<style id="ns-gold-kill">
+    /* novasuede: kill gold-solid fills, off-white instead. Edge color stays gold. */
+    .new-badge, .new-arrivals-pill,
+    .color-filter-btn.active, .drapery-btn,
+    .sample-btn-chip, .cb-cta {
+      background: #f5f1e8 !important;
+      color: #0a0a0a !important;
+      border-color: #f5f1e8 !important;
+    }
+    .new-badge:hover, .new-arrivals-pill:hover,
+    .color-filter-btn.active:hover, .drapery-btn:hover,
+    .sample-btn-chip:hover, .cb-cta:hover {
+      background: #fff !important;
+      color: #0a0a0a !important;
+    }
+  </style>
+<header class="ns-header">
+        <a href="/" class="ns-brand" aria-label="Home">
+            <span class="ns-dot"></span>
+            <span class="ns-name">Heritage Atelier</span>
+        </a>
+        <nav class="ns-nav" id="nsPrimaryNav" aria-label="Primary">
+            <a href="/">Home</a>
+            <a href="/about">About</a>
+            <button type="button" onclick="nsContactOpen()">Contact</button>
+        </nav>
+        <button type="button" class="mobile-toggle" aria-label="Toggle menu" aria-controls="nsPrimaryNav" aria-expanded="false" onclick="nsToggleNav(this)">
+            <span></span><span></span><span></span>
+        </button>
+    </header>
+
+<div class="ns-modal" id="nsContactModal" role="dialog" aria-modal="true" aria-labelledby="nsContactTitle" onclick="if(event.target===this)nsContactClose()">
+        <div class="ns-modal-card">
+            <button type="button" class="close-x" onclick="nsContactClose()" aria-label="Close">×</button>
+            <h3 id="nsContactTitle">How can we help?</h3>
+            <p class="sub">Trade-account replies within one business day.</p>
+            <div class="ns-actions">
+                <a class="ns-action" href="#contact" onclick="nsContactClose()"><span class="ico">📋</span><div class="txt"><b>Get a Quote</b><span>Project specs → priced estimate</span></div></a>
+                <a class="ns-action" href="#contact" onclick="nsContactClose();openModal();"><span class="ico">📦</span><div class="txt"><b>Order a Sample</b><span>Free swatch to your shop</span></div></a>
+                <a class="ns-action" href="mailto:info@hospitalitywallpaper.com?subject=Heritage%20Atelier%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@hospitalitywallpaper.com</span></div></a>
+                <a class="ns-action" href="tel:888-373-4564"><span class="ico">📞</span><div class="txt"><b>Call Us</b><span>(888) 373-4564 · M–F, 9–5 PT</span></div></a>
+            </div>
+        </div>
+    </div>
+<script>
+  function nsContactOpen() { var m = document.getElementById('nsContactModal'); if (m) m.classList.add('show'); }
+  function nsContactClose() { var m = document.getElementById('nsContactModal'); if (m) m.classList.remove('show'); }
+  function nsToggleNav(btn) {
+    var nav = document.getElementById('nsPrimaryNav');
+    if (!nav) return;
+    var open = nav.classList.toggle('open');
+    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
+  }
+  document.addEventListener('keydown', function(e){ if (e.key === 'Escape') nsContactClose(); });
+</script>
+
+
+
+
+
+
+
+<header>
+  <button class="h-link" onclick="dwmOpen('Contact')" aria-label="Contact"><svg class="h-icon" viewBox="0 0 24 24"><path d="M3 7h18M3 12h18M3 17h18"/></svg><span>Contact</span></button>
+  <button class="theme-toggle" id="theme-toggle" aria-label="Theme toggle">☾</button>
+</header>
+
+<section class="cinema">
+  <div class="cinema-bg" id="heroBg"></div>
+  <div class="corner-mark">Trade-Grade</div>
+  <div class="center-mark">Hospitality Wallpaper</div>
+  <div class="meta-line">Hotel · Restaurant · Spa · Class A<span class="num" id="heroNum"></span></div>
+  <a class="enter" href="#shop">Enter <svg viewBox="0 0 24 12" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M0 6h22M16 1l6 5-6 5"/></svg></a>
+</section>
+
+
+<section class="section" id="ideas">
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">New this week</h2>
+    <div class="rail" id="railNewest"></div>
+  </div>
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">Curated picks</h2>
+    <div class="rail" id="railCurated"></div>
+  </div>
+</section>
+
+<section class="section" id="shop">
+  <div class="section-header">
+    <div>
+      <div class="section-eyebrow">The Collection</div>
+      <h2 class="section-title"><span class="accent" id="totalCount">—</span> Patterns.</h2>
+    </div>
+    <div class="section-meta">Hotel · Restaurant · Spa · Class A</div>
+  </div>
+
+  <div class="filters" id="facets">
+    <button class="chip active" data-facet="all">All</button>
+  </div>
+
+  <div class="density">
+    <label>Sort</label>
+    <select id="sortSelect" aria-label="Sort products" style="background:transparent;color:inherit;border:1px solid var(--line,rgba(255,255,255,.2));font:inherit;font-size:11px;letter-spacing:.10em;text-transform:uppercase;padding:4px 8px;cursor:pointer;outline:none;margin-right:14px">
+      <option value="newest">Newest</option>
+      <option value="color">Color</option>
+      <option value="style">Style</option>
+      <option value="sku">SKU A→Z</option>
+      <option value="title">Title A→Z</option>
+      <option value="price-asc">Price ↑</option>
+      <option value="price-desc">Price ↓</option>
+    </select>
+    <label>Grid</label>
+    <input type="range" id="densitySlider" min="4" max="12" step="1" value="6" aria-label="Grid columns">
+    <span class="ct" id="densityLabel">6 cols</span>
+    <div class="search">
+      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-5.5-5.5"/></svg>
+      <input type="text" id="searchInput" placeholder="Search by pattern, color…" autocomplete="off">
+    </div>
+  </div>
+
+  <div class="stat-line" id="statLine">Loading…</div>
+  <div class="grid" id="grid"></div>
+  <div class="loading" id="loading">Loading more…</div>
+  <div class="sentinel" id="sentinel"></div>
+</section>
+
+<footer>
+  <div class="footer-grid">
+    <div>
+      <div class="footer-brand">Heritage Atelier</div>
+      <p class="footer-text">Heritage Atelier — real samples ship free.</p>
+      <p class="footer-text" style="margin-top:14px;font-size:11px;letter-spacing:0.18em;text-transform:uppercase;font-weight:600;color:var(--paper);opacity:0.7"><a href="/about" style="color:inherit;text-decoration:none;border-bottom:1px solid var(--accent)">About →</a></p>
+    </div>
+    <div class="footer-col">
+      <h4>Aesthetic</h4>
+      <div id="footerFacets"></div>
+    </div>
+    <div class="footer-col">
+      <h4>Trade</h4>
+      <button onclick="dwmOpen('Inquiry')">Project Inquiry</button>
+      <button onclick="dwmOpen('Sample')">Request Sample</button>
+      <button onclick="dwmOpen('Contact')">Contact</button>
+    </div>
+  
+    <div class="footer-col">
+      <h4>Social</h4>
+      <a class="fb-link" href="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings" target="_blank" rel="noopener">Facebook</a>
+    </div>
+  </div>
+  <div class="footer-bottom">
+    <span>hospitalitywallpaper.com · Heritage Atelier</span>
+    <span><a href="mailto:info@hospitalitywallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@hospitalitywallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "hospitalitywallpaper";
+  const NICHES = [
+    ['silkwallpaper','Silk','mat'],['silkwallcoverings','Silk W/C','mat'],['linenwallpaper','Linen','mat'],
+    ['jutewallpaper','Jute','mat'],['raffiawallcoverings','Raffia W/C','mat'],['raffiawalls','Raffia Walls','mat'],
+    ['corkwallcovering','Cork','mat'],['fabricwallpaper','Fabric','mat'],['textilewallpaper','Textile','mat'],
+    ['metallicwallpaper','Metallic','mat'],['silverleafwallpaper','Silver Leaf','mat'],['vinylwallpaper','Vinyl','mat'],
+    ['micawallpaper','Mica','mat'],['madagascarwallpaper','Madagascar','mat'],['mylarwallpaper','Mylar','mat'],
+    ['suedewallpaper','Suede','mat'],
+    ['1800swallpaper','1800s','dec'],['1890swallpaper','1890s','dec'],['1900swallpaper','1900s','dec'],
+    ['1920swallpaper','1920s','dec'],['1930swallpaper','1930s','dec'],['1940swallpaper','1940s','dec'],
+    ['1950swallpaper','1950s','dec'],['1960swallpaper','1960s','dec'],['1970swallpaper','1970s','dec'],
+    ['1980swallpaper','1980s','dec'],['retrowalls','Retro','dec'],['wallpapersback','W. Back','dec'],
+    ['agedwallpaper','Aged','cra'],['handcraftedwallpaper','Handcrafted','cra'],['museumwallpaper','Museum','cra'],
+    ['restorationwallpaper','Restoration','cra'],['pastelwallpaper','Pastel','cra'],['glitterwalls','Glitter','cra'],
+    ['greenwallcoverings','Green','cra'],['naturalwallcoverings','Natural','cra'],['saloonwallpaper','Saloon','cra'],
+    ['contractwallpaper','Contract','use'],['hotelwallcoverings','Hotel','use'],['hospitalitywallpaper','Hospitality','use'],
+    ['healthcarewallpaper','Healthcare','use'],['restaurantwallpaper','Restaurant','use'],['architecturalwallcoverings','Architectural','use']
+  ];
+  const COLOR = { mat:'#c9b687', dec:'#b86a4a', cra:'#6b8e6f', use:'#4a6b8e' };
+  const W = 1080, H = 200, BANDS = ['mat','dec','cra','use'];
+  const groups = { mat:[], dec:[], cra:[], use:[] };
+  for (const n of NICHES) groups[n[2]].push(n);
+  const svg = document.getElementById('miniConst');
+  if (!svg) return;
+  const bandW = W / BANDS.length;
+  let nodes = '';
+  BANDS.forEach((band, bi) => {
+    const list = groups[band];
+    const cx = bi * bandW + bandW / 2;
+    list.forEach((n, i) => {
+      const t = list.length === 1 ? 0.5 : i / (list.length - 1);
+      // deterministic jitter per slug
+      let h = 0; for (let k = 0; k < n[0].length; k++) h = (h * 31 + n[0].charCodeAt(k)) | 0;
+      const jx = ((h & 0xff) / 255 - 0.5) * (bandW * 0.5);
+      const jy = (((h >> 8) & 0xff) / 255 - 0.5) * 6;  // tightened from 14 → 6 to prevent same-band collisions (16 mat nodes / 144px = 9px spacing)
+      const x = cx + jx, y = 28 + t * (H - 56) + jy;
+      const isCurrent = n[0] === SLUG;
+      const r = isCurrent ? 8 : 4;
+      const op = isCurrent ? 1 : 0.55;
+      nodes += `<g class="mc-node" data-slug="${n[0]}" data-label="${n[1]}" style="cursor:pointer">
+        <circle cx="${x}" cy="${y}" r="${r}" fill="url(#dna-${band})" fill-opacity="${op}" stroke="${COLOR[band]}" stroke-opacity="${isCurrent?1:0.7}" stroke-width="${isCurrent?2:1}">
+          <title>${n[1]} — ${n[0]}.com</title>
+        </circle>
+        ${isCurrent ? `<circle cx="${x}" cy="${y}" r="${r+5}" fill="none" stroke="${COLOR[band]}" stroke-opacity="0.4" stroke-width="1"><animate attributeName="r" values="${r+5};${r+12};${r+5}" dur="2.4s" repeatCount="indefinite"/><animate attributeName="stroke-opacity" values="0.4;0;0.4" dur="2.4s" repeatCount="indefinite"/></circle>` : ''}
+      </g>`;
+    });
+  });
+  // append nodes after defs
+  svg.insertAdjacentHTML('beforeend', nodes);
+  svg.querySelectorAll('.mc-node').forEach(n => {
+    n.addEventListener('mouseenter', () => n.querySelector('circle').setAttribute('fill-opacity', '1'));
+    n.addEventListener('mouseleave', e => {
+      const isCurrent = n.dataset.slug === SLUG;
+      n.querySelector('circle').setAttribute('fill-opacity', isCurrent ? '1' : '0.55');
+    });
+    n.addEventListener('click', () => window.open('https://' + n.dataset.slug + '.com', '_blank'));
+  });
+})();
+</script>
+
+<script>
+const state = { q:'', facet:'all', page:1, pages:1, total:0, loading:false, exhausted:false };
+const LABELS = {"all":"All"};
+
+function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c])); }
+// Image-URL allowlist: only DW Shopify CDN + designerwallcoverings.com (defends against XSS via crafted products.json)
+function safeImg(u) { return /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(u || '') ? u : '/hero-bg.jpg'; }
+function cardHTML(p) {
+  const eager = state.page === 1;
+  return '<img loading="' + (eager ? 'eager' : 'lazy') + '"' + (eager ? ' fetchpriority="high"' : '') + ' src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+    + '<div class="overlay">'
+    + '<div class="pat">' + escAttr(p.pattern_name || p.title) + '</div>'
+    + '<div class="ven">' + escAttr((p.vendor || '').replace(/-/g, ' ')) + '</div>'
+    + '<div class="actions">'
+    + '<button class="sample-btn" onclick="event.stopPropagation();dwmOpen(\'Sample\',' + JSON.stringify({sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}).replace(/"/g,'&quot;') + ')">Sample</button>'
+    + '</div></div>';
+}
+
+async function loadFacets() {
+  let f;
+  try {
+    const r = await fetch('/api/facets');
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    f = await r.json();
+  } catch (e) { console.error('loadFacets failed:', e); return; }
+  const el = document.getElementById('facets');
+  for (const [k, v] of Object.entries(f.aesthetics).sort((a,b) => b[1] - a[1])) {
+    const b = document.createElement('button');
+    b.className = 'chip'; b.dataset.facet = k;
+    b.innerHTML = (LABELS[k] || k) + ' <span style="opacity:.55;font-weight:500;margin-left:4px">' + v + '</span>';
+    el.appendChild(b);
+  }
+  el.addEventListener('click', e => {
+    if (e.target.tagName !== 'BUTTON') return;
+    document.querySelectorAll('#facets button').forEach(b => b.classList.remove('active'));
+    e.target.classList.add('active');
+    state.facet = e.target.dataset.facet;
+    resetGrid();
+  });
+  document.getElementById('totalCount').textContent = f.total;
+  document.getElementById('footerStat').textContent = f.total + ' patterns · live archive';
+  // Footer aesthetic links
+  const footerEl = document.getElementById('footerFacets');
+  for (const [k] of Object.entries(f.aesthetics)) {
+    const b = document.createElement('button');
+    b.textContent = LABELS[k] || k;
+    b.onclick = () => { state.facet = k; resetGrid(); document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === k)); document.getElementById('shop').scrollIntoView({behavior:'smooth'}); };
+    footerEl.appendChild(b);
+  }
+}
+
+function resetGrid() {
+  state.page = 1; state.exhausted = false;
+  document.getElementById('grid').innerHTML = '';
+  document.getElementById('loading').textContent = 'Loading…';
+  loadGridPage();
+}
+
+async function loadGridPage() {
+  if (state.loading || state.exhausted) return;
+  state.loading = true;
+  const params = new URLSearchParams({ page:state.page, limit:24 });
+  if (state.q) params.set('q', state.q);
+  if (state.facet !== 'all') params.set('aesthetic', state.facet);
+  let data;
+  try {
+    const r = await fetch('/api/products?' + params);
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    data = await r.json();
+  } catch (e) {
+    console.error('loadGridPage failed:', e);
+    document.getElementById('loading').textContent = '— offline — refresh to retry —';
+    state.loading = false;
+    return;
+  }
+  state.total = data.total; state.pages = data.pages;
+
+  if (state.page === 1) {
+    document.getElementById('statLine').textContent = data.total + ' patterns · ' + (state.facet === 'all' ? 'all aesthetics' : (LABELS[state.facet] || state.facet)) + (state.q ? ' · matching "' + state.q + '"' : '');
+  }
+  const grid = document.getElementById('grid');
+  for (const p of data.items) {
+    const a = document.createElement('a');
+    a.className = 'card'; a.href = '#'; a.onclick = (e) => { e.preventDefault(); dwmOpen('Sample',{sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}); };
+    a.innerHTML = cardHTML(p);
+    grid.appendChild(a);
+  }
+  if (state.page >= state.pages || data.items.length === 0) {
+    state.exhausted = true;
+    document.getElementById('loading').textContent = state.total > 0 ? '— end of archive · ' + state.total + ' patterns —' : '';
+  } else state.page++;
+  state.loading = false;
+}
+
+const io = new IntersectionObserver(es => { for (const e of es) if (e.isIntersecting) loadGridPage(); }, { rootMargin:'600px 0px' });
+io.observe(document.getElementById('sentinel'));
+
+document.getElementById('searchInput').addEventListener('input', e => {
+  state.q = e.target.value.trim();
+  clearTimeout(window._t);
+  window._t = setTimeout(resetGrid, 220);
+});
+
+// Density slider
+const slider = document.getElementById('densitySlider');
+const dlabel = document.getElementById('densityLabel');
+function setDensity(n) {
+  document.documentElement.style.setProperty('--cols', n);
+  dlabel.textContent = n + ' cols';
+  try { localStorage.setItem('hosp_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('hosp_theme_density') || '6');
+if (savedDensity >= 4 && savedDensity <= 12) { slider.value = savedDensity; setDensity(savedDensity); }
+
+// Theme toggle
+const tb = document.getElementById('theme-toggle');
+function setTheme(t){ document.documentElement.dataset.theme = t; try { localStorage.setItem('hosp_theme', t); } catch(e){} tb.textContent = t === 'dark' ? '☾' : '☀'; }
+setTheme(document.documentElement.dataset.theme || 'light');
+tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
+
+loadFacets();
+loadGridPage();
+</script>
+<!-- ============================================================
+     DW UNIVERSAL CONTACT MODULE — fashion-house UX
+     Inject before
+ </body> in every DW-family sister site.
+     Self-contained: CSS + 4 modals + JS submission handlers.
+     Uses host site's CSS vars (--bg, --fg, --gold, --rule).
+     ============================================================ -->
+<style>
+  /* === MODAL BASE === */
+  .dwm{position:fixed;inset:0;background:rgba(0,0,0,0.78);display:none;align-items:center;justify-content:center;z-index:9999;padding:24px;overflow-y:auto}
+  .dwm.open{display:flex}
+  .dwm-box{background:var(--bg);border:1px solid var(--rule);max-width:520px;width:100%;padding:36px 32px;position:relative;max-height:90vh;overflow-y:auto;animation:dwm-in 0.25s ease}
+  @keyframes dwm-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
+  .dwm-box h3{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-weight:400;font-size:32px;line-height:1.05;margin-bottom:6px;color:var(--fg);letter-spacing:-0.01em}
+  .dwm-box .sub{color:var(--muted);font-size:12px;letter-spacing:0.16em;text-transform:uppercase;margin-bottom:24px;font-weight:500}
+  .dwm-close{position:absolute;top:18px;right:18px;background:transparent;border:0;color:var(--muted);font-size:24px;cursor:pointer;width:32px;height:32px;line-height:1;padding:0}
+  .dwm-close:hover{color:var(--gold)}
+  .dwm-preview{display:flex;gap:14px;align-items:center;padding:12px;background:var(--bg-soft);margin-bottom:18px}
+  .dwm-preview img{width:64px;height:64px;object-fit:cover}
+  .dwm-preview .pn{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-size:15px;line-height:1.2;color:var(--fg)}
+  .dwm-preview .pc{font-size:10px;letter-spacing:0.14em;text-transform:uppercase;color:var(--muted);margin-top:4px}
+  .dwm-field{margin-bottom:14px}
+  .dwm-field label{display:block;font-size:10px;letter-spacing:0.18em;text-transform:uppercase;color:var(--muted);margin-bottom:6px;font-weight:500}
+  .dwm-field input,.dwm-field textarea,.dwm-field select{width:100%;border:0;border-bottom:1px solid var(--rule);background:transparent;padding:8px 4px;font-size:14px;font-family:inherit;color:var(--fg);outline:none;transition:border-color 0.2s}
+  .dwm-field input:focus,.dwm-field textarea:focus{border-bottom-color:var(--gold)}
+  .dwm-field textarea{min-height:60px;resize:vertical}
+  .dwm-submit{background:transparent;color:var(--muted, #c9b89e);border:1px solid var(--muted, #c9b89e);padding:14px 28px;font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:700;cursor:pointer;width:100%;margin-top:8px;transition:background 0.15s, color 0.15s}
+  .dwm-submit:hover{background:var(--muted, #c9b89e);color:var(--bg, #000)}
+  
+  .dwm-submit:disabled{opacity:0.5;cursor:default}
+  .dwm-status{margin-top:14px;font-size:11px;letter-spacing:0.16em;text-transform:uppercase;text-align:center;display:none}
+  .dwm-status.ok{color:var(--sage);display:block}
+  .dwm-status.err{color:#e08070;display:block}
+  /* contact-options */
+  .dwm-options{display:flex;flex-direction:column;gap:10px}
+  .dwm-option{display:flex;align-items:center;gap:14px;padding:18px 20px;background:transparent;border:1px solid var(--rule);color:var(--fg);font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:600;cursor:pointer;text-decoration:none;transition:all 0.2s;text-align:left;width:100%}
+  .dwm-option:hover{border-color:var(--gold);color:var(--gold)}
+  .dwm-option svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.5;flex-shrink:0}
+  .dwm-option .lbl{flex:1;display:block}
+  .dwm-option .val{display:block;font-size:10px;letter-spacing:0.14em;text-transform:none;font-weight:500;opacity:0.65;margin-top:4px}
+
+/* graphics-loop pass 11: Ideas rails */
+#ideas { padding: 56px 24px 24px; max-width:1600px; margin:0 auto }
+#ideas .rail-block { margin-bottom:48px }
+#ideas .rail-eyebrow { font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:var(--muted, #888); margin-bottom:8px }
+#ideas .rail-title { font-size:clamp(22px,2.6vw,32px); font-weight:500; letter-spacing:-0.01em; margin:0 0 18px; color:var(--ink,#fff) }
+#ideas .rail { display:flex; gap:14px; overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:8px; scrollbar-width:none }
+#ideas .rail::-webkit-scrollbar { display:none }
+#ideas .rail-card { flex:0 0 240px; scroll-snap-align:start; cursor:pointer; transition:transform 0.2s }
+#ideas .rail-card:hover { transform:translateY(-3px) }
+#ideas .rail-card img { width:100%; aspect-ratio:1; object-fit:cover; display:block; background:var(--card,#222) }
+#ideas .rail-card .rc-title { font-size:13px; font-weight:500; color:var(--paper,#fff); padding:8px 0 2px; line-height:1.3 }
+#ideas .rail-card .rc-meta  { font-size:11px; color:var(--muted,#888); letter-spacing:0.06em }
+@media (max-width:720px) { #ideas .rail-card { flex:0 0 160px } }
+</style>
+
+<!-- Contact options modal -->
+<div class="dwm" id="dwmContact" onclick="if(event.target===this)dwmClose('Contact')">
+  <div class="dwm-box" style="max-width:440px">
+    <button class="dwm-close" onclick="dwmClose('Contact')" aria-label="Close">×</button>
+    <h3>Contact</h3>
+    <p class="sub" id="dwmContactSub">Three ways to reach us</p>
+    <div class="dwm-options">
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Inquiry')">
+        <svg viewBox="0 0 24 24"><path d="M4 4h16v12H7l-3 3z"/></svg>
+        <span class="lbl">Send an Inquiry<span class="val">Project name · scope · all the details</span></span>
+      </button>
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Sample')">
+        <svg viewBox="0 0 24 24"><rect x="4" y="6" width="16" height="14"/><path d="M4 10h16M9 6V3h6v3"/></svg>
+        <span class="lbl">Request a Sample<span class="val">Memo sample · ships free · 3–5 business days</span></span>
+      </button>
+      <a class="dwm-option" id="dwmContactEmailLink" href="mailto:info@hospitalitywallpaper.com">
+        <svg viewBox="0 0 24 24"><path d="M3 6h18v12H3z"/><path d="M3 6l9 7 9-7"/></svg>
+        <span class="lbl">Email Us<span class="val" id="dwmContactEmailLabel">info@hospitalitywallpaper.com</span></span>
+      </a>
+    </div>
+  </div>
+</div>
+
+<!-- Inquiry modal -->
+<div class="dwm" id="dwmInquiry" onclick="if(event.target===this)dwmClose('Inquiry')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Inquiry')" aria-label="Close">×</button>
+    <h3>Project Inquiry</h3>
+    <p class="sub">We'll respond within one business day</p>
+    <form id="dwmInquiryForm" onsubmit="return dwmSubmit(event,'inquiry')">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Phone</label><input type="tel" name="phone"></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Project Name</label><input type="text" name="projectName" required></div>
+      <div class="dwm-field"><label>Project Scope</label><textarea name="projectScope" placeholder="Square footage · room count · timeline" required></textarea></div>
+      <div class="dwm-field"><label>Additional Information</label><textarea name="message" placeholder="Patterns of interest, finish preferences, budget"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Inquiry</button>
+      <div class="dwm-status" id="dwmInquiryStatus"></div>
+    </form>
+  </div>
+</div>
+
+<!-- Sample-request modal -->
+<div class="dwm" id="dwmSample" onclick="if(event.target===this)dwmClose('Sample')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Sample')" aria-label="Close">×</button>
+    <h3>Request a Sample</h3>
+    <p class="sub">Memo sample · ships free · 3–5 business days</p>
+    <div class="dwm-preview" id="dwmSamplePreview" style="display:none">
+      <img id="dwmSampleImg" src="" alt="">
+      <div><div class="pn" id="dwmSampleName"></div><div class="pc" id="dwmSampleSku"></div></div>
+    </div>
+    <form id="dwmSampleForm" onsubmit="return dwmSubmit(event,'sample')">
+      <input type="hidden" name="sku" id="dwmSampleSkuInput">
+      <input type="hidden" name="title" id="dwmSampleTitleInput">
+      <input type="hidden" name="image_url" id="dwmSampleImageInput">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Shipping Address</label><input type="text" name="address" placeholder="Street" required></div>
+      <div class="dwm-field" style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:8px">
+        <input type="text" name="city" placeholder="City" required>
+        <input type="text" name="state" placeholder="State" required>
+        <input type="text" name="zip" placeholder="ZIP" required>
+      </div>
+      <div class="dwm-field"><label>Notes (optional)</label><textarea name="message" placeholder="Project, sq.ft., timing"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Sample Request</button>
+      <div class="dwm-status" id="dwmSampleStatus"></div>
+    </form>
+  </div>
+</div>
+
+<script>
+  // Universal modal control
+  function dwmOpen(name, opts){
+    document.getElementById('dwm' + name).classList.add('open');
+    document.body.style.overflow = 'hidden';
+    if (name === 'Sample' && opts) {
+      document.getElementById('dwmSamplePreview').style.display = 'flex';
+      document.getElementById('dwmSampleImg').src = opts.image_url || '';
+      document.getElementById('dwmSampleName').textContent = opts.title || '';
+      document.getElementById('dwmSampleSku').textContent = opts.sku || '';
+      document.getElementById('dwmSampleSkuInput').value = opts.sku || '';
+      document.getElementById('dwmSampleTitleInput').value = opts.title || '';
+      document.getElementById('dwmSampleImageInput').value = opts.image_url || '';
+    } else if (name === 'Sample') {
+      document.getElementById('dwmSamplePreview').style.display = 'none';
+      document.getElementById('dwmSampleSkuInput').value = '';
+      document.getElementById('dwmSampleTitleInput').value = '';
+      document.getElementById('dwmSampleImageInput').value = '';
+    }
+  }
+  function dwmClose(name){ document.getElementById('dwm'+name).classList.remove('open'); document.body.style.overflow=''; }
+
+  // Universal form submit — POSTs to /api/send-{kind}
+  async function dwmSubmit(e, kind) {
+    e.preventDefault();
+    const form = e.target;
+    const data = Object.fromEntries(new FormData(form).entries());
+    const btn = form.querySelector('.dwm-submit');
+    const status = form.querySelector('.dwm-status');
+    btn.disabled = true; const orig = btn.textContent; btn.textContent = 'Sending…';
+    status.className = 'dwm-status';
+    try {
+      const r = await fetch('/api/send-' + kind, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(data) });
+      if (!r.ok) throw new Error('HTTP '+r.status);
+      const j = await r.json();
+      status.textContent = kind === 'sample' ? 'Sample request sent — ships within 3–5 business days' : 'Inquiry sent — we respond within 1 business day';
+      status.className = 'dwm-status ok';
+      btn.textContent = 'Sent ✓';
+      setTimeout(() => { dwmClose(kind === 'sample' ? 'Sample' : 'Inquiry'); btn.disabled = false; btn.textContent = orig; status.className = 'dwm-status'; form.reset(); }, 2800);
+    } catch (err) {
+      status.textContent = 'Send failed — please email info@designerwallcoverings.com';
+      status.className = 'dwm-status err';
+      btn.disabled = false; btn.textContent = orig;
+    }
+    return false;
+  }
+
+  // Wire up "Memo samples ship free" badge in hero to open sample modal directly
+  document.querySelectorAll('.hero .badge, [data-open-sample]').forEach(el => {
+    el.style.cursor = 'pointer';
+    el.addEventListener('click', () => dwmOpen('Sample'));
+  });
+
+  // Wire nav "Trade" link to inquiry modal
+  document.querySelectorAll('nav a[href*="designerwallcoverings.com"]').forEach(a => {
+    a.removeAttribute('target');
+    a.removeAttribute('href');
+    a.style.cursor = 'pointer';
+    a.addEventListener('click', e => { e.preventDefault(); dwmOpen('Contact'); });
+  });
+
+  // Override product card clicks — open Sample modal pre-filled instead of redirecting to DW
+  document.addEventListener('click', e => {
+    const card = e.target.closest('.card, .rail-card');
+    if (!card) return;
+    if (card.tagName === 'A' && (card.getAttribute('href') || '').startsWith('/sample/')) {
+      e.preventDefault();
+      const img = card.querySelector('img');
+      const pat = card.querySelector('.pat');
+      const sku = card.getAttribute('href').replace('/sample/', '');
+      dwmOpen('Sample', {
+        sku,
+        title: pat ? pat.textContent.trim() : '',
+        image_url: img ? img.src : ''
+      });
+    }
+  }, true);
+// DW STANDARD: hero pulls from products.json[0].image_url so dw-collections-viewer
+// drag-drop / hero-pin updates the live front page on next deploy.
+// Always upgrades to the largest Shopify variant (strips _NxN size suffix) so
+// the full-page hero stays sharp.
+// DW STANDARD: hero rotates through top-20 NEWEST products on each visit
+// (novasuede.com pattern). Fetches /api/products?limit=100, sorts by created_at desc,
+// takes the freshest 20, picks one per visit via localStorage counter.
+// Falls back to static /hero-bg.jpg on any error.
+(async function rotateHero() {
+  try {
+    const r = await fetch('/api/products?limit=100');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || [])
+      .filter(p => p && p.image_url && /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(p.image_url))
+      .sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')))
+      .slice(0, 20);
+    if (!items.length) return;
+    let visits = 0;
+    try {
+      visits = parseInt(localStorage.getItem('hero_visits') || '0', 10) || 0;
+      localStorage.setItem('hero_visits', String(visits + 1));
+    } catch(e) {}
+    const pick = items[visits % items.length];
+    // Strip _NxN size suffix to get the largest CDN variant
+    const url = pick.image_url.replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+    const bg = document.getElementById('heroBg') || document.getElementById('cinemaBg');
+    if (bg) bg.style.backgroundImage = "url('" + url + "')";
+  } catch (e) {}
+})();
+
+
+// DW STANDARD sort-select wire-up (added by fleet patcher)
+(function(){
+  const sortSel = document.getElementById('sortSelect');
+  if (!sortSel) return;
+  const KEY = location.hostname.replace(/\./g, '_') + '_sort';
+  const saved = localStorage.getItem(KEY);
+  if (saved) { try { sortSel.value = saved; } catch(e){} }
+  if (typeof state !== 'undefined') state.sort = sortSel.value;
+  sortSel.addEventListener('change', e => {
+    const v = e.target.value;
+    try { localStorage.setItem(KEY, v); } catch(e){}
+    if (typeof state !== 'undefined') state.sort = v;
+    if (typeof resetGrid === 'function') resetGrid();
+    else location.reload();
+  });
+})();
+
+// graphics-loop pass 11: hydrate Ideas rails from /api/products
+(async function hydrateIdeas() {
+  try {
+    const r = await fetch('/api/products?limit=80');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || []).filter(p => p && p.image_url);
+    if (!items.length) return;
+    const sorted = [...items].sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')));
+    const newest = sorted.slice(0, 12);
+    // Curated = deterministic offset slice (every 5th item starting at idx 3) for variety
+    const curated = items.filter((_, i) => i % 5 === 3).slice(0, 12);
+    function card(p) {
+      const url = (p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+      return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle || p.sku) + '">' +
+        '<img src="' + url + '" alt="' + (p.title || '').replace(/"/g, '&quot;') + '" loading="lazy">' +
+        '<div class="rc-title">' + ((p.title || '').split('|')[0] || '').trim() + '</div>' +
+        '<div class="rc-meta">' + (p.vendor || '') + '</div>' +
+      '</a>';
+    }
+    const r1 = document.getElementById('railNewest');
+    const r2 = document.getElementById('railCurated');
+    if (r1) r1.innerHTML = newest.map(card).join('');
+    if (r2) r2.innerHTML = curated.map(card).join('');
+  } catch(e) {}
+})();
+</script>
+
+<script src="/dw-fleet-nav.js" defer></script>
+</body>
+</html>
diff --git a/public/index.html.bak.nspropagate.1778226888801 b/public/index.html.bak.nspropagate.1778226888801
new file mode 100644
index 0000000..7ecc492
--- /dev/null
+++ b/public/index.html.bak.nspropagate.1778226888801
@@ -0,0 +1,968 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<!-- Google tag (gtag.js) -->
+<script async src="https://www.googletagmanager.com/gtag/js?id=G-XM0936TL4N"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-XM0936TL4N');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Heritage Atelier — hospitality, the British way.</title>
+<meta name="description" content="Heritage Atelier is a curated atelier dedicated entirely to hospitality. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#FFF">
+<link rel="canonical" href="https://hospitalitywallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600&family=Inter:wght@300;400;500&display=swap" rel="stylesheet">
+<link rel="preload" as="image" href="/hero-bg.jpg" fetchpriority="high">
+<script type="application/ld+json">
+{
+  "@context": "https://schema.org",
+  "@type": "Organization",
+  "name": "Heritage Atelier",
+  "url": "https://hospitalitywallpaper.com/",
+  "email": "info@hospitalitywallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #FFF;
+  --paper: #000;
+  --muted: #8B7866;
+  --line: #A47C5A;
+  --accent: #A47C5A;
+  --bg-soft: #A47C5A;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #000;
+  --paper: #FFF;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #A47C5A;
+  --bg-soft: #2a1f15;
+}
+* { margin:0; padding:0; box-sizing:border-box }
+html { scroll-behavior:smooth }
+body { font-family:'Inter', sans-serif; color:var(--paper); -webkit-font-smoothing:antialiased; background:var(--bg); min-height:100vh; overflow-x:hidden }
+/* DW-FASHION-TEMPLATE-OVERRIDE */
+.section-title .accent, .footer-brand, .center-mark, h1, h2, h3 { font-family:'Cormorant Garamond', Georgia, serif !important; font-weight:500 !important;  }
+
+/* ===== Auto-hide header ===== */
+header { position:fixed; top:0; left:0; right:0; display:flex; justify-content:space-between; align-items:center; padding:22px 32px; z-index:100; background:rgba(0,0,0,0.55); backdrop-filter:blur(10px); border-bottom:1px solid var(--line); transition:transform .3s }
+.h-link { display:flex; align-items:center; gap:10px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); text-decoration:none; cursor:pointer; background:transparent; border:0 }
+.h-link:hover { opacity:0.7 }
+.h-icon { width:18px; height:18px; stroke:currentColor; fill:none; stroke-width:1.5 }
+
+/* ===== Cinema hero ===== */
+.cinema { position:relative; height:100vh; width:100%; overflow:hidden }
+.cinema-bg { position:absolute; inset:0; background-size:cover; background-position:center; background-image:url('/hero-bg.jpg') }
+.cinema-bg::after { content:""; position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.75) 100%) }
+.corner-mark { position:absolute; top:24px; left:32px; font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:#fff; text-shadow:0 1px 3px rgba(0,0,0,0.55), 0 0 1px rgba(0,0,0,0.4); z-index:5 }
+.corner-mark::before { content:"◆ "; margin-right:6px }
+.center-mark { position:absolute; top:clamp(80px,12vh,140px); left:50%; transform:translateX(-50%); font-size:clamp(28px,4vw,56px); font-weight:500; letter-spacing:0.18em; text-transform:uppercase; text-align:center; color:#fff; text-shadow:0 2px 8px rgba(0,0,0,0.65), 0 0 1px rgba(0,0,0,0.5); z-index:5 }
+.center-mark .tm { font-size:14px; vertical-align:super; opacity:0.7; margin-left:0.2em }
+.center-mark .sub { display:block; font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400; font-size:0.4em; letter-spacing:0.04em; text-transform:none; margin-top:14px; opacity:0.85 }
+.meta-line { position:absolute; bottom:32px; left:32px; font-size:10px; letter-spacing:0.28em; text-transform:uppercase; font-weight:700; color:#fff; z-index:5; opacity:0.85 }
+.meta-line .num { font-size:12px; display:block; margin-top:4px; letter-spacing:0.05em }
+.enter { position:absolute; bottom:32px; right:32px; display:flex; align-items:center; gap:14px; font-size:11px; letter-spacing:0.36em; text-transform:uppercase; font-weight:700; color:#fff; text-decoration:none; padding-bottom:6px; border-bottom:1px solid #fff; transition:gap 0.25s; z-index:5 }
+.enter:hover { gap:22px }
+.enter svg { width:24px; height:12px }
+
+/* ===== Section ===== */
+.section { padding:96px 32px }
+.section-header { display:flex; justify-content:space-between; align-items:flex-end; flex-wrap:wrap; gap:24px; margin-bottom:32px; padding-bottom:24px; border-bottom:1px solid var(--line) }
+.section-title { font-size:clamp(36px,5vw,64px); font-weight:300; letter-spacing:-0.02em; line-height:1 }
+.section-title .accent { color: var(--accent); font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400 }
+.section-eyebrow { font-size:10px; letter-spacing:0.4em; text-transform:uppercase; font-weight:700; color:var(--muted); margin-bottom:16px }
+.section-meta { font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:600; color:var(--muted); text-align:right; line-height:1.6 }
+
+/* ===== Filter bar ===== */
+.filters { display:flex; gap:8px; align-items:center; margin-bottom:18px; flex-wrap:wrap }
+.chip { padding:8px 16px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); background:transparent; border:1px solid var(--line); cursor:pointer; transition:all 0.2s; font-family:inherit }
+.chip:hover { border-color:var(--paper) }
+.chip.active { background:var(--paper); color:var(--bg); border-color:var(--paper) }
+.search { flex:0 1 280px; margin-left:auto; display:flex; align-items:center; gap:10px; border-bottom:1px solid var(--line); padding:6px 0 }
+.search input { flex:1; background:transparent; border:0; color:var(--paper); font-family:inherit; font-size:13px; outline:none; letter-spacing:0.04em }
+.search input::placeholder { color:var(--muted) }
+.search svg { width:16px; height:16px; stroke:var(--muted); fill:none; stroke-width:1.5 }
+
+/* ===== Grid-density slider ===== */
+.density { display:flex; align-items:center; gap:14px; padding:6px 0; margin-bottom:24px }
+.density label { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--muted) }
+.density input[type=range] { flex:1; max-width:240px; -webkit-appearance:none; appearance:none; height:1px; background:var(--line); outline:none }
+.density input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50% }
+.density input[type=range]::-moz-range-thumb { width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50%; border:0 }
+.density .ct { font-size:11px; color:var(--muted); letter-spacing:0.18em; text-transform:uppercase; font-weight:600; min-width:80px }
+
+/* ===== Stats line ===== */
+.stat-line { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:600; color:var(--muted); margin-bottom:24px }
+
+/* ===== Product grid (novasuede pattern: flush grid + slide-up overlay) ===== */
+.grid { display:grid; grid-template-columns:repeat(var(--cols), 1fr); gap:0 }
+.card { position:relative; aspect-ratio:1/1.15; cursor:pointer; overflow:hidden; border:1px solid var(--bg); transition:transform 0.4s cubic-bezier(0.2,0.8,0.2,1); background:var(--bg-soft) }
+.card:hover { transform:scale(1.04); z-index:5 }
+.card img { width:100%; height:100%; object-fit:cover; display:block; transition:transform 0.4s ease }
+.card .overlay { position:absolute; left:0; right:0; bottom:0; padding:20px 16px 14px; background:linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.85) 100%); transform:translateY(48%); opacity:0.85; transition:transform 0.3s ease, opacity 0.3s ease }
+.card:hover .overlay { transform:translateY(0); opacity:1 }
+.card .pat { font-size:13px; font-weight:600; letter-spacing:0.02em; color:#fff; line-height:1.25; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
+.card .ven { font-size:9px; letter-spacing:0.18em; text-transform:uppercase; color:#fff; opacity:0.7; font-weight:500; margin-top:4px }
+.card .actions { margin-top:10px; display:flex; gap:6px }
+.card .sample-btn { flex:1; padding:7px 10px; background:#fff; color:#000; font-family:inherit; font-size:10px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; border:0; cursor:pointer; text-align:center; transition:all 0.2s }
+.card .sample-btn:hover { background:var(--accent); color:#fff }
+
+@media (max-width:1024px) { .grid { grid-template-columns:repeat(min(var(--cols), 4), 1fr) } }
+@media (max-width:720px) { .grid { grid-template-columns:repeat(2, 1fr) } .density { display:none } }
+
+.sentinel { height:1px }
+.loading { text-align:center; color:var(--muted); padding:32px; font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700 }
+
+/* ===== Footer ===== */
+footer { padding:64px 32px 32px; border-top:1px solid var(--line); margin-top:32px }
+.footer-grid { max-width:1400px; margin:0 auto; display:grid; grid-template-columns:2fr 1fr 1fr 1fr; gap:48px; margin-bottom:48px }
+.footer-brand { font-size:24px; font-weight:300; letter-spacing:0.32em; text-transform:uppercase; margin-bottom:12px }
+.footer-text { font-size:13px; line-height:1.6; color:var(--muted); max-width:380px }
+.footer-col h4 { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--paper); margin-bottom:18px }
+.footer-col a { display:block; font-size:13px; color:var(--muted); text-decoration:none; margin-bottom:8px; transition:color 0.2s; cursor:pointer; background:transparent; border:0; font-family:inherit; padding:0; text-align:left }
+.footer-col a:hover { color:var(--accent) }
+.footer-bottom { max-width:1400px; margin:0 auto; padding-top:24px; border-top:1px solid var(--line); display:flex; justify-content:space-between; flex-wrap:wrap; gap:16px; font-size:11px; letter-spacing:0.18em; text-transform:uppercase; color:var(--muted) }
+
+@media (max-width:720px) {
+  .corner-mark, .meta-line, .enter { font-size:10px }
+  .center-mark { font-size:24px; letter-spacing:0.12em; top:clamp(60px,9vh,90px) }
+  .section, footer { padding-left:20px; padding-right:20px }
+  .footer-grid { grid-template-columns:1fr; gap:32px }
+  .search { margin-left:0; flex:1 1 100% }
+}
+
+.theme-toggle { background:transparent; border:1px solid var(--line); width:32px; height:32px; cursor:pointer; color:var(--paper); display:inline-flex; align-items:center; justify-content:center; font-size:14px; line-height:1; transition:all .15s; padding:0 }
+.theme-toggle:hover { border-color:var(--accent); color:var(--accent) }
+
+/* ===== WCAG 2.4.7 — keyboard focus indicators ===== */
+/* Strictly :focus-visible so mouse clicks do NOT show the ring */
+a:focus-visible,
+button:focus-visible,
+input:focus-visible,
+select:focus-visible,
+textarea:focus-visible,
+[tabindex]:focus-visible {
+  outline: 2px solid var(--accent);
+  outline-offset: 2px;
+}
+</style>
+<script>
+(function(){ try { var t = localStorage.getItem('hosp_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://hospitalitywallpaper.com/">
+<meta property="og:title" content="Hospitality Wallpaper">
+<meta property="og:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta property="og:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Hospitality Wallpaper">
+<meta property="article:publisher" content="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:title" content="Hospitality Wallpaper">
+<meta name="twitter:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta name="twitter:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<!-- graphics-loop pass 13: footer + fb -->
+</head>
+<body>
+<style id="ns-header-modal-styles">
+        .ns-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; padding: 18px 36px; background: rgba(10,10,10,0.92) !important; backdrop-filter: blur(8px); border-bottom: 1px solid rgba(245,241,232,0.06); }
+        .ns-brand { display: inline-flex; align-items: center; gap: 14px; text-decoration: none; }
+        .ns-dot { width: 28px; height: 28px; border-radius: 50%; background: radial-gradient(circle at 35% 35%, #a98b5b 0%, #5d4c32 60%, #332a1b 100%); box-shadow: 0 0 0 1px rgba(245,241,232,0.10), 0 2px 12px rgba(180,90,60,0.30); flex-shrink: 0; }
+        .ns-name { font-family: -apple-system, "SF Pro Display", "Helvetica Neue", system-ui, sans-serif; font-size: 18px !important; font-weight: 300 !important; letter-spacing: 0.02em !important; color: #f5f1e8 !important; text-transform: none !important; margin: 0 !important; }
+        .ns-name sup { font-size: 0.55em; font-weight: 300; margin-left: 1px; }
+        .ns-nav { display: flex; gap: 32px; align-items: center; list-style: none; padding: 0; margin: 0; }
+        .ns-nav a, .ns-nav button { font-family: -apple-system, "SF Pro Text", system-ui, sans-serif; font-size: 15px !important; font-weight: 400 !important; color: #f5f1e8 !important; text-decoration: none !important; background: none !important; border: 0 !important; cursor: pointer; padding: 0 !important; transition: color 200ms; letter-spacing: 0 !important; text-transform: none !important; }
+        .ns-nav a:hover, .ns-nav button:hover { color: #ffffff !important; }
+        @media (max-width: 820px) { .ns-header { padding: 14px 18px; } .ns-nav { gap: 16px; } .ns-nav a, .ns-nav button { font-size: 13px !important; } }
+        @media (max-width: 760px) {
+          .ns-header { flex-wrap: wrap; }
+          .ns-nav { display: none !important; flex-basis: 100%; flex-direction: column; align-items: flex-start; gap: 6px; padding: 14px 0 4px; }
+          .ns-nav.open { display: flex !important; }
+          .ns-nav a, .ns-nav button { padding: 10px 0 !important; border-bottom: 1px solid rgba(245,241,232,0.08); width: 100%; text-align: left; }
+          .ns-nav a:nth-child(n+5), .ns-nav button:nth-child(n+5) { display: block !important; }
+          .ns-header .mobile-toggle { display: flex !important; }
+        }
+        @media (min-width: 761px) {
+          .ns-header .mobile-toggle { display: none !important; }
+        }
+        .ns-modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.78); z-index: 200; align-items: center; justify-content: center; padding: 24px; backdrop-filter: blur(6px); }
+        .ns-modal.show { display: flex; }
+        .ns-modal-card { max-width: 460px; width: 100%; background: #141414 !important; border: 1px solid rgba(245,241,232,0.14); border-radius: 6px; padding: 28px 30px 30px; position: relative; }
+        .ns-modal-card .close-x { position: absolute; top: 12px; right: 14px; width: 30px; height: 30px; background: none; border: 1px solid rgba(245,241,232,0.18); color: rgba(245,241,232,0.6) !important; border-radius: 50%; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; }
+        .ns-modal-card .close-x:hover { color: #ffffff !important; border-color: #ffffff; }
+        .ns-modal-card h3 { font-family: -apple-system, "SF Pro Display", system-ui; font-weight: 300 !important; font-size: 22px !important; margin: 0 0 6px !important; color: #f5f1e8 !important; }
+        .ns-modal-card .sub { color: rgba(245,241,232,0.65) !important; font-size: 13px; margin: 0 0 22px; }
+        .ns-actions { display: flex; flex-direction: column; gap: 10px; }
+        .ns-action { display: flex; align-items: center; gap: 14px; padding: 14px 16px; background: rgba(245,241,232,0.04) !important; border: 1px solid rgba(245,241,232,0.12) !important; color: #f5f1e8 !important; text-decoration: none !important; cursor: pointer; transition: all 200ms; font: inherit; text-align: left; }
+        .ns-action:hover { background: rgba(245,241,232,0.08) !important; border-color: #d4b683 !important; }
+        .ns-action .ico { width: 32px; height: 32px; border-radius: 50%; background: rgba(212,182,131,0.12); display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
+        .ns-action .txt { flex: 1; }
+        .ns-action .txt b { display: block; font-weight: 500; font-size: 14px; color: #f5f1e8 !important; }
+        .ns-action .txt span { font-size: 12px; color: rgba(245,241,232,0.55) !important; }
+
+        /* ─── FINAL CONTRAST PASS — kill remaining gold-solid + white-island defects ─── */
+        /* Replace all gold-fill accents with off-white (Gucci-aesthetic, no DW gold solids) */
+        .new-badge, .new-arrivals-pill,
+        .color-filter-btn.active,
+        .drapery-btn, .sample-btn-chip, .cb-cta {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        .new-badge:hover, .new-arrivals-pill:hover,
+        .color-filter-btn.active:hover,
+        .drapery-btn:hover, .sample-btn-chip:hover, .cb-cta:hover {
+          background: #fff !important;
+          color: #0a0a0a !important;
+        }
+        /* Gold accents stay only as edge color (links, glyphs) — not fills */
+        a { color: #d4b683; }
+        a:hover { color: #f5d97a; }
+        /* Authorized-dealer footer line — small caps tracked, muted ink, no gold pill */
+        .authorized, .authorized-dealer p {
+          background: transparent !important;
+          color: rgba(245,241,232,0.5) !important;
+          font-size: 10px !important;
+          letter-spacing: 0.22em !important;
+          text-transform: uppercase !important;
+          padding: 0 !important;
+          border: none !important;
+          margin-top: 14px !important;
+        }
+        /* Kill any straggler white bg in info-card / sample-related cards */
+        .info-card, .info-card-link, .care-highlight, .feature-card, .spec-item {
+          background-color: rgba(245,241,232,0.04) !important;
+          border-color: rgba(245,241,232,0.12) !important;
+        }
+        /* Ensure modal content stays readable — Steve's earlier sweep made it #141414 with white text */
+        .modal-content { background: #141414 !important; color: #f5f1e8 !important; }
+        .modal-content * { color: #f5f1e8 !important; }
+        .modal-content input, .modal-content textarea, .modal-content select {
+          background: rgba(245,241,232,0.05) !important;
+          color: #f5f1e8 !important;
+          border-color: rgba(245,241,232,0.2) !important;
+        }
+        .modal-content label { color: rgba(245,241,232,0.6) !important; }
+        /* Force the wide-tracked NOVASUEDE wordmark to stay white */
+        .ns-wordmark, .ns-wordmark sup { color: #f5f1e8 !important; }
+
+        /* ─── Modal-internal contrast (post-QA defects) ─── */
+        /* Backdrop covers full viewport */
+        .modal { width: 100vw !important; height: 100vh !important; left: 0 !important; top: 0 !important; background: rgba(0, 0, 0, 0.78) !important; backdrop-filter: blur(6px); }
+        /* Chip — flip from white-on-white island to dark card */
+        .request-chip {
+          background: rgba(245, 241, 232, 0.06) !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.18) !important;
+          border-radius: 4px !important;
+        }
+        .request-chip * { color: #f5f1e8 !important; }
+        .request-chip .chip-swatch {
+          /* swatch dot ALWAYS displays the inline-style hex from JS — fight any sweep */
+          border: 1px solid rgba(0, 0, 0, 0.4) !important;
+        }
+        /* + Add to request — hairline white-border on transparent (no gold) */
+        .add-to-request-btn {
+          background: transparent !important;
+          color: #f5f1e8 !important;
+          border: 1px solid rgba(245, 241, 232, 0.6) !important;
+          border-radius: 0 !important;
+          padding: 12px 22px !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 400 !important;
+        }
+        .add-to-request-btn:hover {
+          background: #f5f1e8 !important;
+          color: #0a0a0a !important;
+          border-color: #f5f1e8 !important;
+        }
+        /* Hex caption visible */
+        .preview-hex, #colorPreviewHex {
+          display: block !important;
+          color: rgba(245, 241, 232, 0.55) !important;
+          font-family: ui-monospace, "SF Mono", Menlo, monospace !important;
+          font-size: 11px !important;
+          margin-top: 4px !important;
+          letter-spacing: 0.04em !important;
+          text-transform: lowercase !important;
+        }
+        /* Color preview name — stays single, prominent */
+        #colorPreviewName {
+          color: #f5f1e8 !important;
+          font-size: 11px !important;
+          letter-spacing: 0.32em !important;
+          text-transform: uppercase !important;
+          font-weight: 500 !important;
+          display: block !important;
+          margin-top: 12px !important;
+        }
+
+        /* ─── Mobile hamburger nav (replaces the overflow at <760px) ─── */
+        @media (max-width: 760px) {
+          header .nav-container { flex-wrap: wrap; }
+          header nav { display: none; flex-basis: 100%; flex-direction: column; gap: 6px; padding: 16px 0 6px; }
+          header nav.open { display: flex; }
+          header nav a { padding: 10px 0; border-bottom: 1px solid rgba(245,241,232,0.1); }
+          header .mobile-toggle {
+            display: flex !important;
+            flex-direction: column;
+            gap: 5px;
+            background: transparent;
+            border: 0;
+            cursor: pointer;
+            padding: 8px;
+          }
+          header .mobile-toggle span {
+            width: 22px; height: 1.5px;
+            background: #f5f1e8;
+            display: block;
+          }
+        }
+        @media (min-width: 761px) {
+          header .mobile-toggle { display: none !important; }
+        }
+
+    </style>
+<style id="ns-gold-kill">
+    /* novasuede: kill gold-solid fills, off-white instead. Edge color stays gold. */
+    .new-badge, .new-arrivals-pill,
+    .color-filter-btn.active, .drapery-btn,
+    .sample-btn-chip, .cb-cta {
+      background: #f5f1e8 !important;
+      color: #0a0a0a !important;
+      border-color: #f5f1e8 !important;
+    }
+    .new-badge:hover, .new-arrivals-pill:hover,
+    .color-filter-btn.active:hover, .drapery-btn:hover,
+    .sample-btn-chip:hover, .cb-cta:hover {
+      background: #fff !important;
+      color: #0a0a0a !important;
+    }
+  </style>
+<header class="ns-header">
+        <a href="/" class="ns-brand" aria-label="Home">
+            <span class="ns-dot"></span>
+            <span class="ns-name">Heritage Atelier</span>
+        </a>
+        <nav class="ns-nav" id="nsPrimaryNav" aria-label="Primary">
+            <a href="/">Home</a>
+            <a href="/about">About</a>
+            <button type="button" onclick="nsContactOpen()">Contact</button>
+        </nav>
+        <button type="button" class="mobile-toggle" aria-label="Toggle menu" aria-controls="nsPrimaryNav" aria-expanded="false" onclick="nsToggleNav(this)">
+            <span></span><span></span><span></span>
+        </button>
+    </header>
+
+<div class="ns-modal" id="nsContactModal" role="dialog" aria-modal="true" aria-labelledby="nsContactTitle" onclick="if(event.target===this)nsContactClose()">
+        <div class="ns-modal-card">
+            <button type="button" class="close-x" onclick="nsContactClose()" aria-label="Close">×</button>
+            <h3 id="nsContactTitle">How can we help?</h3>
+            <p class="sub">Trade-account replies within one business day.</p>
+            <div class="ns-actions">
+                <a class="ns-action" href="#contact" onclick="nsContactClose()"><span class="ico">📋</span><div class="txt"><b>Get a Quote</b><span>Project specs → priced estimate</span></div></a>
+                <a class="ns-action" href="#contact" onclick="nsContactClose();openModal();"><span class="ico">📦</span><div class="txt"><b>Order a Sample</b><span>Free swatch to your shop</span></div></a>
+                <a class="ns-action" href="mailto:info@hospitalitywallpaper.com?subject=Heritage%20Atelier%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@hospitalitywallpaper.com</span></div></a>
+                <a class="ns-action" href="tel:888-373-4564"><span class="ico">📞</span><div class="txt"><b>Call Us</b><span>(888) 373-4564 · M–F, 9–5 PT</span></div></a>
+            </div>
+        </div>
+    </div>
+<script>
+  function nsContactOpen() { var m = document.getElementById('nsContactModal'); if (m) m.classList.add('show'); }
+  function nsContactClose() { var m = document.getElementById('nsContactModal'); if (m) m.classList.remove('show'); }
+  function nsToggleNav(btn) {
+    var nav = document.getElementById('nsPrimaryNav');
+    if (!nav) return;
+    var open = nav.classList.toggle('open');
+    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
+  }
+  document.addEventListener('keydown', function(e){ if (e.key === 'Escape') nsContactClose(); });
+</script>
+
+
+
+
+
+
+
+
+
+<header>
+  <button class="h-link" onclick="dwmOpen('Contact')" aria-label="Contact"><svg class="h-icon" viewBox="0 0 24 24"><path d="M3 7h18M3 12h18M3 17h18"/></svg><span>Contact</span></button>
+  <button class="theme-toggle" id="theme-toggle" aria-label="Theme toggle">☾</button>
+</header>
+
+<section class="cinema">
+  <div class="cinema-bg" id="heroBg"></div>
+  <div class="corner-mark">Trade-Grade</div>
+  <div class="center-mark">Hospitality Wallpaper</div>
+  <div class="meta-line">Hotel · Restaurant · Spa · Class A<span class="num" id="heroNum"></span></div>
+  <a class="enter" href="#shop">Enter <svg viewBox="0 0 24 12" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M0 6h22M16 1l6 5-6 5"/></svg></a>
+</section>
+
+
+<section class="section" id="ideas">
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">New this week</h2>
+    <div class="rail" id="railNewest"></div>
+  </div>
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">Curated picks</h2>
+    <div class="rail" id="railCurated"></div>
+  </div>
+</section>
+
+<section class="section" id="shop">
+  <div class="section-header">
+    <div>
+      <div class="section-eyebrow">The Collection</div>
+      <h2 class="section-title"><span class="accent" id="totalCount">—</span> Patterns.</h2>
+    </div>
+    <div class="section-meta">Hotel · Restaurant · Spa · Class A</div>
+  </div>
+
+  <div class="filters" id="facets">
+    <button class="chip active" data-facet="all">All</button>
+  </div>
+
+  <div class="density">
+    <label>Sort</label>
+    <select id="sortSelect" aria-label="Sort products" style="background:transparent;color:inherit;border:1px solid var(--line,rgba(255,255,255,.2));font:inherit;font-size:11px;letter-spacing:.10em;text-transform:uppercase;padding:4px 8px;cursor:pointer;outline:none;margin-right:14px">
+      <option value="newest">Newest</option>
+      <option value="color">Color</option>
+      <option value="style">Style</option>
+      <option value="sku">SKU A→Z</option>
+      <option value="title">Title A→Z</option>
+      <option value="price-asc">Price ↑</option>
+      <option value="price-desc">Price ↓</option>
+    </select>
+    <label>Grid</label>
+    <input type="range" id="densitySlider" min="4" max="12" step="1" value="6" aria-label="Grid columns">
+    <span class="ct" id="densityLabel">6 cols</span>
+    <div class="search">
+      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-5.5-5.5"/></svg>
+      <input type="text" id="searchInput" placeholder="Search by pattern, color…" autocomplete="off">
+    </div>
+  </div>
+
+  <div class="stat-line" id="statLine">Loading…</div>
+  <div class="grid" id="grid"></div>
+  <div class="loading" id="loading">Loading more…</div>
+  <div class="sentinel" id="sentinel"></div>
+</section>
+
+<footer>
+  <div class="footer-grid">
+    <div>
+      <div class="footer-brand">Heritage Atelier</div>
+      <p class="footer-text">Heritage Atelier — real samples ship free.</p>
+      <p class="footer-text" style="margin-top:14px;font-size:11px;letter-spacing:0.18em;text-transform:uppercase;font-weight:600;color:var(--paper);opacity:0.7"><a href="/about" style="color:inherit;text-decoration:none;border-bottom:1px solid var(--accent)">About →</a></p>
+    </div>
+    <div class="footer-col">
+      <h4>Aesthetic</h4>
+      <div id="footerFacets"></div>
+    </div>
+    <div class="footer-col">
+      <h4>Trade</h4>
+      <button onclick="dwmOpen('Inquiry')">Project Inquiry</button>
+      <button onclick="dwmOpen('Sample')">Request Sample</button>
+      <button onclick="dwmOpen('Contact')">Contact</button>
+    </div>
+  
+    <div class="footer-col">
+      <h4>Social</h4>
+      <a class="fb-link" href="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings" target="_blank" rel="noopener">Facebook</a>
+    </div>
+  </div>
+  <div class="footer-bottom">
+    <span>hospitalitywallpaper.com · Heritage Atelier</span>
+    <span><a href="mailto:info@hospitalitywallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@hospitalitywallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "hospitalitywallpaper";
+  const NICHES = [
+    ['silkwallpaper','Silk','mat'],['silkwallcoverings','Silk W/C','mat'],['linenwallpaper','Linen','mat'],
+    ['jutewallpaper','Jute','mat'],['raffiawallcoverings','Raffia W/C','mat'],['raffiawalls','Raffia Walls','mat'],
+    ['corkwallcovering','Cork','mat'],['fabricwallpaper','Fabric','mat'],['textilewallpaper','Textile','mat'],
+    ['metallicwallpaper','Metallic','mat'],['silverleafwallpaper','Silver Leaf','mat'],['vinylwallpaper','Vinyl','mat'],
+    ['micawallpaper','Mica','mat'],['madagascarwallpaper','Madagascar','mat'],['mylarwallpaper','Mylar','mat'],
+    ['suedewallpaper','Suede','mat'],
+    ['1800swallpaper','1800s','dec'],['1890swallpaper','1890s','dec'],['1900swallpaper','1900s','dec'],
+    ['1920swallpaper','1920s','dec'],['1930swallpaper','1930s','dec'],['1940swallpaper','1940s','dec'],
+    ['1950swallpaper','1950s','dec'],['1960swallpaper','1960s','dec'],['1970swallpaper','1970s','dec'],
+    ['1980swallpaper','1980s','dec'],['retrowalls','Retro','dec'],['wallpapersback','W. Back','dec'],
+    ['agedwallpaper','Aged','cra'],['handcraftedwallpaper','Handcrafted','cra'],['museumwallpaper','Museum','cra'],
+    ['restorationwallpaper','Restoration','cra'],['pastelwallpaper','Pastel','cra'],['glitterwalls','Glitter','cra'],
+    ['greenwallcoverings','Green','cra'],['naturalwallcoverings','Natural','cra'],['saloonwallpaper','Saloon','cra'],
+    ['contractwallpaper','Contract','use'],['hotelwallcoverings','Hotel','use'],['hospitalitywallpaper','Hospitality','use'],
+    ['healthcarewallpaper','Healthcare','use'],['restaurantwallpaper','Restaurant','use'],['architecturalwallcoverings','Architectural','use']
+  ];
+  const COLOR = { mat:'#c9b687', dec:'#b86a4a', cra:'#6b8e6f', use:'#4a6b8e' };
+  const W = 1080, H = 200, BANDS = ['mat','dec','cra','use'];
+  const groups = { mat:[], dec:[], cra:[], use:[] };
+  for (const n of NICHES) groups[n[2]].push(n);
+  const svg = document.getElementById('miniConst');
+  if (!svg) return;
+  const bandW = W / BANDS.length;
+  let nodes = '';
+  BANDS.forEach((band, bi) => {
+    const list = groups[band];
+    const cx = bi * bandW + bandW / 2;
+    list.forEach((n, i) => {
+      const t = list.length === 1 ? 0.5 : i / (list.length - 1);
+      // deterministic jitter per slug
+      let h = 0; for (let k = 0; k < n[0].length; k++) h = (h * 31 + n[0].charCodeAt(k)) | 0;
+      const jx = ((h & 0xff) / 255 - 0.5) * (bandW * 0.5);
+      const jy = (((h >> 8) & 0xff) / 255 - 0.5) * 6;  // tightened from 14 → 6 to prevent same-band collisions (16 mat nodes / 144px = 9px spacing)
+      const x = cx + jx, y = 28 + t * (H - 56) + jy;
+      const isCurrent = n[0] === SLUG;
+      const r = isCurrent ? 8 : 4;
+      const op = isCurrent ? 1 : 0.55;
+      nodes += `<g class="mc-node" data-slug="${n[0]}" data-label="${n[1]}" style="cursor:pointer">
+        <circle cx="${x}" cy="${y}" r="${r}" fill="url(#dna-${band})" fill-opacity="${op}" stroke="${COLOR[band]}" stroke-opacity="${isCurrent?1:0.7}" stroke-width="${isCurrent?2:1}">
+          <title>${n[1]} — ${n[0]}.com</title>
+        </circle>
+        ${isCurrent ? `<circle cx="${x}" cy="${y}" r="${r+5}" fill="none" stroke="${COLOR[band]}" stroke-opacity="0.4" stroke-width="1"><animate attributeName="r" values="${r+5};${r+12};${r+5}" dur="2.4s" repeatCount="indefinite"/><animate attributeName="stroke-opacity" values="0.4;0;0.4" dur="2.4s" repeatCount="indefinite"/></circle>` : ''}
+      </g>`;
+    });
+  });
+  // append nodes after defs
+  svg.insertAdjacentHTML('beforeend', nodes);
+  svg.querySelectorAll('.mc-node').forEach(n => {
+    n.addEventListener('mouseenter', () => n.querySelector('circle').setAttribute('fill-opacity', '1'));
+    n.addEventListener('mouseleave', e => {
+      const isCurrent = n.dataset.slug === SLUG;
+      n.querySelector('circle').setAttribute('fill-opacity', isCurrent ? '1' : '0.55');
+    });
+    n.addEventListener('click', () => window.open('https://' + n.dataset.slug + '.com', '_blank'));
+  });
+})();
+</script>
+
+<script>
+const state = { q:'', facet:'all', page:1, pages:1, total:0, loading:false, exhausted:false };
+const LABELS = {"all":"All"};
+
+function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c])); }
+// Image-URL allowlist: only DW Shopify CDN + designerwallcoverings.com (defends against XSS via crafted products.json)
+function safeImg(u) { return /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(u || '') ? u : '/hero-bg.jpg'; }
+function cardHTML(p) {
+  const eager = state.page === 1;
+  return '<img loading="' + (eager ? 'eager' : 'lazy') + '"' + (eager ? ' fetchpriority="high"' : '') + ' src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+    + '<div class="overlay">'
+    + '<div class="pat">' + escAttr(p.pattern_name || p.title) + '</div>'
+    + '<div class="ven">' + escAttr((p.vendor || '').replace(/-/g, ' ')) + '</div>'
+    + '<div class="actions">'
+    + '<button class="sample-btn" onclick="event.stopPropagation();dwmOpen(\'Sample\',' + JSON.stringify({sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}).replace(/"/g,'&quot;') + ')">Sample</button>'
+    + '</div></div>';
+}
+
+async function loadFacets() {
+  let f;
+  try {
+    const r = await fetch('/api/facets');
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    f = await r.json();
+  } catch (e) { console.error('loadFacets failed:', e); return; }
+  const el = document.getElementById('facets');
+  for (const [k, v] of Object.entries(f.aesthetics).sort((a,b) => b[1] - a[1])) {
+    const b = document.createElement('button');
+    b.className = 'chip'; b.dataset.facet = k;
+    b.innerHTML = (LABELS[k] || k) + ' <span style="opacity:.55;font-weight:500;margin-left:4px">' + v + '</span>';
+    el.appendChild(b);
+  }
+  el.addEventListener('click', e => {
+    if (e.target.tagName !== 'BUTTON') return;
+    document.querySelectorAll('#facets button').forEach(b => b.classList.remove('active'));
+    e.target.classList.add('active');
+    state.facet = e.target.dataset.facet;
+    resetGrid();
+  });
+  document.getElementById('totalCount').textContent = f.total;
+  document.getElementById('footerStat').textContent = f.total + ' patterns · live archive';
+  // Footer aesthetic links
+  const footerEl = document.getElementById('footerFacets');
+  for (const [k] of Object.entries(f.aesthetics)) {
+    const b = document.createElement('button');
+    b.textContent = LABELS[k] || k;
+    b.onclick = () => { state.facet = k; resetGrid(); document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === k)); document.getElementById('shop').scrollIntoView({behavior:'smooth'}); };
+    footerEl.appendChild(b);
+  }
+}
+
+function resetGrid() {
+  state.page = 1; state.exhausted = false;
+  document.getElementById('grid').innerHTML = '';
+  document.getElementById('loading').textContent = 'Loading…';
+  loadGridPage();
+}
+
+async function loadGridPage() {
+  if (state.loading || state.exhausted) return;
+  state.loading = true;
+  const params = new URLSearchParams({ page:state.page, limit:24 });
+  if (state.q) params.set('q', state.q);
+  if (state.facet !== 'all') params.set('aesthetic', state.facet);
+  let data;
+  try {
+    const r = await fetch('/api/products?' + params);
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    data = await r.json();
+  } catch (e) {
+    console.error('loadGridPage failed:', e);
+    document.getElementById('loading').textContent = '— offline — refresh to retry —';
+    state.loading = false;
+    return;
+  }
+  state.total = data.total; state.pages = data.pages;
+
+  if (state.page === 1) {
+    document.getElementById('statLine').textContent = data.total + ' patterns · ' + (state.facet === 'all' ? 'all aesthetics' : (LABELS[state.facet] || state.facet)) + (state.q ? ' · matching "' + state.q + '"' : '');
+  }
+  const grid = document.getElementById('grid');
+  for (const p of data.items) {
+    const a = document.createElement('a');
+    a.className = 'card'; a.href = '#'; a.onclick = (e) => { e.preventDefault(); dwmOpen('Sample',{sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}); };
+    a.innerHTML = cardHTML(p);
+    grid.appendChild(a);
+  }
+  if (state.page >= state.pages || data.items.length === 0) {
+    state.exhausted = true;
+    document.getElementById('loading').textContent = state.total > 0 ? '— end of archive · ' + state.total + ' patterns —' : '';
+  } else state.page++;
+  state.loading = false;
+}
+
+const io = new IntersectionObserver(es => { for (const e of es) if (e.isIntersecting) loadGridPage(); }, { rootMargin:'600px 0px' });
+io.observe(document.getElementById('sentinel'));
+
+document.getElementById('searchInput').addEventListener('input', e => {
+  state.q = e.target.value.trim();
+  clearTimeout(window._t);
+  window._t = setTimeout(resetGrid, 220);
+});
+
+// Density slider
+const slider = document.getElementById('densitySlider');
+const dlabel = document.getElementById('densityLabel');
+function setDensity(n) {
+  document.documentElement.style.setProperty('--cols', n);
+  dlabel.textContent = n + ' cols';
+  try { localStorage.setItem('hosp_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('hosp_theme_density') || '6');
+if (savedDensity >= 4 && savedDensity <= 12) { slider.value = savedDensity; setDensity(savedDensity); }
+
+// Theme toggle
+const tb = document.getElementById('theme-toggle');
+function setTheme(t){ document.documentElement.dataset.theme = t; try { localStorage.setItem('hosp_theme', t); } catch(e){} tb.textContent = t === 'dark' ? '☾' : '☀'; }
+setTheme(document.documentElement.dataset.theme || 'light');
+tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
+
+loadFacets();
+loadGridPage();
+</script>
+<!-- ============================================================
+     DW UNIVERSAL CONTACT MODULE — fashion-house UX
+     Inject before
+ </body> in every DW-family sister site.
+     Self-contained: CSS + 4 modals + JS submission handlers.
+     Uses host site's CSS vars (--bg, --fg, --gold, --rule).
+     ============================================================ -->
+<style>
+  /* === MODAL BASE === */
+  .dwm{position:fixed;inset:0;background:rgba(0,0,0,0.78);display:none;align-items:center;justify-content:center;z-index:9999;padding:24px;overflow-y:auto}
+  .dwm.open{display:flex}
+  .dwm-box{background:var(--bg);border:1px solid var(--rule);max-width:520px;width:100%;padding:36px 32px;position:relative;max-height:90vh;overflow-y:auto;animation:dwm-in 0.25s ease}
+  @keyframes dwm-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
+  .dwm-box h3{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-weight:400;font-size:32px;line-height:1.05;margin-bottom:6px;color:var(--fg);letter-spacing:-0.01em}
+  .dwm-box .sub{color:var(--muted);font-size:12px;letter-spacing:0.16em;text-transform:uppercase;margin-bottom:24px;font-weight:500}
+  .dwm-close{position:absolute;top:18px;right:18px;background:transparent;border:0;color:var(--muted);font-size:24px;cursor:pointer;width:32px;height:32px;line-height:1;padding:0}
+  .dwm-close:hover{color:var(--gold)}
+  .dwm-preview{display:flex;gap:14px;align-items:center;padding:12px;background:var(--bg-soft);margin-bottom:18px}
+  .dwm-preview img{width:64px;height:64px;object-fit:cover}
+  .dwm-preview .pn{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-size:15px;line-height:1.2;color:var(--fg)}
+  .dwm-preview .pc{font-size:10px;letter-spacing:0.14em;text-transform:uppercase;color:var(--muted);margin-top:4px}
+  .dwm-field{margin-bottom:14px}
+  .dwm-field label{display:block;font-size:10px;letter-spacing:0.18em;text-transform:uppercase;color:var(--muted);margin-bottom:6px;font-weight:500}
+  .dwm-field input,.dwm-field textarea,.dwm-field select{width:100%;border:0;border-bottom:1px solid var(--rule);background:transparent;padding:8px 4px;font-size:14px;font-family:inherit;color:var(--fg);outline:none;transition:border-color 0.2s}
+  .dwm-field input:focus,.dwm-field textarea:focus{border-bottom-color:var(--gold)}
+  .dwm-field textarea{min-height:60px;resize:vertical}
+  .dwm-submit{background:transparent;color:var(--muted, #c9b89e);border:1px solid var(--muted, #c9b89e);padding:14px 28px;font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:700;cursor:pointer;width:100%;margin-top:8px;transition:background 0.15s, color 0.15s}
+  .dwm-submit:hover{background:var(--muted, #c9b89e);color:var(--bg, #000)}
+  
+  .dwm-submit:disabled{opacity:0.5;cursor:default}
+  .dwm-status{margin-top:14px;font-size:11px;letter-spacing:0.16em;text-transform:uppercase;text-align:center;display:none}
+  .dwm-status.ok{color:var(--sage);display:block}
+  .dwm-status.err{color:#e08070;display:block}
+  /* contact-options */
+  .dwm-options{display:flex;flex-direction:column;gap:10px}
+  .dwm-option{display:flex;align-items:center;gap:14px;padding:18px 20px;background:transparent;border:1px solid var(--rule);color:var(--fg);font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:600;cursor:pointer;text-decoration:none;transition:all 0.2s;text-align:left;width:100%}
+  .dwm-option:hover{border-color:var(--gold);color:var(--gold)}
+  .dwm-option svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.5;flex-shrink:0}
+  .dwm-option .lbl{flex:1;display:block}
+  .dwm-option .val{display:block;font-size:10px;letter-spacing:0.14em;text-transform:none;font-weight:500;opacity:0.65;margin-top:4px}
+
+/* graphics-loop pass 11: Ideas rails */
+#ideas { padding: 56px 24px 24px; max-width:1600px; margin:0 auto }
+#ideas .rail-block { margin-bottom:48px }
+#ideas .rail-eyebrow { font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:var(--muted, #888); margin-bottom:8px }
+#ideas .rail-title { font-size:clamp(22px,2.6vw,32px); font-weight:500; letter-spacing:-0.01em; margin:0 0 18px; color:var(--ink,#fff) }
+#ideas .rail { display:flex; gap:14px; overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:8px; scrollbar-width:none }
+#ideas .rail::-webkit-scrollbar { display:none }
+#ideas .rail-card { flex:0 0 240px; scroll-snap-align:start; cursor:pointer; transition:transform 0.2s }
+#ideas .rail-card:hover { transform:translateY(-3px) }
+#ideas .rail-card img { width:100%; aspect-ratio:1; object-fit:cover; display:block; background:var(--card,#222) }
+#ideas .rail-card .rc-title { font-size:13px; font-weight:500; color:var(--paper,#fff); padding:8px 0 2px; line-height:1.3 }
+#ideas .rail-card .rc-meta  { font-size:11px; color:var(--muted,#888); letter-spacing:0.06em }
+@media (max-width:720px) { #ideas .rail-card { flex:0 0 160px } }
+</style>
+
+<!-- Contact options modal -->
+<div class="dwm" id="dwmContact" onclick="if(event.target===this)dwmClose('Contact')">
+  <div class="dwm-box" style="max-width:440px">
+    <button class="dwm-close" onclick="dwmClose('Contact')" aria-label="Close">×</button>
+    <h3>Contact</h3>
+    <p class="sub" id="dwmContactSub">Three ways to reach us</p>
+    <div class="dwm-options">
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Inquiry')">
+        <svg viewBox="0 0 24 24"><path d="M4 4h16v12H7l-3 3z"/></svg>
+        <span class="lbl">Send an Inquiry<span class="val">Project name · scope · all the details</span></span>
+      </button>
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Sample')">
+        <svg viewBox="0 0 24 24"><rect x="4" y="6" width="16" height="14"/><path d="M4 10h16M9 6V3h6v3"/></svg>
+        <span class="lbl">Request a Sample<span class="val">Memo sample · ships free · 3–5 business days</span></span>
+      </button>
+      <a class="dwm-option" id="dwmContactEmailLink" href="mailto:info@hospitalitywallpaper.com">
+        <svg viewBox="0 0 24 24"><path d="M3 6h18v12H3z"/><path d="M3 6l9 7 9-7"/></svg>
+        <span class="lbl">Email Us<span class="val" id="dwmContactEmailLabel">info@hospitalitywallpaper.com</span></span>
+      </a>
+    </div>
+  </div>
+</div>
+
+<!-- Inquiry modal -->
+<div class="dwm" id="dwmInquiry" onclick="if(event.target===this)dwmClose('Inquiry')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Inquiry')" aria-label="Close">×</button>
+    <h3>Project Inquiry</h3>
+    <p class="sub">We'll respond within one business day</p>
+    <form id="dwmInquiryForm" onsubmit="return dwmSubmit(event,'inquiry')">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Phone</label><input type="tel" name="phone"></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Project Name</label><input type="text" name="projectName" required></div>
+      <div class="dwm-field"><label>Project Scope</label><textarea name="projectScope" placeholder="Square footage · room count · timeline" required></textarea></div>
+      <div class="dwm-field"><label>Additional Information</label><textarea name="message" placeholder="Patterns of interest, finish preferences, budget"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Inquiry</button>
+      <div class="dwm-status" id="dwmInquiryStatus"></div>
+    </form>
+  </div>
+</div>
+
+<!-- Sample-request modal -->
+<div class="dwm" id="dwmSample" onclick="if(event.target===this)dwmClose('Sample')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Sample')" aria-label="Close">×</button>
+    <h3>Request a Sample</h3>
+    <p class="sub">Memo sample · ships free · 3–5 business days</p>
+    <div class="dwm-preview" id="dwmSamplePreview" style="display:none">
+      <img id="dwmSampleImg" src="" alt="">
+      <div><div class="pn" id="dwmSampleName"></div><div class="pc" id="dwmSampleSku"></div></div>
+    </div>
+    <form id="dwmSampleForm" onsubmit="return dwmSubmit(event,'sample')">
+      <input type="hidden" name="sku" id="dwmSampleSkuInput">
+      <input type="hidden" name="title" id="dwmSampleTitleInput">
+      <input type="hidden" name="image_url" id="dwmSampleImageInput">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Shipping Address</label><input type="text" name="address" placeholder="Street" required></div>
+      <div class="dwm-field" style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:8px">
+        <input type="text" name="city" placeholder="City" required>
+        <input type="text" name="state" placeholder="State" required>
+        <input type="text" name="zip" placeholder="ZIP" required>
+      </div>
+      <div class="dwm-field"><label>Notes (optional)</label><textarea name="message" placeholder="Project, sq.ft., timing"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Sample Request</button>
+      <div class="dwm-status" id="dwmSampleStatus"></div>
+    </form>
+  </div>
+</div>
+
+<script>
+  // Universal modal control
+  function dwmOpen(name, opts){
+    document.getElementById('dwm' + name).classList.add('open');
+    document.body.style.overflow = 'hidden';
+    if (name === 'Sample' && opts) {
+      document.getElementById('dwmSamplePreview').style.display = 'flex';
+      document.getElementById('dwmSampleImg').src = opts.image_url || '';
+      document.getElementById('dwmSampleName').textContent = opts.title || '';
+      document.getElementById('dwmSampleSku').textContent = opts.sku || '';
+      document.getElementById('dwmSampleSkuInput').value = opts.sku || '';
+      document.getElementById('dwmSampleTitleInput').value = opts.title || '';
+      document.getElementById('dwmSampleImageInput').value = opts.image_url || '';
+    } else if (name === 'Sample') {
+      document.getElementById('dwmSamplePreview').style.display = 'none';
+      document.getElementById('dwmSampleSkuInput').value = '';
+      document.getElementById('dwmSampleTitleInput').value = '';
+      document.getElementById('dwmSampleImageInput').value = '';
+    }
+  }
+  function dwmClose(name){ document.getElementById('dwm'+name).classList.remove('open'); document.body.style.overflow=''; }
+
+  // Universal form submit — POSTs to /api/send-{kind}
+  async function dwmSubmit(e, kind) {
+    e.preventDefault();
+    const form = e.target;
+    const data = Object.fromEntries(new FormData(form).entries());
+    const btn = form.querySelector('.dwm-submit');
+    const status = form.querySelector('.dwm-status');
+    btn.disabled = true; const orig = btn.textContent; btn.textContent = 'Sending…';
+    status.className = 'dwm-status';
+    try {
+      const r = await fetch('/api/send-' + kind, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(data) });
+      if (!r.ok) throw new Error('HTTP '+r.status);
+      const j = await r.json();
+      status.textContent = kind === 'sample' ? 'Sample request sent — ships within 3–5 business days' : 'Inquiry sent — we respond within 1 business day';
+      status.className = 'dwm-status ok';
+      btn.textContent = 'Sent ✓';
+      setTimeout(() => { dwmClose(kind === 'sample' ? 'Sample' : 'Inquiry'); btn.disabled = false; btn.textContent = orig; status.className = 'dwm-status'; form.reset(); }, 2800);
+    } catch (err) {
+      status.textContent = 'Send failed — please email info@designerwallcoverings.com';
+      status.className = 'dwm-status err';
+      btn.disabled = false; btn.textContent = orig;
+    }
+    return false;
+  }
+
+  // Wire up "Memo samples ship free" badge in hero to open sample modal directly
+  document.querySelectorAll('.hero .badge, [data-open-sample]').forEach(el => {
+    el.style.cursor = 'pointer';
+    el.addEventListener('click', () => dwmOpen('Sample'));
+  });
+
+  // Wire nav "Trade" link to inquiry modal
+  document.querySelectorAll('nav a[href*="designerwallcoverings.com"]').forEach(a => {
+    a.removeAttribute('target');
+    a.removeAttribute('href');
+    a.style.cursor = 'pointer';
+    a.addEventListener('click', e => { e.preventDefault(); dwmOpen('Contact'); });
+  });
+
+  // Override product card clicks — open Sample modal pre-filled instead of redirecting to DW
+  document.addEventListener('click', e => {
+    const card = e.target.closest('.card, .rail-card');
+    if (!card) return;
+    if (card.tagName === 'A' && (card.getAttribute('href') || '').startsWith('/sample/')) {
+      e.preventDefault();
+      const img = card.querySelector('img');
+      const pat = card.querySelector('.pat');
+      const sku = card.getAttribute('href').replace('/sample/', '');
+      dwmOpen('Sample', {
+        sku,
+        title: pat ? pat.textContent.trim() : '',
+        image_url: img ? img.src : ''
+      });
+    }
+  }, true);
+// DW STANDARD: hero pulls from products.json[0].image_url so dw-collections-viewer
+// drag-drop / hero-pin updates the live front page on next deploy.
+// Always upgrades to the largest Shopify variant (strips _NxN size suffix) so
+// the full-page hero stays sharp.
+// DW STANDARD: hero rotates through top-20 NEWEST products on each visit
+// (novasuede.com pattern). Fetches /api/products?limit=100, sorts by created_at desc,
+// takes the freshest 20, picks one per visit via localStorage counter.
+// Falls back to static /hero-bg.jpg on any error.
+(async function rotateHero() {
+  try {
+    const r = await fetch('/api/products?limit=100');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || [])
+      .filter(p => p && p.image_url && /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(p.image_url))
+      .sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')))
+      .slice(0, 20);
+    if (!items.length) return;
+    let visits = 0;
+    try {
+      visits = parseInt(localStorage.getItem('hero_visits') || '0', 10) || 0;
+      localStorage.setItem('hero_visits', String(visits + 1));
+    } catch(e) {}
+    const pick = items[visits % items.length];
+    // Strip _NxN size suffix to get the largest CDN variant
+    const url = pick.image_url.replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+    const bg = document.getElementById('heroBg') || document.getElementById('cinemaBg');
+    if (bg) bg.style.backgroundImage = "url('" + url + "')";
+  } catch (e) {}
+})();
+
+
+// DW STANDARD sort-select wire-up (added by fleet patcher)
+(function(){
+  const sortSel = document.getElementById('sortSelect');
+  if (!sortSel) return;
+  const KEY = location.hostname.replace(/\./g, '_') + '_sort';
+  const saved = localStorage.getItem(KEY);
+  if (saved) { try { sortSel.value = saved; } catch(e){} }
+  if (typeof state !== 'undefined') state.sort = sortSel.value;
+  sortSel.addEventListener('change', e => {
+    const v = e.target.value;
+    try { localStorage.setItem(KEY, v); } catch(e){}
+    if (typeof state !== 'undefined') state.sort = v;
+    if (typeof resetGrid === 'function') resetGrid();
+    else location.reload();
+  });
+})();
+
+// graphics-loop pass 11: hydrate Ideas rails from /api/products
+(async function hydrateIdeas() {
+  try {
+    const r = await fetch('/api/products?limit=80');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || []).filter(p => p && p.image_url);
+    if (!items.length) return;
+    const sorted = [...items].sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')));
+    const newest = sorted.slice(0, 12);
+    // Curated = deterministic offset slice (every 5th item starting at idx 3) for variety
+    const curated = items.filter((_, i) => i % 5 === 3).slice(0, 12);
+    function card(p) {
+      const url = (p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+      return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle || p.sku) + '">' +
+        '<img src="' + url + '" alt="' + (p.title || '').replace(/"/g, '&quot;') + '" loading="lazy">' +
+        '<div class="rc-title">' + ((p.title || '').split('|')[0] || '').trim() + '</div>' +
+        '<div class="rc-meta">' + (p.vendor || '') + '</div>' +
+      '</a>';
+    }
+    const r1 = document.getElementById('railNewest');
+    const r2 = document.getElementById('railCurated');
+    if (r1) r1.innerHTML = newest.map(card).join('');
+    if (r2) r2.innerHTML = curated.map(card).join('');
+  } catch(e) {}
+})();
+</script>
+
+<script src="/dw-fleet-nav.js" defer></script>
+</body>
+</html>
diff --git a/public/index.html.pre-sort-frontend b/public/index.html.pre-sort-frontend
new file mode 100644
index 0000000..3ef6a53
--- /dev/null
+++ b/public/index.html.pre-sort-frontend
@@ -0,0 +1,852 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+
+<meta charset="utf-8">
+<!-- Google tag (gtag.js) -->
+<script async src="https://www.googletagmanager.com/gtag/js?id=G-XM0936TL4N"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-XM0936TL4N');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Heritage Atelier — hospitality, the British way.</title>
+<meta name="description" content="Heritage Atelier is a curated atelier dedicated entirely to hospitality. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#FFF">
+<link rel="canonical" href="https://hospitalitywallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600&family=Inter:wght@300;400;500&display=swap" rel="stylesheet">
+<link rel="preload" as="image" href="/hero-bg.jpg" fetchpriority="high">
+<script type="application/ld+json">
+{
+  "@context": "https://schema.org",
+  "@type": "Organization",
+  "name": "Heritage Atelier",
+  "url": "https://hospitalitywallpaper.com/",
+  "email": "info@hospitalitywallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #FFF;
+  --paper: #000;
+  --muted: #8B7866;
+  --line: #A47C5A;
+  --accent: #A47C5A;
+  --bg-soft: #A47C5A;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #000;
+  --paper: #FFF;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #A47C5A;
+  --bg-soft: #2a1f15;
+}
+* { margin:0; padding:0; box-sizing:border-box }
+html { scroll-behavior:smooth }
+body { font-family:'Inter', sans-serif; color:var(--paper); -webkit-font-smoothing:antialiased; background:var(--bg); min-height:100vh; overflow-x:hidden }
+/* DW-FASHION-TEMPLATE-OVERRIDE */
+.section-title .accent, .footer-brand, .center-mark, h1, h2, h3 { font-family:'Cormorant Garamond', Georgia, serif !important; font-weight:500 !important;  }
+
+/* ===== Auto-hide header ===== */
+header { position:fixed; top:0; left:0; right:0; display:flex; justify-content:space-between; align-items:center; padding:22px 32px; z-index:100; background:rgba(0,0,0,0.55); backdrop-filter:blur(10px); border-bottom:1px solid var(--line); transition:transform .3s }
+.h-link { display:flex; align-items:center; gap:10px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); text-decoration:none; cursor:pointer; background:transparent; border:0 }
+.h-link:hover { opacity:0.7 }
+.h-icon { width:18px; height:18px; stroke:currentColor; fill:none; stroke-width:1.5 }
+
+/* ===== Cinema hero ===== */
+.cinema { position:relative; height:100vh; width:100%; overflow:hidden }
+.cinema-bg { position:absolute; inset:0; background-size:cover; background-position:center; background-image:url('/hero-bg.jpg') }
+.cinema-bg::after { content:""; position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.75) 100%) }
+.corner-mark { position:absolute; top:24px; left:32px; font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:#fff; text-shadow:0 1px 3px rgba(0,0,0,0.55), 0 0 1px rgba(0,0,0,0.4); z-index:5 }
+.corner-mark::before { content:"◆ "; margin-right:6px }
+.center-mark { position:absolute; top:clamp(80px,12vh,140px); left:50%; transform:translateX(-50%); font-size:clamp(28px,4vw,56px); font-weight:500; letter-spacing:0.18em; text-transform:uppercase; text-align:center; color:#fff; text-shadow:0 2px 8px rgba(0,0,0,0.65), 0 0 1px rgba(0,0,0,0.5); z-index:5 }
+.center-mark .tm { font-size:14px; vertical-align:super; opacity:0.7; margin-left:0.2em }
+.center-mark .sub { display:block; font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400; font-size:0.4em; letter-spacing:0.04em; text-transform:none; margin-top:14px; opacity:0.85 }
+.meta-line { position:absolute; bottom:32px; left:32px; font-size:10px; letter-spacing:0.28em; text-transform:uppercase; font-weight:700; color:#fff; z-index:5; opacity:0.85 }
+.meta-line .num { font-size:12px; display:block; margin-top:4px; letter-spacing:0.05em }
+.enter { position:absolute; bottom:32px; right:32px; display:flex; align-items:center; gap:14px; font-size:11px; letter-spacing:0.36em; text-transform:uppercase; font-weight:700; color:#fff; text-decoration:none; padding-bottom:6px; border-bottom:1px solid #fff; transition:gap 0.25s; z-index:5 }
+.enter:hover { gap:22px }
+.enter svg { width:24px; height:12px }
+
+/* ===== Section ===== */
+.section { padding:96px 32px }
+.section-header { display:flex; justify-content:space-between; align-items:flex-end; flex-wrap:wrap; gap:24px; margin-bottom:32px; padding-bottom:24px; border-bottom:1px solid var(--line) }
+.section-title { font-size:clamp(36px,5vw,64px); font-weight:300; letter-spacing:-0.02em; line-height:1 }
+.section-title .accent { color: var(--accent); font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400 }
+.section-eyebrow { font-size:10px; letter-spacing:0.4em; text-transform:uppercase; font-weight:700; color:var(--muted); margin-bottom:16px }
+.section-meta { font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:600; color:var(--muted); text-align:right; line-height:1.6 }
+
+/* ===== Filter bar ===== */
+.filters { display:flex; gap:8px; align-items:center; margin-bottom:18px; flex-wrap:wrap }
+.chip { padding:8px 16px; font-size:11px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--paper); background:transparent; border:1px solid var(--line); cursor:pointer; transition:all 0.2s; font-family:inherit }
+.chip:hover { border-color:var(--paper) }
+.chip.active { background:var(--paper); color:var(--bg); border-color:var(--paper) }
+.search { flex:0 1 280px; margin-left:auto; display:flex; align-items:center; gap:10px; border-bottom:1px solid var(--line); padding:6px 0 }
+.search input { flex:1; background:transparent; border:0; color:var(--paper); font-family:inherit; font-size:13px; outline:none; letter-spacing:0.04em }
+.search input::placeholder { color:var(--muted) }
+.search svg { width:16px; height:16px; stroke:var(--muted); fill:none; stroke-width:1.5 }
+
+/* ===== Grid-density slider ===== */
+.density { display:flex; align-items:center; gap:14px; padding:6px 0; margin-bottom:24px }
+.density label { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--muted) }
+.density input[type=range] { flex:1; max-width:240px; -webkit-appearance:none; appearance:none; height:1px; background:var(--line); outline:none }
+.density input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50% }
+.density input[type=range]::-moz-range-thumb { width:14px; height:14px; background:var(--accent); cursor:pointer; border-radius:50%; border:0 }
+.density .ct { font-size:11px; color:var(--muted); letter-spacing:0.18em; text-transform:uppercase; font-weight:600; min-width:80px }
+
+/* ===== Stats line ===== */
+.stat-line { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:600; color:var(--muted); margin-bottom:24px }
+
+/* ===== Product grid (novasuede pattern: flush grid + slide-up overlay) ===== */
+.grid { display:grid; grid-template-columns:repeat(var(--cols), 1fr); gap:0 }
+.card { position:relative; aspect-ratio:1/1.15; cursor:pointer; overflow:hidden; border:1px solid var(--bg); transition:transform 0.4s cubic-bezier(0.2,0.8,0.2,1); background:var(--bg-soft) }
+.card:hover { transform:scale(1.04); z-index:5 }
+.card img { width:100%; height:100%; object-fit:cover; display:block; transition:transform 0.4s ease }
+.card .overlay { position:absolute; left:0; right:0; bottom:0; padding:20px 16px 14px; background:linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.85) 100%); transform:translateY(48%); opacity:0.85; transition:transform 0.3s ease, opacity 0.3s ease }
+.card:hover .overlay { transform:translateY(0); opacity:1 }
+.card .pat { font-size:13px; font-weight:600; letter-spacing:0.02em; color:#fff; line-height:1.25; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
+.card .ven { font-size:9px; letter-spacing:0.18em; text-transform:uppercase; color:#fff; opacity:0.7; font-weight:500; margin-top:4px }
+.card .actions { margin-top:10px; display:flex; gap:6px }
+.card .sample-btn { flex:1; padding:7px 10px; background:#fff; color:#000; font-family:inherit; font-size:10px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; border:0; cursor:pointer; text-align:center; transition:all 0.2s }
+.card .sample-btn:hover { background:var(--accent); color:#fff }
+
+@media (max-width:1024px) { .grid { grid-template-columns:repeat(min(var(--cols), 4), 1fr) } }
+@media (max-width:720px) { .grid { grid-template-columns:repeat(2, 1fr) } .density { display:none } }
+
+.sentinel { height:1px }
+.loading { text-align:center; color:var(--muted); padding:32px; font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700 }
+
+/* ===== Footer ===== */
+footer { padding:64px 32px 32px; border-top:1px solid var(--line); margin-top:32px }
+.footer-grid { max-width:1400px; margin:0 auto; display:grid; grid-template-columns:2fr 1fr 1fr 1fr; gap:48px; margin-bottom:48px }
+.footer-brand { font-size:24px; font-weight:300; letter-spacing:0.32em; text-transform:uppercase; margin-bottom:12px }
+.footer-text { font-size:13px; line-height:1.6; color:var(--muted); max-width:380px }
+.footer-col h4 { font-size:10px; letter-spacing:0.32em; text-transform:uppercase; font-weight:700; color:var(--paper); margin-bottom:18px }
+.footer-col a { display:block; font-size:13px; color:var(--muted); text-decoration:none; margin-bottom:8px; transition:color 0.2s; cursor:pointer; background:transparent; border:0; font-family:inherit; padding:0; text-align:left }
+.footer-col a:hover { color:var(--accent) }
+.footer-bottom { max-width:1400px; margin:0 auto; padding-top:24px; border-top:1px solid var(--line); display:flex; justify-content:space-between; flex-wrap:wrap; gap:16px; font-size:11px; letter-spacing:0.18em; text-transform:uppercase; color:var(--muted) }
+
+@media (max-width:720px) {
+  .corner-mark, .meta-line, .enter { font-size:10px }
+  .center-mark { font-size:24px; letter-spacing:0.12em; top:clamp(60px,9vh,90px) }
+  .section, footer { padding-left:20px; padding-right:20px }
+  .footer-grid { grid-template-columns:1fr; gap:32px }
+  .search { margin-left:0; flex:1 1 100% }
+}
+
+.theme-toggle { background:transparent; border:1px solid var(--line); width:32px; height:32px; cursor:pointer; color:var(--paper); display:inline-flex; align-items:center; justify-content:center; font-size:14px; line-height:1; transition:all .15s; padding:0 }
+.theme-toggle:hover { border-color:var(--accent); color:var(--accent) }
+
+/* ===== WCAG 2.4.7 — keyboard focus indicators ===== */
+/* Strictly :focus-visible so mouse clicks do NOT show the ring */
+a:focus-visible,
+button:focus-visible,
+input:focus-visible,
+select:focus-visible,
+textarea:focus-visible,
+[tabindex]:focus-visible {
+  outline: 2px solid var(--accent);
+  outline-offset: 2px;
+}
+</style>
+<script>
+(function(){ try { var t = localStorage.getItem('hosp_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://hospitalitywallpaper.com/">
+<meta property="og:title" content="Hospitality Wallpaper">
+<meta property="og:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta property="og:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Hospitality Wallpaper">
+<meta property="article:publisher" content="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:title" content="Hospitality Wallpaper">
+<meta name="twitter:description" content="Hospitality Wallpaper — Hospitality, hotel & class A wallcoverings.">
+<meta name="twitter:image" content="https://hospitalitywallpaper.com/hero-bg.jpg">
+<!-- graphics-loop pass 13: footer + fb -->
+</head>
+<body>
+<style id="ns-header-modal-styles">
+        .ns-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; padding: 18px 36px; background: rgba(10,10,10,0.92) !important; backdrop-filter: blur(8px); border-bottom: 1px solid rgba(245,241,232,0.06); }
+        .ns-brand { display: inline-flex; align-items: center; gap: 14px; text-decoration: none; }
+        .ns-dot { width: 28px; height: 28px; border-radius: 50%; background: var(--ns-dot-bg, radial-gradient(circle at 35% 35%, #b66a4d 0%, #8a4a30 60%, #5a2d1c 100%)); box-shadow: 0 0 0 1px rgba(245,241,232,0.10), 0 2px 12px rgba(180,90,60,0.30); flex-shrink: 0; }
+        .ns-name { font-family: -apple-system, "SF Pro Display", "Helvetica Neue", system-ui, sans-serif; font-size: 18px !important; font-weight: 300 !important; letter-spacing: 0.02em !important; color: #f5f1e8 !important; text-transform: none !important; margin: 0 !important; }
+        .ns-name sup { font-size: 0.55em; font-weight: 300; margin-left: 1px; }
+        .ns-nav a, .ns-nav button { font-family: -apple-system, "SF Pro Text", system-ui, sans-serif; font-size: 15px !important; font-weight: 400 !important; color: #f5f1e8 !important; text-decoration: none !important; background: none !important; border: 0 !important; cursor: pointer; transition: color 200ms; letter-spacing: 0 !important; text-transform: none !important; }
+        .ns-nav a:hover, .ns-nav button:hover { color: #ffffff !important; }
+        /* All widths: hide nav by default, hamburger always visible on right, nav opens as right-anchored dropdown panel */
+        .ns-nav {
+            display: none !important;
+            position: absolute; top: 100%; right: 18px;
+            flex-direction: column; align-items: stretch; gap: 0;
+            background: rgba(10,10,10,0.96); backdrop-filter: blur(10px);
+            border: 1px solid rgba(245,241,232,0.10); border-top: 0;
+            min-width: 220px; padding: 10px 0; margin: 0;
+            box-shadow: 0 16px 40px rgba(0,0,0,0.55);
+            z-index: 150;
+        }
+        .ns-nav.open { display: flex !important; }
+        .ns-nav a, .ns-nav button {
+            padding: 12px 22px !important;
+            border-bottom: 1px solid rgba(245,241,232,0.06);
+            width: 100%; text-align: left;
+        }
+        .ns-nav a:last-child, .ns-nav button:last-child { border-bottom: 0; }
+        .ns-nav a:hover, .ns-nav button:hover { background: rgba(245,241,232,0.06) !important; color: #ffffff !important; }
+        @media (max-width: 480px) { .ns-nav { right: 12px; min-width: 200px; } }
+        .ns-header .mobile-toggle { display: flex !important; align-items: center; justify-content: center; width: 36px; height: 36px; background: transparent; border: 0; cursor: pointer; padding: 0; gap: 4px; flex-direction: column; }
+        .ns-header .mobile-toggle span { display: block; width: 22px; height: 1.5px; background: #f5f1e8; transition: transform 200ms, opacity 200ms; }
+        .ns-header .mobile-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
+        .ns-header .mobile-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
+        .ns-header .mobile-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }
+    </style>
+<style id="ns-gold-kill">
+    /* novasuede: kill gold-solid fills, off-white instead. Edge color stays gold. */
+    .new-badge, .new-arrivals-pill,
+    .color-filter-btn.active, .drapery-btn,
+    .sample-btn-chip, .cb-cta {
+      background: #f5f1e8 !important;
+      color: #0a0a0a !important;
+      border-color: #f5f1e8 !important;
+    }
+    .new-badge:hover, .new-arrivals-pill:hover,
+    .color-filter-btn.active:hover, .drapery-btn:hover,
+    .sample-btn-chip:hover, .cb-cta:hover {
+      background: #fff !important;
+      color: #0a0a0a !important;
+    }
+  </style>
+<header class="ns-header">
+        <a href="/" class="ns-brand" aria-label="Home">
+            <span class="ns-dot"></span>
+            <span class="ns-name">Heritage Atelier</span>
+        </a>
+        <nav class="ns-nav" id="nsPrimaryNav" aria-label="Primary">
+            <a href="/">Home</a>
+            <a href="/about">About</a>
+            <button type="button" onclick="nsContactOpen()">Contact</button>
+        </nav>
+        <button type="button" class="mobile-toggle" aria-label="Toggle menu" aria-controls="nsPrimaryNav" aria-expanded="false" onclick="nsToggleNav(this)">
+            <span></span><span></span><span></span>
+        </button>
+    </header>
+
+<div class="ns-modal" id="nsContactModal" role="dialog" aria-modal="true" aria-labelledby="nsContactTitle" onclick="if(event.target===this)nsContactClose()">
+        <div class="ns-modal-card">
+            <button type="button" class="close-x" onclick="nsContactClose()" aria-label="Close">×</button>
+            <h3 id="nsContactTitle">How can we help?</h3>
+            <p class="sub">Trade-account replies within one business day.</p>
+            <div class="ns-actions">
+                <a class="ns-action" href="#contact" onclick="nsContactClose()"><span class="ico">📋</span><div class="txt"><b>Get a Quote</b><span>Project specs → priced estimate</span></div></a>
+                <a class="ns-action" href="#contact" onclick="nsContactClose();openModal();"><span class="ico">📦</span><div class="txt"><b>Order a Sample</b><span>Free swatch to your shop</span></div></a>
+                <a class="ns-action" href="mailto:info@hospitalitywallpaper.com?subject=Heritage%20Atelier%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@hospitalitywallpaper.com</span></div></a>
+                <a class="ns-action" href="tel:888-373-4564"><span class="ico">📞</span><div class="txt"><b>Call Us</b><span>(888) 373-4564 · M–F, 9–5 PT</span></div></a>
+            </div>
+        </div>
+    </div>
+<script>
+  function nsContactOpen() { var m = document.getElementById('nsContactModal'); if (m) m.classList.add('show'); }
+  function nsContactClose() { var m = document.getElementById('nsContactModal'); if (m) m.classList.remove('show'); }
+  function nsToggleNav(btn) {
+    var nav = document.getElementById('nsPrimaryNav');
+    if (!nav) return;
+    var open = nav.classList.toggle('open');
+    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
+  }
+  document.addEventListener('keydown', function(e){ if (e.key === 'Escape') nsContactClose(); });
+</script>
+
+
+
+
+
+
+
+
+
+
+
+<header>
+  <button class="h-link" onclick="dwmOpen('Contact')" aria-label="Contact"><svg class="h-icon" viewBox="0 0 24 24"><path d="M3 7h18M3 12h18M3 17h18"/></svg><span>Contact</span></button>
+  <button class="theme-toggle" id="theme-toggle" aria-label="Theme toggle">☾</button>
+</header>
+
+<section class="cinema">
+  <div class="cinema-bg" id="heroBg"></div>
+  <div class="corner-mark">Trade-Grade</div>
+  <div class="center-mark">Hospitality Wallpaper</div>
+  <div class="meta-line">Hotel · Restaurant · Spa · Class A<span class="num" id="heroNum"></span></div>
+  <a class="enter" href="#shop">Enter <svg viewBox="0 0 24 12" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M0 6h22M16 1l6 5-6 5"/></svg></a>
+</section>
+
+
+<section class="section" id="ideas">
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">New this week</h2>
+    <div class="rail" id="railNewest"></div>
+  </div>
+  <div class="rail-block">
+    <div class="rail-eyebrow">Ideas</div>
+    <h2 class="rail-title">Curated picks</h2>
+    <div class="rail" id="railCurated"></div>
+  </div>
+</section>
+
+<section class="section" id="shop">
+  <div class="section-header">
+    <div>
+      <div class="section-eyebrow">The Collection</div>
+      <h2 class="section-title"><span class="accent" id="totalCount">—</span> Patterns.</h2>
+    </div>
+    <div class="section-meta">Hotel · Restaurant · Spa · Class A</div>
+  </div>
+
+  <div class="filters" id="facets">
+    <button class="chip active" data-facet="all">All</button>
+  </div>
+
+  <div class="density">
+    <label>Sort</label>
+    <select id="sortSelect" aria-label="Sort products" style="background:transparent;color:inherit;border:1px solid var(--line,rgba(255,255,255,.2));font:inherit;font-size:11px;letter-spacing:.10em;text-transform:uppercase;padding:4px 8px;cursor:pointer;outline:none;margin-right:14px">
+      <option value="newest">Newest</option>
+      <option value="color">Color</option>
+      <option value="style">Style</option>
+      <option value="sku">SKU A→Z</option>
+      <option value="title">Title A→Z</option>
+      <option value="price-asc">Price ↑</option>
+      <option value="price-desc">Price ↓</option>
+    </select>
+    <label>Grid</label>
+    <input type="range" id="densitySlider" min="4" max="12" step="1" value="6" aria-label="Grid columns">
+    <span class="ct" id="densityLabel">6 cols</span>
+    <div class="search">
+      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-5.5-5.5"/></svg>
+      <input type="text" id="searchInput" placeholder="Search by pattern, color…" autocomplete="off">
+    </div>
+  </div>
+
+  <div class="stat-line" id="statLine">Loading…</div>
+  <div class="grid" id="grid"></div>
+  <div class="loading" id="loading">Loading more…</div>
+  <div class="sentinel" id="sentinel"></div>
+</section>
+
+<footer>
+  <div class="footer-grid">
+    <div>
+      <div class="footer-brand">Heritage Atelier</div>
+      <p class="footer-text">Heritage Atelier — real samples ship free.</p>
+      <p class="footer-text" style="margin-top:14px;font-size:11px;letter-spacing:0.18em;text-transform:uppercase;font-weight:600;color:var(--paper);opacity:0.7"><a href="/about" style="color:inherit;text-decoration:none;border-bottom:1px solid var(--accent)">About →</a></p>
+    </div>
+    <div class="footer-col">
+      <h4>Aesthetic</h4>
+      <div id="footerFacets"></div>
+    </div>
+    <div class="footer-col">
+      <h4>Trade</h4>
+      <button onclick="dwmOpen('Inquiry')">Project Inquiry</button>
+      <button onclick="dwmOpen('Sample')">Request Sample</button>
+      <button onclick="dwmOpen('Contact')">Contact</button>
+    </div>
+  
+    <div class="footer-col">
+      <h4>Social</h4>
+      <a class="fb-link" href="https://www.facebook.com/SteveAbramsDesigns.DesignerWallcoverings" target="_blank" rel="noopener">Facebook</a>
+    </div>
+  </div>
+  <div class="footer-bottom">
+    <span>hospitalitywallpaper.com · Heritage Atelier</span>
+    <span><a href="mailto:info@hospitalitywallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@hospitalitywallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "hospitalitywallpaper";
+  const NICHES = [
+    ['silkwallpaper','Silk','mat'],['silkwallcoverings','Silk W/C','mat'],['linenwallpaper','Linen','mat'],
+    ['jutewallpaper','Jute','mat'],['raffiawallcoverings','Raffia W/C','mat'],['raffiawalls','Raffia Walls','mat'],
+    ['corkwallcovering','Cork','mat'],['fabricwallpaper','Fabric','mat'],['textilewallpaper','Textile','mat'],
+    ['metallicwallpaper','Metallic','mat'],['silverleafwallpaper','Silver Leaf','mat'],['vinylwallpaper','Vinyl','mat'],
+    ['micawallpaper','Mica','mat'],['madagascarwallpaper','Madagascar','mat'],['mylarwallpaper','Mylar','mat'],
+    ['suedewallpaper','Suede','mat'],
+    ['1800swallpaper','1800s','dec'],['1890swallpaper','1890s','dec'],['1900swallpaper','1900s','dec'],
+    ['1920swallpaper','1920s','dec'],['1930swallpaper','1930s','dec'],['1940swallpaper','1940s','dec'],
+    ['1950swallpaper','1950s','dec'],['1960swallpaper','1960s','dec'],['1970swallpaper','1970s','dec'],
+    ['1980swallpaper','1980s','dec'],['retrowalls','Retro','dec'],['wallpapersback','W. Back','dec'],
+    ['agedwallpaper','Aged','cra'],['handcraftedwallpaper','Handcrafted','cra'],['museumwallpaper','Museum','cra'],
+    ['restorationwallpaper','Restoration','cra'],['pastelwallpaper','Pastel','cra'],['glitterwalls','Glitter','cra'],
+    ['greenwallcoverings','Green','cra'],['naturalwallcoverings','Natural','cra'],['saloonwallpaper','Saloon','cra'],
+    ['contractwallpaper','Contract','use'],['hotelwallcoverings','Hotel','use'],['hospitalitywallpaper','Hospitality','use'],
+    ['healthcarewallpaper','Healthcare','use'],['restaurantwallpaper','Restaurant','use'],['architecturalwallcoverings','Architectural','use']
+  ];
+  const COLOR = { mat:'#c9b687', dec:'#b86a4a', cra:'#6b8e6f', use:'#4a6b8e' };
+  const W = 1080, H = 200, BANDS = ['mat','dec','cra','use'];
+  const groups = { mat:[], dec:[], cra:[], use:[] };
+  for (const n of NICHES) groups[n[2]].push(n);
+  const svg = document.getElementById('miniConst');
+  if (!svg) return;
+  const bandW = W / BANDS.length;
+  let nodes = '';
+  BANDS.forEach((band, bi) => {
+    const list = groups[band];
+    const cx = bi * bandW + bandW / 2;
+    list.forEach((n, i) => {
+      const t = list.length === 1 ? 0.5 : i / (list.length - 1);
+      // deterministic jitter per slug
+      let h = 0; for (let k = 0; k < n[0].length; k++) h = (h * 31 + n[0].charCodeAt(k)) | 0;
+      const jx = ((h & 0xff) / 255 - 0.5) * (bandW * 0.5);
+      const jy = (((h >> 8) & 0xff) / 255 - 0.5) * 6;  // tightened from 14 → 6 to prevent same-band collisions (16 mat nodes / 144px = 9px spacing)
+      const x = cx + jx, y = 28 + t * (H - 56) + jy;
+      const isCurrent = n[0] === SLUG;
+      const r = isCurrent ? 8 : 4;
+      const op = isCurrent ? 1 : 0.55;
+      nodes += `<g class="mc-node" data-slug="${n[0]}" data-label="${n[1]}" style="cursor:pointer">
+        <circle cx="${x}" cy="${y}" r="${r}" fill="url(#dna-${band})" fill-opacity="${op}" stroke="${COLOR[band]}" stroke-opacity="${isCurrent?1:0.7}" stroke-width="${isCurrent?2:1}">
+          <title>${n[1]} — ${n[0]}.com</title>
+        </circle>
+        ${isCurrent ? `<circle cx="${x}" cy="${y}" r="${r+5}" fill="none" stroke="${COLOR[band]}" stroke-opacity="0.4" stroke-width="1"><animate attributeName="r" values="${r+5};${r+12};${r+5}" dur="2.4s" repeatCount="indefinite"/><animate attributeName="stroke-opacity" values="0.4;0;0.4" dur="2.4s" repeatCount="indefinite"/></circle>` : ''}
+      </g>`;
+    });
+  });
+  // append nodes after defs
+  svg.insertAdjacentHTML('beforeend', nodes);
+  svg.querySelectorAll('.mc-node').forEach(n => {
+    n.addEventListener('mouseenter', () => n.querySelector('circle').setAttribute('fill-opacity', '1'));
+    n.addEventListener('mouseleave', e => {
+      const isCurrent = n.dataset.slug === SLUG;
+      n.querySelector('circle').setAttribute('fill-opacity', isCurrent ? '1' : '0.55');
+    });
+    n.addEventListener('click', () => window.open('https://' + n.dataset.slug + '.com', '_blank'));
+  });
+})();
+</script>
+
+<script>
+const state = { q:'', facet:'all', page:1, pages:1, total:0, loading:false, exhausted:false };
+const LABELS = {"all":"All"};
+
+function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c])); }
+// Image-URL allowlist: only DW Shopify CDN + designerwallcoverings.com (defends against XSS via crafted products.json)
+function safeImg(u) { return /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(u || '') ? u : '/hero-bg.jpg'; }
+function cardHTML(p) {
+  const eager = state.page === 1;
+  return '<img loading="' + (eager ? 'eager' : 'lazy') + '"' + (eager ? ' fetchpriority="high"' : '') + ' src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+    + '<div class="overlay">'
+    + '<div class="pat">' + escAttr(p.pattern_name || p.title) + '</div>'
+    + '<div class="ven">' + escAttr((p.vendor || '').replace(/-/g, ' ')) + '</div>'
+    + '<div class="actions">'
+    + '<button class="sample-btn" onclick="event.stopPropagation();dwmOpen(\'Sample\',' + JSON.stringify({sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}).replace(/"/g,'&quot;') + ')">Sample</button>'
+    + '</div></div>';
+}
+
+async function loadFacets() {
+  let f;
+  try {
+    const r = await fetch('/api/facets');
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    f = await r.json();
+  } catch (e) { console.error('loadFacets failed:', e); return; }
+  const el = document.getElementById('facets');
+  for (const [k, v] of Object.entries(f.aesthetics).sort((a,b) => b[1] - a[1])) {
+    const b = document.createElement('button');
+    b.className = 'chip'; b.dataset.facet = k;
+    b.innerHTML = (LABELS[k] || k) + ' <span style="opacity:.55;font-weight:500;margin-left:4px">' + v + '</span>';
+    el.appendChild(b);
+  }
+  el.addEventListener('click', e => {
+    if (e.target.tagName !== 'BUTTON') return;
+    document.querySelectorAll('#facets button').forEach(b => b.classList.remove('active'));
+    e.target.classList.add('active');
+    state.facet = e.target.dataset.facet;
+    resetGrid();
+  });
+  document.getElementById('totalCount').textContent = f.total;
+  document.getElementById('footerStat').textContent = f.total + ' patterns · live archive';
+  // Footer aesthetic links
+  const footerEl = document.getElementById('footerFacets');
+  for (const [k] of Object.entries(f.aesthetics)) {
+    const b = document.createElement('button');
+    b.textContent = LABELS[k] || k;
+    b.onclick = () => { state.facet = k; resetGrid(); document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === k)); document.getElementById('shop').scrollIntoView({behavior:'smooth'}); };
+    footerEl.appendChild(b);
+  }
+}
+
+function resetGrid() {
+  state.page = 1; state.exhausted = false;
+  document.getElementById('grid').innerHTML = '';
+  document.getElementById('loading').textContent = 'Loading…';
+  loadGridPage();
+}
+
+async function loadGridPage() {
+  if (state.loading || state.exhausted) return;
+  state.loading = true;
+  const params = new URLSearchParams({ page:state.page, limit:24 });
+  if (state.q) params.set('q', state.q);
+  if (state.facet !== 'all') params.set('aesthetic', state.facet);
+  let data;
+  try {
+    const r = await fetch('/api/products?' + params);
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    data = await r.json();
+  } catch (e) {
+    console.error('loadGridPage failed:', e);
+    document.getElementById('loading').textContent = '— offline — refresh to retry —';
+    state.loading = false;
+    return;
+  }
+  state.total = data.total; state.pages = data.pages;
+
+  if (state.page === 1) {
+    document.getElementById('statLine').textContent = data.total + ' patterns · ' + (state.facet === 'all' ? 'all aesthetics' : (LABELS[state.facet] || state.facet)) + (state.q ? ' · matching "' + state.q + '"' : '');
+  }
+  const grid = document.getElementById('grid');
+  for (const p of data.items) {
+    const a = document.createElement('a');
+    a.className = 'card'; a.href = '#'; a.onclick = (e) => { e.preventDefault(); dwmOpen('Sample',{sku:p.sku||p.handle, title:p.title, image_url:safeImg(p.image_url)}); };
+    a.innerHTML = cardHTML(p);
+    grid.appendChild(a);
+  }
+  if (state.page >= state.pages || data.items.length === 0) {
+    state.exhausted = true;
+    document.getElementById('loading').textContent = state.total > 0 ? '— end of archive · ' + state.total + ' patterns —' : '';
+  } else state.page++;
+  state.loading = false;
+}
+
+const io = new IntersectionObserver(es => { for (const e of es) if (e.isIntersecting) loadGridPage(); }, { rootMargin:'600px 0px' });
+io.observe(document.getElementById('sentinel'));
+
+document.getElementById('searchInput').addEventListener('input', e => {
+  state.q = e.target.value.trim();
+  clearTimeout(window._t);
+  window._t = setTimeout(resetGrid, 220);
+});
+
+// Density slider
+const slider = document.getElementById('densitySlider');
+const dlabel = document.getElementById('densityLabel');
+function setDensity(n) {
+  document.documentElement.style.setProperty('--cols', n);
+  dlabel.textContent = n + ' cols';
+  try { localStorage.setItem('hosp_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('hosp_theme_density') || '6');
+if (savedDensity >= 4 && savedDensity <= 12) { slider.value = savedDensity; setDensity(savedDensity); }
+
+// Theme toggle
+const tb = document.getElementById('theme-toggle');
+function setTheme(t){ document.documentElement.dataset.theme = t; try { localStorage.setItem('hosp_theme', t); } catch(e){} tb.textContent = t === 'dark' ? '☾' : '☀'; }
+setTheme(document.documentElement.dataset.theme || 'light');
+tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
+
+loadFacets();
+loadGridPage();
+</script>
+<!-- ============================================================
+     DW UNIVERSAL CONTACT MODULE — fashion-house UX
+     Inject before
+ </body> in every DW-family sister site.
+     Self-contained: CSS + 4 modals + JS submission handlers.
+     Uses host site's CSS vars (--bg, --fg, --gold, --rule).
+     ============================================================ -->
+<style>
+  /* === MODAL BASE === */
+  .dwm{position:fixed;inset:0;background:rgba(0,0,0,0.78);display:none;align-items:center;justify-content:center;z-index:9999;padding:24px;overflow-y:auto}
+  .dwm.open{display:flex}
+  .dwm-box{background:var(--bg);border:1px solid var(--rule);max-width:520px;width:100%;padding:36px 32px;position:relative;max-height:90vh;overflow-y:auto;animation:dwm-in 0.25s ease}
+  @keyframes dwm-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
+  .dwm-box h3{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-weight:400;font-size:32px;line-height:1.05;margin-bottom:6px;color:var(--fg);letter-spacing:-0.01em}
+  .dwm-box .sub{color:var(--muted);font-size:12px;letter-spacing:0.16em;text-transform:uppercase;margin-bottom:24px;font-weight:500}
+  .dwm-close{position:absolute;top:18px;right:18px;background:transparent;border:0;color:var(--muted);font-size:24px;cursor:pointer;width:32px;height:32px;line-height:1;padding:0}
+  .dwm-close:hover{color:var(--gold)}
+  .dwm-preview{display:flex;gap:14px;align-items:center;padding:12px;background:var(--bg-soft);margin-bottom:18px}
+  .dwm-preview img{width:64px;height:64px;object-fit:cover}
+  .dwm-preview .pn{font-family:'Playfair Display',Georgia,serif;font-style:italic;font-size:15px;line-height:1.2;color:var(--fg)}
+  .dwm-preview .pc{font-size:10px;letter-spacing:0.14em;text-transform:uppercase;color:var(--muted);margin-top:4px}
+  .dwm-field{margin-bottom:14px}
+  .dwm-field label{display:block;font-size:10px;letter-spacing:0.18em;text-transform:uppercase;color:var(--muted);margin-bottom:6px;font-weight:500}
+  .dwm-field input,.dwm-field textarea,.dwm-field select{width:100%;border:0;border-bottom:1px solid var(--rule);background:transparent;padding:8px 4px;font-size:14px;font-family:inherit;color:var(--fg);outline:none;transition:border-color 0.2s}
+  .dwm-field input:focus,.dwm-field textarea:focus{border-bottom-color:var(--gold)}
+  .dwm-field textarea{min-height:60px;resize:vertical}
+  .dwm-submit{background:transparent;color:var(--muted, #c9b89e);border:1px solid var(--muted, #c9b89e);padding:14px 28px;font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:700;cursor:pointer;width:100%;margin-top:8px;transition:background 0.15s, color 0.15s}
+  .dwm-submit:hover{background:var(--muted, #c9b89e);color:var(--bg, #000)}
+  
+  .dwm-submit:disabled{opacity:0.5;cursor:default}
+  .dwm-status{margin-top:14px;font-size:11px;letter-spacing:0.16em;text-transform:uppercase;text-align:center;display:none}
+  .dwm-status.ok{color:var(--sage);display:block}
+  .dwm-status.err{color:#e08070;display:block}
+  /* contact-options */
+  .dwm-options{display:flex;flex-direction:column;gap:10px}
+  .dwm-option{display:flex;align-items:center;gap:14px;padding:18px 20px;background:transparent;border:1px solid var(--rule);color:var(--fg);font-family:inherit;font-size:11px;letter-spacing:0.20em;text-transform:uppercase;font-weight:600;cursor:pointer;text-decoration:none;transition:all 0.2s;text-align:left;width:100%}
+  .dwm-option:hover{border-color:var(--gold);color:var(--gold)}
+  .dwm-option svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.5;flex-shrink:0}
+  .dwm-option .lbl{flex:1;display:block}
+  .dwm-option .val{display:block;font-size:10px;letter-spacing:0.14em;text-transform:none;font-weight:500;opacity:0.65;margin-top:4px}
+
+/* graphics-loop pass 11: Ideas rails */
+#ideas { padding: 56px 24px 24px; max-width:1600px; margin:0 auto }
+#ideas .rail-block { margin-bottom:48px }
+#ideas .rail-eyebrow { font-size:11px; font-weight:700; letter-spacing:0.32em; text-transform:uppercase; color:var(--muted, #888); margin-bottom:8px }
+#ideas .rail-title { font-size:clamp(22px,2.6vw,32px); font-weight:500; letter-spacing:-0.01em; margin:0 0 18px; color:var(--ink,#fff) }
+#ideas .rail { display:flex; gap:14px; overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:8px; scrollbar-width:none }
+#ideas .rail::-webkit-scrollbar { display:none }
+#ideas .rail-card { flex:0 0 240px; scroll-snap-align:start; cursor:pointer; transition:transform 0.2s }
+#ideas .rail-card:hover { transform:translateY(-3px) }
+#ideas .rail-card img { width:100%; aspect-ratio:1; object-fit:cover; display:block; background:var(--card,#222) }
+#ideas .rail-card .rc-title { font-size:13px; font-weight:500; color:var(--paper,#fff); padding:8px 0 2px; line-height:1.3 }
+#ideas .rail-card .rc-meta  { font-size:11px; color:var(--muted,#888); letter-spacing:0.06em }
+@media (max-width:720px) { #ideas .rail-card { flex:0 0 160px } }
+</style>
+
+<!-- Contact options modal -->
+<div class="dwm" id="dwmContact" onclick="if(event.target===this)dwmClose('Contact')">
+  <div class="dwm-box" style="max-width:440px">
+    <button class="dwm-close" onclick="dwmClose('Contact')" aria-label="Close">×</button>
+    <h3>Contact</h3>
+    <p class="sub" id="dwmContactSub">Three ways to reach us</p>
+    <div class="dwm-options">
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Inquiry')">
+        <svg viewBox="0 0 24 24"><path d="M4 4h16v12H7l-3 3z"/></svg>
+        <span class="lbl">Send an Inquiry<span class="val">Project name · scope · all the details</span></span>
+      </button>
+      <button class="dwm-option" type="button" onclick="dwmClose('Contact');dwmOpen('Sample')">
+        <svg viewBox="0 0 24 24"><rect x="4" y="6" width="16" height="14"/><path d="M4 10h16M9 6V3h6v3"/></svg>
+        <span class="lbl">Request a Sample<span class="val">Memo sample · ships free · 3–5 business days</span></span>
+      </button>
+      <a class="dwm-option" id="dwmContactEmailLink" href="mailto:info@hospitalitywallpaper.com">
+        <svg viewBox="0 0 24 24"><path d="M3 6h18v12H3z"/><path d="M3 6l9 7 9-7"/></svg>
+        <span class="lbl">Email Us<span class="val" id="dwmContactEmailLabel">info@hospitalitywallpaper.com</span></span>
+      </a>
+    </div>
+  </div>
+</div>
+
+<!-- Inquiry modal -->
+<div class="dwm" id="dwmInquiry" onclick="if(event.target===this)dwmClose('Inquiry')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Inquiry')" aria-label="Close">×</button>
+    <h3>Project Inquiry</h3>
+    <p class="sub">We'll respond within one business day</p>
+    <form id="dwmInquiryForm" onsubmit="return dwmSubmit(event,'inquiry')">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Phone</label><input type="tel" name="phone"></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Project Name</label><input type="text" name="projectName" required></div>
+      <div class="dwm-field"><label>Project Scope</label><textarea name="projectScope" placeholder="Square footage · room count · timeline" required></textarea></div>
+      <div class="dwm-field"><label>Additional Information</label><textarea name="message" placeholder="Patterns of interest, finish preferences, budget"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Inquiry</button>
+      <div class="dwm-status" id="dwmInquiryStatus"></div>
+    </form>
+  </div>
+</div>
+
+<!-- Sample-request modal -->
+<div class="dwm" id="dwmSample" onclick="if(event.target===this)dwmClose('Sample')">
+  <div class="dwm-box">
+    <button class="dwm-close" onclick="dwmClose('Sample')" aria-label="Close">×</button>
+    <h3>Request a Sample</h3>
+    <p class="sub">Memo sample · ships free · 3–5 business days</p>
+    <div class="dwm-preview" id="dwmSamplePreview" style="display:none">
+      <img id="dwmSampleImg" src="" alt="">
+      <div><div class="pn" id="dwmSampleName"></div><div class="pc" id="dwmSampleSku"></div></div>
+    </div>
+    <form id="dwmSampleForm" onsubmit="return dwmSubmit(event,'sample')">
+      <input type="hidden" name="sku" id="dwmSampleSkuInput">
+      <input type="hidden" name="title" id="dwmSampleTitleInput">
+      <input type="hidden" name="image_url" id="dwmSampleImageInput">
+      <div class="dwm-field"><label>Name</label><input type="text" name="name" required></div>
+      <div class="dwm-field"><label>Email</label><input type="email" name="email" required></div>
+      <div class="dwm-field"><label>Company / Trade</label><input type="text" name="company"></div>
+      <div class="dwm-field"><label>Shipping Address</label><input type="text" name="address" placeholder="Street" required></div>
+      <div class="dwm-field" style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:8px">
+        <input type="text" name="city" placeholder="City" required>
+        <input type="text" name="state" placeholder="State" required>
+        <input type="text" name="zip" placeholder="ZIP" required>
+      </div>
+      <div class="dwm-field"><label>Notes (optional)</label><textarea name="message" placeholder="Project, sq.ft., timing"></textarea></div>
+      <button type="submit" class="dwm-submit">Send Sample Request</button>
+      <div class="dwm-status" id="dwmSampleStatus"></div>
+    </form>
+  </div>
+</div>
+
+<script>
+  // Universal modal control
+  function dwmOpen(name, opts){
+    document.getElementById('dwm' + name).classList.add('open');
+    document.body.style.overflow = 'hidden';
+    try { if (typeof gtag === 'function') gtag('event', 'modal_open', { modal_name: name, sku: (opts && opts.sku) || '' }); } catch(_){}
+    if (name === 'Sample' && opts) {
+      document.getElementById('dwmSamplePreview').style.display = 'flex';
+      document.getElementById('dwmSampleImg').src = opts.image_url || '';
+      document.getElementById('dwmSampleName').textContent = opts.title || '';
+      document.getElementById('dwmSampleSku').textContent = opts.sku || '';
+      document.getElementById('dwmSampleSkuInput').value = opts.sku || '';
+      document.getElementById('dwmSampleTitleInput').value = opts.title || '';
+      document.getElementById('dwmSampleImageInput').value = opts.image_url || '';
+    } else if (name === 'Sample') {
+      document.getElementById('dwmSamplePreview').style.display = 'none';
+      document.getElementById('dwmSampleSkuInput').value = '';
+      document.getElementById('dwmSampleTitleInput').value = '';
+      document.getElementById('dwmSampleImageInput').value = '';
+    }
+  }
+  function dwmClose(name){ document.getElementById('dwm'+name).classList.remove('open'); document.body.style.overflow=''; }
+
+  // Universal form submit — POSTs to /api/send-{kind}
+  async function dwmSubmit(e, kind) {
+    e.preventDefault();
+    const form = e.target;
+    const data = Object.fromEntries(new FormData(form).entries());
+    const btn = form.querySelector('.dwm-submit');
+    const status = form.querySelector('.dwm-status');
+    btn.disabled = true; const orig = btn.textContent; btn.textContent = 'Sending…';
+    status.className = 'dwm-status';
+    try {
+      const r = await fetch('/api/send-' + kind, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(data) });
+      if (!r.ok) throw new Error('HTTP '+r.status);
+      const j = await r.json();
+      try {
+        if (typeof gtag === 'function') {
+          if (kind === 'sample') gtag('event', 'memo_request', { sku: data.sku || '', title: data.title || '' });
+          else gtag('event', 'lead', { form_type: kind });
+        }
+      } catch(_){}
+      status.textContent = kind === 'sample' ? 'Sample request sent — ships within 3–5 business days' : 'Inquiry sent — we respond within 1 business day';
+      status.className = 'dwm-status ok';
+      btn.textContent = 'Sent ✓';
+      setTimeout(() => { dwmClose(kind === 'sample' ? 'Sample' : 'Inquiry'); btn.disabled = false; btn.textContent = orig; status.className = 'dwm-status'; form.reset(); }, 2800);
+    } catch (err) {
+      status.textContent = 'Send failed — please email info@designerwallcoverings.com';
+      status.className = 'dwm-status err';
+      btn.disabled = false; btn.textContent = orig;
+    }
+    return false;
+  }
+
+  // Wire up "Memo samples ship free" badge in hero to open sample modal directly
+  document.querySelectorAll('.hero .badge, [data-open-sample]').forEach(el => {
+    el.style.cursor = 'pointer';
+    el.addEventListener('click', () => dwmOpen('Sample'));
+  });
+
+  // Wire nav "Trade" link to inquiry modal
+  document.querySelectorAll('nav a[href*="designerwallcoverings.com"]').forEach(a => {
+    a.removeAttribute('target');
+    a.removeAttribute('href');
+    a.style.cursor = 'pointer';
+    a.addEventListener('click', e => { e.preventDefault(); dwmOpen('Contact'); });
+  });
+
+  // Override product card clicks — open Sample modal pre-filled instead of redirecting to DW
+  document.addEventListener('click', e => {
+    const card = e.target.closest('.card, .rail-card');
+    if (!card) return;
+    if (card.tagName === 'A' && (card.getAttribute('href') || '').startsWith('/sample/')) {
+      e.preventDefault();
+      const img = card.querySelector('img');
+      const pat = card.querySelector('.pat');
+      const sku = card.getAttribute('href').replace('/sample/', '');
+      dwmOpen('Sample', {
+        sku,
+        title: pat ? pat.textContent.trim() : '',
+        image_url: img ? img.src : ''
+      });
+    }
+  }, true);
+// DW STANDARD: hero pulls from products.json[0].image_url so dw-collections-viewer
+// drag-drop / hero-pin updates the live front page on next deploy.
+// Always upgrades to the largest Shopify variant (strips _NxN size suffix) so
+// the full-page hero stays sharp.
+// DW STANDARD: hero rotates through top-20 NEWEST products on each visit
+// (novasuede.com pattern). Fetches /api/products?limit=100, sorts by created_at desc,
+// takes the freshest 20, picks one per visit via localStorage counter.
+// Falls back to static /hero-bg.jpg on any error.
+(async function rotateHero() {
+  try {
+    const r = await fetch('/api/products?limit=100');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || [])
+      .filter(p => p && p.image_url && /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(p.image_url))
+      .sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')))
+      .slice(0, 20);
+    if (!items.length) return;
+    let visits = 0;
+    try {
+      visits = parseInt(localStorage.getItem('hero_visits') || '0', 10) || 0;
+      localStorage.setItem('hero_visits', String(visits + 1));
+    } catch(e) {}
+    const pick = items[visits % items.length];
+    // Strip _NxN size suffix to get the largest CDN variant
+    const url = pick.image_url.replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+    const bg = document.getElementById('heroBg') || document.getElementById('cinemaBg');
+    if (bg) bg.style.backgroundImage = "url('" + url + "')";
+  } catch (e) {}
+})();
+
+
+// DW STANDARD sort-select wire-up (added by fleet patcher)
+(function(){
+  const sortSel = document.getElementById('sortSelect');
+  if (!sortSel) return;
+  const KEY = location.hostname.replace(/\./g, '_') + '_sort';
+  const saved = localStorage.getItem(KEY);
+  if (saved) { try { sortSel.value = saved; } catch(e){} }
+  if (typeof state !== 'undefined') state.sort = sortSel.value;
+  sortSel.addEventListener('change', e => {
+    const v = e.target.value;
+    try { localStorage.setItem(KEY, v); } catch(e){}
+    if (typeof state !== 'undefined') state.sort = v;
+    if (typeof resetGrid === 'function') resetGrid();
+    else location.reload();
+  });
+})();
+
+// graphics-loop pass 11: hydrate Ideas rails from /api/products
+(async function hydrateIdeas() {
+  try {
+    const r = await fetch('/api/products?limit=80');
+    if (!r.ok) return;
+    const d = await r.json();
+    const items = (d.items || []).filter(p => p && p.image_url);
+    if (!items.length) return;
+    const sorted = [...items].sort((a,b) => String(b.created_at || '').localeCompare(String(a.created_at || '')));
+    const newest = sorted.slice(0, 12);
+    // Curated = deterministic offset slice (every 5th item starting at idx 3) for variety
+    const curated = items.filter((_, i) => i % 5 === 3).slice(0, 12);
+    function card(p) {
+      const url = (p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+      return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle || p.sku) + '">' +
+        '<img src="' + url + '" alt="' + (p.title || '').replace(/"/g, '&quot;') + '" loading="lazy">' +
+        '<div class="rc-title">' + ((p.title || '').split('|')[0] || '').trim() + '</div>' +
+        '<div class="rc-meta">' + (p.vendor || '') + '</div>' +
+      '</a>';
+    }
+    const r1 = document.getElementById('railNewest');
+    const r2 = document.getElementById('railCurated');
+    if (r1) r1.innerHTML = newest.map(card).join('');
+    if (r2) r2.innerHTML = curated.map(card).join('');
+  } catch(e) {}
+})();
+</script>
+
+<script src="/dw-fleet-nav.js" defer></script>
+</body>
+</html>
diff --git a/public/sourcing.html b/public/sourcing.html
new file mode 100644
index 0000000..54d38ba
--- /dev/null
+++ b/public/sourcing.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<html lang="en"><head>
+<!-- editorial-gen v1 -->
+<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
+<title>How we source — hospitalitywallpaper.com</title>
+<meta name="description" content="How we source — hospitality, the British way.">
+<link rel="canonical" href="https://hospitalitywallpaper.com/sourcing">
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:ui-sans-serif;background:#FFF;color:#1a1410;line-height:1.65;padding:60px 24px;min-height:100vh}
+.wrap{max-width:720px;margin:0 auto}
+.eyebrow{font-size:10px;letter-spacing:0.22em;text-transform:uppercase;color:#A47C5A;margin-bottom:18px}
+h1{font-family:'Cormorant', serif;font-style:italic;font-size:48px;line-height:1.1;letter-spacing:-0.02em;color:#1a1410;margin-bottom:32px}
+h2{font-family:'Cormorant', serif;font-size:22px;color:#A47C5A;margin:36px 0 12px;font-weight:500}
+p{margin-bottom:16px;color:#3a322c}
+ul{margin:12px 0 20px 18px}
+li{margin-bottom:8px;color:#3a322c}
+strong{color:#1a1410}
+a{color:#A47C5A;text-decoration:underline;text-underline-offset:3px}
+nav.foot{margin-top:56px;padding-top:24px;border-top:1px solid rgba(0,0,0,0.10);font-size:11px;letter-spacing:0.18em;text-transform:uppercase}
+nav.foot a{margin-right:22px;text-decoration:none}
+</style>
+</head><body>
+<div class="wrap">
+<div class="eyebrow">Editorial · sourcing · Heritage Atelier</div>
+<h1>How we source</h1>
+<p>At Studio Castel, our journey begins with a commitment to excellence — not merely in the final product, but in the meticulous process that precedes it. We are not bound by trends or fleeting aesthetics; our focus is singular: to curate wallcoverings that meet the exacting demands of the hospitality sector. This requires a discerning eye, an intimate understanding of materials, and relationships forged over decades with mills and manufacturers who share our ethos. Every roll we select is a testament to this philosophy, a balance of heritage and modernity, tradition and function.</p>  
+
+<h2>The Mills: A Legacy of Craftsmanship</h2>  
+
+<p>Our partnerships with mills are rooted in decades of trust and collaboration. We seek out those with a proven legacy in textile production, where the art of weaving and printing is not a relic of the past but a living, evolving practice. These mills often operate in regions where artisanal techniques have been honed over generations, ensuring that each piece carries a depth of skill that cannot be replicated by mass production. Our visits to these mills are not perfunctory; they are opportunities to inspect not only the final product but the entire process — from the selection of raw materials to the precision of the looms.</p>  
+
+<p>We prioritize mills that demonstrate a commitment to quality over quantity. This means rejecting those who compromise on standards to meet volume demands. Instead, we work with partners who understand that hospitality spaces require materials that endure — not just in appearance, but in resilience against the rigors of daily use.</p>  
+
+<h2>The Trade-Only Catalogs: Curating Exclusivity</h2>  
+
+<p>Our access to trade-only catalogs is a cornerstone of our curation process. These catalogs, which are not available to the general public, offer a glimpse into the most specialized and high-performance materials designed for commercial interiors. We scrutinize each entry with a critical eye, filtering out anything that fails to meet our exacting criteria. This is not a task of elimination for the sake of exclusivity; it is a deliberate effort to ensure that every option we present is both functional and aesthetically aligned with the needs of hospitality design.</p>  
+
+<p>These catalogs often feature limited-run materials, produced in quantities that reflect their suitability for specific applications. We leverage this exclusivity to provide our clients with options that are both unique and practical — materials that are not only visually compelling but also engineered for the environments in which they will be installed.</p>  
+
+<h2>Critieria for Inclusion: Precision and Purpose</h2>  
+
+<p>Every material we consider undergoes a rigorous evaluation based on three core criteria: substrate, repeat, and washfastness. The substrate — the base material upon which the design is applied — must be durable, flexible, and compatible with the environments it will serve. We favor those that balance strength with a tactile quality that enhances the spatial experience.</p>  
+
+<p>The repeat, or the distance between the repetition of a design, is measured with precision. In hospitality settings, this is critical: a poorly measured repeat can lead to misalignment, disrupting the visual harmony of a space. We ensure that every material we select has a repeat that is both mathematically sound and visually seamless.</p>  
+
+<p>Washfastness is perhaps the most critical factor. In spaces where cleaning is frequent and thorough, the ability of a material to withstand repeated exposure to water and detergents is non-negotiable. We test each material to ensure it meets the highest standards of resistance without compromising its appearance or integrity.</p>  
+
+<h2>What Gets Cut:
+<nav class="foot">
+<a href="/">Browse</a>
+<a href="/history">History</a>
+<a href="/vocabulary">Vocabulary</a>
+<a href="/sourcing">Sourcing</a>
+<a href="/care">Care</a>
+<a href="/trade">Trade</a>
+<a href="/about">About</a>
+</nav>
+</div></body></html>
\ No newline at end of file
diff --git a/public/trade.html b/public/trade.html
new file mode 100644
index 0000000..bedaa3d
--- /dev/null
+++ b/public/trade.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<html lang="en"><head>
+<!-- editorial-gen v1 -->
+<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
+<title>Trade program — hospitalitywallpaper.com</title>
+<meta name="description" content="Trade program — hospitality, the British way.">
+<link rel="canonical" href="https://hospitalitywallpaper.com/trade">
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:ui-sans-serif;background:#FFF;color:#1a1410;line-height:1.65;padding:60px 24px;min-height:100vh}
+.wrap{max-width:720px;margin:0 auto}
+.eyebrow{font-size:10px;letter-spacing:0.22em;text-transform:uppercase;color:#A47C5A;margin-bottom:18px}
+h1{font-family:'Cormorant', serif;font-style:italic;font-size:48px;line-height:1.1;letter-spacing:-0.02em;color:#1a1410;margin-bottom:32px}
+h2{font-family:'Cormorant', serif;font-size:22px;color:#A47C5A;margin:36px 0 12px;font-weight:500}
+p{margin-bottom:16px;color:#3a322c}
+ul{margin:12px 0 20px 18px}
+li{margin-bottom:8px;color:#3a322c}
+strong{color:#1a1410}
+a{color:#A47C5A;text-decoration:underline;text-underline-offset:3px}
+nav.foot{margin-top:56px;padding-top:24px;border-top:1px solid rgba(0,0,0,0.10);font-size:11px;letter-spacing:0.18em;text-transform:uppercase}
+nav.foot a{margin-right:22px;text-decoration:none}
+</style>
+</head><body>
+<div class="wrap">
+<div class="eyebrow">Editorial · trade · Heritage Atelier</div>
+<h1>Trade program</h1>
+<p>Welcome to Heritage Atelier’s trade and designer program, a curated gateway to exclusive wallcovering solutions for the hospitality sector. Our approach is rooted in precision, with every detail meticulously considered to align with the needs of professionals who shape spaces where comfort and elegance converge. Whether you’re designing a boutique hotel, a luxury suite, or a commercial lounge, our program offers tailored support, refined product selection, and a legacy of craftsmanship that spans decades.</p>  
+
+<h2>Who Qualifies for the Program</h2>  
+<p>The program is designed for professionals actively engaged in hospitality design and construction. This includes:</p>  
+<ul>  
+  <li>Interior designers specializing in hospitality environments</li>  
+  <li>Architects with a focus on commercial or residential spaces requiring bespoke finishes</li>  
+  <li>Contractors and general contractors with a proven track record in hospitality projects</li>  
+</ul>  
+<p>Qualification is based on a vetting process that prioritizes experience, portfolio relevance, and alignment with Heritage Atelier’s niche focus. Invitations are extended to those who demonstrate a commitment to quality and a discerning eye for detail.</p>  
+
+<h2>Access to Memo Samples</h2>  
+<p>Our memo samples are a cornerstone of the program, offering a tactile and visual glimpse into our curated collection. These samples are sent directly to approved professionals, ensuring they reflect the exact finishes, colors, and textures available for use. Each sample is accompanied by detailed specifications, enabling informed decision-making without the need for on-site visits. Requests are processed swiftly, with samples dispatched within 72 hours of approval.</p>  
+
+<h2>Lead Times and Delivery</h2>  
+<p>Standard lead times for wallcoverings range from 4 to 6 weeks, depending on the complexity of the design and availability of materials. For custom-print options, lead times are extended to accommodate bespoke requirements, with regular updates provided throughout the production process. We prioritize transparency, ensuring clients are informed of any potential delays and offered alternative solutions when necessary.</p>  
+
+<h2>NET-30 Terms and Financial Flexibility</h2>  
+<p>Approved trade and designer clients are eligible for NET-30 payment terms, reflecting our confidence in the professionalism and reliability of our partners. This arrangement allows for seamless project management, with invoicing issued upon delivery and payment expected within 30 days. All terms are clearly outlined in the agreement, ensuring clarity and mutual respect.</p>  
+
+<h2>Custom-Print Availability</h2>  
+<p>Heritage Atelier offers custom-print options tailored to the unique vision of each project. Our team collaborates closely with clients to develop bespoke patterns, colors, and finishes that align with brand identity and spatial requirements. Custom orders are produced in-house, ensuring consistency and quality, with a minimum order quantity of 50 linear meters per design.</p>  
+
+<h2>Legacy and Expertise: The Designer Wallcoverings Connection</h2>  
+<p>As part of the Designer Wallcoverings family, Heritage Atelier benefits from a legacy of excellence dating back to 1996. Our parent house has long been a trusted supplier to the design trade, offering an extensive inventory, real samples, and a dedicated team to support every inquiry. This heritage informs our approach, ensuring that every product and service is delivered with the precision and care expected by professionals in the field.</p>  
+
+<p>Whether you’re seeking a classic finish or a statement-making design, Heritage Atelier’s trade program is your partner in creating spaces that endure. Our commitment to hospitality is unwavering, and our collaboration with Designer Wallcoverings ensures that you receive the highest standard of service and product quality.</p>
+<nav class="foot">
+<a href="/">Browse</a>
+<a href="/history">History</a>
+<a href="/vocabulary">Vocabulary</a>
+<a href="/sourcing">Sourcing</a>
+<a href="/care">Care</a>
+<a href="/trade">Trade</a>
+<a href="/about">About</a>
+</nav>
+</div></body></html>
\ No newline at end of file
diff --git a/public/vocabulary.html b/public/vocabulary.html
new file mode 100644
index 0000000..f705f67
--- /dev/null
+++ b/public/vocabulary.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<html lang="en"><head>
+<!-- editorial-gen v1 -->
+<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
+<title>Design vocabulary — hospitalitywallpaper.com</title>
+<meta name="description" content="Design vocabulary — hospitality, the British way.">
+<link rel="canonical" href="https://hospitalitywallpaper.com/vocabulary">
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:ui-sans-serif;background:#FFF;color:#1a1410;line-height:1.65;padding:60px 24px;min-height:100vh}
+.wrap{max-width:720px;margin:0 auto}
+.eyebrow{font-size:10px;letter-spacing:0.22em;text-transform:uppercase;color:#A47C5A;margin-bottom:18px}
+h1{font-family:'Cormorant', serif;font-style:italic;font-size:48px;line-height:1.1;letter-spacing:-0.02em;color:#1a1410;margin-bottom:32px}
+h2{font-family:'Cormorant', serif;font-size:22px;color:#A47C5A;margin:36px 0 12px;font-weight:500}
+p{margin-bottom:16px;color:#3a322c}
+ul{margin:12px 0 20px 18px}
+li{margin-bottom:8px;color:#3a322c}
+strong{color:#1a1410}
+a{color:#A47C5A;text-decoration:underline;text-underline-offset:3px}
+nav.foot{margin-top:56px;padding-top:24px;border-top:1px solid rgba(0,0,0,0.10);font-size:11px;letter-spacing:0.18em;text-transform:uppercase}
+nav.foot a{margin-right:22px;text-decoration:none}
+</style>
+</head><body>
+<div class="wrap">
+<div class="eyebrow">Editorial · vocabulary · Heritage Atelier</div>
+<h1>Design vocabulary</h1>
+<p>Understanding the precise language of design is essential for buyers navigating the hospitality sector, where every detail contributes to the guest experience. Heritage Atelier’s curated approach demands clarity in terminology to ensure selections align with the functional and aesthetic needs of spaces ranging from boutique hotels to fine dining establishments. Below are key terms that define the materials, techniques, and finishes shaping the industry.</p>
+
+<h2>Weave</h2>
+<p>The interlacing of threads in a textile, determined by the method and direction of the threads. Weave affects durability, drape, and visual structure.</p>
+<ul>
+<li>A tightly woven linen finish on a wallcovering ensures resilience in high-traffic areas like lobbies, while a looser weave may be chosen for a more tactile, artisanal feel in private suites.</li>
+</ul>
+
+<h2>Loom</h2>
+<p>A machine or frame used to interweave threads to create fabric or wallcoverings. The type of loom influences the scale and precision of the design.</p>
+<ul>
+<li>Hand-loomed samples in Heritage Atelier’s collection highlight irregularities in the weave, adding a sense of craftsmanship to bespoke hotel corridors.</li>
+</ul>
+
+<h2>Trompe-l'œil</
+<nav class="foot">
+<a href="/">Browse</a>
+<a href="/history">History</a>
+<a href="/vocabulary">Vocabulary</a>
+<a href="/sourcing">Sourcing</a>
+<a href="/care">Care</a>
+<a href="/trade">Trade</a>
+<a href="/about">About</a>
+</nav>
+</div></body></html>
\ No newline at end of file
diff --git a/server.js.pre-sort-skill b/server.js.pre-sort-skill
new file mode 100644
index 0000000..3c4accd
--- /dev/null
+++ b/server.js.pre-sort-skill
@@ -0,0 +1,159 @@
+/**
+ * HOSPITALITY WALLPAPER — DW family vertical
+ * Curated slice from live designerwallcoverings.com Shopify catalog.
+ */
+const express = require('express');
+const helmet = require('helmet');
+const path = require('path');
+const fs = require('fs');
+
+const PORT = process.env.PORT || 9855;
+const DW_SHOPIFY = 'https://designerwallcoverings.com';
+const __SITE = path.basename(__dirname);
+let DATA_RAW;
+try {
+  const raw = fs.readFileSync(path.join(__dirname, 'data', 'products.json'), 'utf8');
+  DATA_RAW = JSON.parse(raw);
+  if (!Array.isArray(DATA_RAW)) throw new Error('products.json must be an array');
+} catch (e) {
+  console.error(`[${__SITE}] FATAL: could not load products.json — ${e.message}`);
+  console.error(`[${__SITE}] Starting with empty catalog. Run pull script to populate data/products.json.`);
+  DATA_RAW = [];
+}
+
+function isJunk(p) {
+  if (!p.image_url || !p.image_url.trim()) return true;
+  if (!p.handle && !p.sku) return true;
+  const t = p.title || '';
+  if (/lamp|rug|pillow|throw|tripod|frame|mirror|vase|candle|sculpture|figurine/i.test(t)) return true;
+  if (/visual.{0,3}merchandiser/i.test(t)) return true;
+  if (/(?:^|\W)image[ _-]?4(?:\W|$)/i.test(t)) return true;
+  if (/bh.?90210|beverly.?hills.?90210|iconic.{0,4}bh/i.test(t)) return true;
+  return false;
+}
+
+const PRODUCTS = DATA_RAW.filter(p => !isJunk(p));
+const DROPPED = DATA_RAW.length - PRODUCTS.length;
+console.log(`Loaded ${DATA_RAW.length}, kept ${PRODUCTS.length}, dropped ${DROPPED}`);
+
+// graphics-loop pass 12: niche keyword filter — only show products that fit this site's niche
+const NICHE_POS = ["hotel","restaurant","spa","class a","hospitality","luxury"];
+const NICHE_NEG = ["solid","blank","plain"];
+function nicheFit(p) {
+  const blob = ((p.title || '') + ' ' + (p.tags || []).join(' ')).toLowerCase();
+  if (NICHE_NEG.some(n => blob.includes(n.toLowerCase()))) return false;
+  return NICHE_POS.length === 0 || NICHE_POS.some(k => blob.includes(k.toLowerCase()));
+}
+const PRODUCTS_NICHE = PRODUCTS.filter(nicheFit);
+const NICHE_DROPPED = PRODUCTS.length - PRODUCTS_NICHE.length;
+console.log(`Niche filter: kept ${PRODUCTS_NICHE.length} of ${PRODUCTS.length}, dropped ${NICHE_DROPPED}`);
+// Replace PRODUCTS reference with the niche-filtered list for all downstream handlers.
+const PRODUCTS_ORIG = PRODUCTS;
+Object.defineProperty(global, '__products_niche_applied', { value: true });
+
+
+const app = express();
+// Security headers via helmet (added 2026-05-04 overnight YOLO loop)
+// DW STANDARD: sort by color/style/sku/title for any product-rendering site.
+const COLOR_RANK = {
+  black:0,gray:1,grey:1,silver:2,white:3,ivory:4,cream:5,beige:6,brown:7,tan:8,khaki:9,copper:10,
+  red:20,pink:21,coral:22,orange:23,peach:24,salmon:25,
+  yellow:30,gold:31,mustard:32,olive:33,
+  green:40,lime:41,mint:42,teal:50,aqua:51,turquoise:52,cyan:53,
+  blue:60,navy:61,indigo:62,periwinkle:63,
+  purple:70,violet:71,lavender:72,plum:73,magenta:74,fuchsia:75,
+};
+function colorRank(p) {
+  const tags = (p.tags || []).map(t => String(t).toLowerCase());
+  for (const t of tags) for (const k of Object.keys(COLOR_RANK)) if (t.includes(k)) return COLOR_RANK[k];
+  return 999;
+}
+const STYLE_TAGS = ['traditional','transitional','modern','contemporary','minimalist','art deco','victorian','mid-century','mid century','rustic','industrial','farmhouse','bohemian','boho','geometric','floral','botanical','damask','toile','grasscloth','silk','linen','vinyl','natural'];
+function styleKey(p) {
+  const tags = (p.tags || []).map(t => String(t).toLowerCase());
+  for (const s of STYLE_TAGS) if (tags.some(t => t.includes(s))) return s;
+  return 'zzz';
+}
+function sortProducts(list, mode) {
+  if (mode === 'sku') return [...list].sort((a,b) => String(a.sku || a.handle || '').localeCompare(String(b.sku || b.handle || '')));
+  if (mode === 'title') return [...list].sort((a,b) => String(a.title || '').localeCompare(String(b.title || '')));
+  if (mode === 'color') return [...list].sort((a,b) => colorRank(a) - colorRank(b) || String(a.title || '').localeCompare(String(b.title || '')));
+  if (mode === 'style') return [...list].sort((a,b) => styleKey(a).localeCompare(styleKey(b)) || String(a.title || '').localeCompare(String(b.title || '')));
+  if (mode === 'price-asc')  return [...list].sort((a,b) => (Number(a.max_price) || 0) - (Number(b.max_price) || 0));
+  if (mode === 'price-desc') return [...list].sort((a,b) => (Number(b.max_price) || 0) - (Number(a.max_price) || 0));
+  return list;
+}
+
+
+app.use(helmet({ contentSecurityPolicy: false }));
+app.use(express.json({ limit: '256kb' }));
+// Universal contact module — modals, /api/send-inquiry, /api/send-sample, /zd-loader.js
+require('./_universal-contact')(app, { siteName: "Hospitality Wallpaper", zdColor: "#d4a847", zdPosition: 'right' });
+require('./_universal-auth')(app, { siteName: "hospitalitywallpaper" });
+
+app.use(express.static(path.join(__dirname, 'public')));
+
+app.get('/api/products', (req, res) => {
+  const { q, aesthetic, vendor, page = 1, limit = 24, sort = 'newest'} = req.query;
+  let list = PRODUCTS_NICHE;
+  if (q) {
+    const needle = q.toLowerCase();
+    list = list.filter(p => (p.title || '').toLowerCase().includes(needle) || (p.tags || []).some(t => t.toLowerCase().includes(needle)));
+  }
+  if (aesthetic && aesthetic !== 'all') list = list.filter(p => p.aesthetic === aesthetic);
+  if (vendor && vendor !== 'all') list = list.filter(p => p.vendor === vendor);
+  list = sortProducts(list, sort);
+  const total = list.length;
+  const pageNum = Math.max(1, parseInt(page) || 1);
+  const lim = Math.min(60, parseInt(limit) || 24);
+  const start = (pageNum - 1) * lim;
+  res.json({ total, page: pageNum, limit: lim, pages: Math.ceil(total/lim), sort, items: list.slice(start, start + lim) });
+  // (replaced) old: pages: Math.ceil(total / lim), items: list.slice(start, start + lim) });
+});
+
+app.get('/api/sliders', (req, res) => {
+  const SLIDER_AESTHETICS = ["mural","luxury","botanical","chinoiserie","deco","natural"];
+  const out = [];
+  for (const a of SLIDER_AESTHETICS) {
+    const items = PRODUCTS_NICHE.filter(p => p.aesthetic === a).slice(0, 12);
+    if (items.length >= 4) out.push({ aesthetic: a, items });
+  }
+  res.json({ rails: out });
+});
+
+app.get('/api/facets', (req, res) => {
+  const aesthetics = {}; const vendors = {};
+  for (const p of PRODUCTS_NICHE) {
+    aesthetics[p.aesthetic] = (aesthetics[p.aesthetic] || 0) + 1;
+    vendors[p.vendor] = (vendors[p.vendor] || 0) + 1;
+  }
+  res.json({ aesthetics, vendors, total: PRODUCTS.length });
+});
+
+app.get('/api/health', (req, res) => res.json({ status: 'ok', count: PRODUCTS_NICHE.length, dropped: DROPPED }));
+
+app.get('/sample/:handle', (req, res) => {
+  const p = PRODUCTS_NICHE.find(x => x.handle === req.params.handle || x.sku === req.params.handle);
+  if (!p) return res.status(404).send('Not found');
+  res.redirect(302, p.product_url || `${DW_SHOPIFY}/products/${encodeURIComponent(p.handle)}#sample`);
+});
+
+// sitemap.xml + robots.txt for SEO
+app.get('/robots.txt', (req, res) => {
+  res.type('text/plain').send(`User-agent: *
+Allow: /
+Sitemap: https://hospitalitywallpaper.com/sitemap.xml
+`);
+});
+app.get('/sitemap.xml', (req, res) => {
+  const urls = ['/'];
+  const xml = `<?xml version="1.0" encoding="UTF-8"?>
+<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+${urls.map(u => `  <url><loc>https://hospitalitywallpaper.com${u}</loc><changefreq>weekly</changefreq></url>`).join('\n')}
+</urlset>`;
+  res.type('application/xml').send(xml);
+});
+
+app.listen(PORT, '127.0.0.1', () => {
+  console.log(`hospitalitywallpaper listening on http://127.0.0.1:${PORT}`);
+});

← caafd1d sort-skill UI: add Light→Dark / Dark→Light / Color Wheel opt  ·  back to Hospitalitywallpaper  ·  hamburger nav: apply canonical pattern from sister-site flee 34eba8f →