Skip to content

Instantly share code, notes, and snippets.

@apotema
Last active August 13, 2026 13:07
Show Gist options
  • Select an option

  • Save apotema/5c2d32c006e63447cf4146c022e9580a to your computer and use it in GitHub Desktop.

Select an option

Save apotema/5c2d32c006e63447cf4146c022e9580a to your computer and use it in GitHub Desktop.
Embarques vermelhos vs azuis — MBB, 10/07 a 10/08/2026
<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