[object Object]

← back to Rentv Ad Engine

analytics: executive-summary KPI strip (clients/airings/episodes/top client/est. value/guests) + Print-Save-PDF with print stylesheet — hand-to-a-prospect one-pager

6985df0eef3924ed47f3f2fa250b54a29aec850b · 2026-08-07 14:12:04 -0700 · Steve Abrams

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

Files touched

Diff

commit 6985df0eef3924ed47f3f2fa250b54a29aec850b
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Aug 7 14:12:04 2026 -0700

    analytics: executive-summary KPI strip (clients/airings/episodes/top client/est. value/guests) + Print-Save-PDF with print stylesheet — hand-to-a-prospect one-pager
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 public/charts.html | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/public/charts.html b/public/charts.html
index 9d1095e..7071b17 100644
--- a/public/charts.html
+++ b/public/charts.html
@@ -33,6 +33,18 @@
   .dot{width:10px;height:10px;border-radius:3px;display:inline-block}
   svg{display:block;max-width:100%}
   .muted{color:var(--dim);font-size:12px}
+  .kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin:4px 0 8px}
+  .kpi{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:14px 16px}
+  .kpi .v{font-size:26px;font-weight:800;color:var(--ink);line-height:1.1}
+  .kpi .v.gold{color:var(--gold)}.kpi .v.teal{color:var(--teal)}
+  .kpi .k{color:var(--dim);font-size:12px;margin-top:4px}
+  .prbtn{background:var(--teal);color:#08131a;border:0;border-radius:8px;padding:6px 12px;font-weight:700;cursor:pointer;font-size:12px}
+  @media print{
+    header{position:static}.prbtn,#rate,.gauges canvas{display:none!important}
+    body{background:#fff;color:#111}.panel,.kpi,.gauge{background:#fff;border-color:#ccc}
+    .kpi .v{color:#111}.muted{color:#555}h2{color:#333}
+    main{max-width:100%}
+  }
 </style>
 </head>
 <body>
@@ -42,10 +54,13 @@
   <div style="margin-left:auto;display:flex;gap:10px;font-size:12px">
     <a href="./">← Directory</a>
     <a href="https://www.rentvreview.com/Producers/View/618" target="_blank" rel="noopener">🎬 CRE Talk episodes</a>
+    <button class="prbtn" onclick="window.print()">🖨 Print / Save PDF</button>
   </div>
 </header>
 
 <main>
+  <h2 style="margin-top:8px">Executive summary <span class="muted" id="asof" style="text-transform:none;font-weight:400"></span></h2>
+  <div class="kpis" id="kpis"></div>
   <h2>Share of voice — top clients (liquid gauges)</h2>
   <div class="muted" style="margin:-6px 0 10px">Each gauge fills to the client's share of all detected ad airings. Live wave = active sponsor.</div>
   <div class="gauges" id="gauges"></div>
@@ -135,6 +150,7 @@ async function boot(){
 
   $("#stat").innerHTML=`<b>${clients.length}</b> advertising clients · <b>${airings.length}</b> ad airings · <b>${advertisers.length}</b> advertisers total`;
 
+  renderKpis(clients,airings,guests);
   renderGauges(clients.slice(0,6),totalAir);
   renderBars(clients.slice(0,14),clients[0]?.airings||1);
   renderDonut(clients);
@@ -439,6 +455,26 @@ function renderOverlap(airings){
   $("#overlap").innerHTML=h;
 }
 
+// ── EXECUTIVE SUMMARY KPIs ──
+function renderKpis(clients,airings,guests){
+  const eps=new Set(airings.map(a=>a.episode_id));
+  const epByClient={};airings.forEach(a=>{(epByClient[a.advertiser]=epByClient[a.advertiser]||new Set()).add(a.episode_id);});
+  const estVal=Object.values(epByClient).reduce((s,set)=>s+set.size,0)*750;
+  const top=clients[0];
+  const verified=guests.filter(g=>g.verified).length;
+  const K=[
+    ["v teal",clients.length,"advertising clients"],
+    ["v",airings.length,"ad airings (as-aired)"],
+    ["v",eps.size,"episodes with ads"],
+    ["v",top?top.name:"—","top client"],
+    ["v gold","$"+estVal.toLocaleString(),"est. value @ $750/ep"],
+    ["v",guests.length+" · "+verified+" ✓","guests (verified)"],
+  ];
+  $("#kpis").innerHTML=K.map(([cls,v,k])=>`<div class="kpi"><div class="${cls}" style="${String(v).length>14?'font-size:18px':''}">${esc(v)}</div><div class="k">${esc(k)}</div></div>`).join("");
+  const d=new Date();
+  $("#asof").textContent="— RENTV CRE Talk advertiser report · generated "+d.toLocaleString(undefined,{year:'numeric',month:'short',day:'numeric'});
+}
+
 boot();
 </script>
 </body>

← c5ebed2 TK-10343: scale ad-engine harvest to all 123 Vimeo videos (a  ·  back to Rentv Ad Engine  ·  fix(deploy): HEALTH_URL 9789->9793 (app's real remote port; 9302761 →