Marcel0123 commited on
Commit
436b7b6
·
verified ·
1 Parent(s): a86b87b

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +26 -21
index.html CHANGED
@@ -181,6 +181,11 @@
181
  .source-issue-detail{font-size:10px;color:#adbfdb;line-height:1.5;margin:4px 0 0}
182
  .source-audit-ok{font-size:10px;color:#71e8be;line-height:1.5}
183
  @media(max-width:1080px){header{grid-template-columns:1fr;justify-items:start}.header-center-logo{justify-content:flex-start;padding:4px 0 0}.header-center-logo img{height:60px}.header-actions{justify-self:start}}
 
 
 
 
 
184
  </style></head>
185
  <body>
186
  <div class="app">
@@ -246,7 +251,7 @@
246
  </main>
247
  </div>
248
  <div id="reportOverlay" role="dialog" aria-modal="true" aria-label="Reakt Monitor rapport" aria-hidden="true">
249
- <div class="report-actions"><span><strong>REAKT · Rapportvoorvertoning v1.6.2</strong> &nbsp; — voorlopige managementrapportage, controle vereist</span><div><button id="reportClose" type="button">✕ Sluiten</button> <button id="reportPng" class="report-png" type="button">⬇ Download PNG</button> <button id="reportJpg" class="report-jpg" type="button">⬇ Download JPG</button> <button id="reportPrint" class="report-print" type="button">↓ Opslaan als PDF / Afdrukken</button></div></div>
250
  <section id="reportSheet" aria-label="Witte Inloop Monitor"></section>
251
  </div>
252
  <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
@@ -911,43 +916,43 @@ function getReportData(){
911
  const result=importedData.last,site=result.site,period=result.period;
912
  const history=importedData.all.filter(r=>(site==='*'||r.site===site)&&r.date<=period.peildatum);
913
  const quarter=history.filter(r=>r.date>=period.begin);
914
- const counts=new Map(),uniqueDates=new Set(),byMonth=new Map(period.months.map(m=>[m,0])),byWeek=[0,0,0,0,0,0,0];
915
  for(const r of quarter){
916
  const key=JSON.stringify([r.site,r.id,r.date]);if(uniqueDates.has(key))continue;
917
  uniqueDates.add(key);
918
  const mk=r.date.slice(0,7);byMonth.set(mk,(byMonth.get(mk)||0)+1);
919
  const wk=new Date(r.date+'T12:00:00Z').getUTCDay();byWeek[(wk+6)%7]++;
920
  const ck=JSON.stringify([r.site,r.id]);counts.set(ck,(counts.get(ck)||0)+1);
 
 
921
  }
922
  const intensities=[0,0,0,0,0],daysPerClient=[...counts.values()];
923
  daysPerClient.forEach(c=>{intensities[c<=5?0:c<=20?1:c<=50?2:c<=100?3:4]++});
924
  const sorted=daysPerClient.sort((a,b)=>a-b),median=sorted.length?(sorted.length%2?sorted[(sorted.length-1)/2]:(sorted[sorted.length/2-1]+sorted[sorted.length/2])/2):0;
925
  const monthLabels=['jan','feb','mrt','apr','mei','jun','jul','aug','sep','okt','nov','dec'];
926
- const months=period.months.map(key=>({key,label:monthLabels[Number(key.slice(5))-1],visits:byMonth.get(key),newIntake:result.instroomByMonth.get(key)||0}));
927
  return {site:site==='*'?'Alle locaties':site,period,months,byWeek,intensities,
928
  visits:uniqueDates.size,unique:result.unique,quarterClients:result.quarterClients,newIntake:result.newIntake,active:result.active,
929
- average:counts.size?uniqueDates.size/counts.size:0,median,maxDays:Math.max(0,...daysPerClient),
930
  earliest:period.begin,latest:period.peildatum,issues:result.passConflicts+result.identityConflicts+result.unmatchedPasses,hasShadow:false,
931
  historyLoaded:result.historyLoaded,correctedExisting:result.correctedExisting,correctedJanuary:result.correctedJanuary};
932
  }
933
  function buildWhiteReport(){
934
  const d=getReportData();if(!d)return;
935
  const range=d.earliest===d.latest?d.earliest:`${d.earliest} t/m ${d.latest}`;
936
- const avg=d.average.toLocaleString('nl-NL',{minimumFractionDigits:1,maximumFractionDigits:1});
937
  const activeWindow=readableDate(d.period.activeFrom)+' t/m '+readableDate(d.period.peildatum);
938
- const mon=d.months.map(m=>m.label),values=d.months.map(m=>m.visits),newPerMonth=d.months.map(m=>m.newIntake),week=['Ma','Di','Wo','Do','Vr','Za','Zo'];
939
  const weekdayMax=Math.max(...d.byWeek),weekdayMin=Math.min(...d.byWeek),busiest=week[d.byWeek.indexOf(weekdayMax)],quietest=week[d.byWeek.indexOf(weekdayMin)];
940
- const summary=[`In ${d.period.label} zijn bij ${escapeHTML(d.site)} ${reportNL(d.unique)} unieke cliënten met minimaal één geldige scan geregistreerd. Deze cliënten waren samen goed voor ${reportNL(d.visits)} unieke bezoekdagen.`,
941
- `De instroom in ${d.period.label} bedraagt ${reportNL(d.newIntake)} cliënten. Er zijn ${reportNL(d.active)} actieve cliënten met minimaal één scan van ${activeWindow}.`,
942
- `De bezoekintensiteit bedraagt gemiddeld ${avg} unieke dagen per bezoeker in de rapportageperiode (mediaan ${String(d.median).replace('.',',')}). Meeste bezoekdagen: ${busiest} (${reportNL(weekdayMax)}).`,
943
- `Instroom is gebaseerd op de eerste geldige scan in ${d.historyLoaded?'2025 en 2026':'alleen 2026'}, niet op pasuitgifte. ${d.historyLoaded?reportNL(d.correctedExisting)+' aanvankelijke instromers bleken al in 2025 bezoeker.':'Historie 2025 ontbreekt; instroom voorlopig.'} Eerdere bezoeken vóór 2025 kunnen ontbreken. Businesscontrollerverificatie is optioneel.`];
944
- const kpis=[{klass:'purple',icon:'♟',label:'Unieke cliënten',value:reportNL(d.unique),sub:'Min. één geldige scan in rapportageperiode'},
945
  {klass:'green',icon:'+',label:'Nieuwe instroom',value:reportNL(d.newIntake),sub:'Eerste geldige scan op locatie in '+d.period.label},
946
- {klass:'purple',icon:'♙',label:'Actieve cliënten',value:reportNL(d.active),sub:'Min. 1 scan in 3 maanden t/m peildatum'},
947
- {klass:'orange',icon:'▦',label:'Unieke bezoekdagen',value:reportNL(d.visits),sub:'Eén cliëntnummer per locatie per kalenderdag'}];
948
  const kpiHTML=kpis.map(k=>`<div class="report-kpi ${k.klass}"><div class="k-icon">${k.icon}</div><div><div class="k-label">${k.label}</div><div class="k-num">${k.value}</div><div class="k-sub">${k.sub}</div></div><div class="k-underline"></div></div>`).join('');
949
- const maxI=Math.max(1,...d.intensities),ilabels=['1 – 5 dagen','6 – 20 dagen','21 – 50 dagen','51 – 100 dagen','101 dagen of meer'];
950
- const itHTML=d.intensities.map((c,i)=>`<div class="report-intensity-row"><span class="int-label">${ilabels[i]}</span><div class="int-bar-track"><div class="int-bar" style="width:${c/maxI*100}%"></div></div><strong>${c}</strong></div>`).join('');
951
  $('reportSheet').innerHTML=`
952
  <div class="report-brand"><img class="report-logo" src="data:image/png;base64,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" alt="Reakt PG logo"></div>
953
  <div class="report-heading"><div><h1>Reakt Inloop Monitor ${escapeHTML(d.site)}</h1><p>Inzicht in bereik, betrokkenheid en bezoekpatronen</p></div>
@@ -960,19 +965,19 @@ function buildWhiteReport(){
960
  <div><b>Nieuwe instroom</b>De eerste geldige scan van een cliënt op deze locatie (binnen de beschikbare historie) valt in de rapportageperiode.</div>
961
  <div><b>Actieve cliënten</b>Minimaal één scan op deze locatie tussen ${escapeHTML(activeWindow)}.</div>
962
  </div>
963
- <div class="report-definitions-note">Een vervangende scanpas telt niet als nieuwe cliënt; onware scans (Resultaat=0) worden uitgesloten. Historie: ${d.historyLoaded?'2025 + 2026 gekoppeld; '+reportNL(d.correctedExisting)+' eerdere bezoekers niet opnieuw als instroom gerekend.':'alleen 2026 — instroom voorlopig.'}</div>
964
  </section>
965
  <div class="report-chart-grid">
966
- <section class="report-panel"><h2>Instroom per maand <small>(nieuwe deelnemers)</small></h2><div class="chart-box">${reportChartBars(mon,newPerMonth,'#288e28')}</div></section>
967
- <section class="report-panel"><h2>Unieke bezoekdagen per maand</h2><div class="chart-box">${reportChartLine(mon,values)}</div></section>
968
  <section class="report-panel"><h2>Bezoekdagen per weekdag</h2><div class="chart-box">${reportChartBars(week,d.byWeek,'#ff6410',true)}</div></section>
969
  </div>
970
  <div class="report-bottom-grid">
971
- <section class="report-panel"><h2>Kerncijfers locatie</h2><table class="report-mini-table"><thead><tr><th>Locatie</th><th>Unieke cliënten</th><th>Unieke bezoekdagen</th><th>Gem. dagen / bezoeker (periode)</th></tr></thead><tbody><tr><td>⌖ ${escapeHTML(d.site)}</td><td>${reportNL(d.unique)}</td><td>${reportNL(d.visits)}</td><td>${avg}</td></tr><tr class="total"><td>Totaal / gemiddelde</td><td>${reportNL(d.unique)}</td><td>${reportNL(d.visits)}</td><td>${avg}</td></tr></tbody></table></section>
972
- <section class="report-panel"><h2>Bezoekintensiteit <small>(unieke bezoekdagen per cliëntnummer)</small></h2>${itHTML}<div class="report-intensity-summary"><span>Gemiddeld<br><strong>${avg}</strong></span><span>Mediaan<br><strong>${String(d.median).replace('.',',')}</strong></span><span>Hoogste aantal dagen<br><strong>${d.maxDays}</strong></span></div></section>
973
  <section class="report-panel"><h2>Managementanalyse</h2><div class="report-analysis">${summary.map(t=>`<p>${t}</p>`).join('')}</div></section>
974
  </div>
975
- <div class="report-foot"><span>Bron: lokaal ingelezen scans 2026${d.historyLoaded?' + historisch referentiebestand 2025':''} · Instroom = eerste geldige scan sinds ${d.historyLoaded?'2025':'2026'} · Resultaat=0 uitgesloten · Historie kan vóór 2025 onvolledig zijn</span><span class="report-provisional">NIET EXTERN GEVALIDEERD · CONTROLEER VÓÓR PUBLICATIE</span></div>`;
976
  }
977
  function openWhiteReport(){
978
  if(!importedData?.last){alert('Upload eerst een Excelbestand en rond de analyse af. Deze witte rapportage gebruikt geen verzonnen demo-KPI’s.');return;}
 
181
  .source-issue-detail{font-size:10px;color:#adbfdb;line-height:1.5;margin:4px 0 0}
182
  .source-audit-ok{font-size:10px;color:#71e8be;line-height:1.5}
183
  @media(max-width:1080px){header{grid-template-columns:1fr;justify-items:start}.header-center-logo{justify-content:flex-start;padding:4px 0 0}.header-center-logo img{height:60px}.header-actions{justify-self:start}}
184
+ /* v1.6.3: alleen de witte managementrapportage, bestaande dashboard-huisstijl onveranderd */
185
+ #reportSheet .report-average-note{margin-top:8px;font-size:9px;color:#68739a;line-height:1.25}
186
+ #reportSheet .report-client-month-chart{height:157px;max-width:100%;min-width:0}
187
+ #reportSheet .report-client-month-chart svg{display:block;max-width:100%;height:100%}
188
+ @media print{#reportSheet .report-average-note{font-size:8px!important;margin-top:5px!important}#reportSheet .report-client-month-chart{height:133px!important}}
189
  </style></head>
190
  <body>
191
  <div class="app">
 
251
  </main>
252
  </div>
253
  <div id="reportOverlay" role="dialog" aria-modal="true" aria-label="Reakt Monitor rapport" aria-hidden="true">
254
+ <div class="report-actions"><span><strong>REAKT · Rapportvoorvertoning v1.6.3</strong> &nbsp; — voorlopige managementrapportage, controle vereist</span><div><button id="reportClose" type="button">✕ Sluiten</button> <button id="reportPng" class="report-png" type="button">⬇ Download PNG</button> <button id="reportJpg" class="report-jpg" type="button">⬇ Download JPG</button> <button id="reportPrint" class="report-print" type="button">↓ Opslaan als PDF / Afdrukken</button></div></div>
255
  <section id="reportSheet" aria-label="Witte Inloop Monitor"></section>
256
  </div>
257
  <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
 
916
  const result=importedData.last,site=result.site,period=result.period;
917
  const history=importedData.all.filter(r=>(site==='*'||r.site===site)&&r.date<=period.peildatum);
918
  const quarter=history.filter(r=>r.date>=period.begin);
919
+ const counts=new Map(),uniqueDates=new Set(),byMonth=new Map(period.months.map(m=>[m,0])),clientsByMonth=new Map(period.months.map(m=>[m,new Set()])),daysWithScans=new Set(),byWeek=[0,0,0,0,0,0,0];
920
  for(const r of quarter){
921
  const key=JSON.stringify([r.site,r.id,r.date]);if(uniqueDates.has(key))continue;
922
  uniqueDates.add(key);
923
  const mk=r.date.slice(0,7);byMonth.set(mk,(byMonth.get(mk)||0)+1);
924
  const wk=new Date(r.date+'T12:00:00Z').getUTCDay();byWeek[(wk+6)%7]++;
925
  const ck=JSON.stringify([r.site,r.id]);counts.set(ck,(counts.get(ck)||0)+1);
926
+ clientsByMonth.get(mk)?.add(ck);
927
+ daysWithScans.add(r.date);
928
  }
929
  const intensities=[0,0,0,0,0],daysPerClient=[...counts.values()];
930
  daysPerClient.forEach(c=>{intensities[c<=5?0:c<=20?1:c<=50?2:c<=100?3:4]++});
931
  const sorted=daysPerClient.sort((a,b)=>a-b),median=sorted.length?(sorted.length%2?sorted[(sorted.length-1)/2]:(sorted[sorted.length/2-1]+sorted[sorted.length/2])/2):0;
932
  const monthLabels=['jan','feb','mrt','apr','mei','jun','jul','aug','sep','okt','nov','dec'];
933
+ const months=period.months.map(key=>({key,label:monthLabels[Number(key.slice(5))-1],visits:byMonth.get(key),clients:clientsByMonth.get(key)?.size||0,newIntake:result.instroomByMonth.get(key)||0}));
934
  return {site:site==='*'?'Alle locaties':site,period,months,byWeek,intensities,
935
  visits:uniqueDates.size,unique:result.unique,quarterClients:result.quarterClients,newIntake:result.newIntake,active:result.active,
936
+ average:counts.size?uniqueDates.size/counts.size:0,averageClientsPerDay:daysWithScans.size?uniqueDates.size/daysWithScans.size:0,daysWithScans:daysWithScans.size,median,maxDays:Math.max(0,...daysPerClient),
937
  earliest:period.begin,latest:period.peildatum,issues:result.passConflicts+result.identityConflicts+result.unmatchedPasses,hasShadow:false,
938
  historyLoaded:result.historyLoaded,correctedExisting:result.correctedExisting,correctedJanuary:result.correctedJanuary};
939
  }
940
  function buildWhiteReport(){
941
  const d=getReportData();if(!d)return;
942
  const range=d.earliest===d.latest?d.earliest:`${d.earliest} t/m ${d.latest}`;
943
+ const avgDay=d.averageClientsPerDay.toLocaleString('nl-NL',{minimumFractionDigits:1,maximumFractionDigits:1});
944
  const activeWindow=readableDate(d.period.activeFrom)+' t/m '+readableDate(d.period.peildatum);
945
+ const mon=d.months.map(m=>m.label),values=d.months.map(m=>m.visits),clientsPerMonth=d.months.map(m=>m.clients),newPerMonth=d.months.map(m=>m.newIntake),week=['Ma','Di','Wo','Do','Vr','Za','Zo'];
946
  const weekdayMax=Math.max(...d.byWeek),weekdayMin=Math.min(...d.byWeek),busiest=week[d.byWeek.indexOf(weekdayMax)],quietest=week[d.byWeek.indexOf(weekdayMin)];
947
+ const summary=[`In ${d.period.label} zijn bij ${escapeHTML(d.site)} ${reportNL(d.unique)} unieke cliënten met minimaal één geldige scan geregistreerd. Deze cliënten waren samen goed voor ${reportNL(d.visits)} bezoekdagen.`,
948
+ `De instroom in ${d.period.label} bedraagt ${reportNL(d.newIntake)} cliënten. Er zijn ${reportNL(d.active)} actieve cliënten met minimaal één scan in de afgelopen drie maanden (van ${activeWindow}).`,
949
+ `Op dagen met geregistreerde scans kwamen gemiddeld ${avgDay} cliënten per dag (${reportNL(d.daysWithScans)} geregistreerde dagen). De meeste bezoekdagen vallen op ${busiest} (${reportNL(weekdayMax)}).`,
950
+ `De instroom is gebaseerd op de eerste geldige scan in ${d.historyLoaded?'2025 en 2026':'alleen 2026'}, niet op pasuitgifte. ${d.historyLoaded?reportNL(d.correctedExisting)+' aanvankelijk nieuwe cliënten bleken al in 2025 geregistreerd.':'Historie 2025 ontbreekt; de instroom is voorlopig.'} Eerdere scans van vóór 2025 kunnen ontbreken.`];
951
+ const kpis=[{klass:'purple',icon:'♟',label:'Unieke cliënten',value:reportNL(d.unique),sub:''},
952
  {klass:'green',icon:'+',label:'Nieuwe instroom',value:reportNL(d.newIntake),sub:'Eerste geldige scan op locatie in '+d.period.label},
953
+ {klass:'purple',icon:'♙',label:'Actieve cliënten',value:reportNL(d.active),sub:'Minimaal 1 scan in de afgelopen drie maanden.'},
954
+ {klass:'orange',icon:'▦',label:'Bezoekdagen',value:reportNL(d.visits),sub:'Eén cliënt per locatie per kalenderdag'}];
955
  const kpiHTML=kpis.map(k=>`<div class="report-kpi ${k.klass}"><div class="k-icon">${k.icon}</div><div><div class="k-label">${k.label}</div><div class="k-num">${k.value}</div><div class="k-sub">${k.sub}</div></div><div class="k-underline"></div></div>`).join('');
 
 
956
  $('reportSheet').innerHTML=`
957
  <div class="report-brand"><img class="report-logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAADICAMAAADxy0fQAAABcVBMVEX////3Vgb//fz2Vwj4czD3WQr7pnv8tpP+/v/3XxP+7eT+8uv5ayP8uJX9v5/3Ww4ANZ/7mGf918X/+PUURafr7/j4ZBtjeN7/9fD5fkHxAFH6uAD4dzf4Zh0FtFz9w6b+4dL9yK7+5tr7kVz90Lr4bin6i1T90r38nnDrhQJ1ksv5f0L8rYX70Fr9y7P8sYv+8tH5hUv7lGG+zOfW3PcpwHMBMKICb4AvVb79z97+8PRndOYqm5EAuFL7xTH++ezg9ur506P2qwD97twwWrHe5PP8u9Cgs9sLPaNxhOKOnei9xvH8vtP4ZJX0JGr2RYD6krXUeLH2AEx1aMzbFWr5eaSIWbu8L4j1MnNhgMepte74b5z+5OyRoOnzEl3/cpWnTqekjtKKk+xes62NysR32qL+6bCM06Kzy5Cm5cXkvnVnoDT/uG7BjhJHp0LkiQr94pnzrVWjlyPukBfA7tjwnzf913P63rv7zEv95aH+67kv9Ud3AAAZ50lEQVR4nO1dj7/rtlW3/COp4yRebOqXFKd2nMRxSZY0YQVa2HstpaUbbC1jg22MBwy6QVugo+vW7q9HR/IPSZYT577cm3vv9P289iaOfn91jo6kI1nTFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRuBr0lrl1OHrdetpd4CD/q4pPr4J6RcpuotXfJQEXFLTVHPBieRDRbxD39FgtxLvhCz/zL5/DeHxN8i+C9l7WcCfjvrTfff//9N9/SbqU1dK2DWsENwsMgvp1CnAtd23FlC5wLZ/CS9tcffAPwZ08ovvPdv3kZHmM+/vZ733/+yiuvPH/+4UdvXThbABBiGS1Aam5Nur17QImudZlCW6h/aUK0l/7gGxwhwMlPQTre/PCVCs8/kui2FwQQkrf2CeCaQ7ggS65OCSWkLNjFCXlJe7lOyJMnP39P++gVHt+7uJAQQtopLVJ5C1Oy86/MCCGkKtPZhIw51OvSQMiT7/zdDwRCXvnw0oycSQilZJ1cl5EXJMSZmGEJM4xrlWki5Mnf/7DGyI8uVy2CswkB3YX6iwsX49xCvxAhPYurj9eekCf/IPJxHwjBYzuyt9eUkRclxEaMteKeQ8iTfwQRef7jH3//tgaRGxGCYwT1atwdXpwQBkcJ+Qmdh/z0O6yI/NObb731s/c/vA35uJnKIjKy7F28LGcU+q4I+aP8yXv/XDDywx98lBfiR8+ff/TCVamhFSGSAAY6XL4w7Qt9d4TkS1kvf7fQWf9C5x44zptvXqxGFXhCGqgxLEt4AP+uN4zcKSH5k2/lhPzrzy4+F+RQlxCrBvpYIMxAk9ss14lC3z0hL/+cEvJvTLDbYEYgxEDLVSzCizZ7F37jmDPQ4loicveE4Gc//3OCn9InVZQLL/7XCDHH0nBJ5oqShOYXLckZuAoh//4XBP9xkRo0o06IUysf3QHyQlFGLr7I2hbXIER749sEH5Mvv/tmhV+8cH1YyAiRhtM1ZyLqrGsN69cg5O03XiX4JXzxn/4hg3cvUKUSbQmBkElf0Fmb3yNCfkn5ePU/4cszjpDXL9kM7QkhzcCKiHV8KnLz/e6TEe9+Yqj9V87Hq59A6PtBiKY5S9byNdC6OdXj3xvj1YcvefIvQIh+FiFvE/z644KPTz+7R4To2ojdzDJQ2NBcACf2tlEUbb3YYZ4eLwr5v5N43mqx8ryk5zfEvKCEGECIiJKQP/nTNwheLfHf94uQIT+rNyUFgUfOYpOagUs74DRMNwtHO0UJ/Dr2BqO92bddC1muPTXXh822J4nZhhDdF1E80xObFXR3peUBymwYQr79KodPXyOE6N+8J4QsThOC7eNsKay0IMPMvKOMQCVXmemiGvpp5IhRTxKia/E6FIALsKMbUyZvLC7zAMtBkU1ByAciIf/zv5QQ7dnXn3/+9efXJ8RjqyJRWfi7N4dWLdwiDLIQBh/twxFK8PPZvohXaEUjj4nM7piPeYoQbBCaIrE7onGPoiMSIkoI5iMnhODZvSNEHNTxeDlyUd1pwiCP7E7zXny8RzRebXmT8BOuhHyOEoKLEUI/KADeGTt4nCELHgt5GPShWydEkJBPMR+v/YoGAivwdcrH0yvNQyDslg0rMXtny9qSV9WwuF3r29cUQ1tCBVsqq8sX5BgheAq7RqzSNAgfGBkSdSkD64SEvPF/rwG+eFZYH1qusp5e1E3vPEJ2PCHixHCDjtXYsJA9kzLSaaQxb1D824YryBFCdM3fi3zkkW9ASE7GGx//+t0vCCFYZ4Exjv8VptY3b9TwTThrHqKlfFhh6WR0vF2JEESSVFt4huEAgyqzExIy59vdwC1NcTYhxTzkbXj6K0rIa5/QUK8Xpu8vLrpecdZMPba59hYWF0ct2hUZkcRiMvihqfrA2XTVBO44ISOukDjtrPjlBoQw5XwnJ+S1L9/57eu/+01h9D59drOWb8BZEpJWTQdqhF9+z/jmM3KTiWtj/MnmJ8bYUGDnzUZln1XmVt5ek3YSkvFCyvABhFiyQZ1AMqhzq72a/+VrJf6ymoV8ftkFvdaE4Fx3fNdjN6h0bSAoq4o6/jEyee8IfY3YkJQM13VrUQ1UCtcxQjZirFHVXmebvSwhuvZbGSFfXXh9tR0hZElpx9XUYo1e3M9dJOodt2+a5pRrWAPijbjsI8QzN0030cLzVrPdnFtcxgSvW6isHRLKcdCrbtMNJ4DQ4qpsrsnTtVmbGPISolVKqyIE27y3vWPYICFeKmypoxVTFD+EFmIa3t13V4kzduJtZyl0dYu1BfQ9M4JghdZJqiyTDj9zL5cBmwgBOeWA1So396GryD1+6cSrLS83EaJ9IhLy9KKTQlqH01u4uhMPU5uvqlWaLhq1h60yBfi3Z1bsnJ3NZzHxq4ge1+Z9iMas22/ZmEZpZjcQAmttXE4WSmVz0daLix+IhGjvfMER8tWl5UNCiJ3OBaRr00ZiL4eqMlWc8j9v9HLlHP54Jp8HMxhw45K94NbbdW5kwoK0LwstI0TXZrzexIUc1xusxfK71iQhmvbuZ1+UhDz9Wr84HyIhTeAtHmgbh0/DymcgBu3JgiUVL9nYaF2Rycxs8Phbq994yf6+LFWThBBdW1TyRL0r9xI+tBYbVHCC6q8AP3lPIASHfPedz7788unTr37zu8vau2UOIiH1w1OWYQiaAB04V4henxs/aisqurblR4PSPhuH7FGoml+Rrh3YqYOdL73ICMHaLxDkYy3no42EYBkBNDhe6c6zZ7Qcl8fZvr3gNxcM2MLwJq+Bpj1JSdnZAWNoxQGTdL/mLkxkj8l70UgIlsK+IB9hAx+tCHmJ+yMUiv65HX+CGzhb21kipLHmLKWdTG/HAStDZdMnzLaFOZLEG3EtHzVLSLLkpvYGCuv+TDlaSYjkdPqd4NwjbXa4SWojhM02RCB3i59zUlQN68fO/+vauM8mXaxnSQjpmYLdbcrklKIVIdfCmYRYO18UVt4ZpcGfkdv9NfjJYUPBIBOdo9FoJMR3Qn6B9xgfj4kQw3BNUUJI52e65lB6WQcsWbH998geQikqziwUpt1NhCR7kY9jpyAfESEEwYYfLcfcLMNO5BmxBixuhVhamDJZv+cNRuIUv4EQhKZrgbhl004YwSMgRDB6J0x9+fEa6BpI0Z1y6Ymr8IXU6U6yGm4O676R59WGkBpx4VG/oAdESJ0aOgvhH1moXzECrihng9l7KFLBcLxhtjfL1hKXyZtVllhudsldggdESAOM8rSOkVfYTKoEhkL/PHo5R0HInC8ENluHh8ILiJmKtlNZdVjH/MAfEiF4gIy2sxLb2XAzmthI3AvkGnTXdhBibTHGgwh/8mfzaUGFNMKZhBzfZ3tYhNTtHz/eheLSO2L202ESfqZdgHkfVyXQhyGqlsu47RFhc7e9hBxTWg+MkJ5ksjbuBqLjwL6sRXYuHaQZqumjtxZbvmxWcbexHSGUyuYDdw+MEJmfLG61pdDsVlmPGxFilGbBwJayQZVXP+UKd5QQYbxpOJunPQZCaivonFPW6CaElD4kMl+ufCSx1zvH4xq5tcqiSutF1rKuhdZH2rSFoLPKLXVeQozaqWop6AYw2XMV9BIlw1oehmDJrRA7qhwjRLQGmk8JPwpCNPCM5Q6HlIuIGyQO+G0APoz8ggqJTrwjwtEw9mmmK66ZjxBioBFTEDI3WTYorcdCSMxvcOdKRzw0shy1woGMIb6w5oG/TOfDhLa6XhDSRkKwIa7r/NJXo9J6HIRoNUfSYU7IlmuEfWN0Sd4zUdFMhnR7vNiQb0uIQfb4xTUDQz49fCSECFPyYlQnksPEn/baXc1M0kzZdsVacEhTZPJsR0ixfS54kTZU5tEQwin8SiE43Gov5651AsmU03b92pGeloQQnwv4pRcIjEinh4+EEHIIV7oTxbn8tj+8DhqLRc0Pu+2gji0+RzKekVLKlNajIYQbNEu7V+fMrKajuVr9tnYSsYxpMf5zTOm2XNoNq712tR0l7lTJFuIfDSG4tgajP8xy4G3w8TmJEZdepx6A3x5u3jEcl+F5T0i50no8hPB7tcuiR/shk4DRYGf5gx2DDbF651yzDmQNk7YipCyz4DcE7V3vH4+HEP4ISFD6EQpTw/pYUBsv6NB/ihBswbEdvgUhNRNDprR4317rwRIi7mUVC7a84QtMSTwM8BSQORWbT6IZQqqDgFyOB75wpwmpMS9RWj2+uJL+c0WcRQi/FWXF5U8HxGzxWTUfHF0Tc6FuQOxOCp7a1TMcCr29hYTwHmDkd1FpCYQcbssJ8UY4ixDBqKyOa3jCNM2MGRcS+JC/XqLchFqRlSzePCs8d8vstIhr2HaE6Lx7qmwhnh9DwDS+RziLkIgPWtr4rMcnXWh1N2wyvRG3EZiP+/yiC4iIXp1hgIWsTW2Po42EiIJcX9Ni3SFJT9j1fJyjfwuvhTkfZxGy5RUIo3zpARF2sbWfbXtj3MJ+b5EJp0fK/V8yU2ci7eMqNycKBT7aqixwqRfy41cP9NrvtjmZhGZ6HzTXWYRwBwktxiwShCdfRg/CfboPpwiJPbY8r5Bym4W4r44iL+n1Em+YiV5y7QnBHYebxiPBUUA444DKMiwfGCG4RwccIdwiCT0DbtRqicStcfD8LPIWaYTAwXRqG2UCNxjUtdompsG5gdUXWMjgZjVcbnTHOIuQXp8jhFPN+h6JK+J1fyzy2Kru1xCVS+kFZJATWQanB88gRLgdEgnLB0lQYwTw8AjxTY4Q1k4lN740bBcKex47JtLs+A4jVmLciv+uHSG1U/OipSX3y3h4hJClu6IPI34ZETOylzvzCNzw8z/htgtqozHrZUP2AFWx3HX6Rjk4bc2ny00Pe0uZk8QDJITXzbYwlvrZsduAcnt4wKfop81RLGR5/DLHocjq5I1ynssZfQY3PSRnHuvefQ+OEPY4OoFgTWraMEDIkqoDMnhgQ6b2rqRxiiRtQ/kwIu6sg4HC4lrMkxJSFz2+YjOJN9i9IaQ6BwuT7ON3LjLvPJQ5ESQHhOSKizhsZ5JjnfrGyKMIxjGabulqVlG4cjLPvccQyd9j6IBWqipmiGta9A47q/rZuD+EcFgeU1lj4W5rcdEB12iVQstbFtvr6eWJRtpw66KXt005PFFja57AxJ1fPjnkg/rJN32KEQH87qEf7YXbKe7JPKS7NBks0yOEYAteCCyrQpwty4aFtV3azP2sfoVFidUhEBrPnq8oe+OUyzL3r4v6bDH2UgesERcRB5vz00M4ApHtzf50Ou33lzhw/RTwVSB1B2kbWhIA/+evNvt+1f3c6bqz8DW5eOSPnVlnvwxs13XtYLnOIka3yXJsVWaxZj4fLl828/3xGC7tvU9LvpcFrZmfLKLBbrfpDrfxuHp8NIqTxHHcfKH15fF4SRDQ8g73xhC/Nw11p2irBYU4t1cgBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFhXuBaktIl348FuP2cIE81F7XneGumvoqlMbdbpx/3HYHhbPHrDtsPE/k7aLbP2vkdZMXTMEZlBV7QCCHVnOXPr+PCvdyJ2h044Pja823510KyRI1n2dyhqfZ0rUYyU++t0fcvYOeV0NvSt9+pmteccKAHP7rNFQGvGbDWycktmU3beQFiIuroY6AnNU+Gep4ChvJG01uH/qenmiC/Cd2n75PvlM6i9cdemSEiKGkHnT60SDC99nIa/iFNDVzvFGerpQQSWX4v2wg8Fc99o6FWwLx7aVHmtaoE+YnjfZS/+UcpyREVoUmaTv6c9MviS19pW4VWm8lITI2uEc7tLx7CdG1VX4Opmej2YEep8FqjN69NI4Xq17uHuo4+E8v8StCHKenF6GKY4MQyqex+HyS1cKrSHa8xYpeqwgJ4yQ89lcI0MtJ9+NVkXj+wPdsNNAdvUjIY/IioekvJSG+k/tC9mgmZW1wpjE514L/FvpxHK+8hHwZ+xu0jMe3rp1r6C3hUmQY3d1eh37c0tN8/m5J3J7JGYBtP+wl88DdUkLwk06/3yWhTAiVkrot+stkBXfRBBl/HGMCLtfT/KHTIV70YUROnwVrPYKM+ruqr/pzm/QSfQCJu2mlv7TtdGqhoD8FWe5lkFCAS0gBR6mRtV9UEoKHxsl0D5rHm4O3cb9DtNBsGibw8nf3MNa2OJIVrki2GyiIBQXTMjtAVn+6PvqihVtBCoMIDA2mFtGPHfJ+D2eP0GS+D1CwIt79AdQAK4tcQrCqy3DVnBS37DydomBLWLUyww1DXPc5owq6OEzWSS1yNwAkbKWdDLfDkA6dGQrC0EXMBU1+CDdeaP6BJN6HF7FTEEIMIGRL3o+IwnTtooCoMD1DyJynS2QMKpXlLenbRCIb2esU52nG5BxuMEL2BNOZ4SKHOJ0A11jD2U0O8yU5BzkCQqbBnRNCLj7AldNDbP7iSkDN13B8UJ+j/gw3arInqhQT0jdG0SwBQhzCB1FvI9waEIrQCoSgeYK1ygRZ1fkqnGwGaiByyRmNDZCnQWuD/bxBLsp6ur810bTUTf6EvNQwQzbMh3pzuNCm+MlZ2ag7xmqoZ6LlzNd0nFngkXTJG5mcDLmrXGUBHyH0Mc9C+xgzHPVJdxriTA+J3kuRbYeeP+64YPx79JWYDuYlxgq5g5Zer3f3o/oKTpxTLsYTKBceQjJoWyMiNkevD103wqJMh1IiIRlY+aCjwASFUM6SRsqvy/Lc8m1tQHmfXI2JjYUN6f0ZiRIbtkeutqZX0UTMkRpCCDTQjiYesm+tKgb1DrJX9AGZtcQBlBOHxoZjSiRkoHl9RPQV7mP5W6pnUDB4RysR1tigVOtreNvlgF7hqSXr5Ywc07rCoI6BO1oKucPNyBmajKFVt3CpTvF25g705AjRZqRmL24Lys6hnC9soMozRCxSHUamSgHF0YomNYGH/iqi3d0j76HdwLVCumDNUkJG5SVpOzQtVEepjByTqDVqsWNqN+XdzhGcfYtdNEumKHXIQFLNEvdwr8MwfyfiOCCSCLPdEOpo0TOpY8cn/Wh592Yv4AAZp7hrwxiAdWkHaoZ7/MjpAfwd1C+iV/jQeUhWnImGRqGhxgNoFCxWdPzlCCHwk9WhGiZ0J47MnJCAvjm1RggWpTRPfMjePZQHxFqouDqYfNyjdY+G3kIATEhmFv1jVx1P3MEAOcy/j6f5fRQjOFCKVYOd7hZJeW7uKhJC7l9f+UuiYpIA12APE3asF+yAwoWZCul1GiXEhfd9Eo2Ew7t5KBsqTwiB+vCE+HA+ykZWQBcAksEhBFPJtQgh0wZCoH2qxIciIbPqfgYsCRs8CDJF6QAhFrKJpoIyl2+UJvJfEhKwhGBTEoys/n7XuyohWN8PcPGhJf01yrBsdHEdXbSkb36frPfrFUcIChYHWiNM23KSYz/ZNhAST+BIZbpL5oSQQYDN5HA08+wThASovy4SD7ciIVFlNyR4mNOxUVCGngzJ7YDZlgzWoJHyizIJIbMGCcGatpsu4dDqMrkeIRoMmVmUq+sOShfADbRG+fpynZyGrQjBdjDuk3BNLBnwmVBSQjDLbofMtg7wEBsR5gzmdckJQsbL8uA1u1VTBFwUSwzEIunicXvOFgU/G5GbImbEkM/HF7B4MY9yQmhrxMM1Ivr7aoTgdkqzfHCboXBDbjPSJ+xdJjwhUPYBWRrGBk31qh2tgRAvfwGRjgeqDrSRTd5jj/vwcUKw7pRcAlwO6rhPdPJxgRhoI/ZId54cDHLwtLTgoPjYlJIT4jj5udCU3FJxrUEdOo0Z5jo6Cew9cAOdCrcb6WuDcD7mCYGK78mlizuw+UmoYTh3ZISQrhxpPlivxDA9QBORdPNBvZGQLpEBIp8hc1y7CJjCLQdEdva5hTegoVeTfVzQtiW9wSGLQfAb1m5zTUqI7psgkboORpibXGktK28Kw8rf0Im7fF5dXPKQPFsQ2ecIgaUTbPZPiHkbkudeABWVS4ibS8geUS1CJASuksfK4xghYzLLhqD9SlxJwA0mWMO69UBGhg6ZFGHNGJB5SRKCLV6sZY3I/QY7PGmE32CVwJMT4mOGaQKweOFDHDzfvMq9f+MQQeNqeeXoVEmbWajfiYaZSyRCIISoWJjm4WFzCqGoPSMlBEjuLFaDZbBG/Y2DNZg5XC06VohnbdERQnBXt1HQiaJOQEfZHHh4s1NYO8NzynAXDfZknYa8Ud3NhlGnDw1ZEoJLAoKU4qngINpgQ7hLdEIgISQm2W2HKSJPsZ4z99k1JiK4OKU6xoJfTAhnJj34v09I6ej7a6v9EDy7ha6+LULFNHaTlYVNlxgLBTZVB/QtrAcfk28emYcAI/ml2euYVeY7uF4ZpKxLr/qwM3otQbymocMVGaEIIbjk5OXUfkZvMugPqJIuzd4OM6gv8rq4hAa4F6dsjLtFMpsV2nK8jeLisRNl6byz0ElHm83ylehy3p1EEdSKhtryofxFlQyZh2SdmQ+7ovDGlmTQyTYePN6tcHJbPc+5LEROCE5xTBMXFIc3HNBHyWCUHnZ5Tthq33bSNKNFGM/yBQF9QXPwdod0lHsNJNGWdqqitqRStC77+SZfXPa3g+GRC0HuHO36hl770DbBIxH0fPHqROJNCR4ryk1/u1swm5vsPqde/o99zl2R3BSK3y7Vi//0IrBefq1HcVY7u5jfsIkzZaw2WvnCy4uil9/FvKR1YUIp5y6ydABqfHXtciiUSNL1/F7d/62gFIWCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgsKN8f/xYGCv5sONvgAAAABJRU5ErkJggg==" alt="Reakt PG logo"></div>
958
  <div class="report-heading"><div><h1>Reakt Inloop Monitor ${escapeHTML(d.site)}</h1><p>Inzicht in bereik, betrokkenheid en bezoekpatronen</p></div>
 
965
  <div><b>Nieuwe instroom</b>De eerste geldige scan van een cliënt op deze locatie (binnen de beschikbare historie) valt in de rapportageperiode.</div>
966
  <div><b>Actieve cliënten</b>Minimaal één scan op deze locatie tussen ${escapeHTML(activeWindow)}.</div>
967
  </div>
968
+ <div class="report-definitions-note">Een vervangende scanpas telt niet als nieuwe cliënt.</div>
969
  </section>
970
  <div class="report-chart-grid">
971
+ <section class="report-panel"><h2>Instroom per maand <small>(nieuwe cliënten)</small></h2><div class="chart-box">${reportChartBars(mon,newPerMonth,'#288e28')}</div></section>
972
+ <section class="report-panel"><h2>Bezoekdagen per maand</h2><div class="chart-box">${reportChartLine(mon,values)}</div></section>
973
  <section class="report-panel"><h2>Bezoekdagen per weekdag</h2><div class="chart-box">${reportChartBars(week,d.byWeek,'#ff6410',true)}</div></section>
974
  </div>
975
  <div class="report-bottom-grid">
976
+ <section class="report-panel"><h2>Kerncijfers locatie</h2><table class="report-mini-table"><thead><tr><th>Locatie</th><th>Unieke cliënten</th><th>Bezoekdagen</th><th>Gem. cliënten per dag*</th></tr></thead><tbody><tr><td>⌖ ${escapeHTML(d.site)}</td><td>${reportNL(d.unique)}</td><td>${reportNL(d.visits)}</td><td>${avgDay}</td></tr><tr class="total"><td>Totaal / gemiddelde</td><td>${reportNL(d.unique)}</td><td>${reportNL(d.visits)}</td><td>${avgDay}</td></tr></tbody></table><div class="report-average-note">* Gemiddeld over ${reportNL(d.daysWithScans)} dagen met geregistreerde scans.</div></section>
977
+ <section class="report-panel"><h2>Aantal cliënten per maand <small>(iedere cliënt maximaal één keer per maand)</small></h2><div class="chart-box report-client-month-chart">${reportChartBars(mon,clientsPerMonth,'#763fc7')}</div></section>
978
  <section class="report-panel"><h2>Managementanalyse</h2><div class="report-analysis">${summary.map(t=>`<p>${t}</p>`).join('')}</div></section>
979
  </div>
980
+ <div class="report-foot"><span>Bron: scanregistratie 2026${d.historyLoaded?' en historisch referentiebestand 2025':''}. Rapportageperiode en peildatum staan bovenaan vermeld.</span></div>`;
981
  }
982
  function openWhiteReport(){
983
  if(!importedData?.last){alert('Upload eerst een Excelbestand en rond de analyse af. Deze witte rapportage gebruikt geen verzonnen demo-KPI’s.');return;}