← 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 →