JSOTO adicione la CLASSPATH java al grupo COMUNES

This commit is contained in:
2026-08-27 16:04:05 -04:00
parent 9a8c922af3
commit c0f6b23e19
44 changed files with 2072 additions and 1 deletions
@@ -0,0 +1,561 @@
<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 ene–jul (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>