[object Object]

← back to Stars of Design

polish: editorial 2-line hero + by-era anthology section

f86aef56675bfd7a5b3c0ed5cf2da56aaa566a63 · 2026-05-13 14:25:08 -0700 · Steve Abrams

Hero — replace single-line tagline with 2-line italic editorial
headline ("The designers who set the room. / The wallcoverings that
set the tone.") plus 1-line sans subtitle naming Draper through
Wearstler. Bumps tagline color to #f0e3b8 + text-shadow for stronger
APCA on the dark hero ground.

New "By the era" section between the directory grid and the editorial
two-col. Four cards (Early 20th / Mid-Century / Late 20th /
Contemporary) each with a gold hairline rule, era blurb, 3 exemplar
designer names, and a count-deep-link to /designers?era=<bucket>.
Specific to the directory vertical — gives the homepage a real
"anthology by era" identity instead of template-fresh blocks.

Server passes eraIndex into the home view as a single in-memory
pass over data.load() — no DB hit. Hero-readability-auditor passes
APCA Lc 100/99 desktop/mobile, well above the 75 threshold.

Files touched

Diff

commit f86aef56675bfd7a5b3c0ed5cf2da56aaa566a63
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed May 13 14:25:08 2026 -0700

    polish: editorial 2-line hero + by-era anthology section
    
    Hero — replace single-line tagline with 2-line italic editorial
    headline ("The designers who set the room. / The wallcoverings that
    set the tone.") plus 1-line sans subtitle naming Draper through
    Wearstler. Bumps tagline color to #f0e3b8 + text-shadow for stronger
    APCA on the dark hero ground.
    
    New "By the era" section between the directory grid and the editorial
    two-col. Four cards (Early 20th / Mid-Century / Late 20th /
    Contemporary) each with a gold hairline rule, era blurb, 3 exemplar
    designer names, and a count-deep-link to /designers?era=<bucket>.
    Specific to the directory vertical — gives the homepage a real
    "anthology by era" identity instead of template-fresh blocks.
    
    Server passes eraIndex into the home view as a single in-memory
    pass over data.load() — no DB hit. Hero-readability-auditor passes
    APCA Lc 100/99 desktop/mobile, well above the 75 threshold.
---
 public/css/site.css   | 96 +++++++++++++++++++++++++++++++++++++++++++++++++--
 routes/public.js      | 30 ++++++++++++++++
 views/public/home.ejs | 31 ++++++++++++++++-
 3 files changed, 153 insertions(+), 4 deletions(-)

diff --git a/public/css/site.css b/public/css/site.css
index 4205954..736d88b 100644
--- a/public/css/site.css
+++ b/public/css/site.css
@@ -164,10 +164,21 @@ html[data-theme='dark']  .theme-toggle-sun  { display: none; }
   font-family: var(--font-serif);
   font-style: italic;
   font-weight: 300;
-  font-size: clamp(1rem, 1.9vw, 1.5rem);
+  font-size: clamp(1.05rem, 2.1vw, 1.6rem);
+  line-height: 1.35;
   letter-spacing: .01em;
-  color: #d9c89a; margin: 0;
-  max-width: 56ch;
+  color: #f0e3b8; margin: 0;
+  max-width: 64ch;
+  text-shadow: 0 1px 18px rgba(0,0,0,.55);
+}
+.hero-gucci-subtitle {
+  font-family: var(--font-sans);
+  font-weight: 400;
+  font-size: clamp(.92rem, 1.15vw, 1.05rem);
+  letter-spacing: .02em;
+  color: #cdb98a; margin: .35rem 0 0;
+  max-width: 64ch;
+  line-height: 1.55;
 }
 .hero-gucci-cta { margin-top: 1.25rem; display: flex; gap: .9rem; flex-wrap: wrap; justify-content: center; }
 .hero-gucci-cta .btn.primary { background: #f4ecd6; color: #0a0907; border-color: transparent; }
@@ -464,3 +475,82 @@ html[data-theme='dark']  .theme-toggle-sun  { display: none; }
   display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
   overflow: hidden;
 }
+
+/* "By the era" editorial mini-index on the homepage.
+   Four cards in a row, each linking to /designers?era=<bucket>. Gold hairline
+   rule at top of each card; serif heading; sans body; gold deep-link arrow. */
+.era-section { background: var(--surface-1, #faf7f1); }
+[data-theme="dark"] .era-section { background: #14110b; }
+.era-section-lede {
+  font-family: var(--font-serif);
+  font-style: italic;
+  font-size: 1.05rem;
+  color: var(--muted-fg, #5a5346);
+  max-width: 70ch;
+  margin: -.5rem 0 1.75rem;
+}
+[data-theme="dark"] .era-section-lede { color: #b6a986; }
+.era-grid {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  gap: 1.25rem;
+}
+@media (max-width: 980px) { .era-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
+@media (max-width: 560px) { .era-grid { grid-template-columns: 1fr; } }
+.era-card {
+  display: flex; flex-direction: column; gap: .6rem;
+  padding: 1.25rem 1.1rem 1.1rem;
+  background: var(--card-bg, #fff);
+  border: 1px solid var(--border, rgba(0,0,0,.08));
+  border-radius: 4px;
+  color: inherit; text-decoration: none;
+  transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease;
+  position: relative;
+}
+[data-theme="dark"] .era-card { background: #1c1810; border-color: rgba(217,168,104,.18); }
+.era-card:hover {
+  transform: translateY(-2px);
+  border-color: var(--gold, #d9a868);
+  box-shadow: 0 6px 22px rgba(0,0,0,.06);
+  text-decoration: none;
+}
+.era-card-rule {
+  display: block; height: 2px; width: 38px;
+  background: var(--gold, #d9a868);
+  margin-bottom: .15rem;
+}
+.era-card-title {
+  font-family: var(--font-serif);
+  font-weight: 500;
+  font-size: 1.25rem;
+  margin: 0; line-height: 1.2;
+  letter-spacing: .005em;
+}
+.era-card-blurb {
+  font-family: var(--font-sans);
+  font-size: .88rem;
+  color: var(--muted-fg, #5a5346);
+  line-height: 1.5;
+  margin: 0;
+}
+[data-theme="dark"] .era-card-blurb { color: #c0b591; }
+.era-card-names {
+  list-style: none; padding: 0; margin: .15rem 0 0;
+  display: flex; flex-direction: column; gap: .15rem;
+  font-family: var(--font-serif);
+  font-style: italic;
+  font-size: .95rem;
+  color: var(--text-fg, #2a261e);
+}
+[data-theme="dark"] .era-card-names { color: #ece2c5; }
+.era-card-count {
+  margin-top: auto;
+  font-family: var(--font-sans);
+  font-size: .78rem;
+  letter-spacing: .08em;
+  text-transform: uppercase;
+  color: var(--gold, #d9a868);
+  font-weight: 500;
+  padding-top: .65rem;
+  border-top: 1px dotted rgba(217,168,104,.35);
+}
diff --git a/routes/public.js b/routes/public.js
index f14d8d6..e1bbb0c 100644
--- a/routes/public.js
+++ b/routes/public.js
@@ -91,10 +91,39 @@ router.get('/api/health', async (_req, res) => {
   }
 });
 
+// Editorial era index for the homepage — four anchored era cards (Early 20th,
+// Mid-Century, Late 20th, Contemporary) with a count and three exemplar
+// names per era, each linking to /designers?era=<bucket>. Built once at
+// request time from the in-memory dataset; cheap, no DB hit.
+const ERA_ORDER = ['Early 20th Century', 'Mid-Century', 'Late 20th Century', 'Contemporary'];
+const ERA_BLURB = {
+  'Early 20th Century': 'When the profession of decoration was invented — chintz, pale silk, the Edith Wharton school.',
+  'Mid-Century':        'Plaster, jungle prints, glazed bamboo — the era of Draper, Frances Elkins, and the Greenbrier.',
+  'Late 20th Century':  'Chintz on chintz on chintz — Buatta, Hicks, Denning & Fourcade, the maximalist American salon.',
+  'Contemporary':       'The working bench today — Wearstler, McGee, Vervoordt, Tarlow — pattern paired to current practice.',
+};
+function buildEraIndex(all) {
+  const buckets = {};
+  for (const d of all) {
+    if (!d.era) continue;
+    (buckets[d.era] = buckets[d.era] || []).push(d.name);
+  }
+  return ERA_ORDER
+    .filter((era) => buckets[era] && buckets[era].length)
+    .map((era) => ({
+      era,
+      blurb:    ERA_BLURB[era] || '',
+      count:    buckets[era].length,
+      exemplars:buckets[era].slice(0, 3),
+      href:     `/designers?era=${encodeURIComponent(era)}`,
+    }));
+}
+
 router.get('/', (req, res, next) => {
   try {
     const all = data.load();
     const sortKey = SORTS[req.query.sort] ? req.query.sort : 'newest';
+    const eraIndex = buildEraIndex(all);
     // WebSite + Organization JSON-LD. SearchAction declares the site's
     // search endpoint to Google for sitelinks search-box eligibility.
     // /designers acts as the search target (it accepts ?q=).
@@ -130,6 +159,7 @@ router.get('/', (req, res, next) => {
       total: all.length,
       sortKey,
       filter: {},
+      eraIndex,
       json_ld,
     });
   } catch (e) { next(e); }
diff --git a/views/public/home.ejs b/views/public/home.ejs
index fba0b09..4b25c84 100644
--- a/views/public/home.ejs
+++ b/views/public/home.ejs
@@ -10,7 +10,11 @@
     <div class="hero-gucci-stars" aria-hidden="true"></div>
     <div class="hero-gucci-stack">
       <h1 id="hero-wordmark" class="hero-gucci-wordmark">Stars of Design</h1>
-      <p class="hero-gucci-tagline"><em>The designers who shape interiors — and the walls behind them.</em></p>
+      <p class="hero-gucci-tagline">
+        <em>The designers who set the room.</em><br>
+        <em>The wallcoverings that set the tone.</em>
+      </p>
+      <p class="hero-gucci-subtitle">A working atlas of 150 interior designers — Draper through Wearstler — paired to the patterns they'd actually hang.</p>
       <div class="hero-gucci-cta">
         <a class="btn primary" href="/designers">Browse the directory →</a>
         <a class="btn ghost"   href="/about">How it works</a>
@@ -52,6 +56,31 @@
     </div>
   </section>
 
+  <% if (typeof eraIndex !== 'undefined' && eraIndex && eraIndex.length) { %>
+    <section class="section era-section" id="by-era">
+      <div class="wrap">
+        <div class="section-head">
+          <h2>By the era</h2>
+          <a class="muted" href="/designers">Filter the directory →</a>
+        </div>
+        <p class="era-section-lede">A working anthology, decade by decade — the designers who defined each chapter of the modern American interior, and the wallcoverings they put on the walls.</p>
+        <div class="era-grid">
+          <% eraIndex.forEach(function (e) { %>
+            <a class="era-card" href="<%= e.href %>">
+              <span class="era-card-rule" aria-hidden="true"></span>
+              <h3 class="era-card-title"><%= e.era %></h3>
+              <p class="era-card-blurb"><%= e.blurb %></p>
+              <ul class="era-card-names">
+                <% e.exemplars.forEach(function (n) { %><li><%= n %></li><% }) %>
+              </ul>
+              <span class="era-card-count"><%= e.count %> designer<%= e.count === 1 ? '' : 's' %> →</span>
+            </a>
+          <% }); %>
+        </div>
+      </div>
+    </section>
+  <% } %>
+
   <section class="section alt">
     <div class="wrap two-col">
       <div>

← 03cea56 smoke: assert /api/{designers,firms,clients}/featured SWR Ca  ·  back to Stars of Design  ·  smoke: /api/health perf budget 500→1000ms af307bc →