[object Object]

← back to Jutewallpaper

Add clean /privacy route (AdSense URL consistency)

07fa1e9c2bbe6bb72d60a284909b7bae2608e790 · 2026-09-10 11:51:23 -0700 · Steve Abrams

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 07fa1e9c2bbe6bb72d60a284909b7bae2608e790
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Sep 10 11:51:23 2026 -0700

    Add clean /privacy route (AdSense URL consistency)
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 public/hero-bg.jpg | Bin 1309580 -> 712462 bytes
 public/index.html  | 592 ++++++++++++++++++++++++++++++++++-------------------
 server.js          |   1 +
 3 files changed, 383 insertions(+), 210 deletions(-)

diff --git a/public/hero-bg.jpg b/public/hero-bg.jpg
index 2499e3e..cbddbe6 100644
Binary files a/public/hero-bg.jpg and b/public/hero-bg.jpg differ
diff --git a/public/index.html b/public/index.html
index a8a75f9..b5146d6 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,59 +1,61 @@
 <!doctype html>
-<html lang="en">
+<html lang="en" data-hero-mode="huge">
 <head>
     <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5278231299883833" crossorigin="anonymous"></script>
     <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 async src="https://www.googletagmanager.com/gtag/js?id=G-CWZ4ZSQF3T"></script>
 <script>
   window.dataLayer = window.dataLayer || [];
   function gtag(){dataLayer.push(arguments);}
   gtag('js', new Date());
-  gtag('config', 'G-RZY8H2V0TG');
+  gtag('config', 'G-CWZ4ZSQF3T');
 </script>
 
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
-<title>jutewallpaper — jute. Woven by hand.</title>
-<meta name="description" content="jutewallpaper 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">
+<title>JUTE WALLPAPER — Jute & Sisal Wallcoverings</title>
+<meta name="description" content="Jute wallpaper — natural jute, sisal, and woven-fiber wallcoverings sourced from heritage mills.">
+<meta name="theme-color" content="#1a1408">
+<link rel="canonical" href="https://retrowalls.com/">
+<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;700;900&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": "jutewallpaper",
-  "url": "https://jutewallpaper.com/",
-  "email": "info@jutewallpaper.com"
+  "name": "retrowalls",
+  "url": "https://retrowalls.com/",
+  "email": "info@retrowalls.com",
+  "parentOrganization": { "@type": "Organization", "name": "Designer Wallcoverings" },
+  "address": { "@type": "PostalAddress", "streetAddress": "15442 Ventura Bl #102", "addressLocality": "Sherman Oaks", "addressRegion": "CA", "postalCode": "91403", "addressCountry": "US" }
 }
 </script>
 <script src="/zd-loader.js" defer></script>
 <style>
 :root {
-  --bg: #F4F0E6;
-  --paper: #0e1311;
+  --bg: #F5F2EB;
+  --paper: #000;
   --muted: #8B7866;
-  --line: #1d2a23;
-  --accent: #9B7B4F;
-  --bg-soft: #1d2a23;
+  --line: #000;
+  --accent: #000;
+  --bg-soft: #000;
   --cols: 6;
 }
 html[data-theme="dark"] {
-  --bg: #0e1311;
-  --paper: #F4F0E6;
+  --bg: #1a1410;
+  --paper: #F5F2EB;
   --muted: #C9B89E;
   --line: rgba(255,254,250,0.12);
-  --accent: #9B7B4F;
+  --accent: #FF0000;
   --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; }
+.section-title .accent, .footer-brand, .center-mark, h1, h2, h3 { font-family:'Helvetica Neue', Georgia, serif !important; font-weight:500 !important; text-transform:uppercase !important;letter-spacing:0.06em !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 }
@@ -61,15 +63,26 @@ header { position:fixed; top:0; left:0; right:0; display:flex; justify-content:s
 .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 hero (R2 spec: huge full-bleed photo + top-bar logo + below-photo wordmark) ===== */
+.cinema { position:relative; min-height:clamp(560px, 90vh, 1080px); 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%) }
+.cinema-bg::after { content:""; position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0.20) 0%, rgba(0,0,0,0) 35%, rgba(0,0,0,0) 65%, rgba(0,0,0,0.55) 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 }
+/* center-mark deprecated 2026-05-10 per R2 — kept hidden for backwards-compat with any straggler markup */
+.center-mark { display:none !important }
+/* Below-photo wordmark (R2): the brand display lives below the hero, NOT painted on it */
+.hero-wordmark-block { position:relative; padding:38px 32px 24px; text-align:center; background:var(--bg) }
+.hero-wordmark { font-family: ui-serif, Georgia, 'Cormorant Garamond', serif; font-weight:400; font-size:clamp(48px, 9vw, 128px); letter-spacing:-0.01em; line-height:1; color:var(--paper); margin:0; text-transform:none }
+.hero-wordmark-sub { display:block; font-family:'Playfair Display', Georgia, serif; font-style:italic; font-weight:400; font-size:clamp(13px, 1.4vw, 17px); letter-spacing:0.04em; text-transform:none; margin-top:14px; color:var(--muted) }
+@media (max-width:760px) { .hero-wordmark { font-size:clamp(32px, 12vw, 64px) } }
+/* Hero-mode hooks (R4): both modes share the same min-height so swap is CLS-free */
+[data-hero-mode="four-square"] .cinema-bg { display:none }
+[data-hero-mode="four-square"] .cinema-grid { display:grid; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; position:absolute; inset:0 }
+[data-hero-mode="four-square"] .cinema-grid .cell { background-size:cover; background-position:center; border:1px solid var(--bg) }
+.cinema-grid { display:none }
+/* Hero top-bar logo upper-left (sits inside the cinema overlay, paired with header hamburger upper-right) */
+.cinema-logo { position:absolute; top:22px; left:32px; font-family: ui-serif, Georgia, serif; font-size:18px; font-weight:500; letter-spacing:0.02em; color:#fff; text-decoration:none; z-index:6; text-shadow:0 1px 4px rgba(0,0,0,0.5) }
 .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 }
@@ -140,7 +153,7 @@ header { position:fixed; top:0; left:0; right:0; display:flex; justify-content:s
 [data-view=list] .list-head { display:grid; grid-template-columns:56px 2.6fr 1.2fr 1fr .8fr; gap:14px; align-items:center; padding:9px 12px; border-bottom:2px solid var(--accent) }
 .list-head span, .list-head button { font-size:9px; letter-spacing:0.2em; text-transform:uppercase; font-weight:700; color:var(--muted) }
 .list-head button { background:transparent; border:0; cursor:pointer; padding:0; display:inline-flex; gap:3px; align-items:center; font-family:inherit }
-.list-head button:hover { color:var(--fg) }
+.list-head button:hover { color:var(--paper) }
 .list-head button.sorted { color:var(--accent) }
 .list-head .arr { font-size:8px }
 .list-head button[data-sort-col=price] { justify-self:end }
@@ -190,7 +203,6 @@ textarea:focus-visible,
   outline: 2px solid var(--accent);
   outline-offset: 2px;
 }
-
 /* ===== Fields on/off menu ===== */
 .fieldmenu { position:relative; flex-shrink:0 }
 .fbtn { padding:5px 11px; border:1px solid var(--line); background:transparent; font-family:inherit; font-size:10px; letter-spacing:0.22em; text-transform:uppercase; font-weight:700; color:var(--muted); cursor:pointer; transition:all .15s }
@@ -207,31 +219,45 @@ html.hf-vendor  [data-f="vendor"]  { display:none !important }
 html.hf-color   [data-f="color"]   { display:none !important }
 html.hf-price   [data-f="price"]   { display:none !important }
 html.hf-sample  [data-f="sample"]  { display:none !important }
+
+/* === RAILS PATCH CSS (DW fleet sweep A4 2026-05-26) === */
+#rails{display:block;margin:0 0 40px}
+.rail-section{margin-bottom:48px}
+.rail-head{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--line,rgba(0,0,0,.12))}
+.rail-title{font-family:inherit;font-size:18px;letter-spacing:.16em;text-transform:uppercase;color:var(--accent,#9A6E3A);font-weight:600;margin:0}
+.rail-all{font-family:inherit;font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted,#5b5042);font-weight:500;transition:color .15s;cursor:pointer}
+.rail-all:hover{color:var(--accent,#9A6E3A);text-decoration:none}
+.grid.rail-grid{display:flex;gap:14px;overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:8px;scrollbar-width:none}
+.grid.rail-grid::-webkit-scrollbar{display:none}
+.grid.rail-grid > .card{flex:0 0 240px;scroll-snap-align:start}
+@media (max-width:720px){.grid.rail-grid > .card{flex:0 0 160px}}
+/* === END RAILS PATCH CSS === */
+
 </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">
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@400;500;600;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="og:url" content="https://retrowalls.com/">
+<meta property="og:title" content="Retro Walls">
+<meta property="og:description" content="Retro Walls — Vintage to midcentury wallcoverings — a curated archive.">
+<meta property="og:image" content="https://retrowalls.com/hero-bg.jpg">
+<meta property="og:site_name" content="Retro Walls">
 <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">
+<meta name="twitter:title" content="Retro Walls">
+<meta name="twitter:description" content="Retro Walls — Vintage to midcentury wallcoverings — a curated archive.">
+<meta name="twitter:image" content="https://retrowalls.com/hero-bg.jpg">
 <!-- graphics-loop pass 13: footer + fb -->
-<style id="ns-modal-fix">.ns-modal{display:none}.ns-modal.show{display:flex;align-items:center;justify-content:center;position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:1000}.ns-modal-card{background:#faf6ef;color:#1a1714;padding:32px;border-radius:12px;max-width:480px;width:90%;position:relative;box-shadow:0 20px 60px rgba(0,0,0,0.3)}.ns-modal .close-x{position:absolute;top:12px;right:16px;background:transparent;border:0;font-size:24px;cursor:pointer;color:#1a1714}.ns-modal h3{margin:0 0 8px;font-size:22px;font-weight:400}.ns-modal .sub{color:rgba(0,0,0,0.5);margin:0 0 20px;font-size:14px}.ns-actions{display:grid;gap:10px}.ns-action{display:flex;gap:14px;align-items:center;color:inherit;text-decoration:none;padding:14px 16px;border:1px solid rgba(0,0,0,0.12);border-radius:8px}.ns-action:hover{background:rgba(0,0,0,0.04)}.ns-action .ico{font-size:20px}.ns-action .txt{display:flex;flex-direction:column}.ns-action .txt b{font-weight:600}.ns-action .txt span{font-size:12px;color:rgba(0,0,0,0.5)}</style><style id="hero4-anti-header-crop">
+<style id="hero4-anti-header-crop">
 /* Never-show-images-with-headers rule (2026-05-14): every hero image
    is cropped to center 12% from the top to defeat vendor watermarks /
    scraped-site chrome / banner overlays. */
-.cinema-bg, .cell { background-position: center 12% !important; }
+.cinema-bg, .hero4-cell, .cell { background-position: center 12% !important; }
 .card img, .product img { object-position: center 12% !important; }
 </style>
 <!-- Meta Pixel — INERT until set-fb-pixel.sh is run (does NOT load fbevents.js or hit Meta until flipped) -->
@@ -255,7 +281,6 @@ html.hf-sample  [data-f="sample"]  { display:none !important }
 <!-- End Meta Pixel -->
 </head>
 <body>
-<h1 style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0">jutewallpaper</h1>
 <!-- Theme toggle (theme1 / theme2) — query-param-gated preview surface
      (Steve 2026-05-29). ?theme=2 in URL flips to theme2 and persists in
      localStorage. Toggle UI hidden until theme2 mode active. Same key
@@ -357,28 +382,100 @@ html.hf-sample  [data-f="sample"]  { display:none !important }
         .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); }
+
+        /* ── Contact modal (.ns-modal) ──
+           Was missing on this site — modal rendered inline at top of
+           page with raw emoji icons + default-blue underlined links.
+           Added by ns-contact-modal-fanout.js. */
+        .ns-modal {
+          display: none;
+          position: fixed; inset: 0; z-index: 1000;
+          background: rgba(10,10,10,0.78);
+          backdrop-filter: blur(6px);
+          align-items: center; justify-content: center;
+          padding: 24px;
+          font-family: -apple-system, "SF Pro Text", system-ui, sans-serif;
+        }
+        .ns-modal.show { display: flex; }
+        .ns-modal-card {
+          position: relative;
+          background: #f5f1e8;
+          color: #0a0a0a;
+          width: 100%; max-width: 480px;
+          padding: 36px 32px 32px;
+          border-radius: 4px;
+          box-shadow: 0 30px 80px rgba(0,0,0,0.55);
+          animation: nsModalIn 220ms cubic-bezier(.2,.7,.2,1);
+        }
+        @keyframes nsModalIn { from { opacity:0; transform: translateY(8px) scale(.985); } to { opacity:1; transform:none; } }
+        .ns-modal-card .close-x {
+          position: absolute; top: 10px; right: 12px;
+          width: 32px; height: 32px;
+          background: transparent; border: 0; cursor: pointer;
+          font-size: 22px; line-height: 1; color: #6e6e68;
+          transition: color 160ms;
+        }
+        .ns-modal-card .close-x:hover { color: #0a0a0a; }
+        .ns-modal-card h3 {
+          margin: 0 0 4px;
+          font: 300 22px/1.2 -apple-system, "SF Pro Display", system-ui, sans-serif;
+          letter-spacing: -0.005em;
+          color: #0a0a0a;
+        }
+        .ns-modal-card .sub {
+          margin: 0 0 22px;
+          font: 13px/1.45 -apple-system, "SF Pro Text", system-ui, sans-serif;
+          color: #6e6e68;
+          letter-spacing: 0.005em;
+        }
+        .ns-actions { display: flex; flex-direction: column; gap: 10px; }
+        .ns-action {
+          display: flex; align-items: center; gap: 14px;
+          padding: 14px 16px;
+          background: #ffffff;
+          border: 1px solid rgba(10,10,10,0.08);
+          border-radius: 3px;
+          color: #0a0a0a !important;
+          text-decoration: none !important;
+          font: 400 14px/1.3 -apple-system, "SF Pro Text", system-ui, sans-serif;
+          cursor: pointer;
+          transition: background 160ms, border-color 160ms, transform 80ms;
+        }
+        .ns-action:hover { background: #fffdf7; border-color: rgba(10,10,10,0.18); }
+        .ns-action:active { transform: scale(.997); }
+        .ns-action .ico {
+          flex-shrink: 0;
+          width: 38px; height: 38px;
+          display: inline-flex; align-items: center; justify-content: center;
+          background: rgba(10,10,10,0.04);
+          border-radius: 50%;
+          font-size: 18px;
+          line-height: 1;
+        }
+        .ns-action .txt {
+          display: flex; flex-direction: column; gap: 2px;
+          flex: 1; min-width: 0;
+        }
+        .ns-action .txt b { font-weight: 500; font-size: 14px; color: #0a0a0a; letter-spacing: 0; }
+        .ns-action .txt span {
+          font-weight: 400; font-size: 12px; color: #6e6e68;
+          letter-spacing: 0.005em;
+          overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+        }
+        @media (max-width: 480px) {
+          .ns-modal { padding: 14px; }
+          .ns-modal-card { padding: 28px 22px 22px; }
+        }
+        [data-theme="dark"] .ns-modal-card { background: #14110c; color: #f5f1e8; }
+        [data-theme="dark"] .ns-modal-card h3 { color: #f5f1e8; }
+        [data-theme="dark"] .ns-modal-card .sub { color: #a39c8b; }
+        [data-theme="dark"] .ns-action { background: rgba(245,241,232,0.04); border-color: rgba(245,241,232,0.10); color: #f5f1e8 !important; }
+        [data-theme="dark"] .ns-action:hover { background: rgba(245,241,232,0.08); border-color: rgba(245,241,232,0.22); }
+        [data-theme="dark"] .ns-action .ico { background: rgba(245,241,232,0.08); }
+        [data-theme="dark"] .ns-action .txt b { color: #f5f1e8; }
+        [data-theme="dark"] .ns-action .txt span { color: #a39c8b; }
+    
     </style>
-<style id="ns-header-rebuild">
-  /* Rebuild header per spec: both hamburgers upper-LEFT, site name centered */
-  .ns-header { padding:18px 28px !important; position:sticky; }
-  .ns-burgers { display:flex; align-items:center; gap:10px; flex:1 1 0; }
-  .ns-spacer { flex:1 1 0; }
-  .ns-name-center { flex:0 0 auto; text-align:center; font-family:'Recoleta',Georgia,serif; font-style:italic; font-weight:500; font-size:22px; letter-spacing:.01em; color:#f5f1e8; text-decoration:none; text-transform:none; white-space:nowrap; }
-  .ns-burger { display:flex !important; flex-direction:column; align-items:center; justify-content:center; width:34px; height:34px; gap:5px; background:transparent; border:0; cursor:pointer; padding:0; }
-  .ns-burger[hidden] { display:none !important; }   /* admin burger stays hidden until logged in */
-  .ns-burger span { display:block; width:22px; height:1.5px; background:#f5f1e8; transition:transform .2s,opacity .2s; }
-  .ns-burger[aria-expanded="true"] span:nth-child(1){ transform:translateY(6.5px) rotate(45deg); }
-  .ns-burger[aria-expanded="true"] span:nth-child(2){ opacity:0; }
-  .ns-burger[aria-expanded="true"] span:nth-child(3){ transform:translateY(-6.5px) rotate(-45deg); }
-  .ns-admin-burger span { background:var(--accent); }
-  .ns-nav, .ns-admin-nav { display:none !important; position:absolute; top:100%; left:18px !important; right:auto !important; flex-direction:column; align-items:stretch; gap:0; background:rgba(10,10,10,0.97); backdrop-filter:blur(10px); border:1px solid var(--line); border-top:0; min-width:240px; padding:8px 0; margin:0; box-shadow:0 16px 40px rgba(0,0,0,0.55); z-index:150; }
-  .ns-nav.open, .ns-admin-nav.open { display:flex !important; }
-  .ns-admin-nav { left:60px !important; }
-  .ns-admin-head { padding:10px 22px 8px; font-size:10px; letter-spacing:.22em; text-transform:uppercase; color:var(--accent); }
-  .ns-admin-nav a, .ns-admin-nav button { font-family:-apple-system,system-ui,sans-serif; font-size:14px; color:var(--paper); text-decoration:none; background:none; border:0; cursor:pointer; padding:12px 22px; text-align:left; width:100%; border-bottom:1px solid var(--line); display:block; }
-  .ns-admin-nav button:last-child { border-bottom:0; }
-  .ns-admin-nav a:hover, .ns-admin-nav button:hover { background:rgba(245,241,232,0.06); }
-</style>
 <style id="ns-gold-kill">
     /* novasuede: kill gold-solid fills, off-white instead. Edge color stays gold. */
     .new-badge, .new-arrivals-pill,
@@ -396,45 +493,45 @@ html.hf-sample  [data-f="sample"]  { display:none !important }
     }
   </style>
 <header class="ns-header">
-        <div class="ns-burgers">
-            <button type="button" class="ns-burger" id="nsNavBurger" aria-label="Menu" aria-controls="nsPrimaryNav" aria-expanded="false" onclick="nsToggleNav(this)">
-                <span></span><span></span><span></span>
-            </button>
-            <button type="button" class="ns-burger ns-admin-burger" id="nsAdminBurger" aria-label="Admin tools" aria-controls="nsAdminNav" aria-expanded="false" onclick="nsToggleAdmin(this)" hidden>
-                <span></span><span></span><span></span>
-            </button>
-        </div>
-        <a href="/" class="ns-name-center">Jute Wallpaper</a>
-        <div class="ns-spacer" aria-hidden="true"></div>
+        <a href="/" class="ns-brand" aria-label="Home">
+            <span class="ns-dot"></span>
+            <span class="ns-name">retrowalls</span>
+        </a>
         <nav class="ns-nav" id="nsPrimaryNav" aria-label="Primary">
             <a href="/">Home</a>
             <a href="/about">About</a>
-            <a href="/care.html">Care</a>
-            <a href="/history.html">History</a>
-            <a href="/sourcing.html">Sourcing</a>
             <button type="button" onclick="nsContactOpen()">Contact</button>
         </nav>
-        <nav class="ns-admin-nav" id="nsAdminNav" aria-label="Admin tools">
-            <div class="ns-admin-head">Admin tools</div>
-            <a href="https://admin.shopify.com" target="_blank" rel="noopener noreferrer">Shopify admin</a>
-            <a href="#" onclick="return false">Edit hero</a>
-            <a href="#" onclick="return false">Analytics</a>
-            <button type="button" onclick="nsAdminLogout()">Sign out admin</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>
 
 
+<!-- Contact modal — invisible until nsContactOpen() adds .show class. -->
+<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">&times;</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">&#128203;</span><div class="txt"><b>Get a Quote</b><span>Project specs &rarr; priced estimate</span></div></a>
+      <a class="ns-action" href="#contact" onclick="nsContactClose();if(typeof openModal==='function')openModal();"><span class="ico">&#128230;</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@retrowalls.com?subject=Retro%20Walls%20inquiry"><span class="ico">&#9993;</span><div class="txt"><b>Email Us</b><span>info@retrowalls.com</span></div></a>
+      <a class="ns-action" href="tel:888-373-4564"><span class="ico">&#128222;</span><div class="txt"><b>Call Us</b><span>(888) 373-4564 &middot; M&ndash;F, 9&ndash;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 nsCloseNav(){ var n=document.getElementById('nsPrimaryNav'),b=document.getElementById('nsNavBurger'); if(n)n.classList.remove('open'); if(b)b.setAttribute('aria-expanded','false'); }
-  function nsCloseAdmin(){ var n=document.getElementById('nsAdminNav'),b=document.getElementById('nsAdminBurger'); if(n)n.classList.remove('open'); if(b)b.setAttribute('aria-expanded','false'); }
-  function nsToggleNav(btn) { var nav=document.getElementById('nsPrimaryNav'); if(!nav)return; nsCloseAdmin(); var open=nav.classList.toggle('open'); btn.setAttribute('aria-expanded', open?'true':'false'); }
-  function nsToggleAdmin(btn) { var nav=document.getElementById('nsAdminNav'); if(!nav)return; nsCloseNav(); var open=nav.classList.toggle('open'); btn.setAttribute('aria-expanded', open?'true':'false'); }
-  function nsAdminLogout(){ try{localStorage.removeItem('dwAdmin');}catch(e){} location.reload(); }
-  // Pilot admin detection: ?admin=1 sets the flag; localStorage.dwAdmin reveals the admin (2nd) burger.
-  (function(){ try{ var p=new URLSearchParams(location.search); if(p.get('admin')==='1')localStorage.setItem('dwAdmin','1'); if(localStorage.getItem('dwAdmin')==='1'){ var b=document.getElementById('nsAdminBurger'); if(b)b.hidden=false; } }catch(e){} })();
-  document.addEventListener('keydown', function(e){ if (e.key === 'Escape') { nsContactClose(); nsCloseNav(); nsCloseAdmin(); } });
+  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>
 
 
@@ -447,13 +544,23 @@ html.hf-sample  [data-f="sample"]  { display:none !important }
 
 
 
-<section class="cinema">
+<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" id="hero">
+  <a class="cinema-logo" href="/" aria-label="retrowalls home">retrowalls</a>
   <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>
+  <div class="cinema-grid" id="heroGrid" aria-hidden="true"></div>
+  <div class="corner-mark">Vintage to Midcentury</div>
+  <div class="meta-line">Vintage · Midcentury · Deco · Damask<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>
+<div class="hero-wordmark-block">
+  <h1 class="hero-wordmark">retrowalls</h1>
+  <span class="hero-wordmark-sub">Vintage · Midcentury · Deco · Damask</span>
+</div>
 
 
 <section class="section" id="ideas">
@@ -462,7 +569,10 @@ html.hf-sample  [data-f="sample"]  { display:none !important }
     <h2 class="rail-title">New this week</h2>
     <div class="rail" id="railNewest"></div>
   </div>
-  
+  <div class="rail-block">
+    <h2 class="rail-title">Curated picks</h2>
+    <div class="rail" id="railCurated"></div>
+  </div>
 </section>
 
 <section class="section" id="shop">
@@ -471,7 +581,7 @@ html.hf-sample  [data-f="sample"]  { display:none !important }
       <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 class="section-meta">Vintage · Midcentury · Deco · Damask</div>
   </div>
 
   <div class="filters" id="facets">
@@ -504,7 +614,7 @@ html.hf-sample  [data-f="sample"]  { display:none !important }
       <input type="text" id="searchInput" placeholder="Search by pattern, color…" autocomplete="off">
     </div>
     <div class="fieldmenu">
-      <button class="fbtn" id="fieldsBtn" aria-haspopup="true" aria-expanded="false">Fields ▾</button>
+      <button class="fbtn" id="fieldsBtn" aria-haspopup="true" aria-expanded="false">Fields &#9662;</button>
       <div class="fpop" id="fpop" hidden role="menu"></div>
     </div>
   </div>
@@ -523,11 +633,22 @@ html.hf-sample  [data-f="sample"]  { display:none !important }
   <div class="sentinel" id="sentinel"></div>
 </section>
 
+<!-- IG-EMBED:START (TK-11322) -->
+<section class="ig-embed" aria-label="Follow us on Instagram" style="max-width:1120px;margin:44px auto;padding:0 20px">
+  <h2 style="font-family:Georgia,'Times New Roman',serif;font-weight:500;letter-spacing:.02em;text-align:center;margin:0 0 20px">Follow <a href="https://www.instagram.com/retrowalls/" target="_blank" rel="noopener noreferrer">@retrowalls</a> on Instagram</h2>
+  <div class="ig-embed__row" style="display:flex;gap:16px;flex-wrap:wrap;justify-content:center;align-items:flex-start">
+      <blockquote class="instagram-media" data-instgrm-permalink="https://www.instagram.com/p/DcchrqWnxj9/" data-instgrm-version="14" style="margin:0;min-width:250px;max-width:328px;width:100%"></blockquote>
+      <blockquote class="instagram-media" data-instgrm-permalink="https://www.instagram.com/p/Dcb33LOgewK/" data-instgrm-version="14" style="margin:0;min-width:250px;max-width:328px;width:100%"></blockquote>
+      <blockquote class="instagram-media" data-instgrm-permalink="https://www.instagram.com/p/DcWe5rWgaUu/" data-instgrm-version="14" style="margin:0;min-width:250px;max-width:328px;width:100%"></blockquote>
+  </div>
+</section>
+<script async src="//www.instagram.com/embed.js"></script>
+<!-- IG-EMBED:END -->
 <footer>
   <div class="footer-grid">
     <div>
-      <div class="footer-brand">jutewallpaper</div>
-      <p class="footer-text">jutewallpaper — real samples ship free.</p>
+      <div class="footer-brand">retrowalls</div>
+      <p class="footer-text">retrowalls — 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">
@@ -547,8 +668,8 @@ html.hf-sample  [data-f="sample"]  { display:none !important }
     </div>
   </div>
   <div class="footer-bottom">
-    <span>jutewallpaper.com · jutewallpaper</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>retrowalls.com</span>
+    <span><a href="mailto:info@retrowalls.com" style="color:var(--paper);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">info@retrowalls.com</a></span>
     <span><a href="/privacy.html" style="color:inherit;text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:1px">Privacy</a></span>
     <span id="footerStat"></span>
   </div>
@@ -557,7 +678,7 @@ html.hf-sample  [data-f="sample"]  { display:none !important }
 <script>
 // mini-constellation — 43 niche-stars, current site highlighted in gold
 (function(){
-  const SLUG = "jutewallpaper";
+  const SLUG = "retrowalls";
   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'],
@@ -624,7 +745,10 @@ const state = { q:'', facet:'all', sort:'newest', view:'grid', page:1, pages:1,
 // Touch device = no hover. Drives tap-to-reveal card behavior.
 const TOUCH = window.matchMedia('(hover: none)').matches;
 const HOSTKEY = location.hostname.replace(/\./g, '_');
-// DW STANDARD: hydrate saved view + sort BEFORE the first grid load.
+// DW STANDARD: hydrate saved view AND sort BEFORE the first grid load.
+// The change listener for the sort <select> is still attached later in the
+// file; this block just ensures state.sort/state.view are right when
+// loadGridPage() fires for the first time.
 (function(){
   try {
     const savedView = localStorage.getItem(HOSTKEY + '_view');
@@ -632,11 +756,20 @@ const HOSTKEY = location.hostname.replace(/\./g, '_');
     document.documentElement.dataset.view = state.view;
     const savedSort = localStorage.getItem(HOSTKEY + '_sort');
     if (savedSort) state.sort = savedSort;
+    // Hydrate density CSS var BEFORE first paint so the grid renders at the
+    // saved column count instead of flashing the default 6 → saved value.
+    const savedDensity = parseInt(localStorage.getItem('rw_theme_density') || '6', 10);
+    if (savedDensity >= 4 && savedDensity <= 12) {
+      document.documentElement.style.setProperty('--cols', savedDensity);
+    }
   } catch(e){}
 })();
-const LABELS = {"all":"All","natural":"Natural Jute"};
+const LABELS = {"all":"All","deco":"Art Deco","damask":"Damask","global":"Global & Eclectic","geometric":"Geometric & Abstract"};
 
-// -- href-to-deeper-data (HARD rule) -- storefront model: single `aesthetic` facet + q + sort --
+// ── href-to-deeper-data (HARD rule) — storefront model: single `aesthetic` facet + q + sort ──
+// Mirror the filter state into the URL so any filtered view is a real shareable/deep-linkable
+// href; aesthetic values become .drill atoms. drill.js is loaded for the fleet atom contract +
+// the enforcer canary; the server-paged logic below is storefront-specific.
 function sfQstr(){
   const u=new URLSearchParams();
   if(state.facet && state.facet!=='all') u.set('aesthetic',state.facet);
@@ -656,6 +789,7 @@ function sfReadURL(){
 function sfSyncChip(){ document.querySelectorAll('#facets [data-facet]').forEach(b=>b.classList.toggle('active',(b.dataset.facet||'all')===state.facet)); }
 function sfSetAesthetic(v){ state.facet=v||'all'; sfSyncChip(); resetGrid(); sfWriteURL(true); const shop=document.getElementById('shop'); if(shop) shop.scrollIntoView({behavior:'smooth'}); }
 window.sfSetAesthetic=sfSetAesthetic;
+// a .drill atom whose href IS the filtered view for that aesthetic (tag='span' inside the card <a>)
 function sfDrill(value,label,tag){
   if(value==null||value==='') return escAttr(label==null?'':label);
   const t=tag||'a';
@@ -663,6 +797,7 @@ function sfDrill(value,label,tag){
   const hattr=(t==='a')?(' href="?'+escAttr(u.toString())+'"'):'';
   return '<'+t+' class="drill" data-filter="aesthetic" data-v="'+escAttr(value)+'"'+hattr+' title="See all '+escAttr(String(label))+'">'+escAttr(label)+'</'+t+'>';
 }
+// delegated: plain click on any aesthetic drill atom filters in place; modifier/middle keeps the href
 document.addEventListener('click',function(e){
   const d=e.target.closest('.drill[data-filter="aesthetic"]'); if(!d) return;
   if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.button===1) return;
@@ -770,8 +905,12 @@ async function loadFacets() {
     b.innerHTML = (LABELS[k] || k) + ' <span style="opacity:.55;font-weight:500;margin-left:4px">' + v + '</span>';
     el.appendChild(b);
   }
+  // dynamic aesthetic chips are .drill anchors (handled by the delegated document click).
+  // this handler covers the static "All" button (data-facet=all, not a .drill).
   el.addEventListener('click', e => {
     const t = e.target.closest('[data-facet]'); if (!t || t.classList.contains('drill')) return;
+    document.querySelectorAll('#facets [data-facet]').forEach(b => b.classList.remove('active'));
+    t.classList.add('active');
     state.facet = t.dataset.facet || 'all'; sfSyncChip(); resetGrid(); sfWriteURL(true);
   });
   sfSyncChip();
@@ -792,6 +931,7 @@ function resetGrid() {
   document.getElementById('grid').innerHTML = '';
   document.getElementById('loading').textContent = 'Loading…';
   loadGridPage();
+  if (typeof renderRailSections === 'function') renderRailSections();
 }
 
 async function loadGridPage() {
@@ -824,7 +964,8 @@ async function loadGridPage() {
     a.onclick = (e) => {
       e.preventDefault();
       // Touch devices have no hover — 1st tap reveals the card's info overlay,
-      // 2nd tap on the revealed card opens the detail modal.
+      // 2nd tap on the revealed card opens the detail modal. Desktop (hover)
+      // shows the overlay on hover, so a click opens immediately.
       if (TOUCH && !a.classList.contains('revealed')) {
         document.querySelectorAll('.card.revealed').forEach(c => c.classList.remove('revealed'));
         a.classList.add('revealed');
@@ -863,10 +1004,10 @@ 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){}
+  try { localStorage.setItem('rw_theme_density', n); } catch(e){}
 }
 slider.addEventListener('input', e => setDensity(parseInt(e.target.value)));
-const savedDensity = parseInt(localStorage.getItem('jute_theme_density') || '6');
+const savedDensity = parseInt(localStorage.getItem('rw_theme_density') || '6');
 if (savedDensity >= 4 && savedDensity <= 12) { slider.value = savedDensity; setDensity(savedDensity); }
 
 // ===== Grid / List view toggle =====
@@ -884,7 +1025,7 @@ viewToggle.addEventListener('click', e => {
 });
 for (const b of viewToggle.querySelectorAll('button')) b.classList.toggle('active', b.dataset.view === state.view);
 
-// ===== Sortable list-view columns ===== (column → [ascSort, descSort])
+// ===== Sortable list-view columns ===== (column -> [ascSort, descSort])
 const COL_SORTS = {
   title:     ['title', 'title-desc'],
   sku:       ['sku', 'sku-desc'],
@@ -915,10 +1056,95 @@ document.getElementById('listHead').addEventListener('click', e => {
 syncColHeaders();
 
 // Theme toggle
-const tb = (document.getElementById('theme-toggle')||{textContent:'',classList:{add(){},remove(){},toggle(){}},addEventListener(){},style:{}});
-function setTheme(t){ document.documentElement.dataset.theme = t; try { localStorage.setItem('jute_theme', t); } catch(e){} if (tb) tb.textContent = t === 'dark' ? '☾' : '☀'; }
+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');
-if (tb) tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
+tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
+
+// === RAILS PATCH (DW fleet sweep A4 2026-05-26) ===
+// Renders rail sections on the unfiltered homepage above the flat grid.
+// Fed by /api/sliders. Hides flat grid + sentinel while rails are visible.
+async function renderRailSections(){
+  const railsHost = document.getElementById('rails');
+  const grid = document.getElementById('grid');
+  const sentinel = document.getElementById('sentinel');
+  const loading = document.getElementById('loading');
+  const listHead = document.getElementById('listHead');
+  if (!railsHost) return;
+  // Only render rails on the unfiltered "all" home view.
+  if (state.q || state.facet !== 'all') {
+    railsHost.innerHTML = '';
+    railsHost.style.display = 'none';
+    if (grid) grid.style.display = '';
+    if (sentinel) sentinel.style.display = '';
+    if (loading) loading.style.display = '';
+    return;
+  }
+  let payload;
+  try {
+    const r = await fetch('/api/sliders');
+    if (!r.ok) throw new Error('HTTP ' + r.status);
+    payload = await r.json();
+  } catch (e) {
+    console.warn('renderRailSections failed:', e);
+    return;
+  }
+  const rails = Array.isArray(payload && payload.rails) ? payload.rails : [];
+  if (rails.length < 2) return; // no meaningful segmentation
+  const frag = document.createElement('div');
+  for (const rail of rails) {
+    const aes = rail.aesthetic;
+    const items = (rail.items || []).slice(0, 8);
+    if (items.length < 4) continue;
+    const sec = document.createElement('section');
+    sec.className = 'rail-section';
+    const head = document.createElement('div');
+    head.className = 'rail-head';
+    const title = document.createElement('h2');
+    title.className = 'rail-title';
+    title.textContent = ((typeof LABELS !== 'undefined' && LABELS[aes]) || aes).replace(/-/g,' ').replace(/\b\w/g, c => c.toUpperCase());
+    const all = document.createElement('a');
+    all.className = 'rail-all';
+    all.href = '#shop';
+    all.textContent = 'View all →';
+    all.dataset.facet = aes;
+    all.onclick = (e) => {
+      e.preventDefault();
+      state.facet = aes;
+      document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === aes));
+      resetGrid();
+      const shop = document.getElementById('shop');
+      if (shop) shop.scrollIntoView({behavior:'smooth'});
+    };
+    head.appendChild(title); head.appendChild(all);
+    const grid8 = document.createElement('div');
+    grid8.className = 'grid rail-grid';
+    for (const p of items) {
+      const card = document.createElement('a');
+      card.className = 'card';
+      card.href = '#';
+      card.onclick = (e) => { e.preventDefault(); openDetails(p); };
+      card.innerHTML = cardHTML(p);
+      grid8.appendChild(card);
+    }
+    sec.appendChild(head);
+    sec.appendChild(grid8);
+    frag.appendChild(sec);
+  }
+  if (!frag.childNodes.length) return;
+  railsHost.innerHTML = '';
+  railsHost.appendChild(frag);
+  railsHost.style.display = '';
+  // Hide flat grid + scroll bait while rails are showing — clicking a rail
+  // "View all →" or a chip will un-hide them via resetGrid path.
+  if (grid) grid.style.display = 'none';
+  if (sentinel) sentinel.style.display = 'none';
+  if (loading) loading.style.display = 'none';
+  if (listHead) listHead.style.display = 'none';
+  const stat = document.getElementById('statLine');
+  if (stat) stat.textContent = (state.total || '') + ' patterns · browse by aesthetic';
+}
+// === END RAILS PATCH ===
 
 // ===== Fields on/off menu =====
 // [key, label, defaultVisible] — color=OFF by default; image-only achievable by turning rest off.
@@ -1022,7 +1248,7 @@ document.addEventListener('DOMContentLoaded', function(){ try { renderRailSectio
   .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 }
+.cinema h1, h1.headline { font-family: 'Cormorant Garamond', Georgia, serif; font-weight: 500; letter-spacing: -0.01em }
 .h-link { font-size: 13px; letter-spacing: 0.06em }
 
 /* graphics-loop pass 11: Ideas rails */
@@ -1038,15 +1264,6 @@ document.addEventListener('DOMContentLoaded', function(){ try { renderRailSectio
 #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 } }
-
-/* Rail sections (retrowalls-canonical pattern — fleet sweep 2026-05-26) */
-.rail-section{margin-bottom:48px}
-.rail-head{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--line,rgba(0,0,0,.12))}
-.rail-head .rail-title{font-family:inherit;font-size:clamp(18px,2.2vw,26px);margin:0;font-weight:500;letter-spacing:-0.01em;color:var(--ink,#1a1714)}
-.rail-all{font-family:inherit;font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted,#5b5042);font-weight:500;transition:color .15s;cursor:pointer;text-decoration:none}
-.rail-all:hover{color:var(--accent,#9A6E3A);text-decoration:none}
-.grid.rail-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:14px}
-
 </style>
 
 <!-- Product details modal — opens on any chip click. Vendor-redacted. -->
@@ -1112,9 +1329,9 @@ document.addEventListener('DOMContentLoaded', function(){ try { renderRailSectio
         <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">
+      <a class="dwm-option" id="dwmContactEmailLink" href="mailto:info@retrowalls.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>
+        <span class="lbl">Email Us<span class="val" id="dwmContactEmailLabel">info@retrowalls.com</span></span>
       </a>
     </div>
   </div>
@@ -1301,88 +1518,10 @@ document.addEventListener('DOMContentLoaded', function(){ try { renderRailSectio
     if (typeof syncColHeaders === 'function') syncColHeaders();
     if (typeof resetGrid === 'function') resetGrid();
     else location.reload();
+    sfWriteURL(false);
   });
 })();
 
-
-// === RAILS PATCH (DW fleet sweep A3 2026-05-26 — retrowalls canonical) ===
-// Renders rail sections on unfiltered homepage above flat grid, fed by /api/sliders.
-// Hides flat grid + sentinel while rails are visible. Click rail title -> jumpToFacet.
-async function renderRailSections(){
-  const railsHost = document.getElementById('rails');
-  const grid = document.getElementById('grid');
-  const sentinel = document.getElementById('sentinel');
-  const loading = document.getElementById('loading');
-  const listHead = document.getElementById('listHead');
-  if (!railsHost) return;
-  if (typeof state !== 'undefined' && (state.q || (state.facet && state.facet !== 'all'))) {
-    railsHost.innerHTML = '';
-    railsHost.style.display = 'none';
-    if (grid) grid.style.display = '';
-    if (sentinel) sentinel.style.display = '';
-    if (loading) loading.style.display = '';
-    return;
-  }
-  let payload;
-  try {
-    const r = await fetch('/api/sliders');
-    if (!r.ok) throw new Error('HTTP ' + r.status);
-    payload = await r.json();
-  } catch (e) { console.warn('renderRailSections failed:', e); return; }
-  const rails = Array.isArray(payload && payload.rails) ? payload.rails : [];
-  if (rails.length < 2) return; // no meaningful segmentation
-  const frag = document.createElement('div');
-  for (const rail of rails) {
-    const aes = rail.aesthetic;
-    const items = (rail.items || []).slice(0, 8);
-    if (items.length < 4) continue;
-    const sec = document.createElement('section');
-    sec.className = 'rail-section';
-    const head = document.createElement('div');
-    head.className = 'rail-head';
-    const title = document.createElement('h2');
-    title.className = 'rail-title';
-    title.textContent = ((typeof LABELS !== 'undefined' && LABELS[aes]) || aes).replace(/-/g,' ').replace(/\b\w/g, c => c.toUpperCase());
-    const all = document.createElement('a');
-    all.className = 'rail-all';
-    all.href = '#shop';
-    all.textContent = 'View all →';
-    all.dataset.facet = aes;
-    all.onclick = (e) => {
-      e.preventDefault();
-      if (typeof state !== 'undefined') state.facet = aes;
-      document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === aes));
-      if (typeof resetGrid === 'function') resetGrid();
-      const shop = document.getElementById('shop');
-      if (shop) shop.scrollIntoView({behavior:'smooth'});
-    };
-    head.appendChild(title); head.appendChild(all);
-    const grid8 = document.createElement('div');
-    grid8.className = 'grid rail-grid';
-    for (const p of items) {
-      const card = document.createElement('a');
-      card.className = 'card';
-      card.href = '#';
-      card.onclick = (e) => { e.preventDefault(); if (typeof openDetails === 'function') openDetails(p); };
-      card.innerHTML = (typeof cardHTML === 'function') ? cardHTML(p) : ('<img src="'+(p.image_url||'')+'" loading="lazy" alt=""><div class="ti">'+(p.title||'')+'</div>');
-      grid8.appendChild(card);
-    }
-    sec.appendChild(head);
-    sec.appendChild(grid8);
-    frag.appendChild(sec);
-  }
-  if (!frag.childNodes.length) return;
-  railsHost.innerHTML = '';
-  railsHost.appendChild(frag);
-  railsHost.style.display = '';
-  if (grid) grid.style.display = 'none';
-  if (sentinel) sentinel.style.display = 'none';
-  if (loading) loading.style.display = 'none';
-  if (listHead) listHead.style.display = 'none';
-}
-// === END RAILS PATCH ===
-
-
 // graphics-loop pass 11: hydrate Ideas rails from /api/products
 (async function hydrateIdeas() {
   try {
@@ -1397,9 +1536,6 @@ async function renderRailSections(){
     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');
-      // Step 2 vendor-leak fix: prefer the vendor-scrubbed handle_display slug (emitted
-      // by the shared API middleware) so raw vendor-bearing handles never hit the URL bar.
-      // Server /sample/:handle is dual-key — resolves both forms identically.
       return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle_display || 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>' +
@@ -1414,6 +1550,44 @@ async function renderRailSections(){
 })();
 </script>
 
+<script>
+/* R4 — Alternating hero modes (huge / four-square). Server-side default is huge.
+   This client-only flip starts on visit 2. Both modes share the same .cinema min-height,
+   so the swap is CLS-free. Crawlers always see huge (server skips this hydration). */
+(function(){
+  try {
+    var k='dw-hero-mode';
+    var prev=parseInt(localStorage.getItem(k)||'0',10);
+    var next=(prev+1)%2;
+    localStorage.setItem(k,String(next));
+    if (prev>0) {
+      var mode = next===0 ? 'huge' : 'four-square';
+      document.documentElement.dataset.heroMode = mode;
+      if (mode === 'four-square') {
+        // Try to populate four-square from existing product list (newest 4)
+        fetch('/api/products?limit=4&page=1').then(r=>r.ok?r.json():null).then(j=>{
+          if (!j || !j.items || j.items.length < 4) {
+            document.documentElement.dataset.heroMode = 'huge';
+            console.warn('dw-hero-stale: insufficient items for four-square, falling back to huge');
+            return;
+          }
+          var grid = document.getElementById('heroGrid');
+          if (!grid) return;
+          j.items.slice(0,4).forEach(function(it){
+            var d = document.createElement('div');
+            d.className = 'cell';
+            var img = (it.image_url || it.image || '/hero-bg.jpg');
+            d.style.backgroundImage = "url('" + img + "')";
+            grid.appendChild(d);
+          });
+        }).catch(function(){
+          document.documentElement.dataset.heroMode = 'huge';
+        });
+      }
+    }
+  } catch(e) { /* localStorage disabled — keep server default (huge) */ }
+})();
+</script>
 
 <!-- Big Red customer chat — lower-left, woman-avatar, vendor-redacted retail persona. -->
 <script data-bigred-widget src="https://chat.designerwallcoverings.com/widget.js"
@@ -1421,12 +1595,10 @@ async function renderRailSections(){
         data-mode="retail"
         defer onerror="this.remove()"></script>
 
-<!-- corner-nav.js (upper-right 4-icon widget) disabled for the UL-hamburger header rebuild — Steve 2026-06-01 -->
-<!-- <!-- corner-nav disabled (UL-hamburger rebuild) --> -->
+<!-- corner-nav disabled (UL-hamburger rebuild) -->
 <script src="/sku-redact.js" defer></script>
-<!-- hero-4grid grid DISABLED so the single high-res hero shows full-bleed --><!-- <script src="/hero-4grid.js" defer></script> -->
-<script>window.DwHeaderConfig={siteName:"Jute Wallpaper",accent:"#9B7B4F",navLinks:[{name:'Home',url:'/'},{name:'Collections',url:'#shop'},{name:'About',url:'/about'},{name:'Care',url:'/care.html'},{name:'History',url:'/history.html'}],adminLinks:[{name:'Shopify admin',url:'https://admin.shopify.com',external:true},{name:'Edit hero',url:'#'},{name:'Analytics',url:'#'}]};</script>
-<script src="/dw-header.js" defer></script>
+<!-- hero4-fix: activate 2x2 hero (self-contained; was commented placeholder) -->
+<script src="/hero-4grid.js" defer></script>
   <!-- DW network ad slot -->
   <script src="https://ads.agentabrams.com/embed.js" data-slot="footer-strip"></script>
 </body>
diff --git a/server.js b/server.js
index 016ea64..2d4e0a7 100644
--- a/server.js
+++ b/server.js
@@ -206,6 +206,7 @@ app.get(/^\/(care|history|sourcing|trade|vocabulary|index)\.html$/, (req, res) =
 
 require('../_shared/_universal-promo-banner')(app, {}); // new-arrivals promo strip (Tier B)
 app.use(express.static(path.join(__dirname, 'public')));
+app.get('/privacy', (req, res) => res.sendFile(path.join(__dirname, 'public', 'privacy.html')));
 
 // Clean-URL routes for static content pages (no .html extension).
 // /about points at the history page so the header nav link resolves.

← f7297d3 auto-data-snapshot: 2026-09-10T11:43:04 (2 data files) — dat  ·  back to Jutewallpaper  ·  jutewallpaper: declare helmet + dotenv (undeclared deps woul a11b722 →