[object Object]

← back to Rentv 2026

selector: add Classic (original) as 6th option + rank all 6 + why-it-wins + CRE competitor landscape

cfd849bebe9769f43751bb142b86b432e9b55287 · 2026-08-07 14:07:56 -0700 · Steve (RENTV 2026)

- Classic = the current live site, now a first-class selectable card (iframe→/, chosen accepts 'classic').
- All 6 ranked (#1 Cinematic … #6 Classic) with a 'Why it wins' pitch + the CRE competitor each out-designs (Bisnow/The REview/The Real Deal/CoStar/Commercial Observer/current).
- New 'The field' section: 6 real CRE news-wire/conference rivals (The Real Deal, Bisnow, Commercial Observer, GlobeSt, CoStar, Connect CRE) with links.
- Cards sorted by rank; #1 gets a ★ Recommended tag.

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

Files touched

Diff

commit cfd849bebe9769f43751bb142b86b432e9b55287
Author: Steve (RENTV 2026) <steve@designerwallcoverings.com>
Date:   Fri Aug 7 14:07:56 2026 -0700

    selector: add Classic (original) as 6th option + rank all 6 + why-it-wins + CRE competitor landscape
    
    - Classic = the current live site, now a first-class selectable card (iframe→/, chosen accepts 'classic').
    - All 6 ranked (#1 Cinematic … #6 Classic) with a 'Why it wins' pitch + the CRE competitor each out-designs (Bisnow/The REview/The Real Deal/CoStar/Commercial Observer/current).
    - New 'The field' section: 6 real CRE news-wire/conference rivals (The Real Deal, Bisnow, Commercial Observer, GlobeSt, CoStar, Connect CRE) with links.
    - Cards sorted by rank; #1 gets a ★ Recommended tag.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 public/2026/index.html | 107 ++++++++++++++++++++++++++++++++++++++++++-------
 src/ad-system.cjs      |   6 +--
 2 files changed, 95 insertions(+), 18 deletions(-)

diff --git a/public/2026/index.html b/public/2026/index.html
index e595bb1c..2145e452 100644
--- a/public/2026/index.html
+++ b/public/2026/index.html
@@ -80,14 +80,54 @@
 </header>
 
 <section class="hero">
-  <div class="eye">2026 Redesign · Pick the direction</div>
-  <h1>Five ways the new RENTV could look.</h1>
-  <p>A complete 2026 overhaul, video-first to coordinate with <b style="color:#e7ecf1">The REview</b> (rentvreview.com). Each template is a fully working homepage running on live data, with the new ad-slots system built in. Preview any one full-screen, flip between them, then lock your pick with <b style="color:var(--gold)">“Make this the site.”</b></p>
+  <div class="eye">2026 Redesign · Ranked · Pick the direction</div>
+  <h1>Six ways the new RENTV could look — ranked.</h1>
+  <p>A complete 2026 overhaul, video-first to coordinate with <b style="color:#e7ecf1">The REview</b> (rentvreview.com). Every build is a fully working homepage on live data, with the ad-slots system built in — each ranked, with <b style="color:#e7ecf1">why it wins</b> and the competitor it out-designs. Preview any one full-screen, then lock your pick with <b style="color:var(--gold)">“Make this the site.”</b> The field it beats is below ↓</p>
   <div class="meta">Preview is local only — choosing does not deploy. Going live is a separate step. · <a href="/advertise" style="color:var(--red);font-weight:700">See the ad-slots system →</a></div>
 </section>
 
 <main class="grid" id="grid"></main>
 
+<section class="rivals-sec">
+  <div class="rh"><div class="eye">The field · CRE news-wire &amp; conference competitors</div>
+    <h2>Six sites RENTV is up against.</h2>
+    <p>The commercial-real-estate news + conference landscape. Every concept above is built to out-design one of these — RENTV’s edge is <b style="color:#e7ecf1">video</b>, which none of them lead with.</p>
+  </div>
+  <div class="rivals" id="rivals"></div>
+</section>
+
+<style>
+  /* rank badge on each card */
+  .rank{position:absolute;left:12px;top:12px;z-index:2;background:#11161c;border:1px solid #2b3644;color:#c3cbd3;
+    font:800 12px ui-monospace,monospace;padding:3px 9px;border-radius:20px}
+  .rank.r1{background:var(--gold);border-color:var(--gold);color:#1b1a12}
+  .rank.r2{background:#c0c6cc;border-color:#c0c6cc;color:#14171a}
+  .rank.r3{background:#b0763a;border-color:#b0763a;color:#fff}
+  .cbody h3 .best{margin-left:8px;font-family:Inter;font-size:11px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
+    color:var(--gold);border:1px solid rgba(198,162,74,.5);border-radius:20px;padding:2px 9px;vertical-align:middle}
+  .cbody .why{color:#c3cbd3;font-size:13px;line-height:1.5;background:#0b0e12;border:1px solid #1c232b;border-left:3px solid var(--gold);
+    border-radius:8px;padding:11px 13px;margin-top:2px}
+  .cbody .why b{color:#fff}
+  .cbody .ref{display:block;color:#9aa4ad;font-size:12.5px;text-decoration:none;padding:8px 0 2px}
+  .cbody .ref b{color:#e7ecf1}.cbody .ref .vs{color:var(--red);font-weight:800;margin-right:4px}
+  .cbody .ref:hover b{color:var(--red)}
+  /* competitor landscape */
+  .rivals-sec{max-width:1240px;margin:8px auto 0;padding:26px 22px 6px;color:#e7ecf1}
+  .rivals-sec .rh .eye{color:var(--red);font-weight:800;font-size:12px;letter-spacing:.16em;text-transform:uppercase}
+  .rivals-sec .rh h2{font-family:'Playfair Display',serif;font-weight:800;font-size:clamp(22px,3vw,32px);margin:8px 0 6px}
+  .rivals-sec .rh p{color:#aeb6bd;max-width:75ch;font-size:15px}
+  .rivals{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:18px}
+  @media(max-width:820px){.rivals{grid-template-columns:1fr}}
+  .rival{display:block;background:#11161c;border:1px solid #1c232b;border-radius:12px;padding:15px 16px;text-decoration:none;
+    transition:transform .16s,border-color .16s}
+  .rival:hover{transform:translateY(-3px);border-color:#2b3644}
+  .rival .rt{font-size:10px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--red)}
+  .rival b{display:block;color:#fff;font-family:'Playfair Display',serif;font-size:19px;margin:3px 0 4px}
+  .rival .rn{display:block;color:#9aa4ad;font-size:13px}
+  .rival .go{display:inline-block;margin-top:9px;color:#8b949e;font-size:11px;font-weight:800}
+  .rival:hover .go{color:var(--red)}
+</style>
+
 <footer>
   RENTV.com 2026 template selector · templates <b>A–E</b> live under <code style="color:#8b949e">/2026/{a…e}.html</code> · ad-slots system at <a href="/advertise">/advertise</a>.
   “Make this the site” records your pick to <code style="color:#8b949e">data/site-template.json</code> (admin-gated); it never publishes on its own.
@@ -113,26 +153,54 @@
 
 <script>
 const TPL=[
-  {k:'a',name:'The Video Wall',desc:'A premium streaming-style wall of videos — the whole catalog as a browsable grid. Closest to The REview, video is the hero.',tags:['Video-first','Grid','Streaming']},
-  {k:'b',name:'Editorial Lead',desc:'A newspaper-of-record front page: big lead story, a video rail alongside the news, breaking ticker. Serious CRE journalism, elevated.',tags:['News-led','Video rail','Ticker']},
-  {k:'c',name:'Cinematic',desc:'Netflix-for-CRE. A full-bleed featured video hero over dark, cinematic category rails you scroll sideways. The most immersive.',tags:['Dark','Cinematic','Rails']},
-  {k:'d',name:'Magazine',desc:'A glossy monthly translated to web — an art-directed bento grid of feature tiles, a Video of the Week, departments and pull-quotes.',tags:['Editorial','Bento','Whitespace']},
-  {k:'e',name:'Dashboard',desc:'A Bloomberg-style CRE terminal: market pulse KPIs, a live-video panel, the deal wire and a video library — dense, live, data-forward.',tags:['Terminal','Data','Live']}
+  {k:'c',badge:'C',rank:1,name:'Cinematic',url:'/2026/c.html',desc:'Netflix-for-CRE. A full-bleed featured video hero over dark, cinematic category rails you scroll sideways. The most immersive.',tags:['Dark','Cinematic','Rails'],
+    why:'THE pick if RENTV is going video-first. It reads like a premium streaming service, not a news site — which is exactly the differentiation none of the CRE news competitors have. It puts CRE Talk + The REview front-and-center and makes every video feel like a show. Highest ad value: full-bleed hero + sponsored rails.',
+    ref:{name:'Bisnow video + America’s CRE Show',url:'https://www.bisnow.com',note:'beats their talking-head video — cinematic, branded, bingeable'}},
+  {k:'a',badge:'A',rank:2,name:'The Video Wall',url:'/2026/a.html',desc:'A premium streaming-style wall of videos — the whole catalog as a browsable grid. Closest to The REview, video is the hero.',tags:['Video-first','Grid','Streaming'],
+    why:'The most direct match to the new RENTV / The REview. One glance = the whole video library, sortable and dense. Easiest for a viewer to find something to watch, and the grid natively doubles as sponsorable ad inventory. Lowest-risk way to go video-first.',
+    ref:{name:'The REview / YouTube grid',url:'https://www.rentvreview.com',note:'same idea, made premium + monetized'}},
+  {k:'b',badge:'B',rank:3,name:'Editorial Lead',url:'/2026/b.html',desc:'A newspaper-of-record front page: big lead story, a video rail alongside the news, breaking ticker. Serious CRE journalism, elevated.',tags:['News-led','Video rail','Ticker'],
+    why:'The safest evolution — keeps RENTV’s 25-year news authority while sliding video in alongside. If the audience still comes for the deals + headlines first, this wins on trust. Goes toe-to-toe with the CRE news leaders on their own turf, then out-videos them.',
+    ref:{name:'The Real Deal / GlobeSt',url:'https://therealdeal.com',note:'their authority, plus a video rail they don’t have'}},
+  {k:'e',badge:'E',rank:4,name:'Dashboard',url:'/2026/e.html',desc:'A Bloomberg-style CRE terminal: market pulse KPIs, a live-video panel, the deal wire and a video library — dense, live, data-forward.',tags:['Terminal','Data','Live'],
+    why:'The power-user play. Positions RENTV as a live market terminal — rates, spreads, deal wire, video — in one screen. Stickiest for daily professional visitors and the strongest “data” story, but the most niche (casual readers may find it dense).',
+    ref:{name:'CoStar terminal',url:'https://www.costar.com',note:'the terminal feel — but public, free, and video-first'}},
+  {k:'d',badge:'D',rank:5,name:'Magazine',url:'/2026/d.html',desc:'A glossy monthly translated to web — an art-directed bento grid of feature tiles, a Video of the Week, departments and pull-quotes.',tags:['Editorial','Bento','Whitespace'],
+    why:'The most beautiful and brand-forward — reads like a premium print title. Best for a prestige/brand impression and big feature storytelling, but the heaviest to keep filled with fresh content week to week.',
+    ref:{name:'Commercial Observer',url:'https://commercialobserver.com',note:'glossy editorial — with RENTV’s video baked in'}},
+  {k:'classic',badge:'◧',rank:6,name:'Classic',url:'/',desc:'The current live RENTV site — the original news-first front page. Keep it exactly as-is, or use it as the baseline to compare the concepts against.',tags:['Current','News-first','Original'],
+    why:'The zero-risk baseline: change nothing. Ranked last only because it doesn’t advance the video-first goal — but it’s a legitimate choice if you want to hold steady while the ad-slots system rolls out underneath.',
+    ref:{name:'Current RENTV.com',url:'/',note:'the incumbent — the bar every concept must beat'}}
+];
+// competitor landscape — the CRE news-wire / conference field RENTV is up against
+const RIVALS=[
+  {name:'The Real Deal',url:'https://therealdeal.com',tag:'News wire',note:'CRE news leader — editorial authority, huge reach'},
+  {name:'Bisnow',url:'https://www.bisnow.com',tag:'News + Conferences',note:'National CRE news + the biggest events machine'},
+  {name:'Commercial Observer',url:'https://commercialobserver.com',tag:'Magazine',note:'Glossy CRE news + Power lists + galas'},
+  {name:'GlobeSt',url:'https://www.globest.com',tag:'News wire',note:'ALM CRE news wire + national conferences'},
+  {name:'CoStar',url:'https://www.costar.com',tag:'Data terminal',note:'The CRE data terminal + CoStar News'},
+  {name:'Connect CRE',url:'https://www.connectcre.com',tag:'News + Conferences',note:'Regional CRE news + a full conference calendar'}
 ];
+const tplUrl=k=>{const t=TPL.find(x=>x.k===k);return t?t.url:'/2026/'+k+'.html';};
+const byRank=function(a,b){return (a.rank||99)-(b.rank||99);};
 const $=s=>document.querySelector(s), esc=s=>(s||'').replace(/[&<>"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]));
 let CHOSEN=null;
 
 function cardHTML(t){
+  var rankCls = t.rank===1?'r1':t.rank===2?'r2':t.rank===3?'r3':'';
   return `<div class="card" data-k="${t.k}" id="card-${t.k}">
     <div class="framewrap">
-      <iframe src="/2026/${t.k}.html" title="${esc(t.name)} preview" loading="lazy" scrolling="no" aria-hidden="true"></iframe>
+      <iframe src="${t.url}" title="${esc(t.name)} preview" loading="lazy" scrolling="no" aria-hidden="true"></iframe>
       <div class="veil" data-open="${t.k}"></div>
-      <span class="letter">${t.k.toUpperCase()}</span>
+      <span class="rank ${rankCls}">#${t.rank}</span>
+      <span class="letter">${t.badge||t.k.toUpperCase()}</span>
       <span class="open" data-open="${t.k}">◱ Preview full-screen</span>
     </div>
     <div class="cbody">
-      <h3>${esc(t.name)}</h3>
+      <h3>${esc(t.name)}${t.rank===1?'<span class="best">★ Recommended</span>':''}</h3>
       <div class="desc">${esc(t.desc)}</div>
+      <div class="why"><b>Why it wins:</b> ${esc(t.why)}</div>
+      <a class="ref" href="${esc(t.ref.url)}" target="_blank" rel="noopener"><span class="vs">vs</span> <b>${esc(t.ref.name)}</b> — ${esc(t.ref.note)} ↗</a>
       <div class="tags">${t.tags.map(x=>`<span>${esc(x)}</span>`).join('')}</div>
       <div class="actions">
         <button class="btn primary" data-open="${t.k}">Preview</button>
@@ -141,16 +209,25 @@ function cardHTML(t){
     </div>
   </div>`;
 }
-$('#grid').innerHTML=TPL.map(cardHTML).join('');
+$('#grid').innerHTML=TPL.slice().sort(byRank).map(cardHTML).join('');
+// competitor landscape row
+(function(){
+  var host=document.getElementById('rivals'); if(!host)return;
+  host.innerHTML=RIVALS.map(function(r){
+    return '<a class="rival" href="'+esc(r.url)+'" target="_blank" rel="noopener">'+
+      '<span class="rt">'+esc(r.tag)+'</span><b>'+esc(r.name)+'</b>'+
+      '<span class="rn">'+esc(r.note)+'</span><span class="go">Open ↗</span></a>';
+  }).join('');
+})();
 
 // switch buttons in modal
-$('#switch').innerHTML=TPL.map(t=>`<button data-sw="${t.k}"><span class="l">${t.k.toUpperCase()}</span>${esc(t.name)}</button>`).join('');
+$('#switch').innerHTML=TPL.map(t=>`<button data-sw="${t.k}"><span class="l">${t.badge||t.k.toUpperCase()}</span>${esc(t.name)}</button>`).join('');
 
 let cur='a';
 function openModal(k){
   cur=k; const t=TPL.find(x=>x.k===k);
-  $('#mframe').src='/2026/'+k+'.html';
-  $('#mtitle').innerHTML=esc(t.name)+' <small>Template '+k.toUpperCase()+' · live preview</small>';
+  $('#mframe').src=t.url;
+  $('#mtitle').innerHTML=esc(t.name)+' <small>'+(k==='classic'?'Current live site':'Template '+k.toUpperCase())+' · live preview</small>';
   document.querySelectorAll('#switch button').forEach(b=>b.classList.toggle('on',b.dataset.sw===k));
   $('#ovl').classList.add('open'); document.body.style.overflow='hidden';
   refreshMakeBtn();
diff --git a/src/ad-system.cjs b/src/ad-system.cjs
index 1e3d97d0..38daa6b2 100644
--- a/src/ad-system.cjs
+++ b/src/ad-system.cjs
@@ -238,7 +238,7 @@ module.exports = function mountAdSystem(app, opts) {
   });
 
   // The chosen 2026 homepage template ("Make this the site" pick)
-  app.get('/api/ad/site-template', (_q, r) => r.json(readJSON('site-template.json', { chosen: null, options: ['a', 'b', 'c', 'd', 'e'], updated_at: null })));
+  app.get('/api/ad/site-template', (_q, r) => r.json(readJSON('site-template.json', { chosen: null, options: ['classic', 'a', 'b', 'c', 'd', 'e'], updated_at: null })));
 
   /* ── ADMIN ENDPOINTS (adminOnly) ──────────────────────────────────────────── */
 
@@ -280,8 +280,8 @@ module.exports = function mountAdSystem(app, opts) {
   // Record the chosen template ("Make this the site")
   app.post('/api/ad/admin/site-template', adminOnly, (req, r) => {
     const chosen = esc((req.body || {}).chosen).toLowerCase();
-    if (!['a', 'b', 'c', 'd', 'e'].includes(chosen)) return r.status(400).json({ ok: false, error: 'chosen must be a|b|c|d|e' });
-    const rec = { chosen, options: ['a', 'b', 'c', 'd', 'e'], updated_at: nowISO(), note: 'Local selection only — going live is a separate Steve-gated deploy.' };
+    if (!['classic', 'a', 'b', 'c', 'd', 'e'].includes(chosen)) return r.status(400).json({ ok: false, error: 'chosen must be classic|a|b|c|d|e' });
+    const rec = { chosen, options: ['classic', 'a', 'b', 'c', 'd', 'e'], updated_at: nowISO(), note: 'Local selection only — going live is a separate Steve-gated deploy.' };
     writeJSON('site-template.json', rec);
     r.json({ ok: true, chosen, note: rec.note });
   });

← a28939c1 chore: v0.23.0 (session close — admin View all template-comp  ·  back to Rentv 2026  ·  selector: bake rank + why-it-wins + competitor into each ful 3a9785bd →