Files
MBS/Dashboards MARMOTECH/Dashboard_Presidencia_Mockup.html
T

562 lines
28 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<title>Radiografía Marmotech</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600;9..144,700&family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap">
<style>
:root{
--bg:#f2efe9; --surface:#fbfaf7; --surface-2:#f5f2ea;
--ink:#231f18; --muted:#726c60; --faint:#9a9284;
--line:#e4dfd4; --line-2:#efe9dd;
--accent:#9a6a2b; --accent-soft:#e9dcc4;
--pos:#2f7d57; --neg:#b3402a; --warn:#b1832a;
--grid:#eae4d8;
--shadow:0 1px 2px rgba(40,33,20,.05),0 8px 24px -12px rgba(40,33,20,.14);
--radius:14px;
}
@media (prefers-color-scheme:dark){
:root:not([data-theme="light"]){
--bg:#17150f; --surface:#211e16; --surface-2:#26221a;
--ink:#ece6da; --muted:#a69d8c; --faint:#7c7361;
--line:#332e24; --line-2:#2b271e;
--accent:#cd9c56; --accent-soft:#3a3020;
--pos:#4fb07f; --neg:#e0674e; --warn:#d5a34a;
--grid:#2a261d;
--shadow:0 1px 2px rgba(0,0,0,.4),0 10px 30px -14px rgba(0,0,0,.6);
}
}
:root[data-theme="dark"]{
--bg:#17150f; --surface:#211e16; --surface-2:#26221a;
--ink:#ece6da; --muted:#a69d8c; --faint:#7c7361;
--line:#332e24; --line-2:#2b271e;
--accent:#cd9c56; --accent-soft:#3a3020;
--pos:#4fb07f; --neg:#e0674e; --warn:#d5a34a;
--grid:#2a261d;
--shadow:0 1px 2px rgba(0,0,0,.4),0 10px 30px -14px rgba(0,0,0,.6);
}
*{box-sizing:border-box}
html,body{margin:0}
body{
background:var(--bg); color:var(--ink);
font-family:"IBM Plex Sans",system-ui,sans-serif;
font-size:15px; line-height:1.5;
-webkit-font-smoothing:antialiased;
}
.wrap{max-width:1220px; margin:0 auto; padding:22px 20px 60px}
.num{font-variant-numeric:tabular-nums; font-feature-settings:"tnum" 1}
/* Header */
header.top{display:flex; align-items:flex-end; justify-content:space-between; gap:20px; flex-wrap:wrap; margin-bottom:6px}
.brand{display:flex; align-items:center; gap:14px}
.mark{width:44px; height:44px; flex:0 0 auto}
.brand h1{font-family:"Fraunces",serif; font-weight:600; font-size:26px; letter-spacing:-.01em; margin:0; line-height:1.05}
.brand .sub{color:var(--muted); font-size:12.5px; letter-spacing:.14em; text-transform:uppercase; margin-top:3px}
.period{text-align:right}
.period .lbl{font-size:11px; letter-spacing:.16em; text-transform:uppercase; color:var(--faint)}
.period .val{font-family:"Fraunces",serif; font-size:19px; font-weight:500}
.period .note{font-size:11.5px; color:var(--muted)}
.rule{height:1px; background:linear-gradient(90deg,var(--accent),var(--line) 60%,transparent); margin:16px 0 18px; opacity:.7}
/* Tabs */
nav.tabs{display:flex; gap:4px; margin-bottom:20px; border-bottom:1px solid var(--line); flex-wrap:wrap}
nav.tabs button{
appearance:none; border:0; background:none; cursor:pointer; color:var(--muted);
font-family:inherit; font-size:14px; font-weight:500; padding:10px 15px; border-radius:8px 8px 0 0;
border-bottom:2px solid transparent; margin-bottom:-1px; display:flex; align-items:center; gap:8px;
}
nav.tabs button .idx{font-family:"IBM Plex Mono",monospace; font-size:11px; color:var(--faint)}
nav.tabs button:hover{color:var(--ink); background:var(--surface-2)}
nav.tabs button[aria-selected="true"]{color:var(--ink); border-bottom-color:var(--accent)}
nav.tabs button[aria-selected="true"] .idx{color:var(--accent)}
:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.page{display:none; animation:fade .35s ease}
.page.active{display:block}
@keyframes fade{from{opacity:0; transform:translateY(4px)}to{opacity:1; transform:none}}
@media (prefers-reduced-motion:reduce){.page,.page.active{animation:none}}
/* Cards & grid */
.grid{display:grid; gap:14px}
.kpis{grid-template-columns:repeat(4,1fr)}
.card{background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow); padding:16px 17px}
.card h3{margin:0 0 2px; font-size:11.5px; letter-spacing:.13em; text-transform:uppercase; color:var(--muted); font-weight:600}
.card .cap{font-size:11.5px; color:var(--faint); margin:0 0 12px}
.kpi .k-val{font-family:"Fraunces",serif; font-weight:600; font-size:29px; letter-spacing:-.01em; line-height:1.05; margin-top:6px}
.kpi .k-val small{font-size:14px; color:var(--muted); font-weight:500; font-family:"IBM Plex Sans"}
.kpi .k-sub{display:flex; align-items:center; gap:8px; margin-top:9px; font-size:12.5px; color:var(--muted)}
.delta{display:inline-flex; align-items:center; gap:4px; font-weight:600; font-variant-numeric:tabular-nums; padding:2px 7px; border-radius:20px; font-size:12px}
.delta.up{color:var(--pos); background:color-mix(in srgb,var(--pos) 12%,transparent)}
.delta.down{color:var(--neg); background:color-mix(in srgb,var(--neg) 12%,transparent)}
.delta.flat{color:var(--warn); background:color-mix(in srgb,var(--warn) 12%,transparent)}
.accent-bar{height:3px; border-radius:3px; background:var(--accent); opacity:.9; margin:-16px -17px 14px; border-radius:var(--radius) var(--radius) 0 0}
.row{display:grid; gap:14px; margin-top:14px}
.r-8-4{grid-template-columns:1.9fr 1.1fr}
.r-6-6{grid-template-columns:1fr 1fr}
.r-7-5{grid-template-columns:1.4fr 1fr}
/* Chart bits */
svg{display:block; width:100%; height:auto; overflow:visible}
.lgd{display:flex; gap:16px; flex-wrap:wrap; font-size:12px; color:var(--muted); margin-top:10px}
.lgd span{display:inline-flex; align-items:center; gap:6px}
.dot{width:10px; height:10px; border-radius:3px; display:inline-block}
table.tbl{width:100%; border-collapse:collapse; font-size:13px}
table.tbl th{text-align:left; font-size:11px; letter-spacing:.08em; text-transform:uppercase; color:var(--faint); font-weight:600; padding:7px 8px; border-bottom:1px solid var(--line)}
table.tbl td{padding:8px; border-bottom:1px solid var(--line-2); font-variant-numeric:tabular-nums}
table.tbl td.r,table.tbl th.r{text-align:right}
table.tbl tr:last-child td{border-bottom:0}
.barcell{position:relative}
.barcell .fill{position:absolute; left:0; top:50%; transform:translateY(-50%); height:60%; border-radius:3px; background:var(--accent-soft)}
.barcell span{position:relative}
.ratio{display:flex; align-items:baseline; gap:10px}
.ratio .big{font-family:"Fraunces",serif; font-weight:600; font-size:34px; letter-spacing:-.02em}
.foot{color:var(--muted); font-size:12px; margin-top:26px; border-top:1px solid var(--line); padding-top:14px}
.foot code{font-family:"IBM Plex Mono",monospace; font-size:11.5px; background:var(--surface-2); padding:1px 5px; border-radius:4px}
.pill{font-size:10.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--accent); background:var(--accent-soft); padding:3px 8px; border-radius:20px; font-weight:600}
@media(max-width:880px){
.kpis{grid-template-columns:repeat(2,1fr)}
.r-8-4,.r-6-6,.r-7-5{grid-template-columns:1fr}
}
</style>
<div class="wrap">
<header class="top">
<div class="brand">
<svg class="mark" viewBox="0 0 44 44" aria-hidden="true">
<rect x="1" y="1" width="42" height="42" rx="9" fill="none" stroke="var(--accent)" stroke-width="1.5"/>
<path d="M8 30 L17 15 L23 24 L29 12 L36 30 Z" fill="none" stroke="var(--accent)" stroke-width="1.6" stroke-linejoin="round"/>
<path d="M8 33 L36 33" stroke="var(--accent)" stroke-width="1.6"/>
<circle cx="29" cy="12" r="1.8" fill="var(--accent)"/>
</svg>
<div>
<h1>Radiografía de la Empresa</h1>
<div class="sub">Marmotech, S.A. &middot; Cuadro de Mando de Presidencia</div>
</div>
</div>
<div class="period">
<div class="lbl">Periodo</div>
<div class="val num">Enero Julio 2026</div>
<div class="note">acumulado del año · comparado vs. 2025</div>
</div>
</header>
<div class="rule"></div>
<nav class="tabs" role="tablist">
<button role="tab" aria-selected="true" data-p="p1"><span class="idx">01</span> Radiografía</button>
<button role="tab" aria-selected="false" data-p="p2"><span class="idx">02</span> Análisis de Gastos</button>
<button role="tab" aria-selected="false" data-p="p3"><span class="idx">03</span> Estructura Financiera</button>
</nav>
<!-- ============ PÁGINA 1 ============ -->
<section class="page active" id="p1" role="tabpanel">
<div class="grid kpis">
<div class="card kpi"><div class="accent-bar"></div>
<h3>Ventas Netas</h3>
<div class="k-val num">RD$ 1,375.3<small> M</small></div>
<div class="k-sub"><span class="delta down">▼ 1.3%</span> vs. 1,393.1 M (2025)</div>
</div>
<div class="card kpi">
<h3>Utilidad Bruta</h3>
<div class="k-val num">RD$ 706.9<small> M</small></div>
<div class="k-sub"><span class="delta down">▼ 1.4 pp</span> margen 51.4% <span style="color:var(--faint)">(52.8%)</span></div>
</div>
<div class="card kpi">
<h3>Utilidad Operativa</h3>
<div class="k-val num">RD$ 292.1<small> M</small></div>
<div class="k-sub"><span class="delta flat">21.2%</span> margen operativo</div>
</div>
<div class="card kpi"><div class="accent-bar"></div>
<h3>Utilidad Neta</h3>
<div class="k-val num">RD$ 219.6<small> M</small></div>
<div class="k-sub"><span class="delta down">▼ 21.4%</span> margen 16.0% <span style="color:var(--faint)">(20.1%)</span></div>
</div>
</div>
<div class="row r-7-5">
<div class="card">
<h3>Estado de Resultados — Cascada</h3>
<p class="cap">De ventas a utilidad neta · acumulado 2026 (RD$ millones)</p>
<svg id="waterfall" viewBox="0 0 720 300" role="img" aria-label="Cascada del estado de resultados"></svg>
</div>
<div class="card">
<h3>Composición de cada RD$ vendido</h3>
<p class="cap">Estructura del peso de ventas · 2026</p>
<svg id="composition" viewBox="0 0 360 300" role="img" aria-label="Composición de ventas"></svg>
</div>
</div>
<div class="row r-7-5">
<div class="card">
<h3>Comportamiento del periodo actual</h3>
<p class="cap">Ventas netas (barras) y utilidad neta (línea) por mes · 2026</p>
<svg id="trend" viewBox="0 0 720 280" role="img" aria-label="Tendencia mensual 2026"></svg>
<div class="lgd">
<span><i class="dot" style="background:var(--accent-soft)"></i> Ventas netas</span>
<span><i class="dot" style="background:var(--accent)"></i> Utilidad neta</span>
<span><i class="dot" style="background:var(--pos)"></i> Margen neto %</span>
</div>
</div>
<div class="card">
<h3>Trayectoria anual</h3>
<p class="cap">Ventas y utilidad neta por año (RD$ M) · 2026 parcial</p>
<svg id="annual" viewBox="0 0 360 280" role="img" aria-label="Comparativo anual"></svg>
</div>
</div>
</section>
<!-- ============ PÁGINA 2 ============ -->
<section class="page" id="p2" role="tabpanel">
<div class="grid kpis">
<div class="card kpi"><div class="accent-bar"></div>
<h3>Gastos Operativos</h3>
<div class="k-val num">RD$ 414.7<small> M</small></div>
<div class="k-sub"><span class="delta down">▲ 7.1%</span> vs. 387.2 M (2025)</div>
</div>
<div class="card kpi">
<h3>Gasto / Ventas</h3>
<div class="k-val num">30.2<small> %</small></div>
<div class="k-sub"><span class="delta down">▲ 2.4 pp</span> vs. 27.8% (2025)</div>
</div>
<div class="card kpi">
<h3>Gerencia mayor peso</h3>
<div class="k-val" style="font-size:22px">Ventas y Mercadeo</div>
<div class="k-sub num">RD$ 184.5 M · 44% del gasto</div>
</div>
<div class="card kpi">
<h3>Mayor alza YoY</h3>
<div class="k-val" style="font-size:22px">Admin. y Materiales</div>
<div class="k-sub num"><span class="delta down">▲ 13.3%</span> +12.3 M</div>
</div>
</div>
<div class="row r-6-6">
<div class="card">
<h3>Gasto por gerencia</h3>
<p class="cap">2026 vs. 2025 · acumulado enejul (RD$ M)</p>
<svg id="ger" viewBox="0 0 380 300" role="img" aria-label="Gasto por gerencia"></svg>
<div class="lgd">
<span><i class="dot" style="background:var(--accent)"></i> 2026</span>
<span><i class="dot" style="background:var(--accent-soft)"></i> 2025</span>
</div>
</div>
<div class="card">
<h3>Naturaleza del gasto</h3>
<p class="cap">Por subgrupo contable · 2026 (RD$ M)</p>
<table class="tbl">
<thead><tr><th>Subgrupo</th><th class="r">Monto</th><th class="r">% ventas</th></tr></thead>
<tbody id="subg"></tbody>
</table>
<p class="cap" style="margin-top:12px">El subgrupo <b>76 Cierre de gastos de fabricación</b> (325.7 M) es una absorción a costo; reduce el gasto neto operativo.</p>
</div>
</div>
<div class="row">
<div class="card">
<h3>Gasto mensual — control de eficiencia</h3>
<p class="cap">Gasto operativo por mes y su relación con las ventas · 2026</p>
<svg id="gtrend" viewBox="0 0 720 250" role="img" aria-label="Gasto mensual"></svg>
</div>
</div>
</section>
<!-- ============ PÁGINA 3 ============ -->
<section class="page" id="p3" role="tabpanel">
<div class="grid kpis">
<div class="card kpi"><div class="accent-bar"></div>
<h3>Activos Totales</h3>
<div class="k-val num">RD$ 6,435<small> M</small></div>
<div class="k-sub">al 31-jul-2026</div>
</div>
<div class="card kpi">
<h3>Razón Corriente</h3>
<div class="k-val num">2.29<small> ×</small></div>
<div class="k-sub"><span class="delta up">sólida</span> activo cte. 3,250 / pasivo cte. 1,420</div>
</div>
<div class="card kpi">
<h3>Capital de Trabajo</h3>
<div class="k-val num">RD$ 1,830<small> M</small></div>
<div class="k-sub">holgura de liquidez operativa</div>
</div>
<div class="card kpi">
<h3>Endeudamiento</h3>
<div class="k-val num">36<small> %</small></div>
<div class="k-sub"><span class="delta up">conservador</span> pasivo / activo</div>
</div>
</div>
<div class="row r-6-6">
<div class="card">
<h3>De dónde viene y dónde está el capital</h3>
<p class="cap">Activos = Pasivos + Patrimonio + resultado del ejercicio (RD$ M)</p>
<svg id="bal" viewBox="0 0 380 300" role="img" aria-label="Estructura del balance"></svg>
</div>
<div class="card">
<h3>Composición del activo</h3>
<p class="cap">al 31-jul-2026 (RD$ M)</p>
<table class="tbl">
<thead><tr><th>Rubro</th><th class="r">Saldo</th></tr></thead>
<tbody id="act"></tbody>
</table>
<h3 style="margin-top:18px">Composición del pasivo</h3>
<table class="tbl">
<thead><tr><th>Rubro</th><th class="r">Saldo</th></tr></thead>
<tbody id="pas"></tbody>
</table>
</div>
</div>
</section>
<div class="foot">
<span class="pill">Prototipo de diseño</span>
&nbsp; Vista previa del tablero de Power BI. Fuente: <code>MarmotechBI.presidencia.vwPLMensual</code>, <code>vwGastosDepto</code>, <code>vwBalanceMensual</code>
reproduce el Mayor General Analítico (cgprrp008) y el Análisis de Gastos (cgprrp009). Cifras validadas contra el sistema al 31-jul-2026.
</div>
</div>
<script>
(function(){
var css=getComputedStyle(document.documentElement);
var C=function(n){return css.getPropertyValue(n).trim()};
function col(n){return C(n)}
var money=function(v){return v.toLocaleString('en-US',{minimumFractionDigits:1,maximumFractionDigits:1})};
/* tabs */
var btns=document.querySelectorAll('nav.tabs button');
btns.forEach(function(b){
b.addEventListener('click',function(){
btns.forEach(function(x){x.setAttribute('aria-selected','false')});
b.setAttribute('aria-selected','true');
document.querySelectorAll('.page').forEach(function(p){p.classList.remove('active')});
document.getElementById(b.dataset.p).classList.add('active');
});
});
var NS='http://www.w3.org/2000/svg';
function el(t,a){var e=document.createElementNS(NS,t);for(var k in a)e.setAttribute(k,a[k]);return e;}
function txt(x,y,s,o){o=o||{};var t=el('text',{x:x,y:y});t.textContent=s;
t.setAttribute('fill',o.fill||col('--muted'));
t.setAttribute('font-size',o.fs||11);
t.setAttribute('font-family',o.mono?'"IBM Plex Mono",monospace':'"IBM Plex Sans",sans-serif');
t.setAttribute('font-weight',o.fw||400);
if(o.anchor)t.setAttribute('text-anchor',o.anchor);
t.setAttribute('font-variant-numeric','tabular-nums');
return t;}
/* ---------- WATERFALL ---------- */
(function(){
var svg=document.getElementById('waterfall'); if(!svg)return;
var W=720,H=300,padL=8,padR=8,base=250,top=20;
var steps=[
{l:'Ventas',v:1375.3,type:'start'},
{l:'Costo',v:-668.4,type:'neg'},
{l:'Ut. Bruta',v:706.9,type:'sub'},
{l:'Gastos',v:-414.7,type:'neg'},
{l:'Ut. Operat.',v:292.1,type:'sub'},
{l:'Otros/ISR',v:-72.5,type:'neg'},
{l:'Ut. Neta',v:219.6,type:'end'}
];
var max=1375.3, sc=(base-top)/max;
var n=steps.length, gap=14, bw=(W-padL-padR-gap*(n-1))/n;
var run=0;
steps.forEach(function(s,i){
var x=padL+i*(bw+gap), h, y, fill;
if(s.type==='start'||s.type==='sub'||s.type==='end'){
h=s.v*sc; y=base-h; run=s.v;
fill = s.type==='end'?col('--accent') : (s.type==='start'?col('--accent'):col('--ink'));
if(s.type==='sub')fill=col('--faint');
}else{
h=Math.abs(s.v)*sc; y=base-(run*sc); run=run+s.v;
fill=col('--neg');
}
svg.appendChild(el('rect',{x:x,y:y,width:bw,height:Math.max(2,h),rx:3,fill:fill,opacity:s.type==='sub'?0.5:0.92}));
svg.appendChild(txt(x+bw/2,base+16,s.l,{anchor:'middle',fs:10.5,fill:col('--muted')}));
svg.appendChild(txt(x+bw/2,y-6,(s.v>0?'':'')+money(Math.abs(s.v)),{anchor:'middle',fs:11,mono:true,fw:600,fill:col('--ink')}));
});
})();
/* ---------- COMPOSITION (stacked bar of one peso) ---------- */
(function(){
var svg=document.getElementById('composition'); if(!svg)return;
var parts=[
{l:'Costo de ventas',p:48.6,c:col('--neg')},
{l:'Gastos operativos',p:30.2,c:col('--warn')},
{l:'Otros / ISR',p:5.3,c:col('--faint')},
{l:'Utilidad neta',p:16.0,c:col('--pos')}
];
var x=90,y=24,w=54,H=250,total=100,sc=H/total,cy=y;
parts.forEach(function(p){
var h=p.p*sc;
svg.appendChild(el('rect',{x:x,y:cy,width:w,height:h,fill:p.c,opacity:.9}));
svg.appendChild(txt(x-10,cy+h/2+4,p.p.toFixed(1)+'%',{anchor:'end',mono:true,fs:12,fw:600,fill:col('--ink')}));
svg.appendChild(txt(x+w+10,cy+h/2+4,p.l,{fs:11.5,fill:col('--muted')}));
cy+=h;
});
svg.appendChild(txt(x+w/2,y-8,'RD$ 1.00',{anchor:'middle',fs:10,fill:col('--faint')}));
})();
/* ---------- TREND (bars + line) ---------- */
(function(){
var svg=document.getElementById('trend'); if(!svg)return;
var data=[
{m:'Ene',v:132.4,u:2.5},{m:'Feb',v:169.9,u:7.2},{m:'Mar',v:224.8,u:56.3},
{m:'Abr',v:224.3,u:52.6},{m:'May',v:190.8,u:33.0},{m:'Jun',v:225.0,u:37.8},
{m:'Jul',v:208.1,u:30.2}
];
var W=720,base=230,top=18,padL=34,padR=12;
var max=240, sc=(base-top)/max;
[0,60,120,180,240].forEach(function(g){
var y=base-g*sc;
svg.appendChild(el('line',{x1:padL,y1:y,x2:W-padR,y2:y,stroke:col('--grid'),'stroke-width':1}));
svg.appendChild(txt(padL-6,y+3,g,{anchor:'end',fs:9.5,fill:col('--faint'),mono:true}));
});
var n=data.length, gap=18, bw=(W-padL-padR-gap*(n-1))/n;
var pts=[];
data.forEach(function(d,i){
var x=padL+i*(bw+gap);
var h=d.v*sc;
svg.appendChild(el('rect',{x:x,y:base-h,width:bw,height:h,rx:3,fill:col('--accent-soft')}));
svg.appendChild(txt(x+bw/2,base+15,d.m,{anchor:'middle',fs:10.5}));
svg.appendChild(txt(x+bw/2,base-h-6,d.v.toFixed(0),{anchor:'middle',fs:10,mono:true,fill:col('--muted')}));
pts.push([x+bw/2, base-d.u*sc]);
});
var dpath='M'+pts.map(function(p){return p[0]+','+p[1]}).join(' L');
svg.appendChild(el('path',{d:dpath,fill:'none',stroke:col('--accent'),'stroke-width':2.4,'stroke-linejoin':'round'}));
pts.forEach(function(p){svg.appendChild(el('circle',{cx:p[0],cy:p[1],r:3.4,fill:col('--surface'),stroke:col('--accent'),'stroke-width':2}));});
})();
/* ---------- ANNUAL ---------- */
(function(){
var svg=document.getElementById('annual'); if(!svg)return;
var data=[{y:'2024',v:2401,u:462},{y:'2025',v:2401,u:457},{y:"2026*",v:1375,u:220}];
var W=360,base=230,top=18,padL=30,padR=10;
var max=2500,sc=(base-top)/max;
var n=data.length,gap=40,grp=(W-padL-padR-gap*(n-1))/n, bw=grp/2-3;
data.forEach(function(d,i){
var x=padL+i*(grp+gap);
var h1=d.v*sc,h2=d.u*sc;
svg.appendChild(el('rect',{x:x,y:base-h1,width:bw,height:h1,rx:3,fill:col('--accent-soft')}));
svg.appendChild(el('rect',{x:x+bw+6,y:base-h2,width:bw,height:h2,rx:3,fill:col('--accent')}));
svg.appendChild(txt(x+grp/2,base+15,d.y,{anchor:'middle',fs:11}));
svg.appendChild(txt(x+bw/2,base-h1-5,(d.v/1000).toFixed(2)+'k',{anchor:'middle',fs:9.5,mono:true,fill:col('--muted')}));
svg.appendChild(txt(x+bw+6+bw/2,base-h2-5,d.u,{anchor:'middle',fs:9.5,mono:true,fill:col('--muted')}));
});
svg.appendChild(txt(padL,top-4,'RD$ M',{fs:9.5,fill:col('--faint')}));
})();
/* ---------- GERENCIA (grouped horizontal) ---------- */
(function(){
var svg=document.getElementById('ger'); if(!svg)return;
var data=[
{l:'Ventas y Mercadeo',a:184.5,b:178.3},
{l:'Admin. y Materiales',a:104.8,b:92.5},
{l:'Planta / Producción',a:78.1,b:79.9},
{l:'Gerencia General',a:41.3,b:36.4},
{l:'Planta Agregados',a:4.4,b:0},
{l:'Caribbean',a:1.6,b:0}
];
var W=380,padL=8,padR=44,top=6,rowH=46,x0=padL, maxW=W-padL-padR, max=190, sc=maxW/max;
data.forEach(function(d,i){
var y=top+i*rowH;
svg.appendChild(txt(x0,y+11,d.l,{fs:11,fw:500,fill:col('--ink')}));
svg.appendChild(el('rect',{x:x0,y:y+16,width:Math.max(2,d.a*sc),height:9,rx:2,fill:col('--accent')}));
svg.appendChild(el('rect',{x:x0,y:y+27,width:Math.max(2,d.b*sc),height:9,rx:2,fill:col('--accent-soft')}));
svg.appendChild(txt(x0+d.a*sc+6,y+24,money(d.a),{fs:10,mono:true,fill:col('--muted')}));
});
})();
/* ---------- SUBGRUPO table ---------- */
(function(){
var tb=document.getElementById('subg'); if(!tb)return;
var rows=[
['74 · Otros gastos y servicios',304.1,22.1],
['71 · Compensación empleados',293.8,21.4],
['73 · Gastos fijos',114.7,8.3],
['72 · Otros rel. a empleados',27.8,2.0],
['76 · Cierre fabricación (absorción)',-325.7,-23.7]
];
var max=310;
rows.forEach(function(r){
var tr=document.createElement('tr');
var w=Math.abs(r[1])/max*100;
tr.innerHTML='<td class="barcell"><div class="fill" style="width:'+w+'%;background:'+(r[1]<0?'color-mix(in srgb,var(--neg) 20%,transparent)':'var(--accent-soft)')+'"></div><span>'+r[0]+'</span></td>'+
'<td class="r num" style="font-weight:600;color:'+(r[1]<0?'var(--neg)':'var(--ink)')+'">'+(r[1]<0?'':'')+money(Math.abs(r[1]))+'</td>'+
'<td class="r num" style="color:var(--muted)">'+r[2].toFixed(1)+'%</td>';
tb.appendChild(tr);
});
})();
/* ---------- GASTO TREND ---------- */
(function(){
var svg=document.getElementById('gtrend'); if(!svg)return;
var data=[
{m:'Ene',g:55.1,r:41.6},{m:'Feb',g:54.8,r:32.2},{m:'Mar',g:59.2,r:26.3},
{m:'Abr',g:59.9,r:26.7},{m:'May',g:57.7,r:30.3},{m:'Jun',g:61.5,r:27.3},{m:'Jul',g:66.6,r:32.0}
];
var W=720,base=200,top=16,padL=34,padR=40;
var max=80,sc=(base-top)/max;
[0,20,40,60,80].forEach(function(g){var y=base-g*sc;
svg.appendChild(el('line',{x1:padL,y1:y,x2:W-padR,y2:y,stroke:col('--grid')}));
svg.appendChild(txt(padL-6,y+3,g,{anchor:'end',fs:9.5,mono:true,fill:col('--faint')}));});
var n=data.length,gap=20,bw=(W-padL-padR-gap*(n-1))/n, rpts=[];
data.forEach(function(d,i){
var x=padL+i*(bw+gap),h=d.g*sc;
svg.appendChild(el('rect',{x:x,y:base-h,width:bw,height:h,rx:3,fill:col('--accent')}));
svg.appendChild(txt(x+bw/2,base+15,d.m,{anchor:'middle',fs:10.5}));
svg.appendChild(txt(x+bw/2,base-h-5,d.g.toFixed(0),{anchor:'middle',fs:9.5,mono:true,fill:col('--muted')}));
rpts.push([x+bw/2, base-(d.r/ (80/60) )*sc]); // scale % on right (0-60 mapped)
});
// right axis % (gasto/ventas), scale 0-60 across same height
var rsc=(base-top)/60;
rpts=[];data.forEach(function(d,i){var x=padL+i*(bw+gap);rpts.push([x+bw/2, base-d.r*rsc]);});
var dp='M'+rpts.map(function(p){return p[0]+','+p[1]}).join(' L');
svg.appendChild(el('path',{d:dp,fill:'none',stroke:col('--pos'),'stroke-width':2.2,'stroke-dasharray':'1 0'}));
rpts.forEach(function(p,i){svg.appendChild(el('circle',{cx:p[0],cy:p[1],r:3,fill:col('--surface'),stroke:col('--pos'),'stroke-width':2}));
svg.appendChild(txt(p[0],p[1]-8,data[i].r.toFixed(0)+'%',{anchor:'middle',fs:9,mono:true,fill:col('--pos')}));});
svg.appendChild(txt(padL,top-4,'RD$ M',{fs:9.5,fill:col('--faint')}));
svg.appendChild(txt(W-padR+4,top+4,'% ventas',{fs:9.5,fill:col('--pos')}));
})();
/* ---------- BALANCE stacked ---------- */
(function(){
var svg=document.getElementById('bal'); if(!svg)return;
var W=380,base=250,top=20,bw=88;
var max=6435, sc=(base-top)/max;
// col 1 activos
var xA=60;
svg.appendChild(el('rect',{x:xA,y:base-6435*sc,width:bw,height:6435*sc,rx:4,fill:col('--accent'),opacity:.9}));
svg.appendChild(txt(xA+bw/2,base-6435*sc-8,'6,435',{anchor:'middle',fs:12,mono:true,fw:600,fill:col('--ink')}));
svg.appendChild(txt(xA+bw/2,base+16,'Activos',{anchor:'middle',fs:11}));
// col 2 pasivo+patrimonio+result
var xB=xA+bw+70, parts=[{l:'Pasivos',v:2322,c:col('--neg')},{l:'Patrimonio',v:3894,c:col('--pos')},{l:'Result. ejerc.',v:219,c:col('--warn')}];
var cy=base;
parts.forEach(function(p){var h=p.v*sc;cy-=h;
svg.appendChild(el('rect',{x:xB,y:cy,width:bw,height:h,fill:p.c,opacity:.85}));
svg.appendChild(txt(xB+bw+8,cy+h/2+4,p.l+' '+p.v.toLocaleString('en-US'),{fs:10.5,fill:col('--muted')}));
});
svg.appendChild(txt(xB+bw/2,base+16,'Pas. + Patrim.',{anchor:'middle',fs:11}));
})();
/* ---------- ACTIVO / PASIVO tables ---------- */
(function(){
function fill(id,rows,max){
var tb=document.getElementById(id); if(!tb)return;
rows.forEach(function(r){
var tr=document.createElement('tr');
var neg=r[1]<0;
tr.innerHTML='<td>'+r[0]+'</td><td class="r num" style="color:'+(neg?'var(--neg)':'var(--ink)')+'">'+(neg?'':'')+Math.abs(r[1]).toLocaleString('en-US')+'</td>';
tb.appendChild(tr);
});
}
fill('act',[['Activos corrientes',3250],['Activos fijos',4140],['Depreciación acum.',-1136],['Otros activos',181],['Total activos',6435]]);
fill('pas',[['Pasivos corrientes',1420],['Préstamos largo plazo',902],['Total pasivos',2322],['Patrimonio',3894]]);
// bold totals
['act','pas'].forEach(function(id){var t=document.getElementById(id);var rs=t.querySelectorAll('tr');
rs.forEach(function(tr){if(/Total/.test(tr.textContent)){tr.style.fontWeight='700';tr.querySelectorAll('td').forEach(function(td){td.style.borderTop='1px solid var(--line)';});}});});
})();
})();
</script>