<?php
$title = 'Tableau de bord FiberOps';
$userRole = $userRole ?? '';
$currentUser = $currentUser ?? [];
$ftthTickets = $ftthTickets ?? [];
$ftthStats = $ftthStats ?? ['assigned' => 0, 'in_progress' => 0, 'to_fill' => 0, 'awaiting_validation' => 0];
$b2bMetrics = $b2bMetrics ?? [
  'total_tickets' => 0, 'unassigned' => 0, 'in_progress' => 0, 'awaiting_validation' => 0,
  'urgent_open' => 0, 'validated_today' => 0, 'service_restored_rate' => 0, 'avg_assignment_delay_hours' => 0,
];
$eInterventionMetrics = $eInterventionMetrics ?? [
  'total_requests' => 0,
  'requests_today' => 0,
  'pending_intake' => 0,
  'assigned_field' => 0,
  'resolved' => 0,
];
$eInterventionChart = [
  'labels' => ['Reçues', 'Du jour', 'À prendre en charge', 'Assignées terrain', 'Résolues'],
  'data' => [
    (int)($eInterventionMetrics['total_requests'] ?? 0),
    (int)($eInterventionMetrics['requests_today'] ?? 0),
    (int)($eInterventionMetrics['pending_intake'] ?? 0),
    (int)($eInterventionMetrics['assigned_field'] ?? 0),
    (int)($eInterventionMetrics['resolved'] ?? 0),
  ],
  'colors' => ['#0ea5e9', '#8b5cf6', '#f59e0b', '#14b8a6', '#10b981'],
];
$topTechnicians = $topTechnicians ?? [];
$myTechnicianPerformance = $myTechnicianPerformance ?? [
  'backbone_total' => 0,
  'backbone_in_progress' => 0,
  'backbone_closed' => 0,
  'ftth_total' => 0,
  'ftth_in_progress' => 0,
  'ftth_closed' => 0,
  'score' => 0,
];
$technicianPerformanceChart = $technicianPerformanceChart ?? ['labels' => [], 'incident_scores' => [], 'ftth_scores' => [], 'total_scores' => []];
$b2bDistributions = $b2bDistributions ?? ['priority' => [], 'status' => [], 'nature' => [], 'clients' => []];
$moduleMetrics = $moduleMetrics ?? [
  'raccordement_total' => 0,
  'raccordement_pending_study' => 0,
  'raccordement_pending_installation' => 0,
  'raccordement_waiting_validation' => 0,
  'raccordement_validated' => 0,
  'otb_total_boxes' => 0,
  'otb_active_boxes' => 0,
  'otb_alert_boxes' => 0,
  'otb_saturated_boxes' => 0,
  'otb_occupancy_rate' => 0,
];
$raccordementModuleVisible = \App\Core\ModuleManager::isVisible(\App\Core\Database::pdo(), 'raccordement_clients');
$otbModuleVisible = \App\Core\ModuleManager::isVisible(\App\Core\Database::pdo(), 'otb_management');
$showGlobalB2BInsights = in_array($userRole, ['admin', 'manager', 'superviseur', 'supervisor'], true);
$isTechnicianDashboard = in_array($userRole, ['technicien', 'technician'], true);

$distributionMax = static function (array $rows): int {
  $max = 0;
  foreach ($rows as $row) { $max = max($max, (int)($row['total'] ?? 0), (int)($row['active_total'] ?? 0)); }
  return $max > 0 ? $max : 1;
};
$buildInitials = static function (string $name): string {
  $parts = preg_split('/\s+/', trim($name)) ?: [];
  $i = '';
  foreach (array_slice($parts, 0, 2) as $p) { if ($p !== '') $i .= mb_strtoupper(mb_substr($p, 0, 1)); }
  return $i !== '' ? $i : 'NA';
};

$priorityToneMap = [
  'Urgent' => ['bg'=>'#fef2f2','color'=>'#b91c1c'],
  'Haute'  => ['bg'=>'#fffbeb','color'=>'#b45309'],
  'Moyenne'=> ['bg'=>'#eff6ff','color'=>'#1d4ed8'],
  'Basse'  => ['bg'=>'#f8fafc','color'=>'#64748b'],
];
$defaultPriTone = ['bg'=>'#f1f5f9','color'=>'#475569'];
$avatarPalette  = ['#6366f1','#0ea5e9','#10b981','#f59e0b','#ef4444','#8b5cf6','#14b8a6'];

$stats             = $stats ?? ['open'=>0,'in_progress'=>0,'resolved'=>0,'planned_tasks'=>0,'sla_breached'=>0,'active_techs'=>0,'impacted_sites'=>0,'today_tickets'=>0];
$chartData           = $chartData           ?? ['labels'=>[],'opened'=>[],'resolved'=>[],'ftth_opened'=>[],'ftth_resolved'=>[]];
$chartPeriod         = $chartPeriod         ?? 30;
$chartDateFrom       = $chartDateFrom       ?? date('Y-m-d', strtotime('-30 days'));
$chartDateTo         = $chartDateTo         ?? date('Y-m-d');
$chartIsCustom       = $chartIsCustom       ?? false;
$chartAllowedPeriods = $chartAllowedPeriods ?? [7=>'7 jours',30=>'30 jours',90=>'3 mois',180=>'6 mois',365=>'1 an'];
$statusData          = $statusData          ?? ['labels'=>[],'data'=>[],'colors'=>[]];
$recentIncidents   = $recentIncidents ?? [];
$interventionMetrics = $interventionMetrics ?? ['open_to_assigned'=>0,'assigned_to_intervention'=>0,'intervention_to_resolution'=>0];

$heroGreeting = (int)date('H') < 12 ? 'Bonjour' : ((int)date('H') < 18 ? 'Bon après-midi' : 'Bonsoir');
$heroName     = $currentUser['name'] ?? 'Utilisateur';
$activeAssignedCity = normalize_assigned_city_value($currentUser['assigned_city'] ?? null);

/* SLA gauge pct */
$slaTotal = (int)$stats['open'] + (int)$stats['in_progress'] + (int)$stats['resolved'];
$slaPct   = $slaTotal > 0 ? min(100, round((1 - (int)$stats['sla_breached'] / $slaTotal) * 100)) : 100;
$resPct   = $slaTotal > 0 ? min(100, round((int)$stats['resolved'] / $slaTotal * 100)) : 0;
$openPct  = $slaTotal > 0 ? min(100, round((int)$stats['open'] / $slaTotal * 100)) : 0;
?>
<style>
:root{
  --db-radius:1rem;--db-radius-sm:.6rem;
  --db-shadow:0 1px 3px rgba(0,0,0,.06),0 4px 16px rgba(0,0,0,.06);
  --db-shadow-h:0 4px 8px rgba(0,0,0,.08),0 12px 32px rgba(0,0,0,.1);
  --db-border:1px solid #f1f5f9;
  --db-accent:#4f6ef7;--db-success:#10b981;--db-danger:#ef4444;--db-warn:#f59e0b;
  --db-text:#0f172a;--db-muted:#64748b;
}
.db-wrap{display:flex;flex-direction:column;gap:1.5rem;padding-bottom:2rem;}

/* Hero */
.db-hero{position:relative;overflow:hidden;background:linear-gradient(135deg,#0b1829 0%,#10233d 40%,#1a3558 70%,#162e4e 100%);border-radius:var(--db-radius);padding:2rem;color:#fff;}
.db-hero__orb{position:absolute;border-radius:50%;pointer-events:none;filter:blur(60px);opacity:.35;}
.db-hero__orb--a{width:320px;height:320px;background:#4f6ef7;top:-100px;right:-60px;}
.db-hero__orb--b{width:200px;height:200px;background:#0ea5e9;bottom:-60px;left:30%;}
.db-hero__orb--c{width:140px;height:140px;background:#8b5cf6;top:10px;left:10%;opacity:.25;}
.db-hero__inner{position:relative;z-index:1;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:1.5rem;}
.db-hero__kicker{display:inline-flex;align-items:center;gap:.4rem;background:rgba(255,255,255,.1);backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.15);border-radius:2rem;padding:.25rem .75rem;font-size:.72rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:rgba(255,255,255,.8);margin-bottom:.75rem;}
.db-hero__greeting{font-size:1.6rem;font-weight:800;letter-spacing:-.03em;line-height:1.15;margin-bottom:.35rem;}
.db-hero__sub{font-size:.875rem;color:rgba(255,255,255,.6);margin-bottom:1rem;}
.db-hero__meta{display:flex;flex-wrap:wrap;gap:.5rem;}
.db-hero__chip{display:inline-flex;align-items:center;gap:.35rem;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);border-radius:.4rem;padding:.2rem .6rem;font-size:.72rem;color:rgba(255,255,255,.75);}
.db-hero__actions{display:flex;gap:.6rem;flex-wrap:wrap;margin-top:1.25rem;}
.db-hero__btn{display:inline-flex;align-items:center;gap:.4rem;padding:.45rem 1rem;border-radius:.5rem;font-size:.8rem;font-weight:600;cursor:pointer;border:none;text-decoration:none;transition:transform .15s,opacity .15s;}
.db-hero__btn:hover{transform:translateY(-1px);opacity:.9;}
.db-hero__btn--ghost{background:rgba(255,255,255,.1);backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.2);color:#fff;}
.db-hero__btn--primary{background:linear-gradient(135deg,#4f6ef7,#6366f1);color:#fff;box-shadow:0 2px 12px rgba(79,110,247,.4);}
.db-hero__mini-grid{display:grid;grid-template-columns:1fr 1fr;gap:.75rem;min-width:240px;}
.db-mini-stat{background:rgba(255,255,255,.08);backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.12);border-radius:.75rem;padding:.85rem 1rem;}
.db-mini-stat__val{font-size:1.5rem;font-weight:800;letter-spacing:-.04em;line-height:1;}
.db-mini-stat__lbl{font-size:.68rem;color:rgba(255,255,255,.55);text-transform:uppercase;letter-spacing:.05em;margin-top:.2rem;}
.db-mini-stat__dot{display:inline-block;width:6px;height:6px;border-radius:50%;margin-right:.3rem;vertical-align:middle;}

/* KPI */
.db-kpi{background:#fff;border-radius:var(--db-radius);box-shadow:var(--db-shadow);border:var(--db-border);padding:1.25rem 1.25rem 1rem;position:relative;overflow:hidden;transition:box-shadow .2s,transform .2s;}
.db-kpi:hover{box-shadow:var(--db-shadow-h);transform:translateY(-2px);}
.db-kpi__strip{position:absolute;top:0;left:0;right:0;height:3px;}
.db-kpi__icon{width:40px;height:40px;border-radius:.6rem;display:flex;align-items:center;justify-content:center;font-size:1rem;flex-shrink:0;}
.db-kpi__val{font-size:2rem;font-weight:800;letter-spacing:-.05em;line-height:1;margin:0;}
.db-kpi__lbl{font-size:.75rem;color:var(--db-muted);text-transform:uppercase;letter-spacing:.05em;margin-top:.2rem;}
.db-kpi__caption{font-size:.72rem;color:var(--db-muted);margin-top:.4rem;}

/* Card */
.db-card{background:#fff;border-radius:var(--db-radius);box-shadow:var(--db-shadow);border:var(--db-border);}
.db-card__head{padding:1.1rem 1.25rem .75rem;border-bottom:var(--db-border);display:flex;align-items:center;justify-content:space-between;gap:.75rem;}
.db-card__eyebrow{font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--db-muted);margin-bottom:.15rem;}
.db-card__title{font-size:.95rem;font-weight:700;color:var(--db-text);}
.db-card__body{padding:1.25rem;}
.db-card__tab-bar{display:flex;gap:.25rem;padding:.5rem .75rem;border-bottom:var(--db-border);}
.db-card__tab{background:none;border:none;padding:.3rem .7rem;border-radius:.4rem;font-size:.75rem;font-weight:600;color:var(--db-muted);cursor:pointer;transition:background .15s,color .15s;}
.db-card__tab.active,.db-card__tab:hover{background:#f1f5f9;color:var(--db-text);}

/* Section header */
.db-sh{display:flex;align-items:center;gap:.75rem;margin-bottom:1rem;}
.db-sh__pill{background:linear-gradient(135deg,var(--db-accent),#6366f1);color:#fff;border-radius:.35rem;width:4px;height:18px;flex-shrink:0;}
.db-sh__title{font-size:.95rem;font-weight:700;color:var(--db-text);letter-spacing:-.01em;}
.db-sh__actions{margin-left:auto;display:flex;gap:.5rem;}

/* Table */
.db-table{width:100%;border-collapse:collapse;}
.db-table thead th{font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--db-muted);padding:.55rem .85rem;background:#fafafa;border-bottom:2px solid #f1f5f9;}
.db-table tbody tr{transition:background .12s;cursor:pointer;}
.db-table tbody tr:hover{background:#fafbff;}
.db-table tbody td{font-size:.82rem;padding:.7rem .85rem;border-top:1px solid #f8fafc;vertical-align:middle;}
.db-table__num{font-weight:700;color:var(--db-text);}

/* Pills */
.db-pill{display:inline-flex;align-items:center;gap:.3rem;padding:.18rem .55rem;border-radius:2rem;font-size:.7rem;font-weight:600;}
.db-chip{display:inline-flex;align-items:center;gap:.3rem;padding:.2rem .6rem;border-radius:.35rem;font-size:.72rem;font-weight:600;}

/* Rank */
.db-rank{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;font-size:.68rem;font-weight:800;flex-shrink:0;}
.db-rank--1{background:linear-gradient(135deg,#fbbf24,#f59e0b);color:#78350f;}
.db-rank--2{background:linear-gradient(135deg,#d1d5db,#9ca3af);color:#374151;}
.db-rank--3{background:linear-gradient(135deg,#c97c4a,#b45309);color:#fff;}
.db-rank--n{background:#f1f5f9;color:var(--db-muted);}

/* Avatar */
.db-av{width:32px;height:32px;border-radius:.5rem;display:flex;align-items:center;justify-content:center;font-size:.68rem;font-weight:700;color:#fff;flex-shrink:0;}

/* Bar */
.db-bar-track{background:#f1f5f9;border-radius:2rem;height:6px;overflow:hidden;flex:1;}
.db-bar-fill{height:100%;border-radius:2rem;transition:width .7s cubic-bezier(.4,0,.2,1);}

/* B2B metric */
.db-b2b-card{background:#fff;border-radius:var(--db-radius);box-shadow:var(--db-shadow);border:var(--db-border);padding:1.1rem 1.15rem .9rem;position:relative;overflow:hidden;transition:box-shadow .2s,transform .2s;}
.db-b2b-card:hover{box-shadow:var(--db-shadow-h);transform:translateY(-2px);}
.db-b2b-card__bar{position:absolute;bottom:0;left:0;right:0;height:3px;}
.db-b2b-card__icon{font-size:.85rem;margin-bottom:.5rem;}
.db-b2b-card__label{font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--db-muted);margin-bottom:.2rem;}
.db-b2b-card__val{font-size:1.65rem;font-weight:800;letter-spacing:-.04em;line-height:1;}
.db-b2b-card__cap{font-size:.68rem;color:var(--db-muted);margin-top:.25rem;}

/* Gauge SVG */
.db-gauge-wrap{display:flex;flex-direction:column;align-items:center;gap:.35rem;}
.db-gauge-svg{transform:rotate(-90deg);}
.db-gauge-track{fill:none;stroke:#f1f5f9;stroke-width:10;stroke-linecap:round;}
.db-gauge-fill{fill:none;stroke-width:10;stroke-linecap:round;transition:stroke-dashoffset 1.2s cubic-bezier(.4,0,.2,1);}
.db-gauge-label{font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--db-muted);text-align:center;}
.db-gauge-val{font-size:1.1rem;font-weight:800;letter-spacing:-.03em;text-align:center;line-height:1;}

/* FTTH card */
.db-ftth-card{background:#fff;border-radius:var(--db-radius);box-shadow:var(--db-shadow);border:var(--db-border);padding:1rem 1.15rem;display:flex;align-items:flex-start;gap:.85rem;transition:box-shadow .2s,transform .2s;cursor:pointer;text-decoration:none;color:inherit;}
.db-ftth-card:hover{box-shadow:var(--db-shadow-h);transform:translateY(-2px);}
.db-ftth-card__icon{width:38px;height:38px;border-radius:.6rem;display:flex;align-items:center;justify-content:center;font-size:.9rem;flex-shrink:0;}

/* Action links */
.db-action-link{display:flex;align-items:center;gap:.75rem;padding:.75rem;border-radius:.65rem;text-decoration:none;color:var(--db-text);transition:background .15s;}
.db-action-link:hover{background:#f8fafc;}
.db-action-link__icon{width:36px;height:36px;border-radius:.5rem;display:flex;align-items:center;justify-content:center;font-size:.85rem;flex-shrink:0;}

/* Buttons */
.db-btn{display:inline-flex;align-items:center;gap:.4rem;padding:.4rem .85rem;border-radius:.5rem;font-size:.78rem;font-weight:600;border:none;cursor:pointer;text-decoration:none;transition:opacity .15s,transform .15s;}
.db-btn:hover{opacity:.88;transform:translateY(-1px);}
.db-btn--primary{background:linear-gradient(135deg,var(--db-accent),#6366f1);color:#fff;box-shadow:0 2px 10px rgba(79,110,247,.3);}
.db-btn--ghost{background:#f1f5f9;color:var(--db-text);}

/* Empty */
.db-empty{text-align:center;padding:2rem 1rem;color:var(--db-muted);}
.db-empty i{font-size:1.6rem;opacity:.35;display:block;margin-bottom:.5rem;}
.db-empty p{font-size:.8rem;margin:0;}

/* ── Filter bar ── */
.db-filter-bar{background:#fff;border-radius:var(--db-radius);box-shadow:var(--db-shadow);border:var(--db-border);padding:.7rem 1.25rem;display:flex;align-items:center;flex-wrap:wrap;gap:.5rem;}
.db-scope-banner{background:linear-gradient(135deg,#ecfeff 0%,#f8fafc 100%);border:1px solid #bae6fd;border-radius:var(--db-radius);box-shadow:var(--db-shadow);padding:.85rem 1.1rem;display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;color:#0f172a;}
.db-scope-banner__title{font-size:.8rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:#0f766e;margin-bottom:.2rem;}
.db-scope-banner__copy{font-size:.84rem;color:#475569;margin:0;}
.db-scope-banner__badge{display:inline-flex;align-items:center;gap:.45rem;padding:.45rem .8rem;border-radius:999px;background:#0f766e;color:#fff;font-size:.78rem;font-weight:700;}
.db-filter__sep{width:1px;height:18px;background:#e2e8f0;margin:0 .25rem;}
.db-filter__lbl{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--db-muted);white-space:nowrap;}
.db-filter__btn{padding:.28rem .7rem;border-radius:.4rem;font-size:.78rem;font-weight:600;border:1.5px solid #e2e8f0;background:#f8fafc;color:var(--db-muted);cursor:pointer;transition:all .15s;white-space:nowrap;}
.db-filter__btn:hover{border-color:var(--db-accent);color:var(--db-accent);}
.db-filter__btn.active{background:var(--db-accent);border-color:var(--db-accent);color:#fff;box-shadow:0 2px 8px rgba(79,110,247,.3);}
.db-filter__custom{display:none;align-items:center;gap:.4rem;flex-wrap:wrap;}
.db-filter__custom.show{display:flex;}
.db-filter__date{padding:.28rem .6rem;border-radius:.4rem;border:1.5px solid #e2e8f0;font-size:.78rem;color:var(--db-text);background:#f8fafc;outline:none;transition:border-color .15s;}
.db-filter__date:focus{border-color:var(--db-accent);}
.db-filter__apply{padding:.28rem .85rem;border-radius:.4rem;font-size:.78rem;font-weight:600;border:none;background:linear-gradient(135deg,var(--db-accent),#6366f1);color:#fff;cursor:pointer;box-shadow:0 2px 8px rgba(79,110,247,.3);}

/* ── Drag & drop sections ── */
.db-sortable{display:flex;flex-direction:column;gap:1.5rem;}
.db-section{position:relative;}
.db-section-handle{position:absolute;left:-28px;top:0;bottom:0;width:24px;display:flex;align-items:flex-start;justify-content:center;padding-top:.55rem;cursor:grab;color:#cbd5e1;font-size:1rem;opacity:0;transition:opacity .15s;user-select:none;z-index:5;}
.db-section-handle:active{cursor:grabbing;}
.db-section:hover>.db-section-handle{opacity:1;}
.db-section.sortable-chosen{opacity:.85;}
.db-section.sortable-ghost{opacity:.25;border:2px dashed var(--db-accent);border-radius:var(--db-radius);}
.db-section.sortable-drag{box-shadow:0 8px 32px rgba(79,110,247,.2);}

/* ── Width picker ── */
.db-col-wrap{position:relative;}
.db-col-wrap .db-width-btn{position:absolute;top:.55rem;right:.75rem;z-index:10;display:none;align-items:center;gap:.2rem;background:#fff;border:var(--db-border);border-radius:.45rem;box-shadow:var(--db-shadow);padding:.2rem .3rem;}
.db-card__head:hover~.db-width-btn,.db-width-btn:hover{display:flex!important;}
.db-col-wrap:hover .db-width-btn{display:flex;}
.db-w-opt{padding:.2rem .45rem;border-radius:.3rem;border:1.5px solid #e2e8f0;background:#f8fafc;font-size:.65rem;font-weight:700;cursor:pointer;color:var(--db-muted);transition:all .12s;white-space:nowrap;}
.db-w-opt:hover,.db-w-opt.active{background:var(--db-accent);border-color:var(--db-accent);color:#fff;}

/* ── Layout panel + widget controls ── */
.db-layout-panel{display:none;background:#fff;border-radius:var(--db-radius);box-shadow:var(--db-shadow);border:var(--db-border);padding:1rem 1.25rem;}
.db-layout-panel.show{display:block;}
.db-layout-panel__head{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-bottom:.85rem;flex-wrap:wrap;}
.db-layout-panel__title{font-size:.85rem;font-weight:700;color:var(--db-text);}
.db-layout-panel__hint{font-size:.72rem;color:var(--db-muted);}
.db-layout-panel__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:1rem;}
.db-layout-panel__group{border:1px solid #e2e8f0;border-radius:.8rem;padding:.85rem .9rem;background:#f8fafc;}
.db-layout-panel__group-title{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--db-muted);margin-bottom:.7rem;}
.db-layout-list{display:grid;gap:.45rem;}
.db-layout-item{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.45rem .6rem;border-radius:.55rem;background:#fff;border:1px solid #e2e8f0;}
.db-layout-item__label{font-size:.78rem;color:var(--db-text);font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.db-layout-item__meta{font-size:.66rem;color:var(--db-muted);text-transform:uppercase;letter-spacing:.05em;}
.db-layout-switch{display:inline-flex;align-items:center;gap:.45rem;font-size:.72rem;color:var(--db-muted);cursor:pointer;}
.db-layout-switch input{margin:0;cursor:pointer;}

.db-widget{position:relative;}
.db-widget-handle,.db-widget-toggle{position:absolute;top:.65rem;z-index:12;display:none;align-items:center;justify-content:center;width:30px;height:30px;border-radius:.5rem;border:1px solid #dbe4f0;background:rgba(255,255,255,.96);box-shadow:var(--db-shadow);color:#64748b;cursor:pointer;transition:all .12s;}
.db-widget-handle{left:.75rem;cursor:grab;}
.db-widget-handle:active{cursor:grabbing;}
.db-widget-toggle{left:2.95rem;}
.db-layout-on .db-widget-handle,.db-layout-on .db-widget-toggle{display:flex;}
.db-widget-handle:hover,.db-widget-toggle:hover{color:var(--db-accent);border-color:#c7d7fe;}
.db-widget.sortable-ghost{opacity:.35;outline:2px dashed rgba(79,110,247,.55);outline-offset:-6px;background:linear-gradient(135deg,rgba(79,110,247,.06),rgba(99,102,241,.1));border-radius:1rem;}
.db-widget.sortable-drag{box-shadow:0 10px 30px rgba(79,110,247,.18);transform:scale(.985);}
.db-item-hidden{display:none !important;}
.db-layout-on .db-widget{cursor:grab;}
.db-layout-on .db-widget:active{cursor:grabbing;}
.db-layout-on .db-card{pointer-events:none;user-select:none;}
.db-layout-on .db-card *{user-select:none;}
.db-layout-on .db-widget-toggle,.db-layout-on .db-width-btn,.db-layout-on .db-width-btn *,.db-layout-on .db-section-handle{pointer-events:auto;}
</style>

<div class="db-wrap">

<?php /* ── HERO ──────────────────────────────────────── */ ?>
<div class="db-hero">
  <div class="db-hero__orb db-hero__orb--a"></div>
  <div class="db-hero__orb db-hero__orb--b"></div>
  <div class="db-hero__orb db-hero__orb--c"></div>
  <div class="db-hero__inner">
    <div class="db-hero__left">
      <div class="db-hero__kicker"><i class="fas fa-signal"></i> FiberOps · Tableau de bord</div>
      <h1 class="db-hero__greeting"><?= htmlspecialchars($heroGreeting) ?>, <?= htmlspecialchars(explode(' ', $heroName)[0]) ?> <span style="opacity:.5;">👋</span></h1>
      <p class="db-hero__sub">Aperçu de vos opérations FTTH B2B en temps réel.</p>
      <div class="db-hero__meta">
        <span class="db-hero__chip"><i class="fas fa-clock"></i><?= date('d/m/Y · H\hi') ?></span>
        <span class="db-hero__chip"><i class="fas fa-user-shield"></i><?= htmlspecialchars(ucfirst($userRole)) ?></span>
        <?php if ($activeAssignedCity): ?>
        <span class="db-hero__chip"><i class="fas fa-location-dot"></i>Ville active: <?= htmlspecialchars($currentUser['assigned_city']) ?></span>
        <?php endif; ?>
        <?php if (($stats['active_techs'] ?? 0) > 0): ?>
        <span class="db-hero__chip"><i class="fas fa-circle" style="color:#4ade80;font-size:.45rem;"></i><?= (int)$stats['active_techs'] ?> techniciens actifs</span>
        <?php endif; ?>
      </div>
      <div class="db-hero__actions">
        <?php if ($showGlobalB2BInsights): ?>
        <a href="<?= route_url('/tickets') ?>" class="db-hero__btn db-hero__btn--primary"><i class="fas fa-ticket-simple"></i>Tickets</a>
        <?php endif; ?>
        <a href="<?= route_url('/users/profile') ?>" class="db-hero__btn db-hero__btn--ghost"><i class="fas fa-circle-user"></i>Profil</a>
      </div>
    </div>
    <div class="db-hero__mini-grid">
      <div class="db-mini-stat">
        <div class="db-mini-stat__val" style="color:#f87171;" data-counter="<?= (int)$stats['open'] ?>"><?= (int)$stats['open'] ?></div>
        <div class="db-mini-stat__lbl"><span class="db-mini-stat__dot" style="background:#f87171;"></span>Ouverts</div>
      </div>
      <div class="db-mini-stat">
        <div class="db-mini-stat__val" style="color:#60a5fa;" data-counter="<?= (int)$stats['in_progress'] ?>"><?= (int)$stats['in_progress'] ?></div>
        <div class="db-mini-stat__lbl"><span class="db-mini-stat__dot" style="background:#60a5fa;"></span>En cours</div>
      </div>
      <div class="db-mini-stat">
        <div class="db-mini-stat__val" style="color:#4ade80;" data-counter="<?= (int)$stats['resolved'] ?>"><?= (int)$stats['resolved'] ?></div>
        <div class="db-mini-stat__lbl"><span class="db-mini-stat__dot" style="background:#4ade80;"></span>Résolus</div>
      </div>
      <div class="db-mini-stat">
        <div class="db-mini-stat__val" style="color:#fbbf24;" data-counter="<?= (int)$stats['sla_breached'] ?>"><?= (int)$stats['sla_breached'] ?></div>
        <div class="db-mini-stat__lbl"><span class="db-mini-stat__dot" style="background:#fbbf24;"></span>SLA</div>
      </div>
    </div>
  </div>
</div>

<?php if ($activeAssignedCity): ?>
<div class="db-scope-banner">
  <div>
    <div class="db-scope-banner__title">Périmètre appliqué</div>
    <p class="db-scope-banner__copy">Les indicateurs FTTH, les classements et les listes affichés sur ce tableau de bord sont limités à votre ville de rattachement active.</p>
  </div>
  <span class="db-scope-banner__badge"><i class="fas fa-location-dot"></i><?= htmlspecialchars($currentUser['assigned_city']) ?></span>
</div>
<?php endif; ?>

<?php /* ── FILTER BAR ──────────────────────────────── */ ?>
<form method="get" action="" id="db-filter-form">
  <div class="db-filter-bar">
    <span class="db-filter__lbl"><i class="fas fa-calendar-alt me-1"></i>Période</span>
    <?php foreach ($chartAllowedPeriods as $p => $lbl): ?>
    <button type="submit" name="period" value="<?= $p ?>"
            class="db-filter__btn<?= ($chartPeriod == $p && !$chartIsCustom) ? ' active' : '' ?>">
      <?= htmlspecialchars($lbl) ?>
    </button>
    <?php endforeach; ?>
    <button type="button" class="db-filter__btn<?= $chartIsCustom ? ' active' : '' ?>" id="db-custom-toggle">
      <i class="fas fa-calendar-range me-1"></i>Personnalisé
    </button>
    <div class="db-filter__sep"></div>
    <div class="db-filter__custom<?= $chartIsCustom ? ' show' : '' ?>" id="db-custom-range">
      <input type="date" name="date_from" class="db-filter__date"
             value="<?= htmlspecialchars($chartDateFrom) ?>" max="<?= date('Y-m-d') ?>">
      <span class="db-filter__lbl">→</span>
      <input type="date" name="date_to" class="db-filter__date"
             value="<?= htmlspecialchars($chartDateTo) ?>" max="<?= date('Y-m-d') ?>">
      <input type="hidden" name="period" value="custom" id="db-custom-period-input"
             <?= $chartIsCustom ? '' : 'disabled' ?>>
      <button type="submit" class="db-filter__apply"><i class="fas fa-check me-1"></i>Appliquer</button>
    </div>
    <div class="ms-auto d-flex align-items-center gap-2">
      <span class="db-filter__lbl" style="color:#94a3b8;font-size:.65rem;">
        <?= htmlspecialchars(date('d/m/Y', strtotime($chartDateFrom))) ?>
        → <?= htmlspecialchars(date('d/m/Y', strtotime($chartDateTo))) ?>
      </span>
      <button type="button" id="db-layout-toggle" class="db-filter__btn" title="Mode édition layout">
        <i class="fas fa-grid-2"></i> Layout
      </button>
      <button type="button" id="db-layout-reset" class="db-filter__btn" title="Réinitialiser le layout">
        <i class="fas fa-rotate-left"></i> Réinitialiser
      </button>
    </div>
  </div>
</form>

<div id="db-layout-panel" class="db-layout-panel" hidden>
  <div class="db-layout-panel__head">
    <div>
      <div class="db-layout-panel__title">Personnalisation du dashboard</div>
      <div class="db-layout-panel__hint">Masquez les blocs inutiles et réorganisez les cartes par glisser-déposer. Les préférences sont enregistrées sur ce navigateur.</div>
    </div>
  </div>
  <div class="db-layout-panel__grid">
    <div class="db-layout-panel__group">
      <div class="db-layout-panel__group-title">Sections</div>
      <div id="db-layout-sections" class="db-layout-list"></div>
    </div>
    <div class="db-layout-panel__group">
      <div class="db-layout-panel__group-title">Blocs</div>
      <div id="db-layout-widgets" class="db-layout-list"></div>
    </div>
  </div>
</div>

<div id="db-sortable" class="db-sortable">

<?php /* ── KPI ROW ───────────────────────────────────── */ ?>
<div class="db-section" data-section-id="kpis" data-layout-label="Indicateurs KPI">
<span class="db-section-handle" title="Déplacer"><i class="fas fa-grip-vertical"></i></span>
<div class="row g-3" data-layout-row="row-kpis">
  <?php
  $kpiRows = [
    ['val'=>$stats['open'],         'lbl'=>'Ouverts',       'cap'=>'Requiert attention',  'color'=>'#ef4444','bg'=>'#fef2f2','grad'=>'linear-gradient(90deg,#ef4444,#f87171)','icon'=>'fa-circle-exclamation'],
    ['val'=>$stats['in_progress'],  'lbl'=>'En cours',      'cap'=>'Interventions actives','color'=>'#3b82f6','bg'=>'#eff6ff','grad'=>'linear-gradient(90deg,#3b82f6,#60a5fa)','icon'=>'fa-spinner'],
    ['val'=>$stats['resolved'],     'lbl'=>'Résolus',       'cap'=>'Ce mois-ci',          'color'=>'#10b981','bg'=>'#f0fdf4','grad'=>'linear-gradient(90deg,#10b981,#34d399)','icon'=>'fa-circle-check'],
    ['val'=>$stats['sla_breached'], 'lbl'=>'SLA dépassés',  'cap'=>'Urgence SLA',         'color'=>'#f59e0b','bg'=>'#fffbeb','grad'=>'linear-gradient(90deg,#f59e0b,#fbbf24)','icon'=>'fa-triangle-exclamation'],
    ['val'=>$stats['today_tickets'],'lbl'=>'Aujourd\'hui',  'cap'=>'Tickets du jour',     'color'=>'#8b5cf6','bg'=>'#f5f3ff','grad'=>'linear-gradient(90deg,#8b5cf6,#a78bfa)','icon'=>'fa-calendar-day'],
    ['val'=>$stats['active_techs'], 'lbl'=>'Techniciens',   'cap'=>'Actifs maintenant',   'color'=>'#14b8a6','bg'=>'#f0fdfa','grad'=>'linear-gradient(90deg,#14b8a6,#2dd4bf)','icon'=>'fa-users-gear'],
  ];
  ?>
  <?php foreach ($kpiRows as $kpi): ?>
  <div class="col-6 col-sm-4 col-xl-2 db-col-wrap db-widget" data-widget-id="kpi-<?= $kpi['icon'] ?>" data-layout-label="<?= htmlspecialchars($kpi['lbl']) ?>">
    <div class="db-kpi">
      <div class="db-kpi__strip" style="background:<?= $kpi['grad'] ?>;"></div>
      <div class="d-flex align-items-center gap-2 mb-2 mt-1">
        <div class="db-kpi__icon" style="background:<?= $kpi['bg'] ?>;color:<?= $kpi['color'] ?>;"><i class="fas <?= $kpi['icon'] ?>"></i></div>
      </div>
      <p class="db-kpi__val" style="color:<?= $kpi['color'] ?>;" data-counter="<?= (int)$kpi['val'] ?>"><?= (int)$kpi['val'] ?></p>
      <p class="db-kpi__lbl"><?= htmlspecialchars($kpi['lbl']) ?></p>
      <p class="db-kpi__caption"><?= htmlspecialchars($kpi['cap']) ?></p>
    </div>
  </div>
  <?php endforeach; ?>
</div>
</div><!-- /section kpis -->

<?php /* ── B2B COMMAND ─────────────────────────────── */ ?>
<?php if ($showGlobalB2BInsights): ?>
<div class="db-section" data-section-id="b2b" data-layout-label="Commande B2B">
<span class="db-section-handle" title="Déplacer"><i class="fas fa-grip-vertical"></i></span>
<div>
  <div class="db-sh">
    <div class="db-sh__pill"></div>
    <span class="db-sh__title">Commande B2B</span>
    <div class="db-sh__actions"><a href="<?= route_url('/tickets') ?>" class="db-btn db-btn--ghost"><i class="fas fa-arrow-right"></i>Voir tout</a></div>
  </div>
  <div class="row g-3" data-layout-row="row-b2b">
    <?php
    $b2bCards = [
      ['label'=>'Total tickets',       'val'=>$b2bMetrics['total_tickets'],   'icon'=>'fa-ticket-simple',  'color'=>'#4f6ef7','bg'=>'#eef2ff','bar'=>'linear-gradient(90deg,#4f6ef7,#6366f1)','cap'=>'Ensemble du parc'],
      ['label'=>'Non assignés',        'val'=>$b2bMetrics['unassigned'],      'icon'=>'fa-user-slash',     'color'=>'#ef4444','bg'=>'#fef2f2','bar'=>'linear-gradient(90deg,#ef4444,#f87171)','cap'=>'À affecter'],
      ['label'=>'En cours',            'val'=>$b2bMetrics['in_progress'],     'icon'=>'fa-bolt',           'color'=>'#0ea5e9','bg'=>'#f0f9ff','bar'=>'linear-gradient(90deg,#0ea5e9,#38bdf8)','cap'=>'Technicien sur site'],
      ['label'=>'Validation N+1',      'val'=>$b2bMetrics['awaiting_validation'],'icon'=>'fa-hourglass-half','color'=>'#f59e0b','bg'=>'#fffbeb','bar'=>'linear-gradient(90deg,#f59e0b,#fbbf24)','cap'=>'En attente retour'],
      ['label'=>'Urgents ouverts',     'val'=>$b2bMetrics['urgent_open'],     'icon'=>'fa-siren-on',       'color'=>'#b91c1c','bg'=>'#fef2f2','bar'=>'linear-gradient(90deg,#b91c1c,#ef4444)','cap'=>'Priorité critique'],
      ['label'=>'Validés aujourd\'hui','val'=>$b2bMetrics['validated_today'], 'icon'=>'fa-badge-check',    'color'=>'#10b981','bg'=>'#f0fdf4','bar'=>'linear-gradient(90deg,#10b981,#34d399)','cap'=>'Clôturés ce jour'],
      ['label'=>'Taux rétablissement', 'val'=>number_format((float)$b2bMetrics['service_restored_rate'],1).'%','icon'=>'fa-chart-line','color'=>'#8b5cf6','bg'=>'#f5f3ff','bar'=>'linear-gradient(90deg,#8b5cf6,#a78bfa)','cap'=>'Service rétabli'],
      ['label'=>'Délai moyen assign.', 'val'=>round($b2bMetrics['avg_assignment_delay_hours'],1).'h','icon'=>'fa-timer','color'=>'#14b8a6','bg'=>'#f0fdfa','bar'=>'linear-gradient(90deg,#14b8a6,#2dd4bf)','cap'=>'Ouverture → Assignation'],
    ];
    ?>
    <?php foreach ($b2bCards as $bc): ?>
    <div class="col-6 col-sm-4 col-xl-3 db-col-wrap db-widget" data-widget-id="b2b-card-<?= $bc['icon'] ?>" data-layout-label="<?= htmlspecialchars($bc['label']) ?>">
      <div class="db-b2b-card">
        <div class="db-b2b-card__bar" style="background:<?= $bc['bar'] ?>;"></div>
        <div class="db-b2b-card__icon" style="color:<?= $bc['color'] ?>;"><i class="fas <?= $bc['icon'] ?>"></i></div>
        <div class="db-b2b-card__label"><?= htmlspecialchars($bc['label']) ?></div>
        <div class="db-b2b-card__val" style="color:<?= $bc['color'] ?>;"><?= htmlspecialchars((string)$bc['val']) ?></div>
        <div class="db-b2b-card__cap"><?= htmlspecialchars($bc['cap']) ?></div>
      </div>
    </div>
    <?php endforeach; ?>
  </div>
</div>
</div><!-- /section b2b -->
<?php endif; ?>

<?php if ($showGlobalB2BInsights && ($raccordementModuleVisible || $otbModuleVisible)): ?>
<div class="db-section" data-section-id="new-modules" data-layout-label="Nouveaux modules">
<span class="db-section-handle" title="Déplacer"><i class="fas fa-grip-vertical"></i></span>
<div>
  <div class="db-sh">
    <div class="db-sh__pill"></div>
    <span class="db-sh__title">Nouveaux modules</span>
    <div class="db-sh__actions">
      <?php if ($raccordementModuleVisible): ?>
      <a href="<?= route_url('/raccordement-clients') ?>" class="db-btn db-btn--ghost"><i class="fas fa-diagram-project"></i>Raccordement</a>
      <?php endif; ?>
      <?php if ($otbModuleVisible): ?>
      <a href="<?= route_url('/otb-management') ?>" class="db-btn db-btn--ghost"><i class="fas fa-box"></i>Boîtiers OTB</a>
      <?php endif; ?>
    </div>
  </div>
  <div class="row g-3" data-layout-row="row-new-modules">
    <?php
    $moduleCards = [];
    if ($raccordementModuleVisible) {
      $moduleCards[] = ['label'=>'Demandes raccordement', 'val'=>$moduleMetrics['raccordement_total'], 'icon'=>'fa-diagram-project', 'color'=>'#4f46e5', 'bg'=>'#eef2ff', 'bar'=>'linear-gradient(90deg,#4f46e5,#6366f1)', 'cap'=>'Période sélectionnée'];
      $moduleCards[] = ['label'=>'Études à finaliser', 'val'=>$moduleMetrics['raccordement_pending_study'], 'icon'=>'fa-compass-drafting', 'color'=>'#0ea5e9', 'bg'=>'#f0f9ff', 'bar'=>'linear-gradient(90deg,#0ea5e9,#38bdf8)', 'cap'=>'Phase étude active'];
      $moduleCards[] = ['label'=>'Installations terrain', 'val'=>$moduleMetrics['raccordement_pending_installation'], 'icon'=>'fa-person-digging', 'color'=>'#14b8a6', 'bg'=>'#f0fdfa', 'bar'=>'linear-gradient(90deg,#14b8a6,#2dd4bf)', 'cap'=>'En phase raccordement'];
      $moduleCards[] = ['label'=>'Validation raccordement', 'val'=>$moduleMetrics['raccordement_waiting_validation'], 'icon'=>'fa-hourglass-half', 'color'=>'#f59e0b', 'bg'=>'#fffbeb', 'bar'=>'linear-gradient(90deg,#f59e0b,#fbbf24)', 'cap'=>'Soumis au N+1'];
      $moduleCards[] = ['label'=>'Raccordements validés', 'val'=>$moduleMetrics['raccordement_validated'], 'icon'=>'fa-circle-check', 'color'=>'#10b981', 'bg'=>'#f0fdf4', 'bar'=>'linear-gradient(90deg,#10b981,#34d399)', 'cap'=>'Sur la période'];
    }
    if ($otbModuleVisible) {
      $moduleCards[] = ['label'=>'Boîtiers OTB', 'val'=>$moduleMetrics['otb_total_boxes'], 'icon'=>'fa-box', 'color'=>'#8b5cf6', 'bg'=>'#f5f3ff', 'bar'=>'linear-gradient(90deg,#8b5cf6,#a78bfa)', 'cap'=>'Référentiel global'];
      $moduleCards[] = ['label'=>'Boîtiers en alerte', 'val'=>$moduleMetrics['otb_alert_boxes'], 'icon'=>'fa-triangle-exclamation', 'color'=>'#ef4444', 'bg'=>'#fef2f2', 'bar'=>'linear-gradient(90deg,#ef4444,#f87171)', 'cap'=>'Seuil atteint'];
      $moduleCards[] = ['label'=>'Occupation OTB', 'val'=>number_format((float)$moduleMetrics['otb_occupancy_rate'],1).'%','icon'=>'fa-gauge-high', 'color'=>'#0891b2', 'bg'=>'#ecfeff', 'bar'=>'linear-gradient(90deg,#0891b2,#06b6d4)', 'cap'=>(int)($moduleMetrics['otb_saturated_boxes'] ?? 0) . ' boîtier(s) saturé(s)'];
    }
    ?>
    <?php foreach ($moduleCards as $card): ?>
    <div class="col-6 col-sm-4 col-xl-3 db-col-wrap db-widget" data-widget-id="module-card-<?= $card['icon'] ?>" data-layout-label="<?= htmlspecialchars($card['label']) ?>">
      <div class="db-b2b-card h-100">
        <div class="db-b2b-card__bar" style="background:<?= $card['bar'] ?>;"></div>
        <div class="db-b2b-card__icon" style="color:<?= $card['color'] ?>;"><i class="fas <?= $card['icon'] ?>"></i></div>
        <div class="db-b2b-card__label"><?= htmlspecialchars($card['label']) ?></div>
        <div class="db-b2b-card__val" style="color:<?= $card['color'] ?>;"><?= htmlspecialchars((string)$card['val']) ?></div>
        <div class="db-b2b-card__cap"><?= htmlspecialchars($card['cap']) ?></div>
      </div>
    </div>
    <?php endforeach; ?>
  </div>
</div>
</div><!-- /section new-modules -->
<?php endif; ?>

<?php /* ── E-INTERVENTION ─────────────────────────── */ ?>
<?php if ($showGlobalB2BInsights): ?>
<div class="db-section" data-section-id="eintervention" data-layout-label="Demandes e-Intervention">
<span class="db-section-handle" title="Déplacer"><i class="fas fa-grip-vertical"></i></span>
<div>
  <div class="db-sh">
    <div class="db-sh__pill"></div>
    <span class="db-sh__title">Demandes e-Intervention</span>
  </div>
  <div class="row g-3" data-layout-row="row-ei-metrics">
    <?php
    $eInterventionCards = [
      ['label'=>'Demandes reçues', 'val'=>$eInterventionMetrics['total_requests'], 'icon'=>'fa-mobile-screen-button', 'color'=>'#0ea5e9', 'bar'=>'linear-gradient(90deg,#0ea5e9,#38bdf8)', 'cap'=>'Historique cumulé'],
      ['label'=>'Demandes du jour', 'val'=>$eInterventionMetrics['requests_today'], 'icon'=>'fa-calendar-day', 'color'=>'#8b5cf6', 'bar'=>'linear-gradient(90deg,#8b5cf6,#a78bfa)', 'cap'=>'Nouvelles déclarations'],
      ['label'=>'À prendre en charge', 'val'=>$eInterventionMetrics['pending_intake'], 'icon'=>'fa-headset', 'color'=>'#f59e0b', 'bar'=>'linear-gradient(90deg,#f59e0b,#fbbf24)', 'cap'=>'Service client / opérateur'],
      ['label'=>'Assignées terrain', 'val'=>$eInterventionMetrics['assigned_field'], 'icon'=>'fa-user-check', 'color'=>'#14b8a6', 'bar'=>'linear-gradient(90deg,#14b8a6,#2dd4bf)', 'cap'=>'Transmises aux techniciens'],
      ['label'=>'Résolues', 'val'=>$eInterventionMetrics['resolved'], 'icon'=>'fa-circle-check', 'color'=>'#10b981', 'bar'=>'linear-gradient(90deg,#10b981,#34d399)', 'cap'=>'Clôture côté client'],
    ];
    ?>
    <?php foreach ($eInterventionCards as $ec): ?>
    <div class="col-6 col-sm-4 col-xl db-col-wrap db-widget" data-widget-id="ei-metric-<?= $ec['icon'] ?>" data-layout-label="<?= htmlspecialchars($ec['label']) ?>">
      <div class="db-b2b-card h-100">
        <div class="db-b2b-card__bar" style="background:<?= $ec['bar'] ?>;"></div>
        <div class="db-b2b-card__icon" style="color:<?= $ec['color'] ?>;"><i class="fas <?= $ec['icon'] ?>"></i></div>
        <div class="db-b2b-card__label"><?= htmlspecialchars($ec['label']) ?></div>
        <div class="db-b2b-card__val" style="color:<?= $ec['color'] ?>;"><?= (int)$ec['val'] ?></div>
        <div class="db-b2b-card__cap"><?= htmlspecialchars($ec['cap']) ?></div>
      </div>
    </div>
    <?php endforeach; ?>
  </div>
  <div class="row g-3 mt-1" data-layout-row="row-ei-details">
    <div class="col-12 col-xl-7 db-col-wrap db-widget" data-widget-id="ei-chart" data-layout-label="Distribution des demandes e-Intervention">
      <div class="db-card h-100">
        <div class="db-card__head">
          <div>
            <div class="db-card__eyebrow">Visualisation</div>
            <div class="db-card__title">Distribution des demandes e-Intervention</div>
          </div>
        </div>
        <div class="db-card__body">
          <canvas id="chartEIntervention" height="180"></canvas>
        </div>
      </div>
    </div>
    <div class="col-12 col-xl-5 db-col-wrap db-widget" data-widget-id="ei-summary" data-layout-label="Canal client public">
      <div class="db-card h-100">
        <div class="db-card__head">
          <div>
            <div class="db-card__eyebrow">Lecture rapide</div>
            <div class="db-card__title">Canal client public</div>
          </div>
        </div>
        <div class="db-card__body">
          <div class="db-empty" style="padding:1rem 0 0; text-align:left;">
            <p>Le graphique met en évidence le volume global, la charge du jour, les demandes encore à prendre en charge par l'opérateur, celles déjà transmises au terrain et celles résolues côté client.</p>
            <p style="margin-top:.75rem;">Utilisez-le pour suivre le poids réel du canal e-Intervention dans le portefeuille FTTH B2B.</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
</div><!-- /section eintervention -->
<?php endif; ?>

<?php /* ── ROW : HISTOGRAM + DOUGHNUT + GAUGES ─────── */ ?>
<div class="db-section" data-section-id="charts" data-layout-label="Graphiques et jauges">
<span class="db-section-handle" title="Déplacer"><i class="fas fa-grip-vertical"></i></span>
<div class="row g-3" data-layout-row="row-charts">

  <!-- Histogramme tickets (7 derniers jours) -->
  <div class="col-12 col-xl-6 db-col-wrap db-widget" data-col-id="col-chart-bar" data-widget-id="chart-bar" data-layout-label="Tickets — 7 derniers jours">
    <div class="db-width-btn"><span class="db-filter__lbl me-1" style="font-size:.6rem;">Largeur</span><?php foreach([['col-xl-12','Full'],['col-xl-8','¾'],['col-xl-6','½'],['col-xl-4','⅓']] as [$cls,$lbl]): ?><button class="db-w-opt" data-col-class="<?= $cls ?>"><?= $lbl ?></button><?php endforeach; ?></div>
    <div class="db-card h-100">
      <div class="db-card__head">
        <div>
          <div class="db-card__eyebrow">Évolution</div>
          <div class="db-card__title">Tickets — 7 derniers jours</div>
        </div>
        <div style="font-size:.72rem;color:var(--db-muted);">
          <?php
            $pLabel = $chartIsCustom ? date('d/m', strtotime($chartDateFrom)).'→'.date('d/m', strtotime($chartDateTo))
                    : ($chartAllowedPeriods[$chartPeriod] ?? $chartPeriod.'j');
          ?>
          <i class="fas fa-calendar-alt me-1"></i><?= htmlspecialchars($pLabel) ?>
        </div>
      </div>
      <div class="db-card__body">
        <canvas id="chartBar" height="210"></canvas>
      </div>
    </div>
  </div>

  <!-- Doughnut statuts -->
  <div class="col-12 col-sm-6 col-xl-3 db-col-wrap db-widget" data-col-id="col-doughnut" data-widget-id="chart-doughnut" data-layout-label="Répartition par statut">
    <div class="db-width-btn"><?php foreach([['col-xl-6','½'],['col-xl-4','⅓'],['col-xl-3','¼']] as [$cls,$lbl]): ?><button class="db-w-opt" data-col-class="<?= $cls ?>"><?= $lbl ?></button><?php endforeach; ?></div>
    <div class="db-card h-100">
      <div class="db-card__head">
        <div>
          <div class="db-card__eyebrow">Répartition</div>
          <div class="db-card__title">Par statut</div>
        </div>
      </div>
      <div class="db-card__body d-flex flex-column align-items-center" style="gap:.75rem;">
        <div style="position:relative;width:160px;height:160px;flex-shrink:0;">
          <canvas id="chartDoughnut" width="160" height="160"></canvas>
          <div style="position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;pointer-events:none;">
            <span style="font-size:1.5rem;font-weight:800;color:var(--db-text);" data-counter="<?= $slaTotal ?>"><?= $slaTotal ?></span>
            <span style="font-size:.65rem;color:var(--db-muted);text-transform:uppercase;letter-spacing:.05em;">total</span>
          </div>
        </div>
        <div class="w-100" style="font-size:.75rem;">
          <?php foreach (($statusData['labels'] ?? []) as $si => $slbl): ?>
          <div class="d-flex align-items-center gap-2 mb-1">
            <span style="width:8px;height:8px;border-radius:50%;background:<?= htmlspecialchars($statusData['colors'][$si] ?? '#ccc') ?>;flex-shrink:0;"></span>
            <span class="flex-grow-1" style="color:var(--db-muted);"><?= htmlspecialchars($slbl) ?></span>
            <span style="font-weight:700;"><?= (int)($statusData['data'][$si] ?? 0) ?></span>
          </div>
          <?php endforeach; ?>
        </div>
      </div>
    </div>
  </div>

  <!-- Jauges animées -->
  <div class="col-12 col-sm-6 col-xl-3 db-col-wrap db-widget" data-col-id="col-gauges" data-widget-id="chart-gauges" data-layout-label="Jauges indicateurs clés">
    <div class="db-width-btn"><?php foreach([['col-xl-6','½'],['col-xl-4','⅓'],['col-xl-3','¼']] as [$cls,$lbl]): ?><button class="db-w-opt" data-col-class="<?= $cls ?>"><?= $lbl ?></button><?php endforeach; ?></div>
    <div class="db-card h-100">
      <div class="db-card__head">
        <div>
          <div class="db-card__eyebrow">Indicateurs clés</div>
          <div class="db-card__title">Jauges</div>
        </div>
      </div>
      <div class="db-card__body d-flex flex-column justify-content-around gap-3">

        <!-- Gauge SLA -->
        <?php $c = 2 * M_PI * 45; $off = $c * (1 - $slaPct/100); ?>
        <div class="db-gauge-wrap">
          <svg class="db-gauge-svg" width="110" height="110" viewBox="0 0 110 110">
            <circle class="db-gauge-track" cx="55" cy="55" r="45"/>
            <circle class="db-gauge-fill" cx="55" cy="55" r="45"
                    stroke="<?= $slaPct >= 80 ? '#10b981' : ($slaPct >= 50 ? '#f59e0b' : '#ef4444') ?>"
                    stroke-dasharray="<?= round($c,2) ?>"
                    stroke-dashoffset="<?= round($c,2) ?>"
                    data-dash-offset="<?= round($off,2) ?>"
                    id="gaugeSla"/>
            <text transform="rotate(90,55,55)" x="55" y="59" text-anchor="middle"
                  style="font-size:16px;font-weight:800;fill:var(--db-text);font-family:inherit;"><?= $slaPct ?>%</text>
          </svg>
          <div class="db-gauge-label">Respect SLA</div>
        </div>

        <!-- Gauge résolution -->
        <?php $offR = $c * (1 - $resPct/100); ?>
        <div class="db-gauge-wrap">
          <svg class="db-gauge-svg" width="110" height="110" viewBox="0 0 110 110">
            <circle class="db-gauge-track" cx="55" cy="55" r="45"/>
            <circle class="db-gauge-fill" cx="55" cy="55" r="45"
                    stroke="#10b981"
                    stroke-dasharray="<?= round($c,2) ?>"
                    stroke-dashoffset="<?= round($c,2) ?>"
                    data-dash-offset="<?= round($offR,2) ?>"
                    id="gaugeRes"/>
            <text transform="rotate(90,55,55)" x="55" y="59" text-anchor="middle"
                  style="font-size:16px;font-weight:800;fill:var(--db-text);font-family:inherit;"><?= $resPct ?>%</text>
          </svg>
          <div class="db-gauge-label">Taux résolution</div>
        </div>

        <!-- Gauge tickets ouverts -->
        <?php $offO = $c * (1 - $openPct/100); ?>
        <div class="db-gauge-wrap">
          <svg class="db-gauge-svg" width="110" height="110" viewBox="0 0 110 110">
            <circle class="db-gauge-track" cx="55" cy="55" r="45"/>
            <circle class="db-gauge-fill" cx="55" cy="55" r="45"
                    stroke="#ef4444"
                    stroke-dasharray="<?= round($c,2) ?>"
                    stroke-dashoffset="<?= round($c,2) ?>"
                    data-dash-offset="<?= round($offO,2) ?>"
                    id="gaugeOpen"/>
            <text transform="rotate(90,55,55)" x="55" y="59" text-anchor="middle"
                  style="font-size:16px;font-weight:800;fill:var(--db-text);font-family:inherit;"><?= $openPct ?>%</text>
          </svg>
          <div class="db-gauge-label">Part ouverts</div>
        </div>

      </div>
    </div>
  </div>
</div>
</div><!-- /section charts -->

<?php /* ── ROW : DÉLAIS + INCIDENTS + TOP TECHS ───── */ ?>
<div class="db-section" data-section-id="activity" data-layout-label="Activité et performance">
<span class="db-section-handle" title="Déplacer"><i class="fas fa-grip-vertical"></i></span>
<div class="row g-3" data-layout-row="row-activity">

  <!-- Cycle délais -->
  <div class="col-12 col-sm-6 col-xl-3 db-col-wrap db-widget" data-col-id="col-cycle" data-widget-id="activity-cycle" data-layout-label="Cycle terrain">
    <div class="db-width-btn"><?php foreach([['col-xl-6','½'],['col-xl-4','⅓'],['col-xl-3','¼']] as [$cls,$lbl]): ?><button class="db-w-opt" data-col-class="<?= $cls ?>"><?= $lbl ?></button><?php endforeach; ?></div>
    <div class="db-card h-100">
      <div class="db-card__head">
        <div>
          <div class="db-card__eyebrow">Délais moyens</div>
          <div class="db-card__title">Cycle terrain</div>
        </div>
      </div>
      <div class="db-card__body d-flex flex-column gap-3">
        <?php
        $cycleItems = [
          ['label'=>'Ouvert → Assigné',    'val'=>$interventionMetrics['open_to_assigned'],          'color'=>'#4f6ef7'],
          ['label'=>'Assigné → Interv.',   'val'=>$interventionMetrics['assigned_to_intervention'],  'color'=>'#0ea5e9'],
          ['label'=>'Interv. → Résolu',    'val'=>$interventionMetrics['intervention_to_resolution'],'color'=>'#10b981'],
        ];
        $cycleMax = max(1, max(array_column($cycleItems,'val')));
        ?>
        <?php foreach ($cycleItems as $ci): ?>
        <div>
          <div class="d-flex justify-content-between mb-1">
            <span style="font-size:.72rem;color:var(--db-muted);"><?= htmlspecialchars($ci['label']) ?></span>
            <span style="font-size:.78rem;font-weight:700;color:<?= $ci['color'] ?>;"><?= round($ci['val'],1) ?>h</span>
          </div>
          <div class="db-bar-track">
            <div class="db-bar-fill" style="background:<?= $ci['color'] ?>;width:0;"
                 data-target-width="<?= min(100, $cycleMax > 0 ? round($ci['val']/$cycleMax*100) : 0) ?>%"></div>
          </div>
        </div>
        <?php endforeach; ?>
        <div style="margin-top:auto;padding-top:.75rem;border-top:var(--db-border);">
          <div style="font-size:.68rem;color:var(--db-muted);text-transform:uppercase;letter-spacing:.05em;">Total moyen</div>
          <div style="font-size:1.5rem;font-weight:800;color:var(--db-text);" data-counter="<?= round(array_sum(array_column($cycleItems,'val')),0) ?>"><?= round(array_sum(array_column($cycleItems,'val')),1) ?>h</div>
        </div>
        <!-- Mini bar chart délais -->
        <canvas id="chartCycle" height="80"></canvas>
      </div>
    </div>
  </div>

  <!-- Incidents récents -->
  <div class="col-12 col-xl-5 db-col-wrap db-widget" data-col-id="col-incidents" data-widget-id="activity-incidents" data-layout-label="Incidents récents">
    <div class="db-width-btn"><?php foreach([['col-xl-12','Full'],['col-xl-8','⅔'],['col-xl-5','½'],['col-xl-4','⅓']] as [$cls,$lbl]): ?><button class="db-w-opt" data-col-class="<?= $cls ?>"><?= $lbl ?></button><?php endforeach; ?></div>
    <div class="db-card h-100">
      <div class="db-card__head">
        <div>
          <div class="db-card__eyebrow">Activité</div>
          <div class="db-card__title">Incidents récents</div>
        </div>
        <?php if ($showGlobalB2BInsights): ?>
        <a href="<?= route_url('/tickets') ?>" class="db-btn db-btn--ghost" style="font-size:.72rem;padding:.3rem .65rem;"><i class="fas fa-arrow-right"></i>Tout voir</a>
        <?php endif; ?>
      </div>
      <div style="overflow-x:auto;">
        <?php if (empty($recentIncidents)): ?>
        <div class="db-empty"><i class="fas fa-inbox"></i><p>Aucun incident récent</p></div>
        <?php else: ?>
        <table class="db-table">
          <thead>
            <tr><th>Ticket</th><th>Titre</th><th>Priorité</th><th>Màj</th></tr>
          </thead>
          <tbody>
            <?php foreach (array_slice($recentIncidents, 0, 10) as $inc):
              $pri     = $inc['priority'] ?? 'Basse';
              $tone    = $priorityToneMap[$pri] ?? $defaultPriTone;
              $isFtth  = ($inc['_source'] ?? '') === 'ftth';
              $dateRef = $inc['updated_at'] ?? $inc['declared_at'] ?? null;
            ?>
            <tr class="incident-row" data-id="<?= (int)($inc['id'] ?? 0) ?>" data-source="<?= $isFtth ? 'ftth' : 'backbone' ?>">
              <td>
                <span style="font-size:.72rem;color:var(--db-muted);font-weight:700;">#<?= htmlspecialchars($inc['ticket_id'] ?? '') ?></span>
                <?php if ($isFtth): ?>
                <span class="db-pill ms-1" style="background:#e0f2fe;color:#0369a1;font-size:.62rem;padding:.1rem .4rem;"><i class="fas fa-network-wired" style="font-size:.55rem;"></i> FTTH</span>
                <?php endif; ?>
              </td>
              <td style="max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;"><?= htmlspecialchars($inc['title'] ?? '') ?></td>
              <td><span class="db-chip" style="background:<?= $tone['bg'] ?>;color:<?= $tone['color'] ?>;"><?= htmlspecialchars($pri) ?></span></td>
              <td style="white-space:nowrap;color:var(--db-muted);font-size:.75rem;"><?= $dateRef ? date('d/m H\hi', strtotime($dateRef)) : '—' ?></td>
            </tr>
            <?php endforeach; ?>
          </tbody>
        </table>
        <?php endif; ?>
      </div>
    </div>
  </div>

  <!-- Top techniciens -->
  <?php if ($showGlobalB2BInsights): ?>
  <div class="col-12 col-xl-4 db-col-wrap db-widget" data-col-id="col-technicians" data-widget-id="activity-technicians" data-layout-label="Performance techniciens">
    <div class="db-width-btn"><?php foreach([['col-xl-12','Full'],['col-xl-6','½'],['col-xl-4','⅓']] as [$cls,$lbl]): ?><button class="db-w-opt" data-col-class="<?= $cls ?>"><?= $lbl ?></button><?php endforeach; ?></div>
    <div class="db-card h-100">
      <div class="db-card__head">
        <div>
          <div class="db-card__eyebrow">Performance</div>
          <div class="db-card__title">Performance techniciens</div>
        </div>
      </div>
      <?php if (empty($topTechnicians)): ?>
      <div class="db-card__body" style="text-align:center;color:var(--db-muted);padding:2rem 1rem;">
        <i class="fas fa-user-hard-hat" style="font-size:2rem;opacity:.3;display:block;margin-bottom:.75rem;"></i>
        <div style="font-size:.85rem;">Aucun technicien actif trouvé</div>
      </div>
      <?php else: ?>
      <div style="overflow-x:auto;">
        <table class="db-table">
          <thead>
            <tr>
              <th>#</th>
              <th>Technicien</th>
              <th style="text-align:center;">
                <div style="font-size:.7rem;font-weight:700;color:#4f6ef7;">Incidents</div>
                <div style="font-size:.6rem;color:var(--db-muted);font-weight:400;">Total · EnCours · Clôt.</div>
              </th>
              <th style="text-align:center;">
                <div style="font-size:.7rem;font-weight:700;color:#0ea5e9;">FTTH</div>
                <div style="font-size:.6rem;color:var(--db-muted);font-weight:400;">Total · EnCours · Clôt.</div>
              </th>
              <th>Score</th>
            </tr>
          </thead>
          <tbody>
            <?php foreach (array_slice($topTechnicians, 0, 7) as $ri => $tech):
              $tBg = $avatarPalette[($tech['id'] ?? $ri) % count($avatarPalette)];
              $rankCls = $ri===0?'db-rank--1':($ri===1?'db-rank--2':($ri===2?'db-rank--3':'db-rank--n'));
              $incTotal     = (int)($tech['total_incidents_count'] ?? 0);
              $incProgress  = (int)($tech['in_progress_incidents_count'] ?? 0);
              $incClosed    = (int)($tech['closed_incidents_count'] ?? 0);
              $ftthTotal    = (int)($tech['assigned_count'] ?? 0);
              $ftthProgress = (int)($tech['in_progress_count'] ?? 0);
              $ftthClosed   = (int)($tech['closed_count'] ?? 0);
            ?>
            <tr>
              <td><span class="db-rank <?= $rankCls ?>"><?= $ri+1 ?></span></td>
              <td>
                <div class="d-flex align-items-center gap-2">
                  <div class="db-av" style="background:<?= $tBg ?>;"><?= htmlspecialchars($buildInitials($tech['name'] ?? '')) ?></div>
                  <span style="font-size:.82rem;font-weight:600;"><?= htmlspecialchars($tech['name'] ?? '') ?></span>
                </div>
              </td>
              <td style="text-align:center;">
                <div class="db-table__num" style="color:#4f6ef7;"><?= $incTotal ?></div>
                <div style="font-size:.67rem;color:var(--db-muted);">
                  <span title="En cours" style="color:#f59e0b;">&#9679; <?= $incProgress ?></span>
                  &nbsp;
                  <span title="Clôturés" style="color:#10b981;">&#10003; <?= $incClosed ?></span>
                </div>
              </td>
              <td style="text-align:center;">
                <div class="db-table__num" style="color:#0ea5e9;"><?= $ftthTotal ?></div>
                <div style="font-size:.67rem;color:var(--db-muted);">
                  <span title="En cours" style="color:#f59e0b;">&#9679; <?= $ftthProgress ?></span>
                  &nbsp;
                  <span title="Clôturés" style="color:#10b981;">&#10003; <?= $ftthClosed ?></span>
                </div>
              </td>
              <td><span class="db-chip" style="background:#f0fdf4;color:#15803d;"><?= (int)($tech['score'] ?? 0) ?></span></td>
            </tr>
            <?php endforeach; ?>
          </tbody>
        </table>
      </div>
      <!-- Histogram scores techniciens -->
      <div style="padding:1rem 1.25rem .75rem;border-top:var(--db-border);">
        <div style="font-size:.72rem;color:var(--db-muted);margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em;">Courbe de performance incidents + FTTH</div>
        <canvas id="chartTechScores" height="110"></canvas>
      </div>
      <?php endif; ?>
    </div>
  </div>
  <?php else: ?>
  <!-- Performance technicien / accès rapides -->
  <div class="col-12 col-xl-4 db-col-wrap db-widget" data-col-id="col-quicklinks" data-widget-id="activity-quicklinks" data-layout-label="<?= htmlspecialchars($isTechnicianDashboard ? 'Ma performance terrain' : 'Accès rapides') ?>">
    <div class="db-width-btn"><?php foreach([['col-xl-12','Full'],['col-xl-6','½'],['col-xl-4','⅓']] as [$cls,$lbl]): ?><button class="db-w-opt" data-col-class="<?= $cls ?>"><?= $lbl ?></button><?php endforeach; ?></div>
    <div class="db-card h-100">
      <div class="db-card__head">
        <div><div class="db-card__eyebrow"><?= $isTechnicianDashboard ? 'Performance' : 'Navigation' ?></div><div class="db-card__title"><?= $isTechnicianDashboard ? 'Ma performance terrain' : 'Accès rapides' ?></div></div>
      </div>
      <div class="db-card__body d-flex flex-column gap-1">
        <?php if ($isTechnicianDashboard): ?>
        <div class="row g-2 mb-2">
          <?php foreach ([
            ['label' => 'Score', 'value' => (int)($myTechnicianPerformance['score'] ?? 0), 'color' => '#10b981'],
            ['label' => 'Backbones', 'value' => (int)($myTechnicianPerformance['backbone_total'] ?? 0), 'color' => '#4f6ef7'],
            ['label' => 'FTTH', 'value' => (int)($myTechnicianPerformance['ftth_total'] ?? 0), 'color' => '#0ea5e9'],
          ] as $perfStat): ?>
          <div class="col-4">
            <div class="db-b2b-card" style="padding:.85rem .75rem;min-height:auto;">
              <div class="db-b2b-card__label"><?= htmlspecialchars($perfStat['label']) ?></div>
              <div class="db-b2b-card__val" style="color:<?= $perfStat['color'] ?>;font-size:1.35rem;"><?= (int)$perfStat['value'] ?></div>
            </div>
          </div>
          <?php endforeach; ?>
        </div>
        <div style="display:grid;gap:.5rem;margin-bottom:.75rem;">
          <div class="db-action-link" style="cursor:default;">
            <div class="db-action-link__icon" style="background:#eef2ff;color:#4f6ef7;"><i class="fas fa-tower-broadcast"></i></div>
            <div>
              <div style="font-size:.82rem;font-weight:600;">Incidents backbones</div>
              <div style="font-size:.68rem;color:var(--db-muted);">Total: <?= (int)($myTechnicianPerformance['backbone_total'] ?? 0) ?> · En cours: <?= (int)($myTechnicianPerformance['backbone_in_progress'] ?? 0) ?> · Traités / clôturés: <?= (int)($myTechnicianPerformance['backbone_closed'] ?? 0) ?></div>
            </div>
          </div>
          <div class="db-action-link" style="cursor:default;">
            <div class="db-action-link__icon" style="background:#f0f9ff;color:#0ea5e9;"><i class="fas fa-network-wired"></i></div>
            <div>
              <div style="font-size:.82rem;font-weight:600;">Maintenance FTTH</div>
              <div style="font-size:.68rem;color:var(--db-muted);">Total: <?= (int)($myTechnicianPerformance['ftth_total'] ?? 0) ?> · En cours: <?= (int)($myTechnicianPerformance['ftth_in_progress'] ?? 0) ?> · Traités / clôturés: <?= (int)($myTechnicianPerformance['ftth_closed'] ?? 0) ?></div>
            </div>
          </div>
        </div>
        <?php endif; ?>
        <?php foreach ([
          ['/tickets','fa-ticket-simple','#4f6ef7','#eef2ff','Mes tickets','Consulter votre file'],
          ['/ftth','fa-network-wired','#0ea5e9','#f0f9ff','Fiches FTTH','Interventions terrain'],
          ['/users/profile','fa-circle-user','#10b981','#f0fdf4','Mon profil','Prise en charge & infos'],
        ] as $ql): ?>
        <a href="<?= route_url($ql[0]) ?>" class="db-action-link">
          <div class="db-action-link__icon" style="background:<?= $ql[3] ?>;color:<?= $ql[2] ?>;"><i class="fas <?= $ql[1] ?>"></i></div>
          <div><div style="font-size:.82rem;font-weight:600;"><?= $ql[4] ?></div><div style="font-size:.68rem;color:var(--db-muted);"><?= $ql[5] ?></div></div>
          <i class="fas fa-chevron-right" style="margin-left:auto;color:var(--db-muted);font-size:.7rem;"></i>
        </a>
        <?php endforeach; ?>
      </div>
    </div>
  </div>
  <?php endif; ?>
</div>
</div><!-- /section activity -->

<?php /* ── DISTRIBUTIONS ──────────────────────────── */ ?>
<?php if ($showGlobalB2BInsights && (!empty($b2bDistributions['priority']) || !empty($b2bDistributions['status']))): ?>
<div class="db-section" data-section-id="distributions" data-layout-label="Distributions">
<span class="db-section-handle" title="Déplacer"><i class="fas fa-grip-vertical"></i></span>
<div>
  <div class="db-sh">
    <div class="db-sh__pill"></div>
    <span class="db-sh__title">Distributions</span>
  </div>
  <div class="row g-3" data-layout-row="row-distributions">
    <?php
    $distSets = [
      ['key'=>'priority','title'=>'Par priorité'],
      ['key'=>'status',  'title'=>'Par statut'],
      ['key'=>'nature',  'title'=>'Par nature'],
      ['key'=>'clients', 'title'=>'Top clients'],
    ];
    $distColors = ['#4f6ef7','#10b981','#f59e0b','#ef4444','#8b5cf6','#0ea5e9','#14b8a6','#ec4899'];
    $distCanvasIdx = 0;
    ?>
    <?php foreach ($distSets as $ds):
      $rows = $b2bDistributions[$ds['key']] ?? [];
      if (empty($rows)) continue;
      $dmax = $distributionMax($rows);
      $canvasId = 'chartDist'.$distCanvasIdx++;
      $distLabels = [];
      $distVals   = [];
      $distBgs    = [];
      foreach (array_slice($rows,0,6) as $di => $drow) {
        $distLabels[] = $drow['label'] ?? $drow['priority'] ?? $drow['status'] ?? $drow['nature'] ?? $drow['client_name'] ?? '?';
        $distVals[]   = (int)($drow['active_total'] ?? $drow['total'] ?? 0);
        $distBgs[]    = $distColors[$di % count($distColors)];
      }
    ?>
    <div class="col-12 col-sm-6 col-xl-3 db-col-wrap db-widget" data-widget-id="dist-<?= $ds['key'] ?>" data-layout-label="<?= htmlspecialchars($ds['title']) ?>">
      <div class="db-card">
        <div class="db-card__head">
          <div><div class="db-card__eyebrow">Distribution</div><div class="db-card__title"><?= $ds['title'] ?></div></div>
        </div>
        <div class="db-card__body">
          <canvas id="<?= $canvasId ?>" height="160"
                  data-labels='<?= json_encode($distLabels, JSON_UNESCAPED_UNICODE) ?>'
                  data-values='<?= json_encode($distVals) ?>'
                  data-colors='<?= json_encode($distBgs) ?>'></canvas>
        </div>
      </div>
    </div>
    <?php endforeach; ?>
  </div>
</div>
</div><!-- /section distributions -->
<?php endif; ?>

<?php /* ── FTTH technicien ──────────────────────────── */ ?>
<?php if ($userRole === 'technicien' && !empty($ftthTickets)): ?>
<div class="db-section" data-section-id="ftth" data-layout-label="Mes interventions FTTH">
<span class="db-section-handle" title="Déplacer"><i class="fas fa-grip-vertical"></i></span>
<div>
  <div class="db-sh">
    <div class="db-sh__pill"></div>
    <span class="db-sh__title">Mes interventions FTTH</span>
    <div class="db-sh__actions"><a href="<?= route_url('/ftth') ?>" class="db-btn db-btn--primary"><i class="fas fa-network-wired"></i>Voir tout</a></div>
  </div>
  <div class="row g-2 mb-3" data-layout-row="row-ftth-stats">
    <?php foreach ([
      ['label'=>'Assignés','val'=>$ftthStats['assigned'],'color'=>'#4f6ef7','icon'=>'fa-clipboard-list'],
      ['label'=>'En cours','val'=>$ftthStats['in_progress'],'color'=>'#0ea5e9','icon'=>'fa-bolt'],
      ['label'=>'À remplir','val'=>$ftthStats['to_fill'],'color'=>'#f59e0b','icon'=>'fa-pen-to-square'],
      ['label'=>'Validation','val'=>$ftthStats['awaiting_validation'],'color'=>'#8b5cf6','icon'=>'fa-hourglass-half'],
    ] as $fc): ?>
    <div class="col-6 col-sm-3 db-col-wrap db-widget" data-widget-id="ftth-stat-<?= $fc['icon'] ?>" data-layout-label="<?= htmlspecialchars($fc['label']) ?>">
      <div class="db-b2b-card">
        <div class="db-b2b-card__bar" style="background:<?= $fc['color'] ?>;"></div>
        <div class="db-b2b-card__icon" style="color:<?= $fc['color'] ?>;"><i class="fas <?= $fc['icon'] ?>"></i></div>
        <div class="db-b2b-card__label"><?= $fc['label'] ?></div>
        <div class="db-b2b-card__val" style="color:<?= $fc['color'] ?>;"><?= (int)$fc['val'] ?></div>
      </div>
    </div>
    <?php endforeach; ?>
  </div>
  <div class="row g-2" data-layout-row="row-ftth-tickets">
    <?php
    $ftthStatusMap = [
      'assigné'=>['bg'=>'#fffbeb','color'=>'#b45309','icon'=>'fa-user-check'],
      'en_cours'=>['bg'=>'#f0f9ff','color'=>'#0369a1','icon'=>'fa-bolt'],
      'fiche_a_remplir'=>['bg'=>'#faf5ff','color'=>'#7e22ce','icon'=>'fa-pen-to-square'],
      'attente_validation'=>['bg'=>'#f5f3ff','color'=>'#6d28d9','icon'=>'fa-hourglass-half'],
      'validé'=>['bg'=>'#f0fdf4','color'=>'#15803d','icon'=>'fa-circle-check'],
    ];
    $ftthDefault=['bg'=>'#f1f5f9','color'=>'#475569','icon'=>'fa-circle'];
    ?>
    <?php foreach (array_slice($ftthTickets, 0, 6) as $ft):
      $fst = $ft['status'] ?? 'assigné';
      $ftone = $ftthStatusMap[$fst] ?? $ftthDefault;
    ?>
    <div class="col-12 col-sm-6 col-lg-4 db-col-wrap db-widget" data-widget-id="ftth-ticket-<?= (int)($ft['id'] ?? 0) ?>" data-layout-label="<?= htmlspecialchars($ft['ticket_id'] ?? ($ft['title'] ?? 'Ticket FTTH')) ?>">
      <a href="<?= route_url('/ftth/'.(int)($ft['id']??0)) ?>" class="db-ftth-card">
        <div class="db-ftth-card__icon" style="background:<?= $ftone['bg'] ?>;color:<?= $ftone['color'] ?>;"><i class="fas <?= $ftone['icon'] ?>"></i></div>
        <div class="min-w-0 flex-grow-1">
          <div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--db-muted);"><?= htmlspecialchars($ft['ticket_id'] ?? '#—') ?></div>
          <div style="font-size:.85rem;font-weight:600;color:var(--db-text);margin:.1rem 0 .3rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;"><?= htmlspecialchars($ft['title'] ?? 'Sans titre') ?></div>
          <div class="d-flex flex-wrap gap-1">
            <span class="db-chip" style="background:<?= $ftone['bg'] ?>;color:<?= $ftone['color'] ?>;"><?= htmlspecialchars(str_replace('_',' ',$fst)) ?></span>
            <?php if (!empty($ft['client_name'])): ?>
            <span class="db-chip" style="background:#f1f5f9;color:#475569;"><?= htmlspecialchars($ft['client_name']) ?></span>
            <?php endif; ?>
          </div>
        </div>
      </a>
    </div>
    <?php endforeach; ?>
  </div>
</div>
</div><!-- /section ftth -->
<?php endif; ?>

</div><!-- /db-sortable -->
</div><!-- .db-wrap -->

<script>
(function(){
'use strict';

function readJson(key, fallback){
  try {
    var parsed = JSON.parse(localStorage.getItem(key));
    return parsed && typeof parsed === 'object' ? parsed : fallback;
  } catch (error) {
    return fallback;
  }
}

function saveJson(key, value){
  try { localStorage.setItem(key, JSON.stringify(value)); } catch (error) {}
}

/* ── Counters ─────────────────────────────── */
document.querySelectorAll('[data-counter]').forEach(function(el){
  var t=parseInt(el.getAttribute('data-counter'),10);
  if(isNaN(t))return;
  var dur=900,s=null;
  (function step(ts){
    if(!s)s=ts;
    var p=Math.min((ts-s)/dur,1),e=1-Math.pow(1-p,3);
    el.textContent=Math.round(t*e);
    if(p<1)requestAnimationFrame(step); else el.textContent=t;
  })(0);
  requestAnimationFrame(function(ts){
    var s2=null;
    requestAnimationFrame(function step(ts2){
      if(!s2)s2=ts2;
      var p=Math.min((ts2-s2)/900,1),e=1-Math.pow(1-p,3);
      el.textContent=Math.round(t*e);
      if(p<1)requestAnimationFrame(step); else el.textContent=t;
    });
  });
});

/* ── Gauge animation ─────────────────────── */
setTimeout(function(){
  document.querySelectorAll('.db-gauge-fill[data-dash-offset]').forEach(function(el){
    el.style.strokeDashoffset=el.getAttribute('data-dash-offset');
  });
},300);

/* ── Bar animation ───────────────────────── */
setTimeout(function(){
  document.querySelectorAll('[data-target-width]').forEach(function(el){
    el.style.width=el.getAttribute('data-target-width');
  });
},300);

/* ════════════════════════════════════════════
   FILTRE + LAYOUT
   ════════════════════════════════════════════ */
(function(){
  var customToggle = document.getElementById('db-custom-toggle');
  var customRange  = document.getElementById('db-custom-range');
  var periodInput  = document.getElementById('db-custom-period-input');
  if(customToggle && customRange){
    customToggle.addEventListener('click', function(){
      var open = customRange.classList.toggle('show');
      customToggle.classList.toggle('active', open);
      if(periodInput) periodInput.disabled = !open;
    });
    document.querySelectorAll('#db-filter-form button[name="period"]').forEach(function(btn){
      btn.addEventListener('click', function(){
        customRange.classList.remove('show');
        customToggle.classList.remove('active');
        if(periodInput) periodInput.disabled = true;
      });
    });
  }

  var LS_SECTION_ORDER = 'db_section_order_v2';
  var LS_WIDGET_ORDER  = 'db_widget_order_v2';
  var LS_WIDTHS        = 'db_col_widths_v1';
  var LS_HIDDEN        = 'db_hidden_items_v2';
  var sortableEl       = document.getElementById('db-sortable');
  var layoutBtn        = document.getElementById('db-layout-toggle');
  var resetBtn         = document.getElementById('db-layout-reset');
  var layoutPanel      = document.getElementById('db-layout-panel');
  var sectionList      = document.getElementById('db-layout-sections');
  var widgetList       = document.getElementById('db-layout-widgets');
  var sortInstances    = [];
  var layoutMode       = false;
  var widthMap         = readJson(LS_WIDTHS, {});
  var widgetOrderMap   = readJson(LS_WIDGET_ORDER, {});
  var hiddenState      = readJson(LS_HIDDEN, { sections: {}, widgets: {} });
  var COL_CLASSES      = /\bcol-xl-\d+\b/g;

  if(!sortableEl) return;

  function collectSectionMeta(){
    return Array.from(sortableEl.querySelectorAll('[data-section-id]')).map(function(section){
      return {
        id: section.getAttribute('data-section-id'),
        label: section.getAttribute('data-layout-label') || section.getAttribute('data-section-id')
      };
    });
  }

  function collectWidgetMeta(){
    return Array.from(document.querySelectorAll('[data-widget-id]')).map(function(widget){
      return {
        id: widget.getAttribute('data-widget-id'),
        label: widget.getAttribute('data-layout-label') || widget.getAttribute('data-widget-id'),
        row: (widget.parentElement && widget.parentElement.getAttribute('data-layout-row')) || ''
      };
    });
  }

  function persistSectionOrder(){
    var order = collectSectionMeta().map(function(section){ return section.id; });
    saveJson(LS_SECTION_ORDER, order);
  }

  function persistWidgetOrder(row){
    var rowId = row.getAttribute('data-layout-row');
    if(!rowId) return;
    widgetOrderMap[rowId] = Array.from(row.querySelectorAll('[data-widget-id]')).map(function(widget){
      return widget.getAttribute('data-widget-id');
    });
    saveJson(LS_WIDGET_ORDER, widgetOrderMap);
  }

  function persistAllWidgetOrders(){
    document.querySelectorAll('[data-layout-row]').forEach(function(row){
      persistWidgetOrder(row);
    });
  }

  function applySectionOrder(){
    var saved = readJson(LS_SECTION_ORDER, []);
    if(!Array.isArray(saved) || saved.length < 2) return;
    saved.forEach(function(id){
      var section = sortableEl.querySelector('[data-section-id="'+id+'"]');
      if(section) sortableEl.appendChild(section);
    });
  }

  function applyWidgetOrder(){
    document.querySelectorAll('[data-layout-row]').forEach(function(row){
      var rowId = row.getAttribute('data-layout-row');
      var saved = widgetOrderMap[rowId];
      if(!Array.isArray(saved) || saved.length < 2) return;
      saved.forEach(function(id){
        var widget = row.querySelector('[data-widget-id="'+id+'"]');
        if(widget) row.appendChild(widget);
      });
    });
  }

  function setHidden(type, id, hidden){
    var selector = type === 'section' ? '[data-section-id="'+id+'"]' : '[data-widget-id="'+id+'"]';
    var target = document.querySelector(selector);
    if(!target) return;
    target.classList.toggle('db-item-hidden', hidden);
    target.setAttribute('aria-hidden', hidden ? 'true' : 'false');
    if(type === 'section') {
      hiddenState.sections[id] = hidden;
    } else {
      hiddenState.widgets[id] = hidden;
    }
    saveJson(LS_HIDDEN, hiddenState);
    syncInlineControls();
    buildLayoutPanel();
  }

  function applyHiddenState(){
    Object.keys(hiddenState.sections || {}).forEach(function(id){
      setHidden('section', id, !!hiddenState.sections[id]);
    });
    Object.keys(hiddenState.widgets || {}).forEach(function(id){
      setHidden('widget', id, !!hiddenState.widgets[id]);
    });
  }

  function ensureWidgetControls(){
    document.querySelectorAll('[data-widget-id]').forEach(function(widget){
      if(!widget.querySelector('.db-widget-handle')){
        var handle = document.createElement('button');
        handle.type = 'button';
        handle.className = 'db-widget-handle';
        handle.title = 'Déplacer le bloc';
        handle.innerHTML = '<i class="fas fa-grip"></i>';
        widget.insertBefore(handle, widget.firstChild);
      }
      if(!widget.querySelector('.db-widget-toggle')){
        var toggle = document.createElement('button');
        toggle.type = 'button';
        toggle.className = 'db-widget-toggle';
        toggle.title = 'Masquer le bloc';
        toggle.setAttribute('data-widget-toggle', widget.getAttribute('data-widget-id'));
        toggle.innerHTML = '<i class="fas fa-eye-slash"></i>';
        widget.insertBefore(toggle, widget.firstChild);
      }
    });
  }

  function syncInlineControls(){
    document.querySelectorAll('[data-widget-toggle]').forEach(function(button){
      var widgetId = button.getAttribute('data-widget-toggle');
      var hidden = !!(hiddenState.widgets && hiddenState.widgets[widgetId]);
      button.title = hidden ? 'Afficher le bloc' : 'Masquer le bloc';
      button.innerHTML = hidden ? '<i class="fas fa-eye"></i>' : '<i class="fas fa-eye-slash"></i>';
    });
  }

  function buildLayoutPanel(){
    if(!sectionList || !widgetList) return;
    sectionList.innerHTML = collectSectionMeta().map(function(section){
      var checked = !(hiddenState.sections && hiddenState.sections[section.id]);
      return '<label class="db-layout-item">'
        + '<span><span class="db-layout-item__label">'+ section.label +'</span><span class="db-layout-item__meta">Section</span></span>'
        + '<span class="db-layout-switch"><input type="checkbox" data-layout-type="section" data-layout-id="'+ section.id +'" '+ (checked ? 'checked' : '') +'>Visible</span>'
      + '</label>';
    }).join('');
    widgetList.innerHTML = collectWidgetMeta().map(function(widget){
      var checked = !(hiddenState.widgets && hiddenState.widgets[widget.id]);
      return '<label class="db-layout-item">'
        + '<span><span class="db-layout-item__label">'+ widget.label +'</span><span class="db-layout-item__meta">'+ (widget.row || 'Bloc') +'</span></span>'
        + '<span class="db-layout-switch"><input type="checkbox" data-layout-type="widget" data-layout-id="'+ widget.id +'" '+ (checked ? 'checked' : '') +'>Visible</span>'
      + '</label>';
    }).join('');
  }

  function destroySortables(){
    sortInstances.forEach(function(instance){ instance.destroy(); });
    sortInstances = [];
  }

  function initSortables(){
    destroySortables();
    if(typeof Sortable === 'undefined') {
      window.setTimeout(function(){ if(layoutMode) initSortables(); }, 250);
      return;
    }

    sortInstances.push(Sortable.create(sortableEl, {
      handle: '.db-section-handle',
      animation: 180,
      forceFallback: true,
      fallbackTolerance: 4,
      ghostClass: 'sortable-ghost',
      chosenClass: 'sortable-chosen',
      dragClass: 'sortable-drag',
      onEnd: function(){
        persistSectionOrder();
        buildLayoutPanel();
      }
    }));

    document.querySelectorAll('[data-layout-row]').forEach(function(row){
      sortInstances.push(Sortable.create(row, {
        group: 'dashboard-widgets',
        draggable: '[data-widget-id]',
        animation: 180,
        forceFallback: true,
        fallbackTolerance: 4,
        ghostClass: 'sortable-ghost',
        chosenClass: 'sortable-chosen',
        dragClass: 'sortable-drag',
        filter: '.db-widget-toggle, .db-width-btn, .db-w-opt, input, textarea, select, label',
        preventOnFilter: false,
        onEnd: function(){
          persistAllWidgetOrders();
          buildLayoutPanel();
        }
      }));
    });
  }

  function applyWidth(colWrap, cls){
    if(!colWrap || !cls) return;
    var colId = colWrap.getAttribute('data-col-id');
    var current = colWrap.className.replace(COL_CLASSES,'').trim();
    colWrap.className = current + ' ' + cls;
    colWrap.querySelectorAll('.db-w-opt').forEach(function(button){
      button.classList.toggle('active', button.getAttribute('data-col-class') === cls);
    });
    if(colId){
      widthMap[colId] = cls;
      saveJson(LS_WIDTHS, widthMap);
    }
  }

  function restoreWidths(){
    document.querySelectorAll('.db-col-wrap[data-col-id]').forEach(function(wrap){
      var id = wrap.getAttribute('data-col-id');
      if(widthMap[id]) applyWidth(wrap, widthMap[id]);
    });
  }

  function setLayoutMode(on){
    layoutMode = on;
    sortableEl.classList.toggle('db-layout-on', on);
    sortableEl.querySelectorAll('.db-section-handle').forEach(function(handle){
      handle.style.display = on ? 'flex' : '';
    });
    document.querySelectorAll('.db-width-btn').forEach(function(button){
      button.style.display = on ? 'flex' : '';
    });
    if(layoutBtn) layoutBtn.classList.toggle('active', on);
    if(layoutPanel){
      layoutPanel.hidden = !on;
      layoutPanel.classList.toggle('show', on);
    }
    if(on) {
      initSortables();
    } else {
      destroySortables();
    }
  }

  function resetLayout(){
    [LS_SECTION_ORDER, LS_WIDGET_ORDER, LS_WIDTHS, LS_HIDDEN].forEach(function(key){
      try { localStorage.removeItem(key); } catch (error) {}
    });
    window.location.reload();
  }

  applySectionOrder();
  applyWidgetOrder();
  ensureWidgetControls();
  restoreWidths();
  applyHiddenState();
  buildLayoutPanel();
  syncInlineControls();

  if(layoutBtn){
    layoutBtn.addEventListener('click', function(){
      setLayoutMode(!layoutMode);
    });
  }

  if(resetBtn){
    resetBtn.addEventListener('click', resetLayout);
  }

  document.addEventListener('click', function(event){
    var widthBtn = event.target.closest('.db-w-opt');
    if(widthBtn){
      var colWrap = widthBtn.closest('.db-col-wrap');
      var cls = widthBtn.getAttribute('data-col-class');
      if(colWrap && cls) applyWidth(colWrap, cls);
      return;
    }

    var widgetToggle = event.target.closest('[data-widget-toggle]');
    if(widgetToggle){
      var widgetId = widgetToggle.getAttribute('data-widget-toggle');
      setHidden('widget', widgetId, !(hiddenState.widgets && hiddenState.widgets[widgetId]));
    }
  });

  document.addEventListener('change', function(event){
    var control = event.target.closest('[data-layout-type][data-layout-id]');
    if(!control) return;
    var type = control.getAttribute('data-layout-type');
    var id = control.getAttribute('data-layout-id');
    setHidden(type, id, !control.checked);
  });

  setLayoutMode(false);
})();

if(typeof Chart==='undefined')return;

/* ── Histogram tickets (bar) ─────────────── */
var ctxBar=document.getElementById('chartBar');
if(ctxBar){try{new Chart(ctxBar.getContext('2d'),{
    type:'bar',
    data:{
      labels:<?= json_encode($chartData['labels']??[]) ?>,
      datasets:[
        {label:'Backbone ouverts',data:<?= json_encode($chartData['opened']??[]) ?>,backgroundColor:'rgba(239,68,68,.70)',hoverBackgroundColor:'rgba(239,68,68,1)',borderRadius:6,borderSkipped:false,stack:'backbone'},
        {label:'Backbone résolus',data:<?= json_encode($chartData['resolved']??[]) ?>,backgroundColor:'rgba(16,185,129,.70)',hoverBackgroundColor:'rgba(16,185,129,1)',borderRadius:6,borderSkipped:false,stack:'backbone'},
        {label:'FTTH ouverts',data:<?= json_encode($chartData['ftth_opened']??[]) ?>,backgroundColor:'rgba(14,165,233,.70)',hoverBackgroundColor:'rgba(14,165,233,1)',borderRadius:6,borderSkipped:false,stack:'ftth'},
        {label:'FTTH validés',data:<?= json_encode($chartData['ftth_resolved']??[]) ?>,backgroundColor:'rgba(139,92,246,.70)',hoverBackgroundColor:'rgba(139,92,246,1)',borderRadius:6,borderSkipped:false,stack:'ftth'}
      ]
    },
    options:{
      responsive:true,maintainAspectRatio:true,
      interaction:{mode:'index',intersect:false},
      plugins:{
        legend:{position:'top',labels:{font:{size:11},usePointStyle:true,boxWidth:8}},
        tooltip:{backgroundColor:'#0f172a',titleFont:{size:11},bodyFont:{size:11},padding:10,cornerRadius:8}
      },
      scales:{
        x:{stacked:true,grid:{display:false},ticks:{font:{size:11},color:'#94a3b8'}},
        y:{stacked:true,grid:{color:'#f1f5f9'},ticks:{font:{size:11},color:'#94a3b8'},beginAtZero:true}
      }
    }
  });}catch(e){console.warn('chartBar error:',e);}
}

/* ── Doughnut statuts ────────────────────── */
var ctxD=document.getElementById('chartDoughnut');
if(ctxD){
  new Chart(ctxD.getContext('2d'),{
    type:'doughnut',
    data:{
      labels:<?= json_encode($statusData['labels']??[]) ?>,
      datasets:[{
        data:<?= json_encode($statusData['data']??[]) ?>,
        backgroundColor:<?= json_encode($statusData['colors']??[]) ?>,
        borderWidth:3,borderColor:'#fff',hoverBorderWidth:0
      }]
    },
    options:{
      responsive:false,cutout:'72%',
      plugins:{
        legend:{display:false},
        tooltip:{backgroundColor:'#0f172a',titleFont:{size:11},bodyFont:{size:11},padding:10,cornerRadius:8}
      },
      animation:{animateRotate:true,duration:1000}
    }
  });
}

/* ── E-Intervention chart ────────────────── */
var ctxEI=document.getElementById('chartEIntervention');
if(ctxEI){
  new Chart(ctxEI.getContext('2d'),{
    type:'bar',
    data:{
      labels:<?= json_encode($eInterventionChart['labels'], JSON_UNESCAPED_UNICODE) ?>,
      datasets:[{
        data:<?= json_encode($eInterventionChart['data']) ?>,
        backgroundColor:<?= json_encode($eInterventionChart['colors']) ?>,
        borderRadius:8,
        borderSkipped:false,
        maxBarThickness:48
      }]
    },
    options:{
      responsive:true,
      maintainAspectRatio:true,
      plugins:{
        legend:{display:false},
        tooltip:{backgroundColor:'#0f172a',titleFont:{size:11},bodyFont:{size:11},padding:10,cornerRadius:8}
      },
      scales:{
        x:{grid:{display:false},ticks:{font:{size:11},color:'#64748b',maxRotation:0,minRotation:0}},
        y:{grid:{color:'#f1f5f9'},ticks:{font:{size:11},color:'#94a3b8'},beginAtZero:true,precision:0}
      }
    }
  });
}

/* ── Mini bar cycle délais ───────────────── */
var ctxCycle=document.getElementById('chartCycle');
if(ctxCycle){
  new Chart(ctxCycle.getContext('2d'),{
    type:'bar',
    data:{
      labels:['Ouv→Ass','Ass→Int','Int→Rés'],
      datasets:[{
        data:[
          <?= round($interventionMetrics['open_to_assigned'],1) ?>,
          <?= round($interventionMetrics['assigned_to_intervention'],1) ?>,
          <?= round($interventionMetrics['intervention_to_resolution'],1) ?>
        ],
        backgroundColor:['rgba(79,110,247,.8)','rgba(14,165,233,.8)','rgba(16,185,129,.8)'],
        borderRadius:4,borderSkipped:false
      }]
    },
    options:{
      responsive:true,maintainAspectRatio:true,
      plugins:{legend:{display:false},tooltip:{callbacks:{label:function(c){return c.parsed.y+'h';}},backgroundColor:'#0f172a',padding:8,cornerRadius:6}},
      scales:{
        x:{grid:{display:false},ticks:{font:{size:10},color:'#94a3b8'}},
        y:{display:false,beginAtZero:true}
      }
    }
  });
}

/* ── Mini bar scores techniciens ─────────── */
var ctxT=document.getElementById('chartTechScores');
if(ctxT){
  new Chart(ctxT.getContext('2d'),{
    type:'line',
    data:{
      labels:<?= json_encode($technicianPerformanceChart['labels'] ?? [], JSON_UNESCAPED_UNICODE) ?>,
      datasets:[{
        label:'Incidents Backbones',
        data:<?= json_encode($technicianPerformanceChart['incident_scores'] ?? []) ?>,
        borderColor:'#0ea5e9',
        backgroundColor:'rgba(14,165,233,.15)',
        pointBackgroundColor:'#0ea5e9',
        pointRadius:3,
        tension:.35,
        fill:false
      },{
        label:'Incidents maintenance FTTH',
        data:<?= json_encode($technicianPerformanceChart['ftth_scores'] ?? []) ?>,
        borderColor:'#8b5cf6',
        backgroundColor:'rgba(139,92,246,.15)',
        pointBackgroundColor:'#8b5cf6',
        pointRadius:3,
        tension:.35,
        fill:false
      },{
        label:'Global',
        data:<?= json_encode($technicianPerformanceChart['total_scores'] ?? []) ?>,
        borderColor:'#10b981',
        backgroundColor:'rgba(16,185,129,.12)',
        pointBackgroundColor:'#10b981',
        pointRadius:4,
        pointHoverRadius:5,
        borderWidth:3,
        tension:.3,
        fill:true
      }]
    },
    options:{
      responsive:true,maintainAspectRatio:true,
      plugins:{legend:{display:true,position:'bottom',labels:{boxWidth:10,usePointStyle:true,color:'#64748b'}},tooltip:{callbacks:{label:function(c){return c.dataset.label+': '+c.parsed.y;}},backgroundColor:'#0f172a',padding:8,cornerRadius:6}},
      scales:{
        x:{grid:{display:false},ticks:{font:{size:10},color:'#94a3b8',maxRotation:0}},
        y:{beginAtZero:true,grid:{color:'rgba(148,163,184,.15)'},ticks:{display:false}}
      }
    }
  });
}

/* ── Distribution horizontal bar charts ──── */
document.querySelectorAll('canvas[data-labels]').forEach(function(el){
  var labels=JSON.parse(el.getAttribute('data-labels')||'[]');
  var values=JSON.parse(el.getAttribute('data-values')||'[]');
  var colors=JSON.parse(el.getAttribute('data-colors')||'[]');
  new Chart(el.getContext('2d'),{
    type:'bar',
    data:{
      labels:labels,
      datasets:[{
        data:values,
        backgroundColor:colors.map(function(c){return c+'cc';}),
        hoverBackgroundColor:colors,
        borderRadius:4,borderSkipped:false
      }]
    },
    options:{
      indexAxis:'y',
      responsive:true,maintainAspectRatio:true,
      plugins:{legend:{display:false},tooltip:{backgroundColor:'#0f172a',padding:8,cornerRadius:6}},
      scales:{
        x:{grid:{color:'#f1f5f9'},ticks:{font:{size:10},color:'#94a3b8'},beginAtZero:true},
        y:{grid:{display:false},ticks:{font:{size:10},color:'#64748b'}}
      },
      animation:{duration:800}
    }
  });
});

/* ── Incident row click ──────────────────── */
document.querySelectorAll('.incident-row[data-id]').forEach(function(row){
  row.addEventListener('click',function(){
    var id=row.getAttribute('data-id');
    var src=row.getAttribute('data-source')||'backbone';
    if(id&&parseInt(id)>0){
      if(src==='ftth'){
        window.location.href='<?= route_url('/ftth/') ?>'+id;
      } else {
        window.location.href='<?= route_url('/tickets/') ?>'+id;
      }
    }
  });
});

/* ── Auto-refresh 5 min ──────────────────── */
var cd=300;
setInterval(function(){if(--cd<=0)window.location.reload();},1000);

})();
</script>
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.6/Sortable.min.js"></script>
