Last active
August 13, 2026 13:07
-
-
Save apotema/5c2d32c006e63447cf4146c022e9580a to your computer and use it in GitHub Desktop.
Embarques vermelhos vs azuis — MBB, 10/07 a 10/08/2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <title>Embarques Vermelhos MBB</title> | |
| <style> | |
| :root { | |
| color-scheme: light; | |
| --page: #ffffff; | |
| --surface: #ffffff; | |
| --ink: #0b0b0b; | |
| --ink-2: #52514e; | |
| --muted: #898781; | |
| --grid: #e1e0d9; | |
| --baseline: #c3c2b7; | |
| --border: rgba(11,11,11,0.10); | |
| --s1: #2a78d6; /* embarques azuis (imagem) */ | |
| --s2: #e34948; /* embarques vermelhos (planilhas) */ | |
| --band: rgba(42,120,214,0.055); | |
| } | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; | |
| background: var(--page); | |
| color: var(--ink); | |
| font: 15px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif; | |
| } | |
| .wrap { max-width: 1720px; margin: 0 auto; padding: 40px 24px 64px; display: flex; flex-direction: column; gap: 24px; } | |
| .tiles, header { max-width: 1080px; } | |
| header h1 { font-size: 24px; font-weight: 650; margin: 0 0 6px; text-wrap: balance; } | |
| header p { margin: 0; color: var(--ink-2); max-width: 68ch; } | |
| .tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; } | |
| .tile { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; } | |
| .tile .label { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); display: flex; align-items: center; gap: 6px; } | |
| .tile .dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; } | |
| .tile .value { font-size: 26px; font-weight: 650; margin-top: 2px; } | |
| .tile .sub { font-size: 12.5px; color: var(--ink-2); } | |
| .card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 20px; } | |
| .card h2 { font-size: 15px; font-weight: 650; margin: 0 0 2px; } | |
| .card .hint { font-size: 12.5px; color: var(--muted); margin: 0 0 14px; } | |
| .legend { display: flex; flex-wrap: wrap; gap: 16px; font-size: 13px; color: var(--ink-2); margin-bottom: 10px; } | |
| .legend span { display: inline-flex; align-items: center; gap: 7px; } | |
| .sw { width: 12px; height: 12px; border-radius: 3px; display: inline-block; } | |
| .scroller { overflow-x: auto; position: relative; } | |
| svg { display: block; } | |
| .tooltip { | |
| position: fixed; pointer-events: none; z-index: 10; display: none; | |
| background: var(--surface); border: 1px solid var(--border); border-radius: 8px; | |
| padding: 8px 11px; font-size: 12.5px; box-shadow: 0 4px 14px rgba(0,0,0,0.18); | |
| color: var(--ink); white-space: nowrap; | |
| } | |
| .tooltip .tt-date { font-weight: 650; margin-bottom: 3px; } | |
| .tooltip .row { display: flex; align-items: center; gap: 6px; color: var(--ink-2); } | |
| .tooltip .row b { color: var(--ink); font-variant-numeric: tabular-nums; margin-left: auto; padding-left: 14px; } | |
| .note { font-size: 12.5px; color: var(--muted); margin-top: 12px; max-width: 78ch; } | |
| table { border-collapse: collapse; width: 100%; font-size: 13.5px; } | |
| th, td { padding: 6px 10px; text-align: right; font-variant-numeric: tabular-nums; border-bottom: 1px solid var(--grid); } | |
| th { color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; } | |
| th:first-child, td:first-child { text-align: left; } | |
| td.na { color: var(--muted); } | |
| tr.wk td { color: var(--ink-2); } | |
| </style> | |
| <div class="wrap"> | |
| <header> | |
| <h1>Embarques vermelhos e embarques azuis — MBB, 10/07 a 10/08/2026</h1> | |
| <p>Comparativo diário: <strong>embarques vermelhos</strong> são as contagens das abas | |
| “Embarques vermelhos” das duas planilhas exportadas (12/07 e 09/08); | |
| <strong>embarques azuis</strong> são os valores da série “Não Autorizado” do painel de | |
| Embarques (imagem).</p> | |
| </header> | |
| <div class="tiles"> | |
| <div class="tile"> | |
| <div class="label"><span class="dot" style="background:var(--s2)"></span>Embarques vermelhos (9 dias cobertos)</div> | |
| <div class="value">377</div> | |
| <div class="sub">10–12/07 e 03–08/08</div> | |
| </div> | |
| <div class="tile"> | |
| <div class="label"><span class="dot" style="background:var(--s1)"></span>Embarques azuis nos mesmos dias</div> | |
| <div class="value">192</div> | |
| <div class="sub">soma dos rótulos “Não Autorizado” da imagem</div> | |
| </div> | |
| <div class="tile"> | |
| <div class="label">Razão vermelhos ÷ azuis</div> | |
| <div class="value">≈ 1,9×</div> | |
| <div class="sub">consistente em todos os dias comparáveis</div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h2>Embarques por dia</h2> | |
| <p class="hint">Faixas sombreadas marcam os dias em que há embarques vermelhos para comparar. Passe o mouse sobre um dia para ver os valores.</p> | |
| <div class="legend"> | |
| <span><span class="sw" style="background:var(--s1)"></span>Embarques azuis</span> | |
| <span><span class="sw" style="background:var(--s2)"></span>Embarques vermelhos</span> | |
| </div> | |
| <div class="scroller"><svg id="chart" role="img" aria-label="Gráfico de barras comparando embarques vermelhos por dia entre as planilhas e a imagem"></svg></div> | |
| <p class="note">A planilha de 12/07 só contém registros de 06 a 12/07 e a de 09/08 só de 03 a 08/08 — | |
| nos demais dias a barra vermelha aparece em 0 apenas para visualização, sem dado real de planilha. Nos fins de semana | |
| 12/07, 19/07, 26/07, 02/08 e 09/08 a imagem não exibe rótulo para a série vermelha (barras muito | |
| pequenas), indicados como “—”.</p> | |
| </div> | |
| <div class="card"> | |
| <h2>Tabela de valores</h2> | |
| <p class="hint">Apenas os dias com pelo menos uma fonte disponível dentro do período.</p> | |
| <div class="scroller"><table id="tbl"> | |
| <thead><tr><th>Data</th><th>Embarques azuis</th><th>Embarques vermelhos</th><th>Fonte da planilha</th><th>Vermelhos ÷ azuis</th></tr></thead> | |
| <tbody></tbody> | |
| </table></div> | |
| </div> | |
| </div> | |
| <div class="tooltip" id="tt"></div> | |
| <script> | |
| // dia, imagem (null = sem rótulo na imagem), planilha (null = fora da cobertura), arquivo | |
| const DATA = [ | |
| ["10/07", 5, 12, "12/07"], ["11/07", 5, 13, "12/07"], ["12/07", null, 1, "12/07"], | |
| ["13/07", 49, null, null], ["14/07", 49, null, null], ["15/07", 36, null, null], | |
| ["16/07", 41, null, null], ["17/07", 39, null, null], ["18/07", 26, null, null], | |
| ["19/07", null, null, null], ["20/07", 27, null, null], ["21/07", 29, null, null], | |
| ["22/07", 25, null, null], ["23/07", 29, null, null], ["24/07", 26, null, null], | |
| ["25/07", 42, null, null], ["26/07", null, null, null], ["27/07", 29, null, null], | |
| ["28/07", 34, null, null], ["29/07", 31, null, null], ["30/07", 25, null, null], | |
| ["31/07", 30, null, null], ["01/08", 0, null, null], ["02/08", null, null, null], | |
| ["03/08", 33, 64, "09/08"], ["04/08", 39, 75, "09/08"], ["05/08", 42, 83, "09/08"], | |
| ["06/08", 41, 73, "09/08"], ["07/08", 25, 48, "09/08"], ["08/08", 2, 8, "09/08"], | |
| ["09/08", null, null, null], ["10/08", 31, null, null] | |
| ]; | |
| const css = v => getComputedStyle(document.documentElement).getPropertyValue(v).trim(); | |
| const M = { t: 28, r: 10, b: 30, l: 40 }; | |
| const groupW = 50, plotH = 560; | |
| const W = M.l + M.r + DATA.length * groupW, H = M.t + M.b + plotH; | |
| const maxV = 90, y = v => M.t + plotH - (v / maxV) * plotH; | |
| const svg = document.getElementById("chart"); | |
| svg.setAttribute("width", W); svg.setAttribute("height", H); | |
| svg.setAttribute("viewBox", `0 0 ${W} ${H}`); | |
| const el = (n, at) => { const e = document.createElementNS("http://www.w3.org/2000/svg", n); | |
| for (const k in at) e.setAttribute(k, at[k]); return e; }; | |
| const roundedBar = (x, v, w, fill) => { | |
| const top = y(v), base = y(0), r = Math.min(3, Math.max(0, base - top)); | |
| return el("path", { d: `M${x},${base} V${top + r} Q${x},${top} ${x + r},${top} H${x + w - r} Q${x + w},${top} ${x + w},${top + r} V${base} Z`, fill }); | |
| }; | |
| function draw() { | |
| svg.innerHTML = ""; | |
| // coverage bands (dias com planilha) | |
| DATA.forEach((d, i) => { | |
| if (d[2] !== null) svg.appendChild(el("rect", { x: M.l + i * groupW, y: M.t - 6, width: groupW, height: plotH + 6, fill: css("--band") })); | |
| }); | |
| // gridlines + y labels | |
| for (let v = 0; v <= maxV; v += 10) { | |
| svg.appendChild(el("line", { x1: M.l, x2: W - M.r, y1: y(v), y2: y(v), stroke: v === 0 ? css("--baseline") : css("--grid"), "stroke-width": 1 })); | |
| if (v % 30 === 0) { | |
| const t = el("text", { x: M.l - 8, y: y(v) + 4, "text-anchor": "end", "font-size": 11, fill: css("--muted") }); | |
| t.textContent = v; svg.appendChild(t); | |
| } | |
| } | |
| const barW = 17, gap = 2; | |
| const valLabel = (cx, v, bold) => { | |
| const t = el("text", { x: cx, y: y(v) - 5, "text-anchor": "middle", "font-size": 11.5, | |
| "font-weight": bold ? 650 : 500, fill: css("--ink") }); | |
| t.textContent = v; return t; | |
| }; | |
| DATA.forEach((d, i) => { | |
| const gx = M.l + i * groupW, [dia, img, pla] = d; | |
| // dias sem dado de planilha mostram a barra vermelha em 0, apenas para visualização | |
| const plaShow = pla !== null ? pla : (img !== null ? 0 : null); | |
| const both = img !== null && plaShow !== null; | |
| const startX = gx + (groupW - (both ? barW * 2 + gap : barW)) / 2; | |
| if (img !== null) { | |
| svg.appendChild(roundedBar(startX, img, barW, css("--s1"))); | |
| svg.appendChild(valLabel(startX + barW / 2, img, false)); | |
| } | |
| if (plaShow !== null) { | |
| const px = both ? startX + barW + gap : startX; | |
| if (plaShow === 0) { | |
| svg.appendChild(el("rect", { x: px, y: y(0) - 2, width: barW, height: 2, fill: css("--s2") })); | |
| } else { | |
| svg.appendChild(roundedBar(px, plaShow, barW, css("--s2"))); | |
| } | |
| svg.appendChild(valLabel(px + barW / 2, plaShow, true)); | |
| } | |
| if (img === null && pla === null) { | |
| const t = el("text", { x: gx + groupW / 2, y: y(0) - 5, "text-anchor": "middle", "font-size": 10, fill: css("--muted") }); | |
| t.textContent = "—"; svg.appendChild(t); | |
| } | |
| if (i % 2 === 0) { | |
| const t = el("text", { x: gx + groupW / 2, y: H - 8, "text-anchor": "middle", "font-size": 11, fill: css("--muted") }); | |
| t.textContent = dia; svg.appendChild(t); | |
| } | |
| const hit = el("rect", { x: gx, y: M.t - 6, width: groupW, height: plotH + 6, fill: "transparent" }); | |
| hit.dataset.i = i; svg.appendChild(hit); | |
| }); | |
| } | |
| draw(); | |
| const tt = document.getElementById("tt"); | |
| svg.addEventListener("mousemove", e => { | |
| const i = e.target.dataset && e.target.dataset.i; | |
| if (i === undefined) { tt.style.display = "none"; return; } | |
| const [dia, img, pla, src] = DATA[+i]; | |
| tt.innerHTML = `<div class="tt-date">${dia}/2026</div> | |
| <div class="row"><span class="sw" style="background:var(--s1)"></span>Embarques azuis <b>${img === null ? "sem rótulo" : img}</b></div> | |
| <div class="row"><span class="sw" style="background:var(--s2)"></span>Embarques vermelhos <b>${pla === null ? "sem dado" : pla}</b></div>` + | |
| (src ? `<div class="row" style="margin-top:2px;color:var(--muted)">arquivo de ${src}</div>` : ""); | |
| tt.style.display = "block"; | |
| tt.style.left = Math.min(e.clientX + 14, innerWidth - tt.offsetWidth - 8) + "px"; | |
| tt.style.top = (e.clientY + 14) + "px"; | |
| }); | |
| svg.addEventListener("mouseleave", () => tt.style.display = "none"); | |
| // tabela | |
| const tb = document.querySelector("#tbl tbody"); | |
| DATA.forEach(([dia, img, pla, src]) => { | |
| const tr = document.createElement("tr"); | |
| const ratio = img && pla ? (pla / img).toLocaleString("pt-BR", { maximumFractionDigits: 1 }) + "×" : "—"; | |
| tr.innerHTML = `<td>${dia}</td> | |
| <td class="${img === null ? "na" : ""}">${img === null ? "—" : img}</td> | |
| <td class="${pla === null ? "na" : ""}">${pla === null ? "—" : pla}</td> | |
| <td class="${src ? "" : "na"}">${src ? "mbb-red-embarks-2026-" + (src === "12/07" ? "07-12" : "08-09") : "—"}</td> | |
| <td class="${img && pla ? "" : "na"}">${ratio}</td>`; | |
| tb.appendChild(tr); | |
| }); | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment