// Shared UI components for Datamin POS/DTE Intelligence
// Babel-transpiled JSX, share components via window.* assignment at the bottom.

const { useState, useEffect, useRef, useMemo } = React;

// ============ Utilities ============
const fmtCLP = (n) => {
  if (n == null) return "—";
  return "$" + Math.round(n).toLocaleString("es-CL");
};
const fmtNumber = (n) => {
  if (n == null) return "—";
  return Math.round(n).toLocaleString("es-CL");
};
const fmtPct = (n, digits = 1) => {
  if (n == null) return "—";
  return n.toFixed(digits) + "%";
};

// ============ Icons (simple, line-style) ============
const Icon = ({ name, size = 16, stroke = 1.6, className = "" }) => {
  const paths = {
    dashboard: "M3 12h7V3H3v9zm0 9h7v-6H3v6zm11 0h7V12h-7v9zm0-18v6h7V3h-7z",
    invoice: "M6 3h12v18l-3-2-3 2-3-2-3 2V3z M9 8h6 M9 12h6 M9 16h4",
    suppliers: "M3 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2 M5 7a4 4 0 1 0 8 0 4 4 0 0 0-8 0 M17 11l2 2 4-4",
    products: "M3 7l9-4 9 4-9 4-9-4z M3 7v10l9 4 9-4V7 M12 11v10",
    inventory: "M4 7h16v13H4z M4 11h16 M9 7V4h6v3",
    quality: "M12 2l8 4v6c0 5-3.5 9-8 10-4.5-1-8-5-8-10V6l8-4z M9 12l2 2 4-4",
    download: "M12 3v12 m-5-5l5 5 5-5 M5 21h14",
    search: "M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14z M21 21l-5-5",
    filter: "M3 5h18 M6 12h12 M10 19h4",
    chevron: "M9 18l6-6-6-6",
    chevronD: "M6 9l6 6 6-6",
    alert: "M12 9v4 M12 17h.01 M10.3 3.86L1.82 18a2 2 0 0 0 1.7 3h16.9a2 2 0 0 0 1.7-3L13.7 3.86a2 2 0 0 0-3.4 0z",
    bell: "M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9 M13.7 21a2 2 0 0 1-3.4 0",
    user: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2 M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z",
    calendar: "M3 6h18v15H3z M3 10h18 M8 3v6 M16 3v6",
    logout: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4 M16 17l5-5-5-5 M21 12H9",
    sort: "M7 4v16 M3 8l4-4 4 4 M17 20V4 M13 16l4 4 4-4",
    sun: "M12 4V2 M12 22v-2 M4.93 4.93l1.41 1.41 M17.66 17.66l1.41 1.41 M2 12h2 M20 12h2 M4.93 19.07l1.41-1.41 M17.66 6.34l1.41-1.41 M12 7a5 5 0 1 0 0 10 5 5 0 0 0 0-10z",
    moon: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z",
    menu: "M3 6h18 M3 12h18 M3 18h18",
    panel: "M3 4h18v16H3z M9 4v16",
    eye: "M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z",
    eyeOff: "M17.94 17.94A11 11 0 0 1 12 19c-7 0-11-7-11-7a18 18 0 0 1 4.4-5.2 M9.9 5.1A11 11 0 0 1 12 5c7 0 11 7 11 7a18 18 0 0 1-2.6 3.6 M14.1 14.1a3 3 0 1 1-4.2-4.2 M1 1l22 22",
    check: "M5 12l5 5 9-12",
    x: "M6 6l12 12 M18 6l-12 12",
    info: "M12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16z M12 8v.01 M11 12h1v4h1",
    spark: "M3 12l4-6 4 8 4-12 4 10 2-4",
    trendUp: "M3 17l6-6 4 4 8-9 M14 7h6v6",
    trendDn: "M3 7l6 6 4-4 8 9 M14 17h6v-6",
    layers: "M12 3l9 5-9 5-9-5 9-5z M3 13l9 5 9-5 M3 18l9 5 9-5",
    shield: "M12 2l8 4v6c0 5-3.5 9-8 10-4.5-1-8-5-8-10V6l8-4z",
    lock: "M5 11h14v10H5z M8 11V7a4 4 0 0 1 8 0v4",
    globe: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z M3 12h18 M12 3a14 14 0 0 1 0 18 14 14 0 0 1 0-18z",
    grid: "M3 3h7v7H3z M14 3h7v7h-7z M14 14h7v7h-7z M3 14h7v7H3z",
    db: "M4 6c0-1.7 3.6-3 8-3s8 1.3 8 3-3.6 3-8 3-8-1.3-8-3z M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6 M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"
  };
  const d = paths[name] || "";
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
    stroke="currentColor" strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"
    className={className} style={{ flex: "none" }}>
      {d.split(" M").map((seg, i) =>
      <path key={i} d={(i === 0 ? "" : "M") + seg} />
      )}
    </svg>);

};

// ============ Monogram logo ============
const Logo = ({ size = 32 }) =>
<div className="dm-logo" style={{ width: size, height: size }}>
    <svg viewBox="0 0 32 32" width={size} height={size}>
      <rect width="32" height="32" rx="8" fill="#0B1E3F" />
      <path d="M8 8h7c4.4 0 7 2.8 7 8s-2.6 8-7 8H8V8z" fill="none" stroke="#FFFFFF" strokeWidth="2.4" />
      <circle cx="22" cy="22" r="2.2" fill="#F97316" />
    </svg>
  </div>;


// ============ Reliability badge ============
const ReliabilityBadge = ({ level, show = true, size = "sm", lang = "es" }) => {
  if (!show) return null;
  const t = window.I18N[lang].reliability;
  const map = {
    reliable: { label: t.reliable, bg: "rgba(16,185,129,.12)", fg: "#047857", dot: "#10B981" },
    partial: { label: t.partial, bg: "rgba(245,158,11,.14)", fg: "#92400E", dot: "#F59E0B" },
    unreliable: { label: t.unreliable, bg: "rgba(220,38,38,.10)", fg: "#B91C1C", dot: "#DC2626" },
    missing: { label: t.missing, bg: "rgba(100,116,139,.14)", fg: "#475569", dot: "#94A3B8" }
  };
  const s = map[level] || map.missing;
  return (
    <span className={`dm-rel-badge dm-rel-${size}`}
    style={{ background: s.bg, color: s.fg }}>
      <span className="dm-rel-dot" style={{ background: s.dot }}></span>
      {s.label}
    </span>);

};

// ============ KPI card ============
const KPICard = ({ label, value, sub, delta, deltaPositive, icon, reliability, showRel, lang, size = "md", emphasis }) => {
  return (
    <div className={`dm-kpi dm-kpi-${size} ${emphasis ? "dm-kpi-em" : ""}`}>
      <div className="dm-kpi-head">
        <div className="dm-kpi-label">{label}</div>
        {icon && <div className="dm-kpi-icon"><Icon name={icon} size={16} /></div>}
      </div>
      <div className="dm-kpi-value">{value}</div>
      <div className="dm-kpi-foot">
        {delta != null &&
        <span className={`dm-kpi-delta ${deltaPositive ? "up" : "down"}`}>
            <Icon name={deltaPositive ? "trendUp" : "trendDn"} size={12} stroke={2} />
            {delta}
          </span>
        }
        {sub && <span className="dm-kpi-sub">{sub}</span>}
        {reliability && <ReliabilityBadge level={reliability} show={showRel} lang={lang} size="xs" />}
      </div>
    </div>);

};

// ============ Card (panel) ============
const Card = ({ title, subtitle, action, reliability, showRel, lang, children, className = "", padding = true }) =>
<section className={`dm-card ${className}`}>
    {(title || action) &&
  <header className="dm-card-head" style={{ fontFamily: "Raleway" }}>
        <div>
          {title && <h3 className="dm-card-title">{title}</h3>}
          {subtitle && <p className="dm-card-sub">{subtitle}</p>}
        </div>
        <div className="dm-card-actions">
          {reliability && <ReliabilityBadge level={reliability} show={showRel} lang={lang} />}
          {action}
        </div>
      </header>
  }
    <div className={padding ? "dm-card-body" : ""}>{children}</div>
  </section>;


// ============ Sidebar ============
const NAV = (lang) => [
{ id: "executive", label: window.I18N[lang].nav.executive, icon: "dashboard" },
{ id: "compras", label: window.I18N[lang].nav.compras, icon: "invoice" },
{ id: "proveedores", label: window.I18N[lang].nav.proveedores, icon: "suppliers" },
{ id: "productos", label: window.I18N[lang].nav.productos, icon: "products" },
{ id: "inventario", label: window.I18N[lang].nav.inventario, icon: "inventory" },
{ id: "calidad", label: window.I18N[lang].nav.calidad, icon: "quality" }];


const Sidebar = ({ route, setRoute, collapsed, setCollapsed, lang, onLogout }) => {
  const items = NAV(lang);
  return (
    <aside className={`dm-sidebar ${collapsed ? "collapsed" : ""}`}>
      <div className="dm-sidebar-top">
        <div className="dm-brand">
          <Logo size={32} />
          {!collapsed &&
          <div className="dm-brand-text">
              <strong>{window.I18N[lang].appName}</strong>
              <span>{window.I18N[lang].tagline}</span>
            </div>
          }
        </div>
        <button className="dm-icon-btn dm-collapse-btn" onClick={() => setCollapsed((c) => !c)} title="Toggle">
          <Icon name="panel" size={16} />
        </button>
      </div>
      <nav className="dm-nav">
        {items.map((it) =>
        <button key={it.id}
        className={`dm-nav-item ${route === it.id ? "active" : ""}`}
        onClick={() => setRoute(it.id)}
        title={collapsed ? it.label : ""}>
            <Icon name={it.icon} size={18} />
            {!collapsed && <span>{it.label}</span>}
            {!collapsed && it.id === "calidad" &&
          <span className="dm-nav-dot" title="7 issues"></span>
          }
          </button>
        )}
      </nav>
      <div className="dm-sidebar-bot">
        {!collapsed &&
        <div className="dm-user">
            <div className="dm-avatar">JP</div>
            <div className="dm-user-text">
              <strong>Juan Pernía</strong>
              <span>Dueño · Director</span>
            </div>
          </div>
        }
        <button className="dm-icon-btn" onClick={onLogout} title={window.I18N[lang].nav.logout}>
          <Icon name="logout" size={16} />
        </button>
      </div>
    </aside>);

};

// ============ Topbar / Header ============
const Topbar = ({ lang, company, setCompany, period, setPeriod, density, setDensity, onToggleSidebar, screenTitle, screenSub }) => {
  const t = window.I18N[lang].header;
  return (
    <header className="dm-topbar">
      <div className="dm-topbar-left">
        <button className="dm-icon-btn dm-mobile-only" onClick={onToggleSidebar} title="Menu">
          <Icon name="menu" size={18} />
        </button>
        <div>
          <h1 className="dm-screen-title">{screenTitle}</h1>
          <p className="dm-screen-sub">{screenSub}</p>
        </div>
      </div>
      <div className="dm-topbar-right">
        <div className="dm-search">
          <Icon name="search" size={14} />
          <input placeholder={t.search} />
          <kbd>⌘K</kbd>
        </div>
        <div className="dm-selector">
          <Icon name="grid" size={14} />
          <select value={company} onChange={(e) => setCompany(e.target.value)}>
            {window.COMPANIES.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}
          </select>
        </div>
        <div className="dm-selector">
          <Icon name="calendar" size={14} />
          <select value={period} onChange={(e) => setPeriod(e.target.value)}>
            <option value="7d">Últimos 7 días</option>
            <option value="30d">Últimos 30 días</option>
            <option value="90d">Últimos 90 días</option>
            <option value="ytd">YTD 2026</option>
            <option value="12m">12 meses</option>
          </select>
        </div>
        <button className="dm-btn dm-btn-secondary">
          <Icon name="download" size={14} />
          {t.export}
        </button>
        <button className="dm-icon-btn" title="Notificaciones">
          <Icon name="bell" size={16} />
          <span className="dm-notif-dot"></span>
        </button>
      </div>
    </header>);

};

// ============ Charts ============

// Line + stacked area chart
const LineChart = ({ data, labels, series, height = 220, showGrid = true, currency = true }) => {
  const W = 720,H = height,pad = { l: 56, r: 16, t: 16, b: 32 };
  const innerW = W - pad.l - pad.r,innerH = H - pad.t - pad.b;
  const allVals = series.flatMap((s) => s.values);
  const max = Math.max(...allVals) * 1.1;
  const xs = labels.map((_, i) => pad.l + (labels.length === 1 ? 0 : innerW * i / (labels.length - 1)));
  const y = (v) => pad.t + innerH - v / max * innerH;
  const ticks = 4;
  return (
    <div className="dm-chart">
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} preserveAspectRatio="none">
        {showGrid && Array.from({ length: ticks + 1 }).map((_, i) => {
          const yy = pad.t + innerH * i / ticks;
          const val = max * (1 - i / ticks);
          return (
            <g key={i}>
              <line x1={pad.l} x2={W - pad.r} y1={yy} y2={yy} stroke="#E2E8F0" strokeDasharray="3 3" />
              <text x={pad.l - 8} y={yy + 4} fontSize="10" fill="#64748B" textAnchor="end" fontFamily="ui-monospace, JetBrains Mono, monospace">
                {currency ? "$" + (val / 1e6).toFixed(1) + "M" : Math.round(val)}
              </text>
            </g>);

        })}
        {series.map((s, si) => {
          const path = s.values.map((v, i) => `${i === 0 ? "M" : "L"} ${xs[i]} ${y(v)}`).join(" ");
          const area = path + ` L ${xs[xs.length - 1]} ${pad.t + innerH} L ${xs[0]} ${pad.t + innerH} Z`;
          return (
            <g key={si}>
              {s.fill && <path d={area} fill={s.fill} opacity="0.18" />}
              <path d={path} fill="none" stroke={s.color} strokeWidth={s.width || 2.2} strokeLinejoin="round" strokeLinecap="round" />
              {s.dots !== false && s.values.map((v, i) =>
              <circle key={i} cx={xs[i]} cy={y(v)} r="3" fill="#fff" stroke={s.color} strokeWidth="2" />
              )}
            </g>);

        })}
        {labels.map((l, i) =>
        <text key={i} x={xs[i]} y={H - 10} fontSize="10" fill="#64748B" textAnchor="middle"
        fontFamily="ui-monospace, JetBrains Mono, monospace">{l}</text>
        )}
      </svg>
      {series.length > 1 &&
      <div className="dm-chart-legend">
          {series.map((s, i) =>
        <span key={i} className="dm-chart-leg-item">
              <span className="dm-chart-leg-dot" style={{ background: s.color }}></span>{s.name}
            </span>
        )}
        </div>
      }
    </div>);

};

// Bar chart (horizontal)
const HBarChart = ({ data, valueKey = "value", labelKey = "label", subKey, color = "#0EA5E9", format = fmtCLP, max: maxProp, height }) => {
  const max = maxProp || Math.max(...data.map((d) => d[valueKey]));
  return (
    <div className="dm-hbar" style={height ? { maxHeight: height, overflowY: "auto" } : null}>
      {data.map((d, i) =>
      <div key={i} className="dm-hbar-row">
          <div className="dm-hbar-label">
            <span className="dm-hbar-rank">{i + 1}</span>
            <div className="dm-hbar-name-stack">
              <span className="dm-hbar-name">{d[labelKey]}</span>
              {subKey && d[subKey] && <span className="dm-hbar-sub">{d[subKey]}</span>}
            </div>
          </div>
          <div className="dm-hbar-track">
            <div className="dm-hbar-fill" style={{ width: d[valueKey] / max * 100 + "%", background: color }}></div>
          </div>
          <div className="dm-hbar-value">{format(d[valueKey])}</div>
        </div>
      )}
    </div>);

};

// Vertical bar chart
const VBarChart = ({ labels, values, color = "#0EA5E9", height = 200, format = fmtNumber, currency = false }) => {
  const W = 720,H = height,pad = { l: 56, r: 16, t: 16, b: 32 };
  const innerW = W - pad.l - pad.r,innerH = H - pad.t - pad.b;
  const max = Math.max(...values) * 1.15;
  const bw = innerW / values.length * 0.6;
  const step = innerW / values.length;
  return (
    <div className="dm-chart">
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} preserveAspectRatio="none">
        {[0, 1, 2, 3, 4].map((i) => {
          const yy = pad.t + innerH * i / 4;
          const val = max * (1 - i / 4);
          return (
            <g key={i}>
              <line x1={pad.l} x2={W - pad.r} y1={yy} y2={yy} stroke="#E2E8F0" strokeDasharray="3 3" />
              <text x={pad.l - 8} y={yy + 4} fontSize="10" fill="#64748B" textAnchor="end" fontFamily="ui-monospace, JetBrains Mono, monospace">
                {currency ? "$" + (val / 1e6).toFixed(1) + "M" : Math.round(val)}
              </text>
            </g>);

        })}
        {values.map((v, i) => {
          const h = v / max * innerH;
          const x = pad.l + step * i + (step - bw) / 2;
          const yy = pad.t + innerH - h;
          return (
            <g key={i}>
              <rect x={x} y={yy} width={bw} height={h} rx="3" fill={color} />
              <text x={x + bw / 2} y={H - 10} fontSize="10" fill="#64748B" textAnchor="middle"
              fontFamily="ui-monospace, JetBrains Mono, monospace">{labels[i]}</text>
            </g>);

        })}
      </svg>
    </div>);

};

// Donut chart
const Donut = ({ segments, size = 160, thickness = 24, centerLabel, centerSub }) => {
  const total = segments.reduce((a, s) => a + s.value, 0);
  const r = size / 2 - thickness / 2;
  const c = 2 * Math.PI * r;
  let offset = 0;
  return (
    <div className="dm-donut" style={{ width: size, height: size, position: "relative" }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
        <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="#F1F5F9" strokeWidth={thickness} />
        {segments.map((s, i) => {
          const len = s.value / total * c;
          const dasharray = `${len} ${c - len}`;
          const el =
          <circle key={i} cx={size / 2} cy={size / 2} r={r} fill="none"
          stroke={s.color} strokeWidth={thickness}
          strokeDasharray={dasharray} strokeDashoffset={-offset}
          transform={`rotate(-90 ${size / 2} ${size / 2})`} />;

          offset += len;
          return el;
        })}
      </svg>
      {centerLabel &&
      <div className="dm-donut-center">
          <div className="dm-donut-val">{centerLabel}</div>
          {centerSub && <div className="dm-donut-sub">{centerSub}</div>}
        </div>
      }
    </div>);

};

// Heatmap (provider × month)
const Heatmap = ({ rows, cols, getValue, max, color = "#0EA5E9" }) => {
  const computedMax = max || Math.max(...rows.flatMap((r, ri) => cols.map((c, ci) => getValue(ri, ci))));
  return (
    <div className="dm-heatmap" style={{ gridTemplateColumns: `160px repeat(${cols.length}, 1fr)` }}>
      <div></div>
      {cols.map((c, i) => <div key={"c" + i} className="dm-hm-col-label">{c}</div>)}
      {rows.map((r, ri) =>
      <React.Fragment key={"r" + ri}>
          <div className="dm-hm-row-label">{r}</div>
          {cols.map((c, ci) => {
          const v = getValue(ri, ci);
          const a = computedMax === 0 ? 0 : v / computedMax;
          return (
            <div key={"v" + ri + "-" + ci} className="dm-hm-cell"
            style={{ background: `color-mix(in oklab, ${color} ${Math.round(a * 100)}%, #F8FAFC)`,
              color: a > 0.55 ? "#fff" : "#0B1E3F" }}>
                {v > 0 && (v / 1e6).toFixed(1) + "M"}
              </div>);

        })}
        </React.Fragment>
      )}
    </div>);

};

// Sparkline
const Sparkline = ({ values, color = "#0EA5E9", w = 96, h = 28 }) => {
  const max = Math.max(...values),min = Math.min(...values);
  const range = max - min || 1;
  const pts = values.map((v, i) => `${i / (values.length - 1) * w},${h - (v - min) / range * h}`).join(" ");
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} className="dm-spark">
      <polyline points={pts} fill="none" stroke={color} strokeWidth="2" strokeLinejoin="round" strokeLinecap="round" />
    </svg>);

};

// Histogram (small)
const Histogram = ({ bins, color = "#0EA5E9" }) => {
  const max = Math.max(...bins.map((b) => b.count));
  return (
    <div className="dm-histo">
      {bins.map((b, i) =>
      <div key={i} className="dm-histo-col" title={`${b.label}: ${b.count}`}>
          <div className="dm-histo-bar" style={{ height: b.count / max * 100 + "%", background: color }}></div>
          <span className="dm-histo-lab">{b.label}</span>
        </div>
      )}
    </div>);

};

// Progress bar (for completeness)
const ProgressBar = ({ value, color = "#0EA5E9", showVal = true, label }) =>
<div className="dm-pb-wrap">
    {label && <div className="dm-pb-label">{label}</div>}
    <div className="dm-pb-track">
      <div className="dm-pb-fill" style={{ width: value + "%", background: color }}></div>
    </div>
    {showVal && <div className="dm-pb-val">{value}%</div>}
  </div>;


// ============ Alert list ============
const AlertList = ({ items }) =>
<ul className="dm-alerts">
    {items.map((a, i) =>
  <li key={i} className={`dm-alert dm-alert-${a.sev}`}>
        <span className="dm-alert-icon"><Icon name="alert" size={14} /></span>
        <div>
          <strong>{a.title}</strong>
          <p>{a.detail}</p>
        </div>
        {a.cta && <button className="dm-btn dm-btn-ghost dm-btn-sm">{a.cta}</button>}
      </li>
  )}
  </ul>;


// ============ Empty state ============
const EmptyState = ({ icon = "db", title, sub, action }) =>
<div className="dm-empty">
    <div className="dm-empty-ico"><Icon name={icon} size={28} /></div>
    <h4>{title}</h4>
    <p>{sub}</p>
    {action}
  </div>;


// ============ Data table ============
const DataTable = ({ columns, rows, rowKey = "id", onRowClick, searchable = true, density = "cozy", searchPlaceholder = "Buscar..." }) => {
  const [q, setQ] = useState("");
  const [sortKey, setSortKey] = useState(null);
  const [sortDir, setSortDir] = useState("asc");

  const filtered = useMemo(() => {
    let out = rows;
    if (q) {
      const Q = q.toLowerCase();
      out = out.filter((r) => columns.some((c) => {
        const v = c.accessor ? c.accessor(r) : r[c.key];
        return String(v ?? "").toLowerCase().includes(Q);
      }));
    }
    if (sortKey) {
      const col = columns.find((c) => c.key === sortKey);
      out = [...out].sort((a, b) => {
        const av = col.accessor ? col.accessor(a) : a[sortKey];
        const bv = col.accessor ? col.accessor(b) : b[sortKey];
        if (typeof av === "number") return sortDir === "asc" ? av - bv : bv - av;
        return sortDir === "asc" ?
        String(av).localeCompare(String(bv)) :
        String(bv).localeCompare(String(av));
      });
    }
    return out;
  }, [rows, q, sortKey, sortDir, columns]);

  return (
    <div className={`dm-table-wrap dm-density-${density}`}>
      {searchable &&
      <div className="dm-table-toolbar">
          <div className="dm-search dm-search-sm">
            <Icon name="search" size={12} />
            <input value={q} onChange={(e) => setQ(e.target.value)} placeholder={searchPlaceholder} />
          </div>
          <span className="dm-table-count">{filtered.length} de {rows.length}</span>
        </div>
      }
      <div className="dm-table-scroll">
        <table className="dm-table">
          <thead>
            <tr>
              {columns.map((c) =>
              <th key={c.key} style={{ width: c.width, textAlign: c.align || "left" }}
              onClick={c.sortable !== false ? () => {
                if (sortKey === c.key) setSortDir((d) => d === "asc" ? "desc" : "asc");else
                {setSortKey(c.key);setSortDir("asc");}
              } : null}
              className={c.sortable !== false ? "dm-th-sortable" : ""}>
                  <span>{c.header}</span>
                  {c.sortable !== false &&
                <Icon name="sort" size={10} className={`dm-sort-ico ${sortKey === c.key ? "active" : ""}`} />
                }
                </th>
              )}
            </tr>
          </thead>
          <tbody>
            {filtered.length === 0 ?
            <tr><td colSpan={columns.length} className="dm-table-empty">Sin resultados</td></tr> :
            filtered.map((r) =>
            <tr key={r[rowKey] || JSON.stringify(r).slice(0, 40)}
            onClick={onRowClick ? () => onRowClick(r) : null}
            className={onRowClick ? "dm-row-click" : ""}>
                {columns.map((c) =>
              <td key={c.key} style={{ textAlign: c.align || "left" }}>
                    {c.render ? c.render(r) : c.accessor ? c.accessor(r) : r[c.key]}
                  </td>
              )}
              </tr>
            )}
          </tbody>
        </table>
      </div>
    </div>);

};

// ============ Section: filters bar ============
const FiltersBar = ({ children, onReset, lang }) =>
<div className="dm-filters">
    <div className="dm-filters-left">
      <Icon name="filter" size={14} />
      <span className="dm-filters-label">{window.I18N[lang].common.filters}</span>
    </div>
    <div className="dm-filters-controls">{children}</div>
    {onReset && <button className="dm-btn dm-btn-ghost dm-btn-sm" onClick={onReset}>{window.I18N[lang].common.reset}</button>}
  </div>;


// ============ Tag ============
const Tag = ({ children, tone = "neutral" }) =>
<span className={`dm-tag dm-tag-${tone}`}>{children}</span>;


// ---- Export to window ----
Object.assign(window, {
  Icon, Logo, ReliabilityBadge, KPICard, Card, Sidebar, Topbar,
  LineChart, HBarChart, VBarChart, Donut, Heatmap, Sparkline, Histogram, ProgressBar,
  AlertList, EmptyState, DataTable, FiltersBar, Tag,
  fmtCLP, fmtNumber, fmtPct
});
