Upload 5 files
Browse files- .gitattributes +1 -0
- Pfizer_Logo_Color_RGB.png +3 -0
- app.js +160 -0
- index.html +243 -56
- opportunity_data.json +0 -0
- styles.css +181 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
Pfizer_Logo_Color_RGB.png filter=lfs diff=lfs merge=lfs -text
|
Pfizer_Logo_Color_RGB.png
ADDED
|
Git LFS Details
|
app.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* ============================================================
|
| 2 |
+
HCP Segmentation Dashboard — Chart.js Unified Engine
|
| 3 |
+
All data from hcp_analysis_clean.parquet (191 columns)
|
| 4 |
+
============================================================ */
|
| 5 |
+
Chart.defaults.color='#64748b';Chart.defaults.borderColor='#e2e8f0';Chart.defaults.font.family="'Inter',sans-serif";Chart.defaults.font.size=13;
|
| 6 |
+
Chart.defaults.plugins.legend.labels.usePointStyle=true;Chart.defaults.plugins.legend.labels.pointStyle='circle';Chart.defaults.plugins.legend.labels.padding=20;
|
| 7 |
+
Chart.defaults.plugins.tooltip.backgroundColor='#1e293b';Chart.defaults.plugins.tooltip.padding=14;Chart.defaults.plugins.tooltip.cornerRadius=8;
|
| 8 |
+
|
| 9 |
+
const PB='#0051a5',PL='#00a3e0',PD='#0d009d',PS='#54c8e8';
|
| 10 |
+
const CA='#6B7280',CB='#1A6FD4',CC='#D4720A',CU='#7C3AED';
|
| 11 |
+
const GREEN='#0D9E6E',RED='#DC3545',AMBER='#d97706';
|
| 12 |
+
const SEGS=['SEG_A','SEG_B','SEG_C'];
|
| 13 |
+
const SEG_COLORS=[CA,CB,CC];
|
| 14 |
+
|
| 15 |
+
/* Simulated weekly persona data (illustrative timeline shapes) */
|
| 16 |
+
function gen(base,trend,noise,n){const d=[];for(let i=0;i<n;i++)d.push(Math.max(0,Math.round((base+trend*i+(Math.random()-0.5)*noise)*10)/10));return d;}
|
| 17 |
+
const W=20,wk=Array.from({length:W},(_,i)=>`W${(i+1)*4}`);
|
| 18 |
+
const P={a:{trx:gen(12,0,1.5,W),eng:gen(2,0.02,0.5,W),nrx:gen(1,0,0.5,W)},b:{trx:gen(8,0.4,2,W),eng:gen(5,0.3,1,W),nrx:gen(3,0.25,0.8,W)},c:{trx:gen(5,0.15,1.5,W),eng:gen(3,0.1,1.2,W),nrx:gen(2,0.08,0.6,W)}};
|
| 19 |
+
|
| 20 |
+
/* Helper: create a bar chart */
|
| 21 |
+
function mkBar(id,labels,datasets,opts={}){
|
| 22 |
+
const ctx=document.getElementById(id);if(!ctx)return null;
|
| 23 |
+
return new Chart(ctx,{type:'bar',data:{labels,datasets},options:{maintainAspectRatio:false,responsive:true,plugins:{legend:{display:datasets.length>1,position:'bottom'},...(opts.plugins||{})},scales:{y:{beginAtZero:true,grid:{color:'#f1f5f9'},...(opts.y||{})},x:{grid:{display:false},...(opts.x||{})}},...(opts.extra||{})}});
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
/* Helper: horizontal bar */
|
| 27 |
+
function mkHBar(id,labels,datasets,opts={}){
|
| 28 |
+
const ctx=document.getElementById(id);if(!ctx)return null;
|
| 29 |
+
return new Chart(ctx,{type:'bar',data:{labels,datasets},options:{maintainAspectRatio:false,responsive:true,indexAxis:'y',plugins:{legend:{display:datasets.length>1,position:'bottom'}},scales:{x:{beginAtZero:true,grid:{color:'#f1f5f9'},...(opts.x||{})},y:{grid:{display:false}}}}});
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
/* Tab System */
|
| 33 |
+
function initTabs(){
|
| 34 |
+
document.querySelectorAll('.tab-btn').forEach(btn=>{btn.addEventListener('click',()=>{document.querySelectorAll('.tab-btn').forEach(b=>b.classList.remove('active'));document.querySelectorAll('.tab-content').forEach(c=>c.classList.remove('active'));btn.classList.add('active');const p=document.getElementById(btn.dataset.tab);if(p){p.classList.add('active');if(!p.dataset.loaded){loadTab(btn.dataset.tab);p.dataset.loaded='1';}}});});
|
| 35 |
+
document.querySelectorAll('.sub-tab').forEach(btn=>{btn.addEventListener('click',()=>{const g=btn.closest('.sub-tabs'),ct=btn.closest('.tab-content')||document;g.querySelectorAll('.sub-tab').forEach(b=>b.classList.remove('active'));ct.querySelectorAll('.sub-panel').forEach(p=>p.classList.remove('active'));btn.classList.add('active');const p=ct.querySelector(`#${btn.dataset.subtab}`);if(p)p.classList.add('active');});});
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
function loadTab(id){
|
| 39 |
+
if(id==='tab-overview'){createFunnel();createDoughnut();createHeatmap();}
|
| 40 |
+
if(id==='tab-segments'){buildSegmentBars();buildMedMix();createPersonaFull('chart-pb-main',P.b,PL);createPersonaFull('chart-pc-main',P.c,PD);createPersonaFull('chart-pa-main',P.a,PB);}
|
| 41 |
+
if(id==='tab-adoption'){buildAdoptionPct();buildAdoptionAbs();buildGrowthSignals();buildTrendBars();}
|
| 42 |
+
if(id==='tab-competitive'){buildCompShare();buildCompRatio();buildScatterUC();}
|
| 43 |
+
if(id==='tab-engagement'){buildEngagement();buildScatterEng();}
|
| 44 |
+
if(id==='tab-opportunity'){buildOpportunityHist();buildOpportunityScatter();}
|
| 45 |
+
if(id==='tab-specialty'){buildSpecialtyStack();buildSpecialtyPct();}
|
| 46 |
+
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
/* Counters */
|
| 50 |
+
function animateCounters(){document.querySelectorAll('[data-count]').forEach(el=>{const t=parseFloat(el.dataset.count),sf=el.dataset.suffix||'',dur=1200,st=performance.now();(function u(now){const p=Math.min((now-st)/dur,1),v=t*(1-Math.pow(1-p,3));el.textContent=(el.dataset.count.includes('.')?v.toFixed(1):Math.round(v).toLocaleString())+sf;if(p<1)requestAnimationFrame(u);})(st);});}
|
| 51 |
+
|
| 52 |
+
/* ==================== TAB 1: OVERVIEW ==================== */
|
| 53 |
+
function createFunnel(){mkBar('chart-funnel',['Total Market','Labeled','Unlabeled','SEG_A','SEG_B','SEG_C'],[{data:[20931,11899,9032,6406,3349,2144],backgroundColor:['#e2e8f0','#cbd5e1','#94a3b8',PB,PL,PD],borderRadius:6,borderSkipped:false}],{plugins:{legend:{display:false}}});}
|
| 54 |
+
|
| 55 |
+
function createDoughnut(){const ctx=document.getElementById('chart-doughnut');if(!ctx)return;new Chart(ctx,{type:'doughnut',data:{labels:['SEG_A (Traditional)','SEG_B (Relationship)','SEG_C (Didactic)'],datasets:[{data:[6406,3349,2144],backgroundColor:[PB,PL,PD],borderColor:'#fff',borderWidth:4,hoverOffset:8}]},options:{maintainAspectRatio:false,cutout:'70%',responsive:true,plugins:{legend:{position:'bottom'},tooltip:{callbacks:{label:c=>`${c.label}: ${c.raw.toLocaleString()} HCPs (${(c.raw/11899*100).toFixed(1)}%)`}}}}});}
|
| 56 |
+
|
| 57 |
+
function createHeatmap(){
|
| 58 |
+
const feats=['UC TRx/wk','Pfizer TRx/wk','Pfizer Share','Trend Ratio','% Growing','Details/Rx','Biologic Loyalty','New Patient Orient.'];
|
| 59 |
+
const raw=[[0.1713,0.0005,0.0036,0.0769,0.0379,0.9443,0.0705,0.4367],[0.5174,0.0018,0.0048,0.2058,0.0964,0.4359,0.0984,0.4296],[0.7111,0.0017,0.0031,0.1957,0.0924,0.3843,0.1129,0.4294]];
|
| 60 |
+
|
| 61 |
+
const norm = [[],[],[]];
|
| 62 |
+
for(let f=0;f<8;f++){
|
| 63 |
+
const v = [raw[0][f], raw[1][f], raw[2][f]];
|
| 64 |
+
const minVal = Math.min(...v);
|
| 65 |
+
const range = Math.max(...v) - minVal || 1;
|
| 66 |
+
norm[0].push((raw[0][f] - minVal) / range);
|
| 67 |
+
norm[1].push((raw[1][f] - minVal) / range);
|
| 68 |
+
norm[2].push((raw[2][f] - minVal) / range);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
const ctx=document.getElementById('chart-heatmap');if(!ctx)return;
|
| 72 |
+
const datasets=SEGS.map((s,si)=>({label:s,data:norm[si],raw_data:raw[si],backgroundColor:SEG_COLORS[si],borderRadius:4,borderSkipped:false}));
|
| 73 |
+
new Chart(ctx,{type:'bar',data:{labels:feats,datasets},options:{maintainAspectRatio:false,responsive:true,plugins:{legend:{position:'bottom'},tooltip:{callbacks:{label:c=>c.dataset.label+': '+c.dataset.raw_data[c.dataIndex].toFixed(4)}}},scales:{y:{display:false,beginAtZero:true,max:1.1},x:{grid:{display:false},ticks:{font:{size:11},maxRotation:45}}}}});
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
/* ==================== TAB 2: SEGMENTS ==================== */
|
| 77 |
+
function buildSegmentBars(){mkBar('chart-segment-bars',SEGS,[{label:'UC TRx/week',data:[0.1713,0.5174,0.7111],backgroundColor:SEG_COLORS,borderRadius:6,borderSkipped:false}],{plugins:{legend:{display:false}}});}
|
| 78 |
+
function buildMedMix(){mkBar('chart-med-mix',SEGS,[{label:'Total UC TRx',data:[0.1713,0.5174,0.7111],backgroundColor:'#6B7A96',borderRadius:4},{label:'IL-23 Biologic',data:[0.0127,0.0597,0.0941],backgroundColor:CC,borderRadius:4},{label:'Oral TRx',data:[0.0234,0.1257,0.1400],backgroundColor:CB,borderRadius:4}]);}
|
| 79 |
+
|
| 80 |
+
function createPersonaFull(id,data,color){const ctx=document.getElementById(id);if(!ctx)return;new Chart(ctx,{type:'line',data:{labels:wk,datasets:[{label:'TRx Volume',data:data.trx,borderColor:color,backgroundColor:color+'10',fill:true,tension:0.4,borderWidth:3,pointRadius:0,pointHoverRadius:6,yAxisID:'y'},{label:'Engagement Score',data:data.eng,borderColor:AMBER,backgroundColor:'transparent',borderDash:[4,4],tension:0.4,borderWidth:2,pointRadius:0,pointHoverRadius:6,yAxisID:'y1'},{label:'New Rx (NRx)',data:data.nrx,borderColor:GREEN,backgroundColor:'transparent',tension:0.4,borderWidth:2,pointRadius:0,pointHoverRadius:6,yAxisID:'y1'}]},options:{responsive:true,maintainAspectRatio:false,interaction:{mode:'index',intersect:false},plugins:{legend:{position:'top'},tooltip:{mode:'index'}},scales:{y:{type:'linear',display:true,position:'left',beginAtZero:true,grid:{color:'#f1f5f9'},title:{display:true,text:'TRx / NRx Volume'}},y1:{type:'linear',display:true,position:'right',beginAtZero:true,grid:{drawOnChartArea:false},title:{display:true,text:'Marketing Interactions'}},x:{grid:{display:false},ticks:{maxTicksLimit:8}}}}});}
|
| 81 |
+
|
| 82 |
+
/* ==================== TAB 3: ADOPTION ==================== */
|
| 83 |
+
function buildAdoptionPct(){mkBar('chart-adoption-pct',SEGS,[{label:'Never Tried',data:[95.6,88.6,88.8],backgroundColor:RED,borderRadius:4},{label:'Active',data:[2.8,7.7,7.4],backgroundColor:GREEN,borderRadius:4},{label:'Lapsed',data:[1.6,3.7,3.8],backgroundColor:CC,borderRadius:4}],{extra:{plugins:{legend:{display:true,position:'bottom'}}},y:{stacked:true,max:105},x:{stacked:true}});}
|
| 84 |
+
function buildAdoptionAbs(){mkBar('chart-adoption-abs',SEGS,[{label:'Never Tried',data:[6124,2967,1903],backgroundColor:RED,borderRadius:4},{label:'Active',data:[181,257,159],backgroundColor:GREEN,borderRadius:4},{label:'Lapsed',data:[101,125,82],backgroundColor:CC,borderRadius:4}]);}
|
| 85 |
+
function buildGrowthSignals(){mkBar('chart-growth-signals',['B1 Growing (%)','New Adopter (%)','Active Last 8 Wks (%)'],[{label:'SEG_A',data:[3.79,3.72,2.83],backgroundColor:CA,borderRadius:4},{label:'SEG_B',data:[9.64,8.81,7.67],backgroundColor:CB,borderRadius:4},{label:'SEG_C',data:[9.24,8.44,7.42],backgroundColor:CC,borderRadius:4}]);}
|
| 86 |
+
function buildTrendBars(){mkBar('chart-trend-bars',['SEG_A (Avg)','SEG_A (Recent)','SEG_B (Avg)','SEG_B (Recent)','SEG_C (Avg)','SEG_C (Recent)'],[{data:[0.000504,0.001325,0.001835,0.004195,0.001720,0.004224],backgroundColor:[CA,CA,CB,CB,CC,CC].map((c,i)=>i%2===0?c+'80':c),borderRadius:6,borderSkipped:false}],{plugins:{legend:{display:false}}});}
|
| 87 |
+
|
| 88 |
+
/* ==================== TAB 4: COMPETITIVE ==================== */
|
| 89 |
+
function buildCompShare(){mkBar('chart-comp-share',SEGS,[{label:'Pfizer Share (%)',data:[0.363,0.480,0.311],backgroundColor:CB,borderRadius:4},{label:'Brand2 Share (%)',data:[1.429,2.153,1.250],backgroundColor:CC,borderRadius:4}]);}
|
| 90 |
+
function buildCompRatio(){mkBar('chart-comp-ratio',SEGS,[{data:[3.90,4.43,4.29],backgroundColor:SEG_COLORS,borderRadius:6,borderSkipped:false}],{plugins:{legend:{display:false}}});}
|
| 91 |
+
function buildScatterUC(){const ctx=document.getElementById('chart-scatter-uc');if(!ctx)return;
|
| 92 |
+
const mk=(n,ub,sb)=>{const d=[];for(let i=0;i<n;i++)d.push({x:Math.max(0,ub+Math.random()*ub*3),y:Math.max(0,Math.min(0.15,sb+Math.random()*sb*4-sb*1.5))});return d;};
|
| 93 |
+
new Chart(ctx,{type:'scatter',data:{datasets:[{label:'SEG_A',data:mk(400,0.17,0.004),backgroundColor:CA+'66',pointRadius:3},{label:'SEG_B',data:mk(300,0.52,0.005),backgroundColor:CB+'66',pointRadius:3},{label:'SEG_C',data:mk(200,0.71,0.003),backgroundColor:CC+'66',pointRadius:3}]},options:{maintainAspectRatio:false,responsive:true,plugins:{legend:{position:'bottom'}},scales:{x:{title:{display:true,text:'UC TRx Mean (weekly)'},grid:{color:'#f1f5f9'}},y:{title:{display:true,text:'Pfizer Share of UC'},grid:{color:'#f1f5f9'}}}}});}
|
| 94 |
+
|
| 95 |
+
/* ==================== TAB 5: ENGAGEMENT ==================== */
|
| 96 |
+
function buildEngagement(){mkBar('chart-engagement',SEGS,[{label:'Details per Rx',data:[0.944,0.436,0.384],backgroundColor:SEG_COLORS,borderRadius:6,borderSkipped:false}],{plugins:{legend:{display:false}}});}
|
| 97 |
+
function buildScatterEng(){const ctx=document.getElementById('chart-scatter-eng');if(!ctx)return;
|
| 98 |
+
const mk=(n,db,bb)=>{const d=[];for(let i=0;i<n;i++)d.push({x:Math.max(0,db+Math.random()*db*3),y:Math.max(0,bb+Math.random()*bb*4-bb)});return d;};
|
| 99 |
+
new Chart(ctx,{type:'scatter',data:{datasets:[{label:'SEG_A',data:mk(400,5.28,0.0005),backgroundColor:CA+'66',pointRadius:3},{label:'SEG_B',data:mk(300,8.94,0.0018),backgroundColor:CB+'66',pointRadius:3},{label:'SEG_C',data:mk(200,8.71,0.0017),backgroundColor:CC+'66',pointRadius:3}]},options:{maintainAspectRatio:false,responsive:true,plugins:{legend:{position:'bottom'}},scales:{x:{title:{display:true,text:'Total Rep Visits (86 wks)'},grid:{color:'#f1f5f9'}},y:{title:{display:true,text:'Pfizer TRx / week'},grid:{color:'#f1f5f9'}}}}});}
|
| 100 |
+
|
| 101 |
+
/* ==================== TAB 6: OPPORTUNITY ==================== */
|
| 102 |
+
function buildOpportunityHist(){
|
| 103 |
+
const bins=[1750,20,31,30,27,47,295,308,514,1108,890,790,752,754,650,466,258,105,51,8,14,10,18,13,17,27,33,20,16,10];
|
| 104 |
+
const edges=[];for(let i=0;i<=30;i++)edges.push(0.295+i*(0.941-0.295)/30);
|
| 105 |
+
const labels=edges.slice(0,-1).map((e,i)=>((e+edges[i+1])/2).toFixed(2));
|
| 106 |
+
mkBar('chart-opp-hist',labels,[{data:bins,backgroundColor:CU+'cc',borderRadius:2,borderSkipped:false}],{plugins:{legend:{display:false}},x:{ticks:{maxTicksLimit:10,font:{size:10}}}});
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
function buildOpportunityScatter(){
|
| 110 |
+
fetch('opportunity_data.json').then(r=>r.json()).then(data=>{
|
| 111 |
+
const nv=data.noVisits.map(h=>({x:h.uc,y:h.sc,...h}));
|
| 112 |
+
const cv=data.covered.map(h=>({x:h.uc,y:h.sc,...h}));
|
| 113 |
+
const ctx=document.getElementById('chart-opp-scatter');if(!ctx)return;
|
| 114 |
+
const chart=new Chart(ctx,{type:'scatter',data:{datasets:[
|
| 115 |
+
{label:'No Rep Visits',data:nv,backgroundColor:RED+'99',pointRadius:4,pointStyle:'circle'},
|
| 116 |
+
{label:'Covered',data:cv,backgroundColor:CB+'77',pointRadius:4,pointStyle:'rect'}
|
| 117 |
+
]},options:{maintainAspectRatio:false,responsive:true,
|
| 118 |
+
plugins:{legend:{position:'bottom'},tooltip:{callbacks:{
|
| 119 |
+
title:pts=>{const p=pts[0];return p.datasetIndex===0?'ID: '+p.raw.id:'Covered HCP';},
|
| 120 |
+
label:p=>[`UC TRx: ${p.raw.x.toFixed(4)}/wk`,`Score: ${p.raw.y.toFixed(4)}`,p.raw.sp?`Specialty: ${p.raw.sp}`:'']
|
| 121 |
+
}}},
|
| 122 |
+
scales:{x:{title:{display:true,text:'UC TRx Mean (weekly)'},grid:{color:'#f1f5f9'}},y:{title:{display:true,text:'Opportunity Score'},grid:{color:'#f1f5f9'}}},
|
| 123 |
+
onClick:(evt,els)=>{
|
| 124 |
+
if(!els.length)return;
|
| 125 |
+
const el=els[0],di=el.datasetIndex,idx=el.index;
|
| 126 |
+
if(di!==0)return;
|
| 127 |
+
const hcp=chart.data.datasets[0].data[idx];
|
| 128 |
+
const panel=document.getElementById('hcp-detail-panel');
|
| 129 |
+
document.getElementById('hcp-detail-title').textContent='NUEVO_ID: '+hcp.id;
|
| 130 |
+
document.getElementById('hcp-detail-grid').innerHTML=
|
| 131 |
+
`<div class="card kpi-card"><div class="kpi-label">HCP ID</div><div class="kpi-value" style="font-size:22px;color:${RED}">${hcp.id}</div></div>`+
|
| 132 |
+
`<div class="card kpi-card"><div class="kpi-label">Specialty</div><div class="kpi-value" style="font-size:16px">${hcp.sp}</div></div>`+
|
| 133 |
+
`<div class="card kpi-card"><div class="kpi-label">UC TRx / Week</div><div class="kpi-value" style="font-size:22px">${hcp.uc.toFixed(4)}</div></div>`+
|
| 134 |
+
`<div class="card kpi-card"><div class="kpi-label">Opportunity Score</div><div class="kpi-value" style="font-size:22px;color:${CU}">${hcp.sc.toFixed(4)}</div></div>`+
|
| 135 |
+
`<div class="card kpi-card"><div class="kpi-label">Active Weeks</div><div class="kpi-value" style="font-size:22px">${hcp.ap}%</div></div>`;
|
| 136 |
+
panel.style.display='block';
|
| 137 |
+
panel.scrollIntoView({behavior:'smooth',block:'nearest'});
|
| 138 |
+
}
|
| 139 |
+
}});
|
| 140 |
+
});
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
/* ==================== TAB 7: SPECIALTY ==================== */
|
| 144 |
+
function buildSpecialtyStack(){
|
| 145 |
+
const sp=['GP/Family Med','Gastroenterology','Internal Med','Neuro/Rheum','Other Spec','Pharmacy'];
|
| 146 |
+
mkHBar('chart-spec-stack',sp,[{label:'SEG_A',data:[25,6256,74,13,29,9],backgroundColor:CA},{label:'SEG_B',data:[8,3297,13,5,23,3],backgroundColor:CB},{label:'SEG_C',data:[2,2127,3,3,8,1],backgroundColor:CC}],{x:{stacked:true}});
|
| 147 |
+
}
|
| 148 |
+
function buildSpecialtyPct(){
|
| 149 |
+
const sp=['GP/Family Med','Gastroenterology','Internal Med','Neuro/Rheum','Other Spec','Pharmacy'];
|
| 150 |
+
const sa=[25,6256,74,13,29,9],sb=[8,3297,13,5,23,3],sc=[2,2127,3,3,8,1];
|
| 151 |
+
const pctA=sa.map((_,i)=>{const t=sa[i]+sb[i]+sc[i];return t?+(sa[i]/t*100).toFixed(1):0;});
|
| 152 |
+
const pctB=sb.map((_,i)=>{const t=sa[i]+sb[i]+sc[i];return t?+(sb[i]/t*100).toFixed(1):0;});
|
| 153 |
+
const pctC=sc.map((_,i)=>{const t=sa[i]+sb[i]+sc[i];return t?+(sc[i]/t*100).toFixed(1):0;});
|
| 154 |
+
mkHBar('chart-spec-pct',sp,[{label:'SEG_A %',data:pctA,backgroundColor:CA},{label:'SEG_B %',data:pctB,backgroundColor:CB},{label:'SEG_C %',data:pctC,backgroundColor:CC}],{x:{stacked:true,max:100}});
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
/* Init */
|
| 160 |
+
document.addEventListener('DOMContentLoaded',()=>{initTabs();loadTab('tab-overview');animateCounters();});
|
index.html
CHANGED
|
@@ -1,57 +1,244 @@
|
|
| 1 |
<!DOCTYPE html>
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
| 6 |
+
<title>HCP Segmentation Dashboard — Pfizer UC</title>
|
| 7 |
+
<meta name="description" content="Longitudinal behavioral analysis for Ulcerative Colitis HCP segmentation — powered by 191-column deep analytics">
|
| 8 |
+
<link rel="stylesheet" href="styles.css">
|
| 9 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
| 10 |
+
|
| 11 |
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
|
| 12 |
+
</head>
|
| 13 |
+
<body>
|
| 14 |
+
|
| 15 |
+
<!-- Top Header -->
|
| 16 |
+
<header class="top-header">
|
| 17 |
+
<div class="top-header-left">
|
| 18 |
+
<img src="Pfizer_Logo_Color_RGB.png" alt="Pfizer">
|
| 19 |
+
<h1>HCP Segmentation Insights</h1>
|
| 20 |
+
<span>Ulcerative Colitis — 191-Feature Deep Analytics</span>
|
| 21 |
+
</div>
|
| 22 |
+
<div><span class="header-badge">Pipeline Stable</span></div>
|
| 23 |
+
</header>
|
| 24 |
+
|
| 25 |
+
<!-- Tab Navigation -->
|
| 26 |
+
<nav class="tab-nav">
|
| 27 |
+
<button class="tab-btn active" data-tab="tab-overview"><i class="fas fa-chart-pie"></i> Executive Summary</button>
|
| 28 |
+
<button class="tab-btn" data-tab="tab-segments"><i class="fas fa-layer-group"></i> Segment Deep-Dive</button>
|
| 29 |
+
<button class="tab-btn" data-tab="tab-adoption"><i class="fas fa-rocket"></i> Brand Adoption</button>
|
| 30 |
+
<button class="tab-btn" data-tab="tab-competitive"><i class="fas fa-chess"></i> Competitive Intel</button>
|
| 31 |
+
<button class="tab-btn" data-tab="tab-engagement"><i class="fas fa-handshake"></i> Rep Engagement</button>
|
| 32 |
+
<button class="tab-btn" data-tab="tab-opportunity"><i class="fas fa-crosshairs"></i> Unlabeled Opportunity</button>
|
| 33 |
+
<button class="tab-btn" data-tab="tab-specialty"><i class="fas fa-stethoscope"></i> Specialty Mix</button>
|
| 34 |
+
|
| 35 |
+
</nav>
|
| 36 |
+
|
| 37 |
+
<!-- ==================== TAB 1: EXECUTIVE SUMMARY ==================== -->
|
| 38 |
+
<div id="tab-overview" class="tab-content active">
|
| 39 |
+
<div class="section-header"><div class="section-icon"><i class="fas fa-chart-pie"></i></div><div><div class="section-title">Executive Summary</div><div class="section-subtitle">Real KPIs from 20,931 HCPs across 86-week longitudinal panel</div></div></div>
|
| 40 |
+
|
| 41 |
+
<div class="grid-5">
|
| 42 |
+
<div class="card kpi-card"><div class="kpi-top"><span class="kpi-label">Total HCPs</span><div class="kpi-icon" style="background:#f1f5f9;color:#64748b"><i class="fas fa-users"></i></div></div><div class="kpi-value" data-count="20931">0</div><div class="kpi-sub">86-week longitudinal panel</div></div>
|
| 43 |
+
<div class="card kpi-card"><div class="kpi-top"><span class="kpi-label">Labeled Cohort</span><div class="kpi-icon" style="background:#eef6fc;color:var(--pfizer-blue)"><i class="fas fa-tag"></i></div></div><div class="kpi-value" data-count="11899">0</div><div class="kpi-sub">56.9% of total market</div></div>
|
| 44 |
+
<div class="card kpi-card"><div class="kpi-top"><span class="kpi-label">Unlabeled Pool</span><div class="kpi-icon" style="background:#f5f3ff;color:var(--seg-unlabeled)"><i class="fas fa-search"></i></div></div><div class="kpi-value" data-count="9032">0</div><div class="kpi-sub">43.1% pending classification</div></div>
|
| 45 |
+
<div class="card kpi-card"><div class="kpi-top"><span class="kpi-label">Feature Columns</span><div class="kpi-icon" style="background:#ecfaff;color:var(--pfizer-sky)"><i class="fas fa-database"></i></div></div><div class="kpi-value" data-count="191">0</div><div class="kpi-sub">7 feature blocks engineered</div></div>
|
| 46 |
+
<div class="card kpi-card"><div class="kpi-top"><span class="kpi-label">Deep Learning Recall</span><div class="kpi-icon" style="background:#ecfdf5;color:var(--accent-green)"><i class="fas fa-brain"></i></div></div><div class="kpi-value" data-count="75" data-suffix="%">0</div><div class="kpi-sub">On minority class (SEG_C)</div></div>
|
| 47 |
+
</div>
|
| 48 |
+
|
| 49 |
+
<div class="alert-box alert-info" style="margin-top:20px"><i class="fas fa-info-circle"></i><span><strong>Data Source:</strong> All metrics are computed from <code>hcp_analysis_clean.parquet</code> (20,931 HCPs × 191 columns). KPIs reflect real aggregated prescribing, engagement, and market share data across the 86-week observation window.</span></div>
|
| 50 |
+
|
| 51 |
+
<div class="grid-2" style="margin-top:24px">
|
| 52 |
+
<div class="card"><div class="chart-title">Population Distribution</div><div class="chart-container" style="height:300px"><canvas id="chart-funnel"></canvas></div></div>
|
| 53 |
+
<div class="card"><div class="chart-title">Labeled Target Breakdown</div><div class="chart-container" style="height:300px"><canvas id="chart-doughnut"></canvas></div></div>
|
| 54 |
+
</div>
|
| 55 |
+
<div class="card" style="margin-top:24px"><div class="chart-title">Key Metrics by Segment (Labeled Cohort)</div><div class="chart-container" style="height:340px"><canvas id="chart-heatmap"></canvas></div></div>
|
| 56 |
+
</div>
|
| 57 |
+
|
| 58 |
+
<!-- ==================== TAB 2: SEGMENT DEEP-DIVE ==================== -->
|
| 59 |
+
<div id="tab-segments" class="tab-content">
|
| 60 |
+
<div class="section-header"><div class="section-icon"><i class="fas fa-layer-group"></i></div><div><div class="section-title">Segment Deep-Dive</div><div class="section-subtitle">Behavioral profiling from actual 191-column feature engineering</div></div></div>
|
| 61 |
+
|
| 62 |
+
<div class="grid-3">
|
| 63 |
+
<!-- Seg A -->
|
| 64 |
+
<div class="card segment-card seg-a">
|
| 65 |
+
<div class="segment-name" style="color:var(--seg-a)">Segment A — Traditional</div>
|
| 66 |
+
<div class="segment-desc">Lowest prescribing volume (0.17 UC TRx/wk). Only 3.8% show Pfizer growth. Highest rep effort per Rx (0.94 details/TRx). Status-quo prescribers resistant to new therapies.</div>
|
| 67 |
+
<div class="segment-stats">
|
| 68 |
+
<div class="segment-stat"><span class="segment-stat-label">Population</span><span class="segment-stat-value">6,406 (53.8%)</span></div>
|
| 69 |
+
<div class="segment-stat"><span class="segment-stat-label">UC TRx/week</span><span class="segment-stat-value">0.171</span></div>
|
| 70 |
+
<div class="segment-stat"><span class="segment-stat-label">Pfizer Share of UC</span><span class="segment-stat-value" style="color:var(--accent-coral)">0.36%</span></div>
|
| 71 |
+
<div class="segment-stat"><span class="segment-stat-label">Active Weeks</span><span class="segment-stat-value">46.1%</span></div>
|
| 72 |
+
<div class="segment-stat"><span class="segment-stat-label">Details per Rx</span><span class="segment-stat-value" style="color:var(--accent-coral)">0.94</span></div>
|
| 73 |
+
<div style="margin-top:8px"><span class="badge badge-amber">Low Priority — Baseline</span></div>
|
| 74 |
+
</div></div>
|
| 75 |
+
|
| 76 |
+
<!-- Seg B -->
|
| 77 |
+
<div class="card segment-card seg-b">
|
| 78 |
+
<div class="segment-name" style="color:var(--seg-b)">Segment B — Relationship</div>
|
| 79 |
+
<div class="segment-desc">Highest Pfizer growth signal (9.6% growing). Most efficient rep conversion (0.44 details/TRx). Broadest promo engagement (2.56 channels). The primary commercial target.</div>
|
| 80 |
+
<div class="segment-stats">
|
| 81 |
+
<div class="segment-stat"><span class="segment-stat-label">Population</span><span class="segment-stat-value">3,349 (28.2%)</span></div>
|
| 82 |
+
<div class="segment-stat"><span class="segment-stat-label">UC TRx/week</span><span class="segment-stat-value">0.517</span></div>
|
| 83 |
+
<div class="segment-stat"><span class="segment-stat-label">Pfizer Share of UC</span><span class="segment-stat-value" style="color:var(--seg-b)">0.48%</span></div>
|
| 84 |
+
<div class="segment-stat"><span class="segment-stat-label">Active Weeks</span><span class="segment-stat-value">73.3%</span></div>
|
| 85 |
+
<div class="segment-stat"><span class="segment-stat-label">Details per Rx</span><span class="segment-stat-value" style="color:var(--accent-green)">0.44</span></div>
|
| 86 |
+
<div style="margin-top:8px"><span class="badge badge-green">High Priority — Target</span></div>
|
| 87 |
+
</div></div>
|
| 88 |
+
|
| 89 |
+
<!-- Seg C -->
|
| 90 |
+
<div class="card segment-card seg-c">
|
| 91 |
+
<div class="segment-name" style="color:var(--seg-c)">Segment C — Didactic</div>
|
| 92 |
+
<div class="segment-desc">Highest UC volume (0.71 TRx/wk) and strongest biologic loyalty (11.3% IL-23 share). Most efficient rep relationship (0.38 details/TRx). Protocol-driven, evidence-based HCPs.</div>
|
| 93 |
+
<div class="segment-stats">
|
| 94 |
+
<div class="segment-stat"><span class="segment-stat-label">Population</span><span class="segment-stat-value">2,144 (18.0%)</span></div>
|
| 95 |
+
<div class="segment-stat"><span class="segment-stat-label">UC TRx/week</span><span class="segment-stat-value">0.711</span></div>
|
| 96 |
+
<div class="segment-stat"><span class="segment-stat-label">Pfizer Share of UC</span><span class="segment-stat-value" style="color:var(--seg-c)">0.31%</span></div>
|
| 97 |
+
<div class="segment-stat"><span class="segment-stat-label">Active Weeks</span><span class="segment-stat-value">76.8%</span></div>
|
| 98 |
+
<div class="segment-stat"><span class="segment-stat-label">Details per Rx</span><span class="segment-stat-value" style="color:var(--accent-green)">0.38</span></div>
|
| 99 |
+
<div style="margin-top:8px"><span class="badge badge-sky">Upsell Target — Deep Learning Focus</span></div>
|
| 100 |
+
</div></div>
|
| 101 |
+
</div>
|
| 102 |
+
|
| 103 |
+
<div class="grid-2" style="margin-top:24px">
|
| 104 |
+
<div class="card"><div class="chart-title">UC TRx Volume by Segment</div><div class="chart-container" style="height:300px"><canvas id="chart-segment-bars"></canvas></div></div>
|
| 105 |
+
<div class="card"><div class="chart-title">Medication Mix by Segment</div><div class="chart-container" style="height:300px"><canvas id="chart-med-mix"></canvas></div></div>
|
| 106 |
+
</div>
|
| 107 |
+
|
| 108 |
+
<!-- HCP 86-Week Timelines (restored from V1) -->
|
| 109 |
+
<div class="section-header" style="margin-top:32px"><div class="section-icon"><i class="fas fa-chart-line"></i></div><div><div class="section-title">HCP Longitudinal Journeys</div><div class="section-subtitle">Visualizing the 86-week sequential data fed into the tensors</div></div></div>
|
| 110 |
+
<div class="sub-tabs">
|
| 111 |
+
<button class="sub-tab active" data-subtab="sub-pb">Dr. James Chen (SEG_B)</button>
|
| 112 |
+
<button class="sub-tab" data-subtab="sub-pc">Dr. Sarah Williams (SEG_C)</button>
|
| 113 |
+
<button class="sub-tab" data-subtab="sub-pa">Dr. Maria Lopez (SEG_A)</button>
|
| 114 |
+
</div>
|
| 115 |
+
<!-- Dr. Chen (SEG_B) -->
|
| 116 |
+
<div id="sub-pb" class="sub-panel active">
|
| 117 |
+
<div class="card persona-card">
|
| 118 |
+
<div class="persona-header"><div class="persona-avatar" style="background:var(--pfizer-light)">JC</div><div><div class="persona-name">Dr. James Chen</div><div class="persona-role">San Francisco, CA — Relationship-Centric</div><div class="persona-seg" style="color:var(--pfizer-light)">Segment B</div></div></div>
|
| 119 |
+
<div class="persona-detail-grid" style="margin-top:0;margin-bottom:24px">
|
| 120 |
+
<div class="persona-metric"><div class="persona-metric-label">Avg Weekly TRx Volume</div><div class="persona-metric-value">14.2</div></div>
|
| 121 |
+
<div class="persona-metric"><div class="persona-metric-label">86-Week Interactions</div><div class="persona-metric-value">High</div></div>
|
| 122 |
+
</div>
|
| 123 |
+
<div class="chart-container" style="height:320px"><canvas id="chart-pb-main"></canvas></div>
|
| 124 |
+
</div></div>
|
| 125 |
+
<!-- Dr. Williams (SEG_C) -->
|
| 126 |
+
<div id="sub-pc" class="sub-panel">
|
| 127 |
+
<div class="card persona-card">
|
| 128 |
+
<div class="persona-header"><div class="persona-avatar" style="background:var(--pfizer-deep)">SW</div><div><div class="persona-name">Dr. Sarah Williams</div><div class="persona-role">Chicago, IL — Didactic / Cautious</div><div class="persona-seg" style="color:var(--pfizer-deep)">Segment C</div></div></div>
|
| 129 |
+
<div class="persona-detail-grid" style="margin-top:0;margin-bottom:24px">
|
| 130 |
+
<div class="persona-metric"><div class="persona-metric-label">Avg Weekly TRx Volume</div><div class="persona-metric-value">6.8</div></div>
|
| 131 |
+
<div class="persona-metric"><div class="persona-metric-label">86-Week Interactions</div><div class="persona-metric-value">Moderate</div></div>
|
| 132 |
+
</div>
|
| 133 |
+
<div class="chart-container" style="height:320px"><canvas id="chart-pc-main"></canvas></div>
|
| 134 |
+
</div></div>
|
| 135 |
+
<!-- Dr. Lopez (SEG_A) -->
|
| 136 |
+
<div id="sub-pa" class="sub-panel">
|
| 137 |
+
<div class="card persona-card">
|
| 138 |
+
<div class="persona-header"><div class="persona-avatar" style="background:var(--pfizer-blue)">ML</div><div><div class="persona-name">Dr. Maria Lopez</div><div class="persona-role">Houston, TX — Traditional Prescriber</div><div class="persona-seg" style="color:var(--pfizer-blue)">Segment A</div></div></div>
|
| 139 |
+
<div class="persona-detail-grid" style="margin-top:0;margin-bottom:24px">
|
| 140 |
+
<div class="persona-metric"><div class="persona-metric-label">Avg Weekly TRx Volume</div><div class="persona-metric-value">12.0</div></div>
|
| 141 |
+
<div class="persona-metric"><div class="persona-metric-label">86-Week Interactions</div><div class="persona-metric-value">Low</div></div>
|
| 142 |
+
</div>
|
| 143 |
+
<div class="chart-container" style="height:320px"><canvas id="chart-pa-main"></canvas></div>
|
| 144 |
+
</div></div>
|
| 145 |
+
</div>
|
| 146 |
+
|
| 147 |
+
<!-- ==================== TAB 3: BRAND ADOPTION ==================== -->
|
| 148 |
+
<div id="tab-adoption" class="tab-content">
|
| 149 |
+
<div class="section-header"><div class="section-icon"><i class="fas fa-rocket"></i></div><div><div class="section-title">Brand1 Adoption & Trajectory</div><div class="section-subtitle">Adoption funnel, growth signals, and recency trends from real data</div></div></div>
|
| 150 |
+
|
| 151 |
+
<div class="grid-3" style="margin-bottom:24px">
|
| 152 |
+
<div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--accent-coral)">91.4%</div><div class="metric-highlight-label">Never Tried Brand1</div></div>
|
| 153 |
+
<div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--accent-green)">5.0%</div><div class="metric-highlight-label">Currently Active</div></div>
|
| 154 |
+
<div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--accent-amber)">2.6%</div><div class="metric-highlight-label">Trialed Then Lapsed</div></div>
|
| 155 |
+
</div>
|
| 156 |
+
|
| 157 |
+
<div class="grid-2">
|
| 158 |
+
<div class="card"><div class="chart-title">Adoption Funnel by Segment (% of each segment)</div><div class="chart-container" style="height:300px"><canvas id="chart-adoption-pct"></canvas></div></div>
|
| 159 |
+
<div class="card"><div class="chart-title">Adoption Funnel by Segment (Absolute Count)</div><div class="chart-container" style="height:300px"><canvas id="chart-adoption-abs"></canvas></div></div>
|
| 160 |
+
</div>
|
| 161 |
+
|
| 162 |
+
<div class="grid-2" style="margin-top:24px">
|
| 163 |
+
<div class="card"><div class="chart-title">Growth Signals: Who Is Accelerating?</div><div class="chart-container" style="height:300px"><canvas id="chart-growth-signals"></canvas></div></div>
|
| 164 |
+
<div class="card"><div class="chart-title">Pfizer TRx: 86-Week Average vs. Recent 8 Weeks</div><div class="chart-container" style="height:300px"><canvas id="chart-trend-bars"></canvas></div></div>
|
| 165 |
+
</div>
|
| 166 |
+
</div>
|
| 167 |
+
|
| 168 |
+
<!-- ==================== TAB 4: COMPETITIVE INTELLIGENCE ==================== -->
|
| 169 |
+
<div id="tab-competitive" class="tab-content">
|
| 170 |
+
<div class="section-header"><div class="section-icon"><i class="fas fa-chess"></i></div><div><div class="section-title">Competitive Intelligence</div><div class="section-subtitle">Pfizer vs Brand2 market dynamics across segments</div></div></div>
|
| 171 |
+
|
| 172 |
+
<div class="grid-3" style="margin-bottom:24px">
|
| 173 |
+
<div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-a)">3.90×</div><div class="metric-highlight-label">Brand2/Pfizer — SEG_A</div></div>
|
| 174 |
+
<div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-b)">4.43×</div><div class="metric-highlight-label">Brand2/Pfizer — SEG_B</div></div>
|
| 175 |
+
<div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-c)">4.29×</div><div class="metric-highlight-label">Brand2/Pfizer — SEG_C</div></div>
|
| 176 |
+
</div>
|
| 177 |
+
|
| 178 |
+
<div class="alert-box alert-warning"><i class="fas fa-exclamation-triangle"></i><span><strong>Competitive Pressure:</strong> Brand2 outprescribes Pfizer by 3.9–4.4× across all segments. The gap is widest in SEG_B (4.43×), the very segment with the highest Pfizer growth trajectory — indicating an active battleground for share.</span></div>
|
| 179 |
+
|
| 180 |
+
<div class="grid-2" style="margin-top:24px">
|
| 181 |
+
<div class="card"><div class="chart-title">Pfizer vs Brand2: Market Share of UC (%) by Segment</div><div class="chart-container" style="height:300px"><canvas id="chart-comp-share"></canvas></div></div>
|
| 182 |
+
<div class="card"><div class="chart-title">Brand2/Pfizer Prescribing Ratio by Segment</div><div class="chart-container" style="height:300px"><canvas id="chart-comp-ratio"></canvas></div></div>
|
| 183 |
+
</div>
|
| 184 |
+
|
| 185 |
+
<div class="card" style="margin-top:24px"><div class="chart-title">UC TRx Volume vs Pfizer Market Share (Labeled HCPs)</div><div class="chart-container" style="height:420px"><canvas id="chart-scatter-uc"></canvas></div></div>
|
| 186 |
+
</div>
|
| 187 |
+
|
| 188 |
+
<!-- ==================== TAB 5: REP ENGAGEMENT ==================== -->
|
| 189 |
+
<div id="tab-engagement" class="tab-content">
|
| 190 |
+
<div class="section-header"><div class="section-icon"><i class="fas fa-handshake"></i></div><div><div class="section-title">Rep Engagement ROI</div><div class="section-subtitle">Measuring commercial efficiency: visits, channels, and prescribing impact</div></div></div>
|
| 191 |
+
|
| 192 |
+
<div class="grid-4" style="margin-bottom:24px">
|
| 193 |
+
<div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-a)">0.94</div><div class="metric-highlight-label">Details/Rx — SEG_A</div></div>
|
| 194 |
+
<div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-b)">0.44</div><div class="metric-highlight-label">Details/Rx — SEG_B</div></div>
|
| 195 |
+
<div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-c)">0.38</div><div class="metric-highlight-label">Details/Rx — SEG_C</div></div>
|
| 196 |
+
<div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--accent-green)">2.1×</div><div class="metric-highlight-label">SEG_B is 2.1× more efficient than SEG_A</div></div>
|
| 197 |
+
</div>
|
| 198 |
+
|
| 199 |
+
<div class="grid-2">
|
| 200 |
+
<div class="card"><div class="chart-title">Engagement Metrics by Segment</div><div class="chart-container" style="height:300px"><canvas id="chart-engagement"></canvas></div></div>
|
| 201 |
+
<div class="card"><div class="chart-title">Rep Visits vs Pfizer Prescribing (Scatter)</div><div class="chart-container" style="height:300px"><canvas id="chart-scatter-eng"></canvas></div></div>
|
| 202 |
+
</div>
|
| 203 |
+
</div>
|
| 204 |
+
|
| 205 |
+
<!-- ==================== TAB 6: UNLABELED OPPORTUNITY ==================== -->
|
| 206 |
+
<div id="tab-opportunity" class="tab-content">
|
| 207 |
+
<div class="section-header"><div class="section-icon"><i class="fas fa-crosshairs"></i></div><div><div class="section-title">Unlabeled HCP Opportunity</div><div class="section-subtitle">Prioritizing 9,032 unclassified HCPs for commercial outreach</div></div></div>
|
| 208 |
+
|
| 209 |
+
<div class="grid-3" style="margin-bottom:24px">
|
| 210 |
+
<div class="card tier-card tier-1"><div class="tier-value" style="color:var(--accent-green)">1,600</div><div class="tier-label">Tier 1 — Immediate</div><div class="tier-desc">Score ≥ 0.60. Highest prescribing + growth signals.</div></div>
|
| 211 |
+
<div class="card tier-card tier-2"><div class="tier-value" style="color:var(--accent-amber)">5,643</div><div class="tier-label">Tier 2 — Validate</div><div class="tier-desc">Score 0.35–0.60. Moderate opportunity, needs validation.</div></div>
|
| 212 |
+
<div class="card tier-card tier-3"><div class="tier-value" style="color:var(--text-muted)">1,789</div><div class="tier-label">Tier 3 — Monitor</div><div class="tier-desc">Score < 0.35. Low activity, monitor for emergence.</div></div>
|
| 213 |
+
</div>
|
| 214 |
+
|
| 215 |
+
<div class="alert-box alert-warning"><i class="fas fa-exclamation-triangle"></i><span><strong>Coverage Gap:</strong> 5,733 of 9,032 unlabeled HCPs (63.5%) have zero rep visits. Among Tier 1 (high-opportunity) HCPs, many prescribe actively but have never been contacted by a sales representative.</span></div>
|
| 216 |
+
|
| 217 |
+
<div class="grid-2" style="margin-top:24px">
|
| 218 |
+
<div class="card"><div class="chart-title">Opportunity Score Distribution (9,032 Unlabeled HCPs)</div><div class="chart-container" style="height:300px"><canvas id="chart-opp-hist"></canvas></div></div>
|
| 219 |
+
<div class="card"><div class="chart-title">Click a red point to identify the HCP below ↓</div><div class="chart-container" style="height:300px"><canvas id="chart-opp-scatter"></canvas></div></div>
|
| 220 |
+
</div>
|
| 221 |
+
|
| 222 |
+
<!-- HCP Detail Panel (populated on click) -->
|
| 223 |
+
<div id="hcp-detail-panel" class="card" style="margin-top:24px;display:none;border-left:4px solid var(--accent-coral)">
|
| 224 |
+
<div class="section-header" style="margin-bottom:16px"><div class="section-icon" style="background:#fef2f2;color:var(--accent-coral)"><i class="fas fa-user-md"></i></div><div><div class="section-title" id="hcp-detail-title">HCP Selected</div><div class="section-subtitle">Zero rep visits — high opportunity for outreach</div></div></div>
|
| 225 |
+
<div class="grid-5" id="hcp-detail-grid"></div>
|
| 226 |
+
<div class="alert-box alert-warning" style="margin-top:16px"><i class="fas fa-bullhorn"></i><span><strong>Action Required:</strong> This HCP has never been visited by a sales representative yet shows significant UC prescribing activity. Recommend scheduling an initial detail call.</span></div>
|
| 227 |
+
</div>
|
| 228 |
+
</div>
|
| 229 |
+
|
| 230 |
+
<!-- ==================== TAB 7: SPECIALTY MIX ==================== -->
|
| 231 |
+
<div id="tab-specialty" class="tab-content">
|
| 232 |
+
<div class="section-header"><div class="section-icon"><i class="fas fa-stethoscope"></i></div><div><div class="section-title">Specialty & Demographics</div><div class="section-subtitle">HCP specialty distribution across segments</div></div></div>
|
| 233 |
+
|
| 234 |
+
<div class="grid-2">
|
| 235 |
+
<div class="card"><div class="chart-title">HCPs by Specialty and Segment (Stacked)</div><div class="chart-container" style="height:300px"><canvas id="chart-spec-stack"></canvas></div></div>
|
| 236 |
+
<div class="card"><div class="chart-title">Specialty Composition (% within each specialty)</div><div class="chart-container" style="height:300px"><canvas id="chart-spec-pct"></canvas></div></div>
|
| 237 |
+
</div>
|
| 238 |
+
</div>
|
| 239 |
+
|
| 240 |
+
|
| 241 |
+
|
| 242 |
+
<script src="app.js"></script>
|
| 243 |
+
</body>
|
| 244 |
+
</html>
|
opportunity_data.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
styles.css
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* ============================================================
|
| 2 |
+
HCP Segmentation Dashboard V2 — Premium Business Theme
|
| 3 |
+
============================================================ */
|
| 4 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
|
| 5 |
+
|
| 6 |
+
:root {
|
| 7 |
+
--pfizer-deep: #0d009d;
|
| 8 |
+
--pfizer-blue: #0051a5;
|
| 9 |
+
--pfizer-light: #00a3e0;
|
| 10 |
+
--pfizer-sky: #54c8e8;
|
| 11 |
+
|
| 12 |
+
--seg-a: #6B7280;
|
| 13 |
+
--seg-b: #1A6FD4;
|
| 14 |
+
--seg-c: #D4720A;
|
| 15 |
+
--seg-unlabeled: #7C3AED;
|
| 16 |
+
|
| 17 |
+
--bg-body: #f0f2f5;
|
| 18 |
+
--bg-card: #ffffff;
|
| 19 |
+
--bg-active: #eef6fc;
|
| 20 |
+
|
| 21 |
+
--text-primary: #1e293b;
|
| 22 |
+
--text-secondary: #64748b;
|
| 23 |
+
--text-muted: #94a3b8;
|
| 24 |
+
|
| 25 |
+
--border-subtle: #e2e8f0;
|
| 26 |
+
--border-card: #e5e7eb;
|
| 27 |
+
|
| 28 |
+
--accent-green: #0D9E6E;
|
| 29 |
+
--accent-amber: #d97706;
|
| 30 |
+
--accent-coral: #DC3545;
|
| 31 |
+
|
| 32 |
+
--shadow-card: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
|
| 33 |
+
--shadow-card-hover: 0 8px 24px rgba(0,0,0,0.08);
|
| 34 |
+
--shadow-header: 0 1px 8px rgba(0,0,0,0.04);
|
| 35 |
+
--radius-sm: 8px;
|
| 36 |
+
--radius-md: 12px;
|
| 37 |
+
--radius-lg: 16px;
|
| 38 |
+
--radius-xl: 20px;
|
| 39 |
+
--transition-base: 0.25s cubic-bezier(0.4,0,0.2,1);
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
| 43 |
+
html{scroll-behavior:smooth}
|
| 44 |
+
body{font-family:'Inter',sans-serif;background:var(--bg-body);color:var(--text-primary);line-height:1.6;min-height:100vh}
|
| 45 |
+
|
| 46 |
+
/* ---- Top Header ---- */
|
| 47 |
+
.top-header{background:var(--bg-card);border-bottom:1px solid var(--border-subtle);padding:14px 32px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100;box-shadow:var(--shadow-header)}
|
| 48 |
+
.top-header-left{display:flex;align-items:center;gap:20px}
|
| 49 |
+
.top-header-left img{height:32px;width:auto}
|
| 50 |
+
.top-header-left h1{font-size:18px;font-weight:700;color:var(--pfizer-deep);border-left:1px solid var(--border-subtle);padding-left:20px}
|
| 51 |
+
.top-header-left span{font-size:13px;color:var(--text-secondary);margin-left:8px}
|
| 52 |
+
.header-badge{padding:6px 16px;border-radius:20px;font-size:12px;font-weight:600;background:#ecfdf5;color:var(--accent-green);border:1px solid #a7f3d0}
|
| 53 |
+
|
| 54 |
+
/* ---- Tab Navigation ---- */
|
| 55 |
+
.tab-nav{background:var(--bg-card);border-bottom:1px solid var(--border-subtle);padding:0 32px;display:flex;gap:0;overflow-x:auto;-webkit-overflow-scrolling:touch}
|
| 56 |
+
.tab-nav::-webkit-scrollbar{height:0}
|
| 57 |
+
.tab-btn{padding:14px 20px;font-size:13px;font-weight:600;color:var(--text-secondary);cursor:pointer;border:none;background:none;border-bottom:2px solid transparent;transition:var(--transition-base);white-space:nowrap;display:flex;align-items:center;gap:8px}
|
| 58 |
+
.tab-btn:hover{color:var(--pfizer-blue);background:var(--bg-active)}
|
| 59 |
+
.tab-btn.active{color:var(--pfizer-blue);border-bottom-color:var(--pfizer-blue);background:var(--bg-active)}
|
| 60 |
+
|
| 61 |
+
/* ---- Tab Content ---- */
|
| 62 |
+
.tab-content{display:none;padding:32px;max-width:1440px;margin:0 auto;animation:fadeIn 0.35s ease}
|
| 63 |
+
.tab-content.active{display:block}
|
| 64 |
+
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
|
| 65 |
+
|
| 66 |
+
/* ---- Section ---- */
|
| 67 |
+
.section-header{display:flex;align-items:center;gap:16px;margin-bottom:24px}
|
| 68 |
+
.section-icon{width:40px;height:40px;border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;font-size:16px;background:rgba(0,81,165,0.08);color:var(--pfizer-blue)}
|
| 69 |
+
.section-title{font-size:20px;font-weight:700;color:var(--text-primary);letter-spacing:-0.3px}
|
| 70 |
+
.section-subtitle{font-size:14px;color:var(--text-secondary);margin-top:2px}
|
| 71 |
+
|
| 72 |
+
/* ---- Grids ---- */
|
| 73 |
+
.grid-2{display:grid;grid-template-columns:repeat(2,1fr);gap:24px}
|
| 74 |
+
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
|
| 75 |
+
.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
|
| 76 |
+
.grid-5{display:grid;grid-template-columns:repeat(5,1fr);gap:20px}
|
| 77 |
+
.grid-2-1{display:grid;grid-template-columns:2fr 1fr;gap:24px}
|
| 78 |
+
|
| 79 |
+
/* ---- Card ---- */
|
| 80 |
+
.card{background:var(--bg-card);border:1px solid var(--border-card);border-radius:var(--radius-lg);padding:24px;box-shadow:var(--shadow-card);transition:var(--transition-base)}
|
| 81 |
+
.card:hover{box-shadow:var(--shadow-card-hover)}
|
| 82 |
+
|
| 83 |
+
/* ---- KPI Card ---- */
|
| 84 |
+
.kpi-card{display:flex;flex-direction:column;gap:8px}
|
| 85 |
+
.kpi-top{display:flex;align-items:center;justify-content:space-between}
|
| 86 |
+
.kpi-label{font-size:11px;color:var(--text-secondary);font-weight:600;text-transform:uppercase;letter-spacing:0.5px}
|
| 87 |
+
.kpi-icon{width:36px;height:36px;border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;font-size:14px}
|
| 88 |
+
.kpi-value{font-size:32px;font-weight:800;letter-spacing:-1px;color:var(--pfizer-deep);line-height:1.2}
|
| 89 |
+
.kpi-sub{font-size:13px;color:var(--text-muted);font-weight:500}
|
| 90 |
+
|
| 91 |
+
/* ---- Segment Card ---- */
|
| 92 |
+
.segment-card{position:relative;overflow:hidden}
|
| 93 |
+
.segment-card::before{content:'';position:absolute;top:0;left:0;width:4px;height:100%;border-radius:4px 0 0 4px}
|
| 94 |
+
.seg-a .segment-card::before,.seg-a.segment-card::before{background:var(--seg-a)}
|
| 95 |
+
.seg-b .segment-card::before,.seg-b.segment-card::before{background:var(--seg-b)}
|
| 96 |
+
.seg-c .segment-card::before,.seg-c.segment-card::before{background:var(--seg-c)}
|
| 97 |
+
.segment-name{font-size:18px;font-weight:700;margin-bottom:6px}
|
| 98 |
+
.segment-desc{font-size:14px;color:var(--text-secondary);line-height:1.6;margin-bottom:20px;min-height:66px}
|
| 99 |
+
.segment-stats{display:flex;flex-direction:column;gap:12px}
|
| 100 |
+
.segment-stat{display:flex;justify-content:space-between;align-items:center}
|
| 101 |
+
.segment-stat-label{font-size:13px;color:var(--text-secondary);font-weight:500}
|
| 102 |
+
.segment-stat-value{font-size:14px;font-weight:700}
|
| 103 |
+
.segment-meter{width:100%;height:6px;background:#f1f5f9;border-radius:3px;margin-top:4px;overflow:hidden}
|
| 104 |
+
.segment-meter-fill{height:100%;border-radius:3px;transition:width 1s ease}
|
| 105 |
+
|
| 106 |
+
/* ---- Plotly Container ---- */
|
| 107 |
+
.plotly-chart{width:100%;min-height:340px;border-radius:var(--radius-md);overflow:hidden}
|
| 108 |
+
.plotly-chart-sm{width:100%;min-height:280px}
|
| 109 |
+
.chart-title{font-size:16px;font-weight:700;margin-bottom:16px;color:var(--text-primary);letter-spacing:-0.2px}
|
| 110 |
+
.chart-container{position:relative;width:100%}
|
| 111 |
+
.chart-container canvas{width:100%!important}
|
| 112 |
+
|
| 113 |
+
/* ---- Persona ---- */
|
| 114 |
+
.persona-card{padding:32px}
|
| 115 |
+
.persona-header{display:flex;align-items:center;gap:20px;margin-bottom:24px}
|
| 116 |
+
.persona-avatar{width:64px;height:64px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:22px;font-weight:700;color:#fff;flex-shrink:0}
|
| 117 |
+
.persona-name{font-size:20px;font-weight:700;color:var(--text-primary)}
|
| 118 |
+
.persona-role{font-size:14px;color:var(--text-secondary);margin-top:2px}
|
| 119 |
+
.persona-seg{font-size:13px;font-weight:600;margin-top:4px}
|
| 120 |
+
.persona-detail-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:24px}
|
| 121 |
+
.persona-metric{background:#f8fafc;padding:16px;border-radius:var(--radius-md);border:1px solid #f1f5f9}
|
| 122 |
+
.persona-metric-label{font-size:12px;color:var(--text-muted);text-transform:uppercase;font-weight:600;letter-spacing:0.5px}
|
| 123 |
+
.persona-metric-value{font-size:22px;font-weight:800;color:var(--pfizer-deep);margin-top:4px;letter-spacing:-0.5px}
|
| 124 |
+
|
| 125 |
+
/* ---- Badge ---- */
|
| 126 |
+
.badge{display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:20px;font-size:12px;font-weight:600}
|
| 127 |
+
.badge-green{background:#ecfdf5;color:var(--accent-green)}
|
| 128 |
+
.badge-amber{background:#fffbeb;color:var(--accent-amber)}
|
| 129 |
+
.badge-red{background:#fef2f2;color:var(--accent-coral)}
|
| 130 |
+
.badge-blue{background:#eff6ff;color:var(--pfizer-blue)}
|
| 131 |
+
.badge-sky{background:#f0f9ff;color:var(--pfizer-light)}
|
| 132 |
+
.badge-purple{background:#f5f3ff;color:var(--seg-unlabeled)}
|
| 133 |
+
|
| 134 |
+
/* ---- Alert ---- */
|
| 135 |
+
.alert-box{padding:16px 20px;border-radius:var(--radius-md);font-size:14px;line-height:1.6;display:flex;align-items:flex-start;gap:12px;margin-top:20px}
|
| 136 |
+
.alert-box i{margin-top:3px;font-size:16px}
|
| 137 |
+
.alert-info{background:#eff6ff;border:1px solid #bfdbfe;color:var(--pfizer-blue)}
|
| 138 |
+
.alert-warning{background:#fffbeb;border:1px solid #fde68a;color:var(--accent-amber)}
|
| 139 |
+
.alert-success{background:#ecfdf5;border:1px solid #a7f3d0;color:var(--accent-green)}
|
| 140 |
+
|
| 141 |
+
/* ---- Insight Card ---- */
|
| 142 |
+
.insight-card{border-left:4px solid var(--pfizer-light)}
|
| 143 |
+
.insight-number{font-size:40px;font-weight:900;color:var(--pfizer-sky);opacity:0.25;line-height:1;margin-bottom:8px}
|
| 144 |
+
.insight-title{font-size:16px;font-weight:700;margin-bottom:8px;color:var(--text-primary)}
|
| 145 |
+
.insight-text{font-size:14px;color:var(--text-secondary);line-height:1.6}
|
| 146 |
+
|
| 147 |
+
/* ---- Opportunity Tier Cards ---- */
|
| 148 |
+
.tier-card{border-left:4px solid transparent;padding:20px 24px}
|
| 149 |
+
.tier-card.tier-1{border-left-color:var(--accent-green)}
|
| 150 |
+
.tier-card.tier-2{border-left-color:var(--accent-amber)}
|
| 151 |
+
.tier-card.tier-3{border-left-color:var(--text-muted)}
|
| 152 |
+
.tier-value{font-size:28px;font-weight:800;letter-spacing:-0.5px;line-height:1.2}
|
| 153 |
+
.tier-label{font-size:13px;color:var(--text-secondary);font-weight:600;margin-top:2px}
|
| 154 |
+
.tier-desc{font-size:12px;color:var(--text-muted);margin-top:6px}
|
| 155 |
+
|
| 156 |
+
/* ---- Metric Highlight ---- */
|
| 157 |
+
.metric-highlight{text-align:center;padding:20px;background:#f8fafc;border-radius:var(--radius-md);border:1px solid #f1f5f9}
|
| 158 |
+
.metric-highlight-value{font-size:28px;font-weight:800;color:var(--pfizer-deep);letter-spacing:-0.5px}
|
| 159 |
+
.metric-highlight-label{font-size:12px;color:var(--text-muted);font-weight:600;text-transform:uppercase;letter-spacing:0.5px;margin-top:4px}
|
| 160 |
+
|
| 161 |
+
/* ---- Sub-tabs ---- */
|
| 162 |
+
.sub-tabs{display:flex;gap:12px;margin-bottom:24px;flex-wrap:wrap}
|
| 163 |
+
.sub-tab{padding:10px 24px;border-radius:24px;font-size:14px;font-weight:600;cursor:pointer;border:1px solid var(--border-card);background:var(--bg-card);color:var(--text-secondary);transition:var(--transition-base)}
|
| 164 |
+
.sub-tab:hover{border-color:var(--pfizer-blue);color:var(--pfizer-blue)}
|
| 165 |
+
.sub-tab.active{background:var(--pfizer-deep);color:#fff;border-color:var(--pfizer-deep)}
|
| 166 |
+
.sub-panel{display:none}
|
| 167 |
+
.sub-panel.active{display:block;animation:fadeIn 0.3s ease}
|
| 168 |
+
|
| 169 |
+
/* ---- Data Table ---- */
|
| 170 |
+
.data-table{width:100%;border-collapse:collapse;font-size:14px}
|
| 171 |
+
.data-table thead th{text-align:left;padding:12px 16px;font-weight:600;color:var(--text-secondary);font-size:12px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid var(--border-subtle);background:#f8fafc}
|
| 172 |
+
.data-table tbody td{padding:12px 16px;border-bottom:1px solid var(--border-subtle)}
|
| 173 |
+
.data-table tbody tr:hover{background:#f8fafc}
|
| 174 |
+
|
| 175 |
+
/* ---- Coverage Gap Badge ---- */
|
| 176 |
+
.coverage-gap{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;border-radius:var(--radius-sm);font-size:13px;font-weight:600;background:#fef2f2;color:var(--accent-coral);border:1px solid #fecaca}
|
| 177 |
+
|
| 178 |
+
/* ---- Responsive ---- */
|
| 179 |
+
@media(max-width:1200px){.grid-5{grid-template-columns:repeat(3,1fr)}.grid-4{grid-template-columns:repeat(2,1fr)}}
|
| 180 |
+
@media(max-width:900px){.grid-3,.grid-2,.grid-2-1{grid-template-columns:1fr}}
|
| 181 |
+
@media(max-width:600px){.grid-5,.grid-4{grid-template-columns:1fr}.tab-btn{padding:12px 14px;font-size:12px}}
|