<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= htmlspecialchars($title ?? 'GestorEasy') ?></title>
    <link rel="stylesheet" href="/css/theme.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js" defer></script>
    <script src="/js/nfe_pdf.js" defer></script>
    <script src="/js/print-control.js" defer></script>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: var(--text-on-light); }
        .container { max-width: none; width: 100%; margin: 0; padding: 0 10px; }
        header { background: var(--color-white); border-bottom: 1px solid var(--border-muted); padding: 1rem 0; margin-bottom: 2rem; }
        .header-content { display: flex; justify-content: space-between; align-items: center; }
        .brand { font-size: 1.5rem; font-weight: bold; color: var(--color-olive); text-decoration: none; }
        .brand img { height: 40px; max-height: 40px; width: auto; display: block; }
nav a { margin-left: 1rem; color: #666; text-decoration: none; padding: 0.5rem 0.5rem; border-radius: 4px; transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease; }
nav a:hover { background-color: #f3f4f6; color: #111827; box-shadow: inset 0 0 0 1px #e5e7eb; }
        nav a:hover { background: #f3f4f6; color: #333; }
        nav a.active { background: var(--color-orange); color: white; }
        /* Dropdown menus */
        .nav { display:flex; align-items:center; gap:0.5rem; }
        .dropdown { position: relative; }
.dropdown > button { background: transparent; border: none; color: #444; padding: 0.5rem 0.75rem; border-radius: 6px; cursor: pointer; transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease; }
.dropdown > button:hover { background-color: #f3f4f6; color: #111827; box-shadow: inset 0 0 0 1px #e5e7eb; }
        .dropdown > button:hover, .dropdown[aria-expanded="true"] > button { background:#f3f4f6; }
        .dropdown-menu { position: absolute; top: calc(100% + 6px); left: 0; min-width: 240px; background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 10px 20px rgba(0,0,0,0.08); padding: 0.5rem; opacity: 0; transform: translateY(6px); pointer-events: none; transition: opacity 0.2s ease, transform 0.2s ease; z-index: 1000; }
        .dropdown[aria-expanded="true"] .dropdown-menu { opacity: 1; transform: translateY(0); pointer-events: auto; }
        .dropdown-group { padding: 0.25rem 0.25rem 0.5rem; }
        .dropdown-group h4 { margin: 0.25rem 0 0.25rem; padding: 0.25rem 0.5rem; font-size: 0.8rem; color: #6b7280; font-weight: 700; text-transform: uppercase; letter-spacing: .02em; }
.dropdown-item { display:flex; align-items:center; gap:0.5rem; color:#374151; text-decoration:none; padding:0.4rem 0.5rem; border-radius:6px; transition: background-color 0.3s ease, color 0.3s ease; }
.dropdown-item:hover { background-color:#f3f4f6; color:#111827; }
        .dropdown-item.disabled { color:#9ca3af; cursor:not-allowed; }
        .dropdown-item:focus-visible { outline: 2px solid var(--color-olive); outline-offset: 2px; background: #f3f4f6; }
        .dropdown-item.active { background: var(--color-orange); color: #fff; }
        .dropdown > button:focus-visible { outline: 2px solid var(--color-olive); outline-offset: 2px; }
        .dropdown > button.active { background: var(--color-orange); color: #fff; }
        .menu-icon { width:24px; height:24px; flex: 0 0 24px; display:inline-flex; align-items:center; justify-content:center; color:#6b7280; }
        @media (max-width: 768px) {
            .nav { flex-wrap: wrap; gap: 0.25rem; }
            .dropdown-menu { position: static; transform:none; opacity:1; pointer-events:auto; box-shadow:none; border: none; padding: 0.25rem 0; }
        }
        main { min-height: calc(100vh - 200px); }
        .card { background: white; border-radius: 8px; padding: 1.5rem; margin-bottom: 1rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
        .btn { display: inline-block; padding: 0.5rem 1rem; background: var(--color-orange); color: white; text-decoration: none; border-radius: 4px; border: none; cursor: pointer; transition: all 0.2s; }
        .btn:hover { filter: brightness(0.95); }
        .btn-secondary { background: #6b7280; }
        .btn-secondary:hover { background: #4b5563; }
        .btn-danger { background: #dc2626; }
        .btn-danger:hover { background: #b91c1c; }
        .form-group { margin-bottom: 1rem; }
        .form-group label { display: block; margin-bottom: 0.5rem; font-weight: 500; }
        .form-group input, .form-group select, .form-group textarea { width: 100%; padding: 0.5rem; border: 1px solid #d1d5db; border-radius: 4px; font-size: 1rem; }
        .form-group input:focus, .form-group select:focus, .form-group textarea:focus { outline: none; border-color: var(--color-olive); box-shadow: 0 0 0 3px rgba(85, 107, 47, 0.15); }
        .alert { padding: 1rem; border-radius: 4px; margin-bottom: 1rem; }
        .alert-success { background: #d1fae5; color: #065f46; border: 1px solid #a7f3d0; }
        .alert-error { background: #fee2e2; color: #991b1b; border: 1px solid #fca5a5; }
        .table { width: 100%; border-collapse: collapse; }
        .table th, .table td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #e5e7eb; }
        .table th { background: #f9fafb; font-weight: 600; }
        .table tbody tr:hover { background: #f9fafb; }
        footer { background: var(--color-white); border-top: 1px solid var(--border-muted); padding: 1rem 0; margin-top: 2rem; text-align: center; color: #666; }
        .loading { display: none; text-align: center; padding: 2rem; }
        .loading.show { display: block; }
        /* Centralização para a página de login */
        .center-main { display: flex; align-items: center; justify-content: center; min-height: calc(100vh - 160px); }
        /* Transição suave de tema */
        html, body, .card, header, nav, .dropdown-menu { transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease; }
        @media (max-width: 768px) {
            .header-content { flex-direction: column; gap: 1rem; }
            nav { display: flex; flex-wrap: wrap; }
            nav a { margin: 0 0.5rem 0.5rem 0; }
        }
        /* Responsividade da logo: reduzir levemente em telas menores sem alterar altura do header */
        @media (max-width: 640px) {
            .brand img { height: 36px; max-height: 36px; }
        }
        @media (max-width: 420px) {
            .brand img { height: 34px; max-height: 34px; }
        }
        /* Regras globais de impressão: esconder cabeçalho/rodapé e elementos de navegação */
        @media print {
            header, footer, nav, .dropdown-menu { display: none !important; }
            body { background: #ffffff !important; }
            .container { padding: 0 !important; }
        }
    </style>
</head>
<?php 
    $currentPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
    $isLoginPage = ($currentPath === '/login' || strpos($currentPath, '/admin/login') === 0 || strpos($currentPath, '/admin/recovery') === 0 || strpos($currentPath, '/admin/reset') === 0);
    $isAdminArea = (strpos($currentPath, '/admin/') === 0);
    $showMenus = !($hideMenus ?? false) && !$isLoginPage;
?>
<body class="<?= $isLoginPage ? 'bg-gradient' : 'bg-light' ?>">
    <header>
        <div class="container">
            <div class="header-content">
                <?php if (!$isLoginPage): ?>
                <a href="/" class="brand" aria-label="Página inicial">
                    <img id="siteLogo" src="/assets/logo-dark.png" alt="GestorEasy" />
                </a>
                <?php endif; ?>
                <?php if ($showMenus): ?>
                <nav>
                    <?php if ($isAdminArea): ?>
                        <button id="themeToggle" class="btn btn-secondary" title="Alternar tema">🌞</button>
                        <a href="#" class="btn btn-danger" onclick="logout()">Sair</a>
                    <?php else: ?>
                        <div class="nav" role="menubar" aria-label="Navegação principal">
                          <div class="dropdown" role="none">
                            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                              Produtos ▾
                            </button>
                            <div class="dropdown-menu" role="menu" aria-label="Produtos">
                              <a href="/produtos" class="dropdown-item" role="menuitem">
                                Catálogo
                              </a>
                              <a href="/compras/ordens" class="dropdown-item" role="menuitem" data-required-perm="compras.read">Compras: Ordens</a>
                              <a href="/compras/cotacoes" class="dropdown-item" role="menuitem" data-required-perm="cotacoes.read">Compras: Cotações</a>
                              <a href="/estoque/thresholds" class="dropdown-item" role="menuitem" data-required-perm="estoque.read">Estoque: Limites</a>
                              <a href="/estoque/movimentos" class="dropdown-item" role="menuitem" data-required-perm="estoque.read">Estoque: Movimentos</a>
                              <a href="/lotes-series" class="dropdown-item" role="menuitem" data-required-perm="lotes.read">Lotes e Séries</a>
                              <a href="/wms/warehouses" class="dropdown-item" role="menuitem" data-required-perm="wms.read">WMS: Armazéns</a>
                              <a href="/wms/bins" class="dropdown-item" role="menuitem" data-required-perm="wms.read">WMS: Bins</a>
                              <a href="/wms/movimentos" class="dropdown-item" role="menuitem" data-required-perm="wms.read">WMS: Movimentações</a>
                              <a href="/wms/analytics" class="dropdown-item" role="menuitem" data-required-perm="wms.read">WMS: Analytics</a>
                            </div>
                          </div>
                          <div class="dropdown" role="none">
                            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                              Vendas ▾
                            </button>
                            <div class="dropdown-menu" role="menu" aria-label="Vendas">
                              <a href="/vendas/orcamentos" class="dropdown-item" role="menuitem">Orçamentos</a>
                              <a href="/vendas/pedidos" class="dropdown-item" role="menuitem">Pedidos</a>
                              <a href="/vendas/pdv" class="dropdown-item" role="menuitem" data-required-perm="pdv.read">PDV</a>
                              <a href="/vendas/ecommerce" class="dropdown-item" role="menuitem" data-required-perm="ecommerce.read">E-commerce</a>
                              <a href="/vendas/notas" class="dropdown-item" role="menuitem">Notas Fiscais</a>
                              <a href="/vendas/comissoes" class="dropdown-item" role="menuitem">Comissões</a>
                              <a href="/vendas/crm" class="dropdown-item" role="menuitem">CRM</a>
                              <a href="/crm-avancado" class="dropdown-item" role="menuitem" data-required-perm="crm.read">CRM Avançado</a>
                            </div>
                          </div>
                          <div class="dropdown" role="none">
                            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                              Cadastros ▾
                            </button>
                            <div class="dropdown-menu" role="menu" aria-label="Cadastros">
                              <a href="/clientes" class="dropdown-item" role="menuitem">Clientes</a>
                              <a href="/fornecedores" class="dropdown-item" role="menuitem" data-required-perm="cadastros.fornecedores.read">Fornecedores</a>
                              <a href="/cadastros/empresas" class="dropdown-item" role="menuitem" data-required-perm="cadastros.empresas.read">Empresas (multicompany)</a>
                              <a href="/cadastros/transportadoras" class="dropdown-item" role="menuitem" data-required-perm="cadastros.transportadoras.read">Transportadoras</a>
                              <a href="/cadastros/usuarios" class="dropdown-item" role="menuitem" data-required-perm="cadastros.usuarios.read">Usuários</a>
                              <a href="/cadastros/vendedores" class="dropdown-item" role="menuitem" data-required-perm="cadastros.vendedores.read">Vendedores</a>
                              <a href="/cadastros/tecnicos" class="dropdown-item" role="menuitem" data-required-perm="cadastros.tecnicos.read">Técnicos</a>
                            </div>
                          </div>
                          <div class="dropdown" role="none">
                            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                              Financeiro ▾
                            </button>
                            <div class="dropdown-menu" role="menu" aria-label="Financeiro">
                              <a href="/financeiro/pagar" class="dropdown-item" role="menuitem">Contas a Pagar</a>
                              <a href="/financeiro/receber" class="dropdown-item" role="menuitem">Contas a Receber</a>
                              <a href="/financeiro/fluxo" class="dropdown-item" role="menuitem">Fluxo de Caixa</a>
                              <a href="/financeiro/bancos" class="dropdown-item" role="menuitem">Bancos</a>
                              <a href="/financeiro/relatorios" class="dropdown-item" role="menuitem">Relatórios Financeiros</a>
                            </div>
                          </div>
                          <div class="dropdown" role="none">
                            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                              Relatórios ▾
                            </button>
                            <div class="dropdown-menu" role="menu" aria-label="Relatórios">
                              <div class="dropdown-group">
                                <h4>Gerenciais</h4>
                                <a href="/relatorios/vendas" class="dropdown-item" role="menuitem">Vendas por período/produto/vendedor</a>
                                <a href="/relatorios/compras" class="dropdown-item" role="menuitem">Compras por fornecedor</a>
                                <a href="/relatorios/estoque" class="dropdown-item" role="menuitem">Movimentação de estoque</a>
                                <a href="/financeiro/relatorios" class="dropdown-item" role="menuitem">Performance financeira</a>
                              </div>
                              <div class="dropdown-group">
                                <h4>Operacionais</h4>
                                <a href="/relatorios/clientes" class="dropdown-item" role="menuitem">Listagem de clientes</a>
                                <a href="/relatorios/produtos-criticos" class="dropdown-item" role="menuitem">Produtos críticos</a>
                                <a href="/relatorios/titulos-a-vencer" class="dropdown-item" role="menuitem">Títulos a vencer</a>
                              </div>
                            </div>
                          </div>
                          <div class="dropdown" role="none" data-required-perm="servicos.read">
                            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                              Serviços ▾
                            </button>
        <div class="dropdown-menu" role="menu" aria-label="Serviços">
          <a href="/servicos/dashboard" class="dropdown-item" role="menuitem">Dashboard de Serviços</a>
          <a href="/servicos/veiculos" class="dropdown-item" role="menuitem">Veículos</a>
          <a href="/servicos/ordens" class="dropdown-item" role="menuitem">Ordens de Serviço</a>
          <a href="/servicos/checklists" class="dropdown-item" role="menuitem">Checklists</a>
          <a href="/servicos/documentos" class="dropdown-item" role="menuitem">Documentos</a>
          <a href="/servicos/nfse" class="dropdown-item" role="menuitem">Emissão de NFS-e</a>
          <a href="/servicos/relatorios" class="dropdown-item" role="menuitem">Relatórios de Serviços</a>
        </div>
                          </div>
                          <div class="dropdown" role="none">
                            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                              Fiscal ▾
                            </button>
                            <div class="dropdown-menu" role="menu" aria-label="Fiscal">
    <a href="/fiscal/entrada-notas" class="dropdown-item" role="menuitem" data-required-perm="fiscal.read">Entrada de Notas</a>
    <a href="/fiscal/nfce/preview" class="dropdown-item" role="menuitem" data-required-perm="vendas.read">NFC-e: Prévia e comparação</a>
    <a href="/fiscal/config" class="dropdown-item" role="menuitem">Configurações fiscais</a>
    <a href="/fiscal/sped" class="dropdown-item" role="menuitem">SPED Fiscal/Contábil</a>
    <a href="/sped" class="dropdown-item" role="menuitem" data-required-perm="fiscal.sped.read">SPED Completo</a>
    <a href="/fiscal/apuracao" class="dropdown-item" role="menuitem">Apuração de impostos</a>
    <a href="/fiscal/obrigacoes" class="dropdown-item" role="menuitem">Obrigações acessórias</a>
    <a href="/fiscal/documentos" class="dropdown-item" role="menuitem">Controle de documentos fiscais</a>
                            </div>
                          </div>
                          <div class="dropdown" role="none" data-required-perm="bi.dashboard">
                            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                              BI & Relatórios ▾
                            </button>
                            <div class="dropdown-menu" role="menu" aria-label="BI & Relatórios">
                              <div class="dropdown-group">
                                <h4>Business Intelligence</h4>
                                <a href="/bi" class="dropdown-item" role="menuitem" data-required-perm="bi.dashboard">Dashboard BI</a>
                                <a href="/bi/relatorios" class="dropdown-item" role="menuitem" data-required-perm="bi.reports">Relatórios Gerenciais</a>
                              </div>
                            </div>
                          </div>
                          <div class="dropdown" role="none" data-required-perm="modules.access">
                            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                              Módulos ▾
                            </button>
                            <div class="dropdown-menu" role="menu" aria-label="Módulos">
                              <div class="dropdown-group">
                                <h4>Marketplace</h4>
                                <a href="/modulos/marketplace" class="dropdown-item" role="menuitem" data-required-perm="settings.access">Marketplace de Módulos</a>
                              </div>
                              <div class="dropdown-group">
                                <h4>Integrações</h4>
                                <a href="/gestor-y" class="dropdown-item" role="menuitem" data-required-perm="gestory.read">Gestor-Y (Yamaha)</a>
                                <a href="/addons/marketplaces" class="dropdown-item" role="menuitem">Marketplaces</a>
                                <a href="/addons/transportadoras" class="dropdown-item" role="menuitem">Transportadoras</a>
                                <a href="/addons/google-calendar" class="dropdown-item" role="menuitem" data-required-perm="integrations.googlecalendar.read">Google Agenda</a>
                                <a href="/integracoes/mercado-livre" class="dropdown-item" role="menuitem" data-required-perm="integracoes.mercadolivre.read">Mercado Livre</a>
                                <a href="/integracoes/tiktok-seller" class="dropdown-item" role="menuitem" data-required-perm="integracoes.tiktok.read">TikTok Seller</a>
                                <a href="/integracoes/woocommerce" class="dropdown-item" role="menuitem" data-required-perm="integracoes.woocommerce.read">WooCommerce</a>
                                <a href="/integracoes/instagram" class="dropdown-item" role="menuitem" data-required-perm="integracoes.instagram.read">Instagram</a>
                                <a href="/integracoes/facebook" class="dropdown-item" role="menuitem" data-required-perm="integracoes.facebook.read">Facebook</a>
                                <a href="/integracoes/open-banking" class="dropdown-item" role="menuitem" data-required-perm="integracoes.openbanking.read">Open Banking</a>
                                <a href="/integracoes/whatsapp" class="dropdown-item" role="menuitem" data-required-perm="integracoes.whatsapp.read">WhatsApp Business</a>
                              </div>
                              <div class="dropdown-group">
                                <h4>Add-ons</h4>
                                <a href="/contratos" class="dropdown-item" role="menuitem" data-required-perm="contratos.read">Gestor Contratos</a>
                                <a href="/workflows" class="dropdown-item" role="menuitem" data-required-perm="workflows.read">Workflows e Automações</a>
                                <a href="/api/docs" class="dropdown-item" role="menuitem" data-required-perm="api.read">API Pública</a>
                                <a href="/ia" class="dropdown-item" role="menuitem" data-required-perm="ia.read">IA e Machine Learning</a>
                              </div>
                              <div class="dropdown-group">
                                <h4>Operações</h4>
                                <a href="/pcp" class="dropdown-item" role="menuitem" data-required-perm="pcp.read">Produção/PCP</a>
                                <a href="#" class="dropdown-item disabled" role="menuitem" aria-disabled="true" tabindex="-1">Projetos/OS</a>
                                <a href="#" class="dropdown-item disabled" role="menuitem" aria-disabled="true" tabindex="-1">Assinaturas</a>
                              </div>
                            </div>
                          </div>
                          <div class="dropdown" role="none" data-required-perm="settings.access">
                            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                              Configurações ▾
                            </button>
                            <div class="dropdown-menu" role="menu" aria-label="Configurações">
                              <div class="dropdown-group">
                                <h4>Sistema</h4>
                                <a href="/settings/params" class="dropdown-item" role="menuitem">Parâmetros</a>
                                <a href="/settings/rbac" class="dropdown-item" role="menuitem" data-required-role="admin">Permissões (RBAC)</a>
                                <a href="/settings/backup" class="dropdown-item" role="menuitem" data-required-perm="settings.access">Backup</a>
                              </div>
                              <div class="dropdown-group">
                                <h4>Empresa</h4>
                                <a href="/settings/company" class="dropdown-item" role="menuitem">Dados da empresa</a>
                                <a href="/cadastros/usuarios" class="dropdown-item" role="menuitem" data-required-perm="cadastros.usuarios.read">Usuários</a>
                              </div>
                            </div>
                          </div>
                          <button id="themeToggle" class="btn btn-secondary" title="Alternar tema">🌞</button>
                          <a href="#" class="btn btn-danger" onclick="logout()">Sair</a>
                        </div>
                    <?php endif; ?>
                </nav>
                <?php endif; ?>
            </div>
        </div>
    </header>

    <main class="<?= $isLoginPage ? 'center-main' : '' ?>">
        <div class="container">
            <?= $content ?>
        </div>
    </main>

    <footer>
        <div class="container">
            <p>&copy; 2025 GestorEasy. Sistema de gestão empresarial.</p>
        </div>
    </footer>

    <script>
        // Utilitários globais
        const API_BASE = '';
        
        function getAuthToken() {
            // Tenta localStorage primeiro; se não houver, usa cookie
            const lsToken = localStorage.getItem('auth_token');
            if (lsToken) return lsToken;
            const m = document.cookie.match(/(?:^|; )auth_token=([^;]+)/);
            return m ? decodeURIComponent(m[1]) : null;
        }
        function getApiKey() {
            try {
                const ls = localStorage.getItem('api_key');
                if (ls) return ls;
            } catch (_) {}
            const m = document.cookie.match(/(?:^|; )api_key=([^;]+)/);
            return m ? decodeURIComponent(m[1]) : null;
        }
        function getAdminToken() {
            try {
                const ls = localStorage.getItem('admin_token');
                if (ls) return ls;
            } catch (_) {}
            const m = document.cookie.match(/(?:^|; )admin_token=([^;]+)/);
            return m ? decodeURIComponent(m[1]) : null;
        }
        
        function setAuthToken(token) {
            localStorage.setItem('auth_token', token);
        }
        
        function clearAuthToken() {
            localStorage.removeItem('auth_token');
            // Zerar cookie
            document.cookie = 'auth_token=; Max-Age=0; path=/';
        }
        function clearAdminToken() {
            localStorage.removeItem('admin_token');
            document.cookie = 'admin_token=; Max-Age=0; path=/';
        }
        
        function logout() {
            clearAuthToken();
            clearAdminToken();
            // Limpar tenant para evitar inconsistência em novo login
            document.cookie = 'x-tenant-id=; Max-Age=0; path=/';
            window.location.href = '/login';
        }
        
        async function apiRequest(url, options = {}) {
            const token = getAuthToken();
            const useApiKey = options.useApiKey === true;
            const skipAuth = options.skipAuth === true;
            const headers = { ...options.headers };
            const isFormData = (options.body && typeof FormData !== 'undefined' && options.body instanceof FormData);
            if (!isFormData) {
                headers['Content-Type'] = headers['Content-Type'] || 'application/json';
            }
            if (!skipAuth && token) {
                headers['Authorization'] = headers['Authorization'] || `Bearer ${token}`;
            }
            if (useApiKey && !headers['X-API-Key']) {
                const apiKey = getApiKey();
                if (apiKey) headers['X-API-Key'] = apiKey;
            }
            if (!headers['x-tenant-id']) {
                const mTenant = document.cookie.match(/(?:^|; )x-tenant-id=([^;]+)/);
                if (mTenant) {
                    headers['x-tenant-id'] = decodeURIComponent(mTenant[1]);
                }
            }
            let fetchMethod = options.method || 'GET';
            if (isFormData && fetchMethod && fetchMethod.toUpperCase() !== 'POST') {
                options.body.append('_method', fetchMethod.toUpperCase());
                fetchMethod = 'POST';
            }
            const doFetch = async () => fetch(API_BASE + url, { 
                ...options, 
                method: fetchMethod, 
                headers, 
                cache: 'no-store',
                credentials: 'include'
            });
            let response = await doFetch();
            if (response.status === 401) {
                clearAuthToken();
                const adminToken = getAdminToken();
                const mTenant = document.cookie.match(/(?:^|; )x-tenant-id=([^;]+)/);
                const tenantId = mTenant ? decodeURIComponent(mTenant[1]) : 'default';
                if (adminToken && tenantId) {
                    try {
                        const imp = await fetch('/api/admin/tenants/impersonate', {
                            method: 'POST',
                            headers: {
                                'Authorization': `Bearer ${adminToken}`,
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify({ tenant_id: tenantId })
                        });
                        if (imp.ok || imp.status === 302) {
                            const newToken = getAuthToken();
                            if (newToken) {
                                headers['Authorization'] = `Bearer ${newToken}`;
                            } else {
                                delete headers['Authorization'];
                            }
                            response = await doFetch();
                            return response;
                        }
                    } catch (_) {}
                }
                // Sem sucesso em impersonate: redirecionar para login preservando a rota atual
                try {
                    const next = (window.location && window.location.pathname ? window.location.pathname : '/') + (window.location && window.location.search ? window.location.search : '');
                    window.location.href = '/login?next=' + encodeURIComponent(next);
                } catch (_) {}
            }
            return response;
        }
        
        function showLoading() {
            const loading = document.querySelector('.loading');
            if (loading) loading.classList.add('show');
        }
        
        function hideLoading() {
            const loading = document.querySelector('.loading');
            if (loading) loading.classList.remove('show');
        }
        
        function showAlert(message, type = 'success') {
            const alertDiv = document.createElement('div');
            alertDiv.className = `alert alert-${type}`;
            alertDiv.textContent = message;
            
            const container = document.querySelector('.container');
            container.insertBefore(alertDiv, container.firstChild);
            
            setTimeout(() => alertDiv.remove(), 5000);
        }

        // Utilitário global: comportamento padrão para modais (dialog.modal)
        function initModals() {
            const dialogs = document.querySelectorAll('dialog.modal');
            dialogs.forEach(d => {
                const toolbar = d.querySelector('.modal-toolbar');
                if (!toolbar) return;
                const btnMin = toolbar.querySelector('[data-action="minimize"]');
                const btnMax = toolbar.querySelector('[data-action="maximize"]');
                const btnClose = toolbar.querySelector('[data-action="close"]');
                const toggleBody = (hidden) => {
                    // Esconde todo conteúdo exceto a toolbar
                    Array.from(d.children).forEach(ch => {
                        if (ch === toolbar) return;
                        ch.style.display = hidden ? 'none' : '';
                    });
                };
                if (btnMin) btnMin.addEventListener('click', () => {
                    const minimized = d.classList.toggle('is-minimized');
                    if (minimized) {
                        d.classList.remove('is-maximized');
                        toggleBody(true);
                    } else {
                        toggleBody(false);
                    }
                });
                if (btnMax) btnMax.addEventListener('click', () => {
                    const willMax = !d.classList.contains('is-maximized');
                    d.classList.remove('is-minimized');
                    toggleBody(false);
                    if (willMax) d.classList.add('is-maximized'); else d.classList.remove('is-maximized');
                });
                if (btnClose) btnClose.addEventListener('click', () => {
                    try { d.close(); } catch (_) {}
                    d.classList.remove('is-minimized');
                    d.classList.remove('is-maximized');
                    toggleBody(false);
                });
                d.addEventListener('close', () => {
                    d.classList.remove('is-minimized');
                    d.classList.remove('is-maximized');
                    toggleBody(false);
                });
            });
        }

        function openModalById(id){
            const d = document.getElementById(id);
            if (!d) return;
            try {
                if (typeof d.showModal === 'function') d.showModal();
                else if (typeof d.show === 'function') d.show();
                else { d.setAttribute('open',''); }
            } catch (_) { d.setAttribute('open',''); }
        }

        document.addEventListener('DOMContentLoaded', () => {
            try { initModals(); } catch (_) {}
        });

        // Autocomplete simples: cria uma lista com resultados ao digitar
        function attachAutocomplete(input, options){
            const cfg = Object.assign({ minChars: 3, fetch: null, onSelect: null, placeholder: 'Digite para buscar…' }, options||{});
            if (!input || typeof cfg.fetch !== 'function') return;
            let list = document.createElement('div');
            list.className = 'autocomplete-list';
            list.style.display = 'none';
            input.parentNode.style.position = input.parentNode.style.position || 'relative';
            input.parentNode.appendChild(list);
            let timer;
            const closeList = ()=>{ list.style.display='none'; list.innerHTML=''; };
            input.addEventListener('input', async ()=>{
                const term = input.value.trim();
                if (!term || term.length < cfg.minChars) { closeList(); return; }
                clearTimeout(timer);
                timer = setTimeout(async ()=>{
                    try {
                        list.innerHTML = `<div class="item muted">${cfg.placeholder}</div>`;
                        list.style.display = 'block';
                        const items = await cfg.fetch(term);
                        if (!items || items.length === 0) { list.innerHTML = '<div class="item muted">Sem resultados</div>'; return; }
                        list.innerHTML = items.map(it => `<div class="item" data-id="${String(it.id||'')}">${String(it.label||it.nome||it.name||'')}</div>`).join('');
                        list.querySelectorAll('.item').forEach(el=>{
                            el.addEventListener('click', ()=>{
                                const id = el.getAttribute('data-id');
                                const text = el.textContent;
                                if (typeof cfg.onSelect === 'function') cfg.onSelect({ id, label: text });
                                input.value = text;
                                closeList();
                            });
                        });
                    } catch(err){
                        list.innerHTML = '<div class="item muted">Erro na busca</div>';
                    }
                }, 250);
            });
            input.addEventListener('blur', ()=>{ setTimeout(closeList, 150); });
        }

        // Formatação de quantidade: exibe apenas parte inteira, preserva valor original em data-original-value
        function fmtQty(n) {
            if (n == null || n === '') return '0';
            const num = Number(String(n).replace(',', '.'));
            if (!isFinite(num)) return String(n);
            return String(Math.trunc(num));
        }
        window.fmtQty = fmtQty;

        // Formatação de data/hora em PT-BR (dd-mm-aaaa e 24h)
        function fmtDateBR(input) {
            if (!input) return '';
            const d = (input instanceof Date) ? input : new Date(String(input));
            if (isNaN(d)) return String(input);
            const dd = String(d.getDate()).padStart(2, '0');
            const mm = String(d.getMonth() + 1).padStart(2, '0');
            const yyyy = d.getFullYear();
            return `${dd}-${mm}-${yyyy}`;
        }
        function fmtDateTimeBR(input) {
            if (!input) return '';
            const d = (input instanceof Date) ? input : new Date(String(input));
            if (!isNaN(d)) {
                const dd = String(d.getDate()).padStart(2, '0');
                const mm = String(d.getMonth() + 1).padStart(2, '0');
                const yyyy = d.getFullYear();
                const hh = String(d.getHours()).padStart(2, '0');
                const mi = String(d.getMinutes()).padStart(2, '0');
                const ss = String(d.getSeconds()).padStart(2, '0');
                return `${dd}-${mm}-${yyyy} ${hh}:${mi}:${ss}`;
            }
            // Fallback para strings ISO curtas
            const raw = String(input).replace('T', ' ').slice(0, 19);
            const parts = raw.split(/[\s:-]/);
            if (parts.length >= 6) {
                const [Y, M, D, h, m, sec] = parts;
                return `${D}-${M}-${Y} ${h}:${m}:${sec}`;
            }
            return raw;
        }
        function parseDateBR(str) {
            // Aceita dd-mm-aaaa ou dd/mm/aaaa
            if (!str) return null;
            const m = String(str).match(/^(\d{2})[\/-](\d{2})[\/-](\d{4})$/);
            if (!m) return null;
            const dd = Number(m[1]);
            const mm = Number(m[2]) - 1;
            const yyyy = Number(m[3]);
            const d = new Date(yyyy, mm, dd, 0, 0, 0);
            return isNaN(d) ? null : d;
        }
        window.fmtDateBR = fmtDateBR;
        window.fmtDateTimeBR = fmtDateTimeBR;
        window.parseDateBR = parseDateBR;

        // Localização básica de tooltips conforme preferência em Parâmetros
        (async function initTipsPreference(){
            try {
                const r = await fetch('/api/settings', { headers: { 'Accept':'application/json' }, credentials: 'same-origin' });
                if (r && r.ok) {
                    const j = await r.json();
                    const s = j.settings || {};
                    const show = !!s.show_tips;
                    window.__showTips = show;
                    if (!show) {
                        // Remover atributos title para evitar tooltips intrusivos
                        document.querySelectorAll('[title]').forEach(el => el.removeAttribute('title'));
                    }
                }
            } catch(_) { /* silencioso */ }
        })();

        // Hooks: inputs marcados com data-type="quantity" aceitam apenas inteiros na exibição
        function attachQuantityInputHandlers() {
            const qInputs = Array.from(document.querySelectorAll('input[data-type="quantity"]'));
            qInputs.forEach(inp => {
                // passo padrão 1
                if (!inp.getAttribute('step')) inp.setAttribute('step', '1');
                const onChange = () => {
                    const raw = inp.value;
                    if (raw == null || raw === '') { inp.dataset.originalValue = ''; return; }
                    const normalized = String(raw).replace(',', '.');
                    const num = Number(normalized);
                    if (!isFinite(num)) { return; }
                    // preserva valor original para cálculos internos, porém exibe inteiro
                    inp.dataset.originalValue = normalized;
                    inp.value = String(Math.trunc(num));
                };
                inp.addEventListener('input', onChange);
                inp.addEventListener('blur', onChange);
            });
        }
        
        // Verificar autenticação na inicialização (considera cookie HttpOnly do tenant)
        document.addEventListener('DOMContentLoaded', async function() {
            const path = window.location.pathname;
            const publicPaths = ['/login', '/admin/login', '/admin/recovery', '/admin/reset'];
            const isPublic = publicPaths.some(p => path === p || path.startsWith(p));

            // Se não for rota pública, tentar validar sessão via API (aceita cookie HttpOnly)
            if (!isPublic) {
                const userToken = getAuthToken();
                const adminToken = getAdminToken();
                if (!(userToken || adminToken)) {
                    try {
                        const res = await fetch('/api/auth/me', { method: 'GET', credentials: 'same-origin', cache: 'no-store' });
                        if (res.status === 200) {
                            // Sessão válida via cookie; não redirecionar
                        } else {
                            window.location.href = '/login';
                            return;
                        }
                    } catch (_) {
                        window.location.href = '/login';
                        return;
                    }
                }

                // Se estiver com admin_token e sem auth_token, realizar impersonação automática para o tenant atual
                const hasUserToken = !!getAuthToken();
                const hasAdminToken = !!getAdminToken();
                if (!hasUserToken && hasAdminToken) {
                    try {
                        const mTenant = document.cookie.match(/(?:^|; )x-tenant-id=([^;]+)/);
                        const tenantId = mTenant ? decodeURIComponent(mTenant[1]) : 'default';
                        const imp = await fetch('/api/admin/tenants/impersonate', {
                            method: 'POST',
                            headers: {
                                'Authorization': `Bearer ${getAdminToken()}`,
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify({ tenant_id: tenantId }),
                            credentials: 'same-origin'
                        });
                        // Ignorar resultado; cookies serão definidos pelo backend (302 ou 200)
                    } catch (_) { /* silencioso */ }
                }
            }

            // Tema: aplicar tema salvo e configurar toggle
            const savedTheme = localStorage.getItem('theme') || 'light';
            applyTheme(savedTheme);
            const btnToggle = document.getElementById('themeToggle');
            if (btnToggle) {
                btnToggle.textContent = (savedTheme === 'dark') ? '🌜' : '🌞';
                btnToggle.addEventListener('click', function() {
                    const current = document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light';
                    const next = current === 'dark' ? 'light' : 'dark';
                    applyTheme(next);
                    localStorage.setItem('theme', next);
                    btnToggle.textContent = (next === 'dark') ? '🌜' : '🌞';
                });
            }

            // Oculto: sem exibir usuário no cabeçalho por ora
            // Interação dos dropdowns com delay de fechamento (500ms) e transição suave
            const CLOSE_DELAY_MS = 500;
            document.querySelectorAll('.dropdown').forEach(dd => {
                let closeTimer = null;
                const btn = dd.querySelector(':scope > button');
                const open = () => {
                    // fechar outros antes
                    document.querySelectorAll('.dropdown[aria-expanded="true"]').forEach(o => { if (o!==dd) o.setAttribute('aria-expanded','false'); });
                    dd.setAttribute('aria-expanded','true');
                };
                const scheduleClose = () => {
                    clearTimeout(closeTimer);
                    closeTimer = setTimeout(() => {
                        dd.setAttribute('aria-expanded','false');
                    }, CLOSE_DELAY_MS);
                };
                const cancelClose = () => { clearTimeout(closeTimer); };

                // Click/touch toggle
                if (btn) {
                    btn.addEventListener('click', (e) => {
                        const expanded = dd.getAttribute('aria-expanded') === 'true';
                        if (expanded) {
                            scheduleClose();
                        } else {
                            open();
                        }
                    });
                    btn.addEventListener('keydown', (e) => {
                        if (e.key === 'Escape') {
                            dd.setAttribute('aria-expanded','false'); btn.blur();
                        }
                    });
                }

                // Hover intent
                dd.addEventListener('mouseenter', () => { cancelClose(); open(); });
                dd.addEventListener('mouseleave', scheduleClose);
            });

            document.addEventListener('click', (e) => {
                const dd = e.target.closest('.dropdown');
                if (!dd) { document.querySelectorAll('.dropdown').forEach(d => d.setAttribute('aria-expanded','false')); }
            });

            // Complemento de acessibilidade: navegação por teclado nos dropdowns
            document.querySelectorAll('.dropdown').forEach(dd => {
                const btn = dd.querySelector(':scope > button');
                if (btn) {
                    btn.addEventListener('keydown', (e) => {
                        const items = Array.from(dd.querySelectorAll('.dropdown-item:not(.disabled)'));
                        if (e.key === 'Enter' || e.key === ' ') {
                            e.preventDefault();
                            dd.setAttribute('aria-expanded','true');
                            if (items.length) items[0].focus();
                        }
                    });
                }
                dd.addEventListener('keydown', (e) => {
                    const items = Array.from(dd.querySelectorAll('.dropdown-item:not(.disabled)'));
                    const idx = items.indexOf(document.activeElement);
                    if (!items.length) return;
                    if (e.key === 'ArrowDown') {
                        e.preventDefault();
                        const next = items[Math.min(idx + 1, items.length - 1)] || items[0];
                        next.focus();
                    } else if (e.key === 'ArrowUp') {
                        e.preventDefault();
                        const prev = items[Math.max(idx - 1, 0)] || items[items.length - 1];
                        prev.focus();
                    } else if (e.key === 'Home') {
                        e.preventDefault(); items[0].focus();
                    } else if (e.key === 'End') {
                        e.preventDefault(); items[items.length - 1].focus();
                    } else if (e.key === 'Escape') {
                        dd.setAttribute('aria-expanded','false');
                        const b = dd.querySelector(':scope > button');
                        if (b) b.focus();
                    }
                });
            });

            // Injeção de ícones 24x24 nos itens do menu
            const iconMap = (name) => {
                const svg = (p) => `<span class="menu-icon" aria-hidden="true"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="${p}"/></svg></span>`;
                const multi = (...paths) => `<span class="menu-icon" aria-hidden="true"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${paths.map(p=>`<path d="${p}"/>`).join('')}</svg></span>`;
                switch(name) {
                    // Grupos principais
                    case 'Produtos': return multi('M4 10V6l8-4 8 4v4H4z','M4 10v8h16v-8');
                    case 'Vendas': return multi('M6 6h12l-1 10H7L6 6z','M9 20a1 1 0 1 0 0-2 1 1 0 0 0 0 2z','M17 20a1 1 0 1 0 0-2 1 1 0 0 0 0 2z');
                    case 'Cadastros': return multi('M12 12a5 5 0 1 0-5-5 5 5 0 0 0 5 5z','M2 22c0-5.523 4.477-10 10-10');
                    case 'Financeiro': return multi('M4 19V9','M9 19V5','M14 19V12','M19 19V7');
                    case 'Relatórios': return multi('M4 19V9','M9 19V5','M14 19V12','M19 19V7');
                    case 'Serviços': return multi('M12 2l3 5 5 3-5 3-3 5-3-5-5-3 5-3 3-5z');
                    case 'Fiscal': return multi('M6 2h9l5 5v15H6z','M14 2v6h6');
                    case 'Módulos': return multi('M4 4h8v4h4v8h-4v4H4z');
                    case 'E-commerce': return multi('M3 3h18v18H3z','M7 7h10v10H7z','M9 9h6v6H9z');
                    case 'Configurações': return multi('M12 2l3 5 5 3-5 3-3 5-3-5-5-3 5-3 3-5z');
                    // Serviços
                    case 'Dashboard de Serviços': return multi('M4 4h16v6H4z','M4 12h10v8H4z','M16 12h4v8h-4z');
                    case 'Veículos': return multi('M3 14h15l1.5 3H3z','M6 14V9h10v5','M6 20a2 2 0 1 0 0-4 2 2 0 0 0 0 4z','M16 20a2 2 0 1 0 0-4 2 2 0 0 0 0 4z');
                    case 'Ordens de Serviço': return multi('M4 4h14a2 2 0 0 1 2 2v14H6a2 2 0 0 1-2-2V4z','M8 8h8','M8 12h6','M8 16h8');
                    case 'Checklists': return multi('M4 6h16','M4 12h16','M4 18h16','M6 12l2 2 3-3');
                    case 'Documentos': return multi('M6 2h9l5 5v15H6z','M14 2v6h6');
                    case 'Relatórios de Serviços': return multi('M4 19V9','M9 19V5','M14 19V12','M19 19V7');
                    // Demais
                    case 'Catálogo': return multi('M4 6h16','M4 12h16','M4 18h16');
                    case 'Orçamentos': return multi('M4 4h14a2 2 0 0 1 2 2v14','M4 4v14a2 2 0 0 0 2 2h14','M8 8h8','M8 12h6');
                    case 'Pedidos': return multi('M6 2h9l5 5v15a1 1 0 0 1-1 1H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z','M14 2v6h6');
                    case 'PDV (Ponto de Venda)': return multi('M4 7h16v10H4z','M7 17v3h10v-3');
                    case 'PDV': return multi('M4 7h16v10H4z','M7 17v3h10v-3');
                    case 'Notas Fiscais': return multi('M6 2h9l5 5v15H6z','M14 2v6h6');
                    case 'Comissões': return multi('M12 20c4.418 0 8-3.582 8-8','M4 12c0-4.418 3.582-8 8-8','M12 6v6l4 2');
                    case 'CRM': return multi('M16 11c1.657 0 3-1.79 3-4s-1.343-4-3-4-3 1.79-3 4 1.343 4 3 4z','M2 20c0-4 4-7 9-7');
                    case 'Clientes': return multi('M12 12a5 5 0 1 0-5-5 5 5 0 0 0 5 5z','M2 22c0-5.523 4.477-10 10-10');
                    case 'Fornecedores': return multi('M3 7h18','M6 10h12','M4 14h16','M5 18h14');
                    case 'Empresas (multicompany)': return multi('M3 21V5l7-2 7 2v16','M10 12h4');
                    case 'Empresas': return multi('M3 21V5l7-2 7 2v16','M10 12h4');
                    case 'Transportadoras': return multi('M3 16h13V7H3z','M16 13h4l1.5 3H16z','M5 20a2 2 0 1 0 0-4 2 2 0 0 0 0 4z','M17 20a2 2 0 1 0 0-4 2 2 0 0 0 0 4z');
                    case 'Usuários': return multi('M12 12a5 5 0 1 0-5-5 5 5 0 0 0 5 5z','M2 22c0-5.523 4.477-10 10-10');
                    case 'Vendedores': return multi('M8 6h8','M8 10h6','M8 14h8','M6 18h12');
                    case 'Técnicos': return multi('M12 2l3 5 5 3-5 3-3 5-3-5-5-3 5-3 3-5z');
                    // Estoque/WMS/Compras
                    case 'Estoque: Limites': return multi('M4 19V9','M9 19V12','M14 19V15','M19 19V7');
                    case 'Estoque: Movimentos': return multi('M3 12h18','M12 3v18');
                    case 'WMS: Armazéns': return multi('M4 10V6l8-4 8 4v4H4z','M4 10v8h16v-8');
                    case 'WMS: Bins': return multi('M6 6v12','M9 6v12','M12 6v12','M15 6v12','M18 6v12');
                    case 'WMS: Movimentações': return multi('M4 12h16','M12 4v16');
                    case 'WMS: Analytics': return multi('M4 19V9','M9 19V5','M14 19V12','M19 19V7');
                    case 'Compras: Ordens': return multi('M6 2h9l5 5v15H6z','M14 2v6h6');
                    case 'Compras: Cotações': return multi('M7 4h10v4H7z','M5 8h14v12H5z');
                    case 'Contas a Pagar': return multi('M4 7h16','M4 11h16','M4 15h16','M4 19h16');
                    case 'Contas a Receber': return multi('M12 3v18','M7 8l5-5 5 5');
                    case 'Fluxo de Caixa': return multi('M3 12l5 5 6-6 7 7');
                    case 'Bancos': return multi('M3 10h18','M4 10V8l8-4 8 4v2','M6 10v8','M10 10v8','M14 10v8','M18 10v8');
                    case 'Relatórios Financeiros': return multi('M4 19V9','M9 19V5','M14 19V12','M19 19V7');
                    case 'Vendas por período/produto/vendedor': return multi('M3 12l5 5 6-6 7 7');
                    case 'Compras por fornecedor': return multi('M4 19V9','M9 19V5','M14 19V12','M19 19V7');
                    case 'Movimentação de estoque': return multi('M3 12h18','M12 3v18');
                    case 'Performance financeira': return multi('M3 12l5 5 6-6 7 7');
                    case 'Listagem de clientes': return multi('M4 6h16','M4 12h16','M4 18h16');
                    case 'Produtos críticos': return multi('M12 9v4','M12 17h.01','M12 2l10 19H2z');
                    case 'Títulos a vencer': return multi('M7 2h10v4H7z','M5 6h14v14H5z','M8 10h8');
                    case 'Notas Fiscais Eletrônicas': return multi('M6 2h9l5 5v15H6z','M14 2v6h6');
                    case 'SPED Fiscal/Contábil': return multi('M4 4h16v16H4z','M8 8h8','M8 12h8','M8 16h5');
                    case 'Apuração de impostos': return multi('M3 11h18','M10 21V4','M14 21V4');
                    case 'Obrigações acessórias': return multi('M7 4h10v4H7z','M5 8h14v12H5z');
                    case 'Controle de documentos fiscais': return multi('M4 6h16v12H4z','M8 10h8');
                    case 'E-commerce': return multi('M3 3h18v18H3z','M7 7h10v10H7z','M9 9h6v6H9z');
                    case 'Marketplaces': return multi('M3 6h18l-2 12H5L3 6z','M7 20h10');
                    case 'Produção/PCP': return multi('M3 4h18v6H3z','M6 10v10h12V10');
                    case 'Projetos/OS': return multi('M4 4h16v16H4z','M8 8h8','M8 12h8','M8 16h8');
                    case 'Assinaturas': return multi('M12 2v6','M12 16v6','M4 12h16');
                    case 'Parâmetros': return multi('M12 2l3 5 5 3-5 3-3 5-3-5-5-3 5-3 3-5z');
                    case 'Permissões (RBAC)': return multi('M12 2a5 5 0 0 1 5 5v2h2v9H5V9h2V7a5 5 0 0 1 5-5z');
                    case 'Dados da empresa': return multi('M3 21V5l7-2 7 2v16','M10 12h4');
                    default: return multi('M4 6h16','M4 12h16','M4 18h16');
                }
            };
            document.querySelectorAll('.dropdown-menu .dropdown-item').forEach(a => {
                // Evitar duplicação em re-renderizações
                if (!a.querySelector('.menu-icon')) {
                    const name = (a.textContent || '').trim();
                    a.insertAdjacentHTML('afterbegin', iconMap(name));
                }
            });

            // Injetar ícones também nos botões dos grupos de menu
            document.querySelectorAll('.dropdown > button').forEach(btn => {
                if (!btn.querySelector('.menu-icon')) {
                    let name = (btn.textContent || '').trim();
                    name = name.replace(/\s*▾\s*$/, ''); // remove seta do rótulo
                    btn.insertAdjacentHTML('afterbegin', iconMap(name));
                }
            });

            // Aplicar controle de acesso (oculta itens sem permissão) somente em rotas privadas
            if (!isPublic) {
                try {
                    const meRes = await apiRequest('/api/auth/me', { method: 'GET' });
                    if (meRes && meRes.ok) {
                        const me = await meRes.json();
                        const user = me.user || {};
                        const roles = Array.isArray(user.roles) ? user.roles : [];
                        const perms = Array.isArray(user.permissions) ? user.permissions : (Array.isArray(user.perms) ? user.perms : []);
                        const isAdmin = roles.includes('admin') || !!user.impersonated;
                        document.querySelectorAll('[data-required-perm]').forEach(el => {
                            const need = el.getAttribute('data-required-perm');
                            if (!need) return;
                            if (!(isAdmin || perms.includes(need))) {
                                // Oculta o item (dropdown inteiro quando aplicável)
                                const drop = el.classList.contains('dropdown') ? el : el.closest('.dropdown');
                                (drop || el).style.display = 'none';
                            }
                        });
                        document.querySelectorAll('[data-required-role]').forEach(el => {
                            const needR = el.getAttribute('data-required-role');
                            if (!needR) return;
                            if (!(isAdmin || roles.includes(needR))) {
                                const drop = el.classList.contains('dropdown') ? el : el.closest('.dropdown');
                                (drop || el).style.display = 'none';
                            }
                        });
                    }
                } catch (_) { /* silencioso */ }
            }

            // Marcação de item e grupo ativos conforme a rota atual
            try {
                const cur = window.location.pathname;
                const links = Array.from(document.querySelectorAll('.dropdown-menu .dropdown-item[href]'));
                const active = links.find(el => el.getAttribute('href') === cur);
                if (active) {
                    active.classList.add('active');
                    const dd = active.closest('.dropdown');
                    if (dd) {
                        const btn = dd.querySelector(':scope > button');
                        if (btn) btn.classList.add('active');
                    }
                } else if (cur.startsWith('/servicos/')) {
                    const svcDrop = Array.from(document.querySelectorAll('.dropdown')).find(d => {
                        const btn = d.querySelector(':scope > button');
                        return btn && /Serviços/.test(btn.textContent || '');
                    });
                    if (svcDrop) {
                        const btn = svcDrop.querySelector(':scope > button');
                        if (btn) btn.classList.add('active');
                    }
                }
            } catch(_) {}

            // Validador simples de consistência visual (não intrusivo)
            try {
                const checks = [];
                const isPublic = ['/login','/admin/login','/admin/recovery','/admin/reset'].some(p => path === p || path.startsWith(p));
                if (!isPublic) {
                    const container = document.querySelector('main .container');
                    if (!container) checks.push('Container principal não encontrado.');
                    const hasCard = !!container && !!container.querySelector('.card');
                    if (!hasCard) checks.push('Página sem componentes .card (conteúdo principal).');
                    const hasBtn = !!container && !!container.querySelector('.btn');
                    if (!hasBtn) checks.push('Ações principais sem classe .btn.');
                    const tables = Array.from(container ? container.querySelectorAll('table') : []);
                    if (tables.length) {
                        tables.forEach(t => { if (!t.classList.contains('table')) checks.push('Tabela sem classe .table.'); });
                    }
                    const hasHeading = !!container && !!container.querySelector('h1, h2');
                    if (!hasHeading) checks.push('Página sem título (h1/h2).');
                }
                if (checks.length) {
                    console.warn('[UI Check] Inconsistências:', checks);
                    const showBanner = localStorage.getItem('ui_check_banner') === '1';
                    if (showBanner) {
                        const banner = document.createElement('div');
                        banner.className = 'alert alert-error';
                        banner.style.marginBottom = '1rem';
                        banner.innerHTML = '<strong>Inconsistências de UI:</strong> ' + checks.join(' • ');
                        const cont = document.querySelector('main .container');
                        if (cont) cont.insertBefore(banner, cont.firstChild);
                    }
                }
            } catch(_) {}

            // Aplicar handlers de inputs de quantidade (exibição inteira)
            attachQuantityInputHandlers();
        });

        // Removido: carregamento/mostra de usuário no header (será refeito depois)

        // Não sobrescrever Authorization se já estiver definido (evita trocar token admin por token user)
        const _origApiRequest = apiRequest;
        apiRequest = async function(url, options = {}) {
            const token = getAuthToken();
            const useApiKey = options.useApiKey === true;
            const skipAuth = options.skipAuth === true;
            const headers = { ...(options.headers || {}) };
            const isFormData = (options.body && typeof FormData !== 'undefined' && options.body instanceof FormData);
            if (!isFormData) {
                headers['Content-Type'] = headers['Content-Type'] || 'application/json';
            }
            if (!skipAuth && token && !headers['Authorization']) {
                headers['Authorization'] = `Bearer ${token}`;
            }
            if (useApiKey && !headers['X-API-Key']) {
                const apiKey = getApiKey();
                if (apiKey) headers['X-API-Key'] = apiKey;
            }
            if (!headers['x-tenant-id']) {
                const mTenant = document.cookie.match(/(?:^|; )x-tenant-id=([^;]+)/);
                if (mTenant) {
                    headers['x-tenant-id'] = decodeURIComponent(mTenant[1]);
                }
            }
            let fetchMethod = options.method || 'GET';
            if (isFormData && fetchMethod && fetchMethod.toUpperCase() !== 'POST') {
                options.body.append('_method', fetchMethod.toUpperCase());
                fetchMethod = 'POST';
            }
            const doFetch = async () => fetch(API_BASE + url, { ...options, method: fetchMethod, headers, cache: 'no-store', credentials: 'include' });
            try {
                let response = await doFetch();
                if (response.status === 401) {
                    clearAuthToken();
                    const adminToken = getAdminToken();
                    const mTenant = document.cookie.match(/(?:^|; )x-tenant-id=([^;]+)/);
                    const tenantId = mTenant ? decodeURIComponent(mTenant[1]) : 'default';
                    if (adminToken && tenantId) {
                        try {
                            const imp = await fetch('/api/admin/tenants/impersonate', {
                                method: 'POST',
                                headers: {
                                    'Authorization': `Bearer ${adminToken}`,
                                    'Content-Type': 'application/json'
                                },
                                body: JSON.stringify({ tenant_id: tenantId }),
                                credentials: 'include'
                            });
                            if (imp.ok || imp.status === 302) {
                                const newToken = getAuthToken();
                                if (!skipAuth && newToken && !headers['Authorization']) {
                                    headers['Authorization'] = `Bearer ${newToken}`;
                                }
                                response = await doFetch();
                                return response;
                            }
                        } catch (_) {}
                    }
                    return response;
                }
                return response;
            } catch (err) {
                if (err && (err.name === 'AbortError' || err.message === 'The operation was aborted.')) {
                    return null;
                }
                throw err;
            }
        }

        // Alternância de tema claro/escuro (usa tokens CSS via data-theme)
        function applyTheme(theme) {
            const t = (theme === 'dark') ? 'dark' : 'light';
            document.documentElement.setAttribute('data-theme', t);
            try { localStorage.setItem('ui_theme', t); } catch(e) {}
            const btn = document.getElementById('themeToggle');
            if (btn) btn.textContent = (t === 'dark') ? '🌙' : '🌞';
            const logo = document.getElementById('siteLogo');
            if (logo) {
                logo.src = (t === 'dark') ? '/assets/logo-light.png' : '/assets/logo-dark.png';
            }
        }
        (function initTheme(){
            try {
                const saved = localStorage.getItem('ui_theme');
                if (saved === 'dark' || saved === 'light') { applyTheme(saved); return; }
            } catch(e) {}
            // fallback: preferência do sistema
            const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
            applyTheme(prefersDark ? 'dark' : 'light');
        })();
        (function wireThemeToggle(){
            const btn = document.getElementById('themeToggle');
            if (!btn) return;
            btn.addEventListener('click', () => {
                const cur = document.documentElement.getAttribute('data-theme');
                applyTheme(cur === 'dark' ? 'light' : 'dark');
            });
        })();
        // Inicialização centralizada do DatePicker
        (function(){
            const boot = () => {
                if (window.DatePicker && typeof window.DatePicker.init === 'function') {
                    window.DatePicker.init();
                } else {
                    setTimeout(boot, 100);
                }
            };
            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', boot);
            } else {
                window.addEventListener('load', boot);
            }
        })();
    </script>
    <script src="https://cdn.jsdelivr.net/npm/flatpickr" defer></script>
    <script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/pt.js" defer></script>
    <script src="/js/ui/datepicker.js" defer></script>
</body>
</html>