@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&display=swap');
/* ══════════════════════════════════════════════════════════════
CUBA SEN LIVE — Dashboard v2 (shadcn/ui inspired)
Scoped under #cuba-sen-dashboard
══════════════════════════════════════════════════════════════ */
#cuba-sen-dashboard {
all: initial;
display: block;
max-width: 720px;
width: 100%;
margin: 0 auto;
background: #09090b;
border-radius: 12px;
border: 1px solid #27272a;
overflow: hidden;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
color: #fafafa;
box-sizing: border-box;
position: relative;
-webkit-font-smoothing: antialiased;
}
#cuba-sen-dashboard *, #cuba-sen-dashboard *::before, #cuba-sen-dashboard *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* ── Loading ─────────────────────────────────────────────── */
#cuba-sen-dashboard .sen-loading {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 80px 20px;
color: #a1a1aa;
font-size: 14px;
font-family: 'Inter', sans-serif;
}
#cuba-sen-dashboard .sen-spinner {
width: 20px; height: 20px;
border: 2px solid #27272a;
border-top-color: #fafafa;
border-radius: 50%;
animation: csen-spin .7s linear infinite;
flex-shrink: 0;
}
@keyframes csen-spin { to { transform: rotate(360deg); } }
/* ── Header ──────────────────────────────────────────────── */
#cuba-sen-dashboard .sen-header {
padding: 16px 20px;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 10px;
border-bottom: 1px solid #27272a;
}
#cuba-sen-dashboard .sen-header-left {
display: flex;
align-items: center;
gap: 10px;
}
#cuba-sen-dashboard .sen-live-dot {
width: 8px; height: 8px;
border-radius: 50%;
background: #22c55e;
box-shadow: 0 0 0 3px rgba(34,197,94,.2);
animation: csen-pulse 2s ease-in-out infinite;
flex-shrink: 0;
}
@keyframes csen-pulse {
0%,100% { box-shadow: 0 0 0 3px rgba(34,197,94,.2); }
50% { box-shadow: 0 0 0 6px rgba(34,197,94,.05); }
}
#cuba-sen-dashboard .sen-title {
font-size: 14px;
font-weight: 600;
color: #fafafa;
letter-spacing: -.01em;
}
#cuba-sen-dashboard .sen-header-right {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
#cuba-sen-dashboard .sen-date {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: #71717a;
}
#cuba-sen-dashboard .sen-share-btn {
display: inline-flex;
align-items: center;
gap: 4px;
background: transparent;
border: 1px solid #27272a;
border-radius: 6px;
padding: 5px 10px;
font-family: 'Inter', sans-serif;
font-size: 12px;
font-weight: 500;
color: #a1a1aa;
cursor: pointer;
transition: all .15s;
}
#cuba-sen-dashboard .sen-share-btn:hover {
background: #27272a;
color: #fafafa;
border-color: #3f3f46;
}
/* ── Banners ─────────────────────────────────────────────── */
#cuba-sen-dashboard .sen-banner {
padding: 10px 20px;
font-size: 12px;
font-weight: 500;
border-bottom: 1px solid #27272a;
display: flex;
align-items: center;
gap: 8px;
}
#cuba-sen-dashboard .sen-banner-fallback { background: rgba(245,158,11,.06); color: #fbbf24; }
#cuba-sen-dashboard .sen-banner-manual { background: rgba(99,102,241,.06); color: #818cf8; }
#cuba-sen-dashboard .sen-banner-demo { background: rgba(168,85,247,.06); color: #c084fc; }
/* ── Status Hero ─────────────────────────────────────────── */
#cuba-sen-dashboard .sen-hero {
padding: 32px 20px 28px;
text-align: center;
border-bottom: 1px solid #27272a;
background: linear-gradient(180deg, rgba(var(--hero-rgb),.04) 0%, transparent 100%);
}
#cuba-sen-dashboard .sen-hero-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 14px;
border-radius: 9999px;
font-size: 12px;
font-weight: 600;
letter-spacing: .03em;
text-transform: uppercase;
border: 1px solid;
margin-bottom: 16px;
}
#cuba-sen-dashboard .sen-hero-pct {
font-family: 'JetBrains Mono', monospace;
font-size: 64px;
font-weight: 700;
line-height: 1;
letter-spacing: -.04em;
}
#cuba-sen-dashboard .sen-hero-pct-unit {
font-size: 32px;
font-weight: 500;
opacity: .7;
}
#cuba-sen-dashboard .sen-hero-label {
font-size: 13px;
color: #a1a1aa;
margin-top: 6px;
font-weight: 500;
}
#cuba-sen-dashboard .sen-hero-summary {
font-size: 13px;
color: #71717a;
line-height: 1.6;
margin-top: 14px;
max-width: 520px;
margin-left: auto;
margin-right: auto;
}
/* ── Legend ───────────────────────────────────────────────── */
#cuba-sen-dashboard .sen-legend {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 6px 14px;
margin-top: 18px;
padding-top: 16px;
border-top: 1px solid #1c1c1e;
}
#cuba-sen-dashboard .sen-legend-item {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 11px;
color: #71717a;
white-space: nowrap;
}
#cuba-sen-dashboard .sen-legend-dot {
width: 8px; height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
/* ── KPI Cards ───────────────────────────────────────────── */
#cuba-sen-dashboard .sen-kpis {
display: grid;
grid-template-columns: repeat(4, 1fr);
border-bottom: 1px solid #27272a;
}
@media (max-width: 560px) {
#cuba-sen-dashboard .sen-kpis { grid-template-columns: repeat(2, 1fr); }
}
#cuba-sen-dashboard .sen-kpi {
padding: 18px 16px;
text-align: center;
border-right: 1px solid #27272a;
transition: background .15s;
}
#cuba-sen-dashboard .sen-kpi:last-child { border-right: none; }
@media (max-width: 560px) {
#cuba-sen-dashboard .sen-kpi:nth-child(2) { border-right: none; }
#cuba-sen-dashboard .sen-kpi:nth-child(1),
#cuba-sen-dashboard .sen-kpi:nth-child(2) { border-bottom: 1px solid #27272a; }
}
#cuba-sen-dashboard .sen-kpi:hover { background: rgba(255,255,255,.02); }
#cuba-sen-dashboard .sen-kpi-icon {
font-size: 16px;
display: block;
margin-bottom: 8px;
}
#cuba-sen-dashboard .sen-kpi-val {
font-family: 'JetBrains Mono', monospace;
font-size: 20px;
font-weight: 600;
line-height: 1;
color: #fafafa;
}
#cuba-sen-dashboard .sen-kpi-unit {
font-size: 11px;
font-weight: 400;
color: #52525b;
margin-left: 2px;
}
#cuba-sen-dashboard .sen-kpi-label {
font-size: 11px;
font-weight: 500;
color: #71717a;
margin-top: 6px;
letter-spacing: .01em;
}
/* ── Cards ───────────────────────────────────────────────── */
#cuba-sen-dashboard .sen-card {
margin: 16px;
border: 1px solid #27272a;
border-radius: 10px;
overflow: hidden;
background: #09090b;
}
#cuba-sen-dashboard .sen-card-header {
padding: 14px 16px;
font-size: 13px;
font-weight: 600;
color: #fafafa;
border-bottom: 1px solid #27272a;
background: #0c0c0f;
}
/* ── Charts ──────────────────────────────────────────────── */
#cuba-sen-dashboard .sen-chart-container {
padding: 16px;
height: 220px;
position: relative;
}
#cuba-sen-dashboard .sen-chart-container canvas { display: block; }
#cuba-sen-dashboard .sen-chart-sm { height: 180px; }
#cuba-sen-dashboard .sen-chart-empty {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: #52525b;
font-size: 13px;
}
/* ── Province Grid ───────────────────────────────────────── */
#cuba-sen-dashboard .sen-prov-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0;
}
@media (max-width: 480px) {
#cuba-sen-dashboard .sen-prov-grid { grid-template-columns: 1fr; }
}
#cuba-sen-dashboard .sen-prov-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 16px;
border-bottom: 1px solid #1c1c1e;
transition: background .15s;
}
#cuba-sen-dashboard .sen-prov-item:hover { background: rgba(255,255,255,.02); }
/* Remove bottom border on last row */
#cuba-sen-dashboard .sen-prov-grid > .sen-prov-item:nth-last-child(-n+2) { border-bottom: none; }
@media (max-width: 480px) {
#cuba-sen-dashboard .sen-prov-grid > .sen-prov-item:nth-last-child(-n+2) { border-bottom: 1px solid #1c1c1e; }
#cuba-sen-dashboard .sen-prov-grid > .sen-prov-item:last-child { border-bottom: none; }
}
/* Vertical divider between columns */
#cuba-sen-dashboard .sen-prov-item:nth-child(odd) {
border-right: 1px solid #1c1c1e;
}
@media (max-width: 480px) {
#cuba-sen-dashboard .sen-prov-item:nth-child(odd) { border-right: none; }
}
#cuba-sen-dashboard .sen-prov-name {
font-size: 13px;
font-weight: 500;
color: #a1a1aa;
}
#cuba-sen-dashboard .sen-prov-val {
font-family: 'JetBrains Mono', monospace;
font-size: 14px;
font-weight: 600;
letter-spacing: -.01em;
}
/* ── Links ───────────────────────────────────────────────── */
#cuba-sen-dashboard .sen-links {
display: flex;
flex-wrap: wrap;
gap: 8px;
padding: 14px 16px;
}
#cuba-sen-dashboard .sen-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 7px 14px;
background: #18181b;
border: 1px solid #27272a;
border-radius: 8px;
color: #a1a1aa;
font-family: 'Inter', sans-serif;
font-size: 12px;
font-weight: 500;
text-decoration: none;
transition: all .15s;
}
#cuba-sen-dashboard .sen-link:hover {
border-color: #3f3f46;
color: #fafafa;
background: #27272a;
text-decoration: none;
}
/* ── Footer ──────────────────────────────────────────────── */
#cuba-sen-dashboard .sen-footer {
padding: 14px 20px;
border-top: 1px solid #27272a;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 8px;
font-size: 11px;
color: #52525b;
}
#cuba-sen-dashboard .sen-footer a {
color: #a1a1aa;
text-decoration: none;
transition: color .15s;
}
#cuba-sen-dashboard .sen-footer a:hover { color: #fafafa; text-decoration: underline; }
#cuba-sen-dashboard .sen-refresh {
display: inline-flex;
align-items: center;
gap: 4px;
background: transparent;
border: 1px solid #27272a;
border-radius: 6px;
padding: 5px 12px;
font-family: 'Inter', sans-serif;
font-size: 12px;
font-weight: 500;
color: #a1a1aa;
cursor: pointer;
transition: all .15s;
}
#cuba-sen-dashboard .sen-refresh:hover {
background: #27272a;
color: #fafafa;
border-color: #3f3f46;
}
#cuba-sen-dashboard .sen-refresh:disabled { opacity: .35; cursor: not-allowed; }
#cuba-sen-dashboard .sen-cd { font-family: 'JetBrains Mono', monospace; }
/* ── Toast ───────────────────────────────────────────────── */
#cuba-sen-dashboard .sen-toast {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%) translateY(20px);
background: #fafafa;
color: #09090b;
padding: 8px 16px;
border-radius: 8px;
font-family: 'Inter', sans-serif;
font-size: 13px;
font-weight: 500;
box-shadow: 0 8px 30px rgba(0,0,0,.4);
opacity: 0;
transition: all .25s ease;
pointer-events: none;
z-index: 9999;
}
#cuba-sen-dashboard .sen-toast.sen-toast-show {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
/* ── Error ───────────────────────────────────────────────── */
#cuba-sen-dashboard .sen-error {
padding: 48px 20px;
text-align: center;
color: #ef4444;
font-size: 14px;
line-height: 1.7;
}
/* ── Animations ──────────────────────────────────────────── */
@keyframes csen-fadein {
from { opacity: 0; transform: translateY(6px); }
to { opacity: 1; transform: translateY(0); }
}
#cuba-sen-dashboard .sen-header { animation: csen-fadein .3s ease both; }
#cuba-sen-dashboard .sen-hero { animation: csen-fadein .3s ease both .05s; }
#cuba-sen-dashboard .sen-kpis { animation: csen-fadein .3s ease both .1s; }
#cuba-sen-dashboard .sen-card { animation: csen-fadein .3s ease both .15s; }
#cuba-sen-dashboard .sen-footer { animation: csen-fadein .3s ease both .2s; }
window.CubaSEN={"apiBase":"https:\/\/passionvaradero.com\/wp-json\/cuba-sen\/v1","nonce":"c35cef3fac","refreshDelay":300,"i18n":{"loading":"Chargement des donn\u00e9es du r\u00e9seau \u00e9lectrique cubain\u2026","error":"Donn\u00e9es temporairement indisponibles \u2014 r\u00e9essayez dans quelques instants.","last_update":"Mise \u00e0 jour :","fallback_warn":"\u26a0\ufe0f Source UNE indisponible \u2014 derni\u00e8res donn\u00e9es en cache affich\u00e9es.","manual_warn":"\ud83d\udee0\ufe0f Mode manuel activ\u00e9 \u2014 donn\u00e9es saisies manuellement.","demo_warn":"\ud83e\uddea Donn\u00e9es de d\u00e9monstration \u2014 actualisez dans quelques minutes."}};/**
* Cuba SEN Live FR — frontend.js v2
* Dashboard redesigné (shadcn/ui)
*/
(function () {
'use strict';
/* ── Config ──────────────────────────────────────────────── */
var CFG = window.CubaSEN || {};
var API = CFG.apiBase || '/wp-json/cuba-sen/v1';
var NONCE = CFG.nonce || '';
var DELAY = CFG.refreshDelay || 300;
var T = CFG.i18n || {};
T.loading = T.loading || 'Chargement en cours\u2026';
T.error = T.error || 'Donn\u00e9es temporairement indisponibles.';
T.fallback = T.fallback_warn|| '\u26a0\ufe0f Source indisponible \u2014 cache affich\u00e9.';
T.demo = T.demo_warn || '\ud83e\uddea Donn\u00e9es de d\u00e9monstration.';
T.manual = T.manual_warn || '\ud83d\udee0\ufe0f Mode manuel actif.';
/* ── Utilities ───────────────────────────────────────────── */
function qs(s, r) { return (r || document).querySelector(s); }
function fmt(n, d) { return n == null ? '\u2014' : Number(n).toLocaleString('fr-FR', { minimumFractionDigits: d||0, maximumFractionDigits: d||0 }); }
function esc(s) { return String(s||'').replace(/[&"']/g, function(c){return{'&':'&','':'>','"':'"',"'":'''}[c];}); }
function hex2rgb(h) { var r=parseInt(h.slice(1,3),16),g=parseInt(h.slice(3,5),16),b=parseInt(h.slice(5,7),16); return r+','+g+','+b; }
/* ── Status levels (matches PHP calculator) ──────────────── */
function niveau(id) {
var N = {
panne_majeure: { label:'Panne majeure', color:'#ef4444', icon:'\ud83d\udd34' },
deficit_severe: { label:'D\u00e9ficit s\u00e9v\u00e8re', color:'#f97316', icon:'\ud83d\udfe0' },
deficit_modere: { label:'D\u00e9ficit mod\u00e9r\u00e9', color:'#f59e0b', icon:'\ud83d\udfe1' },
sous_tension: { label:'Sous tension', color:'#84cc16', icon:'\ud83d\udfe1' },
normal: { label:'Normal', color:'#22c55e', icon:'\ud83d\udfe2' },
};
return N[id] || { label:'Inconnu', color:'#71717a', icon:'\u26aa' };
}
function niveauPct(pct) {
if (pct < 40) return niveau('panne_majeure');
if (pct < 60) return niveau('deficit_severe');
if (pct < 75) return niveau('deficit_modere');
if (pct 0) drawDailyChart(cD, data);
else showEmpty(cD, 'Donn\u00e9es en cours de collecte\u2026');
});
var cH = qs('#csen-hist', root);
if (cH) loadHistory(24).then(function(data) {
if (data && data.labels && data.labels.length > 0) drawHistChart(cH, data);
else showEmpty(cH, 'Historique en cours de collecte\u2026');
});
});
}
function showEmpty(canvas, msg) {
var p = canvas.parentElement;
canvas.style.display = 'none';
var d = document.createElement('div');
d.className = 'sen-chart-empty';
d.textContent = msg;
p.appendChild(d);
}
/* ── Build HTML ──────────────────────────────────────────── */
function buildHTML(d) {
var niv = niveau(d.statut_id || '');
var col = d.statut_color || niv.color;
var rgb = hex2rgb(col);
/* Banners */
var banners = '';
if (d.is_demo) banners += '
'+T.demo+'
';
if (d.from_fallback && !d.is_demo) banners += '
'+T.fallback+'
';
if (d.manual_mode) banners += '
'+T.manual+'
';
/* KPIs */
var kpis = [
{ icon:'\u26a1', label:'Disponible', val:fmt(d.disponibilidad_mw), unit:'MW' },
{ icon:'\ud83c\udfed', label:'Demande', val:fmt(d.demanda_mw), unit:'MW' },
{ icon:'\ud83d\udcc9', label:'D\u00e9ficit', val:fmt(d.deficit_mw), unit:'MW' },
{ icon:'\ud83d\udca1', label:'Coupures', val:fmt(d.afectacion_mw), unit:'MW' },
];
var kpiHTML = kpis.map(function(k) {
return '
'
+ '
'+k.icon+'
'
+ '
'+k.val+' '+k.unit+'
'
+ '
'+k.label+'
'
+ '
';
}).join('');
/* Provinces — sorted worst first */
var provs = (d.provinces || []).slice().sort(function(a,b) {
return (a.couverture_pct||0) - (b.couverture_pct||0);
});
var provHTML = provs.map(function(p) {
var pNiv = niveauPct(p.couverture_pct || 0);
return '
'
+ ''+esc(p.nom)+''
+ ''+fmt(p.couverture_pct, 1)+' %'
+ '
';
}).join('');
/* Legend */
var legend = [
{ label:'\u2265 90 % Normal', color:'#22c55e' },
{ label:'75\u201389 % Sous tension', color:'#84cc16' },
{ label:'60\u201374 % D\u00e9ficit mod\u00e9r\u00e9', color:'#f59e0b' },
{ label:'40\u201359 % D\u00e9ficit s\u00e9v\u00e8re', color:'#f97316' },
{ label:'< 40 % Panne majeure', color:'#ef4444' },
];
var legendHTML = legend.map(function(l) {
return '
'
+ ''
+ l.label + '';
}).join('');
return ''
/* HEADER */
+ ''
+ banners
/* HERO */
+ '
'
+ '
'
+ niv.icon+' '+esc(d.statut_label || niv.label)
+ '
'
+ '
'+fmt(d.couverture_pct,1)+'%
'
+ '
couverture du r\u00e9seau \u00e9lectrique
'
+ (d.resume ? '
'+esc(d.resume)+'
' : '')
+ '
'+legendHTML+'
'
+ '
'
/* KPIs */
+ '
'+kpiHTML+'
'
/* DAILY CHART */
+ '
'
/* RECENT CHART */
+ '
'
/* PROVINCES */
+ '
'
+ ''
+ '
'+provHTML+'
'
+ '
'
/* SOURCES */
+ '
'
/* FOOTER */
+ ''
/* TOAST */
+ '
';
}
/* ── Share ────────────────────────────────────────────────── */
function bindShare(root) {
var btn = qs('.sen-share-btn', root);
if (!btn) return;
btn.addEventListener('click', function() {
var url = window.location.href;
var title = document.title || '\u00c9lectricit\u00e9 \u00e0 Cuba \u2014 En direct';
if (navigator.share) {
navigator.share({ title: title, url: url }).catch(function(){});
} else {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(url).then(function() {
showToast(root, 'Lien copi\u00e9 !');
}).catch(function() {
fallbackCopy(root, url);
});
} else {
fallbackCopy(root, url);
}
}
});
}
function fallbackCopy(root, text) {
var ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed';
ta.style.opacity = '0';
document.body.appendChild(ta);
ta.select();
try { document.execCommand('copy'); showToast(root, 'Lien copi\u00e9 !'); }
catch(e) { showToast(root, 'Impossible de copier'); }
document.body.removeChild(ta);
}
function showToast(root, msg) {
var toast = qs('.sen-toast', root);
if (!toast) return;
toast.textContent = msg;
toast.classList.add('sen-toast-show');
setTimeout(function() { toast.classList.remove('sen-toast-show'); }, 2000);
}
/* ── Chart.js lazy-load ──────────────────────────────────── */
function ensureChartJS(cb) {
if (window.Chart) { cb(); return; }
var s = document.createElement('script');
s.src = 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js';
s.onload = cb;
document.head.appendChild(s);
}
/* Chart theme defaults */
var chartTheme = {
grid: 'rgba(255,255,255,.04)',
tick: '#52525b',
tooltip: { bg: '#18181b', border: '#27272a', title: '#a1a1aa', body: '#71717a' },
};
/* ── Daily chart (7 days) ────────────────────────────────── */
function drawDailyChart(canvas, data) {
if (!window.Chart) return;
if (dailyChart) { dailyChart.destroy(); dailyChart = null; }
dailyChart = new Chart(canvas, {
type: 'line',
data: data,
options: {
responsive: true, maintainAspectRatio: false,
animation: { duration: 700, easing: 'easeOutQuart' },
interaction: { mode: 'index', intersect: false },
plugins: {
legend: { labels: { color: '#71717a', font: { size: 11, family: 'Inter', weight: '500' }, boxWidth: 8, padding: 16, usePointStyle: true, pointStyle: 'circle' } },
tooltip: {
backgroundColor: chartTheme.tooltip.bg,
borderColor: chartTheme.tooltip.border, borderWidth: 1,
titleColor: chartTheme.tooltip.title, bodyColor: chartTheme.tooltip.body,
padding: 12, cornerRadius: 8,
titleFont: { family: 'Inter', size: 12, weight: '600' },
bodyFont: { family: 'JetBrains Mono', size: 11 },
callbacks: { label: function(ctx){ return ' '+ctx.dataset.label+' : '+fmt(ctx.parsed.y,1)+' %'; } }
}
},
scales: {
x: { ticks: { color: chartTheme.tick, font: { size: 11, family: 'Inter' }, maxRotation: 0 }, grid: { color: chartTheme.grid } },
y: { min:0, max:100, ticks: { color: chartTheme.tick, font: { size: 10, family: 'JetBrains Mono' }, callback: function(v){ return v+'%'; }, stepSize: 25 }, grid: { color: chartTheme.grid } }
}
}
});
}
/* ── History chart (recent hours) ────────────────────────── */
function drawHistChart(canvas, data) {
if (!window.Chart) return;
if (histChart) { histChart.destroy(); histChart = null; }
histChart = new Chart(canvas, {
type: 'line',
data: data,
options: {
responsive: true, maintainAspectRatio: false,
animation: { duration: 700, easing: 'easeOutQuart' },
interaction: { mode: 'index', intersect: false },
plugins: {
legend: { labels: { color: '#71717a', font: { size: 11, family: 'Inter', weight: '500' }, boxWidth: 8, padding: 16, usePointStyle: true, pointStyle: 'circle' } },
tooltip: {
backgroundColor: chartTheme.tooltip.bg,
borderColor: chartTheme.tooltip.border, borderWidth: 1,
titleColor: chartTheme.tooltip.title, bodyColor: chartTheme.tooltip.body,
padding: 12, cornerRadius: 8,
titleFont: { family: 'Inter', size: 12, weight: '600' },
bodyFont: { family: 'JetBrains Mono', size: 11 },
callbacks: { label: function(ctx){ return ' '+ctx.dataset.label+' : '+fmt(ctx.parsed.y,1)+' %'; } }
}
},
scales: {
x: { ticks: { color: chartTheme.tick, font: { size: 10, family: 'Inter' }, maxRotation: 0 }, grid: { color: chartTheme.grid } },
y: { min:0, max:100, ticks: { color: chartTheme.tick, font: { size: 10, family: 'JetBrains Mono' }, callback: function(v){ return v+'%'; }, stepSize: 25 }, grid: { color: chartTheme.grid } }
}
}
});
}
/* ── Countdown + auto-refresh ────────────────────────────── */
function startCountdown(root) {
if (timer) clearInterval(timer);
cd = DELAY;
timer = setInterval(function() {
cd--;
var el = qs('.sen-cd', root);
if (el) el.textContent = cd;
if (cd <= 0) { clearInterval(timer); refreshData(root); }
}, 1000);
var btn = qs('.sen-refresh', root);
if (btn) {
btn.onclick = function() {
clearInterval(timer);
btn.disabled = true;
btn.innerHTML = '\u21bb Actualisation\u2026';
refreshData(root, true);
};
}
}
function refreshData(root, force) {
var url = API + '/status' + (force ? '?force=1' : '');
fetch(url, { headers: { 'X-WP-Nonce': NONCE } })
.then(function(r){ if(!r.ok) throw new Error('HTTP '+r.status); return r.json(); })
.then(function(j){ if(!j.success) throw new Error(j.message||'Erreur'); render(root, j); })
.catch(function(e){ renderError(root, e.message); });
}
/* ── Error ───────────────────────────────────────────────── */
function renderError(root, msg) {
root.innerHTML = '
\u26a0\ufe0f
'
+ esc(T.error)+'
'+esc(msg)+'';
}
/* ── Boot ────────────────────────────────────────────────── */
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();