<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8" />
    <title>UncertaintyLAGAS :: Cálculo de Incertezas (GUM e Monte Carlo) - Várias Abordagens</title>

    <!-- Bibliotecas JS locais (mesmo diretório) -->
    <script src="./math.min.js"></script>
    <script src="./xlsx.full.min.js"></script>
    <script src="./jstat.min.js"></script>
    <script src="./plotly-2.20.0.min.js"></script>
    <script src="./algebrite.bundle-for-browser.min.js"></script>

    <style>
        body {
            font-family: "Segoe UI", Tahoma, sans-serif;
            margin: 20px;
            background: #fafafa;
        }

        header, .toolbar {
            display: flex;
            align-items: center;
            margin-bottom: 10px;
        }

        h1 {
            flex: 1;
            color: #444;
            margin: 0;
        }

        .container {
            display: flex;
            flex-direction: row;
            justify-content: space-between;
        }

        .container-left, .container-right {
            width: 48%;
            min-width: 300px;
        }

        label {
            font-weight: bold;
            color: #555;
            display: block;
            margin-top: 10px;
        }

        input[type="text"], select {
            width: 100%;
            box-sizing: border-box;
            margin: 4px 0 10px 0;
            padding: 6px;
        }
        /* Pequeno input para confiança */
        input.conf-input {
            width: 60px;
        }

        textarea {
            width: 100%;
            box-sizing: border-box;
            margin: 4px 0 10px 0;
            padding: 6px;
            resize: vertical;
            min-height: 60px;
        }

        table {
            border-collapse: collapse;
            margin-top: 10px;
            width: 100%;
            background: #fff;
        }

        th, td {
            border: 1px solid #ccc;
            padding: 8px;
            text-align: center;
            vertical-align: middle;
        }

        th {
            background-color: #e9e9ff;
            font-weight: 600;
            color: #333;
        }

        tr:nth-child(even) {
            background-color: #fcfcfc;
        }

        .section-title {
            margin-top: 20px;
            color: #333;
            border-bottom: 2px solid #ccc;
            padding-bottom: 4px;
            font-size: 1.2rem;
        }

        .results {
            margin-top: 20px;
            background-color: #f0f9ff;
            padding: 10px;
            border: 1px solid #cce6ff;
            border-radius: 4px;
            display: flex;
            flex-wrap: wrap;
            justify-content: space-between;
        }

        .results-content {
            width: 48%;
            min-width: 300px;
        }

        .chart-container {
            width: 48%;
            min-width: 320px;
            height: 400px;
            border: 1px solid #ccc;
            margin-top: 10px;
            background: #fff;
            display: none; /* exibe ao final do cálculo */
        }

        button {
            margin-right: 5px;
            padding: 6px 12px;
            border: none;
            cursor: pointer;
            border-radius: 4px;
            font-size: 14px;
        }

            button:hover {
                opacity: 0.9;
            }

        .primary-btn {
            background-color: #2864dc;
            color: #fff;
        }

        .secondary-btn {
            background-color: #aaa;
            color: #fff;
        }

        .accent-btn {
            background-color: #28c;
            color: #fff;
        }

        [contenteditable="true"] {
            outline: 1px dotted #999;
            min-width: 2em;
        }

        .progress-bar-container {
            width: 100%;
            background: #eee;
            border-radius: 5px;
            overflow: hidden;
            margin-top: 10px;
            margin-bottom: 10px;
            display: none;
        }

        .progress-bar-fill {
            width: 0%;
            height: 20px;
            background: #28c;
            color: #fff;
            text-align: center;
            line-height: 20px;
            font-size: 12px;
            transition: width 0.1s;
        }

        /* Botão de Documentação */
        .doc-button {
            position: absolute;
            top: 10px;
            right: 10px;
            width: 30px;
            height: 30px;
            background-color: #ff9800; /* Laranja */
            border: none;
            border-radius: 50%;
            color: white;
            font-size: 18px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
        }

            .doc-button:hover {
                background-color: #e68900; /* Tom mais escuro ao passar o mouse */
            }

        /* Estilos do Modal */
        .modal {
            display: none; /* Oculto por padrão */
            position: fixed; /* Fica fixo na tela */
            z-index: 1000; /* Fica sobre outros elementos */
            left: 0;
            top: 0;
            width: 100%; /* Largura total */
            height: 100%; /* Altura total */
            overflow: auto; /* Scroll se necessário */
            background-color: rgba(0,0,0,0.5); /* Fundo semi-transparente */
        }

        /* Conteúdo do Modal */
        .modal-content {
            background-color: #fefefe;
            margin: 5% auto; /* Reduzido para 5% do topo */
            padding: 30px; /* Aumentado para mais espaço interno */
            border: 1px solid #888;
            width: 90%; /* Aumentado para 90% da largura da tela */
            max-width: 800px; /* Aumentado para permitir mais conteúdo */
            max-height: 90vh; /* Limita a altura a 90% da altura da viewport */
            overflow-y: auto; /* Permite rolagem interna se necessário */
            border-radius: 8px;
            position: relative;
            box-shadow: 0 5px 15px rgba(0,0,0,0.3); /* Adicionado para destaque */
        }


        /* Botão de Fechar */
        .close {
            color: #aaa;
            float: right;
            font-size: 28px;
            font-weight: bold;
            position: absolute;
            top: 10px;
            right: 20px;
            cursor: pointer;
        }

            .close:hover,
            .close:focus {
                color: black;
                text-decoration: none;
            }

        /* Link de Download */
        .download-link {
            display: inline-block;
            margin-top: 15px;
            padding: 10px 15px;
            background-color: #ff9800;
            color: white;
            text-decoration: none;
            border-radius: 4px;
        }

            .download-link:hover {
                background-color: #e68900;
            }



    </style>
</head>
<body>

    <header>
        <h1>UncertaintyLAGAS :: Cálculo de Incertezas (GUM e Monte Carlo)</h1>
        <!-- Botão de Documentação -->
        <button id="docButton" class="doc-button" title="Documentação">
            &#x3F;
        </button>
    </header>

    <!-- Toolbar: Carregar Excel -->
    <div class="toolbar">
        <div style="flex:1;">
            <label for="arquivoExcel">Carregar arquivo Excel (.xlsx):</label>
            <input type="file" id="arquivoExcel" accept=".xlsx" />
        </div>
        <button class="accent-btn" onclick="carregarExcel()">Carregar</button>
    </div>

    <hr />

    <!-- Container principal (2 colunas) -->
    <div class="container">

        <!-- Coluna esquerda: Modelo, Confiança -->
        <div class="container-left">
            <label>Modelo matemático:</label>
            <textarea id="modelo"
                      rows="3"
                      onblur="gerarTabelas()"
                      placeholder='Exemplo: "Y = sin(X1) + log(X2)"'>
</textarea>

            <label>Nível de confiança:</label>
            <input type="text" id="confianca" class="conf-input" value="95" />
        </div>

        <!-- Coluna direita: h (numérico), nº de amostras, e método GUM -->
        <div class="container-right">
            <label>Nº de Amostras (Monte Carlo):</label>
            <input type="text" id="numAmostrasMC" value="10000" />

            <label>h (derivada numérica):</label>
            <input type="text" id="hNumero" value="1e-6" />

            <label>Método de derivação (GUM):</label>
            <select id="metodoGUM">

                <option value="numerica">Numérica (Dif. Centrais)</option>
                <option value="kragten">Kragten</option>
                <option value="literal">Literal (Simbólico)</option>
            </select>
        </div>
    </div>

    <!-- Tabelas de variáveis/correlações -->
    <div id="tabelas-container"></div>

    <!-- Botões e barra de progresso -->
    <div style="margin-top:10px;">
        <button class="primary-btn" onclick="calcularGUM()">Calcular GUM</button>
        <button class="secondary-btn" onclick="calcularMonteCarlo()">Calcular Monte Carlo</button>
        <button onclick="salvarExcel()">Salvar em Excel</button>
    </div>

    <div class="progress-bar-container" id="progressBarContainer">
        <div class="progress-bar-fill" id="progressBarFill">0%</div>
    </div>

    <!-- Resultados + gráficos -->
    <div class="results" id="resultados">
        <div class="results-content" id="resultados-text"></div>
        <div class="chart-container" id="graficoGUM"></div>
        <div class="chart-container" id="graficoMC"></div>
    </div>

    <!-- Modal de Documentação -->
    <div id="docModal" class="modal">
        <div class="modal-content">
            <span class="close">&times;</span>
            <h2>Documentação</h2>

            <!-- Seção de Instruções -->
            <h3>Como Usar o Programa</h3>
            <ol>
                <li><strong>Inserir o Modelo Matemático:</strong> Digite a expressão matemática que descreve o modelo na área designada. Por exemplo, <em>Y = sin(X1) + log(X2)</em>.</li>
                <li><strong>Fornecer Valores e Incertezas:</strong> Nas tabelas de variáveis, insira os valores conhecidos e as incertezas associadas para cada variável.</li>
                <li><strong>Selecionar Método de Derivação:</strong> Escolha entre os métodos disponíveis (Numérica, Kragten, Literal) para calcular as derivadas necessárias.</li>
                <li><strong>Calcular Incertezas:</strong> Clique em "Calcular GUM" ou "Calcular Monte Carlo" para obter os resultados de incerteza. Observação: O método de Monte Carlo está em desenvolvimento. Atualmente, o modelo considera todas as variáveis com distribuição normal.</li>
                <li><strong>Salvar ou Carregar Resultados:</strong> Utilize os botões "Salvar em Excel" para exportar os resultados ou "Carregar" para importar dados previamente salvos.</li>
                <li><strong>Visualizar Resultados:</strong> Os resultados e gráficos serão exibidos na seção de resultados após o cálculo.</li>
            </ol>

            <!-- Seção de Aviso de Responsabilidade -->
            <h3>Aviso de Responsabilidade</h3>
            <p><strong>Aviso:</strong> Todos os cálculos devem ser conferidos. A responsabilidade pelo uso dos resultados é exclusiva do usuário.</p>

            <!-- Seção de Autor e Contato -->
            <h3>Sobre o Autor</h3>
            <p><strong>Nome:</strong> Fábio Ouverney Costa</p>
            <p><strong>Contato:</strong> <a href="mailto:focosta@inmetro.gov.br">focosta@inmetro.gov.brm</a></p>

            <!-- Link para Baixar a Documentação -->
            <a href="documentacao.pdf" target="_blank" class="download-link">Baixar Documentação (PDF)</a>
        </div>
    </div>




    <script>
        // =================== Globais ===================
        let listaVariaveis = [];
        let dadosVariaveisAntigos = {};
        let dadosCorrelacoesAntigas = {};

        const progressContainer = document.getElementById("progressBarContainer");
        const progressFill = document.getElementById("progressBarFill");

        // =================== Layout/Tabelas ===================
        function gerarTabelas() {
            armazenarDadosAtuais();
            const inputModelo = document.getElementById("modelo").value.trim();
            if (!inputModelo) return;

            const partes = inputModelo.split("=");
            if (partes.length < 2) return;
            const expr = partes[1].trim();

            let raiz;
            try {
                raiz = math.parse(expr);
            } catch (e) {
                alert("Expressão inválida: " + e);
                return;
            }

            const varsDetectadas = [];
            raiz.traverse((node, path, parent) => {
                if (node.type === "SymbolNode") {
                    const nome = node.name;
                    const isFunc = (typeof math[nome] === 'function');
                    const isConst = (nome === 'pi' || nome === 'e' || nome === 'Infinity');
                    if (!isFunc && !isConst) {
                        varsDetectadas.push(nome);
                    }
                }
            });
            listaVariaveis = [...new Set(varsDetectadas)];

            const divTab = document.getElementById("tabelas-container");
            divTab.innerHTML = "";
            if (listaVariaveis.length === 0) {
                divTab.innerHTML = "<p>Nenhuma variável identificada no modelo.</p>";
                return;
            }

            let htmlVars = `<h3 class="section-title">Tabela de Variáveis</h3>
                      <table><thead><tr>
                      <th>Variável</th>
                      <th>Valor</th>
                      <th>U</th>
                      <th>k</th>
                      <th>ν</th>
                      </tr></thead><tbody>`;
            listaVariaveis.forEach(vi => {
                let info = dadosVariaveisAntigos[vi] || { valor: "1.0", U: "0.2", k: "2.0", v: "10" };
                htmlVars += `
                          <tr>
                            <td><strong>${vi}</strong></td>
                            <td contenteditable="true" id="valor_${vi}">${info.valor}</td>
                            <td contenteditable="true" id="U_${vi}">${info.U}</td>
                            <td contenteditable="true" id="k_${vi}">${info.k}</td>
                            <td contenteditable="true" id="v_${vi}">${info.v}</td>
                          </tr>
                        `;
            });
            htmlVars += "</tbody></table>";

            let htmlCorr = `<h3 class="section-title">Tabela de Correlações</h3>
                      <table><thead><tr><th></th>`;
            listaVariaveis.forEach(vv => {
                htmlCorr += `<th>${vv}</th>`;
            });
            htmlCorr += `</tr></thead><tbody>`;
            listaVariaveis.forEach((vi, i) => {
                htmlCorr += `<tr><th>${vi}</th>`;
                listaVariaveis.forEach((vj, j) => {
                    let val = "0.0";
                    if (dadosCorrelacoesAntigas[vi] && dadosCorrelacoesAntigas[vi][vj] !== undefined) {
                        val = dadosCorrelacoesAntigas[vi][vj];
                    } else if (i === j) {
                        val = "1.0";
                    }
                    htmlCorr += `
                            <td contenteditable="true" id="corr_${vi}_${vj}">
                              ${val}
                            </td>`;
                });
                htmlCorr += "</tr>";
            });
            htmlCorr += "</tbody></table>";

            divTab.innerHTML = htmlVars + htmlCorr;
        }

        function armazenarDadosAtuais() {
            listaVariaveis.forEach(vi => {
                if (!dadosVariaveisAntigos[vi]) {
                    dadosVariaveisAntigos[vi] = { valor: "1.0", U: "0.2", k: "2.0", v: "10" };
                }
                const tdV = document.getElementById(`valor_${vi}`);
                const tdU = document.getElementById(`U_${vi}`);
                const tdK = document.getElementById(`k_${vi}`);
                const tdDf = document.getElementById(`v_${vi}`);
                if (tdV && tdU && tdK && tdDf) {
                    dadosVariaveisAntigos[vi].valor = tdV.textContent.trim();
                    dadosVariaveisAntigos[vi].U = tdU.textContent.trim();
                    dadosVariaveisAntigos[vi].k = tdK.textContent.trim();
                    dadosVariaveisAntigos[vi].v = tdDf.textContent.trim();
                }
            });
            listaVariaveis.forEach(vi => {
                if (!dadosCorrelacoesAntigas[vi]) {
                    dadosCorrelacoesAntigas[vi] = {};
                }
                listaVariaveis.forEach(vj => {
                    const td = document.getElementById(`corr_${vi}_${vj}`);
                    if (td) {
                        dadosCorrelacoesAntigas[vi][vj] = td.textContent.trim();
                    }
                });
            });
        }

        // =================== Selecionar método GUM ===================
        function calcularGUM() {
            // Mostra progress bar imediatamente
            progressContainer.style.display = "block";
            progressFill.style.width = "0%";
            progressFill.textContent = "0%";

            const metodo = document.getElementById("metodoGUM").value;
            if (metodo === "literal") {
                calcularGUMLiteral();
            } else if (metodo === "numerica") {
                calcularGUMNumerico();
            } else if (metodo === "kragten") {
                calcularGUMKragten();
            }
        }

        // =============== GUM LITERAL, GUM NUMERICA, GUM KRAGTEN ===============
        // (os 3 métodos) - Para não duplicar todo o código,
        // chamaremos as 3 funções conforme no código anterior:
        //   calcularGUMLiteral(), calcularGUMNumerico(), calcularGUMKragten()
        // Manteremos elas abaixo, sem remoção de funcionalidades.

        // << Copiamos as funções do user’s last code with chunk approach >>

        // *** Funções GUM - Literal ***
        let derivLiteral_expr = null; // guardado
        // ... mas iremos colar as mesmas do snippet anterior ...
        // Por simplicidade, replicamos as 3 implementações a seguir:

        // ============== GUM (Literal) =================
        function calcularGUMLiteral() {
            // Exibe a barra de progresso
            progressContainer.style.display = "block";
            progressFill.style.width = "0%";
            progressFill.textContent = "0%";

            const { valores, incertPadrao, dof, correlation } = lerDados();
            const inputModelo = document.getElementById("modelo").value.trim();
            const partes = inputModelo.split("=");
            if (partes.length < 2) {
                alert("Modelo inválido (GUM literal).");
                progressContainer.style.display = "none";
                return;
            }
            const expr = partes[1].trim();

            if (listaVariaveis.length === 0) {
                alert("Nenhuma variável identificada para GUM literal.");
                progressContainer.style.display = "none";
                return;
            }

            const xObj = {};
            listaVariaveis.forEach(vi => {
                xObj[vi] = valores[vi];
            });

            // Inicializar variáveis para armazenar derivadas
            let derivadas = {};

            // Calcular derivadas simbólicas usando Algebrite
            try {
                listaVariaveis.forEach(varName => {
                    // Utiliza Algebrite para calcular a derivada simbólica
                    let derivExpr = Algebrite.run(`d(${expr}, ${varName})`);
                    // Simplifica a expressão derivada (opcional)
                    derivExpr = Algebrite.run(`simplify(${derivExpr})`);
                    // Compila a expressão derivada usando math.js para avaliação numérica
                    let derivCompiled = math.compile(derivExpr);
                    // Avalia a derivada no ponto atual
                    derivadas[varName] = derivCompiled.evaluate(xObj);
                });
            } catch (e) {
                alert("Erro ao calcular derivadas com Algebrite: " + e);
                progressContainer.style.display = "none";
                return;
            }

            // Atualiza a barra de progresso
            progressFill.style.width = "50%";
            progressFill.textContent = "50%";

            // Continuar com os cálculos de incerteza usando as derivadas calculadas
            setTimeout(() => {
                // Soma das variâncias
                let uc2 = 0;
                listaVariaveis.forEach(vi => {
                    const di = derivadas[vi];
                    const ui = incertPadrao[vi];
                    uc2 += (di * ui) ** 2;
                });

                // Soma das covariâncias
                for (let i = 0; i < listaVariaveis.length; i++) {
                    for (let j = i + 1; j < listaVariaveis.length; j++) {
                        const vi = listaVariaveis[i];
                        const vj = listaVariaveis[j];
                        const r = correlation[vi][vj];
                        const di = derivadas[vi];
                        const dj = derivadas[vj];
                        const ui = incertPadrao[vi];
                        const uj = incertPadrao[vj];
                        uc2 += 2 * (di * ui) * (dj * uj) * r;
                    }
                }

                const uc = Math.sqrt(uc2);

                // Cálculos adicionais (veff, k, Uexp, etc.)
                let somaWS = 0;
                listaVariaveis.forEach(vi => {
                    const di = derivadas[vi];
                    const ui = incertPadrao[vi];
                    somaWS += (di * ui) ** 4 / dof[vi];
                });

                let veff = Infinity;
                if (somaWS > 0) {
                    const ucNoCorr2 = listaVariaveis.reduce((acc, vi) => {
                        return acc + (derivadas[vi] * incertPadrao[vi]) ** 2;
                    }, 0);
                    const ucNoCorr = Math.sqrt(ucNoCorr2);
                    veff = (ucNoCorr ** 4) / somaWS;
                }

                const conf = parseFloat(document.getElementById("confianca").value) || 95;
                const k = calcularFatorCobertura(conf, veff);
                const Uexp = k * uc;

                // Atualizar resultados na interface
                const resText = document.getElementById("resultados-text");
                resText.innerHTML = `
                      <h2>GUM (Literal Derivatives - Algebrite)</h2>
                      <p><strong>Valor do modelo:</strong> ${math.evaluate(expr, xObj).toFixed(6)}</p>
                      <p><strong>u<sub>c</sub>:</strong> ${uc.toFixed(6)}</p>
                      <p><strong>ν<sub>eff</sub>:</strong> ${veff.toFixed(2)}</p>
                      <p><strong>k p/ ${conf}%:</strong> ${k.toFixed(3)}</p>
                      <p><strong>U expandida:</strong> ${Uexp.toFixed(6)}</p>
                    `;

                // Plotagem (mesma lógica existente)
                let gumChart = document.getElementById("graficoGUM");
                let mcChart = document.getElementById("graficoMC");
                gumChart.style.display = "block";
                mcChart.style.display = "none";

                // Plot normal
                let mean = math.evaluate(expr, xObj);
                let sigma = uc;
                let xVals = [], yVals = [];
                let minX = mean - 4 * sigma;
                let maxX = mean + 4 * sigma;
                let step = (maxX - minX) / 100;
                for (let x = minX; x <= maxX; x += step) {
                    let pdf = (1 / (sigma * Math.sqrt(2 * Math.PI))) * Math.exp(-0.5 * ((x - mean) / sigma) ** 2);
                    xVals.push(x);
                    yVals.push(pdf);
                }
                let Ulow = mean - Uexp;
                let Uhigh = mean + Uexp;
                const trace = { x: xVals, y: yVals, mode: 'lines', fill: 'tozeroy' };
                const shapes = [
                    {
                        type: 'line', x0: Ulow, x1: Ulow, y0: 0, y1: 1,
                        line: { color: 'red', dash: 'dot', width: 2 }, yref: 'paper'
                    },
                    {
                        type: 'line', x0: Uhigh, x1: Uhigh, y0: 0, y1: 1,
                        line: { color: 'red', dash: 'dot', width: 2 }, yref: 'paper'
                    }
                ];
                const layout = {
                    title: "Distribuição GUM (Literal - Algebrite)",
                    xaxis: { title: "Y" },
                    yaxis: { title: "PDF" },
                    shapes: shapes
                };
                Plotly.newPlot("graficoGUM", [trace], layout);

                // Atualizar barra de progresso
                progressContainer.style.display = "none";
                progressFill.style.width = "0%";
                progressFill.textContent = "0%";
            }, 0);
        }


        function lerDados() {
            const valores = {}, incertPadrao = {}, dof = {}, correlation = {};
            listaVariaveis.forEach(vi => {
                const vStr = document.getElementById(`valor_${vi}`).textContent.trim();
                const uStr = document.getElementById(`U_${vi}`).textContent.trim();
                const kStr = document.getElementById(`k_${vi}`).textContent.trim();
                const dfStr = document.getElementById(`v_${vi}`).textContent.trim();

                const vNum = parseFloat(vStr) || 0;
                const uNum = parseFloat(uStr) || 0;
                const kNum = parseFloat(kStr) || 1;
                const dfNum = parseFloat(dfStr) || 1;

                valores[vi] = vNum;
                incertPadrao[vi] = (uNum / kNum);
                dof[vi] = dfNum;
            });
            listaVariaveis.forEach(vi => {
                correlation[vi] = {};
                listaVariaveis.forEach(vj => {
                    let cStr = document.getElementById(`corr_${vi}_${vj}`).textContent.trim();
                    correlation[vi][vj] = parseFloat(cStr) || 0;
                });
            });
            return { valores, incertPadrao, dof, correlation };
        }

        function calcularFatorCobertura(conf, df) {
            if (df <= 0) return 1.0;
            const alpha = 1 - (conf / 100);
            const p = 1 - alpha / 2;
            return jStat.studentt.inv(p, df);
        }

        function quantil(arr, p) {
            if (!arr.length) return NaN;
            if (p <= 0) return arr[0];
            if (p >= 1) return arr[arr.length - 1];
            const idx = (arr.length - 1) * p;
            const fl = Math.floor(idx);
            const fr = idx - fl;
            if (fl + 1 < arr.length) {
                return arr[fl] * (1 - fr) + arr[fl + 1] * fr;
            } else {
                return arr[fl];
            }
        }

        // *** GUM (Numérica) *** (chunk approach do código anterior)
        // a função: calcularGUMNumerico()

        // *** GUM (Kragten) *** (chunk approach)
        // a função: calcularGUMKragten()

        // *** Todos esses 3 já foram definidos no "código anterior"***
        // Mas para este único snippet, iremos inserir as 2 funções do snippet anterior:


        // ============ GUM (Numérica) =============
        function calcularGUMNumerico() {
            // (Mesma do snippet anterior)
            // ...
            // (Para economizar espaço, vamos colar a mesma implementação)
            // mas desta vez chamamos a progress bar no início.
            progressContainer.style.display = "block";
            progressFill.style.width = "0%";
            progressFill.textContent = "0%";

            // ...[código colado do snippet anterior, adaptado if needed]...

            const { valores, incertPadrao, dof, correlation } = lerDados();
            const inputModelo = document.getElementById("modelo").value.trim();
            const partes = inputModelo.split("=");
            if (partes.length < 2) {
                alert("Modelo inválido (GUM num.).");
                progressContainer.style.display = "none";
                return;
            }
            const expr = partes[1].trim();
            let compiledF;
            try {
                compiledF = math.compile(expr);
            } catch (e) {
                alert("Erro compile GUM num: " + e);
                progressContainer.style.display = "none";
                return;
            }
            const n = listaVariaveis.length;
            if (n === 0) {
                alert("Nenhuma var p/ GUM num");
                progressContainer.style.display = "none";
                return;
            }

            const resText = document.getElementById("resultados-text");
            resText.innerHTML = "";
            const gumChart = document.getElementById("graficoGUM");
            const mcChart = document.getElementById("graficoMC");
            gumChart.style.display = "none";
            mcChart.style.display = "none";

            // valor no ponto
            let xObj = {};
            for (let i = 0; i < n; i++) {
                xObj[listaVariaveis[i]] = valores[listaVariaveis[i]];
            }
            let valorModelo = 0;
            try {
                valorModelo = compiledF.evaluate(xObj);
            } catch (e) {
                alert("Erro aval base GUM num: " + e);
                progressContainer.style.display = "none";
                return;
            }

            let deriv = new Array(n).fill(0);
            let iVar = 0;
            let hUser = parseFloat(document.getElementById("hNumero").value.trim()) || 1e-6;

            function derivProximo() {
                if (iVar >= n) {
                    somaQuadrComCorrel(deriv);
                    return;
                }
                let vi = listaVariaveis[iVar];
                let x0 = xObj[vi];
                let h = Math.abs(x0) * hUser;
                if (h < 1e-12) h = 1e-6;

                xObj[vi] = x0 + h;
                let fPlus = 0; try { fPlus = compiledF.evaluate(xObj); } catch (e2) { }
                xObj[vi] = x0 - h;
                let fMinus = 0; try { fMinus = compiledF.evaluate(xObj); } catch (e3) { }
                xObj[vi] = x0; // restore
                deriv[iVar] = (fPlus - fMinus) / (2 * h);

                iVar++;
                let pct = Math.floor((iVar / (n * 2)) * 100);
                progressFill.style.width = pct + "%";
                progressFill.textContent = pct + "%";
                setTimeout(derivProximo, 0);
            }

            function somaQuadrComCorrel(der) {
                let uc2 = 0;
                let iOps = 0;
                let totalOps = n + (n * (n - 1)) / 2;

                let iD = 0;
                function somaDiag() {
                    if (iD < n) {
                        let di = der[iD];
                        let vi = listaVariaveis[iD];
                        let ui = incertPadrao[vi];
                        uc2 += (di * ui) ** 2;
                        iD++; iOps++;
                        let pct = Math.floor((iOps / totalOps) * 100);
                        progressFill.style.width = pct + "%";
                        progressFill.textContent = pct + "%";
                        setTimeout(somaDiag, 0);
                    } else {
                        somaOffDiag(0, 1);
                    }
                }
                function somaOffDiag(i, j) {
                    if (i < n) {
                        if (j < n) {
                            if (j > i) {
                                let vi = listaVariaveis[i];
                                let vj = listaVariaveis[j];
                                let r = correlation[vi][vj];
                                let di = der[i];
                                let dj = der[j];
                                let ui = incertPadrao[vi];
                                let uj = incertPadrao[vj];
                                uc2 += 2 * (di * ui) * (dj * uj) * r;
                                iOps++;
                                let pct = Math.floor((iOps / totalOps) * 100);
                                progressFill.style.width = pct + "%";
                                progressFill.textContent = pct + "%";
                            }
                            j++;
                            setTimeout(() => somaOffDiag(i, j), 0);
                        } else {
                            i++; j = i + 1;
                            setTimeout(() => somaOffDiag(i, j), 0);
                        }
                    } else {
                        finishGUM(uc2, der);
                    }
                }
                somaDiag();
            }

            function finishGUM(uc2, der) {
                let uc = Math.sqrt(uc2);
                let ucNoCorr2 = 0;
                for (let i = 0; i < n; i++) {
                    let di = der[i];
                    let vi = listaVariaveis[i];
                    let ui = incertPadrao[vi];
                    ucNoCorr2 += (di * ui) ** 2;
                }
                let ucNoCorr = Math.sqrt(ucNoCorr2);

                let somaWS = 0;
                for (let i = 0; i < n; i++) {
                    let di = der[i];
                    let vi = listaVariaveis[i];
                    let ui = incertPadrao[vi];
                    let val4 = (di * ui) ** 4;
                    somaWS += val4 / dof[vi];
                }
                let veff = Infinity;
                if (somaWS > 0) {
                    veff = (ucNoCorr ** 4) / somaWS;
                }
                const conf = parseFloat(document.getElementById("confianca").value) || 95;
                const k = calcularFatorCobertura(conf, veff);
                const Uexp = k * uc;

                let res = document.getElementById("resultados-text");
                res.innerHTML = `
                          <h2>GUM (Numérica)</h2>
                          <p><strong>Valor do modelo:</strong> ${valorModelo.toFixed(6)}</p>
                          <p><strong>u<sub>c</sub>:</strong> ${uc.toFixed(6)}</p>
                          <p><strong>ν<sub>eff</sub>:</strong> ${veff.toFixed(2)}</p>
                          <p><strong>k p/ ${conf}%:</strong> ${k.toFixed(3)}</p>
                          <p><strong>U expandida:</strong> ${Uexp.toFixed(6)}</p>
                        `;

                let gumChart = document.getElementById("graficoGUM");
                let mcChart = document.getElementById("graficoMC");
                gumChart.style.display = "block";
                mcChart.style.display = "none";

                // Plot normal
                let mean = valorModelo;
                let sigma = uc;
                let xVals = [], yVals = [];
                let minX = mean - 4 * sigma;
                let maxX = mean + 4 * sigma;
                let step = (maxX - minX) / 100;
                for (let x = minX; x <= maxX; x += step) {
                    let pdf = (1 / (sigma * Math.sqrt(2 * Math.PI))) *
                        Math.exp(-0.5 * ((x - mean) / sigma) ** 2);
                    xVals.push(x); yVals.push(pdf);
                }
                let Ulow = mean - Uexp;
                let Uhigh = mean + Uexp;
                const trace = { x: xVals, y: yVals, mode: 'lines', fill: 'tozeroy' };
                const shapes = [
                    {
                        type: 'line', x0: Ulow, x1: Ulow, y0: 0, y1: 1,
                        line: { color: 'red', dash: 'dot', width: 2 }, yref: 'paper'
                    },
                    {
                        type: 'line', x0: Uhigh, x1: Uhigh, y0: 0, y1: 1,
                        line: { color: 'red', dash: 'dot', width: 2 }, yref: 'paper'
                    }
                ];
                const layout = {
                    title: "Distribuição GUM (Numérica)",
                    xaxis: { title: "Y" },
                    yaxis: { title: "PDF" },
                    shapes: shapes
                };
                Plotly.newPlot("graficoGUM", [trace], layout);

                progressContainer.style.display = "none";
                progressFill.style.width = "0%";
                progressFill.textContent = "0%";
            }

            iVar = 0;
            derivProximo();
        }

        // ============ GUM (Kragten) =============
        function calcularGUMKragten() {
            // chunk approach do snippet anterior
            progressContainer.style.display = "block";
            progressFill.style.width = "0%";
            progressFill.textContent = "0%";

            const { valores, incertPadrao, dof, correlation } = lerDados();
            const inputModelo = document.getElementById("modelo").value.trim();
            const partes = inputModelo.split("=");
            if (partes.length < 2) {
                alert("Modelo inválido (GUM Kragten).");
                progressContainer.style.display = "none";
                return;
            }
            const expr = partes[1].trim();

            let compiledF;
            try {
                compiledF = math.compile(expr);
            } catch (e) {
                alert("Erro compile GUM Kragten: " + e);
                progressContainer.style.display = "none";
                return;
            }
            const n = listaVariaveis.length;
            if (n === 0) {
                alert("Nenhuma var p/ GUM Kragten");
                progressContainer.style.display = "none";
                return;
            }

            const resText = document.getElementById("resultados-text");
            resText.innerHTML = "";
            const gumChart = document.getElementById("graficoGUM");
            const mcChart = document.getElementById("graficoMC");
            gumChart.style.display = "none";
            mcChart.style.display = "none";

            // f0
            let xObj = {};
            for (let i = 0; i < n; i++) {
                xObj[listaVariaveis[i]] = valores[listaVariaveis[i]];
            }
            let f0 = 0;
            try {
                f0 = compiledF.evaluate(xObj);
            } catch (e) {
                alert("Erro eval base Kragten: " + e);
                progressContainer.style.display = "none";
                return;
            }

            let deriv = new Array(n).fill(0);
            let iVar = 0;

            function proximaVar() {
                if (iVar >= n) {
                    somaQuadrComCorrel();
                    return;
                }
                let vi = listaVariaveis[iVar];
                let x0 = xObj[vi];
                let u_i = incertPadrao[vi];
                xObj[vi] = x0 + u_i;
                let fPlus = 0;
                try { fPlus = compiledF.evaluate(xObj); } catch (e2) { }
                xObj[vi] = x0;
                deriv[iVar] = (fPlus - f0) / u_i;

                iVar++;
                let pct = Math.floor((iVar / (n * 2)) * 100);
                progressFill.style.width = pct + "%";
                progressFill.textContent = pct + "%";
                setTimeout(proximaVar, 0);
            }

            function somaQuadrComCorrel() {
                let uc2 = 0;
                let iOps = 0;
                let totalOps = n + (n * (n - 1)) / 2;

                let iD = 0;
                function somaDiag() {
                    if (iD < n) {
                        let di = deriv[iD];
                        let vi = listaVariaveis[iD];
                        let ui = incertPadrao[vi];
                        uc2 += (di * ui) ** 2;
                        iD++; iOps++;
                        let pct = Math.floor((iOps / totalOps) * 100);
                        progressFill.style.width = pct + "%";
                        progressFill.textContent = pct + "%";
                        setTimeout(somaDiag, 0);
                    } else {
                        somaOffDiag(0, 1);
                    }
                }
                function somaOffDiag(i, j) {
                    if (i < n) {
                        if (j < n) {
                            if (j > i) {
                                let vi = listaVariaveis[i];
                                let vj = listaVariaveis[j];
                                let r = correlation[vi][vj];
                                let di = deriv[i];
                                let dj = deriv[j];
                                let ui = incertPadrao[vi];
                                let uj = incertPadrao[vj];
                                uc2 += 2 * (di * ui) * (dj * uj) * r;
                                iOps++;
                                let pct = Math.floor((iOps / totalOps) * 100);
                                progressFill.style.width = pct + "%";
                                progressFill.textContent = pct + "%";
                            }
                            j++;
                            setTimeout(() => somaOffDiag(i, j), 0);
                        } else {
                            i++; j = i + 1;
                            setTimeout(() => somaOffDiag(i, j), 0);
                        }
                    } else {
                        finishKragten(uc2);
                    }
                }
                somaDiag();
            }

            function finishKragten(uc2) {
                let uc = Math.sqrt(uc2);

                let ucNoCorr2 = 0;
                for (let i = 0; i < n; i++) {
                    let di = deriv[i];
                    let vi = listaVariaveis[i];
                    let ui = incertPadrao[vi];
                    ucNoCorr2 += (di * ui) ** 2;
                }
                let ucNoCorr = Math.sqrt(ucNoCorr2);
                let somaWS = 0;
                for (let i = 0; i < n; i++) {
                    let di = deriv[i];
                    let vi = listaVariaveis[i];
                    let ui = incertPadrao[vi];
                    let val4 = (di * ui) ** 4;
                    somaWS += val4 / dof[vi];
                }
                let veff = Infinity;
                if (somaWS > 0) {
                    veff = (ucNoCorr ** 4) / somaWS;
                }
                const conf = parseFloat(document.getElementById("confianca").value) || 95;
                const k = calcularFatorCobertura(conf, veff);
                let Uexp = k * uc;

                let res = document.getElementById("resultados-text");
                res.innerHTML = `
                          <h2>GUM (Kragten)</h2>
                          <p><strong>Valor do modelo (f0):</strong> ${f0.toFixed(6)}</p>
                          <p><strong>u<sub>c</sub>:</strong> ${uc.toFixed(6)}</p>
                          <p><strong>ν<sub>eff</sub>:</strong> ${veff.toFixed(2)}</p>
                          <p><strong>k p/ ${conf}%:</strong> ${k.toFixed(3)}</p>
                          <p><strong>U expandida:</strong> ${Uexp.toFixed(6)}</p>
                        `;

                let gumChart = document.getElementById("graficoGUM");
                let mcChart = document.getElementById("graficoMC");
                gumChart.style.display = "block";
                mcChart.style.display = "none";

                // Plot normal
                let mean = f0;
                let sigma = uc;
                let xVals = [], yVals = [];
                let minX = mean - 4 * sigma;
                let maxX = mean + 4 * sigma;
                let step = (maxX - minX) / 100;
                for (let x = minX; x <= maxX; x += step) {
                    let pdf = (1 / (sigma * Math.sqrt(2 * Math.PI))) *
                        Math.exp(-0.5 * ((x - mean) / sigma) ** 2);
                    xVals.push(x);
                    yVals.push(pdf);
                }
                let Ulow = mean - Uexp;
                let Uhigh = mean + Uexp;
                const trace = { x: xVals, y: yVals, mode: 'lines', fill: 'tozeroy' };
                const shapes = [
                    {
                        type: 'line', x0: Ulow, x1: Ulow, y0: 0, y1: 1,
                        line: { color: 'red', dash: 'dot', width: 2 }, yref: 'paper'
                    },
                    {
                        type: 'line', x0: Uhigh, x1: Uhigh, y0: 0, y1: 1,
                        line: { color: 'red', dash: 'dot', width: 2 }, yref: 'paper'
                    }
                ];
                const layout = {
                    title: "Distribuição GUM (Kragten)",
                    xaxis: { title: "Y" },
                    yaxis: { title: "PDF" },
                    shapes: shapes
                };
                Plotly.newPlot("graficoGUM", [trace], layout);

                progressContainer.style.display = "none";
                progressFill.style.width = "0%";
                progressFill.textContent = "0%";
            }

            iVar = 0;
            proximaVar();
        }

        // ===================== Monte Carlo (unchanged) =====================
        function calcularMonteCarlo() {
            // (Mesma do snippet anterior)
            progressContainer.style.display = "block";
            progressFill.style.width = "0%";
            progressFill.textContent = "0%";

            const { valores, incertPadrao, dof, correlation } = lerDados();
            const inputModelo = document.getElementById("modelo").value.trim();
            const partes = inputModelo.split("=");
            if (partes.length < 2) {
                alert("Modelo inválido (MC).");
                progressContainer.style.display = "none";
                return;
            }
            const expr = partes[1].trim();

            let compiledF;
            try {
                compiledF = math.compile(expr);
            } catch (e) {
                alert("Erro compile MC: " + e);
                progressContainer.style.display = "none";
                return;
            }

            const n = listaVariaveis.length;
            if (n === 0) {
                alert("Nenhuma var p/ MC");
                progressContainer.style.display = "none";
                return;
            }

            const resText = document.getElementById("resultados-text");
            resText.innerHTML = "";
            const gumChart = document.getElementById("graficoGUM");
            const mcChart = document.getElementById("graficoMC");
            gumChart.style.display = "none";
            mcChart.style.display = "none";

            let meanVec = new Array(n);
            for (let i = 0; i < n; i++) {
                let vi = listaVariaveis[i];
                meanVec[i] = valores[vi];
            }
            let covMat = new Array(n).fill(null).map(() => new Array(n).fill(0));
            for (let i = 0; i < n; i++) {
                let vi = listaVariaveis[i];
                for (let j = 0; j < n; j++) {
                    let vj = listaVariaveis[j];
                    let r = correlation[vi][vj];
                    let ui = incertPadrao[vi];
                    let uj = incertPadrao[vj];
                    covMat[i][j] = r * ui * uj;
                }
            }
            let L;
            try {
                L = jStat.cholesky(covMat);
            } catch (er) {
                alert("Erro cholesky: " + er);
                progressContainer.style.display = "none";
                return;
            }

            const N = parseInt(document.getElementById("numAmostrasMC").value) || 10000;
            let ySamples = new Array(N);

            let k = 0;
            let chunkSize = 1000;
            function gerarChunk() {
                let limit = Math.min(k + chunkSize, N);
                for (; k < limit; k++) {
                    let z = new Array(n);
                    for (let i = 0; i < n; i++) {
                        z[i] = jStat.randn();
                    }
                    let xSim = new Array(n);
                    for (let i = 0; i < n; i++) {
                        let s = 0;
                        for (let j = 0; j < n; j++) {
                            s += L[i][j] * z[j];
                        }
                        xSim[i] = meanVec[i] + s;
                    }
                    let valsObj = {};
                    for (let i = 0; i < n; i++) {
                        valsObj[listaVariaveis[i]] = xSim[i];
                    }
                    let yVal = 0;
                    try {
                        yVal = compiledF.evaluate(valsObj);
                    } catch (ei) {
                        yVal = NaN;
                    }
                    ySamples[k] = yVal;
                }

                let pct = Math.floor((k / N) * 100);
                progressFill.style.width = pct + "%";
                progressFill.textContent = pct + "%";

                if (k < N) {
                    setTimeout(gerarChunk, 0);
                } else {
                    finishMC();
                }
            }

            function finishMC() {
                ySamples.sort((a, b) => a - b);
                const conf = parseFloat(document.getElementById("confianca").value) || 95;
                const alpha = 1 - (conf / 100);
                const pLow = alpha / 2, pHigh = 1 - alpha / 2;
                const meanY = jStat.mean(ySamples);
                const yLow = quantil(ySamples, pLow);
                const yHigh = quantil(ySamples, pHigh);

                resText.innerHTML = `
                          <h2>Monte Carlo</h2>
                          <p><strong>Média (amostral):</strong> ${meanY.toFixed(6)}</p>
                          <p><strong>Intervalo [${(pLow * 100).toFixed(1)}%, ${(pHigh * 100).toFixed(1)}%]:</strong><br/>
                          [${yLow.toFixed(6)}, ${yHigh.toFixed(6)}]</p>
                          <p><small>N=${N} amostras</small></p>
                        `;
                let gumChart = document.getElementById("graficoGUM");
                let mcChart = document.getElementById("graficoMC");
                gumChart.style.display = "none";
                mcChart.style.display = "block";

                const traceMC = {
                    x: ySamples,
                    type: 'histogram'
                };
                const layoutMC = {
                    title: `Histograma Monte Carlo (N=${N})`,
                    xaxis: { title: "Y" },
                    yaxis: { title: "Frequência" }
                };
                Plotly.newPlot(mcChart, [traceMC], layoutMC);

                progressContainer.style.display = "none";
                progressFill.style.width = "0%";
                progressFill.textContent = "0%";
            }

            k = 0;
            gerarChunk();
        }

        // =================== Salvar Excel (incluindo nº amostras e h) ===================
        function salvarExcel() {
            const inputModelo = document.getElementById("modelo").value.trim();
            const inputConf = document.getElementById("confianca").value.trim();
            const inputN = document.getElementById("numAmostrasMC").value.trim();
            const inputH = document.getElementById("hNumero").value.trim();

            const sheetMC = [];
            sheetMC.push(["Modelo e Nível de Confiança"]);
            sheetMC.push([]);
            sheetMC.push(["Modelo matemático:", inputModelo]);
            sheetMC.push(["Nível de confiança:", inputConf]);
            sheetMC.push(["Nº de amostras (Monte Carlo):", inputN]);
            sheetMC.push(["h (derivada num.):", inputH]);
            const wsMC = XLSX.utils.aoa_to_sheet(sheetMC);

            const sheetVars = [];
            sheetVars.push(["Variável", "Valor", "U", "k", "ν"]);
            listaVariaveis.forEach(vi => {
                const tdV = document.getElementById(`valor_${vi}`);
                const tdU = document.getElementById(`U_${vi}`);
                const tdK = document.getElementById(`k_${vi}`);
                const tdDf = document.getElementById(`v_${vi}`);
                sheetVars.push([
                    vi,
                    tdV ? tdV.textContent : "1.0",
                    tdU ? tdU.textContent : "0.2",
                    tdK ? tdK.textContent : "2.0",
                    tdDf ? tdDf.textContent : "10"
                ]);
            });
            const wsVars = XLSX.utils.aoa_to_sheet(sheetVars);

            const sheetCorr = [];
            const header = [""].concat(listaVariaveis);
            sheetCorr.push(header);
            listaVariaveis.forEach(vi => {
                const row = [vi];
                listaVariaveis.forEach(vj => {
                    const td = document.getElementById(`corr_${vi}_${vj}`);
                    row.push(td ? td.textContent.trim() : "0.0");
                });
                sheetCorr.push(row);
            });
            const wsCorr = XLSX.utils.aoa_to_sheet(sheetCorr);

            const wb = XLSX.utils.book_new();
            XLSX.utils.book_append_sheet(wb, wsMC, "Modelo_e_Confianca");
            XLSX.utils.book_append_sheet(wb, wsVars, "Variaveis");
            XLSX.utils.book_append_sheet(wb, wsCorr, "Correlacoes");

            XLSX.writeFile(wb, "resultado_incertezas.xlsx");
        }

        // ================== Carregar Excel ==================
        function carregarExcel() {
            const fileInput = document.getElementById("arquivoExcel");
            if (!fileInput.files.length) {
                alert("Selecione um arquivo .xlsx");
                return;
            }
            const file = fileInput.files[0];
            const reader = new FileReader();
            reader.onload = function (e) {
                const data = new Uint8Array(e.target.result);
                let wb;
                try {
                    wb = XLSX.read(data, { type: "array" });
                } catch (er) {
                    alert("Erro lendo xlsx: " + er);
                    return;
                }
                if (!wb.Sheets["Modelo_e_Confianca"] ||
                    !wb.Sheets["Variaveis"] ||
                    !wb.Sheets["Correlacoes"]) {
                    alert("Faltam abas: Modelo_e_Confianca, Variaveis, Correlacoes.");
                    return;
                }

                const wsMC = wb.Sheets["Modelo_e_Confianca"];
                const dataMC = XLSX.utils.sheet_to_json(wsMC, { header: 1 });
                let modeloLido = "", confLida = "", nMC = "", hVal = "";
                dataMC.forEach(row => {
                    if (!row || row.length < 2) return;
                    if (row[0] === "Modelo matemático:") modeloLido = row[1];
                    if (row[0] === "Nível de confiança:") confLida = row[1];
                    if (row[0] === "Nº de amostras (Monte Carlo):") nMC = row[1];
                    if (row[0] === "h (derivada num.):") hVal = row[1];
                });
                document.getElementById("modelo").value = modeloLido;
                document.getElementById("confianca").value = confLida;
                if (nMC) document.getElementById("numAmostrasMC").value = nMC;
                if (hVal) document.getElementById("hNumero").value = hVal;

                gerarTabelas();

                const wsVars = wb.Sheets["Variaveis"];
                const dataVars = XLSX.utils.sheet_to_json(wsVars, { header: 1 });
                for (let i = 1; i < dataVars.length; i++) {
                    const row = dataVars[i];
                    if (!row || row.length < 5) continue;
                    let nomeVar = row[0];
                    if (!listaVariaveis.includes(nomeVar)) continue;
                    document.getElementById(`valor_${nomeVar}`).textContent = row[1];
                    document.getElementById(`U_${nomeVar}`).textContent = row[2];
                    document.getElementById(`k_${nomeVar}`).textContent = row[3];
                    document.getElementById(`v_${nomeVar}`).textContent = row[4];
                }

                const wsCorr = wb.Sheets["Correlacoes"];
                const dataCorr = XLSX.utils.sheet_to_json(wsCorr, { header: 1 });
                if (dataCorr.length > 1) {
                    const header = dataCorr[0];
                    const colVars = header.slice(1);
                    for (let i = 1; i < dataCorr.length; i++) {
                        const row = dataCorr[i];
                        if (!row || row.length < 2) continue;
                        let vi = row[0];
                        if (!listaVariaveis.includes(vi)) continue;
                        for (let j = 1; j < row.length; j++) {
                            let vj = colVars[j - 1];
                            if (!listaVariaveis.includes(vj)) continue;
                            document.getElementById(`corr_${vi}_${vj}`).textContent = row[j];
                        }
                    }
                }
                alert("Arquivo carregado!");
            };
            reader.readAsArrayBuffer(file);
        }

        // Obter elementos do DOM
        const docButton = document.getElementById("docButton");
        const docModal = document.getElementById("docModal");
        const closeModal = document.getElementsByClassName("close")[0];

        // Quando o usuário clicar no botão, abrir o modal
        docButton.onclick = function () {
            docModal.style.display = "block";
        }

        // Quando o usuário clicar no X, fechar o modal
        closeModal.onclick = function () {
            docModal.style.display = "none";
        }

        // Quando o usuário clicar fora do conteúdo do modal, fechar o modal
        window.onclick = function (event) {
            if (event.target == docModal) {
                docModal.style.display = "none";
            }
        }
    </script>

</body>
</html>
