[object Object]

← back to Dw Domain Fleet

monetize: content sections + checklist as collapsed <details> panels (SEO-safe, SSR in DOM) (TK-11322)

00c6cee83094597ddfc6eef06bdd24cd397243f2 · 2026-09-09 10:47:36 -0700 · Steve Abrams

Steve request. Native <details>/<summary>, first panel open by default, intro
lede stays visible above the fold. Content is server-rendered in the HTML so it
stays fully crawlable/indexable (collapsed != hidden for mobile-first indexing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S81Y5KkGKrUHg2mwWQtD96

Files touched

Diff

commit 00c6cee83094597ddfc6eef06bdd24cd397243f2
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Sep 9 10:47:36 2026 -0700

    monetize: content sections + checklist as collapsed <details> panels (SEO-safe, SSR in DOM) (TK-11322)
    
    Steve request. Native <details>/<summary>, first panel open by default, intro
    lede stays visible above the fold. Content is server-rendered in the HTML so it
    stays fully crawlable/indexable (collapsed != hidden for mobile-first indexing).
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01S81Y5KkGKrUHg2mwWQtD96
---
 shared/render.js | 38 ++++++++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/shared/render.js b/shared/render.js
index 547d2e2..ee399b3 100644
--- a/shared/render.js
+++ b/shared/render.js
@@ -1131,6 +1131,22 @@ function monetizeCss() {
 .m-guide ul{list-style:none;display:grid;gap:14px}
 .m-guide li{display:flex;gap:12px;font-size:15.5px;line-height:1.6;color:var(--fg)}
 .m-guide li b{font-family:var(--serif);color:var(--accent);flex:none}
+/* collapsible content panels (native <details> — content is server-rendered in
+   the DOM, so it stays fully crawlable/indexable; collapsed != hidden for SEO) */
+.m-panels{max-width:760px;margin:0 auto;padding:8px 0 30px}
+.m-panel{border:1px solid var(--rule);border-radius:10px;margin:0 0 12px;background:var(--card);overflow:hidden}
+.m-panel>summary{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;
+  gap:16px;padding:19px 24px;font-family:var(--serif);font-size:clamp(19px,2.3vw,26px);color:var(--fg)}
+.m-panel>summary::-webkit-details-marker{display:none}
+.m-panel>summary::after{content:"+";font-family:var(--sans);font-weight:400;font-size:26px;line-height:1;
+  color:var(--accent);flex:none}
+.m-panel[open]>summary::after{content:"\\2212"}
+.m-panel>summary:hover{color:var(--accent)}
+.m-panel__body{padding:2px 24px 22px}
+.m-panel__body p{font-size:16.5px;line-height:1.85;color:var(--fg);margin-bottom:14px}
+.m-panel__body ul{list-style:none;display:grid;gap:12px;margin-top:2px}
+.m-panel__body li{display:flex;gap:14px;font-size:15.5px;line-height:1.6;color:var(--fg)}
+.m-panel__body li b{font-family:var(--serif);color:var(--accent);flex:none;min-width:70px}
 .m-legal{max-width:760px;margin:0 auto;padding:30px 0 70px}
 .m-legal h1{font-family:var(--serif);font-size:clamp(30px,4vw,44px);margin-bottom:8px}
 .m-legal h2{font-family:var(--serif);font-size:22px;margin:26px 0 8px}
@@ -1158,15 +1174,18 @@ function monetizeHome(cfg) {
   // NOTE: authored content.* copy is rendered esc-only (NOT clean()) — these are
   // for-sale generic domains that legitimately contain "wallpaper"; the DW
   // wallpaper→wallcovering swap only applies to DW-branded funnel copy.
-  const secHtml = sections.map(s =>
-    `<section class="m-sec"><h2>${esc(s.h)}</h2>${
-      String(s.body || '').split(/\n\n+/).map(par => `<p>${esc(par)}</p>`).join('')
-    }</section>`).join('');
+  // Collapsible panels — native <details>, content server-rendered in the DOM
+  // (SEO-safe). First panel open by default so there is visible content at rest.
+  const secHtml = sections.map((s, i) =>
+    `<details class="m-panel"${i === 0 ? ' open' : ''}><summary>${esc(s.h)}</summary>
+      <div class="m-panel__body">${
+        String(s.body || '').split(/\n\n+/).map(par => `<p>${esc(par)}</p>`).join('')
+      }</div></details>`).join('');
   const guideHtml = guide.length ? `
-  <div class="m-guide" id="guide">
-    <h2>${esc(c.guideTitle || 'A quick guide')}</h2>
-    <ul>${guide.map(g => `<li><b>${esc(g.k)}</b><span>${esc(g.v)}</span></li>`).join('')}</ul>
-  </div>` : '';
+    <details class="m-panel"><summary>${esc(c.guideTitle || 'A quick guide')}</summary>
+      <div class="m-panel__body">
+        <ul>${guide.map(g => `<li><b>${esc(g.k)}</b><span>${esc(g.v)}</span></li>`).join('')}</ul>
+      </div></details>` : '';
   return head(cfg, title, desc, '/', null, '')
     + `<style>${monetizeCss()}</style>`
     + banner + jsonld(cfg) + monetizeChrome(cfg) + `
@@ -1180,8 +1199,7 @@ function monetizeHome(cfg) {
 <div class="wrap">
   <article class="m-article">
     <p class="lede">${esc(lede)}</p>
-    ${secHtml}
-    ${guideHtml}
+    <div class="m-panels" id="guide">${secHtml}${guideHtml}</div>
   </article>
 </div>
 ${monetizeFooter(cfg)}

← 6769abd monetize: fix header overlap (in-flow sticky m-nav, not fixe  ·  back to Dw Domain Fleet  ·  monetize template: full AdSense-ready build — Guide+Contact 1681057 →