<?php
// Shell view — sem DB. Dados carregados via /api/dashboard/data após DOMContentLoaded.
$segmentoAtual = $segmento ?? '';
$temMesa = in_array($segmentoAtual, ['restaurante','bar','lanchonete','sushi','pizzaria','churrascaria']);

// Monta query string para a API repasse os filtros de período
$apiParams = [];
if ($filtroAno) $apiParams['ano'] = $filtroAno;
if ($filtroMes) $apiParams['mes'] = $filtroMes;
if (isset($_GET['hoje']) && $_GET['hoje'] === '1') $apiParams['hoje'] = '1';
$apiQs = $apiParams ? '?' . http_build_query($apiParams) : '';
?>
<!-- ECharts -->
<script src="/assets/js/echarts.min.js"></script>
<script src="/assets/js/pbi-async.js"></script>

<script>
window.__DASHBOARD = {
    filtroAno: <?= $filtroAno ? (int)$filtroAno : 'null' ?>,
    filtroMes: <?= $filtroMes ? (int)$filtroMes : 'null' ?>,
    eHoje:     <?= ($eHoje ?? true) ? 'true' : 'false' ?>,
    apiUrl:    '/api/dashboard/data<?= $apiQs ?>',
    temMesa:   <?= $temMesa ? 'true' : 'false' ?>,
    segmento:  '<?= htmlspecialchars($segmentoAtual, ENT_QUOTES) ?>',
};
</script>

<div class="pbi-dashboard-page" id="dashboardRoot">

    <!-- ===== CABEÇALHO ===== -->
    <div class="pbi-page-header mb-1">
        <div class="d-flex align-items-center gap-3">
            <div class="pbi-page-icon"><i class="bi bi-speedometer2"></i></div>
            <div>
                <h1 class="pbi-page-title">Painel Executivo</h1>
                <p class="pbi-page-subtitle">
                    <?= \App\Core\View::e($config['empresa'] ?? '') ?>
                    &nbsp;·&nbsp;
                    <strong><?= \App\Core\View::e(ucfirst(str_replace('_', ' ', $segmentoAtual ?: 'geral'))) ?></strong>
                    &nbsp;·&nbsp; <?= date('d/m/Y') ?>
                </p>
            </div>
        </div>
        <div class="d-flex align-items-center gap-2">
            <a href="/dashboard?hoje=1"
               class="btn btn-sm <?= ($eHoje ?? true) ? 'pbi-btn-filtrar' : 'btn-outline-secondary' ?>"
               title="Ver dados de hoje">
                <i class="bi bi-broadcast me-1"></i>Hoje
            </a>
            <div class="pbi-conn-badge" id="dashConnBadge" style="opacity:.4">
                <span class="pbi-conn-dot"></span>
                <span id="dashConnLabel">Carregando…</span>
            </div>
        </div>
    </div>

    <!-- Breadcrumb -->
    <nav class="pbi-breadcrumb mb-3" aria-label="breadcrumb">
        <a href="/"><i class="bi bi-house"></i> Início</a>
        <span class="pbi-breadcrumb-sep">/</span>
        <span class="pbi-breadcrumb-current">Dashboard</span>
    </nav>

    <!-- ===== BARRA DE FILTRO DE PERÍODO (esqueleto estático) ===== -->
    <div class="pbi-filtro-barra mb-4" id="dashFiltroBarra">
        <div class="pbi-filtro-anos" id="dashFiltroAnos">
            <?php
            $anoAtual = (int)date('Y');
            $anos = range($anoAtual + 1, max(2020, $anoAtual - 4));
            ?>
            <a href="/dashboard?hoje=1" class="pbi-ano-btn<?= ($eHoje ?? true) ? ' active' : '' ?>">
                <i class="bi bi-broadcast me-1"></i>Hoje
            </a>
            <a href="/dashboard" class="pbi-ano-btn <?= !$filtroAno ? 'active' : '' ?>">Atual</a>
            <?php foreach ($anos as $a): ?>
            <a href="/dashboard?ano=<?= (int)$a ?>"
               class="pbi-ano-btn <?= ($filtroAno == (int)$a) ? 'active' : '' ?>">
                <?= (int)$a ?>
            </a>
            <?php endforeach; ?>
        </div>
        <?php if ($filtroAno): ?>
        <div class="pbi-filtro-meses" id="dashFiltroMeses">
            <?php
            $nomeMeses = ['','Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'];
            ?>
            <a href="/dashboard?ano=<?= $filtroAno ?>"
               class="pbi-mes-btn <?= !$filtroMes ? 'active' : '' ?>">Todos</a>
            <?php for ($m = 1; $m <= 12; $m++): ?>
            <a href="/dashboard?ano=<?= $filtroAno ?>&mes=<?= $m ?>"
               class="pbi-mes-btn <?= $filtroMes == $m ? 'active' : '' ?>">
                <?= $nomeMeses[$m] ?>
            </a>
            <?php endfor; ?>
        </div>
        <?php endif; ?>

        <div class="pbi-filtro-info" id="dashFiltroInfo">
            <i class="bi bi-broadcast"></i>
            <span id="dashFiltroInfoText">
                <?php if ($filtroAno && $filtroMes): ?>
                    <?php $nm = ['','Janeiro','Fevereiro','Março','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro']; ?>
                    <?= $nm[$filtroMes] ?> de <?= $filtroAno ?>
                <?php elseif ($filtroAno): ?>
                    Ano <?= $filtroAno ?>
                <?php else: ?>
                    Tempo real — <?= date('d/m/Y') ?>
                <?php endif; ?>
            </span>
        </div>
    </div>

    <!-- ===== ÁREA DE CONTEÚDO ASYNC ===== -->
    <div id="dashContent">

        <!-- Skeleton: alerta de meta -->
        <div class="pbi-card mb-4 pbi-skeleton-block" id="skelMetaCard" style="height:180px"></div>

        <!-- Skeleton: alertas gerenciais -->
        <div class="row g-2 mb-4" id="skelAlertas">
            <div class="col-12 col-sm-6 col-xl-3"><div class="pbi-skeleton-block" style="height:80px;border-radius:10px"></div></div>
            <div class="col-12 col-sm-6 col-xl-3"><div class="pbi-skeleton-block" style="height:80px;border-radius:10px"></div></div>
            <div class="col-12 col-sm-6 col-xl-3"><div class="pbi-skeleton-block" style="height:80px;border-radius:10px"></div></div>
            <div class="col-12 col-sm-6 col-xl-3"><div class="pbi-skeleton-block" style="height:80px;border-radius:10px"></div></div>
        </div>

        <!-- Skeleton: KPI grid — Hoje -->
        <div class="pbi-kpi-secao-label"><i class="bi bi-broadcast-pin me-1"></i>Hoje</div>
        <div class="pbi-kpi-grid-4 mb-4" id="skelKpiHoje">
            <?php for ($i = 0; $i < 4; $i++): ?>
            <div class="pbi-kpi-card"><div class="pbi-skeleton-block" style="height:70px;border-radius:8px"></div></div>
            <?php endfor; ?>
        </div>

        <!-- Skeleton: KPI grid — Mês -->
        <div class="pbi-kpi-secao-label"><i class="bi bi-calendar-month me-1"></i>Mês</div>
        <div class="pbi-kpi-grid-4 mb-4" id="skelKpiMes">
            <?php for ($i = 0; $i < 4; $i++): ?>
            <div class="pbi-kpi-card"><div class="pbi-skeleton-block" style="height:70px;border-radius:8px"></div></div>
            <?php endfor; ?>
        </div>

        <!-- Skeleton: KPI grid — Financeiro -->
        <div class="pbi-kpi-secao-label"><i class="bi bi-bank me-1"></i>Financeiro</div>
        <div class="pbi-kpi-grid-4 mb-4" id="skelKpiFinanceiro">
            <?php for ($i = 0; $i < 4; $i++): ?>
            <div class="pbi-kpi-card"><div class="pbi-skeleton-block" style="height:70px;border-radius:8px"></div></div>
            <?php endfor; ?>
        </div>

        <!-- Skeleton: KPI grid — Operacional -->
        <div class="pbi-kpi-secao-label"><i class="bi bi-cpu me-1"></i>Operacional</div>
        <div class="pbi-kpi-grid-4 mb-4" id="skelKpiOperacional">
            <?php for ($i = 0; $i < 4; $i++): ?>
            <div class="pbi-kpi-card"><div class="pbi-skeleton-block" style="height:70px;border-radius:8px"></div></div>
            <?php endfor; ?>
        </div>

        <!-- Skeleton: gráficos principais -->
        <div class="row g-4 mb-4">
            <div class="col-lg-7">
                <div class="pbi-card h-100">
                    <div class="pbi-card-header"><i class="bi bi-bar-chart-fill me-2 text-accent"></i>Faturamento — Últimos 30 dias</div>
                    <div class="pbi-card-body"><div class="pbi-hint mb-2" style="margin-top:0">Quanto a loja vendeu em cada um dos últimos 30 dias.</div><div id="grafico30dias" style="height:240px"><div class="pbi-skeleton-block h-100"></div></div></div>
                </div>
            </div>
            <div class="col-lg-5">
                <div class="pbi-card h-100">
                    <div class="pbi-card-header"><i class="bi bi-bar-chart-steps me-2" style="color:#f97316"></i>Comparativo — período atual × anterior</div>
                    <div class="pbi-card-body">
                        <div class="pbi-hint mb-2" style="margin-top:0">Comparação rápida do mês atual versus o mês anterior em 4 indicadores-chave.</div>
                        <div id="graficoComparativo" style="height:240px"><div class="pbi-skeleton-block h-100"></div></div>
                    </div>
                </div>
            </div>
        </div>

        <!-- Pico de vendas por hora (movido para ocupar linha inteira) -->
        <div class="row g-4 mb-4">
            <div class="col-12">
                <div class="pbi-card">
                    <div class="pbi-card-header"><i class="bi bi-clock-fill me-2 text-accent"></i>Pico de Vendas por Hora</div>
                    <div class="pbi-card-body"><div class="pbi-hint mb-2" style="margin-top:0">Mostra em quais horas do dia a loja mais vende.</div><div id="graficoHoras" style="height:240px"><div class="pbi-skeleton-block h-100"></div></div></div>
                </div>
            </div>
        </div>

        <!-- Skeleton: rolling 12m -->
        <div class="pbi-card mb-4">
            <div class="pbi-card-header"><i class="bi bi-graph-up me-2 text-accent"></i>Tendência — Últimos 12 Meses</div>
            <div class="pbi-card-body"><div class="pbi-hint mb-2" style="margin-top:0">Faturamento mês a mês dos últimos 12 meses. A linha mostra a média dos 3 últimos meses para ver se a loja está subindo ou caindo.</div><div id="graficoRolling12m" style="height:260px"><div class="pbi-skeleton-block h-100"></div></div></div>
        </div>

        <!-- Skeleton: histórico anual + mensal -->
        <div class="row g-4 mb-4">
            <div class="col-lg-5">
                <div class="pbi-card h-100">
                    <div class="pbi-card-header"><i class="bi bi-calendar3 me-2 text-accent"></i>Faturamento por Ano</div>
                    <div class="pbi-card-body"><div class="pbi-hint mb-2" style="margin-top:0">Comparação do faturamento de cada ano. A linha é o ticket médio (valor médio por venda) daquele ano.</div><div id="graficoAnual" style="height:260px"><div class="pbi-skeleton-block h-100"></div></div></div>
                </div>
            </div>
            <div class="col-lg-7">
                <div class="pbi-card h-100">
                    <div class="pbi-card-header"><i class="bi bi-calendar2-range me-2 text-accent"></i>Faturamento Mensal — Histórico</div>
                    <div class="pbi-card-body"><div class="pbi-hint mb-2" style="margin-top:0">Faturamento de cada mês ao longo do tempo. Arraste a barra de baixo para ver mais meses.</div><div id="graficoMensal" style="height:260px"><div class="pbi-skeleton-block h-100"></div></div></div>
                </div>
            </div>
        </div>

        <!-- Skeleton: produtos + mesas -->
        <div class="row g-4 mb-4">
            <div class="col-lg-6">
                <div class="pbi-card">
                    <div class="pbi-card-header"><i class="bi bi-trophy-fill me-2 text-accent"></i>Top Produtos — Hoje</div>
                    <div class="pbi-card-body"><div class="pbi-hint mb-2" style="margin-top:0">Produtos que mais faturaram no período (em R$).</div><div id="graficoProdutos" style="height:280px"><div class="pbi-skeleton-block h-100"></div></div></div>
                </div>
            </div>
            <div class="col-lg-6" id="colMesas">
                <div class="pbi-card">
                    <div class="pbi-card-header"><i class="bi bi-grid-3x3-gap-fill me-2 text-accent"></i>Mesas Abertas</div>
                    <div class="pbi-card-body"><div class="pbi-hint mb-2" style="margin-top:0">Mesas em atendimento agora, com horário de abertura e total consumido.</div><div class="pbi-skeleton-block" style="height:200px;border-radius:8px"></div></div>
                </div>
            </div>
        </div>

        <!-- Containers para conteúdo dinâmico inserido após carga -->
        <div id="dashTopSemana"></div>
        <div id="dashTopHistorico"></div>

    </div><!-- /#dashContent -->

</div><!-- /.pbi-dashboard-page -->

<!-- ===== SCRIPT ASYNC ===== -->
<script>
(function () {
    'use strict';

    var D = window.__DASHBOARD;

    // Helpers de formatação
    function moeda(v) {
        return 'R$ ' + (+v).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
    }
    function fmt0(v) { return (+v).toLocaleString('pt-BR', { maximumFractionDigits: 0 }); }
    function fmtPct(v) { return (+v).toLocaleString('pt-BR', { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + '%'; }
    function esc(s) { var d = document.createElement('div'); d.textContent = String(s || ''); return d.innerHTML; }

    var corAcento  = '#4f8ef7';
    var corSup     = 'rgba(79,142,247,0.15)';
    var corGrade   = '#252a38';
    var corTexto   = '#64748b';
    var corVerde   = '#22c55e';
    var corAmarelo = '#f59e0b';

    function base(left) {
        return {
            backgroundColor: 'transparent',
            textStyle: { color: corTexto },
            grid: { top: 24, right: 20, bottom: 40, left: left || 60, containLabel: true },
        };
    }
    function tooltipDark(formatter) {
        var t = { backgroundColor: '#1c2030', borderColor: '#252a38', textStyle: { color: '#e2e8f0' } };
        if (formatter) t.formatter = formatter;
        return t;
    }

    // Removemos os skeletons de um elemento e ficamos com o container
    function clearSkel(id) {
        var el = document.getElementById(id);
        if (el) { var s = el.querySelector('.pbi-skeleton-block'); if (s) s.remove(); }
        return el;
    }

    function setConnBadge(ok, label) {
        var badge = document.getElementById('dashConnBadge');
        var lbl   = document.getElementById('dashConnLabel');
        if (!badge) return;
        badge.style.opacity = '1';
        badge.className = 'pbi-conn-badge ' + (ok ? 'conectado' : 'erro');
        if (lbl) lbl.textContent = label;
    }

    // Renderiza gauge da meta
    function renderGauge(mvr) {
        var el = document.getElementById('gaugeMetaDash');
        if (!el) return;
        var perc  = parseFloat(mvr.perc_meta) || 0;
        var corM  = perc >= 100 ? '#22c55e' : (perc >= 70 ? '#f59e0b' : '#ef4444');
        var chart = echarts.init(el, null, { renderer: 'canvas' });
        chart.setOption({
            backgroundColor: 'transparent',
            series: [{
                type: 'gauge',
                startAngle: 200, endAngle: -20,
                min: 0, max: 120,
                radius: '90%',
                pointer: { show: true, length: '60%', width: 5, itemStyle: { color: corM } },
                axisLine: { lineStyle: { width: 18, color: [[0.58,'#ef4444'],[0.83,'#f59e0b'],[1,'#22c55e']] } },
                axisTick: { show: false }, splitLine: { show: false }, axisLabel: { show: false },
                detail: { valueAnimation: true, formatter: function(v){ return v.toFixed(1)+'%'; },
                          color: corM, fontSize: 22, fontWeight: 'bold', offsetCenter: [0,'60%'] },
                title: { show: true, offsetCenter: [0,'85%'], color: '#64748b', fontSize: 12 },
                data: [{ value: Math.min(perc, 120), name: 'da meta' }]
            }]
        });
        window.addEventListener('resize', function(){ chart.resize(); });
    }

    // Renderiza seção Meta vs Realizado
    function renderMeta(dados) {
        var mvr  = dados.meta_vs_real;
        var meta = dados.meta;
        var el   = document.getElementById('skelMetaCard');
        if (!el) return;

        var nomeMeses = ['','Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'];

        if (!mvr.tem_meta) {
            el.outerHTML = '<div class="alert d-flex align-items-center gap-3 mb-4" style="background:var(--pbi-surface);border:1px dashed var(--pbi-border);border-radius:10px">' +
                '<i class="bi bi-bullseye fs-4 text-muted"></i>' +
                '<div><strong>Metas não configuradas.</strong><span class="text-muted ms-1">Configure as metas mensais para ver o progresso e a projeção no dashboard.</span></div>' +
                '<a href="/metas?ano=' + (mvr.ano || new Date().getFullYear()) + '" class="btn pbi-btn-filtrar btn-sm ms-auto"><i class="bi bi-bullseye me-1"></i>Configurar Metas</a>' +
                '</div>';
            return;
        }

        var percMeta = parseFloat(mvr.perc_meta) || 0;
        var percProj = parseFloat(mvr.perc_proj) || 0;
        var corR = percMeta >= 100 ? '#22c55e' : (percMeta >= 70 ? '#f59e0b' : '#ef4444');
        var corP = percProj >= 100 ? '#22c55e' : (percProj >= 70 ? '#f59e0b' : '#ef4444');
        var corG = parseFloat(mvr.gap) <= 0 ? '#22c55e' : '#ef4444';
        var clsR = percMeta >= 100 ? 'text-success' : (percMeta >= 70 ? 'text-warning' : 'text-danger');
        var clsP = percProj >= 100 ? 'text-success' : (percProj >= 70 ? 'text-warning' : 'text-danger');
        var clsG = parseFloat(mvr.gap) <= 0 ? 'text-success' : 'text-danger';
        var diasP = Math.round(mvr.dia_ref / mvr.dias_mes * 100);

        el.outerHTML = '<div class="pbi-card mb-4" id="metaCard">' +
            '<div class="pbi-card-header d-flex justify-content-between align-items-center">' +
            '<span><i class="bi bi-bullseye me-2"></i>Meta × Realizado — ' + (nomeMeses[mvr.mes] || '') + ' ' + mvr.ano + '</span>' +
            '<a href="/metas?ano=' + mvr.ano + '" class="btn btn-sm btn-outline-secondary"><i class="bi bi-pencil me-1"></i>Editar Metas</a>' +
            '</div><div class="p-3">' +
            '<div class="pbi-hint mb-3" style="margin-top:0"><strong>Meta do Mês</strong> = objetivo de faturamento do mês. <strong>Realizado</strong> = quanto já vendeu até hoje. <strong>Projeção Final</strong> = quanto o mês deve fechar mantendo o ritmo atual (no começo do mês costuma exagerar, pois usa a média diária x dias do mês). <strong>GAP</strong> = quanto falta (vermelho) ou sobra (verde) pra bater a meta. O ponteiro mostra a % da meta já atingida.</div>' +
            '<div class="row g-3 align-items-center">' +
            '<div class="col-lg-4 text-center"><div id="gaugeMetaDash" style="height:220px"></div></div>' +
            '<div class="col-lg-8"><div class="row g-3">' +
            '<div class="col-6 col-md-3"><div class="pbi-kpi-card h-100" style="border-color:#4f8ef7"><div class="pbi-kpi-label">Meta do Mês</div><div class="pbi-kpi-value text-primary">' + moeda(mvr.meta) + '</div><div class="pbi-kpi-sub">' + mvr.dias_mes + ' dias</div></div></div>' +
            '<div class="col-6 col-md-3"><div class="pbi-kpi-card h-100" style="border-color:' + corR + '"><div class="pbi-kpi-label">Realizado</div><div class="pbi-kpi-value ' + clsR + '">' + moeda(mvr.realizado) + '</div><div class="pbi-kpi-sub">' + fmtPct(percMeta) + ' da meta</div></div></div>' +
            '<div class="col-6 col-md-3"><div class="pbi-kpi-card h-100" style="border-color:' + corP + '"><div class="pbi-kpi-label">Projeção Final</div><div class="pbi-kpi-value ' + clsP + '">' + moeda(mvr.projecao) + '</div><div class="pbi-kpi-sub">' + fmtPct(percProj) + ' da meta</div></div></div>' +
            '<div class="col-6 col-md-3"><div class="pbi-kpi-card h-100" style="border-color:' + corG + '"><div class="pbi-kpi-label">GAP (Falta/Sobra)</div><div class="pbi-kpi-value ' + clsG + '">' + (parseFloat(mvr.gap) <= 0 ? '+' : '-') + moeda(Math.abs(mvr.gap)) + '</div><div class="pbi-kpi-sub">' + mvr.dias_rest + ' dias restantes</div></div></div>' +
            '</div>' +
            '<div class="mt-3"><div class="d-flex justify-content-between small text-muted mb-1"><span>Progresso do mês (dia ' + mvr.dia_ref + '/' + mvr.dias_mes + ')</span><span>Média: ' + moeda(mvr.media_dia) + '/dia</span></div>' +
            '<div class="progress" style="height:8px;background:var(--pbi-border)"><div class="progress-bar bg-info" style="width:' + diasP + '%;opacity:.4"></div></div>' +
            '<div class="d-flex justify-content-between small text-muted mt-1"><span>' + diasP + '% dos dias passados</span><span>' + fmtPct(percMeta) + ' da meta atingida</span></div></div>' +
            '</div></div></div></div>';

        renderGauge(mvr);
    }

    // Renderiza alertas
    function renderAlertas(al) {
        var el = document.getElementById('skelAlertas');
        if (!el) return;
        var html = '';
        if (al.inadimplencia_valor > 0) html +=
            '<div class="col-12 col-sm-6 col-xl-3"><a href="/relatorios/inadimplencia" class="text-decoration-none">' +
            '<div class="pbi-alerta-card pbi-alerta-danger"><div class="pbi-alerta-icon"><i class="bi bi-exclamation-triangle-fill"></i></div>' +
            '<div class="pbi-alerta-body"><div class="pbi-alerta-titulo">Inadimplência</div><div class="pbi-alerta-valor">R$ ' + fmt0(al.inadimplencia_valor) + '</div><div class="pbi-alerta-sub">títulos vencidos</div></div>' +
            '<i class="bi bi-arrow-right-circle pbi-alerta-arrow"></i></div></a></div>';
        if (al.pagar_vencido_valor > 0) html +=
            '<div class="col-12 col-sm-6 col-xl-3"><a href="/financeiro/contas-pagar" class="text-decoration-none">' +
            '<div class="pbi-alerta-card pbi-alerta-warning"><div class="pbi-alerta-icon"><i class="bi bi-calendar-x-fill"></i></div>' +
            '<div class="pbi-alerta-body"><div class="pbi-alerta-titulo">Contas Vencidas a Pagar</div><div class="pbi-alerta-valor">R$ ' + fmt0(al.pagar_vencido_valor) + '</div><div class="pbi-alerta-sub">em atraso</div></div>' +
            '<i class="bi bi-arrow-right-circle pbi-alerta-arrow"></i></div></a></div>';
        if (al.estoque_abaixo_qtd > 0) html +=
            '<div class="col-12 col-sm-6 col-xl-3"><a href="/estoque/minimos" class="text-decoration-none">' +
            '<div class="pbi-alerta-card pbi-alerta-info"><div class="pbi-alerta-icon"><i class="bi bi-boxes"></i></div>' +
            '<div class="pbi-alerta-body"><div class="pbi-alerta-titulo">Estoque Abaixo do Mínimo</div><div class="pbi-alerta-valor">' + fmt0(al.estoque_abaixo_qtd) + ' itens</div><div class="pbi-alerta-sub">precisam de reposição</div></div>' +
            '<i class="bi bi-arrow-right-circle pbi-alerta-arrow"></i></div></a></div>';
        if (al.clientes_inativos_60 > 0) html +=
            '<div class="col-12 col-sm-6 col-xl-3"><a href="/clientes/inativos" class="text-decoration-none">' +
            '<div class="pbi-alerta-card pbi-alerta-purple"><div class="pbi-alerta-icon"><i class="bi bi-person-x-fill"></i></div>' +
            '<div class="pbi-alerta-body"><div class="pbi-alerta-titulo">Clientes Inativos</div><div class="pbi-alerta-valor">' + fmt0(al.clientes_inativos_60) + ' clientes</div><div class="pbi-alerta-sub">sem compra há 60+ dias</div></div>' +
            '<i class="bi bi-arrow-right-circle pbi-alerta-arrow"></i></div></a></div>';
        if (html) { el.innerHTML = html; } else { el.style.display = 'none'; }
    }

    // Renderiza KPIs
    function renderKpis(ind, al, meta) {
        var nomeMesesFull = ['','Janeiro','Fevereiro','Março','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'];
        var partes = ((meta.data_ref_fmt) || '').split('/');
        var mAtual = parseInt(partes[1]) || new Date().getMonth() + 1;
        var aAtual = partes[2] || String(new Date().getFullYear());
        var nomeMesAtual = nomeMesesFull[mAtual] || '';
        var mAnt = mAtual === 1 ? 12 : mAtual - 1;
        var nomeMesAnt = nomeMesesFull[mAnt] || '';
        var mv = ind.melhor_vendedor || { NOME: '—', TOTAL: 0, QTD: 0 };

        function delta(d) {
            if (d === null || d === undefined) return '<span class="pbi-delta pbi-delta-neutro">—</span>';
            var cls = d >= 0 ? 'pbi-delta-up' : 'pbi-delta-down';
            var ico = d >= 0 ? '▲' : '▼';
            return '<span class="pbi-delta ' + cls + '">' + ico + ' ' + Math.abs(d).toLocaleString('pt-BR',{minimumFractionDigits:1,maximumFractionDigits:1}) + '%</span>';
        }

        // Atualiza label da seção Hoje
        var secHoje = document.querySelector('.pbi-kpi-secao-label');
        if (secHoje) secHoje.innerHTML = '<i class="bi bi-broadcast-pin me-1"></i>Hoje — ' + esc(meta.data_ref_fmt);

        // KPI Hoje — paleta: rosa, roxo, azul, cinza-azul
        var elHoje = document.getElementById('skelKpiHoje');
        if (elHoje) elHoje.innerHTML =
            kpiCardColor('bi-cash-stack', '', '#ec4899', 'Faturamento Hoje', moeda(ind.faturamento_hoje || 0),
                    '<span>' + fmt0(ind.total_vendas_hoje || 0) + ' notas</span> ' + delta(ind.delta_hoje_ontem)) +
            kpiCardColor('bi-receipt-cutoff', '', '#a855f7', 'Notas Emitidas', fmt0(ind.total_vendas_hoje || 0), 'cupons / NF-e') +
            kpiCardColor('bi-receipt', '', '#3b82f6', 'Ticket Médio', moeda(ind.ticket_medio || 0), 'por venda') +
            kpiCardColor('bi-graph-up', '', '#64748b', 'vs Ontem',
                    '<span class="' + ((ind.delta_hoje_ontem || 0) >= 0 ? 'text-success' : 'text-danger') + '">' +
                    (ind.delta_hoje_ontem !== null && ind.delta_hoje_ontem !== undefined
                        ? (ind.delta_hoje_ontem >= 0 ? '+' : '') + fmtPct(ind.delta_hoje_ontem)
                        : '—') + '</span>',
                    'variação diária');

        // KPI Mês — paleta: roxo (faturamento), verde (lucro/médio), amarelo (margem), azul (projeção)
        var elMes = document.getElementById('skelKpiMes');
        if (elMes) {
            var secMes = elMes.previousElementSibling;
            if (secMes) secMes.innerHTML = '<i class="bi bi-calendar-month me-1"></i>Mês — ' + nomeMesAtual + ' ' + aAtual;
            elMes.innerHTML =
                kpiCardColor('bi-graph-up-arrow', '', '#8b5cf6', 'Faturamento Mês', moeda(ind.faturamento_mes || 0),
                        '<span>' + fmt0(ind.total_vendas_mes || 0) + ' notas</span> ' + delta(ind.delta_mes_anterior)) +
                kpiCardColor('bi-calendar-day', '', '#10b981', 'Média Diária', moeda(ind.media_diaria || 0), 'por dia útil') +
                kpiCardColor('bi-rocket-takeoff', '', '#3b82f6', 'Projeção do Mês', moeda(ind.projecao_mes || 0), 'extrapolação linear') +
                kpiCardColor('bi-calendar2-check', '', '#f59e0b', 'vs ' + nomeMesAnt + ' / Ano Ant.',
                        '<span style="font-size:.95rem">' +
                        '<span class="' + ((ind.delta_mes_anterior || 0) >= 0 ? 'text-success' : 'text-danger') + '">' +
                        (ind.delta_mes_anterior !== null && ind.delta_mes_anterior !== undefined
                            ? (ind.delta_mes_anterior >= 0 ? '+' : '') + fmtPct(ind.delta_mes_anterior) : '—') + '</span>' +
                        '<span class="text-muted mx-1">/</span>' +
                        '<span class="' + ((ind.delta_mes_ano_anterior || 0) >= 0 ? 'text-success' : 'text-danger') + '">' +
                        (ind.delta_mes_ano_anterior !== null && ind.delta_mes_ano_anterior !== undefined
                            ? (ind.delta_mes_ano_anterior >= 0 ? '+' : '') + fmtPct(ind.delta_mes_ano_anterior) : '—') + '</span>' +
                        '</span>',
                        'mês ant. / mesmo mês ano ant.');
        }

        // KPI Financeiro — paleta: verde-mar (a receber), vermelho (vencido), laranja (a pagar), vermelho-laranja (pagar vencido)
        var elFin = document.getElementById('skelKpiFinanceiro');
        if (elFin) elFin.innerHTML =
            kpiCardColor('bi-arrow-down-circle-fill', '', '#14b8a6', 'A Receber', '<span>' + moeda(al.a_receber_valor || 0) + '</span>', 'títulos a vencer') +
            kpiCardColor('bi-exclamation-circle-fill', '', '#ef4444', 'Receber Vencido', '<span class="' + ((al.inadimplencia_valor || 0) > 0 ? 'text-danger' : '') + '">' + moeda(al.inadimplencia_valor || 0) + '</span>', 'inadimplência') +
            kpiCardColor('bi-arrow-up-circle-fill', '', '#f97316', 'A Pagar', moeda(al.a_pagar_valor || 0), 'títulos a vencer') +
            kpiCardColor('bi-calendar-x-fill', '', '#ef4444', 'Pagar Vencido', '<span class="' + ((al.pagar_vencido_valor || 0) > 0 ? 'text-warning' : '') + '">' + moeda(al.pagar_vencido_valor || 0) + '</span>', 'pagamentos em atraso');

        // KPI Operacional — paleta: amarelo escuro (estoque), azul (clientes), roxo claro (sem mov/inativos), verde
        var elOp = document.getElementById('skelKpiOperacional');
        if (elOp) elOp.innerHTML =
            kpiCardColor('bi-boxes', '', '#eab308', 'Itens Abaixo do Mínimo',
                         '<span class="' + ((al.estoque_abaixo_qtd || 0) > 0 ? 'text-danger' : 'text-success') + '">' + fmt0(al.estoque_abaixo_qtd || 0) + '</span>',
                         'produtos abaixo do mínimo') +
            kpiCardColor('bi-people-fill', '', '#0ea5e9', 'Clientes Ativos',
                         fmt0(ind.clientes_ativos_mes || 0), 'compraram em ' + nomeMesAtual) +
            kpiCardColor('bi-trophy-fill', '', '#f59e0b', 'Melhor Vendedor',
                         '<span style="font-size:1rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">' + esc(mv.NOME) + '</span>',
                         moeda(parseFloat(mv.TOTAL || 0)) + ' · ' + fmt0(mv.QTD || 0) + ' notas') +
            (D.temMesa
                ? kpiCardColor('bi-door-open-fill', '', '#10b981', 'Mesas Abertas', fmt0(ind.mesas_abertas || 0), 'em atendimento agora')
                : kpiCardColor('bi-person-x-fill', '', '#a855f7', 'Inativos +60 dias',
                               '<span class="' + ((al.clientes_inativos_60 || 0) > 0 ? 'text-warning' : '') + '">' + fmt0(al.clientes_inativos_60 || 0) + '</span>',
                               'clientes sem comprar'));
    }

    // Converte uma cor hex em rgba com alpha (para o fundo suave do ícone)
    function hexToRgba(hex, alpha) {
        var h = String(hex || '#4f8ef7').replace('#','');
        if (h.length === 3) h = h.split('').map(function(c){return c+c;}).join('');
        var r = parseInt(h.substring(0,2), 16);
        var g = parseInt(h.substring(2,4), 16);
        var b = parseInt(h.substring(4,6), 16);
        return 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')';
    }

    // KPI moderno (estilo MasterSoftware) — borda lateral colorida + ícone arredondado em container colorido
    function kpiCardColor(icon, bgIgnored, color, label, valor, sub) {
        var c = color || '#4f8ef7';
        var bg = hexToRgba(c, 0.14);
        return '<div class="pbi-kpi-card pbi-kpi-color" style="border-left-color:' + c + '">' +
            '<div class="pbi-kpi-icon" style="background:' + bg + ';color:' + c + '"><i class="bi ' + icon + '"></i></div>' +
            '<div class="pbi-kpi-body"><div class="pbi-kpi-label">' + label + '</div>' +
            '<div class="pbi-kpi-valor">' + valor + '</div>' +
            '<div class="pbi-kpi-sub">' + sub + '</div>' +
            '</div></div>';
    }

    // Versão antiga (compat) — agora também usa a paleta colorida. O 4º arg "accent" continua aceito por compat.
    function kpiCard(icon, bg, label, valor, sub, accent) {
        // Reaproveita o estilo color usando o accent (rosa default) ou roxo para "mês"
        var color = accent ? '#ec4899' : '#8b5cf6';
        return '<div class="pbi-kpi-card pbi-kpi-color" style="border-left-color:' + color + '">' +
            '<div class="pbi-kpi-icon" style="background:' + hexToRgba(color, 0.14) + ';color:' + color + '"><i class="bi ' + icon + '"></i></div>' +
            '<div class="pbi-kpi-body"><div class="pbi-kpi-label">' + label + '</div>' +
            '<div class="pbi-kpi-valor">' + valor + '</div>' +
            '<div class="pbi-kpi-sub d-flex align-items-center gap-2">' + sub + '</div>' +
            '</div></div>';
    }

    // Renderiza gráfico 30 dias
    function renderG30(gDias) {
        var el = clearSkel('grafico30dias');
        if (!el) return;
        var g = echarts.init(el, null, { renderer: 'canvas' });
        var labels = gDias.labels || ['Sem dados'];
        var vals   = gDias.valores || [0];
        g.setOption(Object.assign(base(), {
            tooltip: { trigger:'axis', ...tooltipDark(function(p){ return p[0].name+'<br/>R$ '+p[0].value.toLocaleString('pt-BR',{minimumFractionDigits:2}); }) },
            xAxis: { type:'category', data:labels, axisLine:{lineStyle:{color:corGrade}}, axisLabel:{color:corTexto,rotate:labels.length>15?45:0,fontSize:10} },
            yAxis: { type:'value', splitLine:{lineStyle:{color:corGrade}}, axisLabel:{color:corTexto,formatter:function(v){return 'R$'+v.toLocaleString('pt-BR');}} },
            series:[{ type:'bar', data:vals, barMaxWidth:32,
                itemStyle:{color:{type:'linear',x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:corAcento},{offset:1,color:corSup}]},borderRadius:[4,4,0,0]},
                emphasis:{itemStyle:{color:corAcento}} }]
        }));
        window.addEventListener('resize', function(){ g.resize(); });
    }

    // Renderiza gráfico horas
    function renderGHoras(gHoras) {
        var el = clearSkel('graficoHoras');
        if (!el) return;
        var g    = echarts.init(el, null, { renderer: 'canvas' });
        var labH = gHoras.labels || ['Sem dados'];
        var vH   = gHoras.valores || [0];
        g.setOption(Object.assign(base(), {
            tooltip: { trigger:'axis', ...tooltipDark() },
            xAxis: { type:'category', data:labH, axisLine:{lineStyle:{color:corGrade}}, axisLabel:{color:corTexto} },
            yAxis: { type:'value', splitLine:{lineStyle:{color:corGrade}}, axisLabel:{color:corTexto} },
            series:[{ type:'line', data:vH, smooth:true,
                lineStyle:{color:corVerde,width:2}, itemStyle:{color:corVerde},
                areaStyle:{color:{type:'linear',x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:'rgba(34,197,94,0.25)'},{offset:1,color:'rgba(34,197,94,0.02)'}]}} }]
        }));
        window.addEventListener('resize', function(){ g.resize(); });
    }

    // Renderiza gráfico anual
    function renderGAnual(gAnual) {
        var el = clearSkel('graficoAnual');
        if (!el) return;
        var g    = echarts.init(el, null, { renderer: 'canvas' });
        var labA = gAnual.labels || ['Sem dados'];
        var vA   = gAnual.valores || [0];
        var tA   = gAnual.tickets || [0];
        g.setOption(Object.assign(base(50), {
            legend: { top:0, textStyle:{color:corTexto}, data:['Faturamento','Ticket Médio'] },
            tooltip: { trigger:'axis', ...tooltipDark(function(ps){
                var s=ps[0].name+'<br/>';
                ps.forEach(function(p){ s+=p.marker+p.seriesName+': R$ '+p.value.toLocaleString('pt-BR',{minimumFractionDigits:2})+'<br/>'; });
                return s;
            })},
            xAxis: { type:'category', data:labA, axisLine:{lineStyle:{color:corGrade}}, axisLabel:{color:corTexto} },
            yAxis: { type:'value', splitLine:{lineStyle:{color:corGrade}}, axisLabel:{color:corTexto,formatter:function(v){return 'R$'+v.toLocaleString('pt-BR');}} },
            series:[
                { name:'Faturamento', type:'bar', data:vA, barMaxWidth:40,
                  itemStyle:{color:{type:'linear',x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:corAcento},{offset:1,color:corSup}]},borderRadius:[4,4,0,0]} },
                { name:'Ticket Médio', type:'line', data:tA, smooth:true,
                  lineStyle:{color:corAmarelo,width:2}, itemStyle:{color:corAmarelo} }
            ]
        }));
        window.addEventListener('resize', function(){ g.resize(); });
    }

    // Renderiza gráfico mensal
    function renderGMensal(gMensal) {
        var el = clearSkel('graficoMensal');
        if (!el) return;
        var g    = echarts.init(el, null, { renderer: 'canvas' });
        var labM = gMensal.labels || ['Sem dados'];
        var vM   = gMensal.valores || [0];
        g.setOption(Object.assign(base(), {
            tooltip: { trigger:'axis', ...tooltipDark(function(p){ return p[0].name+'<br/>R$ '+p[0].value.toLocaleString('pt-BR',{minimumFractionDigits:2}); }) },
            dataZoom: [{ type:'inside', start:Math.max(0,100-Math.round(2400/labM.length)), end:100 }, { type:'slider', height:18, bottom:0, fillerColor:'rgba(79,142,247,0.2)', borderColor:corGrade, textStyle:{color:corTexto} }],
            xAxis: { type:'category', data:labM, axisLine:{lineStyle:{color:corGrade}}, axisLabel:{color:corTexto,rotate:45,fontSize:10} },
            yAxis: { type:'value', splitLine:{lineStyle:{color:corGrade}}, axisLabel:{color:corTexto,formatter:function(v){return 'R$'+v.toLocaleString('pt-BR');}} },
            series:[{ type:'bar', data:vM, barMaxWidth:24,
                itemStyle:{color:{type:'linear',x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:'#a78bfa'},{offset:1,color:'rgba(167,139,250,0.15)'}]},borderRadius:[4,4,0,0]},
                emphasis:{itemStyle:{color:'#a78bfa'}} }]
        }));
        window.addEventListener('resize', function(){ g.resize(); });
    }

    // Renderiza rolling 12m
    function renderGRolling(gR12m) {
        var el = clearSkel('graficoRolling12m');
        if (!el) return;
        var g    = echarts.init(el, null, { renderer: 'canvas' });
        var labR = gR12m.labels || ['Sem dados'];
        var vR   = gR12m.valores || [0];
        var ma3  = gR12m.ma3 || [null];
        if (!labR.length) { labR=['Sem dados']; vR=[0]; ma3=[null]; }
        g.setOption(Object.assign(base(60), {
            legend: { top:0, textStyle:{color:corTexto}, data:['Faturamento','Média 3m'] },
            tooltip: { trigger:'axis', ...tooltipDark(function(ps){
                var s=ps[0].name+'<br/>';
                ps.forEach(function(p){ if(p.value!==null&&p.value!==undefined) s+=p.marker+p.seriesName+': R$ '+(+p.value).toLocaleString('pt-BR',{minimumFractionDigits:2})+'<br/>'; });
                return s;
            })},
            xAxis: { type:'category', data:labR, axisLine:{lineStyle:{color:corGrade}}, axisLabel:{color:corTexto,fontSize:11} },
            yAxis: { type:'value', splitLine:{lineStyle:{color:corGrade}}, axisLabel:{color:corTexto,formatter:function(v){return 'R$'+v.toLocaleString('pt-BR');}} },
            series:[
                { name:'Faturamento', type:'bar', data:vR, barMaxWidth:36,
                  itemStyle:{color:{type:'linear',x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:corAcento},{offset:1,color:corSup}]},borderRadius:[4,4,0,0]} },
                { name:'Média 3m', type:'line', data:ma3, smooth:true, connectNulls:false,
                  lineStyle:{color:corAmarelo,width:2.5}, itemStyle:{color:corAmarelo}, symbol:'circle', symbolSize:6 }
            ]
        }));
        window.addEventListener('resize', function(){ g.resize(); });
    }

    // Renderiza top produtos
    function renderGProdutos(topProdutos, topSemana, meta) {
        var prodDisplay = (topProdutos && topProdutos.length) ? topProdutos : topSemana;
        var prodLabel   = (topProdutos && topProdutos.length)
            ? (meta.e_hoje ? 'Hoje' : (meta.data_ref_fmt || 'Hoje'))
            : 'Últimos 7 dias';

        // Atualiza label do card
        var cardHeader = document.querySelector('#graficoProdutos')
            ? document.querySelector('#graficoProdutos').closest('.pbi-card')?.querySelector('.pbi-card-header') : null;
        if (cardHeader) cardHeader.innerHTML = '<i class="bi bi-trophy-fill me-2 text-accent"></i>Top Produtos — ' + prodLabel;

        var el = clearSkel('graficoProdutos');
        if (!el) return;

        if (!prodDisplay || !prodDisplay.length) {
            el.innerHTML = '<div class="p-4 text-center text-muted"><i class="bi bi-inbox fs-2"></i><p class="mt-2">Sem vendas no período.</p></div>';
            return;
        }

        var g    = echarts.init(el, null, { renderer: 'canvas' });
        var data = prodDisplay.slice(0, 8).map(function(p) { return { name: p.PRODUTO, value: Math.round(parseFloat(p.TOTAL) * 100) / 100 }; });

        g.setOption({
            backgroundColor: 'transparent',
            tooltip:{ trigger:'axis', axisPointer:{type:'shadow'}, ...tooltipDark(function(p){ return p[0].name+'<br/>R$ '+p[0].value.toLocaleString('pt-BR',{minimumFractionDigits:2}); }) },
            grid:{ top:10, right:20, bottom:10, left:10, containLabel:true },
            xAxis:{ type:'value', show:false },
            yAxis:{ type:'category', data:data.map(function(p){ var n=p.name||'(sem desc.)'; return n.length>22?n.substring(0,22)+'…':n; }),
                axisLabel:{color:corTexto,fontSize:11}, axisLine:{lineStyle:{color:corGrade}}, inverse:true },
            series:[{ type:'bar', data:data.map(function(p){return p.value;}), barMaxWidth:28,
                itemStyle:{color:corAcento,borderRadius:[0,6,6,0]},
                label:{show:true,position:'right',formatter:function(p){return 'R$'+p.value.toLocaleString('pt-BR',{minimumFractionDigits:2});},color:corTexto,fontSize:10}
            }]
        });
        window.addEventListener('resize', function(){ g.resize(); });
    }

    // Renderiza Comparativo período atual × anterior
    // TODO: trazer dados reais do DashboardRepository::comparativo() — por ora, placeholder a partir
    // dos KPIs já disponíveis no payload (faturamento mês × delta_mes_anterior); demais métricas mostradas estáticas.
    function renderComparativo(ind, dados) {
        var el = clearSkel('graficoComparativo');
        if (!el || typeof echarts === 'undefined') return;

        // Cálculo do "anterior" a partir do delta % (quando disponível). Demais métricas: placeholders.
        var fatAtual = parseFloat(ind.faturamento_mes || 0);
        var deltaFat = parseFloat(ind.delta_mes_anterior || 0); // percentual
        var fatAnt   = deltaFat !== 0 ? (fatAtual / (1 + deltaFat / 100)) : fatAtual * 0.92;

        var lucroAtual = fatAtual * 0.32;   // placeholder
        var lucroAnt   = fatAnt   * 0.30;

        var ticketAtual = parseFloat(ind.ticket_medio || 0);
        var ticketAnt   = ticketAtual * 0.95;

        var clientesAtual = parseInt(ind.clientes_ativos_mes || 0);
        var clientesAnt   = Math.round(clientesAtual * 0.90);

        var g = echarts.init(el, null, { renderer: 'canvas' });
        g.setOption({
            backgroundColor: 'transparent',
            tooltip: {
                trigger: 'axis', axisPointer: { type: 'shadow' },
                ...tooltipDark(function(ps){
                    var s = ps[0].name + '<br/>';
                    ps.forEach(function(p){
                        var v = p.value;
                        var fmt = (p.name === 'Clientes') ? fmt0(v) : moeda(v);
                        s += p.marker + p.seriesName + ': <b>' + fmt + '</b><br/>';
                    });
                    return s;
                })
            },
            legend: { top: 0, textStyle: { color: corTexto }, data: ['Atual', 'Anterior'] },
            grid: { top: 28, right: 14, bottom: 24, left: 10, containLabel: true },
            xAxis: {
                type: 'category',
                data: ['Faturamento', 'Lucro', 'Ticket', 'Clientes'],
                axisLine: { lineStyle: { color: corGrade } },
                axisLabel: { color: corTexto, fontSize: 11 }
            },
            yAxis: { type: 'value', show: false, splitLine: { show: false } },
            series: [
                {
                    name: 'Atual', type: 'bar', barMaxWidth: 22,
                    itemStyle: { color: '#f97316', borderRadius: [6, 6, 0, 0] },
                    label: {
                        show: true, position: 'top', color: corTexto, fontSize: 10,
                        formatter: function(p){
                            var v = p.value;
                            if (p.name === 'Clientes') return fmt0(v);
                            if (v >= 1e6) return 'R$' + (v/1e6).toFixed(1) + 'M';
                            if (v >= 1e3) return 'R$' + (v/1e3).toFixed(0) + 'k';
                            return 'R$' + Math.round(v);
                        }
                    },
                    data: [fatAtual, lucroAtual, ticketAtual, clientesAtual]
                },
                {
                    name: 'Anterior', type: 'bar', barMaxWidth: 22,
                    itemStyle: { color: 'rgba(249,115,22,0.35)', borderRadius: [6, 6, 0, 0] },
                    data: [fatAnt, lucroAnt, ticketAnt, clientesAnt]
                }
            ]
        });
        window.addEventListener('resize', function(){ g.resize(); });
    }

    // Renderiza mesas
    function renderMesas(mesas) {
        var col = document.getElementById('colMesas');
        if (!col) return;
        if (!D.temMesa) { col.style.display = 'none'; return; }
        var body = col.querySelector('.pbi-card-body');
        if (!body) return;
        if (!mesas || !mesas.length) {
            body.innerHTML = '<div class="text-center text-muted"><i class="bi bi-door-closed fs-2"></i><p class="mt-2">Nenhuma mesa aberta.</p></div>';
            return;
        }
        var rows = mesas.map(function(m) {
            return '<tr><td class="fw-semibold">' + esc(m.MESA) + '</td>' +
                '<td class="text-muted small">' + esc((m.HORA_ABERTURA||'').substring(0,5)) + '</td>' +
                '<td class="text-muted">' + parseInt(m.PESSOAS||0) + '</td>' +
                '<td class="text-end fw-semibold text-accent">' + moeda(parseFloat(m.TOTAL||0)) + '</td></tr>';
        }).join('');
        var header = col.querySelector('.pbi-card-header');
        if (header) header.innerHTML = '<i class="bi bi-grid-3x3-gap-fill me-2 text-accent"></i>Mesas Abertas <span class="ms-auto pbi-tag-salvo">' + mesas.length + '</span>';
        body.innerHTML = '<div class="table-responsive"><table class="pbi-table">' +
            '<thead><tr><th>Mesa</th><th>Abertura</th><th>Pessoas</th><th class="text-end">Total</th></tr></thead>' +
            '<tbody>' + rows + '</tbody></table></div>';
    }

    // Renderiza top semana
    function renderTopSemana(semana) {
        var el = document.getElementById('dashTopSemana');
        if (!el || !semana || !semana.length) return;
        var rows = semana.map(function(p, i) {
            return '<tr><td class="text-muted">' + (i+1) + '</td>' +
                '<td class="text-muted" style="white-space:nowrap">' + esc(p.COD_ITEM) + '</td>' +
                '<td class="fw-semibold">' + esc(p.PRODUTO) + '</td>' +
                '<td class="text-end text-muted">' + parseFloat(p.QTD).toLocaleString('pt-BR',{minimumFractionDigits:3,maximumFractionDigits:3}) + '</td>' +
                '<td class="text-end fw-semibold">' + moeda(parseFloat(p.TOTAL||0)) + '</td></tr>';
        }).join('');
        el.innerHTML = '<div class="pbi-card mb-4"><div class="pbi-card-header"><i class="bi bi-star-fill me-2 text-accent"></i>Top 10 Produtos — Últimos 7 dias</div>' +
            '<div class="pbi-card-body p-0"><div class="table-responsive"><table class="pbi-table">' +
            '<thead><tr><th>#</th><th>Código</th><th>Produto</th><th class="text-end">Qtd</th><th class="text-end">Total</th></tr></thead>' +
            '<tbody>' + rows + '</tbody></table></div></div></div>';
    }

    // Renderiza top histórico + top dias
    function renderTopHistorico(topHist, topDias, meta) {
        var el = document.getElementById('dashTopHistorico');
        if (!el || !topHist || !topHist.length) return;

        var rowsH = topHist.map(function(p, i) {
            return '<tr><td class="text-muted">' + (i+1) + '</td>' +
                '<td class="text-muted" style="white-space:nowrap">' + esc(p.COD_ITEM) + '</td>' +
                '<td class="fw-semibold">' + esc(p.PRODUTO) + '</td>' +
                '<td class="text-end text-muted">' + fmt0(p.QTD) + '</td>' +
                '<td class="text-end text-muted">' + fmt0(p.QTD_NOTAS) + '</td>' +
                '<td class="text-end fw-semibold text-accent">' + moeda(parseFloat(p.TOTAL||0)) + '</td></tr>';
        }).join('');

        var rowsD = (topDias || []).map(function(d) {
            var dataFmt = String(d.DIA || '');
            if (dataFmt.length >= 10) dataFmt = dataFmt.substring(8,10)+'/'+dataFmt.substring(5,7)+'/'+dataFmt.substring(0,4);
            return '<tr><td class="fw-semibold">' + esc(dataFmt) + '</td>' +
                '<td class="text-end text-muted">' + fmt0(d.QTD_VENDAS) + '</td>' +
                '<td class="text-end fw-semibold text-accent">' + moeda(parseFloat(d.TOTAL||0)) + '</td></tr>';
        }).join('');

        var bancoRange = meta.banco_inicio ? '<small class="ms-auto text-muted">' + esc(meta.banco_inicio) + ' → ' + esc(meta.banco_fim) + '</small>' : '';

        el.innerHTML = '<div class="row g-4 mb-4">' +
            '<div class="col-lg-7"><div class="pbi-card"><div class="pbi-card-header"><i class="bi bi-award-fill me-2 text-accent"></i>Top 15 Produtos — Todos os tempos ' + bancoRange + '</div>' +
            '<div class="pbi-card-body p-0"><div class="table-responsive"><table class="pbi-table">' +
            '<thead><tr><th>#</th><th>Código</th><th>Produto</th><th class="text-end">Qtd total</th><th class="text-end">Notas</th><th class="text-end">Faturado</th></tr></thead>' +
            '<tbody>' + rowsH + '</tbody></table></div></div></div></div>' +
            '<div class="col-lg-5"><div class="pbi-card"><div class="pbi-card-header"><i class="bi bi-fire me-2 text-accent"></i>Top 10 Dias — Maior faturamento</div>' +
            '<div class="pbi-card-body p-0"><div class="table-responsive"><table class="pbi-table">' +
            '<thead><tr><th>Data</th><th class="text-end">Vendas</th><th class="text-end">Total</th></tr></thead>' +
            '<tbody>' + rowsD + '</tbody></table></div></div></div></div>' +
            '</div>';
    }

    // ── Carrega dados via fetch ───────────────────────────────────────────────
    document.addEventListener('DOMContentLoaded', function () {
        fetch(D.apiUrl)
            .then(function(r) { return r.json(); })
            .then(function(res) {
                if (res.erro) {
                    setConnBadge(false, 'Sem conexão');
                    document.getElementById('dashContent').innerHTML =
                        '<div class="pbi-alert pbi-alert-danger"><i class="bi bi-exclamation-triangle-fill fs-5"></i>' +
                        '<div><strong>Erro ao carregar dados.</strong><br><small>' + esc(res.erro) + '</small></div>' +
                        '<a href="/configurar" class="btn pbi-btn-outline btn-sm ms-auto">Configurar</a></div>';
                    return;
                }

                setConnBadge(true, 'Ao vivo');
                var dados = res.dados;

                renderMeta(dados);
                renderAlertas(dados.alertas);
                renderKpis(dados.indicadores, dados.alertas, dados.meta);
                renderG30(dados.grafico_dias);
                renderComparativo(dados.indicadores || {}, dados);
                renderGHoras(dados.grafico_horas);
                renderGAnual(dados.grafico_anual);
                renderGMensal(dados.grafico_mensal);
                renderGRolling(dados.rolling_12m);
                renderGProdutos(dados.top_produtos, dados.top_semana, dados.meta);
                renderMesas(dados.mesas);
                renderTopSemana(dados.top_semana);
                renderTopHistorico(dados.top_historico, dados.top_dias, dados.meta);
            })
            .catch(function(err) {
                setConnBadge(false, 'Erro');
                console.error('Dashboard API error:', err);
            });
    });

}());
</script>
