[object Object]

← back to Jutewallpaper

snapshot before fleet-grid refine

cec0790150a1a32fcf8db5d47682be4f56dfbc9e · 2026-05-11 03:02:55 -0700 · Steve Abrams

Files touched

Diff

commit cec0790150a1a32fcf8db5d47682be4f56dfbc9e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon May 11 03:02:55 2026 -0700

    snapshot before fleet-grid refine
---
 public/care.html                                |  55 ++
 public/history.html                             |  51 ++
 public/index.html.bak.dwfoot.1778203445674      | 969 +++++++++++++++++++++++
 public/index.html.bak.gtagev.1778426584872      | 977 +++++++++++++++++++++++
 public/index.html.bak.ns-canonical              | 984 ++++++++++++++++++++++++
 public/index.html.bak.nspropagate.1778203385106 | 954 +++++++++++++++++++++++
 public/index.html.bak.nspropagate.1778209715052 | 969 +++++++++++++++++++++++
 public/index.html.bak.nspropagate.1778226815153 | 971 +++++++++++++++++++++++
 public/index.html.bak.nspropagate.1778226888805 | 973 +++++++++++++++++++++++
 public/index.html.pre-sort-frontend             | 857 +++++++++++++++++++++
 public/sourcing.html                            |  60 ++
 public/trade.html                               |  55 ++
 public/vocabulary.html                          |  83 ++
 server.js.pre-sort-skill                        | 159 ++++
 14 files changed, 8117 insertions(+)

diff --git a/public/care.html b/public/care.html
new file mode 100644
index 0000000..24c8cd1
--- /dev/null
+++ b/public/care.html
@@ -0,0 +1,55 @@
+<!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 — jutewallpaper.com</title>
+<meta name="description" content="Care &amp; installation — jute. Woven by hand.">
+<link rel="canonical" href="https://jutewallpaper.com/care">
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:ui-sans-serif;background:#F4F0E6;color:#107A3B;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:#107A3B;margin-bottom:18px}
+h1{font-family:'Recoleta', 'Playfair Display', serif;font-style:italic;font-size:48px;line-height:1.1;letter-spacing:-0.02em;color:#107A3B;margin-bottom:32px}
+h2{font-family:'Recoleta', 'Playfair Display', serif;font-size:22px;color:#107A3B;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:#107A3B}
+a{color:#107A3B;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 · Filato</div>
+<h1>Care &amp; installation</h1>
+<p>Installation and care of jute wallcoverings demand precision and respect for the material’s inherent properties. This guide outlines essential steps to ensure longevity and performance, adhering to the discipline of craft and the rigor of Italian design.</p>  
+
+<h2>Substrate Preparation</h2>  
+<p>Begin with a clean, dry, and stable surface. Remove any existing adhesives, grease, or residue using a mild solvent. Fill cracks and holes with a suitable compound, ensuring the wall is smooth and even. Porous surfaces must be sealed with a primer compatible with jute. Avoid substrates with high moisture content; if unavoidable, allow full drying before proceeding.</p>  
+
+<h2>Paste Selection and Application</h2>  
+<p>Use a water-based, high-adhesion paste specifically formulated for natural fibers. Avoid starch or wheat-based products, which may degrade over time. Apply paste evenly to the back of the wallcovering, ensuring full coverage without excess pooling. Slightly dilute the paste if the backing is dense, to prevent stiffness. Work in sections, pressing firmly to eliminate air pockets and ensure adhesion.</p>  
+
+<h2>Seam Handling</h2>  
+<p>Align seams precisely, using a utility knife to trim the paper backing for a clean edge. Overlap seams by 1–2 cm, pressing with a seam roller to secure. Avoid stretching the material, as this may cause buckling or distortion. Trim excess at the top and bottom, leaving a margin for future adjustments. For wide panels, use a T-square to maintain straight alignment.</p>  
+
+<h2>Cleaning and Maintenance</h2>  
+<p>Dust regularly with a soft, dry brush to prevent particulate buildup. For localized stains, use a damp cloth with mild, neutral soap. Blot, never rub, to avoid fiber damage. Avoid direct contact with water, steam, or chemical cleaners. In high-traffic areas, wipe spills immediately. Do not use abrasive tools or solvents, which may compromise the surface.</p>  
+
+<h2>Light Exposure and Environmental Factors</h2>  
+<p>Prolonged exposure to direct sunlight will cause fading. Mitigate this by using UV-filtering window films or curtains. Avoid placing jute in areas with high humidity, such as bathrooms or kitchens, where moisture may lead to mold or degradation. In fluctuating climates, maintain stable indoor conditions to prevent warping or loosening of the adhesive.</p>  
+
+<h2>Lifespan and Long-Term Considerations</h2>  
+<p>With proper care, jute wallcoverings can last 10–15 years. Performance depends on installation quality, environmental conditions, and maintenance. Regular inspections for wear, adhesive failure, or discoloration are critical. If damage occurs, replace affected sections promptly to preserve the integrity of the overall application. Avoid overloading seams with heavy objects, which may cause tearing or separation.</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/history.html b/public/history.html
new file mode 100644
index 0000000..3a58b23
--- /dev/null
+++ b/public/history.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>A short history — jutewallpaper.com</title>
+<meta name="description" content="A short history — jute. Woven by hand.">
+<link rel="canonical" href="https://jutewallpaper.com/history">
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:ui-sans-serif;background:#F4F0E6;color:#107A3B;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:#107A3B;margin-bottom:18px}
+h1{font-family:'Recoleta', 'Playfair Display', serif;font-style:italic;font-size:48px;line-height:1.1;letter-spacing:-0.02em;color:#107A3B;margin-bottom:32px}
+h2{font-family:'Recoleta', 'Playfair Display', serif;font-size:22px;color:#107A3B;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:#107A3B}
+a{color:#107A3B;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 · Filato</div>
+<h1>A short history</h1>
+<p>Jute’s journey as a wallcovering is not one of floral motifs or ornamental excess, but of materiality and function. Its history is etched into the walls of factories, the floors of mills, and the ceilings of rooms where utility and aesthetics converged. From the late 19th century to the present, jute has been shaped by the hands of industrialists, the philosophies of designers, and the demands of eras that valued its raw, unpretentious character. This is the story of a material that never sought to be anything other than itself.</p>
+
+<h2>The Industrial Crucible: Late 19th Century</h2>
+
+<p>The roots of jute as a wallcovering trace to the mechanized mills of Bengal, where the crop was first spun into rope and burlap. By the 1870s, the material had begun to leave its agrarian origins, finding its way into the interiors of British colonial homes. Here, jute was pressed into sheets, its fibrous surface left unadorned. It was not wallpaper in the traditional sense, but a utilitarian solution for damp, humid climates. The material’s resilience—its ability to withstand humidity and pests—made it a fixture in the kitchens and storage rooms of estates, where it was layered over wood or plaster. These early uses were pragmatic, not decorative, yet they established jute’s reputation as a material of endurance.</p>
+
+<p>The mills of Dundee, Scotland, later refined this process. In the 1880s, Scottish manufacturers began experimenting with jute’s tensile strength, weaving it into broader, more uniform sheets. These were exported to Europe and the Americas, where they were used to line walls in factories and warehouses. The material’s rough, tactile surface became a hallmark of industrial modernity, a symbol of the era’s embrace of unvarnished materials.</p>
+
+<h2>Modernism’s Edge: Bauhaus and the 1920s</h2>
+
+<p>By the 1920s, jute had entered the realm of design. The Bauhaus school, with its focus on material honesty, found in jute a material that aligned with its ethos. The school’s workshops in Dessau and Weimar experimented with jute’s potential, using it in interior partitions and as a base for experimental pigments. These applications were not decorative but structural—jute was stretched across frames, its fibers left exposed to emphasize the material’s natural grain. The material’s neutrality, its ability to absorb and reflect light, made it a canvas for the era’s minimalist ambitions.</p>
+
+<p>Architects like Walter Gropius and Hannes Meyer incorporated jute into their designs, particularly in communal spaces. In the Bauhaus dormitories, jute was used to line walls, its surface left untreated. This was not a rejection of beauty but a redefinition of it: beauty as function, as materiality unadorned. The material’s presence in these spaces was a quiet assertion of modernity’s values—practicality, clarity, and the rejection of ornament for its own sake.</p>
+
+<h2>Postwar America: The 1950s and the Rise of the
+<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.1778203445674 b/public/index.html.bak.dwfoot.1778203445674
new file mode 100644
index 0000000..8607abf
--- /dev/null
+++ b/public/index.html.bak.dwfoot.1778203445674
@@ -0,0 +1,969 @@
+<!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-RZY8H2V0TG"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-RZY8H2V0TG');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Filato — jute. Woven by hand.</title>
+<meta name="description" content="Filato is a curated atelier dedicated entirely to jute. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#F4F0E6">
+<link rel="canonical" href="https://jutewallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;1,400&family=Inter:wght@300;400;500;600&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": "Filato",
+  "url": "https://jutewallpaper.com/",
+  "email": "info@jutewallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #F4F0E6;
+  --paper: #0e1311;
+  --muted: #8B7866;
+  --line: #1d2a23;
+  --accent: #107A3B;
+  --bg-soft: #1d2a23;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #0e1311;
+  --paper: #F4F0E6;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #107A3B;
+  --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:'Recoleta', Georgia, serif !important; font-weight:500 !important; font-style:italic !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('jute_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&display=swap">
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://jutewallpaper.com/">
+<meta property="og:title" content="Jute Wallpaper">
+<meta property="og:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta property="og:image" content="https://jutewallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Jute 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="Jute Wallpaper">
+<meta name="twitter:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta name="twitter:image" content="https://jutewallpaper.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">Filato</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">Earth Woven</div>
+  <div class="center-mark">Jute Wallpaper</div>
+  <div class="meta-line">Jute · Sisal · Grasscloth · Raffia<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">Jute · Sisal · Grasscloth · Raffia</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">Jute Wallpaper</div>
+      <p class="footer-text">Jute Wallpaper is a specialty jute 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>jutewallpaper.com · Filato</span>
+    <span><a href="mailto:info@jutewallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@jutewallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "jutewallpaper";
+  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('jute_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('jute_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('jute_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 5: serif hero typography + nav legibility */
+.cinema h1, h1.headline { font-family: 'Libre Baskerville', Georgia, serif; font-weight: 500; letter-spacing: -0.01em }
+.h-link { font-size: 13px; letter-spacing: 0.06em }
+
+/* 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@jutewallpaper.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@jutewallpaper.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.1778426584872 b/public/index.html.bak.gtagev.1778426584872
new file mode 100644
index 0000000..5c11b95
--- /dev/null
+++ b/public/index.html.bak.gtagev.1778426584872
@@ -0,0 +1,977 @@
+<!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-RZY8H2V0TG"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-RZY8H2V0TG');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Filato — jute. Woven by hand.</title>
+<meta name="description" content="Filato is a curated atelier dedicated entirely to jute. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#F4F0E6">
+<link rel="canonical" href="https://jutewallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;1,400&family=Inter:wght@300;400;500;600&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": "Filato",
+  "url": "https://jutewallpaper.com/",
+  "email": "info@jutewallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #F4F0E6;
+  --paper: #0e1311;
+  --muted: #8B7866;
+  --line: #1d2a23;
+  --accent: #107A3B;
+  --bg-soft: #1d2a23;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #0e1311;
+  --paper: #F4F0E6;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #107A3B;
+  --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:'Recoleta', Georgia, serif !important; font-weight:500 !important; font-style:italic !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('jute_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&display=swap">
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://jutewallpaper.com/">
+<meta property="og:title" content="Jute Wallpaper">
+<meta property="og:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta property="og:image" content="https://jutewallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Jute 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="Jute Wallpaper">
+<meta name="twitter:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta name="twitter:image" content="https://jutewallpaper.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">Filato</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@jutewallpaper.com?subject=Filato%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@jutewallpaper.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">Earth Woven</div>
+  <div class="center-mark">Jute Wallpaper</div>
+  <div class="meta-line">Jute · Sisal · Grasscloth · Raffia<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">Jute · Sisal · Grasscloth · Raffia</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">Filato</div>
+      <p class="footer-text">Filato — 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>jutewallpaper.com · Filato</span>
+    <span><a href="mailto:info@jutewallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@jutewallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "jutewallpaper";
+  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('jute_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('jute_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('jute_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 5: serif hero typography + nav legibility */
+.cinema h1, h1.headline { font-family: 'Libre Baskerville', Georgia, serif; font-weight: 500; letter-spacing: -0.01em }
+.h-link { font-size: 13px; letter-spacing: 0.06em }
+
+/* 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@jutewallpaper.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@jutewallpaper.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.ns-canonical b/public/index.html.bak.ns-canonical
new file mode 100644
index 0000000..f940246
--- /dev/null
+++ b/public/index.html.bak.ns-canonical
@@ -0,0 +1,984 @@
+<!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-RZY8H2V0TG"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-RZY8H2V0TG');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Filato — jute. Woven by hand.</title>
+<meta name="description" content="Filato is a curated atelier dedicated entirely to jute. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#F4F0E6">
+<link rel="canonical" href="https://jutewallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;1,400&family=Inter:wght@300;400;500;600&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": "Filato",
+  "url": "https://jutewallpaper.com/",
+  "email": "info@jutewallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #F4F0E6;
+  --paper: #0e1311;
+  --muted: #8B7866;
+  --line: #1d2a23;
+  --accent: #107A3B;
+  --bg-soft: #1d2a23;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #0e1311;
+  --paper: #F4F0E6;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #107A3B;
+  --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:'Recoleta', Georgia, serif !important; font-weight:500 !important; font-style:italic !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('jute_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&display=swap">
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://jutewallpaper.com/">
+<meta property="og:title" content="Jute Wallpaper">
+<meta property="og:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta property="og:image" content="https://jutewallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Jute 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="Jute Wallpaper">
+<meta name="twitter:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta name="twitter:image" content="https://jutewallpaper.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">Filato</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@jutewallpaper.com?subject=Filato%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@jutewallpaper.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">Earth Woven</div>
+  <div class="center-mark">Jute Wallpaper</div>
+  <div class="meta-line">Jute · Sisal · Grasscloth · Raffia<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">Jute · Sisal · Grasscloth · Raffia</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">Filato</div>
+      <p class="footer-text">Filato — 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>jutewallpaper.com · Filato</span>
+    <span><a href="mailto:info@jutewallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@jutewallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "jutewallpaper";
+  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('jute_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('jute_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('jute_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 5: serif hero typography + nav legibility */
+.cinema h1, h1.headline { font-family: 'Libre Baskerville', Georgia, serif; font-weight: 500; letter-spacing: -0.01em }
+.h-link { font-size: 13px; letter-spacing: 0.06em }
+
+/* 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@jutewallpaper.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@jutewallpaper.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>
+
+</body>
+</html>
diff --git a/public/index.html.bak.nspropagate.1778203385106 b/public/index.html.bak.nspropagate.1778203385106
new file mode 100644
index 0000000..e7bce1e
--- /dev/null
+++ b/public/index.html.bak.nspropagate.1778203385106
@@ -0,0 +1,954 @@
+<!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-RZY8H2V0TG"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-RZY8H2V0TG');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Filato — jute. Woven by hand.</title>
+<meta name="description" content="Filato is a curated atelier dedicated entirely to jute. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#F4F0E6">
+<link rel="canonical" href="https://jutewallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;1,400&family=Inter:wght@300;400;500;600&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": "Filato",
+  "url": "https://jutewallpaper.com/",
+  "email": "info@jutewallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #F4F0E6;
+  --paper: #0e1311;
+  --muted: #8B7866;
+  --line: #1d2a23;
+  --accent: #107A3B;
+  --bg-soft: #1d2a23;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #0e1311;
+  --paper: #F4F0E6;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #107A3B;
+  --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:'Recoleta', Georgia, serif !important; font-weight:500 !important; font-style:italic !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('jute_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&display=swap">
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://jutewallpaper.com/">
+<meta property="og:title" content="Jute Wallpaper">
+<meta property="og:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta property="og:image" content="https://jutewallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Jute 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="Jute Wallpaper">
+<meta name="twitter:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta name="twitter:image" content="https://jutewallpaper.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="Filato home">
+            <span class="ns-dot"></span>
+            <span class="ns-name">Filato</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">Earth Woven</div>
+  <div class="center-mark">Jute Wallpaper</div>
+  <div class="meta-line">Jute · Sisal · Grasscloth · Raffia<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">Jute · Sisal · Grasscloth · Raffia</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">Jute Wallpaper</div>
+      <p class="footer-text">Jute Wallpaper is a specialty jute 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>jutewallpaper.com · Filato</span>
+    <span><a href="mailto:info@jutewallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@jutewallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "jutewallpaper";
+  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('jute_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('jute_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('jute_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 5: serif hero typography + nav legibility */
+.cinema h1, h1.headline { font-family: 'Libre Baskerville', Georgia, serif; font-weight: 500; letter-spacing: -0.01em }
+.h-link { font-size: 13px; letter-spacing: 0.06em }
+
+/* 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@jutewallpaper.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@jutewallpaper.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.1778209715052 b/public/index.html.bak.nspropagate.1778209715052
new file mode 100644
index 0000000..73d6107
--- /dev/null
+++ b/public/index.html.bak.nspropagate.1778209715052
@@ -0,0 +1,969 @@
+<!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-RZY8H2V0TG"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-RZY8H2V0TG');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Filato — jute. Woven by hand.</title>
+<meta name="description" content="Filato is a curated atelier dedicated entirely to jute. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#F4F0E6">
+<link rel="canonical" href="https://jutewallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;1,400&family=Inter:wght@300;400;500;600&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": "Filato",
+  "url": "https://jutewallpaper.com/",
+  "email": "info@jutewallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #F4F0E6;
+  --paper: #0e1311;
+  --muted: #8B7866;
+  --line: #1d2a23;
+  --accent: #107A3B;
+  --bg-soft: #1d2a23;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #0e1311;
+  --paper: #F4F0E6;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #107A3B;
+  --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:'Recoleta', Georgia, serif !important; font-weight:500 !important; font-style:italic !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('jute_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&display=swap">
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://jutewallpaper.com/">
+<meta property="og:title" content="Jute Wallpaper">
+<meta property="og:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta property="og:image" content="https://jutewallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Jute 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="Jute Wallpaper">
+<meta name="twitter:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta name="twitter:image" content="https://jutewallpaper.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">Filato</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">Earth Woven</div>
+  <div class="center-mark">Jute Wallpaper</div>
+  <div class="meta-line">Jute · Sisal · Grasscloth · Raffia<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">Jute · Sisal · Grasscloth · Raffia</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">Filato</div>
+      <p class="footer-text">Filato — 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>jutewallpaper.com · Filato</span>
+    <span><a href="mailto:info@jutewallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@jutewallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "jutewallpaper";
+  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('jute_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('jute_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('jute_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 5: serif hero typography + nav legibility */
+.cinema h1, h1.headline { font-family: 'Libre Baskerville', Georgia, serif; font-weight: 500; letter-spacing: -0.01em }
+.h-link { font-size: 13px; letter-spacing: 0.06em }
+
+/* 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@jutewallpaper.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@jutewallpaper.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.1778226815153 b/public/index.html.bak.nspropagate.1778226815153
new file mode 100644
index 0000000..1654f73
--- /dev/null
+++ b/public/index.html.bak.nspropagate.1778226815153
@@ -0,0 +1,971 @@
+<!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-RZY8H2V0TG"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-RZY8H2V0TG');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Filato — jute. Woven by hand.</title>
+<meta name="description" content="Filato is a curated atelier dedicated entirely to jute. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#F4F0E6">
+<link rel="canonical" href="https://jutewallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;1,400&family=Inter:wght@300;400;500;600&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": "Filato",
+  "url": "https://jutewallpaper.com/",
+  "email": "info@jutewallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #F4F0E6;
+  --paper: #0e1311;
+  --muted: #8B7866;
+  --line: #1d2a23;
+  --accent: #107A3B;
+  --bg-soft: #1d2a23;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #0e1311;
+  --paper: #F4F0E6;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #107A3B;
+  --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:'Recoleta', Georgia, serif !important; font-weight:500 !important; font-style:italic !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('jute_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&display=swap">
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://jutewallpaper.com/">
+<meta property="og:title" content="Jute Wallpaper">
+<meta property="og:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta property="og:image" content="https://jutewallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Jute 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="Jute Wallpaper">
+<meta name="twitter:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta name="twitter:image" content="https://jutewallpaper.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">Filato</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@jutewallpaper.com?subject=Filato%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@jutewallpaper.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">Earth Woven</div>
+  <div class="center-mark">Jute Wallpaper</div>
+  <div class="meta-line">Jute · Sisal · Grasscloth · Raffia<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">Jute · Sisal · Grasscloth · Raffia</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">Filato</div>
+      <p class="footer-text">Filato — 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>jutewallpaper.com · Filato</span>
+    <span><a href="mailto:info@jutewallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@jutewallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "jutewallpaper";
+  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('jute_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('jute_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('jute_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 5: serif hero typography + nav legibility */
+.cinema h1, h1.headline { font-family: 'Libre Baskerville', Georgia, serif; font-weight: 500; letter-spacing: -0.01em }
+.h-link { font-size: 13px; letter-spacing: 0.06em }
+
+/* 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@jutewallpaper.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@jutewallpaper.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.1778226888805 b/public/index.html.bak.nspropagate.1778226888805
new file mode 100644
index 0000000..b863223
--- /dev/null
+++ b/public/index.html.bak.nspropagate.1778226888805
@@ -0,0 +1,973 @@
+<!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-RZY8H2V0TG"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-RZY8H2V0TG');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Filato — jute. Woven by hand.</title>
+<meta name="description" content="Filato is a curated atelier dedicated entirely to jute. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#F4F0E6">
+<link rel="canonical" href="https://jutewallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;1,400&family=Inter:wght@300;400;500;600&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": "Filato",
+  "url": "https://jutewallpaper.com/",
+  "email": "info@jutewallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #F4F0E6;
+  --paper: #0e1311;
+  --muted: #8B7866;
+  --line: #1d2a23;
+  --accent: #107A3B;
+  --bg-soft: #1d2a23;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #0e1311;
+  --paper: #F4F0E6;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #107A3B;
+  --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:'Recoleta', Georgia, serif !important; font-weight:500 !important; font-style:italic !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('jute_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&display=swap">
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://jutewallpaper.com/">
+<meta property="og:title" content="Jute Wallpaper">
+<meta property="og:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta property="og:image" content="https://jutewallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Jute 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="Jute Wallpaper">
+<meta name="twitter:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta name="twitter:image" content="https://jutewallpaper.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">Filato</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@jutewallpaper.com?subject=Filato%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@jutewallpaper.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">Earth Woven</div>
+  <div class="center-mark">Jute Wallpaper</div>
+  <div class="meta-line">Jute · Sisal · Grasscloth · Raffia<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">Jute · Sisal · Grasscloth · Raffia</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">Filato</div>
+      <p class="footer-text">Filato — 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>jutewallpaper.com · Filato</span>
+    <span><a href="mailto:info@jutewallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@jutewallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "jutewallpaper";
+  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('jute_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('jute_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('jute_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 5: serif hero typography + nav legibility */
+.cinema h1, h1.headline { font-family: 'Libre Baskerville', Georgia, serif; font-weight: 500; letter-spacing: -0.01em }
+.h-link { font-size: 13px; letter-spacing: 0.06em }
+
+/* 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@jutewallpaper.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@jutewallpaper.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.pre-sort-frontend b/public/index.html.pre-sort-frontend
new file mode 100644
index 0000000..2ff0f29
--- /dev/null
+++ b/public/index.html.pre-sort-frontend
@@ -0,0 +1,857 @@
+<!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-RZY8H2V0TG"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'G-RZY8H2V0TG');
+</script>
+
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Filato — jute. Woven by hand.</title>
+<meta name="description" content="Filato is a curated atelier dedicated entirely to jute. We do one thing — and we do it carefully.">
+<meta name="theme-color" content="#F4F0E6">
+<link rel="canonical" href="https://jutewallpaper.com/">
+<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;1,400&family=Inter:wght@300;400;500;600&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": "Filato",
+  "url": "https://jutewallpaper.com/",
+  "email": "info@jutewallpaper.com"
+}
+</script>
+<script src="/zd-loader.js" defer></script>
+<style>
+:root {
+  --bg: #F4F0E6;
+  --paper: #0e1311;
+  --muted: #8B7866;
+  --line: #1d2a23;
+  --accent: #107A3B;
+  --bg-soft: #1d2a23;
+  --cols: 6;
+}
+html[data-theme="dark"] {
+  --bg: #0e1311;
+  --paper: #F4F0E6;
+  --muted: #C9B89E;
+  --line: rgba(255,254,250,0.12);
+  --accent: #107A3B;
+  --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:'Recoleta', Georgia, serif !important; font-weight:500 !important; font-style:italic !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('jute_theme') || 'light'; document.documentElement.dataset.theme = t; } catch(e){} })();
+</script>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&display=swap">
+
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://jutewallpaper.com/">
+<meta property="og:title" content="Jute Wallpaper">
+<meta property="og:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta property="og:image" content="https://jutewallpaper.com/hero-bg.jpg">
+<meta property="og:site_name" content="Jute 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="Jute Wallpaper">
+<meta name="twitter:description" content="Jute Wallpaper — Jute, sisal & grasscloth wallcoverings.">
+<meta name="twitter:image" content="https://jutewallpaper.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">Filato</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@jutewallpaper.com?subject=Filato%20inquiry"><span class="ico">✉️</span><div class="txt"><b>Email Us</b><span>info@jutewallpaper.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">Earth Woven</div>
+  <div class="center-mark">Jute Wallpaper</div>
+  <div class="meta-line">Jute · Sisal · Grasscloth · Raffia<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">Jute · Sisal · Grasscloth · Raffia</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">Filato</div>
+      <p class="footer-text">Filato — 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>jutewallpaper.com · Filato</span>
+    <span><a href="mailto:info@jutewallpaper.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@jutewallpaper.com</a></span>
+    <span id="footerStat"></span>
+  </div>
+</footer>
+
+<script>
+// mini-constellation — 43 niche-stars, current site highlighted in gold
+(function(){
+  const SLUG = "jutewallpaper";
+  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('jute_theme_density', n); } catch(e){}
+}
+slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
+const savedDensity = parseInt(localStorage.getItem('jute_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('jute_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 5: serif hero typography + nav legibility */
+.cinema h1, h1.headline { font-family: 'Libre Baskerville', Georgia, serif; font-weight: 500; letter-spacing: -0.01em }
+.h-link { font-size: 13px; letter-spacing: 0.06em }
+
+/* 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@jutewallpaper.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@jutewallpaper.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>
+
+</body>
+</html>
diff --git a/public/sourcing.html b/public/sourcing.html
new file mode 100644
index 0000000..01ed41c
--- /dev/null
+++ b/public/sourcing.html
@@ -0,0 +1,60 @@
+<!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 — jutewallpaper.com</title>
+<meta name="description" content="How we source — jute. Woven by hand.">
+<link rel="canonical" href="https://jutewallpaper.com/sourcing">
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:ui-sans-serif;background:#F4F0E6;color:#107A3B;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:#107A3B;margin-bottom:18px}
+h1{font-family:'Recoleta', 'Playfair Display', serif;font-style:italic;font-size:48px;line-height:1.1;letter-spacing:-0.02em;color:#107A3B;margin-bottom:32px}
+h2{font-family:'Recoleta', 'Playfair Display', serif;font-size:22px;color:#107A3B;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:#107A3B}
+a{color:#107A3B;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 · Filato</div>
+<h1>How we source</h1>
+<p>We do not chase novelty. Our selection is not dictated by trends but by the integrity of the material and the precision of its execution. Every roll that reaches our atelier is the result of a process as exacting as it is deliberate — a dialogue between mill, maker, and material that begins long before the first sample is cut.</p>  
+
+<h2>Mills</h2>  
+<p>We work with mills that understand the grain of jute as intimately as a weaver knows the warp of a loom. These are not factories; they are workshops where generations of knowledge are embedded in every thread. Our partnerships are built on proximity — both geographical and philosophical. We visit mills where the looms are tended by hands that have spent decades mastering the rhythm of the weave. Here, the material is not a commodity but a conversation. We seek mills that produce with minimal intervention, where the jute’s inherent character is preserved rather than obscured. Their processes are not optimized for scale but for fidelity. This is how we ensure that every roll we source carries the weight of tradition, not the lightness of mass production.</p>  
+
+<h2>Trade-Only Catalogs</h2>  
+<p>Our access to catalogues is not through public displays or glossy spreads. We deal only in trade-only materials, where the language of the page is not salesmanship but specificity. These catalogues are curated by those who know the material’s limits and possibilities. We scrutinize them with a discerning eye, looking not for what is available but for what is necessary. Each entry is evaluated for its structural coherence and its alignment with our standards. The catalogues we consult are not for decoration but for function — they are blueprints of potential, annotated with data that matters: tensile strength, humidity resistance, and the subtleties of shade variation. We do not collect; we curate. What remains after this process is a selection that reflects not only our vision but the material’s own logic.</p>  
+
+<h2>Critieria for Inclusion</h2>  
+<ul>  
+<li><strong>Substrate compatibility:</strong> We reject any backing that compromises the jute’s breathability or introduces synthetic rigidity. The substrate must be inert, allowing the natural fibers to remain unencumbered.</li>  
+<li><strong>Repeat intervals:</strong> We measure repeats with precision, ensuring they are neither excessive nor arbitrary. A repeat must serve the material’s rhythm, not impose an artificial cadence.</li>  
+<li><strong>Washfastness ratings:</strong> We test for resilience. A roll must withstand the rigors of cleaning without degrading in texture or hue. Weakness in this regard is an immediate disqualifier.</li>  
+</ul>  
+
+<h2>Exclusions</h2>  
+<ul>  
+<li>Any material that introduces synthetic additives or chemical treatments that alter the jute’s natural state.</li>  
+<li>Patterns that rely on optical illusions or visual tricks rather than the material’s inherent structure.</li>  
+<li>Rolls that fail to meet our benchmarks for durability or that exhibit inconsistencies in weave density or fiber alignment.</li>  
+<li>Products that prioritize aesthetic novelty over functional longevity, regardless of their initial appeal.</li>  
+</ul>  
+
+<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/trade.html b/public/trade.html
new file mode 100644
index 0000000..d5cfd1c
--- /dev/null
+++ b/public/trade.html
@@ -0,0 +1,55 @@
+<!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 — jutewallpaper.com</title>
+<meta name="description" content="Trade program — jute. Woven by hand.">
+<link rel="canonical" href="https://jutewallpaper.com/trade">
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:ui-sans-serif;background:#F4F0E6;color:#107A3B;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:#107A3B;margin-bottom:18px}
+h1{font-family:'Recoleta', 'Playfair Display', serif;font-style:italic;font-size:48px;line-height:1.1;letter-spacing:-0.02em;color:#107A3B;margin-bottom:32px}
+h2{font-family:'Recoleta', 'Playfair Display', serif;font-size:22px;color:#107A3B;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:#107A3B}
+a{color:#107A3B;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 · Filato</div>
+<h1>Trade program</h1>
+<p>Filato operates within a framework of precision and purpose. This program is reserved for professionals engaged in the design and execution of interior environments. It is not a catalog; it is a curated dialogue between material and intent. Those who qualify—designers, architects, and contractors—are invited to participate in a process that values discernment over volume, and integrity over impulse.</p>
+
+<h2>Who Qualifies</h2>
+<p>Eligibility is determined by professional engagement with interior design, construction, or architectural practice. The program is designed for individuals and firms that prioritize material quality and finish, and who require access to a material that is both rare and rigorously selected. Verification of credentials is standard; applications are reviewed for alignment with the atelier’s ethos.</p>
+
+<h2>Memo Samples</h2>
+<p>Requests for samples are handled through a direct channel. Each memo sample is dispatched in a format that reflects the material’s inherent character—unadorned, unaltered. These samples are not promotional; they are functional, meant to be tested in context. The process is streamlined: a request is submitted, and within seven business days, a sample is sent. Return of unused material is required, unless otherwise specified.</p>
+
+<h2>Lead Times</h2>
+<p>Production timelines are dictated by the complexity of the weave and the availability of raw material. Standard lead times range from four to six weeks, depending on the specific finish and quantity requested. Expedited options are available for urgent projects, subject to prior arrangement and additional cost.</p>
+
+<h2>Terms</h2>
+<p>All transactions are governed by NET-30 terms, applicable to trade accounts that have been vetted and approved. Invoices are issued upon confirmation of order, with payment due within thirty days of receipt. Non-payment or delayed payment may result in suspension of access to the program, without prior notice.</p>
+
+<h2>Custom-Print Availability</h2>
+<p>Custom-print options are available, though they are not a standard offering. The process begins with a consultation to define the scope of the print, including resolution, color fidelity, and alignment with the atelier’s material constraints. Approval of the concept is required before production commences. Custom-printed rolls are subject to a minimum order quantity and extended lead times.</p>
+
+<h2>Parent Relationship Since 1996</h2>
+<p>Filato is nested within the broader framework of Designer Wallcoverings, an entity that has operated since 1996. This relationship provides access to an extensive archive of material knowledge, a depth of stock that spans decades, and a commitment to maintaining standards that transcend trends. The parent house does not dictate aesthetic direction; it ensures that every selection made by Filato is rooted in authenticity and technical mastery.</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..e649e4c
--- /dev/null
+++ b/public/vocabulary.html
@@ -0,0 +1,83 @@
+<!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 — jutewallpaper.com</title>
+<meta name="description" content="Design vocabulary — jute. Woven by hand.">
+<link rel="canonical" href="https://jutewallpaper.com/vocabulary">
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{font-family:ui-sans-serif;background:#F4F0E6;color:#107A3B;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:#107A3B;margin-bottom:18px}
+h1{font-family:'Recoleta', 'Playfair Display', serif;font-style:italic;font-size:48px;line-height:1.1;letter-spacing:-0.02em;color:#107A3B;margin-bottom:32px}
+h2{font-family:'Recoleta', 'Playfair Display', serif;font-size:22px;color:#107A3B;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:#107A3B}
+a{color:#107A3B;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 · Filato</div>
+<h1>Design vocabulary</h1>
+<p>Understanding the language of jute is essential for discerning buyers. This material, raw and unyielding, demands precision in its handling and presentation. Below are key terms that define its character, from the loom to the wall.</p>  
+
+<h2>Weave Structure</h2>  
+<ul>  
+  <li><strong>Definition:</strong> The arrangement of warp and weft threads, determined by the loom’s mechanics and the artisan’s technique.</strong></li>  
+  <li><strong>Product example:</strong> A tight, diagonal weave reinforces rigidity, while a loose, open structure allows light to pass through, altering the surface’s perceived depth.</strong></li>  
+</ul>  
+
+<h2>Loom Finish</h2>  
+<ul>  
+  <li><strong>Definition:</strong> The final treatment applied to the fabric after weaving, including trimming, smoothing, or distressing to meet aesthetic or functional criteria.</strong></li>  
+  <li><strong>Product example:</strong> A frayed edge, left untrimmed, exposes the thread’s natural grain, contrasting with a polished, cut edge that sharpens the material’s profile.</strong></li>  
+</ul>  
+
+<h2>Hue Variation</h2>  
+<ul>  
+  <li><strong>Definition:</strong> The range of tones within a single batch, influenced by the jute’s origin, dyeing process, and exposure to light or moisture.</strong></li>  
+  <li><strong>Product example:</strong> A roll may show subtle gradations from golden to ash, a byproduct of the fiber’s natural pigmentation and the dye’s uneven absorption.</strong></li>  
+</ul>  
+
+<h2>Density Grade</h2>  
+<ul>  
+  <li><strong>Definition:</strong> A classification based on the number of threads per square inch, affecting the material’s opacity, weight, and durability.</strong></li>  
+  <li><strong>Product example:</strong> A high-density grade blocks light completely, suitable for privacy, while a lower grade allows translucency, ideal for layered applications.</strong></li>  
+</ul>  
+
+<h2>Loom Weight</h2>  
+<ul>  
+  <li><strong>Definition:</strong> The mass of the fabric per unit area, measured in ounces or grams, reflecting the thickness and strength of the weave.</strong></li>  
+  <li><strong>Product example:</strong> A heavier loom weight resists sagging over time, making it preferable for large-scale installations where dimensional stability is critical.</strong></li>  
+</ul>  
+
+<h2>Milled Edge</h2>  
+<ul>  
+  <li><strong>Definition:</strong> An edge that has been processed by a machine to remove fraying, often through cutting or hemming, to ensure a clean, finished appearance.</strong></li>  
+  <li><strong>Product example:</strong> A milled edge on a roll prevents unraveling during installation, though it may obscure the raw, organic texture of the fiber’s natural state.</strong></li>  
+</ul>  
+
+<h2>Resin Coating</h2>  
+<ul>  
+  <li><strong>Definition:</strong> A thin, protective layer applied to the surface post-weaving, enhancing resistance to moisture, abrasion, or fading.</strong></li>  
+  <li><strong>Product example:</strong> A matte resin coating preserves the jute’s matte finish without altering its tactile quality, while a glossy variant introduces a reflective sheen.</strong></li>  
+</ul>  
+
+<h2>Slit Weave</h2>  
+<ul>  
+  <li><strong>Definition:</strong> A technique where individual threads are
+<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..b1c71ac
--- /dev/null
+++ b/server.js.pre-sort-skill
@@ -0,0 +1,159 @@
+/**
+ * JUTE 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 || 9843;
+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 = ["jute","sisal","grasscloth","raffia","natural fiber","seagrass"];
+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: "Jute Wallpaper", zdColor: "#c89858", zdPosition: 'right' });
+require('./_universal-auth')(app, { siteName: "jutewallpaper" });
+
+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 = ["jute","sisal","grasscloth","raffia","woven","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://jutewallpaper.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://jutewallpaper.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(`jutewallpaper listening on http://127.0.0.1:${PORT}`);
+});

← 5fb1363 sort-skill UI: add Light→Dark / Dark→Light / Color Wheel opt  ·  back to Jutewallpaper  ·  fleet-grid refine: chip_uniform_aspect (jutewallpaper) 276d4c6 →